[FFmpeg-soc] [soc]: r2411 - in nellyenc: checkout.sh ffmpeg.patch nellymoserenc.c

bwolowiec subversion at mplayerhq.hu
Sun Jun 8 23:33:15 CEST 2008


Author: bwolowiec
Date: Sun Jun  8 23:33:15 2008
New Revision: 2411

Log:
initial commit: simple nellymoser encoder. It's slow and has average quality of sound.


Added:
   nellyenc/checkout.sh   (contents, props changed)
   nellyenc/ffmpeg.patch
   nellyenc/nellymoserenc.c

Added: nellyenc/checkout.sh
==============================================================================
--- (empty file)
+++ nellyenc/checkout.sh	Sun Jun  8 23:33:15 2008
@@ -0,0 +1,16 @@
+FILES="nellymoserenc.c"
+
+echo "checking out ffmpeg svn"
+for i in $FILES Makefile allcodecs.c; do
+    rm -f ffmpeg/libavcodec/$i
+done
+svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk/ ffmpeg -r 13713
+echo "patching ffmpeg"
+cd ffmpeg
+patch -p0 <../ffmpeg.patch
+echo "copying the Nellymoser files to ffmpeg/libavcodec"
+for i in $FILES; do
+    rm -f libavcodec/$i
+    ln -s ../../$i libavcodec/$i
+done
+echo "Done, now just do a regular configure and make to build."

Added: nellyenc/ffmpeg.patch
==============================================================================
--- (empty file)
+++ nellyenc/ffmpeg.patch	Sun Jun  8 23:33:15 2008
@@ -0,0 +1,25 @@
+Index: libavcodec/Makefile
+===================================================================
+--- libavcodec/Makefile	(wersja 13713)
++++ libavcodec/Makefile	(kopia robocza)
+@@ -133,6 +133,7 @@
+ OBJS-$(CONFIG_MSVIDEO1_DECODER)        += msvideo1.o
+ OBJS-$(CONFIG_MSZH_DECODER)            += lcldec.o
+ OBJS-$(CONFIG_NELLYMOSER_DECODER)      += nellymoserdec.o nellymoser.o mdct.o fft.o
++OBJS-$(CONFIG_NELLYMOSER_ENCODER)      += nellymoserenc.o nellymoser.o mdct.o fft.o
+ OBJS-$(CONFIG_NUV_DECODER)             += nuv.o rtjpeg.o
+ OBJS-$(CONFIG_PAM_ENCODER)             += pnmenc.o pnm.o
+ OBJS-$(CONFIG_PBM_ENCODER)             += pnmenc.o pnm.o
+Index: libavcodec/allcodecs.c
+===================================================================
+--- libavcodec/allcodecs.c	(wersja 13713)
++++ libavcodec/allcodecs.c	(kopia robocza)
+@@ -195,7 +195,7 @@
+     REGISTER_DECODER (MP3ON4, mp3on4);
+     REGISTER_DECODER (MPC7, mpc7);
+     REGISTER_DECODER (MPC8, mpc8);
+-    REGISTER_DECODER (NELLYMOSER, nellymoser);
++    REGISTER_ENCDEC  (NELLYMOSER, nellymoser);
+     REGISTER_DECODER (QDM2, qdm2);
+     REGISTER_DECODER (RA_144, ra_144);
+     REGISTER_DECODER (RA_288, ra_288);

