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 29typedef 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 36static 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 115static 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 177const 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