[FFmpeg-devel] [GSoC] [PATCH 2/2] mlpenc: Working MLP/TrueHD encoder
Michael Niedermayer
michael at niedermayer.cc
Sun Aug 28 04:56:44 EEST 2016
On Tue, Aug 23, 2016 at 02:33:00AM +0530, Jai Luthra wrote:
> * Multichannel support for TrueHD is experimental
>
> There should be downmix substreams present for 2+ channel bitstreams,
> but ffmpeg decoder doesn't need it. Will add support for this soon.
>
> * There might be lossless check failures on LFE channels
>
> * 32-bit sample support has been removed for now, will add it later
>
> While testing, some samples gave lossless check failures when enforcing
> s32. Probably this will also get solved with other lossless issues.
>
> Signed-off-by: Jai Luthra <me at jailuthra.in>
> ---
> libavcodec/Makefile | 2 +
> libavcodec/allcodecs.c | 4 +-
> libavcodec/mlp.c | 21 +
> libavcodec/mlp.h | 40 +
> libavcodec/mlpenc.c | 2416 ++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 2481 insertions(+), 2 deletions(-)
> create mode 100644 libavcodec/mlpenc.c
[...]
> +static av_cold int mlp_encode_init(AVCodecContext *avctx)
> +{
> + MLPEncodeContext *ctx = avctx->priv_data;
> + unsigned int substr, index;
> + unsigned int sum = 0;
> + unsigned int size;
> +
> + ctx->avctx = avctx;
> +
> + switch (avctx->sample_rate) {
> + case 44100 << 0:
> + avctx->frame_size = 40 << 0;
> + ctx->coded_sample_rate[0] = 0x08 + 0;
> + ctx->fs = 0x08 + 1;
> + break;
> + case 44100 << 1:
> + avctx->frame_size = 40 << 1;
> + ctx->coded_sample_rate[0] = 0x08 + 1;
> + ctx->fs = 0x0C + 1;
> + break;
> + case 44100 << 2:
> + ctx->substream_info |= SUBSTREAM_INFO_HIGH_RATE;
> + avctx->frame_size = 40 << 2;
> + ctx->coded_sample_rate[0] = 0x08 + 2;
> + ctx->fs = 0x10 + 1;
> + break;
> + case 48000 << 0:
> + avctx->frame_size = 40 << 0;
> + ctx->coded_sample_rate[0] = 0x00 + 0;
> + ctx->fs = 0x08 + 2;
> + break;
> + case 48000 << 1:
> + avctx->frame_size = 40 << 1;
> + ctx->coded_sample_rate[0] = 0x00 + 1;
> + ctx->fs = 0x0C + 2;
> + break;
> + case 48000 << 2:
> + ctx->substream_info |= SUBSTREAM_INFO_HIGH_RATE;
> + avctx->frame_size = 40 << 2;
> + ctx->coded_sample_rate[0] = 0x00 + 2;
> + ctx->fs = 0x10 + 2;
> + break;
> + default:
> + av_log(avctx, AV_LOG_ERROR, "Unsupported sample rate %d. Supported "
> + "sample rates are 44100, 88200, 176400, 48000, "
> + "96000, and 192000.\n", avctx->sample_rate);
> + return -1;
> + }
> + ctx->coded_sample_rate[1] = -1 & 0xf;
> +
> + /* TODO Keep count of bitrate and calculate real value. */
> + ctx->coded_peak_bitrate = mlp_peak_bitrate(9600000, avctx->sample_rate);
> +
> + /* TODO support more channels. */
> + if (avctx->channels > 2) {
> + av_log(avctx, AV_LOG_WARNING,
> + "Only mono and stereo are supported at the moment.\n");
> + }
> +
> + ctx->substream_info |= SUBSTREAM_INFO_ALWAYS_SET;
> + if (avctx->channels <= 2) {
> + ctx->substream_info |= SUBSTREAM_INFO_MAX_2_CHAN;
> + }
> +
> + switch (avctx->sample_fmt) {
> + case AV_SAMPLE_FMT_S16:
> + ctx->coded_sample_fmt[0] = BITS_16;
> + ctx->wordlength = 16;
> + avctx->bits_per_raw_sample = 16;
> + break;
> + /* TODO 20 bits: */
> + case AV_SAMPLE_FMT_S32:
> + ctx->coded_sample_fmt[0] = BITS_24;
> + ctx->wordlength = 24;
> + avctx->bits_per_raw_sample = 24;
> + break;
> + default:
> + av_log(avctx, AV_LOG_ERROR, "Sample format not supported. "
> + "Only 16- and 24-bit samples are supported.\n");
> + return -1;
> + }
> + ctx->coded_sample_fmt[1] = -1 & 0xf;
> +
> + ctx->dts = -avctx->frame_size;
> +
> + ctx->num_channels = avctx->channels + 2; /* +2 noise channels */
> + ctx->one_sample_buffer_size = avctx->frame_size
> + * ctx->num_channels;
> + /* TODO Let user pass major header interval as parameter. */
> + ctx->max_restart_interval = MAJOR_HEADER_INTERVAL;
> +
> + ctx->max_codebook_search = 3;
> + ctx->min_restart_interval = MAJOR_HEADER_INTERVAL;
> + ctx->restart_intervals = ctx->max_restart_interval / ctx->min_restart_interval;
> +
> + /* TODO Let user pass parameters for LPC filter. */
> +
> + size = sizeof(int32_t) * avctx->frame_size * ctx->max_restart_interval;
> +
> + ctx->lpc_sample_buffer = av_malloc(size);
av_malloc_array()
> + if (!ctx->lpc_sample_buffer) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Not enough memory for buffering samples.\n");
> + return -1;
AVERROR(ENOMEM)
> + }
> +
> + size = sizeof(int32_t)
> + * ctx->one_sample_buffer_size * ctx->max_restart_interval;
> +
> + ctx->major_scratch_buffer = av_malloc(size);
> + if (!ctx->major_scratch_buffer) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Not enough memory for buffering samples.\n");
> + return -1;
> + }
> +
> + ctx->major_inout_buffer = av_malloc(size);
> + if (!ctx->major_inout_buffer) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Not enough memory for buffering samples.\n");
> + return -1;
> + }
> +
> + ff_mlp_init_crc();
> +
> + ctx->num_substreams = 1; // TODO: change this after adding multi-channel support for TrueHD
> +
> + if (ctx->avctx->codec_id == AV_CODEC_ID_MLP) {
> + /* MLP */
> + switch(avctx->channel_layout) {
> + case AV_CH_LAYOUT_MONO:
> + ctx->channel_arrangement = 0; break;
> + case AV_CH_LAYOUT_STEREO:
> + ctx->channel_arrangement = 1; break;
> + case AV_CH_LAYOUT_2_1:
> + ctx->channel_arrangement = 2; break;
> + case AV_CH_LAYOUT_QUAD:
> + ctx->channel_arrangement = 3; break;
> + case AV_CH_LAYOUT_2POINT1:
> + ctx->channel_arrangement = 4; break;
> + case AV_CH_LAYOUT_SURROUND:
> + ctx->channel_arrangement = 7; break;
> + case AV_CH_LAYOUT_4POINT0:
> + ctx->channel_arrangement = 8; break;
> + case AV_CH_LAYOUT_5POINT0_BACK:
> + ctx->channel_arrangement = 9; break;
> + case AV_CH_LAYOUT_3POINT1:
> + ctx->channel_arrangement = 10; break;
> + case AV_CH_LAYOUT_4POINT1:
> + ctx->channel_arrangement = 11; break;
> + case AV_CH_LAYOUT_5POINT1_BACK:
> + ctx->channel_arrangement = 12; break;
> + default:
> + av_log(avctx, AV_LOG_ERROR, "Unsupported channel arrangement\n");
> + return -1;
> + }
> + ctx->flags = FLAGS_DVDA;
> + ctx->channel_occupancy = ff_mlp_ch_info[ctx->channel_arrangement].channel_occupancy;
> + ctx->summary_info = ff_mlp_ch_info[ctx->channel_arrangement].summary_info ;
> + } else {
> + /* TrueHD */
> + switch(avctx->channel_layout) {
> + case AV_CH_LAYOUT_STEREO:
> + ctx->ch_modifier_thd0 = 0;
> + ctx->ch_modifier_thd1 = 0;
> + ctx->ch_modifier_thd2 = 0;
> + ctx->channel_arrangement = 1;
> + break;
> + case AV_CH_LAYOUT_5POINT0_BACK:
> + ctx->ch_modifier_thd0 = 1;
> + ctx->ch_modifier_thd1 = 1;
> + ctx->ch_modifier_thd2 = 1;
> + ctx->channel_arrangement = 11;
> + break;
> + case AV_CH_LAYOUT_5POINT1_BACK:
> + ctx->ch_modifier_thd0 = 2;
> + ctx->ch_modifier_thd1 = 1;
> + ctx->ch_modifier_thd2 = 2;
> + ctx->channel_arrangement = 15;
> + break;
> + default:
> + av_log(avctx, AV_LOG_ERROR, "Unsupported channel arrangement\n");
> + return -1;
> + }
> + ctx->flags = 0;
> + ctx->channel_occupancy = 0;
> + ctx->summary_info = 0;
> + }
> +
> + size = sizeof(unsigned int) * ctx->max_restart_interval;
> +
> + ctx->frame_size = av_malloc(size);
> + if (!ctx->frame_size)
> + return -1;
> +
> + ctx->max_output_bits = av_malloc(size);
> + if (!ctx->max_output_bits)
> + return -1;
> +
> + size = sizeof(int32_t)
> + * ctx->num_substreams * ctx->max_restart_interval;
> +
> + ctx->lossless_check_data = av_malloc(size);
> + if (!ctx->lossless_check_data)
> + return -1;
> +
> + for (index = 0; index < ctx->restart_intervals; index++) {
> + ctx->seq_offset[index] = sum;
> + ctx->seq_size [index] = ((index + 1) * ctx->min_restart_interval) + 1;
> + sum += ctx->seq_size[index];
> + }
> + ctx->sequence_size = sum;
> + size = sizeof(ChannelParams)
> + * ctx->restart_intervals * ctx->sequence_size * ctx->avctx->channels;
> + ctx->channel_params = av_malloc(size);
> + if (!ctx->channel_params) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Not enough memory for analysis context.\n");
> + return -1;
> + }
> +
> + size = sizeof(DecodingParams)
> + * ctx->restart_intervals * ctx->sequence_size * ctx->num_substreams;
> + ctx->decoding_params = av_malloc(size);
> + if (!ctx->decoding_params) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Not enough memory for analysis context.\n");
> + return -1;
> + }
> +
> + for (substr = 0; substr < ctx->num_substreams; substr++) {
> + RestartHeader *rh = &ctx->restart_header [substr];
> +
> + /* TODO see if noisegen_seed is really worth it. */
> + rh->noisegen_seed = 0;
> +
> + rh->min_channel = 0;
> + rh->max_channel = avctx->channels - 1;
> + /* FIXME: this works for 1 and 2 channels, but check for more */
> + rh->max_matrix_channel = rh->max_channel;
> + }
> +
> + clear_channel_params(ctx, restart_channel_params);
> + clear_decoding_params(ctx, restart_decoding_params);
> +
> + if (ff_lpc_init(&ctx->lpc_ctx, ctx->number_of_samples,
> + MLP_MAX_LPC_ORDER, FF_LPC_TYPE_LEVINSON) < 0) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Not enough memory for LPC context.\n");
> + return -1;
the error code from ff_lpc_init() should be returned
a fate test could also be added
no more comments from me
thx
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
If you think the mosad wants you dead since a long time then you are either
wrong or dead since a long time.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160828/e3fb621b/attachment.sig>
More information about the ffmpeg-devel
mailing list