FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/pcm-dvdenc.c
Date: 2021-09-24 20:55:06
Exec Total Coverage
Lines: 0 91 0.0%
Branches: 0 32 0.0%

Line Branch Exec Source
1 /*
2 * LPCM codecs for PCM formats found in Video DVD streams
3 * Copyright (c) 2018 Paul B Mahol
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 #include "libavutil/channel_layout.h"
23 #include "avcodec.h"
24 #include "bytestream.h"
25 #include "encode.h"
26 #include "internal.h"
27
28 typedef struct PCMDVDContext {
29 uint8_t header[3]; // Header added to every frame
30 int block_size; // Size of a block of samples in bytes
31 int samples_per_block; // Number of samples per channel per block
32 int groups_per_block; // Number of 20/24-bit sample groups per block
33 uint8_t *extra_samples; // Pointer to leftover samples from a frame
34 int extra_sample_count; // Number of leftover samples in the buffer
35 } PCMDVDContext;
36
37 static av_cold int pcm_dvd_encode_init(AVCodecContext *avctx)
38 {
39 PCMDVDContext *s = avctx->priv_data;
40 int quant, freq, frame_size;
41
42 switch (avctx->sample_rate) {
43 case 48000:
44 freq = 0;
45 break;
46 case 96000:
47 freq = 1;
48 break;
49 }
50
51 switch (avctx->sample_fmt) {
52 case AV_SAMPLE_FMT_S16:
53 avctx->bits_per_coded_sample = 16;
54 quant = 0;
55 break;
56 case AV_SAMPLE_FMT_S32:
57 avctx->bits_per_coded_sample = 24;
58 quant = 2;
59 break;
60 }
61
62 avctx->bits_per_coded_sample = 16 + quant * 4;
63 avctx->block_align = avctx->channels * avctx->bits_per_coded_sample / 8;
64 avctx->bit_rate = avctx->block_align * 8LL * avctx->sample_rate;
65 if (avctx->bit_rate > 9800000) {
66 av_log(avctx, AV_LOG_ERROR, "Too big bitrate: reduce sample rate, bitdepth or channels.\n");
67 return AVERROR(EINVAL);
68 }
69
70 if (avctx->sample_fmt == AV_SAMPLE_FMT_S16) {
71 s->samples_per_block = 1;
72 s->block_size = avctx->channels * 2;
73 frame_size = 2008 / s->block_size;
74 } else {
75 switch (avctx->channels) {
76 case 1:
77 case 2:
78 case 4:
79 /* one group has all the samples needed */
80 s->block_size = 4 * avctx->bits_per_coded_sample / 8;
81 s->samples_per_block = 4 / avctx->channels;
82 s->groups_per_block = 1;
83 break;
84 case 8:
85 /* two groups have all the samples needed */
86 s->block_size = 8 * avctx->bits_per_coded_sample / 8;
87 s->samples_per_block = 1;
88 s->groups_per_block = 2;
89 break;
90 default:
91 /* need avctx->channels groups */
92 s->block_size = 4 * avctx->channels *
93 avctx->bits_per_coded_sample / 8;
94 s->samples_per_block = 4;
95 s->groups_per_block = avctx->channels;
96 break;
97 }
98
99 frame_size = FFALIGN(2008 / s->block_size, s->samples_per_block);
100 }
101
102 s->header[0] = 0x0c;
103 s->header[1] = (quant << 6) | (freq << 4) | (avctx->channels - 1);
104 s->header[2] = 0x80;
105
106 if (!avctx->frame_size)
107 avctx->frame_size = frame_size;
108
109 return 0;
110 }
111
112 static int pcm_dvd_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
113 const AVFrame *frame, int *got_packet_ptr)
114 {
115 PCMDVDContext *s = avctx->priv_data;
116 int samples = frame->nb_samples * avctx->channels;
117 int64_t pkt_size = (frame->nb_samples / s->samples_per_block) * s->block_size + 3;
118 int blocks = (pkt_size - 3) / s->block_size;
119 const int16_t *src16;
120 const int32_t *src32;
121 PutByteContext pb;
122 int ret;
123
124 if ((ret = ff_get_encode_buffer(avctx, avpkt, pkt_size, 0)) < 0)
125 return ret;
126
127 memcpy(avpkt->data, s->header, 3);
128
129 src16 = (const int16_t *)frame->data[0];
130 src32 = (const int32_t *)frame->data[0];
131
132 bytestream2_init_writer(&pb, avpkt->data + 3, avpkt->size - 3);
133
134 switch (avctx->sample_fmt) {
135 case AV_SAMPLE_FMT_S16:
136 do {
137 bytestream2_put_be16(&pb, *src16++);
138 } while (--samples);
139 break;
140 case AV_SAMPLE_FMT_S32:
141 if (avctx->channels == 1) {
142 do {
143 for (int i = 2; i; i--) {
144 bytestream2_put_be16(&pb, src32[0] >> 16);
145 bytestream2_put_be16(&pb, src32[1] >> 16);
146 bytestream2_put_byte(&pb, (*src32++) >> 24);
147 bytestream2_put_byte(&pb, (*src32++) >> 24);
148 }
149 } while (--blocks);
150 } else {
151 do {
152 for (int i = s->groups_per_block; i; i--) {
153 bytestream2_put_be16(&pb, src32[0] >> 16);
154 bytestream2_put_be16(&pb, src32[1] >> 16);
155 bytestream2_put_be16(&pb, src32[2] >> 16);
156 bytestream2_put_be16(&pb, src32[3] >> 16);
157 bytestream2_put_byte(&pb, (*src32++) >> 24);
158 bytestream2_put_byte(&pb, (*src32++) >> 24);
159 bytestream2_put_byte(&pb, (*src32++) >> 24);
160 bytestream2_put_byte(&pb, (*src32++) >> 24);
161 }
162 } while (--blocks);
163 }
164 break;
165 }
166
167 avpkt->pts = frame->pts;
168 avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples);
169 *got_packet_ptr = 1;
170
171 return 0;
172 }
173
174 const AVCodec ff_pcm_dvd_encoder = {
175 .name = "pcm_dvd",
176 .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16|20|24-bit big-endian for DVD media"),
177 .type = AVMEDIA_TYPE_AUDIO,
178 .id = AV_CODEC_ID_PCM_DVD,
179 .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SMALL_LAST_FRAME,
180 .priv_data_size = sizeof(PCMDVDContext),
181 .init = pcm_dvd_encode_init,
182 .encode2 = pcm_dvd_encode_frame,
183 .supported_samplerates = (const int[]) { 48000, 96000, 0},
184 .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO,
185 AV_CH_LAYOUT_STEREO,
186 AV_CH_LAYOUT_5POINT1,
187 AV_CH_LAYOUT_7POINT1,
188 0 },
189 .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
190 AV_SAMPLE_FMT_S32,
191 AV_SAMPLE_FMT_NONE },
192 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
193 };
194