Added: nellyenc/nellymoserenc.c
==============================================================================
--- (empty file)
+++ nellyenc/nellymoserenc.c	Sun Jun  8 23:33:15 2008
@@ -0,0 +1,326 @@
+/*
+ * Nellymoser encoder
+ * This code is developed as part of Google Summer of Code 2008 Program.
+ *
+ * Copyright (c) 2008 Bartlomiej Wolowiec
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "nellymoser.h"
+#include "avcodec.h"
+#include "libavutil/random.h"
+#include "dsputil.h"
+
+
+/*
+ * FIXME: Bitstream from vorbis_enc.c (move to seperate file?)
+ */
+typedef struct {
+    int total;
+    int total_pos;
+    int pos;
+    uint8_t * buf_ptr;
+} PutBitContext2;
+
+static inline void init_put_bits2(PutBitContext2 * pb, uint8_t * buf, int buffer_len) {
+    pb->total = buffer_len * 8;
+    pb->total_pos = 0;
+    pb->pos = 0;
+    pb->buf_ptr = buf;
+}
+
+static void put_bits2(PutBitContext2 * pb, int bits, uint64_t val) {
+    if ((pb->total_pos += bits) >= pb->total) return;
+    if (!bits) return;
+    if (pb->pos) {
+        if (pb->pos > bits) {
+            *pb->buf_ptr |= val << (8 - pb->pos);
+            pb->pos -= bits;
+            bits = 0;
+        } else {
+            *pb->buf_ptr++ |= (val << (8 - pb->pos)) & 0xFF;
+            val >>= pb->pos;
+            bits -= pb->pos;
+            pb->pos = 0;
+        }
+    }
+    for (; bits >= 8; bits -= 8) {
+        *pb->buf_ptr++ = val & 0xFF;
+        val >>= 8;
+    }
+    if (bits) {
+        *pb->buf_ptr = val;
+        pb->pos = 8 - bits;
+    }
+}
+
+static inline int put_bits2_count(PutBitContext2 * pb) {
+    return pb->total_pos;
+}
+
+typedef struct NellyMoserEncodeContext {
+    AVCodecContext* avctx;
+    DECLARE_ALIGNED_16(float,float_buf[2*NELLY_SAMPLES]); // NELLY_SAMPLES
+    float           state[128];
+
+    int16_t buf[1024*64]; //FIXME (use any better solution)
+    int bufsize;
+
+    AVRandomState   random_state;
+    int             add_bias;
+    float           scale_bias;
+    DSPContext      dsp;
+    MDCTContext     mdct_ctx;
+    DECLARE_ALIGNED_16(float,mdct_tmp[NELLY_BUF_LEN*2]);
+    DECLARE_ALIGNED_16(float,mdct_out[NELLY_BUF_LEN*2]);
+} NellyMoserEncodeContext;
+
+static DECLARE_ALIGNED_16(float,sine_window2[2*NELLY_BUF_LEN]);
+
+void apply_mdct(NellyMoserEncodeContext *s, float *in, float *coefs)
+{
+    DECLARE_ALIGNED_16(float,in_buff[NELLY_SAMPLES]);
+
+    memcpy(&in_buff[0], &in[0], NELLY_SAMPLES*sizeof(float));
+    s->dsp.vector_fmul(in_buff,sine_window2,NELLY_SAMPLES);
+    memset(coefs, 0, NELLY_BUF_LEN*sizeof(float));
+    ff_mdct_calc(&s->mdct_ctx, coefs, in_buff, s->mdct_tmp);
+}
+
+
+static av_cold int encode_init(AVCodecContext * avctx) {
+    NellyMoserEncodeContext *s = avctx->priv_data;
+    int i;
+
+    //TODO check bitrate
+    if(avctx->channels!=1){
+        av_log(avctx, AV_LOG_ERROR, "Nellymoser supports only 1 channel\n");
+        return -1;
+    }
+    av_log(avctx, AV_LOG_DEBUG, "bit_rate=%i\n", avctx->bit_rate);
+
+    avctx->frame_size = NELLY_SAMPLES;
+
+    s->avctx = avctx;
+    av_init_random(0, &s->random_state);
+    ff_mdct_init(&s->mdct_ctx, 8, 0);
+
+    dsputil_init(&s->dsp, avctx);
+
+    if(s->dsp.float_to_int16 == ff_float_to_int16_c) {
+        s->add_bias = 385;
+        s->scale_bias = 1.0/(8*32768);
+    } else {
+        s->add_bias = 0;
+        s->scale_bias = 1.0/(1*8);
+    }
+
+    /* Generate overlap window */
+    if (!sine_window2[0])
+        for (i=0 ; i<256; i++) {
+            sine_window2[i] = sin((i + 0.5) / 256.0 * M_PI) /8;
+        }
+
+    s->bufsize = 0;
+    return 0;
+}
+
+static av_cold int encode_end(AVCodecContext * avctx) {
+    NellyMoserEncodeContext *s = avctx->priv_data;
+
+    ff_mdct_end(&s->mdct_ctx);
+    return 0;
+}
+
+static void encode_block(NellyMoserEncodeContext *s,
+        unsigned char *buf, int buf_size, int16_t *samples){
+    PutBitContext2 pb;
+    int bits[NELLY_BUF_LEN];
+    int i, j, k, l, b;
+    int bs, bk;
+    float pows[NELLY_FILL_LEN];
+    float *bptr, val;
+    float pval;
+    float best, tmp, stmp;
+    int off[NELLY_BANDS], base; // -1
+    float ss=1./1.;
+    float scale=1./1.;
+
+    for(i=0; i<NELLY_BUF_LEN*3; i++){
+        s->float_buf[i] = samples[i]*ss;
+    }
+    apply_mdct(s, s->float_buf, s->mdct_out);
+    apply_mdct(s, s->float_buf+NELLY_BUF_LEN, s->mdct_out+NELLY_BUF_LEN);
+
+    for(i=0; i<NELLY_SAMPLES; i++){
+        av_log(s->avctx, AV_LOG_DEBUG, "%3i: %f (%f)\n", i, s->mdct_out[i],
+                s->float_buf[i]);
+    }
+
+    init_put_bits2(&pb, buf, buf_size*8);
+
+    /* FIXME: use better (fast) algorithm... */
+    best = 1e10;
+    bk = 0;
+    for(k=0; k<64; k++){
+        pval = pow(2,(ff_nelly_init_table[k])/2048) * scale;
+        tmp = fabs(((s->mdct_out[0]+s->mdct_out[1])/2)/(pval));
+        if(tmp<1) tmp = 1/tmp;
+        if(best > tmp){
+            bk = k;
+            best = tmp;
+        }
+    }
+
+    av_log(s->avctx, AV_LOG_DEBUG, "base_best=%f\n", best  );
+
+    base = bk;
+    put_bits2(&pb, 6, base);
+    j=0;
+
+    val = ff_nelly_init_table[base];
+    for(i=0; i<NELLY_BANDS; i++){
+        if (i > 0){
+            /* FIXME: use better (fast) algorithm... */
+            best = 1e10;
+            bk = 0;
+            for(k=0; k<32; k++){
+                stmp = 0;
+                pval = pow(2,(val+ff_nelly_delta_table[k])/2048) * scale;
+
+                for(b=0; b<2; b++){
+                    for(l=0; l<ff_nelly_band_sizes_table[i]; l++){
+                        tmp = fabs(s->mdct_out[j+l+b*NELLY_BUF_LEN]/(pval));
+                        if(tmp<0.90) tmp=0.90;
+                        if(tmp<1) tmp = 1/tmp;
+                        if(tmp>5) tmp=5;
+                    }
+                    stmp += tmp*tmp;
+                }
+
+
+                if(best > stmp){
+                    bk = k;
+                    best = stmp;
+                }
+            }
+            av_log(s->avctx, AV_LOG_DEBUG, "best=%f\n", best  );
+            off[i] = bk;
+            put_bits2(&pb, 5, off[i]); // [5] -> -1
+            j+=ff_nelly_band_sizes_table[i];
+            val += ff_nelly_delta_table[off[i]];
+        }
+    }
+
+    val = ff_nelly_init_table[base];
+    bptr = pows;
+    for (i=0 ; i<NELLY_BANDS ; i++) {
+        if (i > 0)
+            val += ff_nelly_delta_table[off[i]];
+        for (j = 0; j < ff_nelly_band_sizes_table[i]; j++) {
+            *bptr++ = val;
+            av_log(s->avctx, AV_LOG_DEBUG, " exp: %f\n",
+                -pow(2,val/2048.)*scale);
+        }
+    }
+
+    ff_nelly_get_sample_bits(pows, bits);
+
+    bs=0;
+    for (i = 0; i < 2; i++) { //2
+
+        for (j = 0; j < NELLY_FILL_LEN; j++) {
+            bs+=bits[j];
+            if (bits[j] > 0) {
+                /* FIXME: use better (fast) algorithm... */
+                av_log(s->avctx, AV_LOG_DEBUG, "bits=%i\n", bits[j]);
+                pval = -pow(2, pows[j]/2048)*scale;
+                av_log(s->avctx, AV_LOG_DEBUG, "pval=%f\n", pval);
+                best = 1e10;
+                bk = 0;
+                for(k=0; k<(1<<bits[j]); k++){
+                    tmp = s->mdct_out[i*NELLY_BUF_LEN + j]
+                        /(ff_nelly_dequantization_table[(1<<bits[j])-1+k]*pval);
+                    if(tmp<0) continue;
+                    if(tmp<1) tmp = 1/tmp;
+                    if(best > tmp){
+                        bk = k;
+                        best = tmp;
+                    }
+                }
+                av_log(s->avctx, AV_LOG_DEBUG, "bk=%3i best_deq=%f send=%f\n",
+                        bk,
+                        best,
+                        (ff_nelly_dequantization_table[(1<<bits[j])-1+bk]*pval)
+                      );
+                put_bits2(&pb, bits[j], bk);
+            }
+        }
+        av_log(s->avctx, AV_LOG_DEBUG, "count=%i (%i)\n",
+                put_bits2_count(&pb),
+                NELLY_HEADER_BITS + NELLY_DETAIL_BITS
+                );
+        if(!i)
+            put_bits2(&pb, NELLY_HEADER_BITS + NELLY_DETAIL_BITS - put_bits2_count(&pb) , 0);
+
+        av_log(s->avctx, AV_LOG_DEBUG, "count=%i (%i)\n",
+                put_bits2_count(&pb),
+                NELLY_HEADER_BITS + NELLY_DETAIL_BITS
+                );
+    }
+
+    av_log(s->avctx, AV_LOG_DEBUG, "bs=%i\n", bs);
+}
+
+static int encode_tag(AVCodecContext *avctx,
+        unsigned char *buf, int buf_size, void *data){
+    NellyMoserEncodeContext *s = avctx->priv_data;
+    int16_t *samples = data;
+    int k, i;
+    int n = data ? avctx->frame_size : 0;
+
+    for(k=0; k<n; k++){
+        s->buf[k+s->bufsize]=samples[k];
+    }
+    s->bufsize+=n;
+
+    /* FIXME:
+     *  find better method for it...
+     */
+    for(k=0; (s->bufsize>=3*NELLY_BUF_LEN) && ((k+1)*NELLY_BLOCK_LEN<buf_size); k++){
+        encode_block(s, buf+NELLY_BLOCK_LEN*k, buf_size, s->buf);
+
+        //memmove(s->buf, s->buf+NELLY_SAMPLES, s->bufsize-NELLY_SAMPLES);
+        for(i=NELLY_SAMPLES; i<s->bufsize; i++){
+            s->buf[i-NELLY_SAMPLES] = s->buf[i];
+        }
+        s->bufsize-=NELLY_SAMPLES;
+    }
+    return NELLY_BLOCK_LEN*k;
+}
+
+
+AVCodec nellymoser_encoder = {
+    "nellymoser",
+    CODEC_TYPE_AUDIO,
+    CODEC_ID_NELLYMOSER,
+    sizeof(NellyMoserEncodeContext),
+    encode_init,
+    encode_tag,
+    encode_end,
+    NULL,
+};



More information about the FFmpeg-soc mailing list