8svx: output 8-bit samples instead of 16-bit.
[ffmpeg.git] / libavcodec / 8svx.c
1 /*
2  * 8SVX audio decoder
3  * Copyright (C) 2008 Jaikrishnan Menon
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * 8svx audio decoder
25  * @author Jaikrishnan Menon
26  *
27  * supports: fibonacci delta encoding
28  *         : exponential encoding
29  */
30
31 #include "avcodec.h"
32
33 /** decoder context */
34 typedef struct EightSvxContext {
35     uint8_t fib_acc;
36     const int8_t *table;
37 } EightSvxContext;
38
39 static const int8_t fibonacci[16]   = { -34, -21, -13,  -8, -5, -3, -2, -1,
40                                           0,   1,   2,   3,  5,  8, 13, 21 };
41 static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1,
42                                            0,   1,   2,   4,  8, 16, 32, 64 };
43
44 /**
45  * Delta decode the compressed values in src, and put the resulting
46  * decoded samples in dst.
47  *
48  * @param[in,out] state starting value. it is saved for use in the next call.
49  */
50 static void delta_decode(uint8_t *dst, const uint8_t *src, int src_size,
51                          uint8_t *state, const int8_t *table)
52 {
53     uint8_t val = *state;
54
55     while (src_size--) {
56         uint8_t d = *src++;
57         val = av_clip_uint8(val + table[d & 0xF]);
58         *dst++ = val;
59         val = av_clip_uint8(val + table[d >> 4]);
60         *dst++ = val;
61     }
62
63     *state = val;
64 }
65
66 /** decode a frame */
67 static int eightsvx_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
68                                  AVPacket *avpkt)
69 {
70     const uint8_t *buf = avpkt->data;
71     int buf_size = avpkt->size;
72     EightSvxContext *esc = avctx->priv_data;
73     uint8_t *out_data = data;
74     int consumed = buf_size;
75
76     if(avctx->frame_number == 0) {
77         esc->fib_acc = (int8_t)buf[1] + 128;
78         buf_size -= 2;
79         buf += 2;
80     }
81
82     if (*data_size < buf_size * 2)
83         return AVERROR(EINVAL);
84
85     delta_decode(out_data, buf, buf_size, &esc->fib_acc, esc->table);
86
87     *data_size = buf_size * 2;
88
89     return consumed;
90 }
91
92 /** initialize 8svx decoder */
93 static av_cold int eightsvx_decode_init(AVCodecContext *avctx)
94 {
95     EightSvxContext *esc = avctx->priv_data;
96
97     switch(avctx->codec->id) {
98         case CODEC_ID_8SVX_FIB:
99           esc->table = fibonacci;
100           break;
101         case CODEC_ID_8SVX_EXP:
102           esc->table = exponential;
103           break;
104         default:
105           return -1;
106     }
107     avctx->sample_fmt = AV_SAMPLE_FMT_U8;
108     return 0;
109 }
110
111 AVCodec ff_eightsvx_fib_decoder = {
112   .name           = "8svx_fib",
113   .type           = AVMEDIA_TYPE_AUDIO,
114   .id             = CODEC_ID_8SVX_FIB,
115   .priv_data_size = sizeof (EightSvxContext),
116   .init           = eightsvx_decode_init,
117   .decode         = eightsvx_decode_frame,
118   .long_name      = NULL_IF_CONFIG_SMALL("8SVX fibonacci"),
119 };
120
121 AVCodec ff_eightsvx_exp_decoder = {
122   .name           = "8svx_exp",
123   .type           = AVMEDIA_TYPE_AUDIO,
124   .id             = CODEC_ID_8SVX_EXP,
125   .priv_data_size = sizeof (EightSvxContext),
126   .init           = eightsvx_decode_init,
127   .decode         = eightsvx_decode_frame,
128   .long_name      = NULL_IF_CONFIG_SMALL("8SVX exponential"),
129 };