FFmpeg
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 FFmpeg.
6  *
7  * FFmpeg 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  * FFmpeg 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 FFmpeg; 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  * LPCM codecs for PCM formats found in Video DVD streams
25  */
26 
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 last_block_size; // Size of the last block of samples in bytes
35  int samples_per_block; // Number of samples per channel per block
36  int groups_per_block; // Number of 20/24-bit sample groups per block
37  int extra_sample_count; // Number of leftover samples in the buffer
38  uint8_t extra_samples[8 * 3 * 4]; // Space for leftover samples from a frame
39  // (8 channels, 3B/sample, 4 samples/block)
41 
43 {
44  PCMDVDContext *s = avctx->priv_data;
45 
46  /* Invalid header to force parsing of the first header */
47  s->last_header = -1;
48 
49  return 0;
50 }
51 
53 {
54  /* no traces of 44100 and 32000Hz in any commercial software or player */
55  static const uint32_t frequencies[4] = { 48000, 96000, 44100, 32000 };
56  PCMDVDContext *s = avctx->priv_data;
57  int header_int = (header[0] & 0xe0) | (header[1] << 8) | (header[2] << 16);
58 
59  /* early exit if the header didn't change apart from the frame number */
60  if (s->last_header == header_int)
61  return 0;
62  s->last_header = -1;
63 
64  if (avctx->debug & FF_DEBUG_PICT_INFO)
65  av_log(avctx, AV_LOG_DEBUG, "pcm_dvd_parse_header: header = %02x%02x%02x\n",
66  header[0], header[1], header[2]);
67  /*
68  * header[0] emphasis (1), muse(1), reserved(1), frame number(5)
69  * header[1] quant (2), freq(2), reserved(1), channels(3)
70  * header[2] dynamic range control (0x80 = off)
71  */
72 
73  /* Discard potentially existing leftover samples from old channel layout */
74  s->extra_sample_count = 0;
75 
76  /* get the sample depth and derive the sample format from it */
77  avctx->bits_per_coded_sample = 16 + (header[1] >> 6 & 3) * 4;
78  if (avctx->bits_per_coded_sample == 28) {
79  av_log(avctx, AV_LOG_ERROR,
80  "PCM DVD unsupported sample depth %i\n",
81  avctx->bits_per_coded_sample);
82  return AVERROR_INVALIDDATA;
83  }
84  avctx->sample_fmt = avctx->bits_per_coded_sample == 16 ? AV_SAMPLE_FMT_S16
87 
88  /* get the sample rate */
89  avctx->sample_rate = frequencies[header[1] >> 4 & 3];
90 
91  /* get the number of channels */
92  avctx->channels = 1 + (header[1] & 7);
93  /* calculate the bitrate */
94  avctx->bit_rate = avctx->channels *
95  avctx->sample_rate *
96  avctx->bits_per_coded_sample;
97 
98  /* 4 samples form a group in 20/24-bit PCM on DVD Video.
99  * A block is formed by the number of groups that are
100  * needed to complete a set of samples for each channel. */
101  if (avctx->bits_per_coded_sample == 16) {
102  s->samples_per_block = 1;
103  s->block_size = avctx->channels * 2;
104  } else {
105  switch (avctx->channels) {
106  case 1:
107  case 2:
108  case 4:
109  /* one group has all the samples needed */
110  s->block_size = 4 * avctx->bits_per_coded_sample / 8;
111  s->samples_per_block = 4 / avctx->channels;
112  s->groups_per_block = 1;
113  break;
114  case 8:
115  /* two groups have all the samples needed */
116  s->block_size = 8 * avctx->bits_per_coded_sample / 8;
117  s->samples_per_block = 1;
118  s->groups_per_block = 2;
119  break;
120  default:
121  /* need avctx->channels groups */
122  s->block_size = 4 * avctx->channels *
123  avctx->bits_per_coded_sample / 8;
124  s->samples_per_block = 4;
125  s->groups_per_block = avctx->channels;
126  break;
127  }
128  }
129 
130  if (avctx->debug & FF_DEBUG_PICT_INFO)
131  ff_dlog(avctx,
132  "pcm_dvd_parse_header: %d channels, %d bits per sample, %d Hz, %"PRId64" bit/s\n",
133  avctx->channels, avctx->bits_per_coded_sample,
134  avctx->sample_rate, avctx->bit_rate);
135 
136  s->last_header = header_int;
137 
138  return 0;
139 }
140 
141 static void *pcm_dvd_decode_samples(AVCodecContext *avctx, const uint8_t *src,
142  void *dst, int blocks)
143 {
144  PCMDVDContext *s = avctx->priv_data;
145  int16_t *dst16 = dst;
146  int32_t *dst32 = dst;
147  GetByteContext gb;
148  int i;
149  uint8_t t;
150 
151  bytestream2_init(&gb, src, blocks * s->block_size);
152  switch (avctx->bits_per_coded_sample) {
153  case 16: {
154 #if HAVE_BIGENDIAN
155  bytestream2_get_buffer(&gb, dst16, blocks * s->block_size);
156  dst16 += blocks * s->block_size / 2;
157 #else
158  int samples = blocks * avctx->channels;
159  do {
160  *dst16++ = bytestream2_get_be16u(&gb);
161  } while (--samples);
162 #endif
163  return dst16;
164  }
165  case 20:
166  if (avctx->channels == 1) {
167  do {
168  for (i = 2; i; i--) {
169  dst32[0] = bytestream2_get_be16u(&gb) << 16;
170  dst32[1] = bytestream2_get_be16u(&gb) << 16;
171  t = bytestream2_get_byteu(&gb);
172  *dst32++ += (t & 0xf0) << 8;
173  *dst32++ += (t & 0x0f) << 12;
174  }
175  } while (--blocks);
176  } else {
177  do {
178  for (i = s->groups_per_block; i; i--) {
179  dst32[0] = bytestream2_get_be16u(&gb) << 16;
180  dst32[1] = bytestream2_get_be16u(&gb) << 16;
181  dst32[2] = bytestream2_get_be16u(&gb) << 16;
182  dst32[3] = bytestream2_get_be16u(&gb) << 16;
183  t = bytestream2_get_byteu(&gb);
184  *dst32++ += (t & 0xf0) << 8;
185  *dst32++ += (t & 0x0f) << 12;
186  t = bytestream2_get_byteu(&gb);
187  *dst32++ += (t & 0xf0) << 8;
188  *dst32++ += (t & 0x0f) << 12;
189  }
190  } while (--blocks);
191  }
192  return dst32;
193  case 24:
194  if (avctx->channels == 1) {
195  do {
196  for (i = 2; i; i--) {
197  dst32[0] = bytestream2_get_be16u(&gb) << 16;
198  dst32[1] = bytestream2_get_be16u(&gb) << 16;
199  *dst32++ += bytestream2_get_byteu(&gb) << 8;
200  *dst32++ += bytestream2_get_byteu(&gb) << 8;
201  }
202  } while (--blocks);
203  } else {
204  do {
205  for (i = s->groups_per_block; i; i--) {
206  dst32[0] = bytestream2_get_be16u(&gb) << 16;
207  dst32[1] = bytestream2_get_be16u(&gb) << 16;
208  dst32[2] = bytestream2_get_be16u(&gb) << 16;
209  dst32[3] = bytestream2_get_be16u(&gb) << 16;
210  *dst32++ += bytestream2_get_byteu(&gb) << 8;
211  *dst32++ += bytestream2_get_byteu(&gb) << 8;
212  *dst32++ += bytestream2_get_byteu(&gb) << 8;
213  *dst32++ += bytestream2_get_byteu(&gb) << 8;
214  }
215  } while (--blocks);
216  }
217  return dst32;
218  default:
219  return NULL;
220  }
221 }
222 
223 static int pcm_dvd_decode_frame(AVCodecContext *avctx, void *data,
224  int *got_frame_ptr, AVPacket *avpkt)
225 {
226  AVFrame *frame = data;
227  const uint8_t *src = avpkt->data;
228  int buf_size = avpkt->size;
229  PCMDVDContext *s = avctx->priv_data;
230  int retval;
231  int blocks;
232  void *dst;
233 
234  if (buf_size < 3) {
235  av_log(avctx, AV_LOG_ERROR, "PCM packet too small\n");
236  return AVERROR_INVALIDDATA;
237  }
238 
239  if ((retval = pcm_dvd_parse_header(avctx, src)))
240  return retval;
241  if (s->last_block_size && s->last_block_size != s->block_size) {
242  av_log(avctx, AV_LOG_WARNING, "block_size has changed %d != %d\n", s->last_block_size, s->block_size);
243  s->extra_sample_count = 0;
244  }
245  s->last_block_size = s->block_size;
246  src += 3;
247  buf_size -= 3;
248 
249  blocks = (buf_size + s->extra_sample_count) / s->block_size;
250 
251  /* get output buffer */
252  frame->nb_samples = blocks * s->samples_per_block;
253  if ((retval = ff_get_buffer(avctx, frame, 0)) < 0)
254  return retval;
255  dst = frame->data[0];
256 
257  /* consume leftover samples from last packet */
258  if (s->extra_sample_count) {
259  int missing_samples = s->block_size - s->extra_sample_count;
260  if (buf_size >= missing_samples) {
261  memcpy(s->extra_samples + s->extra_sample_count, src,
262  missing_samples);
263  dst = pcm_dvd_decode_samples(avctx, s->extra_samples, dst, 1);
264  src += missing_samples;
265  buf_size -= missing_samples;
266  s->extra_sample_count = 0;
267  blocks--;
268  } else {
269  /* new packet still doesn't have enough samples */
270  memcpy(s->extra_samples + s->extra_sample_count, src, buf_size);
271  s->extra_sample_count += buf_size;
272  return avpkt->size;
273  }
274  }
275 
276  /* decode remaining complete samples */
277  if (blocks) {
278  pcm_dvd_decode_samples(avctx, src, dst, blocks);
279  buf_size -= blocks * s->block_size;
280  }
281 
282  /* store leftover samples */
283  if (buf_size) {
284  src += blocks * s->block_size;
285  memcpy(s->extra_samples, src, buf_size);
286  s->extra_sample_count = buf_size;
287  }
288 
289  *got_frame_ptr = 1;
290 
291  return avpkt->size;
292 }
293 
295  .name = "pcm_dvd",
296  .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16|20|24-bit big-endian for DVD media"),
297  .type = AVMEDIA_TYPE_AUDIO,
298  .id = AV_CODEC_ID_PCM_DVD,
299  .priv_data_size = sizeof(PCMDVDContext),
302  .capabilities = AV_CODEC_CAP_CHANNEL_CONF |
304  .sample_fmts = (const enum AVSampleFormat[]) {
306  },
307  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
308 };
AVCodec
AVCodec.
Definition: codec.h:197
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
FF_CODEC_CAP_INIT_THREADSAFE
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
Definition: internal.h:41
init
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:31
AVCodecContext::sample_rate
int sample_rate
samples per second
Definition: avcodec.h:1196
GetByteContext
Definition: bytestream.h:33
sample_fmts
static enum AVSampleFormat sample_fmts[]
Definition: adpcmenc.c:925
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:369
ff_pcm_dvd_decoder
AVCodec ff_pcm_dvd_decoder
Definition: pcm-dvd.c:294
data
const char data[16]
Definition: mxf.c:142
PCMDVDContext::extra_samples
uint8_t extra_samples[8 *3 *4]
Definition: pcm-dvd.c:38
FF_DEBUG_PICT_INFO
#define FF_DEBUG_PICT_INFO
Definition: avcodec.h:1624
PCMDVDContext::block_size
int block_size
Definition: pcm-dvd.c:33
pcm_dvd_decode_frame
static int pcm_dvd_decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, AVPacket *avpkt)
Definition: pcm-dvd.c:223
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
av_cold
#define av_cold
Definition: attributes.h:90
PCMDVDContext::groups_per_block
int groups_per_block
Definition: pcm-dvd.c:36
decode
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:71
s
#define s(width, name)
Definition: cbs_vp9.c:257
PCMDVDContext
Definition: pcm-dvd.c:31
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
PCMDVDContext::last_header
uint32_t last_header
Definition: pcm-dvd.c:32
AVCodecContext::bits_per_raw_sample
int bits_per_raw_sample
Bits per sample/pixel of internal libavcodec pixel/sample format.
Definition: avcodec.h:1747
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
AV_CODEC_ID_PCM_DVD
@ AV_CODEC_ID_PCM_DVD
Definition: codec_id.h:332
int32_t
int32_t
Definition: audio_convert.c:194
if
if(ret)
Definition: filter_design.txt:179
NULL
#define NULL
Definition: coverity.c:32
AVCodecContext::bit_rate
int64_t bit_rate
the average bitrate
Definition: avcodec.h:586
pcm_dvd_decode_samples
static void * pcm_dvd_decode_samples(AVCodecContext *avctx, const uint8_t *src, void *dst, int blocks)
Definition: pcm-dvd.c:141
src
#define src
Definition: vp8dsp.c:255
PCMDVDContext::last_block_size
int last_block_size
Definition: pcm-dvd.c:34
bytestream2_get_buffer
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:267
PCMDVDContext::extra_sample_count
int extra_sample_count
Definition: pcm-dvd.c:37
AV_CODEC_CAP_CHANNEL_CONF
#define AV_CODEC_CAP_CHANNEL_CONF
Codec should fill in channel configuration and samplerate instead of container.
Definition: codec.h:104
ff_dlog
#define ff_dlog(a,...)
Definition: tableprint_vlc.h:29
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1900
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVPacket::size
int size
Definition: packet.h:370
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
AVCodecContext::sample_fmt
enum AVSampleFormat sample_fmt
audio sample format
Definition: avcodec.h:1204
AV_SAMPLE_FMT_NONE
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:59
header
static const uint8_t header[24]
Definition: sdr2.c:67
AVCodecContext::channels
int channels
number of audio channels
Definition: avcodec.h:1197
AVCodecContext::bits_per_coded_sample
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:1740
i
int i
Definition: input.c:407
AVSampleFormat
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:58
uint8_t
uint8_t
Definition: audio_convert.c:194
AV_SAMPLE_FMT_S16
@ AV_SAMPLE_FMT_S16
signed 16 bits
Definition: samplefmt.h:61
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:204
avcodec.h
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
AVCodecContext
main external API structure.
Definition: avcodec.h:536
pcm_dvd_parse_header
static int pcm_dvd_parse_header(AVCodecContext *avctx, const uint8_t *header)
Definition: pcm-dvd.c:52
samples
Filter the word “frame” indicates either a video frame or a group of audio samples
Definition: filter_design.txt:8
AVCodecContext::debug
int debug
debug
Definition: avcodec.h:1623
AVPacket
This structure stores compressed data.
Definition: packet.h:346
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:563
bytestream.h
pcm_dvd_decode_init
static av_cold int pcm_dvd_decode_init(AVCodecContext *avctx)
Definition: pcm-dvd.c:42
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
PCMDVDContext::samples_per_block
int samples_per_block
Definition: pcm-dvd.c:35
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
AV_SAMPLE_FMT_S32
@ AV_SAMPLE_FMT_S32
signed 32 bits
Definition: samplefmt.h:62