8svx: check packet size before reading the initial sample value.
[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         if (buf_size < 2) {
78             av_log(avctx, AV_LOG_ERROR, "packet size is too small\n");
79             return AVERROR(EINVAL);
80         }
81         esc->fib_acc = (int8_t)buf[1] + 128;
82         buf_size -= 2;
83         buf += 2;
84     }
85
86     if (*data_size < buf_size * 2)
87         return AVERROR(EINVAL);
88
89     delta_decode(out_data, buf, buf_size, &esc->fib_acc, esc->table);
90
91     *data_size = buf_size * 2;
92
93     return consumed;
94 }
95
96 /** initialize 8svx decoder */
97 static av_cold int eightsvx_decode_init(AVCodecContext *avctx)
98 {
99     EightSvxContext *esc = avctx->priv_data;
100
101     switch(avctx->codec->id) {
102         case CODEC_ID_8SVX_FIB:
103           esc->table = fibonacci;
104           break;
105         case CODEC_ID_8SVX_EXP:
106           esc->table = exponential;
107           break;
108         default:
109           return -1;
110     }
111     avctx->sample_fmt = AV_SAMPLE_FMT_U8;
112     return 0;
113 }
114
115 AVCodec ff_eightsvx_fib_decoder = {
116   .name           = "8svx_fib",
117   .type           = AVMEDIA_TYPE_AUDIO,
118   .id             = CODEC_ID_8SVX_FIB,
119   .priv_data_size = sizeof (EightSvxContext),
120   .init           = eightsvx_decode_init,
121   .decode         = eightsvx_decode_frame,
122   .long_name      = NULL_IF_CONFIG_SMALL("8SVX fibonacci"),
123 };
124
125 AVCodec ff_eightsvx_exp_decoder = {
126   .name           = "8svx_exp",
127   .type           = AVMEDIA_TYPE_AUDIO,
128   .id             = CODEC_ID_8SVX_EXP,
129   .priv_data_size = sizeof (EightSvxContext),
130   .init           = eightsvx_decode_init,
131   .decode         = eightsvx_decode_frame,
132   .long_name      = NULL_IF_CONFIG_SMALL("8SVX exponential"),
133 };