[FFmpeg-devel,2/6] avcodec/vorbisenc: Apply dynamic frame lengths

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

Details

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

Commit Message

Tyler Jones Aug. 22, 2017, 1:23 a.m.
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@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(-)

Comments

Tomas Härdin Aug. 23, 2017, 8:31 a.m.
On 2017-08-22 03:23, Tyler Jones wrote:
> +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);

av_malloc_array()? Applies to most av_malloc() in there


> -    // 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;
> +        }
>       }

Maybe nitpicking, but it would be clearer what the changes are if you 
put the indentation change in a separate commit


> -    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;
> +        }
>       }

Same here

/Tomas
Tyler Jones Aug. 23, 2017, 11:57 p.m.
On Wed, Aug 23, 2017 at 10:31:58AM +0200, Tomas Härdin wrote:
> On 2017-08-22 03:23, Tyler Jones wrote:
> > +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);
> 
> av_malloc_array()? Applies to most av_malloc() in there

I can change it, but I don't feel that it helps readability in this specific
case above. As for the others that happen to show up in the diffs, I did not
want to make any unnecessary and unrelated functional changes. However, I'll
gladly to switch these cases to `av_malloc_array()` in a separate commit if
desired.

> > -    // 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;
> > +        }
> >       }
> 
> Maybe nitpicking, but it would be clearer what the changes are if you put
> the indentation change in a separate commit

No, you're right, and it's a good suggestion. I'll move the indentation to a
separate commit when enough other changes have been provided to warrant a new version.

> > -    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;
> > +        }
> >       }
> 
> Same here
> 
> /Tomas
> 

I felt that separating this small amount of lines would just clutter the git
log history, but I'll move these along with the mapping indentations.

Thanks for taking a look,

Tyler Jones

Patch hide | download patch | download mbox

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