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 "decode.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  CODEC_LONG_NAME("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 };
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:1064
GetByteContext
Definition: bytestream.h:33
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
AVPacket::data
uint8_t * data
Definition: packet.h:491
FFCodec
Definition: codec_internal.h:127
AVChannelLayout::nb_channels
int nb_channels
Number of channels in this layout.
Definition: channel_layout.h:317
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:1389
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
PCMDVDContext::block_size
int block_size
Definition: pcm-dvd.c:34
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
AVCodecContext::ch_layout
AVChannelLayout ch_layout
Audio channel layout.
Definition: avcodec.h:2107
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:306
s
#define s(width, name)
Definition: cbs_vp9.c:198
PCMDVDContext
Definition: pcm-dvd.c:32
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
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:1517
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
channels
channels
Definition: aptx.h:31
decode.h
AV_CODEC_ID_PCM_DVD
@ AV_CODEC_ID_PCM_DVD
Definition: codec_id.h:349
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
frame
static AVFrame * frame
Definition: demux_decode.c:54
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:491
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
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_CODEC_CAP_CHANNEL_CONF
#define AV_CODEC_CAP_CHANNEL_CONF
Codec should fill in channel configuration and samplerate instead of container.
Definition: codec.h:106
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:1617
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:492
codec_internal.h
AVCodecContext::sample_fmt
enum AVSampleFormat sample_fmt
audio sample format
Definition: avcodec.h:1080
AV_SAMPLE_FMT_NONE
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:56
header
static const uint8_t header[24]
Definition: sdr2.c:67
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:972
AVCodecContext::bits_per_coded_sample
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:1510
AVFrame::nb_samples
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:420
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
AVSampleFormat
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:55
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:194
avcodec.h
AVCodecContext
main external API structure.
Definition: avcodec.h:441
pcm_dvd_parse_header
static int pcm_dvd_parse_header(AVCodecContext *avctx, const uint8_t *header)
Definition: pcm-dvd.c:53
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:640
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:1388
AVPacket
This structure stores compressed data.
Definition: packet.h:468
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:468
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