[FFmpeg-devel] [PATCH V4 2/2] avcodec/vorbisenc: Apply dynamic frame lengths
Tyler Jones
tdjones879 at gmail.com
Fri Jul 28 18:15:40 EEST 2017
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 <tdjones879 at gmail.com>
---
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 <stdint.h>
-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
--
2.13.3
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20170728/7bacccc4/attachment.sig>
More information about the ffmpeg-devel
mailing list