--- /dev/null 2021-12-05 17:02:04.576000000 +0300 +++ ./libavcodec/pcm-bluenc.c 2021-12-08 16:22:32.519865993 +0300 @@ -0,0 +1,332 @@ +/* + * LPCM codecs for PCM formats found in Blu-ray m2ts streams + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +typedef struct PCMBDContext { + uint8_t header[4]; // Header added to every frame + int block_size; // Size of a block of samples in bytes + int samples_per_block; // Number of samples per channel per block + int groups_per_block; // Number of 20/24-bit sample groups per block + uint8_t *extra_samples; // Pointer to leftover samples from a frame + int extra_sample_count; // Number of leftover samples in the buffer +} PCMBDContext; + +static av_cold int pcm_bd_encode_init(AVCodecContext *avctx) +{ + PCMBDContext *s = avctx->priv_data; + int quant, freq; + uint16_t frame_size; + uint8_t ch_layout = 0; + + switch (avctx->sample_rate) { + case 48000: + freq = 1; + break; + case 96000: + freq = 4; + break; + case 192000: + freq = 5; + break; + } + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16: + avctx->bits_per_coded_sample = 16; + quant = 1; + break; +/* case AV_SAMPLE_FMT_S20: + avctx->bits_per_coded_sample = 20; + quant = 2; + break; +*/ + case AV_SAMPLE_FMT_S32: + avctx->bits_per_coded_sample = 24; + quant = 3; + break; + } + + avctx->block_align = avctx->channels * avctx->bits_per_coded_sample / 8; + avctx->bit_rate = avctx->block_align * 8LL * avctx->sample_rate; + if (avctx->bit_rate > 19800000) { + av_log(avctx, AV_LOG_ERROR, "Too big bitrate: reduce sample rate, bitdepth or channels.\n"); + return AVERROR(EINVAL); + } + + if (avctx->sample_fmt == AV_SAMPLE_FMT_S16) { + switch (avctx->channels) { + case 1: + s->block_size = avctx->channels * 4; + break; + default: + s->block_size = avctx->channels * 2; + break; + } + s->samples_per_block = 1; + frame_size = 2008 / s->block_size; + } else { + switch (avctx->channels) { + case 1: + s->block_size = 2 * avctx->channels * avctx->bits_per_coded_sample / 8; + s->samples_per_block = 1; + break; + case 2: + case 4: + /* one group has all the samples needed */ + s->block_size = avctx->channels * avctx->bits_per_coded_sample / 8; + s->samples_per_block = 1; + s->groups_per_block = 2; + break; + case 8: + case 6: + /* two groups have all the samples needed */ + s->block_size = avctx->channels * avctx->bits_per_coded_sample / 8; + s->samples_per_block = 1; + // s->groups_per_block = 2; + break; + default: + /* need avctx->channels groups */ + s->block_size = 4 * avctx->channels * + avctx->bits_per_coded_sample / 8; + s->samples_per_block = 4; + s->groups_per_block = avctx->channels; + break; + } + + frame_size = FFALIGN(2008 / s->block_size, s->samples_per_block); + } + + switch(avctx->channel_layout) { + case AV_CH_LAYOUT_MONO: + ch_layout = 1; + break; + case AV_CH_LAYOUT_STEREO: + ch_layout = 3; + break; + case AV_CH_LAYOUT_5POINT1: + case AV_CH_LAYOUT_5POINT1_BACK: + ch_layout = 9; + break; + case AV_CH_LAYOUT_7POINT1: + ch_layout = 11; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Not yet implemented ch layout!\n"); + } +// description on the web: +/* http://forum.doom9.org/showthread.php?t=152897 + +It's a header. + +size in bytes = 16 bits (big endian) +channel assignment = 4 bits +sampling frequency = 4 bits +bits per sample = 2 bits +start flag = 1 bit +reserved = 5 bits + +channel assignment +1 = mono +3 = stereo +4 = 3/0 +5 = 2/1 +6 = 3/1 +7 = 2/2 +8 = 3/2 +9 = 3/2+lfe +10 = 3/4 +11 = 3/4+lfe + +sampling frequency +1 = 48 kHz +4 = 96 kHz +5 = 192 kHz + +bits per sample +1 = 16 +2 = 20 +3 = 24 +*/ + + s->header[2] = (ch_layout << 4) | (freq); + s->header[3] = (quant << 6) | 0x1 ; + + + avctx->frame_size = frame_size; // in num. of samples + + return 0; +} + +static int pcm_bd_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + PCMBDContext *s = avctx->priv_data; + int samples, channels; + int64_t pkt_size = (frame->nb_samples / s->samples_per_block) * s->block_size + 4; + const int16_t *src16; + const int32_t *src32; + PutByteContext pb; + int ret; + + if ((ret = ff_alloc_packet2(avctx, avpkt, pkt_size, 0)) < 0) + return ret; + + AV_WB16(s->header, pkt_size - 4); + memcpy(avpkt->data, s->header, 4); + + src16 = (const int16_t *)frame->data[0]; + src32 = (const int32_t *)frame->data[0]; + + bytestream2_init_writer(&pb, avpkt->data + 4, avpkt->size - 4); + + int num_source_channels = FFALIGN(avctx->channels, 2); + // int num_source_channels = avctx->channels; + // int sample_size = (num_source_channels * + // (avctx->sample_fmt == AV_SAMPLE_FMT_S16 ? 16 : 24)) >> 3; + samples = frame->nb_samples * num_source_channels; + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16: + switch (avctx->channels) { + case 1: + do { + do { + channels = avctx->channels; + bytestream2_put_be16(&pb, *src16++); + } while (--channels); + bytestream2_put_be16(&pb, 0); + } while (--samples); + break; + case 2: + do { + bytestream2_put_be16(&pb, *src16++); + } while (--samples); + break; + case 6: + do { + bytestream2_put_be16(&pb, src16[0]); + bytestream2_put_be16(&pb, src16[1]); + bytestream2_put_be16(&pb, src16[2]); + bytestream2_put_be16(&pb, src16[4]); + bytestream2_put_be16(&pb, src16[5]); + bytestream2_put_be16(&pb, src16[3]); + src16+=6; + } while (--samples); + break; + case 8: + do { + bytestream2_put_be16(&pb, src16[0]); + bytestream2_put_be16(&pb, src16[1]); + bytestream2_put_be16(&pb, src16[2]); + bytestream2_put_be16(&pb, src16[6]); + bytestream2_put_be16(&pb, src16[4]); + bytestream2_put_be16(&pb, src16[5]); + bytestream2_put_be16(&pb, src16[7]); + bytestream2_put_be16(&pb, src16[3]); + src16+=8; + } while (--samples); + break; + + default: + av_log(avctx, AV_LOG_ERROR, "this ch config not implemented for s16!\n"); + break; + } + break; + case AV_SAMPLE_FMT_S32: + switch (avctx->channels) { + case 2: + case 4: + do { + bytestream2_put_be24(&pb, (*src32++) >> 8); + } while (--samples); + break; + case 8: + do { + bytestream2_put_be24(&pb, src32[0] >> 8); + bytestream2_put_be24(&pb, src32[1] >> 8); + bytestream2_put_be24(&pb, src32[2] >> 8); + bytestream2_put_be24(&pb, src32[6] >> 8); + bytestream2_put_be24(&pb, src32[4] >> 8); + bytestream2_put_be24(&pb, src32[5] >> 8); + bytestream2_put_be24(&pb, src32[7] >> 8); + bytestream2_put_be24(&pb, src32[3] >> 8); + src32+=8; + } while (--samples); + break; + case 6: + do { + bytestream2_put_be24(&pb, src32[0] >> 8); + bytestream2_put_be24(&pb, src32[1] >> 8); + bytestream2_put_be24(&pb, src32[2] >> 8); + bytestream2_put_be24(&pb, src32[4] >> 8); + bytestream2_put_be24(&pb, src32[5] >> 8); + bytestream2_put_be24(&pb, src32[3] >> 8); + src32+=6; + } while (--samples); + break; + case 1: + do { + do { + channels = avctx->channels; + bytestream2_put_be24(&pb, (*src32++) >> 8); + } while (--channels); + bytestream2_put_be24(&pb, 0); + } while (--samples); + break; + default: + av_log(avctx, AV_LOG_ERROR, "this bitdepth not implemented!\n"); + break; + } + break; + } + + avpkt->pts = frame->pts; + avpkt->size = pkt_size; + avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples); + *got_packet_ptr = 1; + + return 0; +} + +AVCodec ff_pcm_bluray_encoder = { + .name = "pcm_bluray", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16|24-bit big-endian for bluray media"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_PCM_BLURAY, + .priv_data_size = sizeof(PCMBDContext), + .init = pcm_bd_encode_init, + .encode2 = pcm_bd_encode_frame, + .capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME, + .supported_samplerates = (const int[]) { 48000, 96000, 192000, 0}, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_5POINT1, + AV_CH_LAYOUT_5POINT1_BACK, + AV_CH_LAYOUT_7POINT1, + 0 }, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_S32, + AV_SAMPLE_FMT_NONE }, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, +}; --- ./libavcodec/allcodecs.orig 2021-04-09 00:28:39.000000000 +0300 +++ ./libavcodec/allcodecs.c 2021-12-06 15:45:03.333762281 +0300 @@ -523,6 +523,7 @@ /* PCM codecs */ extern AVCodec ff_pcm_alaw_encoder; extern AVCodec ff_pcm_alaw_decoder; +extern AVCodec ff_pcm_bluray_encoder; extern AVCodec ff_pcm_bluray_decoder; extern AVCodec ff_pcm_dvd_encoder; extern AVCodec ff_pcm_dvd_decoder; --- ./libavcodec/Makefile.orig 2021-04-09 00:28:39.000000000 +0300 +++ ./libavcodec/Makefile 2021-12-06 21:11:19.365842066 +0300 @@ -789,6 +789,7 @@ OBJS-$(CONFIG_PCM_ALAW_DECODER) += pcm.o OBJS-$(CONFIG_PCM_ALAW_ENCODER) += pcm.o OBJS-$(CONFIG_PCM_BLURAY_DECODER) += pcm-bluray.o +OBJS-$(CONFIG_PCM_BLURAY_ENCODER) += pcm-bluenc.o OBJS-$(CONFIG_PCM_DVD_DECODER) += pcm-dvd.o OBJS-$(CONFIG_PCM_DVD_ENCODER) += pcm-dvdenc.o OBJS-$(CONFIG_PCM_F16LE_DECODER) += pcm.o