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

libavcodec/roqaudioenc.c

Go to the documentation of this file.
00001 /*
00002  * RoQ audio encoder
00003  *
00004  * Copyright (c) 2005 Eric Lasota
00005  *    Based on RoQ specs (c)2001 Tim Ferguson
00006  *
00007  * This file is part of FFmpeg.
00008  *
00009  * FFmpeg is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * FFmpeg is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with FFmpeg; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00022  */
00023 
00024 #include "avcodec.h"
00025 #include "bytestream.h"
00026 
00027 #define ROQ_FIRST_FRAME_SIZE     (735*8)
00028 #define ROQ_FRAME_SIZE           735
00029 
00030 
00031 #define MAX_DPCM (127*127)
00032 static unsigned char dpcmValues[MAX_DPCM];
00033 
00034 
00035 typedef struct
00036 {
00037     short lastSample[2];
00038 } ROQDPCMContext;
00039 
00040 static av_cold void roq_dpcm_table_init(void)
00041 {
00042     int i;
00043 
00044     /* Create a table of quick DPCM values */
00045     for (i=0; i<MAX_DPCM; i++) {
00046         int s= ff_sqrt(i);
00047         int mid= s*s + s;
00048         dpcmValues[i]= s + (i>mid);
00049     }
00050 }
00051 
00052 static av_cold int roq_dpcm_encode_init(AVCodecContext *avctx)
00053 {
00054     ROQDPCMContext *context = avctx->priv_data;
00055 
00056     if (avctx->channels > 2) {
00057         av_log(avctx, AV_LOG_ERROR, "Audio must be mono or stereo\n");
00058         return -1;
00059     }
00060     if (avctx->sample_rate != 22050) {
00061         av_log(avctx, AV_LOG_ERROR, "Audio must be 22050 Hz\n");
00062         return -1;
00063     }
00064     if (avctx->sample_fmt != SAMPLE_FMT_S16) {
00065         av_log(avctx, AV_LOG_ERROR, "Audio must be signed 16-bit\n");
00066         return -1;
00067     }
00068 
00069     roq_dpcm_table_init();
00070 
00071     avctx->frame_size = ROQ_FIRST_FRAME_SIZE;
00072 
00073     context->lastSample[0] = context->lastSample[1] = 0;
00074 
00075     avctx->coded_frame= avcodec_alloc_frame();
00076     avctx->coded_frame->key_frame= 1;
00077 
00078     return 0;
00079 }
00080 
00081 static unsigned char dpcm_predict(short *previous, short current)
00082 {
00083     int diff;
00084     int negative;
00085     int result;
00086     int predicted;
00087 
00088     diff = current - *previous;
00089 
00090     negative = diff<0;
00091     diff = FFABS(diff);
00092 
00093     if (diff >= MAX_DPCM)
00094         result = 127;
00095     else
00096         result = dpcmValues[diff];
00097 
00098     /* See if this overflows */
00099  retry:
00100     diff = result*result;
00101     if (negative)
00102         diff = -diff;
00103     predicted = *previous + diff;
00104 
00105     /* If it overflows, back off a step */
00106     if (predicted > 32767 || predicted < -32768) {
00107         result--;
00108         goto retry;
00109     }
00110 
00111     /* Add the sign bit */
00112     result |= negative << 7;   //if (negative) result |= 128;
00113 
00114     *previous = predicted;
00115 
00116     return result;
00117 }
00118 
00119 static int roq_dpcm_encode_frame(AVCodecContext *avctx,
00120                 unsigned char *frame, int buf_size, void *data)
00121 {
00122     int i, samples, stereo, ch;
00123     short *in;
00124     unsigned char *out;
00125 
00126     ROQDPCMContext *context = avctx->priv_data;
00127 
00128     stereo = (avctx->channels == 2);
00129 
00130     if (stereo) {
00131         context->lastSample[0] &= 0xFF00;
00132         context->lastSample[1] &= 0xFF00;
00133     }
00134 
00135     out = frame;
00136     in = data;
00137 
00138     bytestream_put_byte(&out, stereo ? 0x21 : 0x20);
00139     bytestream_put_byte(&out, 0x10);
00140     bytestream_put_le32(&out, avctx->frame_size*avctx->channels);
00141 
00142     if (stereo) {
00143         bytestream_put_byte(&out, (context->lastSample[1])>>8);
00144         bytestream_put_byte(&out, (context->lastSample[0])>>8);
00145     } else
00146         bytestream_put_le16(&out, context->lastSample[0]);
00147 
00148     /* Write the actual samples */
00149     samples = avctx->frame_size;
00150     for (i=0; i<samples; i++)
00151         for (ch=0; ch<avctx->channels; ch++)
00152             *out++ = dpcm_predict(&context->lastSample[ch], *in++);
00153 
00154     /* Use smaller frames from now on */
00155     avctx->frame_size = ROQ_FRAME_SIZE;
00156 
00157     /* Return the result size */
00158     return out - frame;
00159 }
00160 
00161 static av_cold int roq_dpcm_encode_close(AVCodecContext *avctx)
00162 {
00163     av_freep(&avctx->coded_frame);
00164 
00165     return 0;
00166 }
00167 
00168 AVCodec roq_dpcm_encoder = {
00169     "roq_dpcm",
00170     CODEC_TYPE_AUDIO,
00171     CODEC_ID_ROQ_DPCM,
00172     sizeof(ROQDPCMContext),
00173     roq_dpcm_encode_init,
00174     roq_dpcm_encode_frame,
00175     roq_dpcm_encode_close,
00176     NULL,
00177     .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
00178     .long_name = NULL_IF_CONFIG_SMALL("id RoQ DPCM"),
00179 };

Generated on Tue Nov 4 2014 12:59:22 for ffmpeg by  doxygen 1.7.1