|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|