]> git.tue.mpg.de Git - paraslash.git/commitdiff
wma: Fix packet size calculation.
authorAndre Noll <maan@tuebingen.mpg.de>
Tue, 1 Nov 2016 10:44:53 +0000 (11:44 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 11 Dec 2016 12:13:03 +0000 (13:13 +0100)
Usually the (fixed) packet size of a wma file equals the block align
value plus WMA_FRAME_SKIP. However, this is not true in general,
and if the two values differ, we fail to decode the file and bail
out with an "incoherent block length" error.

This patch adds code to read the correct packet size from the file
properties object and uses this value in the decoder and the audio
format handler.

error.h
wma.h
wma_afh.c
wma_common.c
wmadec_filter.c

diff --git a/error.h b/error.h
index 3fda5787774ce739754a58d74706c3081f1e9da5..00b1aa77f8d657415bbaf3b34027351bca102e9d 100644 (file)
--- a/error.h
+++ b/error.h
@@ -148,6 +148,7 @@ extern const char **para_errlist[];
 
 
 #define WMA_COMMON_ERRORS \
+       PARA_ERROR(BAD_ASF_FILE_PROPS, "invalid ASF file properties"), \
        PARA_ERROR(WMA_NO_GUID, "audio stream guid not found"), \
 
 
diff --git a/wma.h b/wma.h
index 15b9c5d492560f2c6532935460cc7ca4f38ca571..b260feb99d76ea58511696cd0c04ddb4ec01b26c 100644 (file)
--- a/wma.h
+++ b/wma.h
@@ -28,6 +28,8 @@ struct asf_header_info {
        bool use_bit_reservoir;
        /** Whether blocks are of variable or of constant size. */
        bool use_variable_block_len;
+       /** Obtained from the file properties object. */
+       uint32_t packet_size;
 };
 
 /* wma_common.c */
index 929e732b8cb03bd84d6b382e05508fc2f81cf49d..4c9d87e047af8d1d5873096db54ab4a9d17ab966 100644 (file)
--- a/wma_afh.c
+++ b/wma_afh.c
 #include "wma.h"
 #include "fd.h"
 
-#define FOR_EACH_FRAME(_f, _buf, _size, _ba) for (_f = (_buf); \
-       _f + (_ba) + WMA_FRAME_SKIP < (_buf) + (_size); \
-       _f += (_ba) + WMA_FRAME_SKIP)
+#define FOR_EACH_FRAME(_f, _buf, _size, _ps) for (_f = (_buf); \
+       _f + (_ps) < (_buf) + (_size); \
+       _f += (_ps))
 
 /*
  * Must be called on a frame boundary, e.g. start + header_len.
  * \return Frame count, superframe count via *num_superframes.
  */
