[FFmpeg-devel] [PATCH] libavfilter/af_hdcd.c: Collect HDCD stats and report

Burt P pburt0 at gmail.com
Sun Jul 3 15:53:46 EEST 2016


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.

Signed-off-by: Burt P <pburt0 at gmail.com>
---
 libavfilter/af_hdcd.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c
index 16bdcb0..c0233eb 100644
--- a/libavfilter/af_hdcd.c
+++ b/libavfilter/af_hdcd.c
@@ -823,11 +823,27 @@ 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 transient_filter;
+    /* 4-bit (3.1) fixed-point, << 7 *
+     * stored positive, but values are negative, so
+     * min and max are swapped when converted to float later */
+    int gain_min, gain_max;
 } 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;
 } HDCDContext;
 
 static const AVOption hdcd_options[] = {
@@ -853,6 +869,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 +1004,25 @@ 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; } \
+    s->peak_extend = !!pe; \
+    s->transient_filter = !!tf; \
+    s->gain_min = FFMIN(s->gain_min, tg); \
+    s->gain_max = FFMAX(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 +1039,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 +1050,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) + ((g>>7 & 1) ? 0.5 : 0.0))
+
 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx = inlink->dst;
@@ -1024,6 +1062,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 +1082,19 @@ 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;
+        gain_min = FFMIN(gain_min, state->gain_min);
+        gain_max = FFMAX(gain_max, state->gain_max);
     }
 
+    /* swapped here because the fixed-point always-negative values
+     *  are stored positive */
+    s->gain_max = -(GAINTOFLOAT(gain_min)); /* max = -min */
+    s->gain_min = -(GAINTOFLOAT(gain_max)); /* min = -max */
+
     av_frame_free(&in);
     return ff_filter_frame(outlink, out);
 }
@@ -1104,6 +1155,13 @@ 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 +1170,9 @@ static av_cold int init(AVFilterContext *ctx)
     HDCDContext *s = ctx->priv;
     int c;
 
+    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



More information about the ffmpeg-devel mailing list