Browse code

libspeex encoder wraper taken from svn head of xuggle (cherry picked from commit a52cdcd296c40882c3b4f88958990c56f0ce3019)

Art Clarke authored on 2011/09/11 10:14:14
Showing 4 changed files
... ...
@@ -177,7 +177,7 @@ External library support:
177 177
   --enable-libopenjpeg     enable JPEG 2000 decoding via OpenJPEG [no]
178 178
   --enable-librtmp         enable RTMP[E] support via librtmp [no]
179 179
   --enable-libschroedinger enable Dirac support via libschroedinger [no]
180
-  --enable-libspeex        enable Speex decoding via libspeex [no]
180
+  --enable-libspeex        enable Speex encoding and decoding via libspeex [no]
181 181
   --enable-libtheora       enable Theora encoding via libtheora [no]
182 182
   --enable-libvo-aacenc    enable AAC encoding via libvo-aacenc [no]
183 183
   --enable-libvo-amrwbenc  enable AMR-WB encoding via libvo-amrwbenc [no]
... ...
@@ -1417,6 +1417,7 @@ libopenjpeg_decoder_deps="libopenjpeg"
1417 1417
 libschroedinger_decoder_deps="libschroedinger"
1418 1418
 libschroedinger_encoder_deps="libschroedinger"
1419 1419
 libspeex_decoder_deps="libspeex"
1420
+libspeex_encoder_deps="libspeex"
1420 1421
 libtheora_encoder_deps="libtheora"
1421 1422
 libvo_aacenc_encoder_deps="libvo_aacenc"
1422 1423
 libvo_amrwbenc_encoder_deps="libvo_amrwbenc"
... ...
@@ -587,6 +587,7 @@ OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER)    += libschroedingerenc.o \
587 587
                                              libschroedinger.o    \
588 588
                                              libdirac_libschro.o
589 589
 OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
590
+OBJS-$(CONFIG_LIBSPEEX_ENCODER)           += libspeexenc.o
590 591
 OBJS-$(CONFIG_LIBTHEORA_ENCODER)          += libtheoraenc.o
591 592
 OBJS-$(CONFIG_LIBVO_AACENC_ENCODER)       += libvo-aacenc.o mpeg4audio.o
592 593
 OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER)     += libvo-amrwbenc.o
... ...
@@ -380,7 +380,7 @@ void avcodec_register_all(void)
380 380
     REGISTER_DECODER (LIBOPENCORE_AMRWB, libopencore_amrwb);
381 381
     REGISTER_DECODER (LIBOPENJPEG, libopenjpeg);
382 382
     REGISTER_ENCDEC  (LIBSCHROEDINGER, libschroedinger);
383
-    REGISTER_DECODER (LIBSPEEX, libspeex);
383
+    REGISTER_ENCDEC  (LIBSPEEX, libspeex);
384 384
     REGISTER_ENCODER (LIBTHEORA, libtheora);
385 385
     REGISTER_ENCODER (LIBVO_AACENC, libvo_aacenc);
386 386
     REGISTER_ENCODER (LIBVO_AMRWBENC, libvo_amrwbenc);
