The new HDCD filter really does nothing to show that it is working or that HDCD control information was even detected in the stream. This patch collects information about the decode, like which features were used, and reports it to the user at the end. First patch I've ever tried to submit to ffmpeg. Has a couple long lines.
Signed-off-by: bp0 <b...@users.noreply.github.com> --- libavfilter/af_hdcd.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index 16bdcb0..f298765 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -823,11 +823,25 @@ typedef struct { int code_counterA; int code_counterB; int code_counterC; + + /* For user information/stats, pulled up into HDCDContext + * by filter_frame() */ + int _hdcd_detected; + int _peak_extend; + int _gain_min; /* 4-bit (3.1) fixed-point, << 7 */ + int _gain_max; /* 4-bit (3.1) fixed-point, << 7 */ + int _transient_filter; } hdcd_state_t; typedef struct HDCDContext { const AVClass *class; hdcd_state_t state[2]; + + /* User information/stats */ + int hdcd_detected; + int peak_extend; + int transient_filter; /* detected, but not implemented */ + float gain_min, gain_max; /* stored positive, but values are negative */ } HDCDContext; static const AVOption hdcd_options[] = { @@ -853,6 +867,12 @@ static void hdcd_reset(hdcd_state_t *state, unsigned rate) state->code_counterA = 0; state->code_counterB = 0; state->code_counterC = 0; + + state->_hdcd_detected = 0; + state->_peak_extend = 0; + state->_gain_min = 0; + state->_gain_max = 0; + state->_transient_filter = 0; } static int integrate(hdcd_state_t *state, int *flag, const int32_t *samples, int count, int stride) @@ -982,14 +1002,20 @@ static int hdcd_envelope(int32_t *samples, int count, int stride, int gain, int return gain; } +/* update the user info/flags */ +#define UPDATE_INFO(s,pe,tg,tf) do{if (pe || tg || tf || s->sustain) { s->_hdcd_detected = 1; } if (pe) { s->_peak_extend = 1; } if (tf) { s->_transient_filter = 1;} if (tg < s->_gain_min) { s->_gain_min=tg; } if (tg > s->_gain_max) { s->_gain_max=tg; } }while(0); + static void hdcd_process(hdcd_state_t *state, int32_t *samples, int count, int stride) { int32_t *samples_end = samples + count * stride; int gain = state->running_gain; int peak_extend = (state->control & 16); int target_gain = (state->control & 15) << 7; + int transient_filter = (state->control & 32); int lead = 0; + UPDATE_INFO(state, peak_extend, target_gain, transient_filter); + while (count > lead) { int envelope_run; int run; @@ -1006,6 +1032,8 @@ static void hdcd_process(hdcd_state_t *state, int32_t *samples, int count, int s lead = run - envelope_run; peak_extend = (state->control & 16); target_gain = (state->control & 15) << 7; + transient_filter = (state->control & 32); + UPDATE_INFO(state, peak_extend, target_gain, transient_filter); } if (lead > 0) { av_assert0(samples + lead * stride <= samples_end); @@ -1015,6 +1043,9 @@ static void hdcd_process(hdcd_state_t *state, int32_t *samples, int count, int s state->running_gain = gain; } +/* convert to float from (4-bit (3.1) fixed-point, << 7) */ +#define GAINTOFLOAT(g) ((float)(g>>8) + ((float)(g>>7 & 1) * 0.5)) + static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; @@ -1024,6 +1055,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) const int16_t *in_data; int32_t *out_data; int n, c; + int _gain_min = 0; + int _gain_max = 0; out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { @@ -1042,8 +1075,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) for (c = 0; c < inlink->channels; c++) { hdcd_state_t *state = &s->state[c]; hdcd_process(state, out_data + c, in->nb_samples, out->channels); + + s->hdcd_detected |= state->_hdcd_detected; + s->peak_extend |= state->_peak_extend; + s->transient_filter |= state->_transient_filter; + if (state->_gain_min < _gain_min) { _gain_min = state->_gain_min; } + if (state->_gain_max > _gain_max) { _gain_max = state->_gain_max; } } + s->gain_min = GAINTOFLOAT(_gain_min); + s->gain_max = GAINTOFLOAT(_gain_max); + av_frame_free(&in); return ff_filter_frame(outlink, out); } @@ -1104,6 +1146,12 @@ static av_cold void uninit(AVFilterContext *ctx) av_log(ctx, AV_LOG_VERBOSE, "Channel %d: counter A: %d, B: %d, C: %d\n", i, state->code_counterA, state->code_counterB, state->code_counterC); } + + av_log(ctx, AV_LOG_INFO, "HDCD detected: %s, peak_extend: %s, transient_filter: %s, min_gain: -%0.1f dB, max_gain: -%0.1f dB\n", + (s->hdcd_detected) ? "yes" : "no", + (s->peak_extend) ? "enabled" : "never enabled", + (s->transient_filter) ? "enabled (but not supported)" : "never enabled", + s->gain_min, s->gain_max); } static av_cold int init(AVFilterContext *ctx) @@ -1112,6 +1160,12 @@ static av_cold int init(AVFilterContext *ctx) HDCDContext *s = ctx->priv; int c; + s->hdcd_detected = 0; + s->peak_extend = 0; + s->transient_filter = 0; + s->gain_min = 0.0; + s->gain_max = 0.0; + for (c = 0; c < 2; c++) { hdcd_reset(&s->state[c], 44100); } -- 2.7.4 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel