• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

libavcodec/libspeexenc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 by Xuggle Incorporated.  All rights reserved.
00003  * This file is part of FFmpeg.
00004  *
00005  * FFmpeg is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2.1 of the License, or (at your option) any later version.
00009  *
00010  * FFmpeg is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with FFmpeg; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00018  */
00019 #include <libavcodec/avcodec.h>
00020 #include <speex/speex.h>
00021 #include <speex/speex_header.h>
00022 #include <speex/speex_stereo.h>
00023 
00024 typedef struct {
00025     SpeexBits bits;
00026     void *enc_state;
00027     SpeexHeader header;
00028 } LibSpeexEncContext;
00029 
00030 
00031 static av_cold int libspeex_encode_init(AVCodecContext *avctx)
00032 {
00033     LibSpeexEncContext *s = (LibSpeexEncContext*)avctx->priv_data;
00034     const SpeexMode *mode;
00035 
00036     if ((avctx->sample_fmt != SAMPLE_FMT_S16 && avctx->sample_fmt != SAMPLE_FMT_FLT) ||
00037             avctx->sample_rate <= 0 ||
00038             avctx->channels <= 0 ||
00039             avctx->channels > 2)
00040     {
00041         av_log(avctx, AV_LOG_ERROR, "Unsupported sample format, rate, or channels for speex");
00042         return -1;
00043     }
00044 
00045     if (avctx->sample_rate <= 8000)
00046         mode = &speex_nb_mode;
00047     else if (avctx->sample_rate <= 16000)
00048         mode = &speex_wb_mode;
00049     else
00050         mode = &speex_uwb_mode;
00051 
00052     speex_bits_init(&s->bits);
00053     s->enc_state = speex_encoder_init(mode);
00054     if (!s->enc_state)
00055     {
00056         av_log(avctx, AV_LOG_ERROR, "could not initialize speex encoder");
00057         return -1;
00058     }
00059 
00060     // initialize the header
00061     speex_init_header(&s->header, avctx->sample_rate,
00062             avctx->channels, mode);
00063 
00064     // TODO: It'd be nice to support VBR here, but
00065     // I'm uncertain what AVCodecContext options to use
00066     // to signal whether to turn it on.
00067     if (avctx->flags & CODEC_FLAG_QSCALE) {
00068         spx_int32_t quality = 0;
00069         // Map global_quality's mpeg 1/2/4 scale into Speex's 0-10 scale
00070         if (avctx->global_quality > FF_LAMBDA_MAX)
00071             quality = 0; // lowest possible quality
00072         else
00073             quality = (spx_int32_t)((FF_LAMBDA_MAX-avctx->global_quality)*10.0/FF_LAMBDA_MAX);
00074         speex_encoder_ctl(s->enc_state, SPEEX_SET_QUALITY, &quality);
00075     } else {
00076         // default to CBR
00077         if (avctx->bit_rate > 0)
00078             speex_encoder_ctl(s->enc_state, SPEEX_SET_BITRATE, &avctx->bit_rate);
00079         // otherwise just take the default quality setting
00080     }
00081     // reset the bit-rate to the actual bit rate speex will use
00082     speex_encoder_ctl(s->enc_state, SPEEX_GET_BITRATE, &s->header.bitrate);
00083     avctx->bit_rate = s->header.bitrate;
00084 
00085     // get the actual sample rate
00086     speex_encoder_ctl(s->enc_state, SPEEX_GET_SAMPLING_RATE, &s->header.rate);
00087     avctx->sample_rate = s->header.rate;
00088 
00089     // get the frame-size.  To align with FLV, we're going to put 2 frames
00090     // per packet.  If someone can tell me how to make this configurable
00091     // from the avcodec contents, I'll mod this so it's not hard-coded.
00092     // but without this, FLV files with speex data won't play correctly
00093     // in flash player 10.
00094     speex_encoder_ctl(s->enc_state, SPEEX_GET_FRAME_SIZE, &s->header.frame_size);
00095     s->header.frames_per_packet = 2; // Need for FLV container support
00096     avctx->frame_size = s->header.frame_size*s->header.frames_per_packet;
00097 
00098     // and we'll put a speex header packet into extradata so that muxers
00099     // can use it.
00100     avctx->extradata = speex_header_to_packet(&s->header, &avctx->extradata_size);
00101     return 0;
00102 }
00103 
00104 static av_cold int libspeex_encode_frame(
00105         AVCodecContext *avctx, uint8_t *frame,
00106         int buf_size, void *data)
00107 {
00108     LibSpeexEncContext *s = (LibSpeexEncContext*)avctx->priv_data;
00109     int i = 0;
00110 
00111     if (!data)
00112         // nothing to flush
00113         return 0;
00114 
00115     speex_bits_reset(&s->bits);
00116     for(i = 0; i < s->header.frames_per_packet; i++)
00117     {
00118         if (avctx->sample_fmt == SAMPLE_FMT_FLT)
00119         {
00120             if (avctx->channels == 2) {
00121                 speex_encode_stereo(
00122                         (float*)data+i*s->header.frame_size,
00123                         s->header.frame_size,
00124                         &s->bits);
00125             }
00126             speex_encode(s->enc_state,
00127                     (float*)data+i*s->header.frame_size, &s->bits);
00128         } else {
00129             if (avctx->channels == 2) {
00130                 speex_encode_stereo_int(
00131                         (spx_int16_t*)data+i*s->header.frame_size,
00132                         s->header.frame_size,
00133                         &s->bits);
00134             }
00135             speex_encode_int(s->enc_state,
00136                     (spx_int16_t*)data+i*s->header.frame_size, &s->bits);
00137         }
00138     }
00139     // put in a terminator so this will fit in a OGG or FLV packet
00140     speex_bits_insert_terminator(&s->bits);
00141 
00142     if (buf_size >= speex_bits_nbytes(&s->bits)) {
00143         return speex_bits_write(&s->bits, frame, buf_size);
00144     } else {
00145         av_log(avctx, AV_LOG_ERROR, "output buffer too small");
00146         return -1;
00147     }
00148 }
00149 
00150 static av_cold int libspeex_encode_close(AVCodecContext *avctx)
00151 {
00152     LibSpeexEncContext *s = (LibSpeexEncContext*)avctx->priv_data;
00153 
00154     speex_bits_destroy(&s->bits);
00155     speex_encoder_destroy(s->enc_state);
00156     s->enc_state = 0;
00157     if (avctx->extradata)
00158         speex_header_free(avctx->extradata);
00159     avctx->extradata = 0;
00160     avctx->extradata_size = 0;
00161 
00162     return 0;
00163 }
00164 
00165 AVCodec ff_libspeex_encoder = {
00166     "libspeex",
00167     AVMEDIA_TYPE_AUDIO,
00168     CODEC_ID_SPEEX,
00169     sizeof(LibSpeexEncContext),
00170     libspeex_encode_init,
00171     libspeex_encode_frame,
00172     libspeex_encode_close,
00173     0,
00174     .capabilities = CODEC_CAP_DELAY,
00175     .supported_samplerates = (const int[]){8000, 16000, 32000, 0},
00176     .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_FLT,SAMPLE_FMT_NONE},
00177     .long_name = NULL_IF_CONFIG_SMALL("libspeex Speex Encoder"),
00178 };

Generated on Wed Apr 11 2012 07:31:33 for FFmpeg by  doxygen 1.7.1