diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index cec40e0250..1221dab2d9 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -39,6 +39,8 @@ #define VALIDATE_INDEX_TS_THRESH 2500 +#define RESYNC_BUFFER_SIZE (1<<20) + typedef struct FLVContext { const AVClass *class; ///< Class for private options. int trust_metadata; ///< configure streams according onMetaData @@ -54,6 +56,8 @@ typedef struct FLVContext { int validate_next; int validate_count; int searched_for_end; + + uint8_t resync_buffer[2*RESYNC_BUFFER_SIZE]; } FLVContext; static int probe(AVProbeData *p, int live) @@ -790,6 +794,36 @@ skip: return ret; } +static int resync(AVFormatContext *s) +{ + FLVContext *flv = s->priv_data; + int64_t i; + int64_t pos = avio_tell(s->pb); + + for (i=0; !avio_feof(s->pb); i++) { + int j = i & (RESYNC_BUFFER_SIZE-1); + int j1 = j + RESYNC_BUFFER_SIZE; + flv->resync_buffer[j ] = + flv->resync_buffer[j1] = avio_r8(s->pb); + + if (i > 22) { + unsigned lsize2 = AV_RB32(flv->resync_buffer + j1 - 4); + if (lsize2 >= 11 && lsize2 + 8LL < FFMIN(i, RESYNC_BUFFER_SIZE)) { + unsigned size2 = AV_RB24(flv->resync_buffer + j1 - lsize2 + 1 - 4); + unsigned lsize1 = AV_RB32(flv->resync_buffer + j1 - lsize2 - 8); + if (lsize1 >= 11 && lsize1 + 8LL + lsize2 < FFMIN(i, RESYNC_BUFFER_SIZE)) { + unsigned size1 = AV_RB24(flv->resync_buffer + j1 - lsize1 + 1 - lsize2 - 8); + if (size1 == lsize1 - 11 && size2 == lsize2 - 11) { + avio_seek(s->pb, pos + i - lsize1 - lsize2 - 8, SEEK_SET); + return 1; + } + } + } + } + } + return AVERROR_EOF; +} + static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) { FLVContext *flv = s->priv_data; @@ -802,11 +836,14 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) int av_uninit(sample_rate); AVStream *st = NULL; int last = -1; + int orig_size; +retry: /* pkt size is repeated at end. skip it */ for (;; last = avio_rb32(s->pb)) { pos = avio_tell(s->pb); type = (avio_r8(s->pb) & 0x1F); + orig_size = size = avio_rb24(s->pb); dts = avio_rb24(s->pb); dts |= avio_r8(s->pb) << 24; @@ -1089,7 +1126,16 @@ retry_duration: pkt->flags |= AV_PKT_FLAG_KEY; leave: - avio_skip(s->pb, 4); + last = avio_rb32(s->pb); + if (last != orig_size + 11) { + av_log(s, AV_LOG_ERROR, "Packet mismatch %d %d\n", last, orig_size + 11); + avio_seek(s->pb, pos + 1, SEEK_SET); + ret = resync(s); + if (ret >= 0) { + av_free_packet(pkt); + goto retry; + } + } return ret; }