Merge branch 'refs/heads/t/wma'
authorAndre Noll <maan@tuebingen.mpg.de>
Sat, 5 Aug 2017 12:05:52 +0000 (14:05 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sat, 5 Aug 2017 12:18:06 +0000 (14:18 +0200)
A couple of patches which simplify the wma decoder and improve the
robustness of the bitstream API.

Cooking for a month.

* refs/heads/t/wma:
  wma: Remove _XOPEN_SOURCE define from wmadec_filter.c.
  wma: make ->ms_stereo local to wma_decode_block().
  wma: Simplify init_coef_vlc().
  wma: Rename input/output buffer variables.
  wma: Drop unused argument from wma_decode_superframe().
  wma: Remove pointless/incorrect sanity checks.
  wma: Combine wmadec_cleanup() and wmadec_close().
  wma: Simplify get_vlc().
  wma: Remove pointless VLC_TYPE define.
  wma: Make bitstream API more robust.

NEWS.md
bitstream.c
bitstream.h
wmadec_filter.c

diff --git a/NEWS.md b/NEWS.md
index 05400a9..5e03421 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,5 @@
 NEWS
 ====
-
 ---------------------
 current master branch
 ---------------------
@@ -14,6 +13,8 @@ current master branch
 - Overhaul of the source code documentation.
 - The deprecated --full-path option of the ls command has been
   removed. It was a no-op since 0.6.0.
+- The wma decoder has been cleaned up and its bitstream API made
+  more robust.
 
 -------------------------------
 0.6.0 (2017-04-28) "fuzzy flux"
index 9cd1273..c2018b5 100644 (file)
@@ -47,7 +47,7 @@ static void alloc_table(struct vlc *vlc, int size)
        if (vlc->table_size > vlc->table_allocated) {
                vlc->table_allocated += (1 << vlc->bits);
                vlc->table = para_realloc(vlc->table,
-                       sizeof(VLC_TYPE) * 2 * vlc->table_allocated);
+                       sizeof(int16_t) * 2 * vlc->table_allocated);
        }
 }
 
