--- /dev/null
+--- /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