summaryrefslogtreecommitdiff
path: root/libavformat/flvdec.c
diff options
context:
space:
mode:
authorMichael Niedermayer <michael@niedermayer.cc>2015-09-16 01:58:10 +0200
committerMichael Niedermayer <michael@niedermayer.cc>2015-09-16 03:43:21 +0200
commitcbbd906be6150be38dfc14b6bc67dcac8da8aea4 (patch)
treeef0fe1438461d405d4a9dea560de7351a8f2abce /libavformat/flvdec.c
parente01ad950bb1beb86add6ba5c38f4a10caac29f62 (diff)
downloadffmpeg-cbbd906be6150be38dfc14b6bc67dcac8da8aea4.tar.gz
avformat/flvdec: Check that sizes match and resync if not
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Diffstat (limited to 'libavformat/flvdec.c')
-rw-r--r--libavformat/flvdec.c48
1 files changed, 47 insertions, 1 deletions
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;
}