libavcodec/8svx.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Jaikrishnan Menon
00003  * Copyright (C) 2011 Stefano Sabatini
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00040 #include "avcodec.h"
00041 
00043 typedef struct EightSvxContext {
00044     AVFrame frame;
00045     const int8_t *table;
00046 
00047     /* buffer used to store the whole audio decoded/interleaved chunk,
00048      * which is sent with the first packet */
00049     uint8_t *samples;
00050     size_t samples_size;
00051     int samples_idx;
00052 } EightSvxContext;
00053 
00054 static const int8_t fibonacci[16]   = { -34,  -21, -13,  -8, -5, -3, -2, -1, 0, 1, 2, 3, 5, 8,  13, 21 };
00055 static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64 };
00056 
00057 #define MAX_FRAME_SIZE 2048
00058 
00066 static void interleave_stereo(uint8_t *dst, const uint8_t *src, int size)
00067 {
00068     uint8_t *dst_end = dst + size;
00069     size = size>>1;
00070 
00071     while (dst < dst_end) {
00072         *dst++ = *src;
00073         *dst++ = *(src+size);
00074         src++;
00075     }
00076 }
00077 
00086 static int delta_decode(int8_t *dst, const uint8_t *src, int src_size,
00087                         int8_t val, const int8_t *table)
00088 {
00089     int n = src_size;
00090     int8_t *dst0 = dst;
00091 
00092     while (n--) {
00093         uint8_t d = *src++;
00094         val = av_clip(val + table[d & 0x0f], -127, 128);
00095         *dst++ = val;
00096         val = av_clip(val + table[d >> 4]  , -127, 128);
00097         *dst++ = val;
00098     }
00099 
00100     return dst-dst0;
00101 }
00102 
00104 static int eightsvx_decode_frame(AVCodecContext *avctx, void *data,
00105                                  int *got_frame_ptr, AVPacket *avpkt)
00106 {
00107     EightSvxContext *esc = avctx->priv_data;
00108     int n, out_data_size, ret;
00109     uint8_t *src, *dst;
00110 
00111     /* decode and interleave the first packet */
00112     if (!esc->samples && avpkt) {
00113         uint8_t *deinterleaved_samples, *p = NULL;
00114 
00115         esc->samples_size = avctx->codec->id == CODEC_ID_8SVX_RAW || avctx->codec->id ==CODEC_ID_PCM_S8_PLANAR?
00116             avpkt->size : avctx->channels + (avpkt->size-avctx->channels) * 2;
00117         if (!(esc->samples = av_malloc(esc->samples_size)))
00118             return AVERROR(ENOMEM);
00119 
00120         /* decompress */
00121         if (avctx->codec->id == CODEC_ID_8SVX_FIB || avctx->codec->id == CODEC_ID_8SVX_EXP) {
00122             const uint8_t *buf = avpkt->data;
00123             int buf_size = avpkt->size;
00124             int n = esc->samples_size;
00125 
00126             if (buf_size < 2) {
00127                 av_log(avctx, AV_LOG_ERROR, "packet size is too small\n");
00128                 return AVERROR(EINVAL);
00129             }
00130             if (!(deinterleaved_samples = av_mallocz(n)))
00131                 return AVERROR(ENOMEM);
00132             p = deinterleaved_samples;
00133 
00134             /* the uncompressed starting value is contained in the first byte */
00135             if (avctx->channels == 2) {
00136                 delta_decode(deinterleaved_samples      , buf+1, buf_size/2-1, buf[0], esc->table);
00137                 buf += buf_size/2;
00138                 delta_decode(deinterleaved_samples+n/2-1, buf+1, buf_size/2-1, buf[0], esc->table);
00139             } else
00140                 delta_decode(deinterleaved_samples      , buf+1, buf_size-1  , buf[0], esc->table);
00141         } else {
00142             deinterleaved_samples = avpkt->data;
00143         }
00144 
00145         if (avctx->channels == 2)
00146             interleave_stereo(esc->samples, deinterleaved_samples, esc->samples_size);
00147         else
00148             memcpy(esc->samples, deinterleaved_samples, esc->samples_size);
00149         av_freep(&p);
00150     }
00151 
00152     /* get output buffer */
00153     esc->frame.nb_samples = (FFMIN(MAX_FRAME_SIZE, esc->samples_size - esc->samples_idx) +avctx->channels-1)  / avctx->channels;
00154     if ((ret = avctx->get_buffer(avctx, &esc->frame)) < 0) {
00155         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00156         return ret;
00157     }
00158 
00159     *got_frame_ptr   = 1;
00160     *(AVFrame *)data = esc->frame;
00161 
00162     dst = esc->frame.data[0];
00163     src = esc->samples + esc->samples_idx;
00164     out_data_size = esc->frame.nb_samples * avctx->channels;
00165     for (n = out_data_size; n > 0; n--)
00166         *dst++ = *src++ + 128;
00167     esc->samples_idx += out_data_size;
00168 
00169     return avctx->codec->id == CODEC_ID_8SVX_FIB || avctx->codec->id == CODEC_ID_8SVX_EXP ?
00170         (avctx->frame_number == 0)*2 + out_data_size / 2 :
00171         out_data_size;
00172 }
00173 
00174 static av_cold int eightsvx_decode_init(AVCodecContext *avctx)
00175 {
00176     EightSvxContext *esc = avctx->priv_data;
00177 
00178     if (avctx->channels < 1 || avctx->channels > 2) {
00179         av_log(avctx, AV_LOG_ERROR, "8SVX does not support more than 2 channels\n");
00180         return AVERROR_INVALIDDATA;
00181     }
00182 
00183     switch (avctx->codec->id) {
00184     case CODEC_ID_8SVX_FIB: esc->table = fibonacci;    break;
00185     case CODEC_ID_8SVX_EXP: esc->table = exponential;  break;
00186     case CODEC_ID_PCM_S8_PLANAR:
00187     case CODEC_ID_8SVX_RAW: esc->table = NULL;         break;
00188     default:
00189         av_log(avctx, AV_LOG_ERROR, "Invalid codec id %d.\n", avctx->codec->id);
00190         return AVERROR_INVALIDDATA;
00191     }
00192     avctx->sample_fmt = AV_SAMPLE_FMT_U8;
00193 
00194     avcodec_get_frame_defaults(&esc->frame);
00195     avctx->coded_frame = &esc->frame;
00196 
00197     return 0;
00198 }
00199 
00200 static av_cold int eightsvx_decode_close(AVCodecContext *avctx)
00201 {
00202     EightSvxContext *esc = avctx->priv_data;
00203 
00204     av_freep(&esc->samples);
00205     esc->samples_size = 0;
00206     esc->samples_idx = 0;
00207 
00208     return 0;
00209 }
00210 
00211 AVCodec ff_eightsvx_fib_decoder = {
00212   .name           = "8svx_fib",
00213   .type           = AVMEDIA_TYPE_AUDIO,
00214   .id             = CODEC_ID_8SVX_FIB,
00215   .priv_data_size = sizeof (EightSvxContext),
00216   .init           = eightsvx_decode_init,
00217   .decode         = eightsvx_decode_frame,
00218   .close          = eightsvx_decode_close,
00219   .capabilities   = CODEC_CAP_DR1,
00220   .long_name      = NULL_IF_CONFIG_SMALL("8SVX fibonacci"),
00221 };
00222 
00223 AVCodec ff_eightsvx_exp_decoder = {
00224   .name           = "8svx_exp",
00225   .type           = AVMEDIA_TYPE_AUDIO,
00226   .id             = CODEC_ID_8SVX_EXP,
00227   .priv_data_size = sizeof (EightSvxContext),
00228   .init           = eightsvx_decode_init,
00229   .decode         = eightsvx_decode_frame,
00230   .close          = eightsvx_decode_close,
00231   .capabilities   = CODEC_CAP_DR1,
00232   .long_name      = NULL_IF_CONFIG_SMALL("8SVX exponential"),
00233 };
00234 
00235 AVCodec ff_pcm_s8_planar_decoder = {
00236     .name           = "pcm_s8_planar",
00237     .type           = AVMEDIA_TYPE_AUDIO,
00238     .id             = CODEC_ID_PCM_S8_PLANAR,
00239     .priv_data_size = sizeof(EightSvxContext),
00240     .init           = eightsvx_decode_init,
00241     .close          = eightsvx_decode_close,
00242     .decode         = eightsvx_decode_frame,
00243     .capabilities   = CODEC_CAP_DR1,
00244     .long_name      = NULL_IF_CONFIG_SMALL("PCM signed 8-bit planar"),
00245 };