8svx.c
Go to the documentation of this file.
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 
31 #include "avcodec.h"
32 #include "internal.h"
33 
35 typedef struct EightSvxContext {
37  uint8_t fib_acc[2];
38  const int8_t *table;
39 
40  /* buffer used to store the whole first packet.
41  data is only sent as one large packet */
42  uint8_t *data[2];
43  int data_size;
44  int data_idx;
46 
47 static const int8_t fibonacci[16] = { -34, -21, -13, -8, -5, -3, -2, -1,
48  0, 1, 2, 3, 5, 8, 13, 21 };
49 static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1,
50  0, 1, 2, 4, 8, 16, 32, 64 };
51 
52 #define MAX_FRAME_SIZE 32768
53 
60 static void delta_decode(uint8_t *dst, const uint8_t *src, int src_size,
61  uint8_t *state, const int8_t *table, int channels)
62 {
63  uint8_t val = *state;
64 
65  while (src_size--) {
66  uint8_t d = *src++;
67  val = av_clip_uint8(val + table[d & 0xF]);
68  *dst = val;
69  dst += channels;
70  val = av_clip_uint8(val + table[d >> 4]);
71  *dst = val;
72  dst += channels;
73  }
74 
75  *state = val;
76 }
77 
78 static void raw_decode(uint8_t *dst, const int8_t *src, int src_size,
79  int channels)
80 {
81  while (src_size--) {
82  *dst = *src++ + 128;
83  dst += channels;
84  }
85 }
86 
88 static int eightsvx_decode_frame(AVCodecContext *avctx, void *data,
89  int *got_frame_ptr, AVPacket *avpkt)
90 {
91  EightSvxContext *esc = avctx->priv_data;
92  int buf_size;
93  uint8_t *out_data;
94  int ret;
95  int is_compr = (avctx->codec_id != CODEC_ID_PCM_S8_PLANAR);
96 
97  /* for the first packet, copy data to buffer */
98  if (avpkt->data) {
99  int hdr_size = is_compr ? 2 : 0;
100  int chan_size = (avpkt->size - hdr_size * avctx->channels) / avctx->channels;
101 
102  if (avpkt->size < hdr_size * avctx->channels) {
103  av_log(avctx, AV_LOG_ERROR, "packet size is too small\n");
104  return AVERROR(EINVAL);
105  }
106  if (esc->data[0]) {
107  av_log(avctx, AV_LOG_ERROR, "unexpected data after first packet\n");
108  return AVERROR(EINVAL);
109  }
110 
111  if (is_compr) {
112  esc->fib_acc[0] = avpkt->data[1] + 128;
113  if (avctx->channels == 2)
114  esc->fib_acc[1] = avpkt->data[2+chan_size+1] + 128;
115  }
116 
117  esc->data_idx = 0;
118  esc->data_size = chan_size;
119  if (!(esc->data[0] = av_malloc(chan_size)))
120  return AVERROR(ENOMEM);
121  if (avctx->channels == 2) {
122  if (!(esc->data[1] = av_malloc(chan_size))) {
123  av_freep(&esc->data[0]);
124  return AVERROR(ENOMEM);
125  }
126  }
127  memcpy(esc->data[0], &avpkt->data[hdr_size], chan_size);
128  if (avctx->channels == 2)
129  memcpy(esc->data[1], &avpkt->data[2*hdr_size+chan_size], chan_size);
130  }
131  if (!esc->data[0]) {
132  av_log(avctx, AV_LOG_ERROR, "unexpected empty packet\n");
133  return AVERROR(EINVAL);
134  }
135 
136  /* decode next piece of data from the buffer */
137  buf_size = FFMIN(MAX_FRAME_SIZE, esc->data_size - esc->data_idx);
138  if (buf_size <= 0) {
139  *got_frame_ptr = 0;
140  return avpkt->size;
141  }
142 
143  /* get output buffer */
144  esc->frame.nb_samples = buf_size * (is_compr + 1);
145  if ((ret = ff_get_buffer(avctx, &esc->frame)) < 0) {
146  av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
147  return ret;
148  }
149  out_data = esc->frame.data[0];
150 
151  if (is_compr) {
152  delta_decode(out_data, &esc->data[0][esc->data_idx], buf_size,
153  &esc->fib_acc[0], esc->table, avctx->channels);
154  if (avctx->channels == 2) {
155  delta_decode(&out_data[1], &esc->data[1][esc->data_idx], buf_size,
156  &esc->fib_acc[1], esc->table, avctx->channels);
157  }
158  } else {
159  int ch;
160  for (ch = 0; ch < avctx->channels; ch++) {
161  raw_decode((int8_t *)&out_data[ch], &esc->data[ch][esc->data_idx],
162  buf_size, avctx->channels);
163  }
164  }
165  esc->data_idx += buf_size;
166 
167  *got_frame_ptr = 1;
168  *(AVFrame *)data = esc->frame;
169 
170  return avpkt->size;
171 }
172 
175 {
176  EightSvxContext *esc = avctx->priv_data;
177 
178  if (avctx->channels < 1 || avctx->channels > 2) {
179  av_log(avctx, AV_LOG_ERROR, "8SVX does not support more than 2 channels\n");
180  return AVERROR(EINVAL);
181  }
182 
183  switch(avctx->codec->id) {
184  case CODEC_ID_8SVX_FIB:
185  esc->table = fibonacci;
186  break;
187  case CODEC_ID_8SVX_EXP:
188  esc->table = exponential;
189  break;
191  break;
192  default:
193  return -1;
194  }
195  avctx->sample_fmt = AV_SAMPLE_FMT_U8;
196 
198  avctx->coded_frame = &esc->frame;
199 
200  return 0;
201 }
202 
204 {
205  EightSvxContext *esc = avctx->priv_data;
206 
207  av_freep(&esc->data[0]);
208  av_freep(&esc->data[1]);
209 
210  return 0;
211 }
212 
214  .name = "8svx_fib",
215  .type = AVMEDIA_TYPE_AUDIO,
216  .id = CODEC_ID_8SVX_FIB,
217  .priv_data_size = sizeof (EightSvxContext),
221  .capabilities = CODEC_CAP_DELAY | CODEC_CAP_DR1,
222  .long_name = NULL_IF_CONFIG_SMALL("8SVX fibonacci"),
223 };
224 
226  .name = "8svx_exp",
227  .type = AVMEDIA_TYPE_AUDIO,
228  .id = CODEC_ID_8SVX_EXP,
229  .priv_data_size = sizeof (EightSvxContext),
233  .capabilities = CODEC_CAP_DELAY | CODEC_CAP_DR1,
234  .long_name = NULL_IF_CONFIG_SMALL("8SVX exponential"),
235 };
236 
238  .name = "pcm_s8_planar",
239  .type = AVMEDIA_TYPE_AUDIO,
241  .priv_data_size = sizeof(EightSvxContext),
245  .capabilities = CODEC_CAP_DELAY | CODEC_CAP_DR1,
246  .long_name = NULL_IF_CONFIG_SMALL("PCM signed 8-bit planar"),
247 };