Line | Branch | Exec | Source |
---|---|---|---|
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) | ||
41 | } PCMDVDContext; | ||
42 | |||
43 | 24 | static av_cold int pcm_dvd_decode_init(AVCodecContext *avctx) | |
44 | { | ||
45 | 24 | PCMDVDContext *s = avctx->priv_data; | |
46 | |||
47 | /* Invalid header to force parsing of the first header */ | ||
48 | 24 | s->last_header = -1; | |
49 | |||
50 | 24 | return 0; | |
51 | } | ||
52 | |||
53 | 603 | 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 | 603 | PCMDVDContext *s = avctx->priv_data; | |
58 | 603 | 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 |
2/2✓ Branch 0 taken 579 times.
✓ Branch 1 taken 24 times.
|
603 | if (s->last_header == header_int) |
63 | 579 | return 0; | |
64 | 24 | s->last_header = -1; | |
65 | |||
66 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | 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 | 24 | s->extra_sample_count = 0; | |
77 | |||
78 | /* get the sample depth and derive the sample format from it */ | ||
79 | 24 | avctx->bits_per_coded_sample = 16 + (header[1] >> 6 & 3) * 4; | |
80 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | 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 | 48 | avctx->sample_fmt = avctx->bits_per_coded_sample == 16 ? AV_SAMPLE_FMT_S16 | |
87 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 10 times.
|
24 | : AV_SAMPLE_FMT_S32; |
88 | 24 | avctx->bits_per_raw_sample = avctx->bits_per_coded_sample; | |
89 | |||
90 | /* get the sample rate */ | ||
91 | 24 | avctx->sample_rate = frequencies[header[1] >> 4 & 3]; | |
92 | |||
93 | /* get the number of channels */ | ||
94 | 24 | channels = 1 + (header[1] & 7); | |
95 | |||
96 | 24 | av_channel_layout_uninit(&avctx->ch_layout); | |
97 | 24 | av_channel_layout_default(&avctx->ch_layout, channels); | |
98 | /* calculate the bitrate */ | ||
99 | 24 | avctx->bit_rate = channels * | |
100 | 24 | avctx->sample_rate * | |
101 | 24 | 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 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 10 times.
|
24 | if (avctx->bits_per_coded_sample == 16) { |
107 | 14 | s->samples_per_block = 1; | |
108 | 14 | s->block_size = channels * 2; | |
109 | } else { | ||
110 |
3/3✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
10 | switch (channels) { |
111 | 6 | case 1: | |
112 | case 2: | ||
113 | case 4: | ||
114 | /* one group has all the samples needed */ | ||
115 | 6 | s->block_size = 4 * avctx->bits_per_coded_sample / 8; | |
116 | 6 | s->samples_per_block = 4 / channels; | |
117 | 6 | s->groups_per_block = 1; | |
118 | 6 | break; | |
119 | 2 | case 8: | |
120 | /* two groups have all the samples needed */ | ||
121 | 2 | s->block_size = 8 * avctx->bits_per_coded_sample / 8; | |
122 | 2 | s->samples_per_block = 1; | |
123 | 2 | s->groups_per_block = 2; | |
124 | 2 | break; | |
125 | 2 | default: | |
126 | /* need channels groups */ | ||
127 | 2 | s->block_size = 4 * channels * | |
128 | 2 | avctx->bits_per_coded_sample / 8; | |
129 | 2 | s->samples_per_block = 4; | |
130 | 2 | s->groups_per_block = channels; | |
131 | 2 | break; | |
132 | } | ||
133 | } | ||
134 | |||
135 | 24 | 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", | ||
138 | avctx->ch_layout.nb_channels, avctx->bits_per_coded_sample, | ||
139 | avctx->sample_rate, avctx->bit_rate); | ||
140 | |||
141 | 24 | s->last_header = header_int; | |
142 | |||
143 | 24 | return 0; | |
144 | } | ||
145 | |||
146 | 722 | static void *pcm_dvd_decode_samples(AVCodecContext *avctx, const uint8_t *src, | |
147 | void *dst, int blocks) | ||
148 | { | ||
149 | 722 | PCMDVDContext *s = avctx->priv_data; | |
150 | 722 | int16_t *dst16 = dst; | |
151 | 722 | int32_t *dst32 = dst; | |
152 | GetByteContext gb; | ||
153 | int i; | ||
154 | uint8_t t; | ||
155 | |||
156 | 722 | bytestream2_init(&gb, src, blocks * s->block_size); | |
157 |
2/4✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 493 times.
✗ Branch 3 not taken.
|
722 | switch (avctx->bits_per_coded_sample) { |
158 | 229 | case 16: { | |
159 | #if HAVE_BIGENDIAN | ||
160 | bytestream2_get_buffer(&gb, (uint8_t*)dst16, blocks * s->block_size); | ||
161 | dst16 += blocks * s->block_size / 2; | ||
162 | #else | ||
163 | 229 | int samples = blocks * avctx->ch_layout.nb_channels; | |
164 | do { | ||
165 | 228483 | *dst16++ = bytestream2_get_be16u(&gb); | |
166 |
2/2✓ Branch 0 taken 228254 times.
✓ Branch 1 taken 229 times.
|
228483 | } while (--samples); |
167 | #endif | ||
168 | 229 | 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 | 493 | case 24: | |
199 |
2/2✓ Branch 0 taken 84 times.
✓ Branch 1 taken 409 times.
|
493 | if (avctx->ch_layout.nb_channels == 1) { |
200 | do { | ||
201 |
2/2✓ Branch 0 taken 17612 times.
✓ Branch 1 taken 8806 times.
|
26418 | for (i = 2; i; i--) { |
202 | 17612 | dst32[0] = bytestream2_get_be16u(&gb) << 16; | |
203 | 17612 | dst32[1] = bytestream2_get_be16u(&gb) << 16; | |
204 | 17612 | *dst32++ += bytestream2_get_byteu(&gb) << 8; | |
205 | 17612 | *dst32++ += bytestream2_get_byteu(&gb) << 8; | |
206 | } | ||
207 |
2/2✓ Branch 0 taken 8722 times.
✓ Branch 1 taken 84 times.
|
8806 | } while (--blocks); |
208 | } else { | ||
209 | do { | ||
210 |
2/2✓ Branch 0 taken 53448 times.
✓ Branch 1 taken 34795 times.
|
88243 | for (i = s->groups_per_block; i; i--) { |
211 | 53448 | dst32[0] = bytestream2_get_be16u(&gb) << 16; | |
212 | 53448 | dst32[1] = bytestream2_get_be16u(&gb) << 16; | |
213 | 53448 | dst32[2] = bytestream2_get_be16u(&gb) << 16; | |
214 | 53448 | dst32[3] = bytestream2_get_be16u(&gb) << 16; | |
215 | 53448 | *dst32++ += bytestream2_get_byteu(&gb) << 8; | |
216 | 53448 | *dst32++ += bytestream2_get_byteu(&gb) << 8; | |
217 | 53448 | *dst32++ += bytestream2_get_byteu(&gb) << 8; | |
218 | 53448 | *dst32++ += bytestream2_get_byteu(&gb) << 8; | |
219 | } | ||
220 |
2/2✓ Branch 0 taken 34386 times.
✓ Branch 1 taken 409 times.
|
34795 | } while (--blocks); |
221 | } | ||
222 | 493 | return dst32; | |
223 | ✗ | default: | |
224 | ✗ | return NULL; | |
225 | } | ||
226 | } | ||
227 | |||
228 | 603 | static int pcm_dvd_decode_frame(AVCodecContext *avctx, AVFrame *frame, | |
229 | int *got_frame_ptr, AVPacket *avpkt) | ||
230 | { | ||
231 | 603 | const uint8_t *src = avpkt->data; | |
232 | 603 | int buf_size = avpkt->size; | |
233 | 603 | PCMDVDContext *s = avctx->priv_data; | |
234 | int retval; | ||
235 | int blocks; | ||
236 | void *dst; | ||
237 | |||
238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 603 times.
|
603 | if (buf_size < 3) { |
239 | ✗ | av_log(avctx, AV_LOG_ERROR, "PCM packet too small\n"); | |
240 | ✗ | return AVERROR_INVALIDDATA; | |
241 | } | ||
242 | |||
243 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 603 times.
|
603 | if ((retval = pcm_dvd_parse_header(avctx, src))) |
244 | ✗ | return retval; | |
245 |
3/4✓ Branch 0 taken 579 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 579 times.
|
603 | 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 | 603 | s->last_block_size = s->block_size; | |
250 | 603 | src += 3; | |
251 | 603 | buf_size -= 3; | |
252 | |||
253 | 603 | blocks = (buf_size + s->extra_sample_count) / s->block_size; | |
254 | |||
255 | /* get output buffer */ | ||
256 | 603 | frame->nb_samples = blocks * s->samples_per_block; | |
257 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 603 times.
|
603 | if ((retval = ff_get_buffer(avctx, frame, 0)) < 0) |
258 | ✗ | return retval; | |
259 | 603 | dst = frame->data[0]; | |
260 | |||
261 | /* consume leftover samples from last packet */ | ||
262 |
2/2✓ Branch 0 taken 119 times.
✓ Branch 1 taken 484 times.
|
603 | if (s->extra_sample_count) { |
263 | 119 | int missing_samples = s->block_size - s->extra_sample_count; | |
264 |
1/2✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
|
119 | if (buf_size >= missing_samples) { |
265 | 119 | memcpy(s->extra_samples + s->extra_sample_count, src, | |
266 | missing_samples); | ||
267 | 119 | dst = pcm_dvd_decode_samples(avctx, s->extra_samples, dst, 1); | |
268 | 119 | src += missing_samples; | |
269 | 119 | buf_size -= missing_samples; | |
270 | 119 | s->extra_sample_count = 0; | |
271 | 119 | 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 |
1/2✓ Branch 0 taken 603 times.
✗ Branch 1 not taken.
|
603 | if (blocks) { |
282 | 603 | pcm_dvd_decode_samples(avctx, src, dst, blocks); | |
283 | 603 | buf_size -= blocks * s->block_size; | |
284 | } | ||
285 | |||
286 | /* store leftover samples */ | ||
287 |
2/2✓ Branch 0 taken 122 times.
✓ Branch 1 taken 481 times.
|
603 | if (buf_size) { |
288 | 122 | src += blocks * s->block_size; | |
289 | 122 | memcpy(s->extra_samples, src, buf_size); | |
290 | 122 | s->extra_sample_count = buf_size; | |
291 | } | ||
292 | |||
293 | 603 | *got_frame_ptr = 1; | |
294 | |||
295 | 603 | return avpkt->size; | |
296 | } | ||
297 | |||
298 | const FFCodec ff_pcm_dvd_decoder = { | ||
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), | ||
304 | .init = pcm_dvd_decode_init, | ||
305 | FF_CODEC_DECODE_CB(pcm_dvd_decode_frame), | ||
306 | .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | | ||
307 | AV_CODEC_CAP_DR1, | ||
308 | .p.sample_fmts = (const enum AVSampleFormat[]) { | ||
309 | AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE | ||
310 | }, | ||
311 | }; | ||
312 |