]> git.sesse.net Git - ffmpeg/commitdiff
avformat/brstm: fix decoding brstm with custom coeff offsets
authorPaul B Mahol <onemda@gmail.com>
Sat, 12 Sep 2020 12:45:31 +0000 (14:45 +0200)
committerPaul B Mahol <onemda@gmail.com>
Sat, 12 Sep 2020 12:52:31 +0000 (14:52 +0200)
libavformat/brstm.c

index a63c7ee5abe4c67ce96f5a2ce8fc31d6da18294b..c4230a63bf385974672449b73a230a713c1783e9 100644 (file)
 #include "avformat.h"
 #include "internal.h"
 
+typedef struct BRSTMCoeffOffset {
+    uint8_t  channel;
+    uint32_t offset;
+} BRSTMCoeffOffset;
+
 typedef struct BRSTMDemuxContext {
     uint32_t    block_size;
     uint32_t    block_count;
@@ -35,6 +40,7 @@ typedef struct BRSTMDemuxContext {
     uint32_t    data_start;
     uint8_t     *table;
     uint8_t     *adpc;
+    BRSTMCoeffOffset offsets[256];
     int         little_endian;
 } BRSTMDemuxContext;
 
@@ -67,6 +73,13 @@ static int read_close(AVFormatContext *s)
     return 0;
 }
 
+static int sort_offsets(const void *a, const void *b)
+{
+    const BRSTMCoeffOffset *s1 = a;
+    const BRSTMCoeffOffset *s2 = b;
+    return FFDIFFSIGN(s1->offset, s2->offset);
+}
+
 static av_always_inline unsigned int read16(AVFormatContext *s)
 {
     BRSTMDemuxContext *b = s->priv_data;
@@ -259,17 +272,33 @@ static int read_header(AVFormatContext *s)
         if (toffset > size)
             return AVERROR_INVALIDDATA;
 
+        if (!bfstm) {
+            avio_skip(s->pb, pos + toffset - avio_tell(s->pb) - 8LL * (st->codecpar->channels + 1));
+            for (ch = 0; ch < st->codecpar->channels; ch++) {
+                avio_skip(s->pb, 4);
+                b->offsets[ch].channel = ch;
+                b->offsets[ch].offset = read32(s);
+            }
+
+            qsort(b->offsets, st->codecpar->channels, sizeof(*b->offsets), sort_offsets);
+        }
+
         avio_skip(s->pb, pos + toffset - avio_tell(s->pb));
         b->table = av_mallocz(32 * st->codecpar->channels);
         if (!b->table)
             return AVERROR(ENOMEM);
 
         for (ch = 0; ch < st->codecpar->channels; ch++) {
+            if (!bfstm)
+                avio_skip(s->pb, pos + 16LL + b->offsets[ch].offset - avio_tell(s->pb));
+
             if (avio_read(s->pb, b->table + ch * 32, 32) != 32) {
                 ret = AVERROR_INVALIDDATA;
                 goto fail;
             }
-            avio_skip(s->pb, bfstm ? 14 : 24);
+
+            if (bfstm)
+                avio_skip(s->pb, 14);
         }
     }