387 387
new file mode 100644
... ...
@@ -0,0 +1,178 @@
0
+/*
1
+ * Copyright (c) 2009 by Xuggle Incorporated.  All rights reserved.
2
+ * This file is part of FFmpeg.
3
+ *
4
+ * FFmpeg is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU Lesser General Public
6
+ * License as published by the Free Software Foundation; either
7
+ * version 2.1 of the License, or (at your option) any later version.
8
+ *
9
+ * FFmpeg is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * Lesser General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Lesser General Public
15
+ * License along with FFmpeg; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+#include <libavcodec/avcodec.h>
19
+#include <speex/speex.h>
20
+#include <speex/speex_header.h>
21
+#include <speex/speex_stereo.h>
22
+
23
+typedef struct {
24
+    SpeexBits bits;
25
+    void *enc_state;
26
+    SpeexHeader header;
27
+} LibSpeexEncContext;
28
+
29
+
30
+static av_cold int libspeex_encode_init(AVCodecContext *avctx)
31
+{
32
+    LibSpeexEncContext *s = (LibSpeexEncContext*)avctx->priv_data;
33
+    const SpeexMode *mode;
34
+
35
+    if ((avctx->sample_fmt != SAMPLE_FMT_S16 && avctx->sample_fmt != SAMPLE_FMT_FLT) ||
36
+            avctx->sample_rate <= 0 ||
37
+            avctx->channels <= 0 ||
38
+            avctx->channels > 2)
39
+    {
40
+        av_log(avctx, AV_LOG_ERROR, "Unsupported sample format, rate, or channels for speex");
41
+        return -1;
42
+    }
43
+
44
+    if (avctx->sample_rate <= 8000)
45
+        mode = &speex_nb_mode;
46
+    else if (avctx->sample_rate <= 16000)
47
+        mode = &speex_wb_mode;
48
+    else
49
+        mode = &speex_uwb_mode;
50
+
51
+    speex_bits_init(&s->bits);
52
+    s->enc_state = speex_encoder_init(mode);
53
+    if (!s->enc_state)
54
+    {
55
+        av_log(avctx, AV_LOG_ERROR, "could not initialize speex encoder");
56
+        return -1;
57
+    }
58
+
59
+    // initialize the header
60
+    speex_init_header(&s->header, avctx->sample_rate,
61
+            avctx->channels, mode);
62
+
63
+    // TODO: It'd be nice to support VBR here, but
64
+    // I'm uncertain what AVCodecContext options to use
65
+    // to signal whether to turn it on.
66
+    if (avctx->flags & CODEC_FLAG_QSCALE) {
67
+        spx_int32_t quality = 0;
68
+        // Map global_quality's mpeg 1/2/4 scale into Speex's 0-10 scale
69
+        if (avctx->global_quality > FF_LAMBDA_MAX)
70
+            quality = 0; // lowest possible quality
71
+        else
72
+            quality = (spx_int32_t)((FF_LAMBDA_MAX-avctx->global_quality)*10.0/FF_LAMBDA_MAX);
73
+        speex_encoder_ctl(s->enc_state, SPEEX_SET_QUALITY, &quality);
74
+    } else {
75
+        // default to CBR
76
+        if (avctx->bit_rate > 0)
77
+            speex_encoder_ctl(s->enc_state, SPEEX_SET_BITRATE, &avctx->bit_rate);
78
+        // otherwise just take the default quality setting
79
+    }
80
+    // reset the bit-rate to the actual bit rate speex will use
81
+    speex_encoder_ctl(s->enc_state, SPEEX_GET_BITRATE, &s->header.bitrate);
82
+    avctx->bit_rate = s->header.bitrate;
83
+
84
+    // get the actual sample rate
85
+    speex_encoder_ctl(s->enc_state, SPEEX_GET_SAMPLING_RATE, &s->header.rate);
86
+    avctx->sample_rate = s->header.rate;
87
+
88
+    // get the frame-size.  To align with FLV, we're going to put 2 frames
89
+    // per packet.  If someone can tell me how to make this configurable
90
+    // from the avcodec contents, I'll mod this so it's not hard-coded.
91
+    // but without this, FLV files with speex data won't play correctly
92
+    // in flash player 10.
93
+    speex_encoder_ctl(s->enc_state, SPEEX_GET_FRAME_SIZE, &s->header.frame_size);
94
+    s->header.frames_per_packet = 2; // Need for FLV container support
95
+    avctx->frame_size = s->header.frame_size*s->header.frames_per_packet;
96
+
97
+    // and we'll put a speex header packet into extradata so that muxers
98
+    // can use it.
99
+    avctx->extradata = speex_header_to_packet(&s->header, &avctx->extradata_size);
100
+    return 0;
101
+}
102
+
103
+static av_cold int libspeex_encode_frame(
104
+        AVCodecContext *avctx, uint8_t *frame,
105
+        int buf_size, void *data)
106
+{
107
+    LibSpeexEncContext *s = (LibSpeexEncContext*)avctx->priv_data;
108
+    int i = 0;
109
+
110
+    if (!data)
111
+        // nothing to flush
112
+        return 0;
113
+
114
+    speex_bits_reset(&s->bits);
115
+    for(i = 0; i < s->header.frames_per_packet; i++)
116
+    {
117
+        if (avctx->sample_fmt == SAMPLE_FMT_FLT)
118
+        {
119
+            if (avctx->channels == 2) {
120
+                speex_encode_stereo(
121
+                        (float*)data+i*s->header.frame_size,
122
+                        s->header.frame_size,
123
+                        &s->bits);
124
+            }
125
+            speex_encode(s->enc_state,
126
+                    (float*)data+i*s->header.frame_size, &s->bits);
127
+        } else {
128
+            if (avctx->channels == 2) {
129
+                speex_encode_stereo_int(
130
+                        (spx_int16_t*)data+i*s->header.frame_size,
131
+                        s->header.frame_size,
132
+                        &s->bits);
133
+            }
134
+            speex_encode_int(s->enc_state,
135
+                    (spx_int16_t*)data+i*s->header.frame_size, &s->bits);
136
+        }
137
+    }
138
+    // put in a terminator so this will fit in a OGG or FLV packet
139
+    speex_bits_insert_terminator(&s->bits);
140
+
141
+    if (buf_size >= speex_bits_nbytes(&s->bits)) {
142
+        return speex_bits_write(&s->bits, frame, buf_size);
143
+    } else {
144
+        av_log(avctx, AV_LOG_ERROR, "output buffer too small");
145
+        return -1;
146
+    }
147
+}
148
+
149
+static av_cold int libspeex_encode_close(AVCodecContext *avctx)
150
+{
151
+    LibSpeexEncContext *s = (LibSpeexEncContext*)avctx->priv_data;
152
+
153
+    speex_bits_destroy(&s->bits);
154
+    speex_encoder_destroy(s->enc_state);
155
+    s->enc_state = 0;
156
+    if (avctx->extradata)
157
+        speex_header_free(avctx->extradata);
158
+    avctx->extradata = 0;
159
+    avctx->extradata_size = 0;
160
+
161
+    return 0;
162
+}
163
+
164
+AVCodec ff_libspeex_encoder = {
165
+    "libspeex",
166
+    AVMEDIA_TYPE_AUDIO,
167
+    CODEC_ID_SPEEX,
168
+    sizeof(LibSpeexEncContext),
169
+    libspeex_encode_init,
170
+    libspeex_encode_frame,
171
+    libspeex_encode_close,
172
+    0,
173
+    .capabilities = CODEC_CAP_DELAY,
174
+    .supported_samplerates = (const int[]){8000, 16000, 32000, 0},
175
+    .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_FLT,SAMPLE_FMT_NONE},
176
+    .long_name = NULL_IF_CONFIG_SMALL("libspeex Speex Encoder"),
177
+};