-static int count_frames(const char *buf, int buf_size, int block_align,
+static int count_frames(const char *buf, int buf_size, uint32_t packet_size,
        int *num_superframes)
 {
        int fc = 0, sfc = 0; /* frame count, superframe count */
        const uint8_t *p;
 
 
-       FOR_EACH_FRAME(p, (uint8_t *)buf, buf_size, block_align) {
+       FOR_EACH_FRAME(p, (uint8_t *)buf, buf_size, packet_size) {
                fc += p[WMA_FRAME_SKIP] & 0x0f;
                sfc++;
        }
@@ -192,7 +192,7 @@ static void set_chunk_tv(int frames_per_chunk, int frequency,
 }
 
 /* Must be called on a frame boundary. */
-static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align,
+static int wma_make_chunk_table(char *buf, size_t buf_size, uint32_t packet_size,
                struct afh_info *afhi)
 {
        const uint8_t *f, *start = (uint8_t *)buf;
@@ -204,7 +204,7 @@ static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align,
        afhi->chunk_table[0] = 0;
        afhi->chunk_table[1] = afhi->header_len;
 
-       num_frames = count_frames(buf, buf_size, block_align,
+       num_frames = count_frames(buf, buf_size, packet_size,
                &num_superframes);
        ret = -E_NO_WMA;
        if (num_frames == 0 || num_superframes == 0)
@@ -214,7 +214,7 @@ static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align,
        frames_per_chunk = num_frames / num_superframes / 2;
        PARA_INFO_LOG("%d frames per chunk\n", frames_per_chunk);
        j = 1;
-       FOR_EACH_FRAME(f, start, buf_size, block_align) {
+       FOR_EACH_FRAME(f, start, buf_size, packet_size) {
                count += f[WMA_FRAME_SKIP] & 0x0f;
                while (count > j * frames_per_chunk) {
                        j++;
@@ -224,7 +224,8 @@ static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align,
                                        afhi->chunk_table,
                                        ct_size * sizeof(uint32_t));
                        }
-                       afhi->chunk_table[j] = f - start + afhi->header_len + block_align + WMA_FRAME_SKIP;
+                       afhi->chunk_table[j] = f - start + afhi->header_len
+                               + packet_size;
                }
        }
        afhi->chunks_total = j;
@@ -262,7 +263,7 @@ static int wma_get_file_info(char *map, size_t numbytes, __a_unused int fd,
                ahi.use_variable_block_len? "vbl" : ""
        );
        wma_make_chunk_table(map + ahi.header_len, numbytes - ahi.header_len,
-               ahi.block_align, afhi);
+               ahi.packet_size, afhi);
        read_asf_tags(map, ahi.header_len, &afhi->tags);
        return 0;
 }
index 88873c956ebd2293779b6d79699eaf8725871b5f..27cb51d0434367e168fa49554e05bf1f13d9f473 100644 (file)
@@ -42,6 +42,17 @@ const char *search_pattern(const char *pattern, int pattern_len,
        return NULL;
 }
 
+static int find_file_properties(const char *buf, int len)
+{
+       const char pattern[] = {0xa1, 0xdc, 0xab, 0x8c};
+       const char *p = search_pattern(pattern, sizeof(pattern), buf, len);
+
+       if (!p)
+               return -E_WMA_NO_GUID;
+       PARA_DEBUG_LOG("found file property guid@%0x\n", (int)(p - buf));
+       return p - buf + 16;
+}
+
 /*
    40 9e 69 f8 4d 5b cf 11  a8 fd 00 80 5f 5c 44 2b
  */
@@ -112,6 +123,21 @@ int read_asf_header(const char *buf, int loaded, struct asf_header_info *ahi)
        ahi->use_exp_vlc = ahi->flags2 & 0x0001;
        ahi->use_bit_reservoir = ahi->flags2 & 0x0002;
        ahi->use_variable_block_len = ahi->flags2 & 0x0004;
+
+       ret = find_file_properties(buf, ahi->header_len);
+       if (ret < 0)
+               return ret;
+       /* file property header is always 88 bytes (sans GUID) */
+       if (ret + 88 > loaded)
+               return 0;
+       start = buf + ret;
+       ahi->packet_size = read_u32(start + 76); /* min packet size */
+       /* we only support fixed packet sizes */
+       if (ahi->packet_size != read_u32(start + 80)) /* min != max */
+               return -E_BAD_ASF_FILE_PROPS;
+       if (ahi->packet_size <= ahi->block_align)
+               return -E_BAD_ASF_FILE_PROPS;
+       PARA_INFO_LOG("packet size: %u\n", ahi->packet_size);
        return 1;
 }
 
index 48257c19b11de385e999f96706b9ca83632ea4a4..f695d869806fef2223e4c70dbd41040e1d404d12 100644 (file)
@@ -1221,12 +1221,12 @@ next_buffer:
                        fn->min_iqs += 4096;
                        goto next_buffer;
                }
-               fn->min_iqs = 2 * (WMA_FRAME_SKIP + pwd->ahi.block_align);
+               fn->min_iqs = 2 * pwd->ahi.packet_size;
                fn->private_data = pwd;
                converted = pwd->ahi.header_len;
                goto success;
        }
-       fn->min_iqs = WMA_FRAME_SKIP + pwd->ahi.block_align;
+       fn->min_iqs = pwd->ahi.packet_size;
        if (fn->min_iqs > len)
                goto success;
        out_size = WMA_OUTPUT_BUFFER_SIZE;
@@ -1242,7 +1242,7 @@ next_buffer:
                btr_add_output(out, out_size, btrn);
        } else
                free(out);
-       converted += ret + WMA_FRAME_SKIP;
+       converted += pwd->ahi.packet_size;
 success:
        btr_consume(btrn, converted);
        return 0;