[FFmpeg-devel] [PATCH 4/5] af_hdcd: hdcd_scan() and hdcd_integrate() handle stereo and single channel

Burt P pburt0 at gmail.com
Sun Oct 2 10:46:32 EEST 2016


New versions of hdcd_scan() and hdcd_integrate() that also do the
work of hdcd_scan_stereo() and hdcd_integrate_stereo().

Some code split into previously separate functions to remove
duplication is now merged back into each function in the single
place where it is used.

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

diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c
index 6f35c09..b5aad85 100644
--- a/libavfilter/af_hdcd.c
+++ b/libavfilter/af_hdcd.c
@@ -1031,267 +1031,134 @@ static void hdcd_reset(hdcd_state *state, unsigned rate, unsigned cdt_ms)
     state->_ana_snb = 0;
 }
 
-/** update the user info/counters */
-static void hdcd_update_info(hdcd_state *state)
+static int hdcd_integrate(HDCDContext *ctx, hdcd_state *states, int channels, int *flag, const int32_t *samples, int count, int stride)
 {
-    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));
-}
-
-typedef enum {
-    HDCD_CODE_NONE=0,
-    HDCD_CODE_A,
-    HDCD_CODE_A_ALMOST,
-    HDCD_CODE_B,
-    HDCD_CODE_B_CHECKFAIL,
-    HDCD_CODE_EXPECT_A,
-    HDCD_CODE_EXPECT_B,
-} hdcd_code_result;
-
-static hdcd_code_result hdcd_code(const uint32_t bits, unsigned char *code)
-{
-    if ((bits & 0x0fa00500) == 0x0fa00500) {
-        /* A: 8-bit code  0x7e0fa005[..] */
-        if ((bits & 0xc8) == 0) {
-            /*                   [..pt gggg]
-             * 0x0fa005[..] -> 0b[00.. 0...], gain part doubled */
-            *code = (bits & 255) + (bits & 7);
-            return HDCD_CODE_A;
-        } else
-            return HDCD_CODE_A_ALMOST; /* one of bits 3, 6, or 7 was not 0 */
-    } else if ((bits & 0xa0060000) == 0xa0060000) {
-        /* B: 8-bit code, 8-bit XOR check, 0x7e0fa006[....] */
-        if (((bits ^ (~bits >> 8 & 255)) & 0xffff00ff) == 0xa0060000) {
-            /*          check:   [..pt gggg ~(..pt gggg)]
-             * 0xa006[....] -> 0b[.... ....   .... .... ] */
-            *code = bits >> 8 & 255;
-            return HDCD_CODE_B;
-        } else
-            return HDCD_CODE_B_CHECKFAIL;  /* XOR check failed */
-    }
-    if (bits == 0x7e0fa005)
-        return HDCD_CODE_EXPECT_A;
-    else if (bits == 0x7e0fa006)
-        return HDCD_CODE_EXPECT_B;
-
-    return HDCD_CODE_NONE;
-}
-
-static int hdcd_integrate(HDCDContext *ctx, hdcd_state *state, int *flag, const int32_t *samples, int count, int stride)
-{
-    uint32_t bits = 0;
-    int result = FFMIN(state->readahead, count);
-    int i;
+    uint32_t bits[HDCD_MAX_CHANNELS];
+    int result = count;
+    int i, j, f;
     *flag = 0;
 
-    for (i = result - 1; i >= 0; i--) {
-        bits |= (*samples & 1) << i; /* might be better as a conditional? */
-        samples += stride;
-    }
+    memset(bits, 0, sizeof(bits));
+    if (stride < channels) stride = channels;
 
-    state->window = (state->window << result) | bits;
-    state->readahead -= result;
-    if (state->readahead > 0)
-        return result;
+    for (i = 0; i < channels; i++)
+        result = FFMIN(states[i].readahead, result);
 
-    bits = (state->window ^ state->window >> 5 ^ state->window >> 23);
-
-    if (state->arg) {
-        switch (hdcd_code(bits, &state->control)) {
-            case HDCD_CODE_A:
-                *flag = 1;
-                state->code_counterA++;
-                break;
-            case HDCD_CODE_B:
-                *flag = 1;
-                state->code_counterB++;
-                break;
-            case HDCD_CODE_A_ALMOST:
-                state->code_counterA_almost++;
-                av_log(ctx->fctx, AV_LOG_VERBOSE,
-                    "hdcd error: Control A almost: 0x%02x near %d\n", bits & 0xff, ctx->sample_count);
-                break;
-            case HDCD_CODE_B_CHECKFAIL:
-                state->code_counterB_checkfails++;
-                av_log(ctx->fctx, AV_LOG_VERBOSE,
-                    "hdcd error: Control B check failed: 0x%04x (0x%02x vs 0x%02x) near %d\n", bits & 0xffff, (bits & 0xff00) >> 8, ~bits & 0xff, ctx->sample_count);
-                break;
-            case HDCD_CODE_NONE:
-                state->code_counterC_unmatched++;
-                av_log(ctx->fctx, AV_LOG_VERBOSE,
-                    "hdcd error: Unmatched code: 0x%08x near %d\n", bits, ctx->sample_count);
-            default:
-                av_log(ctx->fctx, AV_LOG_INFO,
-                    "hdcd error: Unexpected return value from hdcd_code()\n");
-                av_assert0(0); /* die */
-        }
-        if (*flag) hdcd_update_info(state);
-        state->arg = 0;
+    for (j = result - 1; j >= 0; j--) {
+        for (i = 0; i < channels; i++)
+            bits[i] |= (*(samples++) & 1) << j;
+        samples += stride - channels;
     }
-    if (bits == 0x7e0fa005 || bits == 0x7e0fa006) {
-        /* 0x7e0fa00[.]-> [0b0101 or 0b0110] */
-        state->readahead = (bits & 3) * 8;
-        state->arg = 1;
-        state->code_counterC++;
-    } else {
-        if (bits)
-            state->readahead = readaheadtab[bits & 0xff];
-        else
-            state->readahead = 31; /* ffwd over digisilence */
-    }
-    return result;
-}
-
-static int hdcd_integrate_stereo(HDCDContext *ctx, int *flag, const int32_t *samples, int count)
-{
-    uint32_t bits[2] = {0, 0};
-    int result;
-    int i;
-    *flag = 0;
-
-    /* result = min(count, s0ra, s1ra) */
-    result = FFMIN(ctx->state[0].readahead, count);
-    result = FFMIN(ctx->state[1].readahead, result);
 
-    for (i = result - 1; i >= 0; i--) {
-        bits[0] |= (*(samples++) & 1) << i;
-        bits[1] |= (*(samples++) & 1) << i;
-    }
-
-    for (i = 0; i < 2; i++) {
-        ctx->state[i].window = (ctx->state[i].window << result) | bits[i];
-        ctx->state[i].readahead -= result;
-
-        if (ctx->state[i].readahead == 0) {
-            uint32_t wbits = (ctx->state[i].window ^ ctx->state[i].window >> 5 ^ ctx->state[i].window >> 23);
-            if (ctx->state[i].arg) {
-                switch (hdcd_code(wbits, &ctx->state[i].control)) {
-                    case HDCD_CODE_A:
-                        *flag |= i+1;
-                        ctx->state[i].code_counterA++;
-                        break;
-                    case HDCD_CODE_B:
-                        *flag |= i+1;
-                        ctx->state[i].code_counterB++;
-                        break;
-                    case HDCD_CODE_A_ALMOST:
-                        ctx->state[i].code_counterA_almost++;
+    for (i = 0; i < channels; i++) {
+        states[i].window = (states[i].window << result) | bits[i];
+        states[i].readahead -= result;
+
+        if (states[i].readahead == 0) {
+            uint32_t wbits = (uint32_t)(states[i].window ^ states[i].window >> 5 ^ states[i].window >> 23);
+            if (states[i].arg) {
+                f = 0;
+                if ((wbits & 0x0fa00500) == 0x0fa00500) {
+                    /* A: 8-bit code  0x7e0fa005[..] */
+                    if ((wbits & 0xc8) == 0) {
+                        /*                   [..pt gggg]
+                         * 0x0fa005[..] -> 0b[00.. 0...], gain part doubled (shifted left 1) */
+                        states[i].control = (wbits & 255) + (wbits & 7);
+                        f = 1;
+                        states[i].code_counterA++;
+                    } else {
+                        /* one of bits 3, 6, or 7 was not 0 */
+                        states[i].code_counterA_almost++;
                         av_log(ctx->fctx, AV_LOG_VERBOSE,
                             "hdcd error: Control A almost: 0x%02x near %d\n", wbits & 0xff, ctx->sample_count);
-                        break;
-                    case HDCD_CODE_B_CHECKFAIL:
-                        ctx->state[i].code_counterB_checkfails++;
+                    }
+                } else if ((wbits & 0xa0060000) == 0xa0060000) {
+                    /* B: 8-bit code, 8-bit XOR check, 0x7e0fa006[....] */
+                    if (((wbits ^ (~wbits >> 8 & 255)) & 0xffff00ff) == 0xa0060000) {
+                        /*          check:   [..pt gggg ~(..pt gggg)]
+                         * 0xa006[....] -> 0b[.... ....   .... .... ] */
+                        states[i].control = wbits >> 8 & 255;
+                        f = 1;
+                        states[i].code_counterB++;
+                    } else {
+                        /* XOR check failed */
+                        states[i].code_counterB_checkfails++;
                         av_log(ctx->fctx, AV_LOG_VERBOSE,
                             "hdcd error: Control B check failed: 0x%04x (0x%02x vs 0x%02x) near %d\n", wbits & 0xffff, (wbits & 0xff00) >> 8, ~wbits & 0xff, ctx->sample_count);
-                        break;
-                    case HDCD_CODE_NONE:
-                        ctx->state[i].code_counterC_unmatched++;
-                        av_log(ctx->fctx, AV_LOG_VERBOSE,
-                            "hdcd error: Unmatched code: 0x%08x near %d\n", wbits, ctx->sample_count);
-                    default:
-                        av_log(ctx->fctx, AV_LOG_INFO,
-                            "hdcd error: Unexpected return value from hdcd_code()\n");
-                        av_assert0(0); /* die */
+                    }
+                }
+                if (f) {
+                    *flag |= (1<<i);
+                    /* update counters */
+                    if (states[i].control & 16) states[i].count_peak_extend++;
+                    if (states[i].control & 32) states[i].count_transient_filter++;
+                    states[i].gain_counts[states[i].control & 15]++;
+                    states[i].max_gain = FFMAX(states[i].max_gain, (states[i].control & 15));
                 }
-                if (*flag&(i+1)) hdcd_update_info(&ctx->state[i]);
-                ctx->state[i].arg = 0;
+                states[i].arg = 0;
             }
             if (wbits == 0x7e0fa005 || wbits == 0x7e0fa006) {
                 /* 0x7e0fa00[.]-> [0b0101 or 0b0110] */
-                ctx->state[i].readahead = (wbits & 3) * 8;
-                ctx->state[i].arg = 1;
-                ctx->state[i].code_counterC++;
+                states[i].readahead = (wbits & 3) * 8;
+                states[i].arg = 1;
+                states[i].code_counterC++;
             } else {
                 if (wbits)
-                    ctx->state[i].readahead = readaheadtab[wbits & 0xff];
+                    states[i].readahead = readaheadtab[wbits & 0xff];
                 else
-                    ctx->state[i].readahead = 31; /* ffwd over digisilence */
+                    states[i].readahead = 31; /* ffwd over digisilence */
             }
         }
     }
     return result;
 }
 
-static void hdcd_sustain_reset(hdcd_state *state)
-{
-    state->sustain = state->sustain_reset;
-    /* if this is the first reset then change
-     * from never set, to never expired */
-    if (state->count_sustain_expired == -1)
-        state->count_sustain_expired = 0;
-}
-
-static int hdcd_scan(HDCDContext *ctx, hdcd_state *state, const int32_t *samples, int max, int stride)
-{
-    int result;
-    int cdt_active = 0;
-    /* code detect timer */
-    if (state->sustain > 0) {
-        cdt_active = 1;
-        if (state->sustain <= max) {
-            state->control = 0;
-            max = state->sustain;
-        }
-        state->sustain -= max;
-    }
-
-    result = 0;
-    while (result < max) {
-        int flag;
-        int consumed = hdcd_integrate(ctx, state, &flag, samples, max - result, stride);
-        result += consumed;
-        if (flag > 0) {
-            /* reset timer if code detected in channel */
-            hdcd_sustain_reset(state);
-            break;
-        }
-        samples += consumed * stride;
-    }
-    /* code detect timer expired */
-    if (cdt_active && state->sustain == 0)
-        state->count_sustain_expired++;
-
-    return result;
-}
-
-static int hdcd_scan_stereo(HDCDContext *ctx, const int32_t *samples, int max)
+static int hdcd_scan(HDCDContext *ctx, hdcd_state *states, int channels, const int32_t *samples, int max, int stride)
 {
     int result;
     int i;
-    int cdt_active[2] = {0, 0};
+    int cdt_active[HDCD_MAX_CHANNELS];
+    memset(cdt_active, 0, sizeof(cdt_active));
+
+    if (stride < channels) stride = channels;
 
     /* code detect timers for each channel */
-    for(i=0; i<2; i++) {
-        if (ctx->state[i].sustain > 0) {
+    for(i = 0; i < channels; i++) {
+        if (states[i].sustain > 0) {
             cdt_active[i] = 1;
-            if (ctx->state[i].sustain <= max) {
-                ctx->state[i].control = 0;
-                max = ctx->state[i].sustain;
+            if (states[i].sustain <=  (unsigned)max) {
+                states[i].control = 0;
+                max = states[i].sustain;
             }
-            ctx->state[i].sustain -= max;
+            states[i].sustain -= max;
         }
     }
 
     result = 0;
     while (result < max) {
         int flag;
-        int consumed = hdcd_integrate_stereo(ctx, &flag, samples, max - result);
+        int consumed = hdcd_integrate(ctx, states, channels, &flag, samples, max - result, stride);
         result += consumed;
         if (flag) {
             /* reset timer if code detected in a channel */
-            if (flag & 1) hdcd_sustain_reset(&ctx->state[0]);
-            if (flag & 2) hdcd_sustain_reset(&ctx->state[1]);
+            for(i = 0; i < channels; i++) {
+                if (flag & (1<<i)) {
+                    states[i].sustain = states[i].sustain_reset;
+                    /* if this is the first reset then change
+                     * from never set, to never expired */
+                    if (states[i].count_sustain_expired == -1)
+                        states[i].count_sustain_expired = 0;
+                }
+            }
             break;
         }
-        samples += consumed * 2;
+        samples += consumed * stride;
     }
 
-    for(i=0; i<2; i++) {
+    for(i = 0; i < channels; i++) {
         /* code detect timer expired */
-        if (cdt_active[i] && ctx->state[i].sustain == 0)
-            ctx->state[i].count_sustain_expired++;
+        if (cdt_active[i] && states[i].sustain == 0)
+            states[i].count_sustain_expired++;
     }
 
     return result;
@@ -1496,7 +1363,7 @@ static void hdcd_process(HDCDContext *ctx, hdcd_state *state, int32_t *samples,
         int run;
 
         av_assert0(samples + lead * stride + stride * (count - lead) <= samples_end);
-        run = hdcd_scan(ctx, state, samples + lead * stride, count - lead, stride) + lead;
+        run = hdcd_scan(ctx, state, 1, samples + lead * stride, count - lead, 0) + lead;
         envelope_run = run - 1;
 
         av_assert0(samples + envelope_run * stride <= samples_end);
@@ -1540,7 +1407,7 @@ static void hdcd_process_stereo(HDCDContext *ctx, int32_t *samples, int count)
         int envelope_run, run;
 
         av_assert0(samples + lead * stride + stride * (count - lead) <= samples_end);
-        run = hdcd_scan_stereo(ctx, samples + lead * stride, count - lead) + lead;
+        run = hdcd_scan(ctx, ctx->state, 2, samples + lead * stride, count - lead, 0) + lead;
         envelope_run = run - 1;
 
         av_assert0(samples + envelope_run * stride <= samples_end);
-- 
2.7.4



More information about the ffmpeg-devel mailing list