diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 5a11fdcc9f..d2727d4d1d 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -787,6 +787,11 @@ typedef struct AVStream { * NOT PART OF PUBLIC API */ int request_probe; + /** + * Indicates that everything up to the next keyframe + * should be discarded. + */ + int skip_to_keyframe; } AVStream; #define AV_PROGRAM_RUNNING 1 diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index e9c31013cd..27d84adbc2 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1839,9 +1839,14 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, } if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) { - if (!is_keyframe || timecode < matroska->skip_to_timecode) + if (timecode < matroska->skip_to_timecode) return res; - matroska->skip_to_keyframe = 0; + if (!st->skip_to_keyframe) { + av_log(matroska->ctx, AV_LOG_ERROR, "File is broken, keyframes not correctly marked!\n"); + matroska->skip_to_keyframe = 0; + } + if (is_keyframe) + matroska->skip_to_keyframe = 0; } switch ((flags & 0x06) >> 1) { @@ -2147,6 +2152,7 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, avio_seek(s->pb, st->index_entries[index_min].pos, SEEK_SET); matroska->current_id = 0; + st->skip_to_keyframe = matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY); matroska->skip_to_timecode = st->index_entries[index].timestamp; matroska->done = 0; @@ -2158,6 +2164,7 @@ err: // the generic seeking code. matroska_clear_queue(matroska); matroska->current_id = 0; + st->skip_to_keyframe = matroska->skip_to_keyframe = 0; matroska->done = 0; matroska->num_levels = 0; diff --git a/libavformat/utils.c b/libavformat/utils.c index 3c3ced75a0..0636742b4e 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -1315,6 +1315,12 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) /* free packet */ av_free_packet(&cur_pkt); } + if (pkt->flags & AV_PKT_FLAG_KEY) + st->skip_to_keyframe = 0; + if (st->skip_to_keyframe) { + av_free_packet(&cur_pkt); + got_packet = 0; + } } if (!got_packet && s->parse_queue)