Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mpc-hc/FFmpeg.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBurt P <pburt0@gmail.com>2016-07-05 20:23:33 +0300
committerMichael Niedermayer <michael@niedermayer.cc>2016-07-06 23:54:47 +0300
commitba69a81019a2642969b108c39e3bea7d2f8ffbfa (patch)
treeb2ef0456ae004cecfc511e675fbc64fec4fb15e3 /libavfilter/af_hdcd.c
parent3e4357eb822c8bcaf9743dde008f5774d1356e74 (diff)
libavfilter/af_hdcd.c: Collect HDCD stats and report
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. Also, * Fixes low-level gain adjustment * Updates the documentation Signed-off-by: Burt P <pburt0@gmail.com> Reviewed-by: Paul B Mahol <onemda@gmail.com> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Diffstat (limited to 'libavfilter/af_hdcd.c')
-rw-r--r--libavfilter/af_hdcd.c76
1 files changed, 73 insertions, 3 deletions
diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c
index 16bdcb01ea..89012eb53e 100644
--- a/libavfilter/af_hdcd.c
+++ b/libavfilter/af_hdcd.c
@@ -31,7 +31,8 @@
*/
/*
- More information about high definition audio cds:
+ HDCD is High Definition Compatible Digital
+ More information about HDCD-encoded audio CDs:
http://www.audiomisc.co.uk/HFN/HDCD/Enigma.html
http://www.audiomisc.co.uk/HFN/HDCD/Examined.html
*/
@@ -823,11 +824,29 @@ typedef struct {
int code_counterA;
int code_counterB;
int code_counterC;
+
+ /* For user information/stats, pulled up into HDCDContext
+ * by filter_frame() */
+ int count_peak_extend;
+ int count_transient_filter;
+ /* target_gain is a 4-bit (3.1) fixed-point value, always
+ * negative, but stored positive.
+ * The 16 possible values range from -7.5 to 0.0 dB in
+ * steps of 0.5, but no value below -6.0 dB should appear. */
+ int gain_counts[16]; /* for cursiosity, mostly */
+ int max_gain;
+ int cb6, cb7; /* watch bits 6 and 7 of the control code, for curiosity */
} hdcd_state_t;
typedef struct HDCDContext {
const AVClass *class;
hdcd_state_t state[2];
+
+ /* User information/stats */
+ int hdcd_detected;
+ int uses_peak_extend;
+ int uses_transient_filter; /* detected, but not implemented */
+ float max_gain_adjustment; /* in dB, expected in the range -6.0 to 0.0 */
} HDCDContext;
static const AVOption hdcd_options[] = {
@@ -840,6 +859,8 @@ AVFILTER_DEFINE_CLASS(hdcd);
static void hdcd_reset(hdcd_state_t *state, unsigned rate)
{
+ int i;
+
state->window = 0;
state->readahead = 32;
state->arg = 0;
@@ -853,6 +874,13 @@ static void hdcd_reset(hdcd_state_t *state, unsigned rate)
state->code_counterA = 0;
state->code_counterB = 0;
state->code_counterC = 0;
+
+ state->count_peak_extend = 0;
+ state->count_transient_filter = 0;
+ for(i = 0; i < 16; i++) state->gain_counts[i] = 0;
+ state->max_gain = 0;
+ state->cb6 = 0;
+ state->cb7 = 0;
}
static int integrate(hdcd_state_t *state, int *flag, const int32_t *samples, int count, int stride)
@@ -949,6 +977,7 @@ static int hdcd_envelope(int32_t *samples, int count, int stride, int gain, int
int len = FFMIN(count, target_gain - gain);
/* attenuate slowly */
for (i = 0; i < len; i++) {
+ ++gain;
APPLY_GAIN(*samples, gain);
samples += stride;
}
@@ -982,6 +1011,18 @@ static int hdcd_envelope(int32_t *samples, int count, int stride, int gain, int
return gain;
}
+/* update the user info/flags */
+static void hdcd_update_info(hdcd_state_t *state)
+{
+ if (state->control & 16) state->count_peak_extend++;
+ if (state->control & 32) state->count_transient_filter++;
+ state->gain_counts[state->control & 15]++;
+ state->max_gain = FFMAX(state->max_gain, (state->control & 15));
+
+ if (state->control & 64) state->cb6++;
+ if (state->control & 128) state->cb7++;
+}
+
static void hdcd_process(hdcd_state_t *state, int32_t *samples, int count, int stride)
{
int32_t *samples_end = samples + count * stride;
@@ -990,6 +1031,8 @@ static void hdcd_process(hdcd_state_t *state, int32_t *samples, int count, int s
int target_gain = (state->control & 15) << 7;
int lead = 0;
+ hdcd_update_info(state);
+
while (count > lead) {
int envelope_run;
int run;
@@ -1006,6 +1049,7 @@ 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;
+ hdcd_update_info(state);
}
if (lead > 0) {
av_assert0(samples + lead * stride <= samples_end);
@@ -1015,6 +1059,10 @@ 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
+ * the always-negative value is stored positive, so make it negative */
+#define GAINTOFLOAT(g) (g) ? -(float)(g>>1) - ((g & 1) ? 0.5 : 0.0) : 0.0
+
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
AVFilterContext *ctx = inlink->dst;
@@ -1042,6 +1090,11 @@ 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->uses_peak_extend |= !!state->count_peak_extend;
+ s->uses_transient_filter |= !!state->count_transient_filter;
+ s->max_gain_adjustment = FFMIN(s->max_gain_adjustment, GAINTOFLOAT(state->max_gain));
+ s->hdcd_detected |= state->code_counterC || state->code_counterB || state->code_counterA;
}
av_frame_free(&in);
@@ -1097,13 +1150,28 @@ static int query_formats(AVFilterContext *ctx)
static av_cold void uninit(AVFilterContext *ctx)
{
HDCDContext *s = ctx->priv;
- int i;
+ int i, j;
+ /* dump the state for each channel for AV_LOG_VERBOSE */
for (i = 0; i < 2; i++) {
hdcd_state_t *state = &s->state[i];
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_VERBOSE, "Channel %d: c(pe): %d, c(tf): %d, cb6: %d, cb7: %d\n", i,
+ state->count_peak_extend, state->count_transient_filter, state->cb6, state->cb7);
+ for (j = 0; j <= state->max_gain; j++) {
+ av_log(ctx, AV_LOG_VERBOSE, "Channel %d: tg %0.1f - %d\n", i, GAINTOFLOAT(j), state->gain_counts[j]);
+ }
}
+
+ /* log the HDCD decode information */
+ av_log(ctx, AV_LOG_INFO,
+ "HDCD detected: %s, peak_extend: %s, max_gain_adj: %0.1f dB, transient_filter: %s\n",
+ (s->hdcd_detected) ? "yes" : "no",
+ (s->uses_peak_extend) ? "enabled" : "never enabled",
+ s->max_gain_adjustment,
+ (s->uses_transient_filter) ? "detected" : "not detected"
+ );
}
static av_cold int init(AVFilterContext *ctx)
@@ -1112,6 +1180,8 @@ static av_cold int init(AVFilterContext *ctx)
HDCDContext *s = ctx->priv;
int c;
+ s->max_gain_adjustment = 0.0;
+
for (c = 0; c < 2; c++) {
hdcd_reset(&s->state[c], 44100);
}
@@ -1138,7 +1208,7 @@ static const AVFilterPad avfilter_af_hdcd_outputs[] = {
AVFilter ff_af_hdcd = {
.name = "hdcd",
- .description = NULL_IF_CONFIG_SMALL("Apply high definition audio cd decoding."),
+ .description = NULL_IF_CONFIG_SMALL("Apply High Definition Compatible Digital (HDCD) decoding."),
.priv_size = sizeof(HDCDContext),
.priv_class = &hdcd_class,
.init = init,