[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