From patchwork Sun Oct 2 07:46:33 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Burt P X-Patchwork-Id: 826 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.140.66 with SMTP id o63csp1042591vsd; Sun, 2 Oct 2016 01:01:49 -0700 (PDT) X-Received: by 10.194.87.197 with SMTP id ba5mr13009441wjb.69.1475395309600; Sun, 02 Oct 2016 01:01:49 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id uf1si29293750wjc.223.2016.10.02.01.01.47; Sun, 02 Oct 2016 01:01:49 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4FC6468A0F0; Sun, 2 Oct 2016 11:01:32 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-it0-f66.google.com (mail-it0-f66.google.com [209.85.214.66]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 6B07E68A0C3 for ; Sun, 2 Oct 2016 11:01:25 +0300 (EEST) Received: by mail-it0-f66.google.com with SMTP id 184so4555624ity.0 for ; Sun, 02 Oct 2016 01:01:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id:in-reply-to:references; bh=/BqdExWyx9Bl0S67ay6eLPSQ3j9ULOrwLRuR5UXqQJg=; b=lLbIeD9YLyEKAC2zPW7xnG7092PC9pMu51kUj+/IRzOxsJfYD5EQTldwtDDWirONTk ZT9/uR1ZYWQR1lPfO4j84SBe0EJMe+xNbRc/zqYs0lyuIxbGuNeBIgXdPuhBYnxKUsqa 1lRVZW5JApBe3VbsJQIb8T3UICg7oDNWojTvsJDD/ym2e60+EO+KAgzXA4ztdGUAHqy9 O3pOpzy76VIC7kYu8wEd1MBBagVGufo1C0qrXABG/+ZbFJAcPXGkpWJlNVjC4iNjN2Q7 7L3zHpYMMmRNdI1CZDexAvmh+zw4XGj0QtkDetXdBYd4JQhofgZ3/UJPhSUhf0bg+9hJ sIQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=/BqdExWyx9Bl0S67ay6eLPSQ3j9ULOrwLRuR5UXqQJg=; b=lCxqWhZl6O/uVNcAonykEozIzA2JAv31ByjNNExanCyI6nPo+T8iToGOibNZpaq4nE SJUavfjg6apRPaVSonmIAfUVw4GjUaM0wUSzyfdxI/Iy0vbvR19JQptUQxMq92OO0qDk Fw6KY28SBQtVfUpzXM9ThicLlDU0RNkJNYO/mw4YuAWkO3YQ7S8GI+vDN6D+ITKJq/D1 omujUkLnZlYIEpk0Hp3Kh6alhrFLu4T1sIWiGbluZd+zxhxakVC75I+yHPRpL+AA6/6s rvZ5WjqMWxIkOBRtus9BKn3vLj055qXKMl69lrOl1A22qU2lawz1iUW7asYjvGlC7tsd 2/nw== X-Gm-Message-State: AA6/9RlVIxa/+teVLJCK9mSxc1k/u5TSEmo8NPhvpQeLVYozf1LhjIl0i+gD7jIvZi3n1w== X-Received: by 10.36.61.6 with SMTP id n6mr13154014itn.75.1475394404887; Sun, 02 Oct 2016 00:46:44 -0700 (PDT) Received: from localhost.localdomain ([216.16.66.181]) by smtp.gmail.com with ESMTPSA id s185sm5387725ita.21.2016.10.02.00.46.44 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 02 Oct 2016 00:46:44 -0700 (PDT) From: Burt P To: ffmpeg-devel@ffmpeg.org Date: Sun, 2 Oct 2016 02:46:33 -0500 Message-Id: <1475394393-10173-6-git-send-email-pburt0@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1475394393-10173-1-git-send-email-pburt0@gmail.com> References: <1475394393-10173-1-git-send-email-pburt0@gmail.com> Subject: [FFmpeg-devel] [PATCH 5/5] af_hdcd: add experimental 20 and 24-bit decoding support X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" As in this libhdcd commit: [0] I don't have any legitimate 20 or 24-bit HDCD to test. It is known that the PM Model Two would insert packets into 20 and 24-bit output, but I have no idea what differences in behavior existed when decoding 20 or 24-bit. For now, as with 16-bit, PE (if enabled) will expand the top 3dB into 9dB and LLE (gain adjust) will be applied if signaled. Also, As all known valid HDCD sample formats and sample rates are now handled by the filter, remove the scan that "invades the privacy" of the filter graph and turn off autoconvert by default as requested by Nicolas George. [1] [0] https://github.com/bp0/libhdcd/commit/dc32b383efab5608820af4f641db292f9a776778 [1] http://ffmpeg.org/pipermail/ffmpeg-devel/2016-August/197571.html Signed-off-by: Burt P --- libavfilter/af_hdcd.c | 135 ++++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index b5aad85..91f84ae 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -964,6 +964,8 @@ typedef struct HDCDContext { int cdt_ms; /**< code detect timer period in ms */ int disable_autoconvert; /**< disable any format conversion or resampling in the filter graph */ + + int bits_per_sample; /**< bits per sample 16, 20, or 24 */ /* end AVOption members */ /** config_input() and config_output() scan links for any resampling @@ -983,7 +985,7 @@ typedef struct HDCDContext { #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM static const AVOption hdcd_options[] = { { "disable_autoconvert", "Disable any format conversion or resampling in the filter graph.", - OFFSET(disable_autoconvert), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, A }, + OFFSET(disable_autoconvert), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, A }, { "process_stereo", "Process stereo channels together. Only apply target_gain when both channels match.", OFFSET(process_stereo), AV_OPT_TYPE_BOOL, { .i64 = HDCD_PROCESS_STEREO_DEFAULT }, 0, 1, A }, { "cdt_ms", "Code detect timer period in ms.", @@ -997,6 +999,11 @@ static const AVOption hdcd_options[] = { { "pe", HDCD_ANA_PE_DESC, 0, AV_OPT_TYPE_CONST, {.i64=HDCD_ANA_PE}, 0, 0, A, "analyze_mode" }, { "cdt", HDCD_ANA_CDT_DESC, 0, AV_OPT_TYPE_CONST, {.i64=HDCD_ANA_CDT}, 0, 0, A, "analyze_mode" }, { "tgm", HDCD_ANA_TGM_DESC, 0, AV_OPT_TYPE_CONST, {.i64=HDCD_ANA_TGM}, 0, 0, A, "analyze_mode" }, + { "bits_per_sample", "Valid bits per sample (location of the true LSB).", + OFFSET(bits_per_sample), AV_OPT_TYPE_INT, { .i64=16 }, 16, 24, A, "bits_per_sample"}, + { "16", "16-bit (in s32 or s16)", 0, AV_OPT_TYPE_CONST, {.i64=16}, 0, 0, A, "bits_per_sample" }, + { "20", "20-bit (in s32)", 0, AV_OPT_TYPE_CONST, {.i64=20}, 0, 0, A, "bits_per_sample" }, + { "24", "24-bit (in s32)", 0, AV_OPT_TYPE_CONST, {.i64=24}, 0, 0, A, "bits_per_sample" }, {NULL} }; @@ -1253,29 +1260,34 @@ static int hdcd_analyze(int32_t *samples, int count, int stride, int gain, int t } /** apply HDCD decoding parameters to a series of samples */ -static int hdcd_envelope(int32_t *samples, int count, int stride, int gain, int target_gain, int extend) +static int hdcd_envelope(int32_t *samples, int count, int stride, int vbits, int gain, int target_gain, int extend) { static const int max_asample = sizeof(peaktab) / sizeof(peaktab[0]) - 1; int32_t *samples_end = samples + stride * count; int i; + int pe_level = PEAK_EXT_LEVEL, shft = 15; + if (vbits != 16) { + pe_level = (1 << (vbits - 1)) - (0x8000 - PEAK_EXT_LEVEL); + shft = 32 - vbits - 1; + } av_assert0(PEAK_EXT_LEVEL + max_asample == 0x8000); if (extend) { for (i = 0; i < count; i++) { int32_t sample = samples[i * stride]; - int32_t asample = abs(sample) - PEAK_EXT_LEVEL; + int32_t asample = abs(sample) - pe_level; if (asample >= 0) { av_assert0(asample <= max_asample); sample = sample >= 0 ? peaktab[asample] : -peaktab[asample]; } else - sample <<= 15; + sample <<= shft; samples[i * stride] = sample; } } else { for (i = 0; i < count; i++) - samples[i * stride] <<= 15; + samples[i * stride] <<= shft; } if (gain <= target_gain) { @@ -1370,7 +1382,7 @@ static void hdcd_process(HDCDContext *ctx, hdcd_state *state, int32_t *samples, if (ctx->analyze_mode) gain = hdcd_analyze(samples, envelope_run, stride, gain, target_gain, peak_extend, ctx->analyze_mode, state->sustain, -1); else - gain = hdcd_envelope(samples, envelope_run, stride, gain, target_gain, peak_extend); + gain = hdcd_envelope(samples, envelope_run, stride, ctx->bits_per_sample, gain, target_gain, peak_extend); samples += envelope_run * stride; count -= envelope_run; @@ -1382,7 +1394,7 @@ static void hdcd_process(HDCDContext *ctx, hdcd_state *state, int32_t *samples, if (ctx->analyze_mode) gain = hdcd_analyze(samples, lead, stride, gain, target_gain, peak_extend, ctx->analyze_mode, state->sustain, -1); else - gain = hdcd_envelope(samples, lead, stride, gain, target_gain, peak_extend); + gain = hdcd_envelope(samples, lead, stride, ctx->bits_per_sample, gain, target_gain, peak_extend); } state->running_gain = gain; @@ -1422,8 +1434,8 @@ static void hdcd_process_stereo(HDCDContext *ctx, int32_t *samples, int count) ctx->state[1].sustain, (ctlret == HDCD_TG_MISMATCH) ); } else { - gain[0] = hdcd_envelope(samples, envelope_run, stride, gain[0], ctx->val_target_gain, peak_extend[0]); - gain[1] = hdcd_envelope(samples + 1, envelope_run, stride, gain[1], ctx->val_target_gain, peak_extend[1]); + gain[0] = hdcd_envelope(samples, envelope_run, stride, ctx->bits_per_sample, gain[0], ctx->val_target_gain, peak_extend[0]); + gain[1] = hdcd_envelope(samples + 1, envelope_run, stride, ctx->bits_per_sample, gain[1], ctx->val_target_gain, peak_extend[1]); } samples += envelope_run * stride; @@ -1444,8 +1456,8 @@ static void hdcd_process_stereo(HDCDContext *ctx, int32_t *samples, int count) ctx->state[1].sustain, (ctlret == HDCD_TG_MISMATCH) ); } else { - gain[0] = hdcd_envelope(samples, lead, stride, gain[0], ctx->val_target_gain, peak_extend[0]); - gain[1] = hdcd_envelope(samples + 1, lead, stride, gain[1], ctx->val_target_gain, peak_extend[1]); + gain[0] = hdcd_envelope(samples, lead, stride, ctx->bits_per_sample, gain[0], ctx->val_target_gain, peak_extend[0]); + gain[1] = hdcd_envelope(samples + 1, lead, stride, ctx->bits_per_sample, gain[1], ctx->val_target_gain, peak_extend[1]); } } @@ -1516,8 +1528,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out; const int16_t *in_data; + const int32_t *in_data32; int32_t *out_data; int n, c, result; + int a = 32 - s->bits_per_sample; out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { @@ -1533,16 +1547,32 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) out->format = outlink->format; // is this needed? out_data = (int32_t*)out->data[0]; - if (inlink->format == AV_SAMPLE_FMT_S16P) { - for (n = 0; n < in->nb_samples; n++) - for (c = 0; c < in->channels; c++) { - in_data = (int16_t*)in->extended_data[c]; - out_data[(n * in->channels) + c] = in_data[n]; - } - } else { - in_data = (int16_t*)in->data[0]; - for (n = 0; n < in->nb_samples * in->channels; n++) - out_data[n] = in_data[n]; + switch (inlink->format) { + case AV_SAMPLE_FMT_S16P: + for (n = 0; n < in->nb_samples; n++) + for (c = 0; c < in->channels; c++) { + in_data = (int16_t*)in->extended_data[c]; + out_data[(n * in->channels) + c] = in_data[n]; + } + break; + case AV_SAMPLE_FMT_S16: + in_data = (int16_t*)in->data[0]; + for (n = 0; n < in->nb_samples * in->channels; n++) + out_data[n] = in_data[n]; + break; + + case AV_SAMPLE_FMT_S32P: + for (n = 0; n < in->nb_samples; n++) + for (c = 0; c < in->channels; c++) { + in_data32 = (int32_t*)in->extended_data[c]; + out_data[(n * in->channels) + c] = in_data32[n] >> a; + } + break; + case AV_SAMPLE_FMT_S32: + in_data32 = (int32_t*)in->data[0]; + for (n = 0; n < in->nb_samples * in->channels; n++) + out_data[n] = in_data32[n] >> a; + break; } if (s->process_stereo) { @@ -1583,6 +1613,8 @@ static int query_formats(AVFilterContext *ctx) static const enum AVSampleFormat sample_fmts_in[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_S32, + AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE }; static const enum AVSampleFormat sample_fmts_out[] = { @@ -1678,12 +1710,27 @@ static av_cold int init(AVFilterContext *ctx) static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; HDCDContext *s = ctx->priv; - AVFilterLink *lk; int c; av_log(ctx, AV_LOG_VERBOSE, "Auto-convert: %s\n", (ctx->graph->disable_auto_convert) ? "disabled" : "enabled"); + if ((inlink->format == AV_SAMPLE_FMT_S16 || + inlink->format == AV_SAMPLE_FMT_S16P) && + s->bits_per_sample != 16) { + av_log(ctx, AV_LOG_WARNING, "bits_per_sample %d does not fit into sample format %s, falling back to 16\n", + s->bits_per_sample, av_get_sample_fmt_name(inlink->format) ); + s->bits_per_sample = 16; + } else { + av_log(ctx, AV_LOG_VERBOSE, "Looking for %d-bit HDCD in sample format %s\n", + s->bits_per_sample, av_get_sample_fmt_name(inlink->format) ); + } + + if (s->bits_per_sample != 16) + av_log(ctx, AV_LOG_WARNING, "20 and 24-bit HDCD decoding is experimental\n"); + if (inlink->sample_rate != 44100) + av_log(ctx, AV_LOG_WARNING, "HDCD decoding for sample rates other than 44100 is experimental\n"); + hdcd_detect_reset(&s->detect); for (c = 0; c < HDCD_MAX_CHANNELS; c++) { hdcd_reset(&s->state[c], inlink->sample_rate, s->cdt_ms); @@ -1703,24 +1750,6 @@ static int config_input(AVFilterLink *inlink) { av_log(ctx, AV_LOG_VERBOSE, "Analyze mode: [%d] %s\n", s->analyze_mode, ana_mode_str[s->analyze_mode] ); - lk = inlink; - while(lk != NULL) { - AVFilterContext *nextf = lk->src; - if (lk->type == AVMEDIA_TYPE_AUDIO) { - int sfok = (lk->format == AV_SAMPLE_FMT_S16 || - lk->format == AV_SAMPLE_FMT_S16P); - if ( !sfok || lk->sample_rate != 44100) { - av_log(ctx, AV_LOG_WARNING, "An input format is %s@%dHz at %s. It will truncated/resampled to s16@44100Hz.\n", - av_get_sample_fmt_name(lk->format), lk->sample_rate, - (nextf->name) ? nextf->name : "" - ); - s->bad_config = 1; - break; - } - } - lk = (nextf->inputs) ? nextf->inputs[0] : NULL; - } - /* more warning will appear after config_output() */ return 0; } @@ -1734,36 +1763,10 @@ static const AVFilterPad avfilter_af_hdcd_inputs[] = { { NULL } }; -static int config_output(AVFilterLink *outlink) { - static const char hdcd_baduse[] = - "The HDCD filter is unlikely to produce a desirable result in this context."; - AVFilterContext *ctx = outlink->src; - HDCDContext *s = ctx->priv; - AVFilterLink *lk = outlink; - while(lk != NULL) { - AVFilterContext *nextf = lk->dst; - if (lk->type == AVMEDIA_TYPE_AUDIO) { - if (lk->format == AV_SAMPLE_FMT_S16 || lk->format == AV_SAMPLE_FMT_U8) { - av_log(ctx, AV_LOG_WARNING, "s24 output is being truncated to %s at %s.\n", - av_get_sample_fmt_name(lk->format), - (nextf->name) ? nextf->name : "" - ); - s->bad_config = 1; - break; - } - } - lk = (nextf->outputs) ? nextf->outputs[0] : NULL; - } - if (s->bad_config) - av_log(ctx, AV_LOG_WARNING, "%s\n", hdcd_baduse); - return 0; -} - static const AVFilterPad avfilter_af_hdcd_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .config_props = config_output, }, { NULL } };