[FFmpeg-devel,6/6] avcodec/vorbisenc: Add support for mono streams

Submitted by Tyler Jones on Aug. 22, 2017, 1:23 a.m.

Details

Message ID 20170822012307.6019-7-tdjones879@gmail.com
State New
Headers show

Commit Message

Tyler Jones Aug. 22, 2017, 1:23 a.m.
Signed-off-by: Tyler Jones <tdjones879@gmail.com>
---
 libavcodec/vorbis_enc_data.h | 245 ++++++++++++++++++++++++++++++++++++++++++-
 libavcodec/vorbisenc.c       |  46 ++++----
 2 files changed, 267 insertions(+), 24 deletions(-)

Patch hide | download patch | download mbox

diff --git a/libavcodec/vorbis_enc_data.h b/libavcodec/vorbis_enc_data.h
index 6f2b10feb9..32750da803 100644
--- a/libavcodec/vorbis_enc_data.h
+++ b/libavcodec/vorbis_enc_data.h
@@ -23,6 +23,9 @@ 
 
 #include <stdint.h>
 
+#define RES_PASSES       8
+#define RES_MAX_CLASSIF 10
+
 typedef const struct {
     int dim;
     int len;
@@ -35,12 +38,11 @@  typedef const struct {
 } codebook_setup;
 
 typedef const struct {
-    const int type;
     const int end[2];
     const int classifications;
     const int nbooks;
     const codebook_setup *config;
-    const int8_t books[10][8];
+    const int8_t books[RES_MAX_CLASSIF][RES_PASSES];
 } res_setup;
 
 static const uint8_t floor_128_c0[] = {
@@ -552,6 +554,209 @@  static const uint8_t res_stereo_p9_2[] = {
      9, 10, 10, 10,
 };
 
+static const uint8_t res_mono_long_master[] = {
+     6,  9, 13, 12, 14, 11, 10, 13,  8,  4,  5,  7,  8,  7,  8,
+    12, 11,  4,  3,  5,  5,  7,  9, 14, 11,  6,  5,  6,  6,  6,
+     7, 13, 13,  7,  5,  6,  4,  5,  7, 14, 11,  7,  6,  6,  5,
+     5,  6, 13,  9,  7,  8,  6,  7,  5,  3,  9,  9, 12, 13, 12,
+    14, 10,  6,  7,
+};
+
+static const uint8_t res_mono_short_master[] = {
+    14, 14, 14, 15, 13, 15, 12, 16, 10,  8,  7,  9,  9,  8, 12,
+    16, 10,  5,  4,  6,  5,  6,  9, 16, 14,  8,  6,  8,  7,  8,
+    10, 16, 14,  7,  4,  6,  3,  5,  8, 16, 15,  9,  5,  7,  4,
+     4,  7, 16, 13, 10,  6,  7,  4,  3,  4, 13, 13, 12,  7,  9,
+     5,  5,  6, 12,
+};
+
+static const uint8_t res_mono_p1_0[] = {
+     1,  4,  4,  5,  8,  7,  5,  7,  8,  5,  8,  8,  8, 10, 11,
+     8, 10, 11,  5,  8,  8,  8, 11, 10,  8, 11, 11,  4,  8,  8,
+     8, 11, 11,  8, 11, 11,  8, 11, 11, 11, 13, 14, 11, 14, 14,
+     8, 11, 11, 10, 14, 12, 11, 14, 14,  4,  8,  8,  8, 11, 11,
+     8, 11, 11,  7, 11, 11, 11, 14, 14, 10, 12, 14,  8, 11, 11,
+    11, 14, 14, 11, 14, 13,
+};
+
+static const uint8_t res_mono_p2_0[] = {
+     2,  5,  4,  5,  6,  6,  5,  6,  6,  5,  6,  6,  7,  8,  8,
+     6,  8,  8,  5,  6,  6,  6,  8,  8,  7,  8,  8,  5,  7,  6,
+     7,  8,  8,  6,  8,  8,  7,  8,  8,  8,  9, 10,  8, 10, 10,
+     6,  8,  8,  8, 10,  8,  8, 10, 10,  5,  6,  6,  6,  8,  8,
+     7,  8,  8,  6,  8,  8,  8, 10, 10,  8,  8, 10,  7,  8,  8,
+     8, 10, 10,  8, 10,  9,
+};
+
+static const uint8_t res_mono_p3_0[] = {
+     2,  4,  4,  7,  7,  5,  7,  7,  9,  9,  5,  7,  7,  9,  9,
+     8,  9,  9, 12, 12,  8,  9,  9, 11, 12,  5,  7,  7, 10, 10,
+     7,  9,  9, 11, 11,  7,  9,  9, 10, 11, 10, 11, 11, 13, 13,
+     9, 10, 11, 13, 13,  5,  7,  7, 10, 10,  7,  9,  9, 11, 10,
+     7,  9,  9, 11, 11,  9, 11, 10, 13, 13, 10, 11, 11, 14, 13,
+     8, 10, 10, 14, 13, 10, 11, 11, 15, 14,  9, 11, 11, 14, 14,
+    13, 14, 13, 16, 16, 12, 13, 13, 15, 15,  8, 10, 10, 13, 14,
+     9, 11, 11, 14, 14, 10, 11, 11, 14, 15, 12, 13, 13, 15, 15,
+    13, 14, 14, 15, 16,  5,  7,  7, 10, 10,  7,  9,  9, 11, 11,
+     7,  9,  9, 11, 12, 10, 11, 11, 14, 14, 10, 11, 11, 14, 14,
+     7,  9,  9, 12, 12,  9, 11, 11, 13, 13,  9, 11, 11, 13, 13,
+    12, 12, 13, 15, 15, 11, 12, 13, 15, 16,  7,  9,  9, 11, 11,
+     8, 11, 10, 13, 12,  9, 11, 11, 13, 13, 11, 13, 12, 15, 13,
+    11, 13, 13, 15, 16,  9, 12, 11, 15, 14, 11, 12, 13, 16, 15,
+    11, 13, 13, 15, 16, 14, 14, 15, 17, 16, 13, 15, 16,  0, 17,
+     9, 11, 11, 15, 15, 10, 13, 12, 15, 15, 11, 13, 13, 15, 16,
+    13, 15, 13, 16, 15, 14, 16, 15,  0, 19,  5,  7,  7, 10, 10,
+     7,  9,  9, 11, 11,  7,  9,  9, 11, 11, 10, 12, 11, 14, 14,
+    10, 11, 12, 14, 14,  7,  9,  9, 12, 12,  9, 11, 11, 14, 13,
+     9, 10, 11, 12, 13, 11, 13, 13, 16, 16, 11, 12, 13, 13, 16,
+     7,  9,  9, 12, 12,  9, 11, 11, 13, 13,  9, 11, 11, 13, 13,
+    11, 13, 13, 15, 15, 12, 13, 12, 15, 14,  9, 11, 11, 15, 14,
+    11, 13, 12, 16, 16, 10, 12, 12, 15, 15, 13, 15, 15, 17, 19,
+    13, 14, 15, 16, 17, 10, 12, 12, 15, 15, 11, 13, 13, 16, 16,
+    11, 13, 13, 15, 16, 13, 15, 15,  0,  0, 14, 15, 15, 16, 16,
+     8, 10, 10, 14, 14, 10, 12, 12, 15, 15, 10, 12, 11, 15, 16,
+    14, 15, 15, 19, 20, 13, 14, 14, 18, 16,  9, 11, 11, 15, 15,
+    11, 13, 13, 17, 16, 11, 13, 13, 16, 16, 15, 17, 17, 20, 20,
+    14, 15, 16, 17, 20,  9, 11, 11, 15, 15, 10, 13, 12, 16, 15,
+    11, 13, 13, 15, 17, 14, 16, 15, 18,  0, 14, 16, 15, 18, 20,
+    12, 14, 14,  0,  0, 14, 14, 16,  0,  0, 13, 16, 15,  0,  0,
+    17, 17, 18,  0,  0, 16, 17, 19, 19,  0, 12, 14, 14, 18,  0,
+    12, 16, 14,  0, 17, 13, 15, 15, 18,  0, 16, 18, 17,  0, 17,
+    16, 18, 17,  0,  0,  7, 10, 10, 14, 14, 10, 12, 11, 15, 15,
+    10, 12, 12, 16, 15, 13, 15, 15, 18,  0, 14, 15, 15, 17,  0,
+     9, 11, 11, 15, 15, 11, 13, 13, 16, 16, 11, 12, 13, 16, 16,
+    14, 15, 16, 17, 17, 14, 16, 16, 16, 18,  9, 11, 12, 16, 16,
+    11, 13, 13, 17, 17, 11, 14, 13, 20, 17, 15, 16, 16, 19,  0,
+    15, 16, 17,  0, 19, 11, 13, 14, 17, 16, 14, 15, 15, 20, 18,
+    13, 14, 15, 17, 19, 16, 18, 18,  0, 20, 16, 16, 19, 17,  0,
+    12, 15, 14, 17,  0, 14, 15, 15, 18, 19, 13, 16, 15, 19, 20,
+    15, 18, 18,  0, 20, 17,  0, 16,  0,  0,
+};
+
+static const uint8_t res_mono_p4_0[] = {
+     4,  5,  5,  8,  8,  5,  7,  6,  9,  9,  5,  6,  7,  9,  9,
+     9,  9,  9, 11, 11,  9,  9,  9, 11, 11,  5,  7,  7,  9,  9,
+     7,  8,  8, 10, 10,  7,  7,  8, 10, 10,  9, 10, 10, 11, 12,
+     9, 10, 10, 11, 12,  5,  7,  7,  9,  9,  7,  8,  7, 10, 10,
+     7,  8,  8, 10, 10,  9, 10,  9, 12, 11,  9, 10, 10, 12, 11,
+     9, 10,  9, 12, 12,  9, 10, 10, 13, 12,  9, 10, 10, 12, 13,
+    12, 12, 12, 14, 14, 11, 12, 12, 13, 14,  9,  9, 10, 12, 12,
+     9, 10, 10, 12, 12,  9, 10, 10, 12, 13, 11, 12, 11, 14, 13,
+    12, 12, 12, 14, 13,  5,  7,  7,  9,  9,  7,  8,  8, 10, 10,
+     7,  8,  8, 10, 10, 10, 10, 10, 12, 12,  9, 10, 10, 12, 12,
+     7,  8,  8, 11, 10,  8,  8,  9, 11, 11,  8,  9,  9, 11, 11,
+    11, 11, 11, 12, 13, 10, 11, 11, 13, 13,  6,  8,  8, 10, 10,
+     7,  9,  8, 11, 10,  8,  9,  9, 11, 11, 10, 11, 10, 13, 11,
+    10, 11, 11, 13, 13,  9, 11, 10, 13, 12, 10, 11, 11, 13, 13,
+    10, 11, 11, 13, 13, 12, 12, 13, 12, 15, 12, 13, 13, 15, 15,
+     9, 10, 10, 12, 13, 10, 11, 10, 13, 12, 10, 11, 11, 13, 14,
+    12, 13, 11, 15, 13, 12, 13, 13, 15, 15,  5,  7,  7,  9,  9,
+     7,  8,  8, 10, 10,  7,  8,  8, 10, 10,  9, 10, 10, 12, 12,
+    10, 10, 11, 12, 12,  6,  8,  8, 10, 10,  8,  9,  9, 11, 11,
+     7,  8,  9, 10, 11, 10, 11, 11, 13, 13, 10, 10, 11, 11, 13,
+     7,  8,  8, 10, 10,  8,  9,  9, 11, 11,  8,  9,  9, 11, 11,
+    10, 11, 11, 13, 13, 11, 11, 11, 13, 12,  9, 10, 10, 13, 12,
+    10, 11, 11, 14, 13, 10, 10, 11, 12, 13, 12, 13, 13, 15, 15,
+    12, 11, 13, 13, 14,  9, 10, 11, 12, 13, 10, 11, 11, 13, 13,
+    10, 11, 11, 13, 13, 12, 13, 13, 15, 15, 12, 13, 12, 15, 12,
+     8,  9,  9, 12, 12,  9, 11, 10, 13, 13,  9, 10, 10, 13, 13,
+    12, 13, 13, 15, 14, 12, 12, 12, 14, 13,  9, 10, 10, 13, 12,
+    10, 11, 11, 13, 13, 10, 11, 11, 14, 12, 13, 13, 14, 14, 16,
+    12, 13, 13, 15, 15,  9, 10, 10, 13, 13, 10, 11, 10, 14, 13,
+    10, 11, 11, 13, 14, 12, 14, 13, 15, 14, 13, 13, 13, 15, 15,
+    11, 13, 12, 15, 14, 11, 12, 13, 14, 15, 12, 13, 13, 16, 14,
+    14, 12, 15, 12, 16, 14, 15, 15, 17, 15, 11, 12, 12, 14, 14,
+    11, 13, 11, 15, 14, 12, 13, 13, 15, 15, 13, 15, 12, 17, 13,
+    14, 15, 15, 16, 16,  8,  9,  9, 12, 12,  9, 10, 10, 12, 13,
+     9, 10, 10, 13, 13, 12, 12, 12, 14, 14, 12, 13, 13, 15, 15,
+     9, 10, 10, 13, 12, 10, 11, 11, 14, 13, 10, 10, 11, 13, 14,
+    12, 13, 13, 15, 15, 12, 12, 13, 14, 16,  9, 10, 10, 13, 13,
+    10, 11, 11, 13, 14, 10, 11, 11, 14, 13, 12, 13, 13, 14, 15,
+    13, 14, 13, 16, 14, 11, 12, 12, 14, 14, 12, 13, 13, 15, 14,
+    11, 12, 13, 14, 15, 14, 15, 15, 16, 16, 13, 13, 15, 13, 16,
+    11, 12, 12, 14, 15, 12, 13, 13, 14, 15, 11, 13, 12, 15, 14,
+    14, 15, 15, 16, 16, 14, 15, 12, 16, 13,
+};
+
+static const uint8_t res_mono_p5_0[] = {
+     2,  3,  3,  6,  6,  7,  7,  9,  9,  4,  5,  5,  7,  7,  8,
+     8, 10, 10,  4,  5,  5,  7,  7,  8,  8, 10, 10,  6,  7,  7,
+     8,  8,  9,  9, 11, 10,  6,  7,  7,  8,  8,  9,  9, 10, 10,
+     7,  8,  8,  9,  9, 10, 10, 11, 11,  7,  8,  8,  9,  9, 10,
+    10, 11, 11,  9, 10, 10, 11, 10, 11, 11, 12, 12,  9, 10, 10,
+    10, 10, 11, 11, 12, 12,
+};
+
+static const uint8_t res_mono_p6_0[] = {
+     1,  4,  4,  6,  6,  8,  8,  9,  9, 10, 11, 13, 14,  4,  6,
+     5,  8,  8,  9,  9, 10, 10, 11, 11, 14, 14,  4,  6,  6,  8,
+     8,  9,  9, 10, 10, 11, 11, 14, 14,  6,  8,  8,  9,  9, 10,
+    10, 11, 11, 12, 12, 15, 15,  6,  8,  8,  9,  9, 10, 11, 11,
+    11, 12, 12, 15, 15,  8,  9,  9, 11, 10, 11, 11, 12, 12, 13,
+    13, 15, 16,  8,  9,  9, 10, 11, 11, 11, 12, 12, 13, 13, 16,
+    16, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 17, 16,  9,
+    10, 11, 12, 11, 12, 12, 13, 13, 13, 13, 16, 18, 11, 12, 11,
+    12, 12, 13, 13, 13, 14, 15, 14, 17, 17, 11, 11, 12, 12, 12,
+    13, 13, 13, 14, 14, 15, 18, 17, 14, 15, 15, 15, 15, 16, 16,
+    17, 17, 19, 18,  0, 20, 14, 15, 14, 15, 15, 16, 16, 16, 17,
+    18, 16, 20, 18,
+};
+
+static const uint8_t res_mono_p6_1[] = {
+     2,  4,  4,  5,  5,  4,  5,  5,  6,  5,  4,  5,  5,  5,  6,
+     5,  6,  5,  6,  6,  5,  5,  6,  6,  6,
+};
+
+static const uint8_t res_mono_p7_0[] = {
+     1,  3,  3, 10, 10, 10, 10, 10, 10,  4, 10, 10, 10, 10, 10,
+    10, 10, 10,  4, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+     9,  9,  9,  9,  9,  9,
+};
+
+static const uint8_t res_mono_p7_1[] = {
+     1,  4,  4,  6,  6,  7,  6,  8,  7,  9,  8, 10,  9, 11, 11,
+     4,  7,  7,  8,  7,  9,  9, 10, 10, 11, 11, 11, 11, 12, 12,
+     4,  7,  7,  7,  7,  9,  9, 10, 10, 11, 11, 12, 12, 12, 11,
+     6,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 13, 12, 13, 13,
+     6,  8,  8,  9,  9, 10, 11, 11, 11, 12, 12, 13, 14, 13, 13,
+     8,  9,  9, 11, 11, 12, 12, 12, 13, 14, 13, 14, 14, 14, 15,
+     8,  9,  9, 11, 11, 11, 12, 13, 14, 13, 14, 15, 17, 14, 15,
+     9, 10, 10, 12, 12, 13, 13, 13, 14, 15, 15, 15, 16, 16, 16,
+     9, 11, 11, 12, 12, 13, 13, 14, 14, 14, 15, 16, 16, 16, 16,
+    10, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 17, 17, 17, 17,
+    10, 12, 11, 13, 13, 15, 14, 15, 14, 16, 17, 16, 16, 16, 16,
+    11, 13, 12, 14, 14, 14, 14, 15, 16, 17, 16, 17, 17, 17, 17,
+    11, 13, 12, 14, 14, 14, 15, 17, 16, 17, 17, 17, 17, 17, 17,
+    12, 13, 13, 15, 16, 15, 16, 17, 17, 16, 16, 17, 17, 17, 17,
+    12, 13, 13, 15, 15, 15, 16, 17, 17, 17, 16, 17, 16, 17, 17,
+};
+
+static const uint8_t res_mono_p7_2[] = {
+     2,  5,  5,  7,  6,  7,  7,  8,  8,  8,  8,  9,  9,  9,  9,
+     9,  9,  5,  6,  6,  7,  7,  8,  8,  8,  8,  9,  9,  9,  9,
+     9,  9, 10, 10,  5,  6,  6,  7,  7,  8,  8,  8,  8,  9,  8,
+     9,  9,  9,  9, 10,  9,  7,  7,  7,  8,  8,  8,  8,  9,  9,
+     9,  9,  9,  9, 10, 10, 10, 10,  7,  7,  7,  8,  8,  8,  8,
+     9,  9,  9,  9, 10,  9, 10, 10, 10, 10,  7,  8,  8,  8,  8,
+     9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10,  7,  8,  8,
+     9,  8,  9,  9,  9,  9, 10,  9, 10, 10, 10, 10, 10, 10,  8,
+     8,  8,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10,
+    10,  8,  9,  8,  9,  9,  9,  9, 10,  9, 10, 10, 10, 10, 10,
+    10, 10, 10,  9,  9,  9,  9,  9,  9, 10,  9, 10, 10, 10, 10,
+    10, 10, 10, 10, 10,  9,  9,  9,  9,  9, 10,  9, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10,  9,  9,  9, 10,  9, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10,  9,  9,  9, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  9,  9,  9, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11,  9, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11,
+     9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10,  9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11,
+    11, 11, 10, 11,
+};
+
 codebook_setup floor_config[] = {
     { 2,   64,   64, floor_128_c0,     0 },
     { 2,  256,  256, floor_128_c1,     0 },
@@ -596,6 +801,21 @@  static codebook_setup res_stereo_config[] = {
     { 2,  289,  289, res_stereo_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 codebook_setup res_mono_config[] = {
+    { 2,   64,   64, res_mono_short_master, 0 },
+    { 2,   64,   64, res_mono_long_master,  0 },
+    { 4,   81,   81, res_mono_p1_0, 1,    -1.0,   1.0, (const uint8_t[]){ 1, 0, 2, } },
+    { 4,   81,   81, res_mono_p2_0, 1,    -1.0,   1.0, (const uint8_t[]){ 1, 0, 2, } },
+    { 4,  625,  625, res_mono_p3_0, 1,    -2.0,   1.0, (const uint8_t[]){ 2, 1, 3, 0,  4, } },
+    { 4,  625,  625, res_mono_p4_0, 1,    -2.0,   1.0, (const uint8_t[]){ 2, 1, 3, 0,  4, } },
+    { 2,   81,   81, res_mono_p5_0, 1,    -4.0,   1.0, (const uint8_t[]){ 4, 3, 5, 2,  6, 1,  7, 0,  8, } },
+    { 2,  169,  169, res_mono_p6_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_mono_p6_1, 1,    -2.0,   1.0, (const uint8_t[]){ 2, 1, 3, 0,  4, } },
+    { 4,   81,   81, res_mono_p7_0, 1, -1020.0, 255.0, (const uint8_t[]){ 4, 3, 5, 2,  6, 1,  7, 0,  8, } },
+    { 2,  225,  225, res_mono_p7_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_mono_p7_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 {
     int dim;
     int subclass;
@@ -612,8 +832,23 @@  static const struct {
       { 3, 2, 5, { -1, 20, 21, 22 } },},
 };
 
-res_setup res_class = {
-    .type = 2,
+res_setup res_class[] = {
+{
+    .end = { 112, 800 },
+    .classifications = 8,
+    .nbooks = 11,
+    .config = res_mono_config,
+    .books = { { -1, -1, -1, -1, -1, -1, -1, -1, },
+               { -1, -1,  2, -1, -1, -1, -1, -1, },
+               { -1, -1,  3, -1, -1, -1, -1, -1, },
+               { -1, -1,  4, -1, -1, -1, -1, -1, },
+               { -1, -1,  5, -1, -1, -1, -1, -1, },
+               { -1, -1,  6, -1, -1, -1, -1, -1, },
+               {  7,  8, -1, -1, -1, -1, -1, -1, },
+               {  8,  9, 10, -1, -1, -1, -1, -1, },
+               { -1, -1, -1, -1, -1, -1, -1, -1, },
+               { -1, -1, -1, -1, -1, -1, -1, -1, }, } },
+{
     .end = { 208, 1600 },
     .classifications = 10,
     .nbooks = 15,
@@ -627,7 +862,7 @@  res_setup res_class = {
                { -1, -1,  7, -1, -1, -1, -1, -1, },
                {  8,  9, -1, -1, -1, -1, -1, -1, },
                { 10, 11, -1, -1, -1, -1, -1, -1, },
-               { 12, 13, 14, -1, -1, -1, -1, -1, }, },
+               { 12, 13, 14, -1, -1, -1, -1, -1, }, }, },
 };
 
 #endif /* AVCODEC_VORBIS_ENC_DATA_H */
diff --git a/libavcodec/vorbisenc.c b/libavcodec/vorbisenc.c
index c2c6e1b7d8..f4af2f4071 100644
--- a/libavcodec/vorbisenc.c
+++ b/libavcodec/vorbisenc.c
@@ -167,7 +167,7 @@  static int create_residues(vorbis_enc_context *venc, res_setup setup)
 
     for (res = 0; res < venc->nresidues; res++) {
         rc = &venc->residues[res];
-        rc->type            = setup.type;
+        rc->type            = 2;
         rc->begin           = 0;
         rc->end             = setup.end[res];
         rc->partition_size  = res ?   32 :  16;
@@ -177,7 +177,8 @@  static int create_residues(vorbis_enc_context *venc, res_setup setup)
         if (!rc->books)
             return AVERROR(ENOMEM);
 
-        memcpy(rc->books, setup.books, sizeof(setup.books));
+        memcpy(rc->books, setup.books,
+               sizeof(**setup.books) * RES_PASSES * rc->classifications);
         if ((ret = ready_residue(rc, venc)) < 0)
             return ret;
     }
@@ -297,7 +298,7 @@  static int create_vorbis_context(vorbis_enc_context *venc,
                                  AVCodecContext *avctx)
 {
     vorbis_enc_mapping *mc;
-    int i, map, ret, blocks;
+    int i, map, ret, blocks, chan_config;
 
     venc->channels    = avctx->channels;
     venc->sample_rate = avctx->sample_rate;
@@ -318,13 +319,15 @@  static int create_vorbis_context(vorbis_enc_context *venc,
         return ret;
 
     // Setup and configure our residues
-    venc->nres_books = res_class.nbooks;
+    chan_config = venc->channels - 1;
+    chan_config = chan_config > 1 ? 2 : chan_config;
+    venc->nres_books = res_class[chan_config].nbooks;
     venc->res_books = av_malloc(sizeof(vorbis_enc_codebook) * venc->nres_books);
     if (!venc->res_books)
         return AVERROR(ENOMEM);
 
-    copy_codebooks(venc->res_books, res_class.config, venc->nres_books);
-    if ((ret = create_residues(venc, res_class)) < 0)
+    copy_codebooks(venc->res_books, res_class[chan_config].config, venc->nres_books);
+    if ((ret = create_residues(venc, res_class[chan_config])) < 0)
         return ret;
 
     venc->nmappings = 2;
@@ -835,7 +838,7 @@  static int residue_encode(vorbis_enc_context *venc, vorbis_enc_residue *rc,
                           PutBitContext *pb, float *coeffs, int samples,
                           int real_ch)
 {
-    int pass, i, j, p, k;
+    int pass, ch, i, j, p, k;
     int psize      = rc->partition_size;
     int partitions = (rc->end - rc->begin) / psize;
     int channels   = (rc->type == 2) ? 1 : real_ch;
@@ -843,22 +846,27 @@  static int residue_encode(vorbis_enc_context *venc, vorbis_enc_residue *rc,
     int classwords = venc->res_books[rc->classbook].ndimensions;
 
     av_assert0(rc->type == 2);
-    av_assert0(real_ch == 2);
     for (p = 0; p < partitions; p++) {
-        float max1 = 0.0, max2 = 0.0;
+        float max[MAX_CHANNELS] = { 0, 0, };
         int s = rc->begin + p * psize;
-        for (k = s; k < s + psize; k += 2) {
-            max1 = FFMAX(max1, fabs(coeffs[          k / real_ch]));
-            max2 = FFMAX(max2, fabs(coeffs[samples + k / real_ch]));
-        }
-
-        for (i = 0; i < rc->classifications - 1; i++)
-            if (max1 < rc->maxes[i][0] && max2 < rc->maxes[i][1])
+        for (k = s; k < s + psize; k += real_ch)
+            for (ch = 0; ch < real_ch; ch++)
+                max[ch] = FFMAX(max[ch], fabs(coeffs[samples * ch + k / real_ch]));
+
+        /* Keep checking until all channels' values are less than their respective
+           residue maxes */
+        for (i = 0; i < rc->classifications - 1; i++) {
+            int found = 0;
+            for (ch = 0; ch < real_ch; ch++)
+                if (max[ch] < rc->maxes[i][ch])
+                    found++;
+            if (found == real_ch)
                 break;
+        }
         classes[0][p] = i;
     }
 
-    for (pass = 0; pass < 8; pass++) {
+    for (pass = 0; pass < RES_PASSES; pass++) {
         p = 0;
         while (p < partitions) {
             if (pass == 0)
@@ -1271,8 +1279,8 @@  static av_cold int vorbis_encode_init(AVCodecContext *avctx)
     vorbis_enc_context *venc = avctx->priv_data;
     int ret;
 
-    if (avctx->channels != 2) {
-        av_log(avctx, AV_LOG_ERROR, "Current FFmpeg Vorbis encoder only supports 2 channels.\n");
+    if (avctx->channels > 2) {
+        av_log(avctx, AV_LOG_ERROR, "Current FFmpeg Vorbis encoder only supports 1 or 2 channels.\n");
         return -1;
     }