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 "codec_internal.h"
30 #include "internal.h"
31 
32 typedef struct PCMDVDContext {
33  uint32_t last_header; // Cached header to see if parsing is needed
34  int block_size; // Size of a block of samples in bytes
35  int last_block_size; // Size of the last block of samples in bytes
36  int samples_per_block; // Number of samples per channel per block
37  int groups_per_block; // Number of 20/24-bit sample groups per block
38  int extra_sample_count; // Number of leftover samples in the buffer
39  uint8_t extra_samples[8 * 3 * 4]; // Space for leftover samples from a frame
40  // (8 channels, 3B/sample, 4 samples/block)
42 
44 {
45  PCMDVDContext *s = avctx->priv_data;
46 
47  /* Invalid header to force parsing of the first header */
48  s->last_header = -1;
49 
50  return 0;
51 }
52 
53 static int pcm_dvd_parse_header(AVCodecContext *avctx, const uint8_t *header)
54 {
55  /* no traces of 44100 and 32000Hz in any commercial software or player */
56  static const uint32_t frequencies[4] = { 48000, 96000, 44100, 32000 };
57  PCMDVDContext *s = avctx->priv_data;
58  int header_int = (header[0] & 0xe0) | (header[1] << 8) | (header[2] << 16);
59  int channels;
60 
61  /* early exit if the header didn't change apart from the frame number */
62  if (s->last_header == header_int)
63  return 0;
64  s->last_header = -1;
65 
66  if (avctx->debug & FF_DEBUG_PICT_INFO)
67  av_log(avctx, AV_LOG_DEBUG, "pcm_dvd_parse_header: header = %02x%02x%02x\n",
68  header[0], header[1], header[2]);
69  /*
70  * header[0] emphasis (1), muse(1), reserved(1), frame number(5)
71  * header[1] quant (2), freq(2), reserved(1), channels(3)
72  * header[2] dynamic range control (0x80 = off)
73  */
74 
75  /* Discard potentially existing leftover samples from old channel layout */
76  s->extra_sample_count = 0;
77 
78  /* get the sample depth and derive the sample format from it */
79  avctx->bits_per_coded_sample = 16 + (header[1] >> 6 & 3) * 4;
80  if (avctx->bits_per_coded_sample == 28) {
81  av_log(avctx, AV_LOG_ERROR,
82  "PCM DVD unsupported sample depth %i\n",
83  avctx->bits_per_coded_sample);
84  return AVERROR_INVALIDDATA;
85  }
86  avctx->sample_fmt = avctx->bits_per_coded_sample == 16 ? AV_SAMPLE_FMT_S16
89 
90  /* get the sample rate */
91  avctx->sample_rate = frequencies[header[1] >> 4 & 3];
92 
93  /* get the number of channels */
94  channels = 1 + (header[1] & 7);
95 
98  /* calculate the bitrate */
99  avctx->bit_rate = channels *
100  avctx->sample_rate *
101  avctx->bits_per_coded_sample;
102 
103  /* 4 samples form a group in 20/24-bit PCM on DVD Video.
104  * A block is formed by the number of groups that are
105  * needed to complete a set of samples for each channel. */
106  if (avctx->bits_per_coded_sample == 16) {
107  s->samples_per_block = 1;
108  s->block_size = channels * 2;
109  } else {
110  switch (channels) {
111  case 1:
112  case 2:
113  case 4:
114  /* one group has all the samples needed */
115  s->block_size = 4 * avctx->bits_per_coded_sample / 8;
116  s->samples_per_block = 4 / channels;
117  s->groups_per_block = 1;
118  break;
119  case 8:
120  /* two groups have all the samples needed */
121  s->block_size = 8 * avctx->bits_per_coded_sample / 8;
122  s->samples_per_block = 1;
123  s->groups_per_block = 2;
124  break;
125  default:
126  /* need channels groups */
127  s->block_size = 4 * channels *
128  avctx->bits_per_coded_sample / 8;
129  s->samples_per_block = 4;
130  s->groups_per_block = channels;
131  break;
132  }
133  }
134 
135  if (avctx->debug & FF_DEBUG_PICT_INFO)
136  ff_dlog(avctx,
137  "pcm_dvd_parse_header: %d channels, %d bits per sample, %d Hz, %"PRId64" bit/s\n",
139  avctx->sample_rate, avctx->bit_rate);
140 
141  s->last_header = header_int;
142 
143  return 0;
144 }
145 
146 static void *pcm_dvd_decode_samples(AVCodecContext *avctx, const uint8_t *src,
147  void *dst, int blocks)
148 {
149  PCMDVDContext *s = avctx->priv_data;
150  int16_t *dst16 = dst;
151  int32_t *dst32 = dst;
152  GetByteContext gb;
153  int i;
154  uint8_t t;
155 
156  bytestream2_init(&gb, src, blocks * s->block_size);
157  switch (avctx->bits_per_coded_sample) {
158  case 16: {
159 #if HAVE_BIGENDIAN
160  bytestream2_get_buffer(&gb, dst16, blocks * s->block_size);
161  dst16 += blocks * s->block_size / 2;
162 #else
163  int samples = blocks * avctx->ch_layout.nb_channels;
164  do {
165  *dst16++ = bytestream2_get_be16u(&gb);
166  } while (--samples);
167 #endif
168  return dst16;
169  }
170  case 20:
171  if (avctx->ch_layout.nb_channels == 1) {
172  do {
173  for (i = 2; i; i--) {
174  dst32[0] = bytestream2_get_be16u(&gb) << 16;
175  dst32[1] = bytestream2_get_be16u(&gb) << 16;
176  t = bytestream2_get_byteu(&gb);
177  *dst32++ += (t & 0xf0) << 8;
178  *dst32++ += (t & 0x0f) << 12;
179  }
180  } while (--blocks);
181  } else {
182  do {
183  for (i = s->groups_per_block; i; i--) {
184  dst32[0] = bytestream2_get_be16u(&gb) << 16;
185  dst32[1] = bytestream2_get_be16u(&gb) << 16;
186  dst32[2] = bytestream2_get_be16u(&gb) << 16;
187  dst32[3] = bytestream2_get_be16u(&gb) << 16;
188  t = bytestream2_get_byteu(&gb);
189  *dst32++ += (t & 0xf0) << 8;
190  *dst32++ += (t & 0x0f) << 12;
191  t = bytestream2_get_byteu(&gb);
192  *dst32++ += (t & 0xf0) << 8;
193  *dst32++ += (t & 0x0f) << 12;
194  }
195  } while (--blocks);
196  }
197  return dst32;
198  case 24:
199  if (avctx->ch_layout.nb_channels == 1) {
200  do {
201  for (i = 2; i; i--) {
202  dst32[0] = bytestream2_get_be16u(&gb) << 16;
203  dst32[1] = bytestream2_get_be16u(&gb) << 16;
204  *dst32++ += bytestream2_get_byteu(&gb) << 8;
205  *dst32++ += bytestream2_get_byteu(&gb) << 8;
206  }
207  } while (--blocks);
208  } else {
209  do {
210  for (i = s->groups_per_block; i; i--) {
211  dst32[0] = bytestream2_get_be16u(&gb) << 16;
212  dst32[1] = bytestream2_get_be16u(&gb) << 16;
213  dst32[2] = bytestream2_get_be16u(&gb) << 16;
214  dst32[3] = bytestream2_get_be16u(&gb) << 16;
215  *dst32++ += bytestream2_get_byteu(&gb) << 8;
216  *dst32++ += bytestream2_get_byteu(&gb) << 8;
217  *dst32++ += bytestream2_get_byteu(&gb) << 8;
218  *dst32++ += bytestream2_get_byteu(&gb) << 8;
219  }
220  } while (--blocks);
221  }
222  return dst32;
223  default:
224  return NULL;
225  }
226 }
227 
229  int *got_frame_ptr, AVPacket *avpkt)
230 {
231  const uint8_t *src = avpkt->data;
232  int buf_size = avpkt->size;
233  PCMDVDContext *s = avctx->priv_data;
234  int retval;
235  int blocks;
236  void *dst;
237 
238  if (buf_size < 3) {
239  av_log(avctx, AV_LOG_ERROR, "PCM packet too small\n");
240  return AVERROR_INVALIDDATA;
241  }
242 
243  if ((retval = pcm_dvd_parse_header(avctx, src)))
244  return retval;
245  if (s->last_block_size && s->last_block_size != s->block_size) {
246  av_log(avctx, AV_LOG_WARNING, "block_size has changed %d != %d\n", s->last_block_size, s->block_size);
247  s->extra_sample_count = 0;
248  }
249  s->last_block_size = s->block_size;
250  src += 3;
251  buf_size -= 3;
252 
253  blocks = (buf_size + s->extra_sample_count) / s->block_size;
254 
255  /* get output buffer */
256  frame->nb_samples = blocks * s->samples_per_block;
257  if ((retval = ff_get_buffer(avctx, frame, 0)) < 0)
258  return retval;
259  dst = frame->data[0];
260 
261  /* consume leftover samples from last packet */
262  if (s->extra_sample_count) {
263  int missing_samples = s->block_size - s->extra_sample_count;
264  if (buf_size >= missing_samples) {
265  memcpy(s->extra_samples + s->extra_sample_count, src,
266  missing_samples);
267  dst = pcm_dvd_decode_samples(avctx, s->extra_samples, dst, 1);
268  src += missing_samples;
269  buf_size -= missing_samples;
270  s->extra_sample_count = 0;
271  blocks--;
272  } else {
273  /* new packet still doesn't have enough samples */
274  memcpy(s->extra_samples + s->extra_sample_count, src, buf_size);
275  s->extra_sample_count += buf_size;
276  return avpkt->size;
277  }
278  }
279 
280  /* decode remaining complete samples */
281  if (blocks) {
282  pcm_dvd_decode_samples(avctx, src, dst, blocks);
283  buf_size -= blocks * s->block_size;
284  }
285 
286  /* store leftover samples */
287  if (buf_size) {
288  src += blocks * s->block_size;
289  memcpy(s->extra_samples, src, buf_size);
290  s->extra_sample_count = buf_size;
291  }
292 
293  *got_frame_ptr = 1;
294 
295  return avpkt->size;
296 }
297 
299  .p.name = "pcm_dvd",
300  .p.long_name = NULL_IF_CONFIG_SMALL("PCM signed 16|20|24-bit big-endian for DVD media"),
301  .p.type = AVMEDIA_TYPE_AUDIO,
302  .p.id = AV_CODEC_ID_PCM_DVD,
303  .priv_data_size = sizeof(PCMDVDContext),
306  .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF |
308  .p.sample_fmts = (const enum AVSampleFormat[]) {
310  },
311  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
312 };
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVCodecContext::sample_rate
int sample_rate
samples per second
Definition: avcodec.h:998
GetByteContext
Definition: bytestream.h:33
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:374
FFCodec
Definition: codec_internal.h:112
AVChannelLayout::nb_channels
int nb_channels
Number of channels in this layout.
Definition: channel_layout.h:300
PCMDVDContext::extra_samples
uint8_t extra_samples[8 *3 *4]
Definition: pcm-dvd.c:39
FF_DEBUG_PICT_INFO
#define FF_DEBUG_PICT_INFO
Definition: avcodec.h:1323
init
static int init
Definition: av_tx.c:47
PCMDVDContext::block_size
int block_size
Definition: pcm-dvd.c:34
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:116
AVCodecContext::ch_layout
AVChannelLayout ch_layout
Audio channel layout.
Definition: avcodec.h:2056
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
PCMDVDContext::groups_per_block
int groups_per_block
Definition: pcm-dvd.c:37
pcm_dvd_decode_frame
static int pcm_dvd_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt)
Definition: pcm-dvd.c:228
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:254
s
#define s(width, name)
Definition: cbs_vp9.c:256
PCMDVDContext
Definition: pcm-dvd.c:32
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
PCMDVDContext::last_header
uint32_t last_header
Definition: pcm-dvd.c:33
AVCodecContext::bits_per_raw_sample
int bits_per_raw_sample
Bits per sample/pixel of internal libavcodec pixel/sample format.
Definition: avcodec.h:1448
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
channels
channels
Definition: aptx.h:32
AV_CODEC_ID_PCM_DVD
@ AV_CODEC_ID_PCM_DVD
Definition: codec_id.h:337
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:439
pcm_dvd_decode_samples
static void * pcm_dvd_decode_samples(AVCodecContext *avctx, const uint8_t *src, void *dst, int blocks)
Definition: pcm-dvd.c:146
PCMDVDContext::last_block_size
int last_block_size
Definition: pcm-dvd.c:35
bytestream2_get_buffer
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:267
av_channel_layout_default
void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
Get the default channel layout for a given number of channels.
Definition: channel_layout.c:960
PCMDVDContext::extra_sample_count
int extra_sample_count
Definition: pcm-dvd.c:38
ff_pcm_dvd_decoder
const FFCodec ff_pcm_dvd_decoder
Definition: pcm-dvd.c:298
av_channel_layout_uninit
void av_channel_layout_uninit(AVChannelLayout *channel_layout)
Free any allocated data in the channel layout and reset the channel count to 0.
Definition: channel_layout.c:630
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:109
ff_dlog
#define ff_dlog(a,...)
Definition: tableprint_vlc.h:28
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1403
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:375
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
codec_internal.h
AVCodecContext::sample_fmt
enum AVSampleFormat sample_fmt
audio sample format
Definition: avcodec.h:1014
AV_SAMPLE_FMT_NONE
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:56
header
static const uint8_t header[24]
Definition: sdr2.c:67
AVCodecContext::bits_per_coded_sample
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:1441
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
AVSampleFormat
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:55
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: codec_internal.h:31
AV_SAMPLE_FMT_S16
@ AV_SAMPLE_FMT_S16
signed 16 bits
Definition: samplefmt.h:58
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:203
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:389
pcm_dvd_parse_header
static int pcm_dvd_parse_header(AVCodecContext *avctx, const uint8_t *header)
Definition: pcm-dvd.c:53
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:1322
AVPacket
This structure stores compressed data.
Definition: packet.h:351
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:416
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
int32_t
int32_t
Definition: audioconvert.c:56
bytestream.h
pcm_dvd_decode_init
static av_cold int pcm_dvd_decode_init(AVCodecContext *avctx)
Definition: pcm-dvd.c:43
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:36
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
AV_SAMPLE_FMT_S32
@ AV_SAMPLE_FMT_S32
signed 32 bits
Definition: samplefmt.h:59