@@ -57,7 +57,7 @@ static int build_table(struct vlc *vlc, int table_nb_bits, int nb_codes,
 {
        int i, j, k, n, table_size, table_index, nb, n1, idx;
        uint32_t code;
-       VLC_TYPE(*table)[2];
+       int16_t (*table)[2];
 
        table_size = 1 << table_nb_bits;
        table_index = vlc->table_size;
@@ -165,33 +165,29 @@ void free_vlc(struct vlc *vlc)
  * Parse a vlc code.
  *
  * \param gbc The getbit context structure.
- * \param table The vlc tables to use.
- * \param bits The number of bits which will be read at once.
- *
- * The \a bits parameter must be identical to the \a nb_bits value supplied to
- * \ref init_vlc().
+ * \param vlc The vlc tables to use.
  *
  * \return The vlc code.
  */
-int get_vlc(struct getbit_context *gbc, VLC_TYPE(*table)[2], int bits)
+int get_vlc(struct getbit_context *gbc, const struct vlc *vlc)
 {
        int n, idx, nb_bits, code;
 
-       idx = show_bits(gbc, bits);
-       code = table[idx][0];
-       n = table[idx][1];
+       idx = show_bits(gbc, vlc->bits);
+       code = vlc->table[idx][0];
+       n = vlc->table[idx][1];
        if (n < 0) {
-               skip_bits(gbc, bits);
+               skip_bits(gbc, vlc->bits);
                nb_bits = -n;
                idx = show_bits(gbc, nb_bits) + code;
-               code = table[idx][0];
-               n = table[idx][1];
+               code = vlc->table[idx][0];
+               n = vlc->table[idx][1];
                if (n < 0) {
                        skip_bits(gbc, nb_bits);
                        nb_bits = -n;
                        idx = show_bits(gbc, nb_bits) + code;
-                       code = table[idx][0];
-                       n = table[idx][1];
+                       code = vlc->table[idx][0];
+                       n = vlc->table[idx][1];
                }
        }
        skip_bits(gbc, n);
index a634986..4d81fa3 100644 (file)
 struct getbit_context {
        /** Start of the internal buffer. */
        const uint8_t *buffer;
-       /** End of the internal buffer. */
-       const uint8_t *buffer_end;
+       /** Length of buffer in bits (always a multiple of 8). */
+       uint32_t num_bits;
        /** Bit counter. */
        int index;
 };
 
-#define VLC_TYPE int16_t
-
 /** A variable length code table. */
 struct vlc {
        /** Number of bits of the table. */
        int bits;
        /** The code and the bits table. */
-       VLC_TYPE(*table)[2];
+       int16_t (*table)[2];
        /** The size of the table. */
        int table_size;
        /** Amount of memory allocated so far. */
@@ -36,8 +34,12 @@ struct vlc {
 static inline uint32_t show_bits(struct getbit_context *gbc, int num)
 {
        int idx = gbc->index;
-       const char *p = (const char *)gbc->buffer + (idx >> 3);
-       uint32_t x = read_u32_be(p);
+       const char *p;
+       uint32_t x;
+
+       assert(idx + num <= gbc->num_bits);
+       p = (const char *)gbc->buffer + (idx >> 3);
+       x = read_u32_be(p);
        return (x << (idx & 7)) >> (32 - num);
 }
 
@@ -48,12 +50,13 @@ static inline int get_bits_count(struct getbit_context *gbc)
 
 static inline void skip_bits(struct getbit_context *gbc, int n)
 {
+       assert(gbc->index + n <= gbc->num_bits);
        gbc->index += n;
 }
 
 static inline unsigned int get_bits(struct getbit_context *gbc, int n)
 {
-       unsigned int ret = show_bits(gbc, n);
+       unsigned int ret = show_bits(gbc, n); /* checks n */
        skip_bits(gbc, n);
        return ret;
 }
@@ -61,8 +64,13 @@ static inline unsigned int get_bits(struct getbit_context *gbc, int n)
 /* This is rather hot, we can do better than get_bits(gbc, 1). */
 static inline unsigned int get_bit(struct getbit_context *gbc)
 {
-       int idx = gbc->index++;
-       uint8_t tmp = gbc->buffer[idx >> 3], mask = 1 << (7 - (idx & 7));
+       int idx;
+       uint8_t tmp, mask;
+
+       assert(gbc->index < gbc->num_bits);
+       idx = gbc->index++;
+       tmp = gbc->buffer[idx >> 3];
+       mask = 1 << (7 - (idx & 7));
        return !!(tmp & mask);
 }
 
@@ -81,11 +89,11 @@ static inline void init_get_bits(struct getbit_context *gbc,
                const uint8_t *buffer, int size)
 {
        gbc->buffer = buffer;
-       gbc->buffer_end = buffer + size;
+       gbc->num_bits = size * 8;
        gbc->index = 0;
 }
 
 void init_vlc(struct vlc *vlc, int nb_bits, int nb_codes, const void *bits,
                const void *codes, int codes_size);
 void free_vlc(struct vlc *vlc);
-int get_vlc(struct getbit_context *gbc, VLC_TYPE(*table)[2], int bits);
+int get_vlc(struct getbit_context *gbc, const struct vlc *vlc);
index 525ed31..b96f146 100644 (file)
@@ -15,8 +15,6 @@
  * This decoder handles Microsoft Windows Media Audio data version 2.
  */
 
-#define _XOPEN_SOURCE 600
-
 #include <math.h>
 #include <regex.h>
 #include <sys/select.h>
@@ -81,7 +79,6 @@ struct private_wmadec_data {
        struct vlc coef_vlc[2];
        uint16_t *run_table[2];
        uint16_t *level_table[2];
-       const struct coef_vlc_table *coef_vlcs[2];
        /** Frame length in samples. */
        int frame_len;
        /** log2 of frame_len. */
@@ -100,8 +97,6 @@ struct private_wmadec_data {
        int block_len;
        /** Current position in frame. */
        int block_pos;
-       /** True if mid/side stereo mode. */
-       uint8_t ms_stereo;
        /** True if channel is coded. */
        uint8_t channel_coded[MAX_CHANNELS];
        /** log2 ratio frame/exp. length. */
@@ -159,51 +154,27 @@ static void sine_window_init(float *window, int n)
                window[i] = sinf((i + 0.5) * (M_PI / (2.0 * n)));
 }
 
-static void wmadec_cleanup(struct private_wmadec_data *pwd)
-{
-       int i;
-
-       for (i = 0; i < pwd->nb_block_sizes; i++)
-               imdct_end(pwd->mdct_ctx[i]);
-       if (pwd->ahi.use_exp_vlc)
-               free_vlc(&pwd->exp_vlc);
-       if (pwd->use_noise_coding)
-               free_vlc(&pwd->hgain_vlc);
-       for (i = 0; i < 2; i++) {
-               free_vlc(&pwd->coef_vlc[i]);
-               free(pwd->run_table[i]);
-               free(pwd->level_table[i]);
-       }
-}
-
-static void init_coef_vlc(struct vlc *vlc, uint16_t **prun_table,
-               uint16_t **plevel_table, const struct coef_vlc_table *vlc_table)
+static void init_coef_vlc(struct private_wmadec_data *pwd, int sidx, int didx)
 {
-       int n = vlc_table->n;
-       const uint8_t *table_bits = vlc_table->huffbits;
-       const uint32_t *table_codes = vlc_table->huffcodes;
-       const uint16_t *levels_table = vlc_table->levels;
-       uint16_t *run_table, *level_table;
-       int i, l, j, k, level;
+       const struct coef_vlc_table *src = coef_vlcs + sidx;
+       struct vlc *dst = pwd->coef_vlc + didx;
+       int i, l, j, k, level, n = src->n;
 
-       init_vlc(vlc, VLCBITS, n, table_bits, table_codes, 4);
-
-       run_table = para_malloc(n * sizeof(uint16_t));
-       level_table = para_malloc(n * sizeof(uint16_t));
+       init_vlc(dst, VLCBITS, n, src->huffbits, src->huffcodes, 4);
+       pwd->run_table[didx] = para_malloc(n * sizeof(uint16_t));
+       pwd->level_table[didx] = para_malloc(n * sizeof(uint16_t));
        i = 2;
        level = 1;
        k = 0;
        while (i < n) {
-               l = levels_table[k++];
+               l = src->levels[k++];
                for (j = 0; j < l; j++) {
-                       run_table[i] = j;
-                       level_table[i] = level;
+                       pwd->run_table[didx][i] = j;
+                       pwd->level_table[didx][i] = level;
                        i++;
                }
                level++;
        }
-       *prun_table = run_table;
-       *plevel_table = level_table;
 }
 
 /* compute the scale factor band sizes for each MDCT block size */
@@ -413,19 +384,15 @@ static int wma_init(struct private_wmadec_data *pwd)
        }
 
        /* choose the VLC tables for the coefficients */
-       coef_vlc_table = 2;
+       coef_vlc_table = 4;
        if (ahi->sample_rate >= 32000) {
                if (bps1 < 0.72)
                        coef_vlc_table = 0;
                else if (bps1 < 1.16)
-                       coef_vlc_table = 1;
+                       coef_vlc_table = 2;
        }
-       pwd->coef_vlcs[0] = &coef_vlcs[coef_vlc_table * 2];
-       pwd->coef_vlcs[1] = &coef_vlcs[coef_vlc_table * 2 + 1];
-       init_coef_vlc(&pwd->coef_vlc[0], &pwd->run_table[0], &pwd->level_table[0],
-               pwd->coef_vlcs[0]);
-       init_coef_vlc(&pwd->coef_vlc[1], &pwd->run_table[1], &pwd->level_table[1],
-               pwd->coef_vlcs[1]);
+       init_coef_vlc(pwd, coef_vlc_table, 0);
+       init_coef_vlc(pwd, coef_vlc_table + 1, 1);
        return 0;
 }
 
@@ -581,7 +548,7 @@ static int decode_exp_vlc(struct private_wmadec_data *pwd, int ch)
        last_exp = 36;
 
        while (q < q_end) {
-               code = get_vlc(&pwd->gb, pwd->exp_vlc.table, EXPVLCBITS);
+               code = get_vlc(&pwd->gb, &pwd->exp_vlc);
                if (code < 0)
                        return code;
                /* NOTE: this offset is the same as MPEG4 AAC ! */
@@ -708,8 +675,7 @@ static int compute_high_band_values(struct private_wmadec_data *pwd,
                        if (val == (int)0x80000000)
                                val = get_bits(&pwd->gb, 7) - 19;
                        else {
-                               int code = get_vlc(&pwd->gb,
-                                       pwd->hgain_vlc.table, HGAINVLCBITS);
+                               int code = get_vlc(&pwd->gb, &pwd->hgain_vlc);
                                if (code < 0)
                                        return code;
                                val += code - 18;
@@ -828,6 +794,7 @@ static int wma_decode_block(struct private_wmadec_data *pwd)
        int ret, n, v, ch, code, bsize;
        int coef_nb_bits, total_gain;
        int nb_coefs[MAX_CHANNELS];
+       bool ms_stereo = false; /* mid/side stereo mode */
 
        /* compute current block length */
        if (pwd->ahi.use_variable_block_len) {
@@ -865,7 +832,7 @@ static int wma_decode_block(struct private_wmadec_data *pwd)
                return -E_INCOHERENT_BLOCK_LEN;
 
        if (pwd->ahi.channels == 2)
-               pwd->ms_stereo = get_bit(&pwd->gb);
+               ms_stereo = get_bit(&pwd->gb);
        v = 0;
        for (ch = 0; ch < pwd->ahi.channels; ch++) {
                int a = get_bit(&pwd->gb);
@@ -931,7 +898,7 @@ static int wma_decode_block(struct private_wmadec_data *pwd)
                 * special VLC tables are used for ms stereo because there is
                 * potentially less energy there
                 */
-               tindex = (ch == 1 && pwd->ms_stereo);
+               tindex = ch == 1 && ms_stereo;
                coef_vlc = &pwd->coef_vlc[tindex];
                run_table = pwd->run_table[tindex];
                level_table = pwd->level_table[tindex];
@@ -940,7 +907,7 @@ static int wma_decode_block(struct private_wmadec_data *pwd)
                eptr = ptr + nb_coefs[ch];
                memset(ptr, 0, pwd->block_len * sizeof(int16_t));
                for (;;) {
-                       code = get_vlc(&pwd->gb, coef_vlc->table, VLCBITS);
+                       code = get_vlc(&pwd->gb, coef_vlc);
                        if (code < 0)
                                return code;
                        if (code == 1) /* EOB */
@@ -966,7 +933,7 @@ static int wma_decode_block(struct private_wmadec_data *pwd)
                }
        }
        compute_mdct_coefficients(pwd, bsize, total_gain, nb_coefs);
-       if (pwd->ms_stereo && pwd->channel_coded[1]) {
+       if (ms_stereo && pwd->channel_coded[1]) {
                float a, b;
                int i;
                /*
@@ -994,7 +961,7 @@ next:
                n4 = pwd->block_len / 2;
                if (pwd->channel_coded[ch])
                        imdct(pwd->mdct_ctx[bsize], pwd->output, pwd->coefs[ch]);
-               else if (!(pwd->ms_stereo && ch == 1))
+               else if (!(ms_stereo && ch == 1))
                        memset(pwd->output, 0, sizeof(pwd->output));
 
                /* multiply by the window and add in the frame */
@@ -1058,24 +1025,13 @@ static int wma_decode_frame(struct private_wmadec_data *pwd, int16_t *samples)
        return 0;
 }
 
-static int wma_decode_superframe(struct private_wmadec_data *pwd, void *data,
-               int *data_size, const uint8_t *buf, int buf_size)
+static int wma_decode_superframe(struct private_wmadec_data *pwd, void *out,
+               int *out_size, const uint8_t *in)
 {
-       int ret;
-       int16_t *samples;
+       int ret, in_size = pwd->ahi.packet_size - WMA_FRAME_SKIP;
+       int16_t *samples = out;
 
-       if (buf_size == 0) {
-               pwd->last_superframe_len = 0;
-               *data_size = 0;
-               return 0;
-       }
-       if (buf_size < pwd->ahi.block_align) {
-               *data_size = 0;
-               return 0;
-       }
-       buf_size = pwd->ahi.block_align;
-       samples = data;
-       init_get_bits(&pwd->gb, buf, buf_size);
+       init_get_bits(&pwd->gb, in, in_size);
        if (pwd->ahi.use_bit_reservoir) {
                int i, nb_frames, bit_offset, pos, len;
                uint8_t *q;
@@ -1086,7 +1042,7 @@ static int wma_decode_superframe(struct private_wmadec_data *pwd, void *data,
                // PARA_DEBUG_LOG("have %d frames\n", nb_frames);
                ret = -E_WMA_OUTPUT_SPACE;
                if ((nb_frames + 1) * pwd->ahi.channels * pwd->frame_len
-                               * sizeof(int16_t) > *data_size)
+                               * sizeof(int16_t) > *out_size)
                        goto fail;
 
                bit_offset = get_bits(&pwd->gb, pwd->byte_offset_bits + 3);
@@ -1124,7 +1080,7 @@ static int wma_decode_superframe(struct private_wmadec_data *pwd, void *data,
 
                /* read each frame starting from bit_offset */
                pos = bit_offset + 4 + 4 + pwd->byte_offset_bits + 3;
-               init_get_bits(&pwd->gb, buf + (pos >> 3),
+               init_get_bits(&pwd->gb, in + (pos >> 3),
                        (MAX_CODED_SUPERFRAME_SIZE - (pos >> 3)));
                len = pos & 7;
                if (len > 0)
@@ -1143,16 +1099,16 @@ static int wma_decode_superframe(struct private_wmadec_data *pwd, void *data,
                        ((bit_offset + 4 + 4 + pwd->byte_offset_bits + 3) & ~7);
                pwd->last_bitoffset = pos & 7;
                pos >>= 3;
-               len = buf_size - pos;
+               len = in_size - pos;
                ret = -E_WMA_BAD_SUPERFRAME;
                if (len > MAX_CODED_SUPERFRAME_SIZE || len < 0)
                        goto fail;
                pwd->last_superframe_len = len;
-               memcpy(pwd->last_superframe, buf + pos, len);
+               memcpy(pwd->last_superframe, in + pos, len);
        } else {
                PARA_DEBUG_LOG("not using bit reservoir\n");
                ret = -E_WMA_OUTPUT_SPACE;
-               if (pwd->ahi.channels * pwd->frame_len * sizeof(int16_t) > *data_size)
+               if (pwd->ahi.channels * pwd->frame_len * sizeof(int16_t) > *out_size)
                        goto fail;
                /* single frame decode */
                ret = wma_decode_frame(pwd, samples);
@@ -1162,8 +1118,8 @@ static int wma_decode_superframe(struct private_wmadec_data *pwd, void *data,
        }
        PARA_DEBUG_LOG("frame_len: %d, block_len: %d, outbytes: %d, eaten: %d\n",
                pwd->frame_len, pwd->block_len,
-               (int)((int8_t *)samples - (int8_t *)data), pwd->ahi.block_align);
-       *data_size = (int8_t *)samples - (int8_t *)data;
+               (int)((int8_t *)samples - (int8_t *)out), pwd->ahi.block_align);
+       *out_size = (int8_t *)samples - (int8_t *)out;
        return pwd->ahi.block_align;
 fail:
        /* reset the bit reservoir on errors */
@@ -1174,10 +1130,21 @@ fail:
 static void wmadec_close(struct filter_node *fn)
 {
        struct private_wmadec_data *pwd = fn->private_data;
+       int i;
 
        if (!pwd)
                return;
-       wmadec_cleanup(pwd);
+       for (i = 0; i < pwd->nb_block_sizes; i++)
+               imdct_end(pwd->mdct_ctx[i]);
+       if (pwd->ahi.use_exp_vlc)
+               free_vlc(&pwd->exp_vlc);
+       if (pwd->use_noise_coding)
+               free_vlc(&pwd->hgain_vlc);
+       for (i = 0; i < 2; i++) {
+               free_vlc(&pwd->coef_vlc[i]);
+               free(pwd->run_table[i]);
+               free(pwd->level_table[i]);
+       }
        free(fn->private_data);
        fn->private_data = NULL;
 }
@@ -1233,7 +1200,7 @@ next_buffer:
        out_size = WMA_OUTPUT_BUFFER_SIZE;
        out = para_malloc(out_size);
        ret = wma_decode_superframe(pwd, out, &out_size,
-               (uint8_t *)in + WMA_FRAME_SKIP, len - WMA_FRAME_SKIP);
+               (uint8_t *)in + WMA_FRAME_SKIP);
        if (ret < 0) {
                free(out);
                goto err;