Libav
pcm-dvd.c
Go to the documentation of this file.
1 /*
2  * LPCM codecs for PCM formats found in Video DVD streams
3  * Copyright (c) 2013 Christian Schmidt
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 
27 #include "avcodec.h"
28 #include "bytestream.h"
29 #include "internal.h"
30 
31 typedef struct PCMDVDContext {
32  uint32_t last_header; // Cached header to see if parsing is needed
33  int block_size; // Size of a block of samples in bytes
34  int samples_per_block; // Number of samples per channel per block
35  int groups_per_block; // Number of 20/24bit sample groups per block
36  uint8_t *extra_samples; // Pointer to leftover samples from a frame
37  int extra_sample_count; // Number of leftover samples in the buffer
39 
41 {
42  PCMDVDContext *s = avctx->priv_data;
43 
44  /* Invalid header to force parsing of the first header */
45  s->last_header = -1;
46  /* reserve space for 8 channels, 3 bytes/sample, 4 samples/block */
47  if (!(s->extra_samples = av_malloc(8 * 3 * 4)))
48  return AVERROR(ENOMEM);
49 
50  return 0;
51 }
52 
54 {
55  PCMDVDContext *s = avctx->priv_data;
56 
58 
59  return 0;
60 }
61 
62 static int pcm_dvd_parse_header(AVCodecContext *avctx, const uint8_t *header)
63 {
64  /* no traces of 44100 and 32000Hz in any commercial software or player */
65  static const uint32_t frequencies[4] = { 48000, 96000, 44100, 32000 };
66  PCMDVDContext *s = avctx->priv_data;
67  int header_int = (header[0] & 0xe0) | (header[1] << 8) | (header[2] << 16);
68 
69  /* early exit if the header didn't change apart from the frame number */
70  if (s->last_header == header_int)
71  return 0;
72 
73  if (avctx->debug & FF_DEBUG_PICT_INFO)
74  av_dlog(avctx, "pcm_dvd_parse_header: header = %02x%02x%02x\n",
75  header[0], header[1], header[2]);
76  /*
77  * header[0] emphasis (1), muse(1), reserved(1), frame number(5)
78  * header[1] quant (2), freq(2), reserved(1), channels(3)
79  * header[2] dynamic range control (0x80 = off)
80  */
81 
82  /* Discard potentially existing leftover samples from old channel layout */
83  s->extra_sample_count = 0;
84 
85  /* get the sample depth and derive the sample format from it */
86  avctx->bits_per_coded_sample = 16 + (header[1] >> 6 & 3) * 4;
87  if (avctx->bits_per_coded_sample == 28) {
88  av_log(avctx, AV_LOG_ERROR, "PCM DVD unsupported sample depth\n");
89  return AVERROR_INVALIDDATA;
90  }
91  avctx->sample_fmt = avctx->bits_per_coded_sample == 16 ? AV_SAMPLE_FMT_S16
94 
95  /* get the sample rate */
96  avctx->sample_rate = frequencies[header[1] >> 4 & 3];
97 
98  /* get the number of channels */
99  avctx->channels = 1 + (header[1] & 7);
100  /* calculate the bitrate */
101  avctx->bit_rate = avctx->channels *
102  avctx->sample_rate *
103  avctx->bits_per_coded_sample;
104 
105  /* 4 samples form a group in 20/24bit PCM on DVD Video.
106  * A block is formed by the number of groups that are
107  * needed to complete a set of samples for each channel. */
108  if (avctx->bits_per_coded_sample == 16) {
109  s->samples_per_block = 1;
110  s->block_size = avctx->channels * 2;
111  } else {
112  switch (avctx->channels) {
113  case 1:
114  case 2:
115  case 4:
116  /* one group has all the samples needed */
117  s->block_size = 4 * avctx->bits_per_coded_sample / 8;
118  s->samples_per_block = 4 / avctx->channels;
119  s->groups_per_block = 1;
120  break;
121  case 8:
122  /* two groups have all the samples needed */
123  s->block_size = 8 * avctx->bits_per_coded_sample / 8;
124  s->samples_per_block = 1;
125  s->groups_per_block = 2;
126  break;
127  default:
128  /* need avctx->channels groups */
129  s->block_size = 4 * avctx->channels *
130  avctx->bits_per_coded_sample / 8;
131  s->samples_per_block = 4;
132  s->groups_per_block = avctx->channels;
133  break;
134  }
135  }
136 
137  if (avctx->debug & FF_DEBUG_PICT_INFO)
138  av_dlog(avctx,
139  "pcm_dvd_parse_header: %d channels, %d bits per sample, %d Hz, %d bit/s\n",
140  avctx->channels, avctx->bits_per_coded_sample,
141  avctx->sample_rate, avctx->bit_rate);
142 
143  s->last_header = header_int;
144 
145  return 0;
146 }
147 
148 static void *pcm_dvd_decode_samples(AVCodecContext *avctx, const uint8_t *src,
149  void *dst, int blocks)
150 {
151  PCMDVDContext *s = avctx->priv_data;
152  int16_t *dst16 = dst;
153  int32_t *dst32 = dst;
154  GetByteContext gb;
155  int i;
156  uint8_t t;
157  int samples;
158 
159  bytestream2_init(&gb, src, blocks * s->block_size);
160  switch (avctx->bits_per_coded_sample) {
161  case 16:
162 #if HAVE_BIGENDIAN
163  bytestream2_get_buffer(&gb, dst16, blocks * s->block_size);
164  dst16 += blocks * s->block_size / 2;
165 #else
166  samples = blocks * avctx->channels;
167  do {
168  *dst16++ = bytestream2_get_be16u(&gb);
169  } while (--samples);
170 #endif
171  return dst16;
172  case 20:
173  do {
174  for (i = s->groups_per_block; i; i--) {
175  dst32[0] = bytestream2_get_be16u(&gb) << 16;
176  dst32[1] = bytestream2_get_be16u(&gb) << 16;
177  dst32[2] = bytestream2_get_be16u(&gb) << 16;
178  dst32[3] = bytestream2_get_be16u(&gb) << 16;
179  t = bytestream2_get_byteu(&gb);
180  *dst32++ += (t & 0xf0) << 8;
181  *dst32++ += (t & 0x0f) << 12;
182  t = bytestream2_get_byteu(&gb);
183  *dst32++ += (t & 0xf0) << 8;
184  *dst32++ += (t & 0x0f) << 12;
185  }
186  } while (--blocks);
187  return dst32;
188  case 24:
189  do {
190  for (i = s->groups_per_block; i; i--) {
191  dst32[0] = bytestream2_get_be16u(&gb) << 16;
192  dst32[1] = bytestream2_get_be16u(&gb) << 16;
193  dst32[2] = bytestream2_get_be16u(&gb) << 16;
194  dst32[3] = bytestream2_get_be16u(&gb) << 16;
195  *dst32++ += bytestream2_get_byteu(&gb) << 8;
196  *dst32++ += bytestream2_get_byteu(&gb) << 8;
197  *dst32++ += bytestream2_get_byteu(&gb) << 8;
198  *dst32++ += bytestream2_get_byteu(&gb) << 8;
199  }
200  } while (--blocks);
201  return dst32;
202  default:
203  return NULL;
204  }
205 }
206 
207 static int pcm_dvd_decode_frame(AVCodecContext *avctx, void *data,
208  int *got_frame_ptr, AVPacket *avpkt)
209 {
210  AVFrame *frame = data;
211  const uint8_t *src = avpkt->data;
212  int buf_size = avpkt->size;
213  PCMDVDContext *s = avctx->priv_data;
214  int retval;
215  int blocks;
216  void *dst;
217 
218  if (buf_size < 3) {
219  av_log(avctx, AV_LOG_ERROR, "PCM packet too small\n");
220  return AVERROR_INVALIDDATA;
221  }
222 
223  if ((retval = pcm_dvd_parse_header(avctx, src)))
224  return retval;
225  src += 3;
226  buf_size -= 3;
227 
228  blocks = (buf_size + s->extra_sample_count) / s->block_size;
229 
230  /* get output buffer */
231  frame->nb_samples = blocks * s->samples_per_block;
232  if ((retval = ff_get_buffer(avctx, frame, 0)) < 0) {
233  av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
234  return retval;
235  }
236  dst = frame->data[0];
237 
238  /* consume leftover samples from last packet */
239  if (s->extra_sample_count) {
240  int missing_samples = s->block_size - s->extra_sample_count;
241  if (buf_size >= missing_samples) {
242  memcpy(s->extra_samples + s->extra_sample_count, src,
243  missing_samples);
244  dst = pcm_dvd_decode_samples(avctx, s->extra_samples, dst, 1);
245  src += missing_samples;
246  buf_size -= missing_samples;
247  s->extra_sample_count = 0;
248  blocks--;
249  } else {
250  /* new packet still doesn't have enough samples */
251  memcpy(s->extra_samples + s->extra_sample_count, src, buf_size);
252  s->extra_sample_count += buf_size;
253  return avpkt->size;
254  }
255  }
256 
257  /* decode remaining complete samples */
258  if (blocks) {
259  pcm_dvd_decode_samples(avctx, src, dst, blocks);
260  buf_size -= blocks * s->block_size;
261  }
262 
263  /* store leftover samples */
264  if (buf_size) {
265  src += blocks * s->block_size;
266  memcpy(s->extra_samples, src, buf_size);
267  s->extra_sample_count = buf_size;
268  }
269 
270  *got_frame_ptr = 1;
271 
272  return avpkt->size;
273 }
274 
276  .name = "pcm_dvd",
277  .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16|20|24-bit big-endian for DVD media"),
278  .type = AVMEDIA_TYPE_AUDIO,
279  .id = AV_CODEC_ID_PCM_DVD,
280  .priv_data_size = sizeof(PCMDVDContext),
284  .capabilities = CODEC_CAP_DR1,
285  .sample_fmts = (const enum AVSampleFormat[]) {
287  }
288 };