From patchwork Tue Aug 22 01:23:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tyler Jones X-Patchwork-Id: 4793 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.137.29 with SMTP id o29csp350131jaj; Mon, 21 Aug 2017 18:31:20 -0700 (PDT) X-Received: by 10.28.10.131 with SMTP id 125mr8417196wmk.132.1503365480364; Mon, 21 Aug 2017 18:31:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503365480; cv=none; d=google.com; s=arc-20160816; b=q5kjoDXcax4YDfhH5g4mGU+Tx7a7JvhplaCIUVLLlYd7IqMNBMhGaQmeIApP/g8EW7 qdpo0APet07xHsyWHayFWlqodZyLIyR8N+eErXVIudoJmVGGHCFhS0MMni5Z4unVJExx jerERgtVDlrUnVxuMSWYIwuFZPjx6HBwRRlVfcMyTDdq65rw7DtT7WQ6Qs7XO998yfnC xv+m0W2yeSTnH7mY8LNF60omjGDpqlUL5o6Pv3lk87P18d2CQb+s7hIdEg1nsSmcsetz 2Lqb4B4zN2yuT5hZz2xFSRfkQ66F+CM9RaY/+5ILTwVW5641eIiG+vPjHu61GL2PJ2AN VT9g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=hevLm1i8x1IZsjC/Xkel67EE4QPinyMw369AWR62z0E=; b=tmkG5GhowxG8qUsJYabU4NfOatISo02sbErg9/WyLyivgRpDoPkigNrvnf0k7jk00m alWgfIuM1pAw3Wf7oYhMczdZ4NqwVmDhbScBJIdVCBdEuqlIwjpuUbhLDvyp5LHkyf8/ uGUjtXKnXWNcFdFlt7Fe4p+0onYWR7aslXq98Nsz7cILlq8lZ1rDIHO6jABj9FXukrnz 2vf6whSrClcdDVQTkT3tcsWnsgb/Qcn8RmH0xXAdPgVd/srlRL7LS524l95ZK29Uksrt kIZLcOoAHyG8wVaRTKmeVN0BB6IJIIyfk8ItrZoNiffB/6INB7peezSudUa99+ZxjIWS 8V3A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=SJZceDwT; 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=NONE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id s16si164042wra.269.2017.08.21.18.31.19; Mon, 21 Aug 2017 18:31:20 -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=@gmail.com header.s=20161025 header.b=SJZceDwT; 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=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id C1EFE689BC3; Tue, 22 Aug 2017 04:31:04 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-it0-f67.google.com (mail-it0-f67.google.com [209.85.214.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2ED95689B83 for ; Tue, 22 Aug 2017 04:31:03 +0300 (EEST) Received: by mail-it0-f67.google.com with SMTP id 77so10878223itj.4 for ; Mon, 21 Aug 2017 18:31:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=vMVlDaKHJSGjYOlhehWlbKlI2OGvT5CHEVhA44XyrXY=; b=SJZceDwTgknWVE0Z0z5pGTPhPzBmWnITJ6KNUWkziMrGx0A2790/XTCQfzpCnIwj6A r9h0irXd53U+ZIJTvWXZXqctoxwDhPqx91zpQg3Rtp9C5mxsWJJ0uL1FXN0Pr+jIFqgZ +ddO84fpOZY8Jywe23hOd5Y4mY+id5NB4e0Mb0Rneek+Zh7HRgVJoANAFIDPQu51hQ79 q4UHDTxZYDH34uXq5VEBtlj8aXxbCjSUxBtg/4qtOV28+weVkR+cOXar5RTpDwxdnFUG 8Z7HcUHNQZgyasFnUpyMZi+uLf2H1DxlZNECSv/Oj5GI3vmt+EMu2KzdzbY6Oi435ux5 TvVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=vMVlDaKHJSGjYOlhehWlbKlI2OGvT5CHEVhA44XyrXY=; b=bhLT2B+1jqJUWmtb6wGGB3uvzAb1BMs3sAa1uASNvwZ+a3oF5bSQohMX3TbGjcIGmi 8m6tdK1Y+BTp89senDWtEGSAYECq0jKOrBhH0l2Vu9vIlP1YCR6SHsSgbDPokdQ2KCq3 pZvUxV/zCGrn35HoMZk7lWL7W0axSZbvk97D+EY9qiXW1mEaf8c/60YSQS0ps9sC7+gd GlGhgZZ6y5L6ctEAJFY4AbGZjDKkzC2WB+2JoHIPq7iWIABVcFPldoqpZq1/k4IS+pxa dNwlL9vyngnY5lea95AvLsWgn5LRK247SoTsKmWNusUHvg6wwtpj8RTBDKzd5r5nqp8k kSJQ== X-Gm-Message-State: AHYfb5gsU8AACSZfy7ZuEcUEM0KTF5OzlaFDCJybAvypgxINe7aMu1CI SFDUhSnPHdRUBMqO X-Received: by 10.36.82.67 with SMTP id d64mr1897621itb.119.1503364987133; Mon, 21 Aug 2017 18:23:07 -0700 (PDT) Received: from tdjones.localdomain (host-184-167-177-46.csp-wy.client.bresnan.net. [184.167.177.46]) by smtp.gmail.com with ESMTPSA id v142sm4607256ita.35.2017.08.21.18.23.05 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 21 Aug 2017 18:23:06 -0700 (PDT) From: Tyler Jones To: ffmpeg-devel@ffmpeg.org Date: Mon, 21 Aug 2017 19:23:03 -0600 Message-Id: <20170822012307.6019-3-tdjones879@gmail.com> In-Reply-To: <20170822012307.6019-1-tdjones879@gmail.com> References: <20170822012307.6019-1-tdjones879@gmail.com> Subject: [FFmpeg-devel] [PATCH 2/6] avcodec/vorbisenc: Apply dynamic frame lengths X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Additional codebooks are added for shorter 128-sample frames. Changes in codeword generation are made to handle valid values of 0 that prepend some codebooks, otherwise books are classified incorrectly and cause unreadable streams. A second residue, floor, and mapping is created for short window lengths so that values are partitioned correctly for transient frames. Signed-off-by: Tyler Jones --- V4: No changes V3: Switch 'bits[p] == 0' to '!bits[p]' in vlc gen V2: Fix double arithmetic in window scale libavcodec/vorbis.c | 10 +- libavcodec/vorbis_enc_data.h | 289 +++++++++++++++++++---------- libavcodec/vorbisenc.c | 424 ++++++++++++++++++++++++++----------------- tests/fate/vorbis.mak | 2 +- 4 files changed, 454 insertions(+), 271 deletions(-) diff --git a/libavcodec/vorbis.c b/libavcodec/vorbis.c index 399020eec5..d8c4b006e7 100644 --- a/libavcodec/vorbis.c +++ b/libavcodec/vorbis.c @@ -59,7 +59,7 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num) unsigned i, j, p, code; for (p = 0; (bits[p] == 0) && (p < num); ++p) - ; + codes[p] = 0; if (p == num) return 0; @@ -78,9 +78,11 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num) for (; p < num; ++p) { if (bits[p] > 32) - return AVERROR_INVALIDDATA; - if (bits[p] == 0) - continue; + return AVERROR_INVALIDDATA; + if (!bits[p]) { + codes[p] = 0; + continue; + } // find corresponding exit(node which the tree can grow further from) for (i = bits[p]; i > 0; --i) if (exit_at_level[i]) diff --git a/libavcodec/vorbis_enc_data.h b/libavcodec/vorbis_enc_data.h index a51aaec978..eca43dfded 100644 --- a/libavcodec/vorbis_enc_data.h +++ b/libavcodec/vorbis_enc_data.h @@ -23,15 +23,78 @@ #include -static const uint8_t codebook0[] = { +static const uint8_t floor_128_c0[] = { + 10, 7, 8, 13, 9, 6, 7, 11, 10, 8, 8, 12, 17, 17, 17, + 17, 7, 5, 5, 9, 6, 4, 4, 8, 8, 5, 5, 8, 16, 14, + 13, 16, 7, 5, 5, 7, 6, 3, 3, 5, 8, 5, 4, 7, 14, + 12, 12, 15, 10, 7, 8, 9, 7, 5, 5, 6, 9, 6, 5, 5, + 15, 12, 9, 10, +}; + +static const uint8_t floor_128_c1[] = { + 8, 13, 17, 17, 8, 11, 17, 17, 11, 13, 17, 17, 17, 17, 17, + 17, 6, 10, 16, 17, 6, 10, 15, 17, 8, 10, 16, 17, 17, 17, + 17, 17, 9, 13, 15, 17, 8, 11, 17, 17, 10, 12, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 6, 11, 15, 17, 7, 10, 15, 17, 8, 10, 17, + 17, 17, 15, 17, 17, 4, 8, 13, 17, 4, 7, 13, 17, 6, 8, + 15, 17, 16, 15, 17, 17, 6, 11, 15, 17, 6, 9, 13, 17, 8, + 10, 17, 17, 15, 17, 17, 17, 16, 17, 17, 17, 12, 14, 15, 17, + 13, 14, 15, 17, 17, 17, 17, 17, 5, 10, 14, 17, 5, 9, 14, + 17, 7, 9, 15, 17, 15, 15, 17, 17, 3, 7, 12, 17, 3, 6, + 11, 17, 5, 7, 13, 17, 12, 12, 17, 17, 5, 9, 14, 17, 3, + 7, 11, 17, 5, 8, 13, 17, 13, 11, 16, 17, 12, 17, 17, 17, + 9, 14, 15, 17, 10, 11, 14, 17, 16, 14, 17, 17, 8, 12, 17, + 17, 8, 12, 17, 17, 10, 12, 17, 17, 17, 17, 17, 17, 5, 10, + 17, 17, 5, 9, 15, 17, 7, 9, 17, 17, 13, 13, 17, 17, 7, + 11, 17, 17, 6, 10, 15, 17, 7, 9, 15, 17, 12, 11, 17, 17, + 12, 15, 17, 17, 11, 14, 17, 17, 11, 10, 15, 17, 17, 16, 17, + 17, +}; + +static const uint8_t floor_128_0sub1[] = { + 0, 3, 3, 3, 3, 3, 3, 3, 3, +}; + +static const uint8_t floor_128_0sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 4, 4, 4, + 4, 5, 4, 5, 4, 5, 4, 6, 4, 6, +}; + +static const uint8_t floor_128_0sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 3, 5, 3, + 5, 4, 5, 4, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, + 5, 6, 5, 7, 8, 9, 11, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, +}; + +static const uint8_t floor_128_1sub1[] = { + 0, 3, 3, 2, 3, 3, 4, 3, 4, +}; + +static const uint8_t floor_128_1sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 6, 3, 6, + 3, 6, 3, 7, 3, 8, 4, 9, 4, 9, +}; + +static const uint8_t floor_128_1sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 7, 2, 7, 3, + 8, 4, 9, 5, 9, 8, 10, 11, 11, 12, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 13, 13, 13, 13, +}; + +static const uint8_t floor_1024_c1[] = { 2, 10, 8, 14, 7, 12, 11, 14, 1, 5, 3, 7, 4, 9, 7, 13, }; -static const uint8_t codebook1[] = { +static const uint8_t floor_1024_c2[] = { 1, 4, 2, 6, 3, 7, 5, 7, }; -static const uint8_t codebook2[] = { +static const uint8_t floor_1024_c3[] = { 1, 5, 7, 21, 5, 8, 9, 21, 10, 9, 12, 20, 20, 16, 20, 20, 4, 8, 9, 20, 6, 8, 9, 20, 11, 11, 13, 20, 20, 15, 17, 20, 9, 11, 14, 20, 8, 10, 15, 20, 11, 13, 15, 20, 20, @@ -52,7 +115,7 @@ static const uint8_t codebook2[] = { 20, }; -static const uint8_t codebook3[] = { +static const uint8_t floor_1024_c4[] = { 2, 3, 7, 13, 4, 4, 7, 15, 8, 6, 9, 17, 21, 16, 15, 21, 2, 5, 7, 11, 5, 5, 7, 14, 9, 7, 10, 16, 17, 15, 16, 21, 4, 7, 10, 17, 7, 7, 9, 15, 11, 9, 11, 16, 21, @@ -60,7 +123,7 @@ static const uint8_t codebook3[] = { 21, 21, 21, 20, }; -static const uint8_t codebook4[] = { +static const uint8_t floor_1024_0sub0[] = { 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 7, 5, 7, 5, 7, 5, 7, 5, 8, 6, 8, 6, 8, 6, 9, 6, 9, 6, 10, 6, 10, @@ -72,79 +135,91 @@ static const uint8_t codebook4[] = { 21, 21, 21, 21, 21, 21, 21, 21, }; -static const uint8_t codebook5[] = { +static const uint8_t floor_1024_1sub0[] = { 2, 5, 5, 4, 5, 4, 5, 4, 5, 4, 6, 5, 6, 5, 6, 5, 6, 5, 7, 5, 7, 6, 8, 6, 8, 6, 8, 6, 9, 6, 9, 6, }; -static const uint8_t codebook6[] = { - 8, 5, 8, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, - 4, 9, 4, 9, 4, 9, 4, 8, 4, 8, 4, 9, 5, 9, 5, - 9, 5, 9, 5, 9, 6, 10, 6, 10, 7, 10, 8, 11, 9, 11, - 11, 12, 13, 12, 14, 13, 15, 13, 15, 14, 16, 14, 17, 15, 17, - 15, 15, 16, 16, 15, 16, 16, 16, 15, 18, 16, 15, 17, 17, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, +static const uint8_t floor_1024_1sub1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 5, 8, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, + 4, 9, 4, 9, 4, 9, 4, 9, 4, 8, 4, 8, 4, 9, 5, + 9, 5, 9, 5, 9, 5, 9, 6, 10, 6, 10, 7, 10, 8, 11, + 9, 11, 11, 12, 13, 12, 14, 13, 15, 13, 15, 14, 16, 14, 17, + 15, 17, 15, 15, 16, 16, 15, 16, 16, 16, 15, 18, 16, 15, 17, + 17, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, }; -static const uint8_t codebook7[] = { +static const uint8_t floor_1024_2sub0[] = { 1, 5, 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 6, 7, 7, 7, 7, 8, 7, 8, 8, 9, 8, 10, 9, 10, 9, }; -static const uint8_t codebook8[] = { - 4, 3, 4, 3, 4, 4, 5, 4, 5, 4, 5, 5, 6, 5, 6, - 5, 7, 5, 7, 6, 7, 6, 8, 7, 8, 7, 8, 7, 9, 8, - 9, 9, 9, 9, 10, 10, 10, 11, 9, 12, 9, 12, 9, 15, 10, - 14, 9, 13, 10, 13, 10, 12, 10, 12, 10, 13, 10, 12, 11, 13, - 11, 14, 12, 13, 13, 14, 14, 13, 14, 15, 14, 16, 13, 13, 14, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 15, 15, +static const uint8_t floor_1024_2sub1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 3, 4, 3, 4, 4, 5, 4, 5, 4, 5, 5, 6, + 5, 6, 5, 7, 5, 7, 6, 7, 6, 8, 7, 8, 7, 8, 7, + 9, 8, 9, 9, 9, 9, 10, 10, 10, 11, 9, 12, 9, 12, 9, + 15, 10, 14, 9, 13, 10, 13, 10, 12, 10, 12, 10, 13, 10, 12, + 11, 13, 11, 14, 12, 13, 13, 14, 14, 13, 14, 15, 14, 16, 13, + 13, 14, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 15, 15 }; -static const uint8_t codebook9[] = { - 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, 4, 4, 4, 5, - 5, 5, +static const uint8_t floor_1024_3sub1[] = { + 0, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, 4, 4, 4, + 5, 5, 5, }; -static const uint8_t codebook10[] = { - 3, 3, 4, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 5, - 7, 5, 8, 6, 8, 6, 9, 7, 10, 7, 10, 8, 10, 8, 11, - 9, 11, +static const uint8_t floor_1024_3sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 3, 4, 3, 4, 4, 4, 4, 5, 5, 5, 5, + 5, 6, 5, 7, 5, 8, 6, 8, 6, 9, 7, 10, 7, 10, 8, + 10, 8, 11, 9, 11, }; -static const uint8_t codebook11[] = { - 3, 7, 3, 8, 3, 10, 3, 8, 3, 9, 3, 8, 4, 9, 4, - 9, 5, 9, 6, 10, 6, 9, 7, 11, 7, 12, 9, 13, 10, 13, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +static const uint8_t floor_1024_3sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 7, 3, 8, 3, 10, 3, 8, 3, 9, + 3, 8, 4, 9, 4, 9, 5, 9, 6, 10, 6, 9, 7, 11, 7, + 12, 9, 13, 10, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, }; -static const uint8_t codebook12[] = { - 4, 5, 4, 5, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, - 5, 4, +static const uint8_t floor_1024_4sub1[] = { + 0, 4, 5, 4, 5, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, + 4, 5, 4, }; -static const uint8_t codebook13[] = { - 4, 2, 4, 2, 5, 3, 5, 4, 6, 6, 6, 7, 7, 8, 7, - 8, 7, 8, 7, 9, 8, 9, 8, 9, 8, 10, 8, 11, 9, 12, - 9, 12, +static const uint8_t floor_1024_4sub2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 2, 4, 2, 5, 3, 5, 4, 6, 6, 6, 7, + 7, 8, 7, 8, 7, 8, 7, 9, 8, 9, 8, 9, 8, 10, 8, + 11, 9, 12, 9, 12, }; -static const uint8_t codebook14[] = { - 2, 5, 2, 6, 3, 6, 4, 7, 4, 7, 5, 9, 5, 11, 6, - 11, 6, 11, 7, 11, 6, 11, 6, 11, 9, 11, 8, 11, 11, 11, +static const uint8_t floor_1024_4sub3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 5, 2, 6, 3, 6, 4, 7, 4, 7, + 5, 9, 5, 11, 6, 11, 6, 11, 7, 11, 6, 11, 6, 11, 9, + 11, 8, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, - 10, 10, 10, + 11, 11, 10, 10, 10, 10, 10, 10, }; -static const uint8_t codebook15[] = { +static const uint8_t res_long_master[] = { 5, 6, 11, 11, 11, 11, 10, 10, 12, 11, 5, 2, 11, 5, 6, 6, 7, 9, 11, 13, 13, 10, 7, 11, 6, 7, 8, 9, 10, 12, 11, 5, 11, 6, 8, 7, 9, 11, 14, 15, 11, 6, 6, 8, 4, @@ -154,7 +229,17 @@ static const uint8_t codebook15[] = { 11, 13, 12, 15, 12, 11, 9, 8, 8, 8, }; -static const uint8_t codebook16[] = { +static const uint8_t res_short_master[] = { + 10, 9, 13, 11, 14, 10, 12, 13, 13, 14, 7, 2, 12, 5, 10, + 5, 7, 10, 12, 14, 12, 6, 9, 8, 7, 7, 9, 11, 13, 16, + 10, 4, 12, 5, 10, 6, 8, 12, 14, 16, 12, 6, 8, 7, 6, + 5, 7, 11, 12, 16, 10, 4, 8, 5, 6, 4, 6, 9, 13, 16, + 10, 6, 10, 7, 7, 6, 7, 9, 13, 15, 12, 9, 11, 9, 8, + 6, 7, 10, 12, 14, 14, 11, 10, 9, 6, 5, 6, 9, 11, 13, + 15, 13, 11, 10, 6, 5, 6, 8, 9, 11, +}; + +static const uint8_t res_p1_0[] = { 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -267,7 +352,7 @@ static const uint8_t codebook16[] = { 0, 0, 0, 8, 9, 8, }; -static const uint8_t codebook17[] = { +static const uint8_t res_p2_0[] = { 2, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 10, 10, 0, 0, @@ -300,7 +385,7 @@ static const uint8_t codebook17[] = { 0, 9, 9, 0, 0, 0, 10, 10, }; -static const uint8_t codebook18[] = { +static const uint8_t res_p3_0[] = { 2, 4, 3, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -310,7 +395,7 @@ static const uint8_t codebook18[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 7, 9, 9, }; -static const uint8_t codebook19[] = { +static const uint8_t res_p4_0[] = { 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, 0, 0, 0, 5, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, @@ -318,7 +403,7 @@ static const uint8_t codebook19[] = { 0, 0, 0, 0, 0, 0, 9, 9, }; -static const uint8_t codebook20[] = { +static const uint8_t res_p5_0[] = { 1, 3, 4, 6, 6, 7, 7, 9, 9, 0, 5, 5, 7, 7, 7, 8, 9, 9, 0, 5, 5, 7, 7, 8, 8, 9, 9, 0, 7, 7, 8, 8, 8, 8, 10, 10, 0, 0, 0, 8, 8, 8, 8, 10, 10, @@ -327,7 +412,7 @@ static const uint8_t codebook20[] = { 0, 0, 10, 10, 11, 11, }; -static const uint8_t codebook21[] = { +static const uint8_t res_p6_0[] = { 2, 3, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 10, 10, 11, 10, 0, 5, 5, 7, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 0, 5, 5, 7, 7, 8, 8, 9, 9, 9, 9, @@ -350,7 +435,7 @@ static const uint8_t codebook21[] = { 13, 13, 13, 13, }; -static const uint8_t codebook22[] = { +static const uint8_t res_p7_0[] = { 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7, 10, 9, 9, 11, 9, 9, 4, 7, 7, 10, 9, 9, 11, 9, 9, 7, 10, 10, 11, 11, 10, 12, 11, 11, 6, 9, 9, 11, 10, 10, 11, 10, 10, @@ -359,7 +444,7 @@ static const uint8_t codebook22[] = { 11, 10, 10, 11, 10, 10, }; -static const uint8_t codebook23[] = { +static const uint8_t res_p7_1[] = { 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 10, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 10, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 10, @@ -371,7 +456,7 @@ static const uint8_t codebook23[] = { 8, }; -static const uint8_t codebook24[] = { +static const uint8_t res_p8_0[] = { 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 6, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9, 10, 10, 7, 5, 5, 7, 7, 8, 8, 8, 8, 9, 9, 11, 10, 0, 8, 8, 8, 8, 9, @@ -386,12 +471,12 @@ static const uint8_t codebook24[] = { 13, 12, 14, 13, }; -static const uint8_t codebook25[] = { +static const uint8_t res_p8_1[] = { 2, 4, 4, 5, 5, 6, 5, 5, 5, 5, 6, 4, 5, 5, 5, 6, 5, 5, 5, 5, 6, 6, 6, 5, 5, }; -static const uint8_t codebook26[] = { +static const uint8_t res_p9_0[] = { 1, 4, 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 9, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 9, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, @@ -406,7 +491,7 @@ static const uint8_t codebook26[] = { 11, 11, 11, 11, }; -static const uint8_t codebook27[] = { +static const uint8_t res_p9_1[] = { 1, 4, 4, 6, 6, 7, 7, 8, 7, 9, 9, 10, 10, 10, 10, 6, 5, 5, 7, 7, 8, 8, 10, 8, 11, 10, 12, 12, 13, 13, 6, 5, 5, 7, 7, 8, 8, 10, 9, 11, 11, 12, 12, 13, 12, @@ -424,7 +509,7 @@ static const uint8_t codebook27[] = { 18, 18, 18, 16, 17, 16, 14, 12, 11, 13, 10, 13, 13, 14, 15, }; -static const uint8_t codebook28[] = { +static const uint8_t res_p9_2[] = { 2, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 10, 6, 6, 7, 7, 8, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, @@ -457,35 +542,44 @@ static const struct { float delta; const uint8_t *quant; } cvectors[] = { - { 2, 16, 16, codebook0, 0 }, - { 2, 8, 8, codebook1, 0 }, - { 2, 256, 256, codebook2, 0 }, - { 2, 64, 64, codebook3, 0 }, - { 2, 128, 128, codebook4, 0 }, - { 2, 32, 32, codebook5, 0 }, - { 2, 96, 96, codebook6, 0 }, - { 2, 32, 32, codebook7, 0 }, - { 2, 96, 96, codebook8, 0 }, - { 2, 17, 17, codebook9, 0 }, - { 2, 32, 32, codebook10, 0 }, - { 2, 78, 78, codebook11, 0 }, - { 2, 17, 17, codebook12, 0 }, - { 2, 32, 32, codebook13, 0 }, - { 2, 78, 78, codebook14, 0 }, - { 2, 100, 100, codebook15, 0 }, - { 8, 1641, 6561, codebook16, 1, -1.0, 1.0, (const uint8_t[]){ 1, 0, 2, } }, - { 4, 443, 625, codebook17, 1, -2.0, 1.0, (const uint8_t[]){ 2, 1, 3, 0, 4, } }, - { 4, 105, 625, codebook18, 1, -2.0, 1.0, (const uint8_t[]){ 2, 1, 3, 0, 4, } }, - { 2, 68, 81, codebook19, 1, -4.0, 1.0, (const uint8_t[]){ 4, 3, 5, 2, 6, 1, 7, 0, 8, } }, - { 2, 81, 81, codebook20, 1, -4.0, 1.0, (const uint8_t[]){ 4, 3, 5, 2, 6, 1, 7, 0, 8, } }, - { 2, 289, 289, codebook21, 1, -8.0, 1.0, (const uint8_t[]){ 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, 0, 16, } }, - { 4, 81, 81, codebook22, 1, -11.0, 11.0, (const uint8_t[]){ 1, 0, 2, } }, - { 2, 121, 121, codebook23, 1, -5.0, 1.0, (const uint8_t[]){ 5, 4, 6, 3, 7, 2, 8, 1, 9, 0, 10, } }, - { 2, 169, 169, codebook24, 1, -30.0, 5.0, (const uint8_t[]){ 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12, } }, - { 2, 25, 25, codebook25, 1, -2.0, 1.0, (const uint8_t[]){ 2, 1, 3, 0, 4, } }, - { 2, 169, 169, codebook26, 1, -1530.0, 255.0, (const uint8_t[]){ 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12, } }, - { 2, 225, 225, codebook27, 1, -119.0, 17.0, (const uint8_t[]){ 7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 13, 0, 14, } }, - { 2, 289, 289, codebook28, 1, -8.0, 1.0, (const uint8_t[]){ 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, 0, 16, } }, + { 2, 64, 64, floor_128_c0, 0 }, + { 2, 256, 256, floor_128_c1, 0 }, + { 2, 16, 16, floor_1024_c1, 0 }, + { 2, 8, 8, floor_1024_c2, 0 }, + { 2, 256, 256, floor_1024_c3, 0 }, + { 2, 64, 64, floor_1024_c4, 0 }, + { 2, 9, 9, floor_128_0sub1, 0 }, + { 2, 25, 25, floor_128_0sub2, 0 }, + { 2, 64, 64, floor_128_0sub3, 0 }, + { 2, 9, 9, floor_128_1sub1, 0 }, + { 2, 25, 25, floor_128_1sub2, 0 }, + { 2, 64, 64, floor_128_1sub3, 0 }, + { 2, 128, 128, floor_1024_0sub0, 0 }, + { 2, 32, 32, floor_1024_1sub0, 0 }, + { 2, 128, 128, floor_1024_1sub1, 0 }, + { 2, 32, 32, floor_1024_2sub0, 0 }, + { 2, 128, 128, floor_1024_2sub1, 0 }, + { 2, 18, 18, floor_1024_3sub1, 0 }, + { 2, 50, 50, floor_1024_3sub2, 0 }, + { 2, 128, 128, floor_1024_3sub3, 0 }, + { 2, 18, 18, floor_1024_4sub1, 0 }, + { 2, 50, 50, floor_1024_4sub2, 0 }, + { 2, 128, 128, floor_1024_4sub3, 0 }, + { 2, 100, 100, res_short_master, 0 }, + { 2, 100, 100, res_long_master, 0 }, + { 8, 1641, 6561, res_p1_0, 1, -1.0, 1.0, (const uint8_t[]){ 1, 0, 2, } }, + { 4, 443, 625, res_p2_0, 1, -2.0, 1.0, (const uint8_t[]){ 2, 1, 3, 0, 4, } }, + { 4, 105, 625, res_p3_0, 1, -2.0, 1.0, (const uint8_t[]){ 2, 1, 3, 0, 4, } }, + { 2, 68, 81, res_p4_0, 1, -4.0, 1.0, (const uint8_t[]){ 4, 3, 5, 2, 6, 1, 7, 0, 8, } }, + { 2, 81, 81, res_p5_0, 1, -4.0, 1.0, (const uint8_t[]){ 4, 3, 5, 2, 6, 1, 7, 0, 8, } }, + { 2, 289, 289, res_p6_0, 1, -8.0, 1.0, (const uint8_t[]){ 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, 0, 16, } }, + { 4, 81, 81, res_p7_0, 1, -11.0, 11.0, (const uint8_t[]){ 1, 0, 2, } }, + { 2, 121, 121, res_p7_1, 1, -5.0, 1.0, (const uint8_t[]){ 5, 4, 6, 3, 7, 2, 8, 1, 9, 0, 10, } }, + { 2, 169, 169, res_p8_0, 1, -30.0, 5.0, (const uint8_t[]){ 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12, } }, + { 2, 25, 25, res_p8_1, 1, -2.0, 1.0, (const uint8_t[]){ 2, 1, 3, 0, 4, } }, + { 2, 169, 169, res_p9_0, 1, -1530.0, 255.0, (const uint8_t[]){ 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12, } }, + { 2, 225, 225, res_p9_1, 1, -119.0, 17.0, (const uint8_t[]){ 7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 13, 0, 14, } }, + { 2, 289, 289, res_p9_2, 1, -8.0, 1.0, (const uint8_t[]){ 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, 0, 16, } }, }; static const struct { @@ -493,12 +587,15 @@ static const struct { int subclass; int masterbook; const int nbooks[4]; -} floor_classes[] = { - { 3, 0, 0, { 4 } }, - { 4, 1, 0, { 5, 6 } }, - { 3, 1, 1, { 7, 8 } }, - { 4, 2, 2, { -1, 9, 10, 11 } }, - { 3, 2, 3, { -1, 12, 13, 14 } }, +} floor_classes[2][5] = { + { { 3, 2, 0, { -1, 6, 7, 8 } }, + { 4, 2, 1, { -1, 9, 10, 11 } },}, + + { { 3, 0, 2, { 12 } }, + { 4, 1, 2, { 13, 14 } }, + { 3, 1, 3, { 15, 16 } }, + { 4, 2, 4, { -1, 17, 18, 19 } }, + { 3, 2, 5, { -1, 20, 21, 22 } },}, }; #endif /* AVCODEC_VORBIS_ENC_DATA_H */ diff --git a/libavcodec/vorbisenc.c b/libavcodec/vorbisenc.c index 6da5f012c2..c968956794 100644 --- a/libavcodec/vorbisenc.c +++ b/libavcodec/vorbisenc.c @@ -106,6 +106,9 @@ typedef struct vorbis_enc_context { int channels; int sample_rate; int log2_blocksize[2]; + int blockflags[3]; ///< Flags used for the previous, current, next windows + int transient; ///< Negative if a series of transients are not being encoded + int num_transient; ///< Number of short blocks for each frame FFTContext mdct[2]; const float *win[2]; int have_saved; @@ -113,7 +116,7 @@ typedef struct vorbis_enc_context { float *samples; float *floor; // also used for tmp values for mdct float *coeffs; // also used for residue after floor - float *scratch; // used for tmp values for psy model + float *scratch; //< Used for temp values for psy model and window application float quality; AudioFrameQueue afq; @@ -268,27 +271,134 @@ static av_cold int dsp_init(AVCodecContext *avctx, vorbis_enc_context *venc) return 0; } +static int create_residues(vorbis_enc_context *venc) +{ + int res, ret; + vorbis_enc_residue *rc; + + venc->nresidues = 2; + venc->residues = av_malloc(sizeof(vorbis_enc_residue) * venc->nresidues); + if (!venc->residues) + return AVERROR(ENOMEM); + + for (res = 0; res < venc->nresidues; res++) { + rc = &venc->residues[res]; + rc->type = 2; + rc->begin = 0; + rc->end = res ? 1600 : 208; + rc->partition_size = res ? 32 : 16; + rc->classbook = res ? 24 : 23; + rc->classifications = 10; + rc->books = av_malloc(sizeof(*rc->books) * rc->classifications); + if (!rc->books) + return AVERROR(ENOMEM); + { + static const int8_t a[10][8] = { + { -1, -1, -1, -1, -1, -1, -1, -1, }, + { -1, -1, 25, -1, -1, -1, -1, -1, }, + { -1, -1, 26, -1, -1, -1, -1, -1, }, + { -1, -1, 27, -1, -1, -1, -1, -1, }, + { -1, -1, 28, -1, -1, -1, -1, -1, }, + { -1, -1, 29, -1, -1, -1, -1, -1, }, + { -1, -1, 30, -1, -1, -1, -1, -1, }, + { 31, 32, -1, -1, -1, -1, -1, -1, }, + { 33, 34, -1, -1, -1, -1, -1, -1, }, + { 35, 36, 37, -1, -1, -1, -1, -1, }, + }; + memcpy(rc->books, a, sizeof a); + } + if ((ret = ready_residue(rc, venc)) < 0) + return ret; + } + return 0; +} + +static int create_floors(vorbis_enc_context *venc, AVCodecContext *avctx) +{ + int i, floor; + vorbis_enc_floor *fc; + + venc->nfloors = 2; + venc->floors = av_malloc(sizeof(vorbis_enc_floor) * venc->nfloors); + if (!venc->floors) + return AVERROR(ENOMEM); + + for (floor = 0; floor < venc->nfloors; floor++) { + fc = &venc->floors[floor]; + fc->partitions = floor ? 8 : 2; + fc->partition_to_class = av_malloc(sizeof(int) * fc->partitions); + if (!fc->partition_to_class) + return AVERROR(ENOMEM); + fc->nclasses = 0; + for (i = 0; i < fc->partitions; i++) { + static const int a[] = {0, 1, 2, 2, 3, 3, 4, 4}; + fc->partition_to_class[i] = a[i]; + fc->nclasses = FFMAX(fc->nclasses, fc->partition_to_class[i]); + } + fc->nclasses++; + fc->classes = av_malloc_array(fc->nclasses, sizeof(vorbis_enc_floor_class)); + if (!fc->classes) + return AVERROR(ENOMEM); + for (i = 0; i < fc->nclasses; i++) { + vorbis_enc_floor_class * c = &fc->classes[i]; + int j, books; + c->dim = floor_classes[floor][i].dim; + c->subclass = floor_classes[floor][i].subclass; + c->masterbook = floor_classes[floor][i].masterbook; + books = (1 << c->subclass); + c->books = av_malloc_array(books, sizeof(int)); + if (!c->books) + return AVERROR(ENOMEM); + for (j = 0; j < books; j++) + c->books[j] = floor_classes[floor][i].nbooks[j]; + } + fc->multiplier = 2; + fc->rangebits = venc->log2_blocksize[floor] - 1; + + fc->values = 2; + for (i = 0; i < fc->partitions; i++) + fc->values += fc->classes[fc->partition_to_class[i]].dim; + + fc->list = av_malloc_array(fc->values, sizeof(vorbis_floor1_entry)); + if (!fc->list) + return AVERROR(ENOMEM); + fc->list[0].x = 0; + fc->list[1].x = 1 << fc->rangebits; + for (i = 2; i < fc->values; i++) { + static const int a[2][27] = { + { 14, 4, 58, 2, 8, 28, 90}, + { 93, 23,372, 6, 46,186,750, 14, 33, 65, + 130,260,556, 3, 10, 18, 28, 39, 55, 79, + 111,158,220,312,464,650,850} + }; + fc->list[i].x = a[floor][i - 2]; + } + if (ff_vorbis_ready_floor1_list(avctx, fc->list, fc->values)) + return AVERROR_BUG; + } + + return 0; +} + static int create_vorbis_context(vorbis_enc_context *venc, AVCodecContext *avctx) { - vorbis_enc_floor *fc; - vorbis_enc_residue *rc; vorbis_enc_mapping *mc; - int i, book, ret, blocks; + int i, map, book, ret, blocks; venc->channels = avctx->channels; venc->sample_rate = avctx->sample_rate; venc->log2_blocksize[0] = 8; venc->log2_blocksize[1] = 11; + venc->blockflags[0] = venc->blockflags[1] = venc->blockflags[2] = 1; + venc->transient = -1; + venc->num_transient = 1 << (venc->log2_blocksize[1] - venc->log2_blocksize[0]); venc->ncodebooks = FF_ARRAY_ELEMS(cvectors); venc->codebooks = av_malloc(sizeof(vorbis_enc_codebook) * venc->ncodebooks); if (!venc->codebooks) return AVERROR(ENOMEM); - // codebook 0..14 - floor1 book, values 0..255 - // codebook 15 residue masterbook - // codebook 16..29 residue for (book = 0; book < venc->ncodebooks; book++) { vorbis_enc_codebook *cb = &venc->codebooks[book]; int vals; @@ -320,126 +430,42 @@ static int create_vorbis_context(vorbis_enc_context *venc, return ret; } - venc->nfloors = 1; - venc->floors = av_malloc(sizeof(vorbis_enc_floor) * venc->nfloors); - if (!venc->floors) - return AVERROR(ENOMEM); - - // just 1 floor - fc = &venc->floors[0]; - fc->partitions = NUM_FLOOR_PARTITIONS; - fc->partition_to_class = av_malloc(sizeof(int) * fc->partitions); - if (!fc->partition_to_class) - return AVERROR(ENOMEM); - fc->nclasses = 0; - for (i = 0; i < fc->partitions; i++) { - static const int a[] = {0, 1, 2, 2, 3, 3, 4, 4}; - fc->partition_to_class[i] = a[i]; - fc->nclasses = FFMAX(fc->nclasses, fc->partition_to_class[i]); - } - fc->nclasses++; - fc->classes = av_malloc_array(fc->nclasses, sizeof(vorbis_enc_floor_class)); - if (!fc->classes) - return AVERROR(ENOMEM); - for (i = 0; i < fc->nclasses; i++) { - vorbis_enc_floor_class * c = &fc->classes[i]; - int j, books; - c->dim = floor_classes[i].dim; - c->subclass = floor_classes[i].subclass; - c->masterbook = floor_classes[i].masterbook; - books = (1 << c->subclass); - c->books = av_malloc_array(books, sizeof(int)); - if (!c->books) - return AVERROR(ENOMEM); - for (j = 0; j < books; j++) - c->books[j] = floor_classes[i].nbooks[j]; - } - fc->multiplier = 2; - fc->rangebits = venc->log2_blocksize[1] - 1; - - fc->values = 2; - for (i = 0; i < fc->partitions; i++) - fc->values += fc->classes[fc->partition_to_class[i]].dim; - - fc->list = av_malloc_array(fc->values, sizeof(vorbis_floor1_entry)); - if (!fc->list) - return AVERROR(ENOMEM); - fc->list[0].x = 0; - fc->list[1].x = 1 << fc->rangebits; - for (i = 2; i < fc->values; i++) { - static const int a[] = { - 93, 23,372, 6, 46,186,750, 14, 33, 65, - 130,260,556, 3, 10, 18, 28, 39, 55, 79, - 111,158,220,312,464,650,850 - }; - fc->list[i].x = a[i - 2]; - } - if (ff_vorbis_ready_floor1_list(avctx, fc->list, fc->values)) - return AVERROR_BUG; - - venc->nresidues = 1; - venc->residues = av_malloc(sizeof(vorbis_enc_residue) * venc->nresidues); - if (!venc->residues) - return AVERROR(ENOMEM); + if ((ret = create_floors(venc, avctx)) < 0) + return ret; - // single residue - rc = &venc->residues[0]; - rc->type = 2; - rc->begin = 0; - rc->end = 1600; - rc->partition_size = 32; - rc->classifications = 10; - rc->classbook = 15; - rc->books = av_malloc(sizeof(*rc->books) * rc->classifications); - if (!rc->books) - return AVERROR(ENOMEM); - { - static const int8_t a[10][8] = { - { -1, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, 16, -1, -1, -1, -1, -1, }, - { -1, -1, 17, -1, -1, -1, -1, -1, }, - { -1, -1, 18, -1, -1, -1, -1, -1, }, - { -1, -1, 19, -1, -1, -1, -1, -1, }, - { -1, -1, 20, -1, -1, -1, -1, -1, }, - { -1, -1, 21, -1, -1, -1, -1, -1, }, - { 22, 23, -1, -1, -1, -1, -1, -1, }, - { 24, 25, -1, -1, -1, -1, -1, -1, }, - { 26, 27, 28, -1, -1, -1, -1, -1, }, - }; - memcpy(rc->books, a, sizeof a); - } - if ((ret = ready_residue(rc, venc)) < 0) + if ((ret = create_residues(venc)) < 0) return ret; - venc->nmappings = 1; + venc->nmappings = 2; venc->mappings = av_malloc(sizeof(vorbis_enc_mapping) * venc->nmappings); if (!venc->mappings) return AVERROR(ENOMEM); - // single mapping - mc = &venc->mappings[0]; - mc->submaps = 1; - mc->mux = av_malloc(sizeof(int) * venc->channels); - if (!mc->mux) - return AVERROR(ENOMEM); - for (i = 0; i < venc->channels; i++) - mc->mux[i] = 0; - mc->floor = av_malloc(sizeof(int) * mc->submaps); - mc->residue = av_malloc(sizeof(int) * mc->submaps); - if (!mc->floor || !mc->residue) - return AVERROR(ENOMEM); - for (i = 0; i < mc->submaps; i++) { - mc->floor[i] = 0; - mc->residue[i] = 0; - } - mc->coupling_steps = venc->channels == 2 ? 1 : 0; - mc->magnitude = av_malloc(sizeof(int) * mc->coupling_steps); - mc->angle = av_malloc(sizeof(int) * mc->coupling_steps); - if (!mc->magnitude || !mc->angle) - return AVERROR(ENOMEM); - if (mc->coupling_steps) { - mc->magnitude[0] = 0; - mc->angle[0] = 1; + for (map = 0; map < venc->nmappings; map++) { + mc = &venc->mappings[map]; + mc->submaps = 1; + mc->mux = av_malloc(sizeof(int) * venc->channels); + if (!mc->mux) + return AVERROR(ENOMEM); + for (i = 0; i < venc->channels; i++) + mc->mux[i] = 0; + mc->floor = av_malloc(sizeof(int) * mc->submaps); + mc->residue = av_malloc(sizeof(int) * mc->submaps); + if (!mc->floor || !mc->residue) + return AVERROR(ENOMEM); + for (i = 0; i < mc->submaps; i++) { + mc->floor[i] = map; + mc->residue[i] = map; + } + mc->coupling_steps = venc->channels == 2 ? 1 : 0; + mc->magnitude = av_malloc(sizeof(int) * mc->coupling_steps); + mc->angle = av_malloc(sizeof(int) * mc->coupling_steps); + if (!mc->magnitude || !mc->angle) + return AVERROR(ENOMEM); + if (mc->coupling_steps) { + mc->magnitude[0] = 0; + mc->angle[0] = 1; + } } venc->nmodes = 2; @@ -452,7 +478,7 @@ static int create_vorbis_context(vorbis_enc_context *venc, venc->modes[0].mapping = 0; // Long block venc->modes[1].blockflag = 1; - venc->modes[1].mapping = 0; + venc->modes[1].mapping = 1; venc->have_saved = 0; venc->saved = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1]) / 2); @@ -499,7 +525,7 @@ static void put_codebook_header(PutBitContext *pb, vorbis_enc_codebook *cb) put_bits(pb, 24, cb->nentries); for (i = 1; i < cb->nentries; i++) - if (cb->lens[i] < cb->lens[i-1]) + if (cb->lens[i-1] == 0 || cb->lens[i] < cb->lens[i-1]) break; if (i == cb->nentries) ordered = 1; @@ -943,10 +969,11 @@ static int residue_encode(vorbis_enc_context *venc, vorbis_enc_residue *rc, if (pass == 0) for (j = 0; j < channels; j++) { vorbis_enc_codebook * book = &venc->codebooks[rc->classbook]; - int entry = 0; - for (i = 0; i < classwords; i++) { + int entry = classes[j][p]; + for (i = 1; i < classwords; i++) { entry *= rc->classifications; - entry += classes[j][p + i]; + if (p + i < partitions) + entry += classes[j][p + i]; } if (put_codeword(pb, book, entry)) return AVERROR(EINVAL); @@ -1005,27 +1032,82 @@ static int residue_encode(vorbis_enc_context *venc, vorbis_enc_residue *rc, return 0; } -static int apply_window_and_mdct(vorbis_enc_context *venc) +/** + * Overlap windowed samples based on the suggested sequence from psy model. + * See Vorbis I spec Fig. 2, 3 for examples. + */ +static void apply_window(vorbis_enc_context *venc, const int *blockflags, + float *out, float* in) { - int channel; - const float * win = venc->win[1]; - int window_len = 1 << (venc->log2_blocksize[1] - 1); - float n = (float)(1 << venc->log2_blocksize[1]) / 4.0; + int prev_size, curr_size, next_size, bound; + float scale = 1.0f / (float) (1 << (venc->log2_blocksize[blockflags[1]] - 2)); + const float *prev_win, *next_win; AVFloatDSPContext *fdsp = venc->fdsp; - for (channel = 0; channel < venc->channels; channel++) { - float *offset = venc->samples + channel * window_len * 2; + prev_size = 1 << (venc->log2_blocksize[blockflags[0]] - 1); + curr_size = 1 << (venc->log2_blocksize[blockflags[1]] - 1); + next_size = 1 << (venc->log2_blocksize[blockflags[2]] - 1); + + prev_win = venc->win[blockflags[0]]; + next_win = venc->win[blockflags[2]]; + + bound = curr_size / 2 - prev_size / 2; + memset(out, 0, sizeof(float) * bound); + + fdsp->vector_fmul(out + bound, in + bound, prev_win, prev_size); + bound += prev_size; - fdsp->vector_fmul(offset, offset, win, window_len); - fdsp->vector_fmul_scalar(offset, offset, 1/n, window_len); + memcpy(out + bound, in + bound, sizeof(float) * (curr_size - bound)); + bound = curr_size + curr_size / 2 - next_size / 2; - offset += window_len; + memcpy(out + curr_size, in + curr_size, sizeof(float) * (bound - curr_size)); - fdsp->vector_fmul_reverse(offset, offset, win, window_len); - fdsp->vector_fmul_scalar(offset, offset, 1/n, window_len); + memcpy(out + bound, in + bound, sizeof(float) * (curr_size / 2 - next_size / 2)); + bound += curr_size / 2 - next_size / 2; + + fdsp->vector_fmul_reverse(out + bound, in + bound, next_win, next_size); + bound += next_size; + + memset(out + bound, 0, sizeof(float) * (2 * curr_size - bound)); + fdsp->vector_fmul_scalar(out, out, scale, 2 * curr_size); +} - venc->mdct[1].mdct_calc(&venc->mdct[1], venc->coeffs + channel * window_len, - venc->samples + channel * window_len * 2); +static int apply_window_and_mdct(vorbis_enc_context *venc, int next_type) +{ + int channel, transient_offset, curr_len, curr_type; + int *blockflags = venc->blockflags; + int short_len = 1 << (venc->log2_blocksize[0] - 1); + int long_len = 1 << (venc->log2_blocksize[1] - 1); + + if (venc->transient < 0) { + curr_type = venc->blockflags[2]; + transient_offset = 0; + } else { + curr_type = 0; + transient_offset = venc->transient * short_len; + } + + if (!curr_type) + venc->transient++; + + blockflags[0] = curr_type ? blockflags[1] : 0; + blockflags[1] = curr_type; + blockflags[2] = curr_type ? next_type : 0; + + curr_len = curr_type ? long_len : short_len; + for (channel = 0; channel < venc->channels; channel++) { + float *out = venc->scratch; + float *in = venc->samples + channel * 2 * long_len + transient_offset; + + apply_window(venc, blockflags, out, in); + + venc->mdct[curr_type].mdct_calc(&venc->mdct[curr_type], + venc->coeffs + channel * curr_len, out); + } + + if (venc->transient < 0 || venc->transient >= venc->num_transient - 1) { + blockflags[2] = next_type; + venc->transient = -1; } return 1; } @@ -1093,10 +1175,9 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) { vorbis_enc_context *venc = avctx->priv_data; - int i, ret, need_more, ch; - int curr_win = 1; - int frame_size = 1 << (venc->log2_blocksize[1] - 1); - int block_size = 1 << (venc->log2_blocksize[0] - 1); + int i, ret, need_more, ch, curr_len, next_win = 1; + int long_win = 1 << (venc->log2_blocksize[1] - 1); + int short_win = 1 << (venc->log2_blocksize[0] - 1); vorbis_enc_mode *mode; vorbis_enc_mapping *mapping; PutBitContext pb; @@ -1109,15 +1190,15 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, if (!venc->afq.remaining_samples) return 0; - need_more = venc->bufqueue.available * avctx->frame_size < frame_size; + need_more = venc->bufqueue.available * avctx->frame_size < long_win; need_more = frame && need_more; if (need_more) return 0; /* Pad the bufqueue with empty frames for encoding the last packet. */ if (!frame) { - if (venc->bufqueue.available * avctx->frame_size < frame_size) { - int frames_needed = (frame_size/avctx->frame_size) - venc->bufqueue.available; + if (venc->bufqueue.available * avctx->frame_size < long_win) { + int frames_needed = (long_win / avctx->frame_size) - venc->bufqueue.available; for (int i = 0; i < frames_needed; i++) { AVFrame *empty = spawn_empty_frame(avctx, venc->channels); @@ -1129,17 +1210,19 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } } - move_audio(venc, avctx->frame_size); + if (venc->transient < 0) { + move_audio(venc, avctx->frame_size); - for (ch = 0; ch < venc->channels; ch++) { - float *scratch = venc->scratch + 2 * ch * frame_size + frame_size; + for (ch = 0; ch < venc->channels; ch++) { + float *scratch = venc->scratch + 2 * ch * long_win + long_win; - if (!ff_psy_vorbis_block_frame(&venc->vpctx, scratch, ch, - frame_size, block_size)) - curr_win = 0; + if (!ff_psy_vorbis_block_frame(&venc->vpctx, scratch, ch, + long_win, short_win)) + next_win = 0; + } } - if (!apply_window_and_mdct(venc)) + if (!apply_window_and_mdct(venc, next_win)) return 0; if ((ret = ff_alloc_packet2(avctx, avpkt, 8192, 0)) < 0) @@ -1154,33 +1237,34 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, put_bits(&pb, 1, 0); // magic bit - put_bits(&pb, ilog(venc->nmodes - 1), 1); // Mode for current frame - - mode = &venc->modes[1]; + put_bits(&pb, ilog(venc->nmodes - 1), venc->blockflags[1]); // Mode for current frame + mode = &venc->modes[venc->blockflags[1]]; mapping = &venc->mappings[mode->mapping]; if (mode->blockflag) { - put_bits(&pb, 1, 1); // Previous windowflag - put_bits(&pb, 1, 1); // Next windowflag + put_bits(&pb, 1, venc->blockflags[0]); // Previous windowflag + put_bits(&pb, 1, venc->blockflags[2]); // Next windowflag } - for (i = 0; i < venc->channels; i++) { - vorbis_enc_floor *fc = &venc->floors[mapping->floor[mapping->mux[i]]]; + curr_len = venc->blockflags[1] ? long_win : short_win; + for (ch = 0; ch < venc->channels; ch++) { + vorbis_enc_floor *fc = &venc->floors[mapping->floor[mapping->mux[ch]]]; uint16_t posts[MAX_FLOOR_VALUES]; - floor_fit(venc, fc, &venc->coeffs[i * frame_size], posts, frame_size); - if (floor_encode(venc, fc, &pb, posts, &venc->floor[i * frame_size], frame_size)) { + + floor_fit(venc, fc, &venc->coeffs[ch * curr_len], posts, curr_len); + if (floor_encode(venc, fc, &pb, posts, &venc->floor[ch * curr_len], curr_len)) { av_log(avctx, AV_LOG_ERROR, "output buffer is too small\n"); return AVERROR(EINVAL); } } - for (i = 0; i < venc->channels * frame_size; i++) + for (i = 0; i < venc->channels * curr_len; i++) venc->coeffs[i] /= venc->floor[i]; for (i = 0; i < mapping->coupling_steps; i++) { - float *mag = venc->coeffs + mapping->magnitude[i] * frame_size; - float *ang = venc->coeffs + mapping->angle[i] * frame_size; + float *mag = venc->coeffs + mapping->magnitude[i] * curr_len; + float *ang = venc->coeffs + mapping->angle[i] * curr_len; int j; - for (j = 0; j < frame_size; j++) { + for (j = 0; j < curr_len; j++) { float a = ang[j]; ang[j] -= mag[j]; if (mag[j] > 0) @@ -1191,7 +1275,7 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } if (residue_encode(venc, &venc->residues[mapping->residue[mapping->mux[0]]], - &pb, venc->coeffs, frame_size, venc->channels)) { + &pb, venc->coeffs, curr_len, venc->channels)) { av_log(avctx, AV_LOG_ERROR, "output buffer is too small\n"); return AVERROR(EINVAL); } @@ -1199,13 +1283,13 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, flush_put_bits(&pb); avpkt->size = put_bits_count(&pb) >> 3; - ff_af_queue_remove(&venc->afq, frame_size, &avpkt->pts, &avpkt->duration); + ff_af_queue_remove(&venc->afq, curr_len, &avpkt->pts, &avpkt->duration); - if (frame_size > avpkt->duration) { + if (long_win > avpkt->duration) { uint8_t *side = av_packet_new_side_data(avpkt, AV_PKT_DATA_SKIP_SAMPLES, 10); if (!side) return AVERROR(ENOMEM); - AV_WL32(&side[4], frame_size - avpkt->duration); + AV_WL32(&side[4], curr_len - avpkt->duration); } *got_packet_ptr = 1; diff --git a/tests/fate/vorbis.mak b/tests/fate/vorbis.mak index 354cc57a0f..bacedc7629 100644 --- a/tests/fate/vorbis.mak +++ b/tests/fate/vorbis.mak @@ -2,7 +2,7 @@ FATE_VORBIS += fate-vorbis-encode fate-vorbis-encode: CMD = enc_dec_pcm ogg wav s16le $(TARGET_SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav -c:a vorbis -strict experimental fate-vorbis-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-vorbis-encode: CMP_SHIFT = 0 -fate-vorbis-encode: CMP_TARGET = 296 +fate-vorbis-encode: CMP_TARGET = 650 fate-vorbis-encode: SIZE_TOLERANCE = 3560 fate-vorbis-encode: FUZZ = 30