From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id 3ADE84C9D0 for ; Mon, 12 May 2025 02:19:31 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 04A0768BF37; Mon, 12 May 2025 05:19:27 +0300 (EEST) Received: from fout-a3-smtp.messagingengine.com (fout-a3-smtp.messagingengine.com [103.168.172.146]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 98E1068B792 for ; Mon, 12 May 2025 05:19:20 +0300 (EEST) Received: from phl-compute-07.internal (phl-compute-07.phl.internal [10.202.2.47]) by mailfout.phl.internal (Postfix) with ESMTP id B687F1380198; Sun, 11 May 2025 22:19:19 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-07.internal (MEProxy); Sun, 11 May 2025 22:19:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jonb.org; h=cc :cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:message-id:mime-version:reply-to:subject:subject:to :to; s=fm1; t=1747016359; x=1747102759; bh=gND0wi0qV6X1dzA8jdKBn 46HYYi369EgovEgkPynyVM=; b=NfjWNpq99euAhk7B3KBhaddK3y9yBQ7zcjnhu 9CEGgAiAV9NxynlmQ94x26Hes8Ho0tt1S6ynlx6vjGbxU6jRYeWIi6UupcCyCMLF H81vXuXlHm/6PRkGGTd6QrOKPhxZ+ZFzH/Hn6CAm2lqJnV4GXKb0kWKuwZde7Vv3 af+sf301WiPsWjsg2tY55ey88WhbeLyGQSYkotXIo6KPPGH0WYHhM7/dyvZfKZkm 139uEnztF23rIQiyGbX44PWqfJcwYKbl148l1/Jy7GbaKQ75uGd7yNqBaJfrLI4q YFhAefC75TBynkQLYSTOR3CaYk5GlpmShvAs2sAyDQebeD2nw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:message-id:mime-version:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t= 1747016359; x=1747102759; bh=gND0wi0qV6X1dzA8jdKBn46HYYi369EgovE gkPynyVM=; b=AXx4uWfsayYyHLJLaeDY8S12ivE89vyS0O0zsUqrEm18VOPaVBa fPwbjyZx687Fg9QqEf2V/e2uBevhlgSIeJh73aytRCpehXLAxmN1h6PuGOs4Zb5S SlKMBJNYvEShPZUp4rbJYmYf87oGcNULs86gP97IgCZ+IdGmcCwNq8X5LTkXB2OE mvTxcwkIdz5pR5Re7Q+WILaEmRP5gS4sk4B77JhWxjmzu56HNtvlBvJAe4yedT0E ILM4sPz6KQuRKssM+W3XZ6N5LI+JhMFgZ8fCyeHnRlLx8/etxhX9Qs/vsY70aWok xbbsWRdzArfQfN3KMoTwPI06puZiovNxffg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdeftddttdegucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucenucfjughrpefhvf evufffkffoggfgsedtkeertdertddtnecuhfhrohhmpeflohhnrghthhgrnhcuuegruhgu rghniigruceojhhonhesjhhonhgsrdhorhhgqeenucggtffrrghtthgvrhhnpeevteduue evtdfhheegueffteetieffvdfhhfekgeeuheehgfejueejfedtieeufeenucevlhhushht vghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehjohhnsehjohhnsgdroh hrghdpnhgspghrtghpthhtohepvddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohep fhhfmhhpvghgqdguvghvvghlsehffhhmphgvghdrohhrghdprhgtphhtthhopehjohhnse hjohhnsgdrohhrgh X-ME-Proxy: Feedback-ID: iff8147ab:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 11 May 2025 22:19:18 -0400 (EDT) From: Jonathan Baudanza To: ffmpeg-devel@ffmpeg.org Date: Mon, 12 May 2025 11:19:15 +0900 Message-ID: <20250512021915.99855-1-jon@jonb.org> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] libavformat/rtpdec_opus Set duration field on Opus AVPacket X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Jonathan Baudanza Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: This commit will properly set the duration field of Opus AVPackets. Currently, duration is set to 0 on Opus packets from the RTP demuxer. The Ogg muxer depends on the duration field to properly compute the page granule value. Without a proper duration, the granule will be wrong, and result in negative pts values in ogg files. See oggenc.c:657 (ogg_write_packet_internal) This commit calculates using the opus_duration function, which was copied from oggparseopus.c I moved this functionality and the existing opus extradata functionality (added by me in 6c24f2b) into a new rtpdec_opus.c file. --- libavformat/Makefile | 1 + libavformat/rtpdec.c | 56 +---------------- libavformat/rtpdec_formats.h | 1 + libavformat/rtpdec_opus.c | 117 +++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 55 deletions(-) create mode 100644 libavformat/rtpdec_opus.c diff --git a/libavformat/Makefile b/libavformat/Makefile index 6c9992adab..ee68345858 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -62,6 +62,7 @@ OBJS-$(CONFIG_RTPDEC) += rdt.o \ rtpdec_mpeg12.o \ rtpdec_mpeg4.o \ rtpdec_mpegts.o \ + rtpdec_opus.o \ rtpdec_qcelp.o \ rtpdec_qdm2.o \ rtpdec_qt.o \ diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index a7d5a79a83..5eff1552f0 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -61,12 +61,6 @@ static const RTPDynamicProtocolHandler speex_dynamic_handler = { .codec_id = AV_CODEC_ID_SPEEX, }; -static const RTPDynamicProtocolHandler opus_dynamic_handler = { - .enc_name = "opus", - .codec_type = AVMEDIA_TYPE_AUDIO, - .codec_id = AV_CODEC_ID_OPUS, -}; - static const RTPDynamicProtocolHandler t140_dynamic_handler = { /* RFC 4103 */ .enc_name = "t140", .codec_type = AVMEDIA_TYPE_SUBTITLE, @@ -125,7 +119,7 @@ static const RTPDynamicProtocolHandler *const rtp_dynamic_protocol_handler_list[ &ff_vp9_dynamic_handler, &gsm_dynamic_handler, &l24_dynamic_handler, - &opus_dynamic_handler, + &ff_opus_dynamic_handler, &realmedia_mp3_dynamic_handler, &speex_dynamic_handler, &t140_dynamic_handler, @@ -531,43 +525,6 @@ int ff_rtp_send_rtcp_feedback(RTPDemuxContext *s, URLContext *fd, return 0; } -static int opus_write_extradata(AVCodecParameters *codecpar) -{ - uint8_t *bs; - int ret; - - /* This function writes an extradata with a channel mapping family of 0. - * This mapping family only supports mono and stereo layouts. And RFC7587 - * specifies that the number of channels in the SDP must be 2. - */ - if (codecpar->ch_layout.nb_channels > 2) { - return AVERROR_INVALIDDATA; - } - - ret = ff_alloc_extradata(codecpar, 19); - if (ret < 0) - return ret; - - bs = (uint8_t *)codecpar->extradata; - - /* Opus magic */ - bytestream_put_buffer(&bs, "OpusHead", 8); - /* Version */ - bytestream_put_byte (&bs, 0x1); - /* Channel count */ - bytestream_put_byte (&bs, codecpar->ch_layout.nb_channels); - /* Pre skip */ - bytestream_put_le16 (&bs, 0); - /* Input sample rate */ - bytestream_put_le32 (&bs, 48000); - /* Output gain */ - bytestream_put_le16 (&bs, 0x0); - /* Mapping family */ - bytestream_put_byte (&bs, 0x0); - - return 0; -} - /** * open a new RTP parse context for stream 'st'. 'st' can be NULL for * MPEG-2 TS streams. @@ -576,7 +533,6 @@ RTPDemuxContext *ff_rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type, int queue_size) { RTPDemuxContext *s; - int ret; s = av_mallocz(sizeof(RTPDemuxContext)); if (!s) @@ -600,16 +556,6 @@ RTPDemuxContext *ff_rtp_parse_open(AVFormatContext *s1, AVStream *st, if (st->codecpar->sample_rate == 8000) st->codecpar->sample_rate = 16000; break; - case AV_CODEC_ID_OPUS: - ret = opus_write_extradata(st->codecpar); - if (ret < 0) { - av_log(s1, AV_LOG_ERROR, - "Error creating opus extradata: %s\n", - av_err2str(ret)); - av_free(s); - return NULL; - } - break; default: break; } diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h index 72a8f16a90..1ff2a72d2a 100644 --- a/libavformat/rtpdec_formats.h +++ b/libavformat/rtpdec_formats.h @@ -77,6 +77,7 @@ extern const RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler; extern const RTPDynamicProtocolHandler ff_mpegts_dynamic_handler; extern const RTPDynamicProtocolHandler ff_ms_rtp_asf_pfa_handler; extern const RTPDynamicProtocolHandler ff_ms_rtp_asf_pfv_handler; +extern const RTPDynamicProtocolHandler ff_opus_dynamic_handler; extern const RTPDynamicProtocolHandler ff_qcelp_dynamic_handler; extern const RTPDynamicProtocolHandler ff_qdm2_dynamic_handler; extern const RTPDynamicProtocolHandler ff_qt_rtp_aud_handler; diff --git a/libavformat/rtpdec_opus.c b/libavformat/rtpdec_opus.c new file mode 100644 index 0000000000..1588f6d715 --- /dev/null +++ b/libavformat/rtpdec_opus.c @@ -0,0 +1,117 @@ +/* + * RTP Depacketization of Opus, RFC 7587 + * Copyright (c) 2025 Jonathan Baudanza + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/bytestream.h" +#include "libavutil/mem.h" +#include "rtpdec_formats.h" +#include "internal.h" + +static int opus_duration(const uint8_t *src, int size) +{ + unsigned nb_frames = 1; + unsigned toc = src[0]; + unsigned toc_config = toc >> 3; + unsigned toc_count = toc & 3; + unsigned frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) : + toc_config < 16 ? 480 << (toc_config & 1) : + 120 << (toc_config & 3); + if (toc_count == 3) { + if (size<2) + return AVERROR_INVALIDDATA; + nb_frames = src[1] & 0x3F; + } else if (toc_count) { + nb_frames = 2; + } + + return frame_size * nb_frames; +} + +static int opus_write_extradata(AVCodecParameters *codecpar) +{ + uint8_t *bs; + int ret; + + /* This function writes an extradata with a channel mapping family of 0. + * This mapping family only supports mono and stereo layouts. And RFC7587 + * specifies that the number of channels in the SDP must be 2. + */ + if (codecpar->ch_layout.nb_channels > 2) { + return AVERROR_INVALIDDATA; + } + + ret = ff_alloc_extradata(codecpar, 19); + if (ret < 0) + return ret; + + bs = (uint8_t *)codecpar->extradata; + + /* Opus magic */ + bytestream_put_buffer(&bs, "OpusHead", 8); + /* Version */ + bytestream_put_byte (&bs, 0x1); + /* Channel count */ + bytestream_put_byte (&bs, codecpar->ch_layout.nb_channels); + /* Pre skip */ + bytestream_put_le16 (&bs, 0); + /* Input sample rate */ + bytestream_put_le32 (&bs, 48000); + /* Output gain */ + bytestream_put_le16 (&bs, 0x0); + /* Mapping family */ + bytestream_put_byte (&bs, 0x0); + + return 0; +} + +static int opus_init(AVFormatContext *s, int st_index, PayloadContext *priv_data) +{ + return opus_write_extradata(s->streams[st_index]->codecpar); +} + +static int opus_parse_packet(AVFormatContext *ctx, PayloadContext *data, + AVStream *st, AVPacket *pkt, uint32_t *timestamp, + const uint8_t *buf, int len, uint16_t seq, + int flags) +{ + int rv; + int duration; + + if ((rv = av_new_packet(pkt, len)) < 0) + return rv; + + memcpy(pkt->data, buf, len); + pkt->stream_index = st->index; + + duration = opus_duration(buf, len); + if (duration != AVERROR_INVALIDDATA) { + pkt->duration = duration; + } + + return 0; +} + +const RTPDynamicProtocolHandler ff_opus_dynamic_handler = { + .enc_name = "opus", + .codec_type = AVMEDIA_TYPE_AUDIO, + .codec_id = AV_CODEC_ID_OPUS, + .parse_packet = opus_parse_packet, + .init = opus_init, +}; -- 2.41.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".