Original Commit: r23 | ods15 | 2006-09-22 13:55:48 +0300 (Fri, 22 Sep 2006) | 2 lines
[ffmpeg.git] / libavcodec / vorbis_enc.c
index 6d82a44..19aa4fb 100644 (file)
 typedef struct {
     int len;
     uint32_t codeword;
-} entry_t;
+} cb_entry_t;
 
 typedef struct {
     int nentries;
-    entry_t * entries;
+    cb_entry_t * entries;
     int ndimentions;
     float min;
     float delta;
     int seq_p;
     int lookup;
-    //float * dimentions;
     int * quantlist;
+    float * dimentions;
 } codebook_t;
 
 typedef struct {
@@ -70,15 +70,31 @@ typedef struct {
 } floor_t;
 
 typedef struct {
+    int type;
+    int begin;
+    int end;
+    int partition_size;
+    int classifications;
+    int classbook;
+    int (*books)[8];
 } residue_t;
 
 typedef struct {
+    int submaps;
+    int * mux;
+    int * floor;
+    int * residue;
 } mapping_t;
 
+typedef struct {
+    int blockflag;
+    int mapping;
+} vorbis_mode_t;
+
 typedef struct {
     int channels;
     int sample_rate;
-    int blocksize[2];
+    int blocksize[2]; // in (1<<n) format
 
     int ncodebooks;
     codebook_t * codebooks;
@@ -91,8 +107,182 @@ typedef struct {
 
     int nmappings;
     mapping_t * mappings;
+
+    int nmodes;
+    vorbis_mode_t * modes;
 } venc_context_t;
 
+static int cb_lookup_vals(int lookup, int dimentions, int entries) {
+    if (lookup == 1) {
+        int tmp, i;
+        for (tmp = 0; ; tmp++) {
+                int n = 1;
+                for (i = 0; i < dimentions; i++) n *= tmp;
+                if (n > entries) break;
+        }
+        return tmp - 1;
+    } else if (lookup == 2) return dimentions * entries;
+    return 0;
+}
+
+static void ready_codebook(codebook_t * cb) {
+    int h[33] = { 1,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 };
+    int i;
+
+    for (i = 0; i < cb->nentries; i++) {
+        cb_entry_t * e = &cb->entries[i];
+        int j = 0;
+        if (h[0]) h[0] = 0;
+        else for (j = e->len; !h[j]; j--) assert(j);
+        e->codeword = h[j];
+        h[j] = 0;
+        for (j++; j <= e->len; j++) h[j] = e->codeword | (1 << (j - 1));
+    }
+    for (i = 0; i < 33; i++) assert(!h[i]);
+
+    if (!cb->lookup) cb->dimentions = NULL;
+    else {
+        int vals = cb_lookup_vals(cb->lookup, cb->ndimentions, cb->nentries);
+        cb->dimentions = av_malloc(sizeof(float) * cb->nentries * cb->ndimentions);
+        for (i = 0; i < cb->nentries; i++) {
+            float last = 0;
+            int j;
+            int div = 1;
+            for (j = 0; j < cb->ndimentions; j++) {
+                int off;
+                if (cb->lookup == 1) off = (i / div) % vals; // lookup type 1
+                else off = i * cb->ndimentions + j; // lookup type 2
+
+                cb->dimentions[i * cb->ndimentions + j] = last + cb->min + cb->quantlist[off] * cb->delta;
+                if (cb->seq_p) last = cb->dimentions[i * cb->ndimentions + j];
+                div *= vals;
+            }
+        }
+    }
+
+}
+
+static void create_vorbis_context(venc_context_t * venc, AVCodecContext * avccontext) {
+    codebook_t * cb;
+    floor_t * fc;
+    residue_t * rc;
+    mapping_t * mc;
+    int i, book;
+
+    venc->channels = avccontext->channels;
+    venc->sample_rate = avccontext->sample_rate;
+    venc->blocksize[0] = venc->blocksize[1] = 8;
+
+    venc->ncodebooks = 10;
+    venc->codebooks = av_malloc(sizeof(codebook_t) * venc->ncodebooks);
+
+    // codebook 1 - floor1 book, values 0..255
+    cb = &venc->codebooks[0];
+    cb->nentries = 256;
+    cb->entries = av_malloc(sizeof(cb_entry_t) * cb->nentries);
+    for (i = 0; i < cb->nentries; i++) cb->entries[i].len = 8;
+    cb->ndimentions = 0;
+    cb->min = 0.;
+    cb->delta = 0.;
+    cb->seq_p = 0;
+    cb->lookup = 0;
+    cb->quantlist = NULL;
+    ready_codebook(cb);
+
+    // codebook 2 - residue classbook, values 0..1, dimentions 200
+    cb = &venc->codebooks[1];
+    cb->nentries = 2;
+    cb->entries = av_malloc(sizeof(cb_entry_t) * cb->nentries);
+    for (i = 0; i < cb->nentries; i++) cb->entries[i].len = 1;
+    cb->ndimentions = 200;
+    cb->min = 0.;
+    cb->delta = 0.;
+    cb->seq_p = 0;
+    cb->lookup = 0;
+    cb->quantlist = NULL;
+    ready_codebook(cb);
+
+    // codebook 3..10 - vector, for the residue, values -32767..32767, dimentions 1
+    for (book = 0; book < 8; book++) {
+        cb = &venc->codebooks[2 + book];
+        cb->nentries = 5;
+        cb->entries = av_malloc(sizeof(cb_entry_t) * cb->nentries);
+        for (i = 0; i < cb->nentries; i++) cb->entries[i].len = i == 2 ? 1 : 3;
+        cb->ndimentions = 1;
+        cb->delta = 1 << ((7 - book) * 2);
+        cb->min = -cb->delta*2;
+        cb->seq_p = 0;
+        cb->lookup = 2;
+        cb->quantlist = av_malloc(sizeof(int) * cb_lookup_vals(cb->lookup, cb->ndimentions, cb->nentries));
+        for (i = 0; i < cb->nentries; i++) cb->quantlist[i] = i;
+        ready_codebook(cb);
+    }
+
+    venc->nfloors = 1;
+    venc->floors = av_malloc(sizeof(floor_t) * venc->nfloors);
+
+    // just 1 floor
+    fc = &venc->floors[0];
+    fc->partitions = 1;
+    fc->partition_to_class = av_malloc(sizeof(int) * fc->partitions);
+    for (i = 0; i < fc->partitions; i++) fc->partition_to_class = 0;
+    fc->nclasses = 1;
+    fc->classes = av_malloc(sizeof(floor_class_t) * fc->nclasses);
+    for (i = 0; i < fc->nclasses; i++) {
+        floor_class_t * c = &fc->classes[i];
+        int j, books;
+        c->dim = 1;
+        c->subclass = 0;
+        c->masterbook = 0;
+        books = (1 << c->subclass);
+        c->books = av_malloc(sizeof(int) * books);
+        for (j = 0; j < books; j++) c->books[j] = 0;
+    }
+    fc->multiplier = 1;
+    fc->rangebits = venc->blocksize[0];
+
+    fc->values = 2;
+    for (i = 0; i < fc->partitions; i++)
+        fc->values += fc->classes[fc->partition_to_class[i]].dim;
+
+    fc->list = av_malloc(sizeof(*fc->list) * fc->values);
+    fc->list[0].x = 0;
+    fc->list[1].x = 1 << fc->rangebits;
+    for (i = 2; i < fc->values; i++) fc->list[i].x = i * 5;
+
+    venc->nresidues = 1;
+    venc->residues = av_malloc(sizeof(residue_t) * venc->nresidues);
+
+    // single residue
+    rc = &venc->residues[0];
+    rc->type = 0;
+    rc->begin = 0;
+    rc->end = 1 << venc->blocksize[0];
+    rc->partition_size = 64;
+    rc->classifications = 1;
+    rc->classbook = 1;
+    rc->books = av_malloc(sizeof(int[8]) * rc->classifications);
+    for (i = 0; i < 8; i++) rc->books[0][i] = 2 + i;
+
+    venc->nmappings = 1;
+    venc->mappings = av_malloc(sizeof(mapping_t) * venc->nmappings);
+
+    // single mapping
+    mc = &venc->mappings[0];
+    mc->submaps = 1;
+    mc->mux = av_malloc(sizeof(int) * venc->channels);
+    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);
+    for (i = 0; i < mc->submaps; i++) {
+        mc->floor[i] = 0;
+        mc->residue[i] = 0;
+    }
+
+    venc->nmodes = 1;
+    venc->modes = av_malloc(sizeof(vorbis_mode_t) * venc->nmodes);
+}
+
 static inline int ilog(unsigned int a) {
     int i;
     for (i = 0; a >> i; i++);
@@ -128,7 +318,7 @@ static void put_codebook_header(PutBitContext * pb, codebook_t * cb) {
         while (i < cb->nentries) {
             int j;
             for (j = 0; j+i < cb->nentries; j++) if (cb->entries[j+i].len != len) break;
-            put_bits(pb, 5, j);
+            put_bits(pb, ilog(cb->nentries - i), j);
             i += j;
             len++;
         }
@@ -146,18 +336,10 @@ static void put_codebook_header(PutBitContext * pb, codebook_t * cb) {
 
     put_bits(pb, 4, cb->lookup);
     if (cb->lookup) {
-        int tmp, bits = ilog(cb->quantlist[0]);
-
-        if (cb->lookup == 1) {
-            for (tmp = 0; ; tmp++) {
-                int n = 1;
-                for (i = 0; i < cb->ndimentions; i++) n *= tmp;
-                if (n > cb->nentries) break;
-            }
-            tmp--;
-        } else tmp = cb->ndimentions * cb->nentries;
+        int tmp = cb_lookup_vals(cb->lookup, cb->ndimentions, cb->nentries);
+        int bits = ilog(cb->quantlist[0]);
 
-        for (i = 1; i < tmp; i++) bits = FFMIN(bits, ilog(cb->quantlist[i]));
+        for (i = 1; i < tmp; i++) bits = FFMAX(bits, ilog(cb->quantlist[i]));
 
         put_float(pb, cb->min);
         put_float(pb, cb->delta);
@@ -198,6 +380,32 @@ static void put_floor_header(PutBitContext * pb, floor_t * fc) {
 }
 
 static void put_residue_header(PutBitContext * pb, residue_t * rc) {
+    int i;
+
+    put_bits(pb, 16, rc->type);
+
+    put_bits(pb, 24, rc->begin);
+    put_bits(pb, 24, rc->end);
+    put_bits(pb, 24, rc->partition_size - 1);
+    put_bits(pb, 6, rc->classifications);
+    put_bits(pb, 8, rc->classbook);
+
+    for (i = 0; i < rc->classifications; i++) {
+        int j, tmp = 0;
+        for (j = 0; j < 8; j++) tmp |= (!!rc->books[i][j]) << j;
+
+        put_bits(pb, 3, tmp & 7);
+        put_bits(pb, 1, tmp > 7);
+
+        if (tmp > 7) put_bits(pb, 5, tmp >> 3);
+    }
+
+    for (i = 0; i < rc->classifications; i++) {
+        int j;
+        for (j = 0; j < 8; j++)
+            if (rc->books[i][j])
+                put_bits(pb, 8, rc->books[i][j]);
+    }
 }
 
 static int put_main_header(venc_context_t * venc, uint8_t ** out) {
@@ -246,7 +454,7 @@ static int put_main_header(venc_context_t * venc, uint8_t ** out) {
 
     // codebooks
     put_bits(&pb, 8, venc->ncodebooks - 1);
-    for (i = 0; i < venc->ncodebooks; i++) put_codebook_header(&pb, &venc->codebooks[0]);
+    for (i = 0; i < venc->ncodebooks; i++) put_codebook_header(&pb, &venc->codebooks[i]);
 
     // time domain, reserved, zero
     put_bits(&pb, 6, 0);
@@ -254,15 +462,42 @@ static int put_main_header(venc_context_t * venc, uint8_t ** out) {
 
     // floors
     put_bits(&pb, 6, venc->nfloors - 1);
-    for (i = 0; i < venc->nfloors; i++) put_floor_header(&pb, &venc->floors[0]);
+    for (i = 0; i < venc->nfloors; i++) put_floor_header(&pb, &venc->floors[i]);
 
     // residues
     put_bits(&pb, 6, venc->nresidues - 1);
-    for (i = 0; i < venc->nresidues; i++) put_residue_header(&pb, &venc->residues[0]);
+    for (i = 0; i < venc->nresidues; i++) put_residue_header(&pb, &venc->residues[i]);
 
     // mappings
     put_bits(&pb, 6, venc->nmappings - 1);
     for (i = 0; i < venc->nmappings; i++) {
+        mapping_t * mc = &venc->mappings[i];
+        int j;
+        put_bits(&pb, 16, 0); // mapping type
+
+        put_bits(&pb, 1, mc->submaps > 1);
+        if (mc->submaps > 1) put_bits(&pb, 4, mc->submaps - 1);
+
+        put_bits(&pb, 1, 0); // channel coupling
+
+        put_bits(&pb, 2, 0); // reserved
+
+        if (mc->submaps > 1) for (j = 0; j < venc->channels; j++) put_bits(&pb, 4, mc->mux[j]);
+
+        for (j = 0; j < mc->submaps; j++) {
+            put_bits(&pb, 8, 0); // reserved time configuration
+            put_bits(&pb, 8, mc->floor[j]);
+            put_bits(&pb, 8, mc->residue[j]);
+        }
+    }
+
+    // modes
+    put_bits(&pb, 6, venc->nmodes - 1);
+    for (i = 0; i < venc->nmodes; i++) {
+        put_bits(&pb, 1, venc->modes[i].blockflag);
+        put_bits(&pb, 16, 0); // reserved window type
+        put_bits(&pb, 16, 0); // reserved transform type
+        put_bits(&pb, 8, venc->modes[i].mapping);
     }
 
     flush_put_bits(&pb);
@@ -288,8 +523,7 @@ static int vorbis_encode_init(AVCodecContext * avccontext)
 {
     venc_context_t * venc = avccontext->priv_data;
 
-    venc->channels = avccontext->channels;
-    venc->sample_rate = avccontext->sample_rate;
+    create_vorbis_context(venc, avccontext);
 
     //if (avccontext->flags & CODEC_FLAG_QSCALE) avccontext->global_quality / (float)FF_QP2LAMBDA); else avccontext->bit_rate;
     //if(avccontext->cutoff > 0) cfreq = avccontext->cutoff / 1000.0;
@@ -315,7 +549,7 @@ static int vorbis_encode_frame(AVCodecContext * avccontext, unsigned char * pack
     avccontext->coded_frame->pts = av_rescale_q(op2->granulepos, (AVRational){1, avccontext->sample_rate}, avccontext->time_base);
     memcpy(packets, compressed_frame, l);
 #endif
-    return 0;
+    return data ? 50 : 0;
 }