You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-10 06:10:52 +02:00
avformat/flvdec: support all multi-track modes
This commit is contained in:
@@ -1275,6 +1275,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
{
|
{
|
||||||
FLVContext *flv = s->priv_data;
|
FLVContext *flv = s->priv_data;
|
||||||
int ret, i, size, flags;
|
int ret, i, size, flags;
|
||||||
|
int res = 0;
|
||||||
enum FlvTagType type;
|
enum FlvTagType type;
|
||||||
int stream_type=-1;
|
int stream_type=-1;
|
||||||
int64_t next, pos, meta_pos;
|
int64_t next, pos, meta_pos;
|
||||||
@@ -1289,6 +1290,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
int pkt_type = 0;
|
int pkt_type = 0;
|
||||||
uint8_t track_idx = 0;
|
uint8_t track_idx = 0;
|
||||||
uint32_t codec_id = 0;
|
uint32_t codec_id = 0;
|
||||||
|
int multitrack_type = MultitrackTypeOneTrack;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
/* pkt size is repeated at end. skip it */
|
/* pkt size is repeated at end. skip it */
|
||||||
@@ -1339,14 +1341,9 @@ retry:
|
|||||||
|
|
||||||
if (pkt_type == AudioPacketTypeMultitrack) {
|
if (pkt_type == AudioPacketTypeMultitrack) {
|
||||||
uint8_t types = avio_r8(s->pb);
|
uint8_t types = avio_r8(s->pb);
|
||||||
int multitrack_type = types >> 4;
|
multitrack_type = types & 0xF0;
|
||||||
pkt_type = types & 0xF;
|
pkt_type = types & 0xF;
|
||||||
|
|
||||||
if (multitrack_type != MultitrackTypeOneTrack) {
|
|
||||||
av_log(s, AV_LOG_ERROR, "Audio multitrack types other than MultitrackTypeOneTrack are unsupported!\n");
|
|
||||||
return AVERROR_PATCHWELCOME;
|
|
||||||
}
|
|
||||||
|
|
||||||
multitrack = 1;
|
multitrack = 1;
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
@@ -1373,14 +1370,9 @@ retry:
|
|||||||
|
|
||||||
if (pkt_type == PacketTypeMultitrack) {
|
if (pkt_type == PacketTypeMultitrack) {
|
||||||
uint8_t types = avio_r8(s->pb);
|
uint8_t types = avio_r8(s->pb);
|
||||||
int multitrack_type = types >> 4;
|
multitrack_type = types & 0xF0;
|
||||||
pkt_type = types & 0xF;
|
pkt_type = types & 0xF;
|
||||||
|
|
||||||
if (multitrack_type != MultitrackTypeOneTrack) {
|
|
||||||
av_log(s, AV_LOG_ERROR, "Multitrack types other than MultitrackTypeOneTrack are unsupported!\n");
|
|
||||||
return AVERROR_PATCHWELCOME;
|
|
||||||
}
|
|
||||||
|
|
||||||
multitrack = 1;
|
multitrack = 1;
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
@@ -1449,6 +1441,14 @@ skip:
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int track_size = size;
|
||||||
|
|
||||||
|
if (multitrack_type != MultitrackTypeOneTrack) {
|
||||||
|
track_size = avio_rb24(s->pb);
|
||||||
|
size -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
/* now find stream */
|
/* now find stream */
|
||||||
for (i = 0; i < s->nb_streams; i++) {
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
st = s->streams[i];
|
st = s->streams[i];
|
||||||
@@ -1485,7 +1485,7 @@ skip:
|
|||||||
if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
|
if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
|
||||||
((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY ||
|
((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY ||
|
||||||
stream_type == FLV_STREAM_TYPE_AUDIO))
|
stream_type == FLV_STREAM_TYPE_AUDIO))
|
||||||
av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME);
|
av_add_index_entry(st, pos, dts, track_size, 0, AVINDEX_KEYFRAME);
|
||||||
|
|
||||||
if ((st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || stream_type == FLV_STREAM_TYPE_AUDIO)) ||
|
if ((st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || stream_type == FLV_STREAM_TYPE_AUDIO)) ||
|
||||||
(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && stream_type == FLV_STREAM_TYPE_VIDEO)) ||
|
(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && stream_type == FLV_STREAM_TYPE_VIDEO)) ||
|
||||||
@@ -1573,6 +1573,7 @@ retry_duration:
|
|||||||
int channel_order = avio_r8(s->pb);
|
int channel_order = avio_r8(s->pb);
|
||||||
channels = avio_r8(s->pb);
|
channels = avio_r8(s->pb);
|
||||||
size -= 2;
|
size -= 2;
|
||||||
|
track_size -= 2;
|
||||||
|
|
||||||
av_channel_layout_uninit(&st->codecpar->ch_layout);
|
av_channel_layout_uninit(&st->codecpar->ch_layout);
|
||||||
|
|
||||||
@@ -1597,6 +1598,7 @@ retry_duration:
|
|||||||
} else if (channel_order == AudioChannelOrderNative) {
|
} else if (channel_order == AudioChannelOrderNative) {
|
||||||
uint64_t mask = avio_rb32(s->pb);
|
uint64_t mask = avio_rb32(s->pb);
|
||||||
size -= 4;
|
size -= 4;
|
||||||
|
track_size -= 4;
|
||||||
|
|
||||||
// The first 18 entries in the mask match ours, but the remaining 6 entries start at AV_CHAN_LOW_FREQUENCY_2
|
// The first 18 entries in the mask match ours, but the remaining 6 entries start at AV_CHAN_LOW_FREQUENCY_2
|
||||||
mask = (mask & 0x3FFFF) | ((mask & 0xFC0000) << (AV_CHAN_LOW_FREQUENCY_2 - 18));
|
mask = (mask & 0x3FFFF) | ((mask & 0xFC0000) << (AV_CHAN_LOW_FREQUENCY_2 - 18));
|
||||||
@@ -1616,6 +1618,7 @@ retry_duration:
|
|||||||
if (sret < 0)
|
if (sret < 0)
|
||||||
return sret;
|
return sret;
|
||||||
size -= sret;
|
size -= sret;
|
||||||
|
track_size -= sret;
|
||||||
} else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) {
|
} else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) {
|
||||||
st->codecpar->codec_id = AV_CODEC_ID_TEXT;
|
st->codecpar->codec_id = AV_CODEC_ID_TEXT;
|
||||||
} else if (stream_type == FLV_STREAM_TYPE_DATA) {
|
} else if (stream_type == FLV_STREAM_TYPE_DATA) {
|
||||||
@@ -1636,9 +1639,10 @@ retry_duration:
|
|||||||
} else {
|
} else {
|
||||||
type = avio_r8(s->pb);
|
type = avio_r8(s->pb);
|
||||||
size--;
|
size--;
|
||||||
|
track_size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size < 0) {
|
if (size < 0 || track_size < 0) {
|
||||||
ret = AVERROR_INVALIDDATA;
|
ret = AVERROR_INVALIDDATA;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@@ -1665,6 +1669,7 @@ retry_duration:
|
|||||||
dts = pts = AV_NOPTS_VALUE;
|
dts = pts = AV_NOPTS_VALUE;
|
||||||
}
|
}
|
||||||
size -= 3;
|
size -= 3;
|
||||||
|
track_size -= 3;
|
||||||
}
|
}
|
||||||
if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
|
if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
|
||||||
st->codecpar->codec_id == AV_CODEC_ID_OPUS || st->codecpar->codec_id == AV_CODEC_ID_FLAC ||
|
st->codecpar->codec_id == AV_CODEC_ID_OPUS || st->codecpar->codec_id == AV_CODEC_ID_FLAC ||
|
||||||
@@ -1673,12 +1678,12 @@ retry_duration:
|
|||||||
AVDictionaryEntry *t;
|
AVDictionaryEntry *t;
|
||||||
|
|
||||||
if (st->codecpar->extradata) {
|
if (st->codecpar->extradata) {
|
||||||
if ((ret = flv_queue_extradata(flv, s->pb, multitrack ? track_idx : stream_type, size, multitrack)) < 0)
|
if ((ret = flv_queue_extradata(flv, s->pb, multitrack ? track_idx : stream_type, track_size, multitrack)) < 0)
|
||||||
return ret;
|
return ret;
|
||||||
ret = FFERROR_REDO;
|
ret = FFERROR_REDO;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
if ((ret = flv_get_extradata(s, st, size)) < 0)
|
if ((ret = flv_get_extradata(s, st, track_size)) < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Workaround for buggy Omnia A/XE encoder */
|
/* Workaround for buggy Omnia A/XE encoder */
|
||||||
@@ -1691,34 +1696,42 @@ retry_duration:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip empty data packets */
|
/* skip empty or broken data packets */
|
||||||
if (!size) {
|
if (size <= 0 || track_size < 0) {
|
||||||
ret = FFERROR_REDO;
|
ret = FFERROR_REDO;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = av_get_packet(s->pb, pkt, size);
|
/* skip empty data track */
|
||||||
|
if (!track_size)
|
||||||
|
goto next_track;
|
||||||
|
|
||||||
|
ret = av_get_packet(s->pb, pkt, track_size);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
track_size -= ret;
|
||||||
|
size -= ret;
|
||||||
|
|
||||||
pkt->dts = dts;
|
pkt->dts = dts;
|
||||||
pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts;
|
pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts;
|
||||||
pkt->stream_index = st->index;
|
pkt->stream_index = st->index;
|
||||||
pkt->pos = pos;
|
pkt->pos = pos;
|
||||||
if (!multitrack && flv->new_extradata[stream_type]) {
|
if (!multitrack && flv->new_extradata[stream_type]) {
|
||||||
int sret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
|
ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
|
||||||
flv->new_extradata[stream_type],
|
flv->new_extradata[stream_type],
|
||||||
flv->new_extradata_size[stream_type]);
|
flv->new_extradata_size[stream_type]);
|
||||||
if (sret >= 0) {
|
if (ret >= 0) {
|
||||||
flv->new_extradata[stream_type] = NULL;
|
flv->new_extradata[stream_type] = NULL;
|
||||||
flv->new_extradata_size[stream_type] = 0;
|
flv->new_extradata_size[stream_type] = 0;
|
||||||
}
|
}
|
||||||
} else if (multitrack &&
|
} else if (multitrack &&
|
||||||
flv->mt_extradata_cnt > track_idx &&
|
flv->mt_extradata_cnt > track_idx &&
|
||||||
flv->mt_extradata[track_idx]) {
|
flv->mt_extradata[track_idx]) {
|
||||||
int sret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
|
ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
|
||||||
flv->mt_extradata[track_idx],
|
flv->mt_extradata[track_idx],
|
||||||
flv->mt_extradata_sz[track_idx]);
|
flv->mt_extradata_sz[track_idx]);
|
||||||
if (sret >= 0) {
|
if (ret >= 0) {
|
||||||
flv->mt_extradata[track_idx] = NULL;
|
flv->mt_extradata[track_idx] = NULL;
|
||||||
flv->mt_extradata_sz[track_idx] = 0;
|
flv->mt_extradata_sz[track_idx] = 0;
|
||||||
}
|
}
|
||||||
@@ -1737,6 +1750,42 @@ retry_duration:
|
|||||||
stream_type == FLV_STREAM_TYPE_DATA)
|
stream_type == FLV_STREAM_TYPE_DATA)
|
||||||
pkt->flags |= AV_PKT_FLAG_KEY;
|
pkt->flags |= AV_PKT_FLAG_KEY;
|
||||||
|
|
||||||
|
ret = ff_buffer_packet(s, pkt);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
res = FFERROR_REDO;
|
||||||
|
|
||||||
|
if (track_size) {
|
||||||
|
av_log(s, AV_LOG_WARNING, "Track size mismatch: %d!\n", track_size);
|
||||||
|
avio_skip(s->pb, track_size);
|
||||||
|
size -= track_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
next_track:
|
||||||
|
if (multitrack_type == MultitrackTypeOneTrack) {
|
||||||
|
av_log(s, AV_LOG_ERROR, "Attempted to read next track in single-track mode.\n");
|
||||||
|
ret = FFERROR_REDO;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multitrack_type == MultitrackTypeManyTracksManyCodecs) {
|
||||||
|
codec_id = avio_rb32(s->pb);
|
||||||
|
size -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
track_idx = avio_r8(s->pb);
|
||||||
|
size--;
|
||||||
|
|
||||||
|
if (avio_feof(s->pb)) {
|
||||||
|
av_log(s, AV_LOG_WARNING, "Premature EOF\n");
|
||||||
|
/* return REDO so that any potentially queued up packages can be drained first */
|
||||||
|
return FFERROR_REDO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
last = avio_rb32(s->pb);
|
last = avio_rb32(s->pb);
|
||||||
if (!flv->trust_datasize) {
|
if (!flv->trust_datasize) {
|
||||||
@@ -1757,7 +1806,7 @@ leave:
|
|||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
flv->last_ts = pkt->dts;
|
flv->last_ts = pkt->dts;
|
||||||
|
|
||||||
return ret;
|
return ret ? ret : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flv_read_seek(AVFormatContext *s, int stream_index,
|
static int flv_read_seek(AVFormatContext *s, int stream_index,
|
||||||
|
Reference in New Issue
Block a user