diff options
author | Lynne <dev@lynne.ee> | 2020-04-28 12:25:46 +0100 |
---|---|---|
committer | Lynne <dev@lynne.ee> | 2020-04-30 23:05:51 +0100 |
commit | 8296443a70f052a6f5c9a867d28b83a5eb7d304d (patch) | |
tree | dc89608a38d95e1c15b2a531a8bac196446a321c /libavformat/oggdec.c | |
parent | e983197cbc93420b67aa7e811be47d7278c2c8a2 (diff) | |
download | ffmpeg-8296443a70f052a6f5c9a867d28b83a5eb7d304d.tar.gz |
oggdec: add support for proper demuxing of chained Opus files and streams
Part of this patch is based on Paul B Mahol's patch from last year.
This also allows for single-stream parameter/codec changes.
Diffstat (limited to 'libavformat/oggdec.c')
-rw-r--r-- | libavformat/oggdec.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index 92dcafe2ed..c591bafddd 100644 --- a/libavformat/oggdec.c +++ b/libavformat/oggdec.c @@ -178,6 +178,7 @@ static int ogg_reset(AVFormatContext *s) if (start_pos <= s->internal->data_offset) { os->lastpts = 0; } + os->start_trimming = 0; os->end_trimming = 0; av_freep(&os->new_metadata); os->new_metadata_size = 0; @@ -206,7 +207,8 @@ static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size) * situation where a new audio stream spawn (identified with a new serial) and * must replace the previous one (track switch). */ -static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, char *magic) +static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, char *magic, + int probing) { struct ogg *ogg = s->priv_data; struct ogg_stream *os; @@ -220,24 +222,25 @@ static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, char *magic) /* Check for codecs */ codec = ogg_find_codec(magic, 8); - if (!codec) { + if (!codec && !probing) { av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n"); return AVERROR_INVALIDDATA; } - /* If the codec matches, then we assume its a replacement */ - for (i = 0; i < ogg->nstreams; i++) { - if (ogg->streams[i].codec == codec) - break; - } - - /* Otherwise, create a new stream */ - if (i >= ogg->nstreams) - return ogg_new_stream(s, serial); - - os = &ogg->streams[i]; - os->serial = serial; - os->codec = codec; + /* We only have a single stream anyway, so if there's a new stream with + * a different codec just replace it */ + os = &ogg->streams[0]; + os->serial = serial; + os->codec = codec; + os->serial = serial; + os->lastpts = 0; + os->lastdts = 0; + os->start_trimming = 0; + os->end_trimming = 0; + + /* Chained files have extradata as a new packet */ + if (codec == &ff_opus_codec) + os->header = -1; return i; } @@ -294,7 +297,7 @@ static int data_packets_seen(const struct ogg *ogg) return 0; } -static int ogg_read_page(AVFormatContext *s, int *sid) +static int ogg_read_page(AVFormatContext *s, int *sid, int probing) { AVIOContext *bc = s->pb; struct ogg *ogg = s->priv_data; @@ -417,7 +420,7 @@ static int ogg_read_page(AVFormatContext *s, int *sid) /* CRC is correct so we can be 99% sure there's an actual change here */ if (idx < 0) { if (data_packets_seen(ogg)) - idx = ogg_replace_stream(s, serial, readout_buf); + idx = ogg_replace_stream(s, serial, readout_buf, probing); else idx = ogg_new_stream(s, serial); @@ -492,7 +495,7 @@ static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize, idx = ogg->curidx; while (idx < 0) { - ret = ogg_read_page(s, &idx); + ret = ogg_read_page(s, &idx, 0); if (ret < 0) return ret; } @@ -643,7 +646,7 @@ static int ogg_get_length(AVFormatContext *s) avio_seek(s->pb, end, SEEK_SET); ogg->page_pos = -1; - while (!ogg_read_page(s, &i)) { + while (!ogg_read_page(s, &i, 1)) { if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && ogg->streams[i].codec) { s->streams[i]->duration = @@ -847,13 +850,15 @@ retry: pkt->duration = os->pduration; pkt->pos = fpos; - if (os->end_trimming) { + if (os->start_trimming || os->end_trimming) { uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); if(!side_data) return AVERROR(ENOMEM); + AV_WL32(side_data + 0, os->start_trimming); AV_WL32(side_data + 4, os->end_trimming); + os->start_trimming = 0; os->end_trimming = 0; } |