This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 3ab8b976c186f68b43dc2cae081453d69a7e8c55 Author: James Almer <[email protected]> AuthorDate: Mon Feb 2 22:56:49 2026 -0300 Commit: James Almer <[email protected]> CommitDate: Thu Feb 5 23:21:49 2026 -0300 avformat/matroskaenc: parse Opus packets to write proper durations Before this patch, the last packet in the affected fate test would be written without a BlockDuration element despite the packet's duration being shorter than the Opus frame size. Signed-off-by: James Almer <[email protected]> --- libavformat/matroskaenc.c | 36 ++++++++++++++++++++++++++++++++-- tests/ref/fate/matroska-ogg-opus-remux | 6 +++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 50188c396c..ceecb5f2ca 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -69,6 +69,7 @@ #include "libavcodec/itut35.h" #include "libavcodec/xiph.h" #include "libavcodec/mpeg4audio.h" +#include "libavcodec/opus/parse.h" /* Level 1 elements we create a SeekHead entry for: * Info, Tracks, Chapters, Attachments, Tags (potentially twice) and Cues */ @@ -209,6 +210,10 @@ typedef struct mkv_track { * The callback shall not return an error on the second call. */ int (*reformat)(struct MatroskaMuxContext *, AVIOContext *, const AVPacket *, int *size); + + // Opus specific + OpusParseContext *opus; + OpusPacket *opus_pkt; } mkv_track; typedef struct MatroskaMuxContext { @@ -859,6 +864,14 @@ static void mkv_deinit(AVFormatContext *s) av_freep(&mkv->cur_block.h2645_nalu_list.nalus); av_freep(&mkv->cues.entries); + + for (int i = 0; i < s->nb_streams; i++) { + mkv_track *track = &mkv->tracks[i]; + if (track->opus) + avpriv_opus_parse_uninit_context(track->opus); + av_freep(&track->opus); + av_freep(&track->opus_pkt); + } av_freep(&mkv->tracks); } @@ -2799,11 +2812,12 @@ static void mkv_write_blockadditional(EbmlWriter *writer, const uint8_t *buf, } static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv, - AVIOContext *pb, const AVCodecParameters *par, + AVIOContext *pb, const AVStream *st, mkv_track *track, const AVPacket *pkt, int keyframe, int64_t ts, uint64_t duration, int force_blockgroup, int64_t relative_packet_pos) { + const AVCodecParameters *par = st->codecpar; uint8_t t35_buf[6 + AV_HDR_PLUS_MAX_PAYLOAD_SIZE]; uint8_t *side_data; size_t side_data_size; @@ -2829,6 +2843,19 @@ static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv, duration != track->default_duration_high && duration != track->default_duration_low)) ebml_writer_add_uint(&writer, MATROSKA_ID_BLOCKDURATION, duration); + else if (track->opus) { + ret = avpriv_opus_parse_packet(&track->opus_pkt, pkt->data, pkt->size, + track->opus->nb_streams > 1, logctx); + if (!ret) { + /* If the packet's duration is inconsistent with the coded duration, + * add an explicit duration element. */ + uint64_t parsed_duration = av_rescale_q(track->opus_pkt->frame_count * track->opus_pkt->frame_duration, + (AVRational){1, par->sample_rate}, + st->time_base); + if (parsed_duration != duration) + ebml_writer_add_uint(&writer, MATROSKA_ID_BLOCKDURATION, duration); + } + } av_log(logctx, AV_LOG_DEBUG, "Writing block of size %d with pts %" PRId64 ", dts %" PRId64 ", " @@ -2999,6 +3026,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt) { MatroskaMuxContext *mkv = s->priv_data; AVIOContext *pb; + AVStream *st = s->streams[pkt->stream_index]; AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; mkv_track *track = &mkv->tracks[pkt->stream_index]; int is_sub = par->codec_type == AVMEDIA_TYPE_SUBTITLE; @@ -3045,7 +3073,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt) /* The WebM spec requires WebVTT to be muxed in BlockGroups; * so we force it even for packets without duration. */ - ret = mkv_write_block(s, mkv, pb, par, track, pkt, + ret = mkv_write_block(s, mkv, pb, st, track, pkt, keyframe, ts, duration, par->codec_id == AV_CODEC_ID_WEBVTT, relative_packet_pos); @@ -3467,6 +3495,10 @@ static int mkv_init(struct AVFormatContext *s) case AV_CODEC_ID_WEBVTT: track->reformat = webm_reformat_vtt; break; + case AV_CODEC_ID_OPUS: + avpriv_opus_parse_extradata(&track->opus, par->extradata, par->extradata_size, + par->ch_layout.nb_channels, s); + break; } if (s->flags & AVFMT_FLAG_BITEXACT) { diff --git a/tests/ref/fate/matroska-ogg-opus-remux b/tests/ref/fate/matroska-ogg-opus-remux index 6e0d91a2d4..600083c134 100644 --- a/tests/ref/fate/matroska-ogg-opus-remux +++ b/tests/ref/fate/matroska-ogg-opus-remux @@ -1,5 +1,5 @@ -87d0185c5b780dd9509aafd957236bdd *tests/data/fate/matroska-ogg-opus-remux.matroska -10203 tests/data/fate/matroska-ogg-opus-remux.matroska +c8596f7b31a8b6693f53759942c3754f *tests/data/fate/matroska-ogg-opus-remux.matroska +10206 tests/data/fate/matroska-ogg-opus-remux.matroska #extradata 0: 19, 0x399c0471 #tb 0: 1/1000 #media_type 0: audio @@ -46,7 +46,7 @@ 0, 733, 733, 20, 219, 0xe2906c62 0, 753, 753, 20, 217, 0xcf316ba1 0, 773, 773, 20, 217, 0x470b6eea -0, 793, 793, 20, 359, 0x36c2a18a, S=1, Skip Samples, 10, 0x0232005e +0, 793, 793, 7, 359, 0x36c2a18a, S=1, Skip Samples, 10, 0x0232005e [PACKET] codec_type=audio stream_index=0 _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
