From patchwork Mon Oct 3 22:45:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Rheinhardt X-Patchwork-Id: 38545 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:3b1c:b0:96:9ee8:5cfd with SMTP id c28csp1575599pzh; Mon, 3 Oct 2022 15:46:36 -0700 (PDT) X-Google-Smtp-Source: AMsMyM7SSjZdx8khOROlEb896uGi9v0eVzGvrWXuALg5fND66XJEdycMEoZHsSpcOOPe4RyK3fYD X-Received: by 2002:a17:907:75dc:b0:783:9c71:5e20 with SMTP id jl28-20020a17090775dc00b007839c715e20mr17007162ejc.125.1664837195874; Mon, 03 Oct 2022 15:46:35 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id qw40-20020a1709066a2800b0078bdc4ee034si3496262ejc.701.2022.10.03.15.46.35; Mon, 03 Oct 2022 15:46:35 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@outlook.com header.s=selector1 header.b=MMptekdD; arc=fail (body hash mismatch); spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=outlook.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 528B168B61C; Tue, 4 Oct 2022 01:46:33 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from EUR03-DBA-obe.outbound.protection.outlook.com (mail-dbaeur03olkn2083.outbound.protection.outlook.com [40.92.58.83]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 5317C68B61C for ; Tue, 4 Oct 2022 01:46:27 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=mFGLV33nVaR5roEUYggYZpRA0eU2GBaklTYz8JE/yJS0vH1lr4DT6v2GnxDHUgKIoUCDHIDEET+5UobkH80aRL71T0zpMYIgtE5kr3NrOqMIGvnxzlAU2cKxX3WtvtJckLakhQqSv+EtJloSDxy1ymT+gqCroHbfqExovNdGDiRRYPvYoyczlJU9/KTpgaH6SGNM1OlnyVQYNpStLC8i0U//a2kBl80AcETU9q/IPP9h0NKyuV1WSYMiKszd1DIkaxFpXKUHOUzx2/bsxXDZpR1krAS5DChdcL/jeQdd479+2KjF2i/gg5/Vci8CKB+tx5HzNwJEzfQDPOrjOVDvIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=eRScGwHQT1eIYeD6GuQRAirwO2IyJlNSNK0xo0ZnfAk=; b=KNltQqp+Mvtz+Q/bmTbeGRBvKL3coGvw/3T0eHf96vJIAtCUg1ZKsL0+SYENBofyuxReRrjZmmWx/XIGVt6I5o2+9qSjX6JIy+JY0OSXepdtg+HAVfu/PDd5+CTMNuuylL9BOPENc1jxeghgiy6gpPEb9DFrTV3yNlU5J9aqLtEib2brNCBEtwlXHqCgAeXX29U13VsS9IofxgAE0lEHlnZUlm+CDA5VggFGzVz9sk14hl7v9B9abl3LEi42iZItvVy3f82aLGr8El1XhAvFfWtzJabSGAefvOFUK/GchMfVn2G339LwHUai5XSTaKUV6JAjKpnqQbFXLN781yV4Ug== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=eRScGwHQT1eIYeD6GuQRAirwO2IyJlNSNK0xo0ZnfAk=; b=MMptekdD+0/9cdsfJKGXovYcU5Q0pcu/M5bgDQSJ4TOpBaJspVo4MgQb6hTXO6+BWtT3wh1V7OYlV4j4KBZK70FvdTebyHczx+FQ5RwRQ0NE7vkedl+SllkkDYYcGgzRh1nouA6IjOLYu2OYzkuea7utfPbfhG1MULeQzb2oQc0CP8CEZuAtQu17FRR9Kq+j1XSQWT8NK9oQ6pKZ35NcP/EUUArO56OAvFX6cHIKX9xUIugzdCIrqt95/qdXye0S3hoYoKEBE3DYYSyZeI0t9eEuxpH8JpmDXFunvHyxQlmt7RTEKI8PrDqNJxFypPjon6Yc+OUG55kkfFSSuEt3mA== Received: from GV1P250MB0737.EURP250.PROD.OUTLOOK.COM (2603:10a6:150:8e::17) by PAXP250MB0470.EURP250.PROD.OUTLOOK.COM (2603:10a6:102:283::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23; Mon, 3 Oct 2022 22:46:25 +0000 Received: from GV1P250MB0737.EURP250.PROD.OUTLOOK.COM ([fe80::68bd:2fc7:ac52:38f8]) by GV1P250MB0737.EURP250.PROD.OUTLOOK.COM ([fe80::68bd:2fc7:ac52:38f8%9]) with mapi id 15.20.5676.023; Mon, 3 Oct 2022 22:46:25 +0000 From: Andreas Rheinhardt To: ffmpeg-devel@ffmpeg.org Date: Tue, 4 Oct 2022 00:45:00 +0200 Message-ID: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: X-TMN: [hlyRQAOBqc70Wgchg2x5KmyQfDUjDpZTmy0rV0PUpV8=] X-ClientProxiedBy: ZR0P278CA0056.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:21::7) To GV1P250MB0737.EURP250.PROD.OUTLOOK.COM (2603:10a6:150:8e::17) X-Microsoft-Original-Message-ID: <20221003224505.1846824-3-andreas.rheinhardt@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: GV1P250MB0737:EE_|PAXP250MB0470:EE_ X-MS-Office365-Filtering-Correlation-Id: ef0414c4-7b42-4683-9d12-08daa59119c0 X-MS-Exchange-SLBlob-MailProps: EgT5Wr3QDKyycDCnlURLUH4o9GEGbtto7uzK3cPCVLVelpng+9wKtmGAco8qePmhNjSMEd7UWyxzPzPmfoaIYBD28xLRPspeoGa/njsUPmMwzzZwGkjqQJl5pfAOhsIOJaD2S9yXeN6SgbOgObPaMRAcG7MUjyTAMORqfQCmWoevakD01tNQxYb822QgIQVJ0LZP1mDD3IpSXNuawQ23trM50u3scs1wayZMHC/ByVn665nFhIxrQWyuRtBqsl/1TjSCX/+lSEugQrXohe4wKFb5M4HZ/wyorrvkbc0W9p0QI0uZt1+OZ3kL4i3fjwT7iGH9DgoCPPUteTzt64+ZMD48lEXlTTOHWm3fhLRWlgVDwEs8jP3mlQCM9/KcpRxlz6LkjmLe+0iZ6f8iTnPoAjtviFWiDxB/+KSgZRvyZ9luX3ncvg9Gc00wEGiO1R1ekoUa1258sUw+U4BLe6jqCj6DSBeeS0e/7mqlImMn0lDFY2wLjS3qDsn8tq3cmYF1MJXCjIAKZ9uRrWnTqu/x1pVSGhvzAkN8rM+50T2Pnj8Q0/U1IESTFpdkMcD26SRluu5ICQOn4x7bYf5m+4kvI1aVwxDeDr2V67uunkhoNwDJgwifCzE2qs96zxzSm0YZJBnvvLMqq61Rzl4p1JhbkgcqA+9x1stWLCweSGeL3RNaq/rX8H0YjzneqSZfBPABOTXedbH1xNeYfYNxYitqX8514jUchv2+4hqnjmGaWuo= X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: yO2HgE8w9RIPyTqJeHeY4I9gIRBSAFP9t99EVDkZUcgQqiIHiJt1Dg97Z1F/bggDPCDgSbqIzhs1G7jMs3k3QsDvt8rH9m8z6hjPwVBxMjcEPg9FDsBe+y1WO3AFdtJzbu+aVmFU+BBUWRIQj02xZy/qpy0po1RwktTYdnmflDR1gzR8SmgGRZ8H/G7qKDiNJCeFHEozJQQVlcYjSANhSCjokfDOyniWaT63x+pSY2LgO9ciRLpU0t+rDd5dDFMcdWG+yJztnbOKVugxTx95Gftzgf75sL7vXUWpLyp6SZN6nvZR3pVXvEkrdbeHQ34B0f6q4sMweqzN79GQxOP2nBCxKQdh7OybiZZzR8prjD00WnzQJc1B7po5XqwjxqRDZq8aC0nlaJiF0oSTzCMzy2a6hBDsGzDj0iPGtNk4PDAEiQT7gVzeVKW7F5+u1Ch9sk7MFcbkxHb7UdHZf4qbx2bnuoQD2x7VIuTmViJwrm9Hc7eoHEsPQCgpFlW+Gz+UgCxh3qkNkeY2WUEYIfPjHJdddJ/SWgqry120YHujr3LwVc9EkS12UvU5KWeni8zsOsv4QEhW8DLHIhngW99bX9Undgaul+9m0tMK5ZSh5SjGkVTkL7/piulB/QffbCYvZY1qOq3DydLQU1vlmcymbZPWHBH+FPqLpDWTRysF8APr004A6jb0Si9vRfFaKK9A X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: /UUgyI1WDHgDeoFRWKAvU4Gud3c4OyvWPmBdVoibOPZgRifszvjk2xtEnpQXXjIwb/Is1v0LlXQcGtjehudqwrWpbKkYO9Ve0V6hOEBjj88yM0qEz6ahNUc7wyoff1KS2kGCVwzoXr9n0ROVncLumUxlfhuWad8ZwP3LIA4JI8ep68vv8gl91zh04QDAkl5xvzI7sWhjaiGBjAOLNwL8VjBqFa8OG1feXPOm3PBAvKNZQ1pAast9qoM3Ghm3HOAQ6k6XK4UcIG56rhUMlWcR5nAMh4iZmnVAg1cl5oGu58MRfuNjLjCZXTQRsrrGr/t4u5/B7hOpkHpuTEYqXDbbj06aI9TO0KT8sJAk1gICn/EV1ItR8c8yBtQcSi8yys1Kgm9uRSSVXD7v64cQ/vMmb+nVlq6sVu3HXFm6306oAZ/+LQtDtEV/pcx+neIp+9R7rJ/xvvBFZhUywtVDZSzNbtyYeNcgW9txAuzU3tyN134lZeD7cbDqlg60/r8+NbjvGKyc3S5fffDN/9mgta50OXq07SLcLS2MREJY5VocsetFj67wd3wI//dSXWZwSUmpoFg6Fi0N6mgqmVvHg/xW5CDxvU33QKKve5JdOOEKK4RqY1RoHLwaKa4WYDXmzgFCOin9ebc/dP54V09AlEh0PcoQBwhHulqukazLg9lHopzyGeYXzRvaQrx/Lvct55Gtrdvu+gFxgSDgl5qxfnw+nefsRD/OqzG4SM36HvA0Ytymqj70D+S3MMcVW4y7XiQ2hFf5GRjQBMdEXj1gYEh6MhCkofmd0QdTqQ4JmQ0PyQLa0z0j0DCbl7Cu+LQhO1gQjuGPYMx0uRTy91K8zx7tpGEIRhk+Y0sBPOTQqaluwng7AZLiLomOAjtQLjE6lPMyFwN4pMznqB78ubxyOwwriWWVrp5bWSkhZYQaCCxrm88sFBaoywDywqn+XEb8+Yp6UkrFI65kB+IJOeDmNprCpgA0KiAyx/b+7FTR2E9pmFXzDTFA9vAtzYCrFIx6ajPXvqVaSC57mZ0B469CXdlZYRonAGA3d9XBXEDdvbkAk0lSlYDwngsvRoZLX5o2oyMpKj+ma5oZcYx5vPZTRAmc7n60uMDGC0nV7cSyWJRDaYGs3R+3Mjy2RgF4EKDOvoWeBrmFV3PzNdaEGm5M2FsjOyJ5hdnrV/CsNUmVjIS7stRGs+TomVilm2XqEbCJnpwBVQSX847AYoiOl/7I5OsNOPp7g4cMUqruJMHEbI3kX1E3j/vXiaSD/mzx1Df2et2S0zyElW03N5O5D6kbDAm8HHGZhdesyiemQPGTYPaARVg= X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: ef0414c4-7b42-4683-9d12-08daa59119c0 X-MS-Exchange-CrossTenant-AuthSource: GV1P250MB0737.EURP250.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Oct 2022 22:46:24.9897 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXP250MB0470 Subject: [FFmpeg-devel] [PATCH 4/9] avcodec/opus: Move stuff shared by decoder and parser to a new file 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: Andreas Rheinhardt Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: UPJ6e99K6nj8 opus.h (which is used by all the Opus code) currently includes several structures only used by the parser and the decoder; several elements of OpusContext are even only used by the decoder. This commit therefore moves the part of OpusContext that is shared between these two components (and used by ff_opus_parse_extradata()) out into a new structure and moves all the other accompanying structures and functions to a new header, opus_parse.h; the functions itself are also moved to a new file, opus_parse.c. (This also allows to remove several spurious dependencies of the Opus parser and encoder.) Signed-off-by: Andreas Rheinhardt --- libavcodec/Makefile | 8 +- libavcodec/opus.c | 442 ------------------------------------ libavcodec/opus.h | 54 ----- libavcodec/opus_parse.c | 469 +++++++++++++++++++++++++++++++++++++++ libavcodec/opus_parse.h | 77 +++++++ libavcodec/opus_parser.c | 13 +- libavcodec/opusdec.c | 59 +++-- 7 files changed, 594 insertions(+), 528 deletions(-) create mode 100644 libavcodec/opus_parse.c create mode 100644 libavcodec/opus_parse.h diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 1946930c20..10a9c47ea3 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -556,9 +556,9 @@ OBJS-$(CONFIG_NUV_DECODER) += nuv.o rtjpeg.o OBJS-$(CONFIG_ON2AVC_DECODER) += on2avc.o on2avcdata.o OBJS-$(CONFIG_OPUS_DECODER) += opusdec.o opus.o opus_celt.o opus_rc.o \ opus_pvq.o opus_silk.o opustab.o vorbis_data.o \ - opusdsp.o + opusdsp.o opus_parse.o OBJS-$(CONFIG_OPUS_ENCODER) += opusenc.o opus.o opus_rc.o opustab.o opus_pvq.o \ - opusenc_psy.o vorbis_data.o + opusenc_psy.o OBJS-$(CONFIG_PAF_AUDIO_DECODER) += pafaudio.o OBJS-$(CONFIG_PAF_VIDEO_DECODER) += pafvideo.o OBJS-$(CONFIG_PAM_DECODER) += pnmdec.o pnm.o @@ -1156,8 +1156,8 @@ OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \ OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ mpeg12.o mpeg12data.o -OBJS-$(CONFIG_OPUS_PARSER) += opus_parser.o opus.o opustab.o \ - opus_rc.o vorbis_data.o +OBJS-$(CONFIG_OPUS_PARSER) += opus_parser.o opus_parse.o \ + vorbis_data.o OBJS-$(CONFIG_PNG_PARSER) += png_parser.o OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o OBJS-$(CONFIG_QOI_PARSER) += qoi_parser.o diff --git a/libavcodec/opus.c b/libavcodec/opus.c index b91f57dec3..791e25c488 100644 --- a/libavcodec/opus.c +++ b/libavcodec/opus.c @@ -19,452 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file - * Opus decoder/parser shared code - */ - #include -#include "libavutil/channel_layout.h" -#include "libavutil/error.h" -#include "libavutil/ffmath.h" - #include "opus_celt.h" #include "opustab.h" -#include "internal.h" -#include "vorbis_data.h" - -static const uint16_t opus_frame_duration[32] = { - 480, 960, 1920, 2880, - 480, 960, 1920, 2880, - 480, 960, 1920, 2880, - 480, 960, - 480, 960, - 120, 240, 480, 960, - 120, 240, 480, 960, - 120, 240, 480, 960, - 120, 240, 480, 960, -}; - -/** - * Read a 1- or 2-byte frame length - */ -static inline int xiph_lacing_16bit(const uint8_t **ptr, const uint8_t *end) -{ - int val; - - if (*ptr >= end) - return AVERROR_INVALIDDATA; - val = *(*ptr)++; - if (val >= 252) { - if (*ptr >= end) - return AVERROR_INVALIDDATA; - val += 4 * *(*ptr)++; - } - return val; -} - -/** - * Read a multi-byte length (used for code 3 packet padding size) - */ -static inline int xiph_lacing_full(const uint8_t **ptr, const uint8_t *end) -{ - int val = 0; - int next; - - while (1) { - if (*ptr >= end || val > INT_MAX - 254) - return AVERROR_INVALIDDATA; - next = *(*ptr)++; - val += next; - if (next < 255) - break; - else - val--; - } - return val; -} - -/** - * Parse Opus packet info from raw packet data - */ -int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size, - int self_delimiting) -{ - const uint8_t *ptr = buf; - const uint8_t *end = buf + buf_size; - int padding = 0; - int frame_bytes, i; - - if (buf_size < 1) - goto fail; - - /* TOC byte */ - i = *ptr++; - pkt->code = (i ) & 0x3; - pkt->stereo = (i >> 2) & 0x1; - pkt->config = (i >> 3) & 0x1F; - - /* code 2 and code 3 packets have at least 1 byte after the TOC */ - if (pkt->code >= 2 && buf_size < 2) - goto fail; - - switch (pkt->code) { - case 0: - /* 1 frame */ - pkt->frame_count = 1; - pkt->vbr = 0; - - if (self_delimiting) { - int len = xiph_lacing_16bit(&ptr, end); - if (len < 0 || len > end - ptr) - goto fail; - end = ptr + len; - buf_size = end - buf; - } - - frame_bytes = end - ptr; - if (frame_bytes > MAX_FRAME_SIZE) - goto fail; - pkt->frame_offset[0] = ptr - buf; - pkt->frame_size[0] = frame_bytes; - break; - case 1: - /* 2 frames, equal size */ - pkt->frame_count = 2; - pkt->vbr = 0; - - if (self_delimiting) { - int len = xiph_lacing_16bit(&ptr, end); - if (len < 0 || 2 * len > end - ptr) - goto fail; - end = ptr + 2 * len; - buf_size = end - buf; - } - - frame_bytes = end - ptr; - if (frame_bytes & 1 || frame_bytes >> 1 > MAX_FRAME_SIZE) - goto fail; - pkt->frame_offset[0] = ptr - buf; - pkt->frame_size[0] = frame_bytes >> 1; - pkt->frame_offset[1] = pkt->frame_offset[0] + pkt->frame_size[0]; - pkt->frame_size[1] = frame_bytes >> 1; - break; - case 2: - /* 2 frames, different sizes */ - pkt->frame_count = 2; - pkt->vbr = 1; - - /* read 1st frame size */ - frame_bytes = xiph_lacing_16bit(&ptr, end); - if (frame_bytes < 0) - goto fail; - - if (self_delimiting) { - int len = xiph_lacing_16bit(&ptr, end); - if (len < 0 || len + frame_bytes > end - ptr) - goto fail; - end = ptr + frame_bytes + len; - buf_size = end - buf; - } - - pkt->frame_offset[0] = ptr - buf; - pkt->frame_size[0] = frame_bytes; - - /* calculate 2nd frame size */ - frame_bytes = end - ptr - pkt->frame_size[0]; - if (frame_bytes < 0 || frame_bytes > MAX_FRAME_SIZE) - goto fail; - pkt->frame_offset[1] = pkt->frame_offset[0] + pkt->frame_size[0]; - pkt->frame_size[1] = frame_bytes; - break; - case 3: - /* 1 to 48 frames, can be different sizes */ - i = *ptr++; - pkt->frame_count = (i ) & 0x3F; - padding = (i >> 6) & 0x01; - pkt->vbr = (i >> 7) & 0x01; - - if (pkt->frame_count == 0 || pkt->frame_count > MAX_FRAMES) - goto fail; - - /* read padding size */ - if (padding) { - padding = xiph_lacing_full(&ptr, end); - if (padding < 0) - goto fail; - } - - /* read frame sizes */ - if (pkt->vbr) { - /* for VBR, all frames except the final one have their size coded - in the bitstream. the last frame size is implicit. */ - int total_bytes = 0; - for (i = 0; i < pkt->frame_count - 1; i++) { - frame_bytes = xiph_lacing_16bit(&ptr, end); - if (frame_bytes < 0) - goto fail; - pkt->frame_size[i] = frame_bytes; - total_bytes += frame_bytes; - } - - if (self_delimiting) { - int len = xiph_lacing_16bit(&ptr, end); - if (len < 0 || len + total_bytes + padding > end - ptr) - goto fail; - end = ptr + total_bytes + len + padding; - buf_size = end - buf; - } - - frame_bytes = end - ptr - padding; - if (total_bytes > frame_bytes) - goto fail; - pkt->frame_offset[0] = ptr - buf; - for (i = 1; i < pkt->frame_count; i++) - pkt->frame_offset[i] = pkt->frame_offset[i-1] + pkt->frame_size[i-1]; - pkt->frame_size[pkt->frame_count-1] = frame_bytes - total_bytes; - } else { - /* for CBR, the remaining packet bytes are divided evenly between - the frames */ - if (self_delimiting) { - frame_bytes = xiph_lacing_16bit(&ptr, end); - if (frame_bytes < 0 || pkt->frame_count * frame_bytes + padding > end - ptr) - goto fail; - end = ptr + pkt->frame_count * frame_bytes + padding; - buf_size = end - buf; - } else { - frame_bytes = end - ptr - padding; - if (frame_bytes % pkt->frame_count || - frame_bytes / pkt->frame_count > MAX_FRAME_SIZE) - goto fail; - frame_bytes /= pkt->frame_count; - } - - pkt->frame_offset[0] = ptr - buf; - pkt->frame_size[0] = frame_bytes; - for (i = 1; i < pkt->frame_count; i++) { - pkt->frame_offset[i] = pkt->frame_offset[i-1] + pkt->frame_size[i-1]; - pkt->frame_size[i] = frame_bytes; - } - } - } - - pkt->packet_size = buf_size; - pkt->data_size = pkt->packet_size - padding; - - /* total packet duration cannot be larger than 120ms */ - pkt->frame_duration = opus_frame_duration[pkt->config]; - if (pkt->frame_duration * pkt->frame_count > MAX_PACKET_DUR) - goto fail; - - /* set mode and bandwidth */ - if (pkt->config < 12) { - pkt->mode = OPUS_MODE_SILK; - pkt->bandwidth = pkt->config >> 2; - } else if (pkt->config < 16) { - pkt->mode = OPUS_MODE_HYBRID; - pkt->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND + (pkt->config >= 14); - } else { - pkt->mode = OPUS_MODE_CELT; - pkt->bandwidth = (pkt->config - 16) >> 2; - /* skip medium band */ - if (pkt->bandwidth) - pkt->bandwidth++; - } - - return 0; - -fail: - memset(pkt, 0, sizeof(*pkt)); - return AVERROR_INVALIDDATA; -} - -static int channel_reorder_vorbis(int nb_channels, int channel_idx) -{ - return ff_vorbis_channel_layout_offsets[nb_channels - 1][channel_idx]; -} - -static int channel_reorder_unknown(int nb_channels, int channel_idx) -{ - return channel_idx; -} - -av_cold int ff_opus_parse_extradata(AVCodecContext *avctx, - OpusContext *s) -{ - static const uint8_t default_channel_map[2] = { 0, 1 }; - - int (*channel_reorder)(int, int) = channel_reorder_unknown; - int channels = avctx->ch_layout.nb_channels; - - const uint8_t *extradata, *channel_map; - int extradata_size; - int version, map_type, streams, stereo_streams, i, j, ret; - AVChannelLayout layout = { 0 }; - - if (!avctx->extradata) { - if (channels > 2) { - av_log(avctx, AV_LOG_ERROR, - "Multichannel configuration without extradata.\n"); - return AVERROR(EINVAL); - } - extradata = opus_default_extradata; - extradata_size = sizeof(opus_default_extradata); - } else { - extradata = avctx->extradata; - extradata_size = avctx->extradata_size; - } - - if (extradata_size < 19) { - av_log(avctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", - extradata_size); - return AVERROR_INVALIDDATA; - } - - version = extradata[8]; - if (version > 15) { - avpriv_request_sample(avctx, "Extradata version %d", version); - return AVERROR_PATCHWELCOME; - } - - avctx->delay = AV_RL16(extradata + 10); - if (avctx->internal) - avctx->internal->skip_samples = avctx->delay; - - channels = avctx->extradata ? extradata[9] : (channels == 1) ? 1 : 2; - if (!channels) { - av_log(avctx, AV_LOG_ERROR, "Zero channel count specified in the extradata\n"); - return AVERROR_INVALIDDATA; - } - - s->gain_i = AV_RL16(extradata + 16); - if (s->gain_i) - s->gain = ff_exp10(s->gain_i / (20.0 * 256)); - - map_type = extradata[18]; - if (!map_type) { - if (channels > 2) { - av_log(avctx, AV_LOG_ERROR, - "Channel mapping 0 is only specified for up to 2 channels\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } - layout = (channels == 1) ? (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO : - (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; - streams = 1; - stereo_streams = channels - 1; - channel_map = default_channel_map; - } else if (map_type == 1 || map_type == 2 || map_type == 255) { - if (extradata_size < 21 + channels) { - av_log(avctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", - extradata_size); - ret = AVERROR_INVALIDDATA; - goto fail; - } - - streams = extradata[19]; - stereo_streams = extradata[20]; - if (!streams || stereo_streams > streams || - streams + stereo_streams > 255) { - av_log(avctx, AV_LOG_ERROR, - "Invalid stream/stereo stream count: %d/%d\n", streams, stereo_streams); - ret = AVERROR_INVALIDDATA; - goto fail; - } - - if (map_type == 1) { - if (channels > 8) { - av_log(avctx, AV_LOG_ERROR, - "Channel mapping 1 is only specified for up to 8 channels\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } - av_channel_layout_copy(&layout, &ff_vorbis_ch_layouts[channels - 1]); - channel_reorder = channel_reorder_vorbis; - } else if (map_type == 2) { - int ambisonic_order = ff_sqrt(channels) - 1; - if (channels != ((ambisonic_order + 1) * (ambisonic_order + 1)) && - channels != ((ambisonic_order + 1) * (ambisonic_order + 1) + 2)) { - av_log(avctx, AV_LOG_ERROR, - "Channel mapping 2 is only specified for channel counts" - " which can be written as (n + 1)^2 or (n + 1)^2 + 2" - " for nonnegative integer n\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } - if (channels > 227) { - av_log(avctx, AV_LOG_ERROR, "Too many channels\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } - - layout.order = AV_CHANNEL_ORDER_AMBISONIC; - layout.nb_channels = channels; - if (channels != ((ambisonic_order + 1) * (ambisonic_order + 1))) - layout.u.mask = AV_CH_LAYOUT_STEREO; - } else { - layout.order = AV_CHANNEL_ORDER_UNSPEC; - layout.nb_channels = channels; - } - - channel_map = extradata + 21; - } else { - avpriv_request_sample(avctx, "Mapping type %d", map_type); - return AVERROR_PATCHWELCOME; - } - - s->channel_maps = av_calloc(channels, sizeof(*s->channel_maps)); - if (!s->channel_maps) { - ret = AVERROR(ENOMEM); - goto fail; - } - - for (i = 0; i < channels; i++) { - ChannelMap *map = &s->channel_maps[i]; - uint8_t idx = channel_map[channel_reorder(channels, i)]; - - if (idx == 255) { - map->silence = 1; - continue; - } else if (idx >= streams + stereo_streams) { - av_log(avctx, AV_LOG_ERROR, - "Invalid channel map for output channel %d: %d\n", i, idx); - av_freep(&s->channel_maps); - ret = AVERROR_INVALIDDATA; - goto fail; - } - - /* check that we did not see this index yet */ - map->copy = 0; - for (j = 0; j < i; j++) - if (channel_map[channel_reorder(channels, j)] == idx) { - map->copy = 1; - map->copy_idx = j; - break; - } - - if (idx < 2 * stereo_streams) { - map->stream_idx = idx / 2; - map->channel_idx = idx & 1; - } else { - map->stream_idx = idx - stereo_streams; - map->channel_idx = 0; - } - } - - ret = av_channel_layout_copy(&avctx->ch_layout, &layout); - if (ret < 0) - goto fail; - - s->nb_streams = streams; - s->nb_stereo_streams = stereo_streams; - - return 0; -fail: - av_channel_layout_uninit(&layout); - return ret; -} void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc) { diff --git a/libavcodec/opus.h b/libavcodec/opus.h index 264128f09e..c88bb89dde 100644 --- a/libavcodec/opus.h +++ b/libavcodec/opus.h @@ -25,8 +25,6 @@ #include -#include "libavutil/float_dsp.h" - #include "avcodec.h" #include "opus_rc.h" @@ -77,58 +75,6 @@ typedef struct SilkContext SilkContext; typedef struct CeltFrame CeltFrame; -typedef struct OpusPacket { - int packet_size; /**< packet size */ - int data_size; /**< size of the useful data -- packet size - padding */ - int code; /**< packet code: specifies the frame layout */ - int stereo; /**< whether this packet is mono or stereo */ - int vbr; /**< vbr flag */ - int config; /**< configuration: tells the audio mode, - ** bandwidth, and frame duration */ - int frame_count; /**< frame count */ - int frame_offset[MAX_FRAMES]; /**< frame offsets */ - int frame_size[MAX_FRAMES]; /**< frame sizes */ - int frame_duration; /**< frame duration, in samples @ 48kHz */ - enum OpusMode mode; /**< mode */ - enum OpusBandwidth bandwidth; /**< bandwidth */ -} OpusPacket; - -// a mapping between an opus stream and an output channel -typedef struct ChannelMap { - int stream_idx; - int channel_idx; - - // when a single decoded channel is mapped to multiple output channels, we - // write to the first output directly and copy from it to the others - // this field is set to 1 for those copied output channels - int copy; - // this is the index of the output channel to copy from - int copy_idx; - - // this channel is silent - int silence; -} ChannelMap; - -typedef struct OpusContext { - AVClass *av_class; - struct OpusStreamContext *streams; - int apply_phase_inv; - - int nb_streams; - int nb_stereo_streams; - - AVFloatDSPContext *fdsp; - int16_t gain_i; - float gain; - - ChannelMap *channel_maps; -} OpusContext; - -int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size, - int self_delimited); - -int ff_opus_parse_extradata(AVCodecContext *avctx, OpusContext *s); - int ff_silk_init(AVCodecContext *avctx, SilkContext **ps, int output_channels); void ff_silk_free(SilkContext **ps); void ff_silk_flush(SilkContext *s); diff --git a/libavcodec/opus_parse.c b/libavcodec/opus_parse.c new file mode 100644 index 0000000000..39765c5b79 --- /dev/null +++ b/libavcodec/opus_parse.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * + * 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 + */ + +/** + * @file + * Opus decoder/parser shared code + */ + +#include "libavutil/attributes.h" +#include "libavutil/channel_layout.h" +#include "libavutil/error.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" +#include "libavutil/mem.h" + +#include "avcodec.h" +#include "internal.h" +#include "mathops.h" +#include "opus.h" +#include "opus_parse.h" +#include "vorbis_data.h" + +static const uint16_t opus_frame_duration[32] = { + 480, 960, 1920, 2880, + 480, 960, 1920, 2880, + 480, 960, 1920, 2880, + 480, 960, + 480, 960, + 120, 240, 480, 960, + 120, 240, 480, 960, + 120, 240, 480, 960, + 120, 240, 480, 960, +}; + +/** + * Read a 1- or 2-byte frame length + */ +static inline int xiph_lacing_16bit(const uint8_t **ptr, const uint8_t *end) +{ + int val; + + if (*ptr >= end) + return AVERROR_INVALIDDATA; + val = *(*ptr)++; + if (val >= 252) { + if (*ptr >= end) + return AVERROR_INVALIDDATA; + val += 4 * *(*ptr)++; + } + return val; +} + +/** + * Read a multi-byte length (used for code 3 packet padding size) + */ +static inline int xiph_lacing_full(const uint8_t **ptr, const uint8_t *end) +{ + int val = 0; + int next; + + while (1) { + if (*ptr >= end || val > INT_MAX - 254) + return AVERROR_INVALIDDATA; + next = *(*ptr)++; + val += next; + if (next < 255) + break; + else + val--; + } + return val; +} + +/** + * Parse Opus packet info from raw packet data + */ +int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size, + int self_delimiting) +{ + const uint8_t *ptr = buf; + const uint8_t *end = buf + buf_size; + int padding = 0; + int frame_bytes, i; + + if (buf_size < 1) + goto fail; + + /* TOC byte */ + i = *ptr++; + pkt->code = (i ) & 0x3; + pkt->stereo = (i >> 2) & 0x1; + pkt->config = (i >> 3) & 0x1F; + + /* code 2 and code 3 packets have at least 1 byte after the TOC */ + if (pkt->code >= 2 && buf_size < 2) + goto fail; + + switch (pkt->code) { + case 0: + /* 1 frame */ + pkt->frame_count = 1; + pkt->vbr = 0; + + if (self_delimiting) { + int len = xiph_lacing_16bit(&ptr, end); + if (len < 0 || len > end - ptr) + goto fail; + end = ptr + len; + buf_size = end - buf; + } + + frame_bytes = end - ptr; + if (frame_bytes > MAX_FRAME_SIZE) + goto fail; + pkt->frame_offset[0] = ptr - buf; + pkt->frame_size[0] = frame_bytes; + break; + case 1: + /* 2 frames, equal size */ + pkt->frame_count = 2; + pkt->vbr = 0; + + if (self_delimiting) { + int len = xiph_lacing_16bit(&ptr, end); + if (len < 0 || 2 * len > end - ptr) + goto fail; + end = ptr + 2 * len; + buf_size = end - buf; + } + + frame_bytes = end - ptr; + if (frame_bytes & 1 || frame_bytes >> 1 > MAX_FRAME_SIZE) + goto fail; + pkt->frame_offset[0] = ptr - buf; + pkt->frame_size[0] = frame_bytes >> 1; + pkt->frame_offset[1] = pkt->frame_offset[0] + pkt->frame_size[0]; + pkt->frame_size[1] = frame_bytes >> 1; + break; + case 2: + /* 2 frames, different sizes */ + pkt->frame_count = 2; + pkt->vbr = 1; + + /* read 1st frame size */ + frame_bytes = xiph_lacing_16bit(&ptr, end); + if (frame_bytes < 0) + goto fail; + + if (self_delimiting) { + int len = xiph_lacing_16bit(&ptr, end); + if (len < 0 || len + frame_bytes > end - ptr) + goto fail; + end = ptr + frame_bytes + len; + buf_size = end - buf; + } + + pkt->frame_offset[0] = ptr - buf; + pkt->frame_size[0] = frame_bytes; + + /* calculate 2nd frame size */ + frame_bytes = end - ptr - pkt->frame_size[0]; + if (frame_bytes < 0 || frame_bytes > MAX_FRAME_SIZE) + goto fail; + pkt->frame_offset[1] = pkt->frame_offset[0] + pkt->frame_size[0]; + pkt->frame_size[1] = frame_bytes; + break; + case 3: + /* 1 to 48 frames, can be different sizes */ + i = *ptr++; + pkt->frame_count = (i ) & 0x3F; + padding = (i >> 6) & 0x01; + pkt->vbr = (i >> 7) & 0x01; + + if (pkt->frame_count == 0 || pkt->frame_count > MAX_FRAMES) + goto fail; + + /* read padding size */ + if (padding) { + padding = xiph_lacing_full(&ptr, end); + if (padding < 0) + goto fail; + } + + /* read frame sizes */ + if (pkt->vbr) { + /* for VBR, all frames except the final one have their size coded + in the bitstream. the last frame size is implicit. */ + int total_bytes = 0; + for (i = 0; i < pkt->frame_count - 1; i++) { + frame_bytes = xiph_lacing_16bit(&ptr, end); + if (frame_bytes < 0) + goto fail; + pkt->frame_size[i] = frame_bytes; + total_bytes += frame_bytes; + } + + if (self_delimiting) { + int len = xiph_lacing_16bit(&ptr, end); + if (len < 0 || len + total_bytes + padding > end - ptr) + goto fail; + end = ptr + total_bytes + len + padding; + buf_size = end - buf; + } + + frame_bytes = end - ptr - padding; + if (total_bytes > frame_bytes) + goto fail; + pkt->frame_offset[0] = ptr - buf; + for (i = 1; i < pkt->frame_count; i++) + pkt->frame_offset[i] = pkt->frame_offset[i-1] + pkt->frame_size[i-1]; + pkt->frame_size[pkt->frame_count-1] = frame_bytes - total_bytes; + } else { + /* for CBR, the remaining packet bytes are divided evenly between + the frames */ + if (self_delimiting) { + frame_bytes = xiph_lacing_16bit(&ptr, end); + if (frame_bytes < 0 || pkt->frame_count * frame_bytes + padding > end - ptr) + goto fail; + end = ptr + pkt->frame_count * frame_bytes + padding; + buf_size = end - buf; + } else { + frame_bytes = end - ptr - padding; + if (frame_bytes % pkt->frame_count || + frame_bytes / pkt->frame_count > MAX_FRAME_SIZE) + goto fail; + frame_bytes /= pkt->frame_count; + } + + pkt->frame_offset[0] = ptr - buf; + pkt->frame_size[0] = frame_bytes; + for (i = 1; i < pkt->frame_count; i++) { + pkt->frame_offset[i] = pkt->frame_offset[i-1] + pkt->frame_size[i-1]; + pkt->frame_size[i] = frame_bytes; + } + } + } + + pkt->packet_size = buf_size; + pkt->data_size = pkt->packet_size - padding; + + /* total packet duration cannot be larger than 120ms */ + pkt->frame_duration = opus_frame_duration[pkt->config]; + if (pkt->frame_duration * pkt->frame_count > MAX_PACKET_DUR) + goto fail; + + /* set mode and bandwidth */ + if (pkt->config < 12) { + pkt->mode = OPUS_MODE_SILK; + pkt->bandwidth = pkt->config >> 2; + } else if (pkt->config < 16) { + pkt->mode = OPUS_MODE_HYBRID; + pkt->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND + (pkt->config >= 14); + } else { + pkt->mode = OPUS_MODE_CELT; + pkt->bandwidth = (pkt->config - 16) >> 2; + /* skip medium band */ + if (pkt->bandwidth) + pkt->bandwidth++; + } + + return 0; + +fail: + memset(pkt, 0, sizeof(*pkt)); + return AVERROR_INVALIDDATA; +} + +static int channel_reorder_vorbis(int nb_channels, int channel_idx) +{ + return ff_vorbis_channel_layout_offsets[nb_channels - 1][channel_idx]; +} + +static int channel_reorder_unknown(int nb_channels, int channel_idx) +{ + return channel_idx; +} + +av_cold int ff_opus_parse_extradata(AVCodecContext *avctx, + OpusParseContext *s) +{ + static const uint8_t default_channel_map[2] = { 0, 1 }; + + int (*channel_reorder)(int, int) = channel_reorder_unknown; + int channels = avctx->ch_layout.nb_channels; + + const uint8_t *extradata, *channel_map; + int extradata_size; + int version, map_type, streams, stereo_streams, i, j, ret; + AVChannelLayout layout = { 0 }; + + if (!avctx->extradata) { + if (channels > 2) { + av_log(avctx, AV_LOG_ERROR, + "Multichannel configuration without extradata.\n"); + return AVERROR(EINVAL); + } + extradata = opus_default_extradata; + extradata_size = sizeof(opus_default_extradata); + } else { + extradata = avctx->extradata; + extradata_size = avctx->extradata_size; + } + + if (extradata_size < 19) { + av_log(avctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", + extradata_size); + return AVERROR_INVALIDDATA; + } + + version = extradata[8]; + if (version > 15) { + avpriv_request_sample(avctx, "Extradata version %d", version); + return AVERROR_PATCHWELCOME; + } + + avctx->delay = AV_RL16(extradata + 10); + if (avctx->internal) + avctx->internal->skip_samples = avctx->delay; + + channels = avctx->extradata ? extradata[9] : (channels == 1) ? 1 : 2; + if (!channels) { + av_log(avctx, AV_LOG_ERROR, "Zero channel count specified in the extradata\n"); + return AVERROR_INVALIDDATA; + } + + s->gain_i = AV_RL16(extradata + 16); + + map_type = extradata[18]; + if (!map_type) { + if (channels > 2) { + av_log(avctx, AV_LOG_ERROR, + "Channel mapping 0 is only specified for up to 2 channels\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + layout = (channels == 1) ? (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO : + (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; + streams = 1; + stereo_streams = channels - 1; + channel_map = default_channel_map; + } else if (map_type == 1 || map_type == 2 || map_type == 255) { + if (extradata_size < 21 + channels) { + av_log(avctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", + extradata_size); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + streams = extradata[19]; + stereo_streams = extradata[20]; + if (!streams || stereo_streams > streams || + streams + stereo_streams > 255) { + av_log(avctx, AV_LOG_ERROR, + "Invalid stream/stereo stream count: %d/%d\n", streams, stereo_streams); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + if (map_type == 1) { + if (channels > 8) { + av_log(avctx, AV_LOG_ERROR, + "Channel mapping 1 is only specified for up to 8 channels\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + av_channel_layout_copy(&layout, &ff_vorbis_ch_layouts[channels - 1]); + channel_reorder = channel_reorder_vorbis; + } else if (map_type == 2) { + int ambisonic_order = ff_sqrt(channels) - 1; + if (channels != ((ambisonic_order + 1) * (ambisonic_order + 1)) && + channels != ((ambisonic_order + 1) * (ambisonic_order + 1) + 2)) { + av_log(avctx, AV_LOG_ERROR, + "Channel mapping 2 is only specified for channel counts" + " which can be written as (n + 1)^2 or (n + 1)^2 + 2" + " for nonnegative integer n\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + if (channels > 227) { + av_log(avctx, AV_LOG_ERROR, "Too many channels\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + layout.order = AV_CHANNEL_ORDER_AMBISONIC; + layout.nb_channels = channels; + if (channels != ((ambisonic_order + 1) * (ambisonic_order + 1))) + layout.u.mask = AV_CH_LAYOUT_STEREO; + } else { + layout.order = AV_CHANNEL_ORDER_UNSPEC; + layout.nb_channels = channels; + } + + channel_map = extradata + 21; + } else { + avpriv_request_sample(avctx, "Mapping type %d", map_type); + return AVERROR_PATCHWELCOME; + } + + s->channel_maps = av_calloc(channels, sizeof(*s->channel_maps)); + if (!s->channel_maps) { + ret = AVERROR(ENOMEM); + goto fail; + } + + for (i = 0; i < channels; i++) { + ChannelMap *map = &s->channel_maps[i]; + uint8_t idx = channel_map[channel_reorder(channels, i)]; + + if (idx == 255) { + map->silence = 1; + continue; + } else if (idx >= streams + stereo_streams) { + av_log(avctx, AV_LOG_ERROR, + "Invalid channel map for output channel %d: %d\n", i, idx); + av_freep(&s->channel_maps); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + /* check that we did not see this index yet */ + map->copy = 0; + for (j = 0; j < i; j++) + if (channel_map[channel_reorder(channels, j)] == idx) { + map->copy = 1; + map->copy_idx = j; + break; + } + + if (idx < 2 * stereo_streams) { + map->stream_idx = idx / 2; + map->channel_idx = idx & 1; + } else { + map->stream_idx = idx - stereo_streams; + map->channel_idx = 0; + } + } + + ret = av_channel_layout_copy(&avctx->ch_layout, &layout); + if (ret < 0) + goto fail; + + s->nb_streams = streams; + s->nb_stereo_streams = stereo_streams; + + return 0; +fail: + av_channel_layout_uninit(&layout); + return ret; +} + diff --git a/libavcodec/opus_parse.h b/libavcodec/opus_parse.h new file mode 100644 index 0000000000..8e5c6a880c --- /dev/null +++ b/libavcodec/opus_parse.h @@ -0,0 +1,77 @@ +/* + * Opus decoder/parser common functions and structures + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * + * 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 + */ + +#ifndef AVCODEC_OPUS_PARSE_H +#define AVCODEC_OPUS_PARSE_H + +#include + +#include "avcodec.h" +#include "opus.h" + +typedef struct OpusPacket { + int packet_size; /**< packet size */ + int data_size; /**< size of the useful data -- packet size - padding */ + int code; /**< packet code: specifies the frame layout */ + int stereo; /**< whether this packet is mono or stereo */ + int vbr; /**< vbr flag */ + int config; /**< configuration: tells the audio mode, + ** bandwidth, and frame duration */ + int frame_count; /**< frame count */ + int frame_offset[MAX_FRAMES]; /**< frame offsets */ + int frame_size[MAX_FRAMES]; /**< frame sizes */ + int frame_duration; /**< frame duration, in samples @ 48kHz */ + enum OpusMode mode; /**< mode */ + enum OpusBandwidth bandwidth; /**< bandwidth */ +} OpusPacket; + +// a mapping between an opus stream and an output channel +typedef struct ChannelMap { + int stream_idx; + int channel_idx; + + // when a single decoded channel is mapped to multiple output channels, we + // write to the first output directly and copy from it to the others + // this field is set to 1 for those copied output channels + int copy; + // this is the index of the output channel to copy from + int copy_idx; + + // this channel is silent + int silence; +} ChannelMap; + +typedef struct OpusParseContext { + int nb_streams; + int nb_stereo_streams; + + int16_t gain_i; + + ChannelMap *channel_maps; +} OpusParseContext; + +int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size, + int self_delimited); + +int ff_opus_parse_extradata(AVCodecContext *avctx, OpusParseContext *s); + +#endif /* AVCODEC_OPUS_PARSE_H */ diff --git a/libavcodec/opus_parser.c b/libavcodec/opus_parser.c index 726c010f67..e6df34abab 100644 --- a/libavcodec/opus_parser.c +++ b/libavcodec/opus_parser.c @@ -28,15 +28,16 @@ #include "avcodec.h" #include "bytestream.h" #include "opus.h" +#include "opus_parse.h" #include "parser.h" -typedef struct OpusParseContext { +typedef struct OpusParserContext { ParseContext pc; - OpusContext ctx; + OpusParseContext ctx; OpusPacket pkt; int extradata_parsed; int ts_framing; -} OpusParseContext; +} OpusParserContext; static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_len, int buf_len) { @@ -83,7 +84,7 @@ static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_le static int opus_find_frame_end(AVCodecParserContext *ctx, AVCodecContext *avctx, const uint8_t *buf, int buf_size, int *header_len) { - OpusParseContext *s = ctx->priv_data; + OpusParserContext *s = ctx->priv_data; ParseContext *pc = &s->pc; int ret, start_found, i = 0, payload_len = 0; const uint8_t *payload; @@ -166,7 +167,7 @@ static int opus_parse(AVCodecParserContext *ctx, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size) { - OpusParseContext *s = ctx->priv_data; + OpusParserContext *s = ctx->priv_data; ParseContext *pc = &s->pc; int next, header_len; @@ -192,7 +193,7 @@ static int opus_parse(AVCodecParserContext *ctx, AVCodecContext *avctx, const AVCodecParser ff_opus_parser = { .codec_ids = { AV_CODEC_ID_OPUS }, - .priv_data_size = sizeof(OpusParseContext), + .priv_data_size = sizeof(OpusParserContext), .parser_parse = opus_parse, .parser_close = ff_parse_close }; diff --git a/libavcodec/opusdec.c b/libavcodec/opusdec.c index 87a86b6b47..e26ca0b2c3 100644 --- a/libavcodec/opusdec.c +++ b/libavcodec/opusdec.c @@ -38,6 +38,8 @@ #include "libavutil/attributes.h" #include "libavutil/audio_fifo.h" #include "libavutil/channel_layout.h" +#include "libavutil/ffmath.h" +#include "libavutil/float_dsp.h" #include "libavutil/frame.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" @@ -50,6 +52,7 @@ #include "opus.h" #include "opustab.h" #include "opus_celt.h" +#include "opus_parse.h" static const uint16_t silk_frame_duration_ms[16] = { 10, 20, 40, 60, @@ -110,6 +113,18 @@ typedef struct OpusStreamContext { int redundancy_idx; } OpusStreamContext; +typedef struct OpusContext { + AVClass *av_class; + + struct OpusStreamContext *streams; + int apply_phase_inv; + + AVFloatDSPContext *fdsp; + float gain; + + OpusParseContext p; +} OpusContext; + static int get_silk_samplerate(int config) { if (config < 4) @@ -469,7 +484,7 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, int i, ret; /* calculate the number of delayed samples */ - for (i = 0; i < c->nb_streams; i++) { + for (int i = 0; i < c->p.nb_streams; i++) { OpusStreamContext *s = &c->streams[i]; s->out[0] = s->out[1] = NULL; @@ -480,7 +495,7 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, /* decode the header of the first sub-packet to find out the sample count */ if (buf) { OpusPacket *pkt = &c->streams[0].packet; - ret = ff_opus_parse_packet(pkt, buf, buf_size, c->nb_streams > 1); + ret = ff_opus_parse_packet(pkt, buf, buf_size, c->p.nb_streams > 1); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error parsing the packet header.\n"); return ret; @@ -504,13 +519,13 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, frame->nb_samples = 0; for (i = 0; i < avctx->ch_layout.nb_channels; i++) { - ChannelMap *map = &c->channel_maps[i]; + ChannelMap *map = &c->p.channel_maps[i]; if (!map->copy) c->streams[map->stream_idx].out[map->channel_idx] = (float*)frame->extended_data[i]; } /* read the data from the sync buffers */ - for (i = 0; i < c->nb_streams; i++) { + for (int i = 0; i < c->p.nb_streams; i++) { OpusStreamContext *s = &c->streams[i]; float **out = s->out; int sync_size = av_audio_fifo_size(s->sync_buffer); @@ -542,11 +557,11 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, } /* decode each sub-packet */ - for (i = 0; i < c->nb_streams; i++) { + for (int i = 0; i < c->p.nb_streams; i++) { OpusStreamContext *s = &c->streams[i]; if (i && buf) { - ret = ff_opus_parse_packet(&s->packet, buf, buf_size, i != c->nb_streams - 1); + ret = ff_opus_parse_packet(&s->packet, buf, buf_size, i != c->p.nb_streams - 1); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error parsing the packet header.\n"); return ret; @@ -572,7 +587,7 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, } /* buffer the extra samples */ - for (i = 0; i < c->nb_streams; i++) { + for (int i = 0; i < c->p.nb_streams; i++) { OpusStreamContext *s = &c->streams[i]; int buffer_samples = s->decoded_samples - decoded_samples; if (buffer_samples) { @@ -587,7 +602,7 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, } for (i = 0; i < avctx->ch_layout.nb_channels; i++) { - ChannelMap *map = &c->channel_maps[i]; + ChannelMap *map = &c->p.channel_maps[i]; /* handle copied channels */ if (map->copy) { @@ -598,7 +613,7 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, memset(frame->extended_data[i], 0, frame->linesize[0]); } - if (c->gain_i && decoded_samples > 0) { + if (c->p.gain_i && decoded_samples > 0) { c->fdsp->vector_fmul_scalar((float*)frame->extended_data[i], (float*)frame->extended_data[i], c->gain, FFALIGN(decoded_samples, 8)); @@ -614,9 +629,8 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame, static av_cold void opus_decode_flush(AVCodecContext *ctx) { OpusContext *c = ctx->priv_data; - int i; - for (i = 0; i < c->nb_streams; i++) { + for (int i = 0; i < c->p.nb_streams; i++) { OpusStreamContext *s = &c->streams[i]; memset(&s->packet, 0, sizeof(s->packet)); @@ -635,9 +649,8 @@ static av_cold void opus_decode_flush(AVCodecContext *ctx) static av_cold int opus_decode_close(AVCodecContext *avctx) { OpusContext *c = avctx->priv_data; - int i; - for (i = 0; i < c->nb_streams; i++) { + for (int i = 0; i < c->p.nb_streams; i++) { OpusStreamContext *s = &c->streams[i]; ff_silk_free(&s->silk); @@ -653,9 +666,9 @@ static av_cold int opus_decode_close(AVCodecContext *avctx) av_freep(&c->streams); - c->nb_streams = 0; + c->p.nb_streams = 0; - av_freep(&c->channel_maps); + av_freep(&c->p.channel_maps); av_freep(&c->fdsp); return 0; @@ -664,7 +677,7 @@ static av_cold int opus_decode_close(AVCodecContext *avctx) static av_cold int opus_decode_init(AVCodecContext *avctx) { OpusContext *c = avctx->priv_data; - int ret, i, j; + int ret; avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; avctx->sample_rate = 48000; @@ -674,26 +687,28 @@ static av_cold int opus_decode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); /* find out the channel configuration */ - ret = ff_opus_parse_extradata(avctx, c); + ret = ff_opus_parse_extradata(avctx, &c->p); if (ret < 0) return ret; + if (c->p.gain_i) + c->gain = ff_exp10(c->p.gain_i / (20.0 * 256)); /* allocate and init each independent decoder */ - c->streams = av_calloc(c->nb_streams, sizeof(*c->streams)); + c->streams = av_calloc(c->p.nb_streams, sizeof(*c->streams)); if (!c->streams) { - c->nb_streams = 0; + c->p.nb_streams = 0; return AVERROR(ENOMEM); } - for (i = 0; i < c->nb_streams; i++) { + for (int i = 0; i < c->p.nb_streams; i++) { OpusStreamContext *s = &c->streams[i]; AVChannelLayout layout; - s->output_channels = (i < c->nb_stereo_streams) ? 2 : 1; + s->output_channels = (i < c->p.nb_stereo_streams) ? 2 : 1; s->avctx = avctx; - for (j = 0; j < s->output_channels; j++) { + for (int j = 0; j < s->output_channels; j++) { s->silk_output[j] = s->silk_buf[j]; s->celt_output[j] = s->celt_buf[j]; s->redundancy_output[j] = s->redundancy_buf[j];