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