Browse code

iff/8svx: redesign 8SVX demuxing and decoding for handling stereo samples correctly

Make the iff demuxer send the whole audio chunk to the decoder as a
single packet, move stereo interleaving from the iff demuxer to the
decoder, and introduce an 8svx_raw decoder which performs
stereo interleaving.

This is required for handling stereo data correctly, indeed samples
are stored like:
LLLLLL....RRRRRR

that is all left samples are at the beginning of the chunk, all right
samples at the end, so it is necessary to store and process the whole
buffer in order to decode each frame. Thus the decoder needs all the
audio chunk before it can return interleaved data.

Fix decoding of files 8svx_exp.iff and 8svx_fib.iff, fix trac issue #169.

Stefano Sabatini authored on 2011/05/15 20:24:46
Showing 7 changed files
... ...
@@ -1,5 +1,6 @@
1 1
 /*
2 2
  * Copyright (C) 2008 Jaikrishnan Menon
3
+ * Copyright (C) 2011 Stefano Sabatini
3 4
  *
4 5
  * This file is part of FFmpeg.
5 6
  *
... ...
@@ -38,62 +39,155 @@
38 38
 
39 39
 /** decoder context */
40 40
 typedef struct EightSvxContext {
41
-    int16_t fib_acc;
42
-    const int16_t *table;
41
+    const int8_t *table;
42
+
43
+    /* buffer used to store the whole audio decoded/interleaved chunk,
44
+     * which is sent with the first packet */
45
+    uint8_t *samples;
46
+    size_t samples_size;
47
+    int samples_idx;
43 48
 } EightSvxContext;
44 49
 
45
-static const int16_t fibonacci[16]   = { -34<<8, -21<<8, -13<<8,  -8<<8, -5<<8, -3<<8, -2<<8, -1<<8,
46
-                                          0, 1<<8, 2<<8, 3<<8, 5<<8, 8<<8, 13<<8, 21<<8 };
47
-static const int16_t exponential[16] = { -128<<8, -64<<8, -32<<8, -16<<8, -8<<8, -4<<8, -2<<8, -1<<8,
48
-                                          0, 1<<8, 2<<8, 4<<8, 8<<8, 16<<8, 32<<8, 64<<8 };
50
+static const int8_t fibonacci[16]   = { -34,  -21, -13,  -8, -5, -3, -2, -1, 0, 1, 2, 3, 5, 8,  13, 21 };
51
+static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64 };
52
+
53
+#define MAX_FRAME_SIZE 2048
54
+
55
+/**
56
+ * Interleave samples in buffer containing all left channel samples
57
+ * at the beginning, and right channel samples at the end.
58
+ * Each sample is assumed to be in signed 8-bit format.
59
+ *
60
+ * @param size the size in bytes of the dst and src buffer
61
+ */
62
+static void interleave_stereo(uint8_t *dst, const uint8_t *src, int size)
63
+{
64
+    uint8_t *dst_end = dst + size;
65
+    size = size>>1;
66
+
67
+    while (dst < dst_end) {
68
+        *dst++ = *src;
69
+        *dst++ = *(src+size);
70
+        src++;
71
+    }
72
+}
73
+
74
+/**
75
+ * Delta decode the compressed values in src, and put the resulting
76
+ * decoded n samples in dst.
77
+ *
78
+ * @param val starting value assumed by the delta sequence
79
+ * @param table delta sequence table
80
+ * @return size in bytes of the decoded data, must be src_size*2
81
+ */
82
+static int delta_decode(int8_t *dst, const uint8_t *src, int src_size,
83
+                        int8_t val, const int8_t *table)
84
+{
85
+    int n = src_size;
86
+    int8_t *dst0 = dst;
87
+
88
+    while (n--) {
89
+        uint8_t d = *src++;
90
+        val = av_clip(val + table[d & 0x0f], -127, 128);
91
+        *dst++ = val;
92
+        val = av_clip(val + table[d >> 4]  , -127, 128);
93
+        *dst++ = val;
94
+    }
95
+
96
+    return dst-dst0;
97
+}
49 98
 
50 99
 static int eightsvx_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
51 100
                                  AVPacket *avpkt)
52 101
 {
53
-    const uint8_t *buf = avpkt->data;
54
-    int buf_size = avpkt->size;
55 102
     EightSvxContext *esc = avctx->priv_data;
56
-    int16_t *out_data = data;
57
-    int consumed = buf_size;
58
-    const uint8_t *buf_end = buf + buf_size;
103
+    int out_data_size, n;
104
+    uint8_t *src, *dst;
59 105
 
60
-    if((*data_size >> 2) < buf_size)
61
-        return -1;
106
+    /* decode and interleave the first packet */
107
+    if (!esc->samples && avpkt) {
108
+        uint8_t *deinterleaved_samples;
62 109
 
63
-    if(avctx->frame_number == 0) {
64
-        esc->fib_acc = buf[1] << 8;
65
-        buf_size -= 2;
66
-        buf += 2;
67
-    }
110
+        esc->samples_size = avctx->codec->id == CODEC_ID_8SVX_RAW ?
111
+            avpkt->size : avctx->channels + (avpkt->size-avctx->channels) * 2;
112
+        if (!(esc->samples = av_malloc(esc->samples_size)))
113
+            return AVERROR(ENOMEM);
68 114
 
69
-    *data_size = buf_size << 2;
115
+        /* decompress */
116
+        if (avctx->codec->id == CODEC_ID_8SVX_FIB || avctx->codec->id == CODEC_ID_8SVX_EXP) {
117
+            const uint8_t *buf = avpkt->data;
118
+            int buf_size = avpkt->size;
119
+            int n = esc->samples_size;
70 120
 
71
-    while(buf < buf_end) {
72
-        uint8_t d = *buf++;
73
-        esc->fib_acc += esc->table[d & 0x0f];
74
-        *out_data++ = esc->fib_acc;
75
-        esc->fib_acc += esc->table[d >> 4];
76
-        *out_data++ = esc->fib_acc;
121
+            if (!(deinterleaved_samples = av_mallocz(n)))
122
+                return AVERROR(ENOMEM);
123
+
124
+            /* the uncompressed starting value is contained in the first byte */
125
+            if (avctx->channels == 2) {
126
+                delta_decode(deinterleaved_samples      , buf+1, buf_size/2-1, buf[0], esc->table);
127
+                buf += buf_size/2;
128
+                delta_decode(deinterleaved_samples+n/2-1, buf+1, buf_size/2-1, buf[0], esc->table);
129
+            } else
130
+                delta_decode(deinterleaved_samples      , buf+1, buf_size-1  , buf[0], esc->table);
131
+        } else {
132
+            deinterleaved_samples = avpkt->data;
133
+        }
134
+
135
+        if (avctx->channels == 2)
136
+            interleave_stereo(esc->samples, deinterleaved_samples, esc->samples_size);
137
+        else
138
+            memcpy(esc->samples, deinterleaved_samples, esc->samples_size);
77 139
     }
78 140
 
79
-    return consumed;
141
+    /* return single packed with fixed size */
142
+    out_data_size = FFMIN(MAX_FRAME_SIZE, esc->samples_size - esc->samples_idx);
143
+    if (*data_size < out_data_size) {
144
+        av_log(avctx, AV_LOG_ERROR, "Provided buffer with size %d is too small.\n", *data_size);
145
+        return AVERROR(EINVAL);
146
+    }
147
+
148
+    *data_size = out_data_size;
149
+    dst = data;
150
+    src = esc->samples + esc->samples_idx;
151
+    for (n = out_data_size; n > 0; n--)
152
+        *dst++ = *src++ + 128;
153
+    esc->samples_idx += *data_size;
154
+
155
+    return avctx->codec->id == CODEC_ID_8SVX_FIB || avctx->codec->id == CODEC_ID_8SVX_EXP ?
156
+        (avctx->frame_number == 0)*2 + out_data_size / 2 :
157
+        out_data_size;
80 158
 }
81 159
 
82 160
 static av_cold int eightsvx_decode_init(AVCodecContext *avctx)
83 161
 {
84 162
     EightSvxContext *esc = avctx->priv_data;
85 163
 
86
-    switch(avctx->codec->id) {
87
-        case CODEC_ID_8SVX_FIB:
88
-          esc->table = fibonacci;
89
-          break;
90
-        case CODEC_ID_8SVX_EXP:
91
-          esc->table = exponential;
92
-          break;
93
-        default:
94
-          return -1;
164
+    if (avctx->channels > 2) {
165
+        av_log(avctx, AV_LOG_ERROR, "8SVX does not support more than 2 channels\n");
166
+        return AVERROR_INVALIDDATA;
95 167
     }
96
-    avctx->sample_fmt = AV_SAMPLE_FMT_S16;
168
+
169
+    switch (avctx->codec->id) {
170
+    case CODEC_ID_8SVX_FIB: esc->table = fibonacci;    break;
171
+    case CODEC_ID_8SVX_EXP: esc->table = exponential;  break;
172
+    case CODEC_ID_8SVX_RAW: esc->table = NULL;         break;
173
+    default:
174
+        av_log(avctx, AV_LOG_ERROR, "Invalid codec id %d.\n", avctx->codec->id);
175
+        return AVERROR_INVALIDDATA;
176
+    }
177
+    avctx->sample_fmt = AV_SAMPLE_FMT_U8;
178
+
179
+    return 0;
180
+}
181
+
182
+static av_cold int eightsvx_decode_close(AVCodecContext *avctx)
183
+{
184
+    EightSvxContext *esc = avctx->priv_data;
185
+
186
+    av_freep(&esc->samples);
187
+    esc->samples_size = 0;
188
+    esc->samples_idx = 0;
189
+
97 190
     return 0;
98 191
 }
99 192
 
... ...
@@ -104,6 +198,7 @@ AVCodec ff_eightsvx_fib_decoder = {
104 104
   .priv_data_size = sizeof (EightSvxContext),
105 105
   .init           = eightsvx_decode_init,
106 106
   .decode         = eightsvx_decode_frame,
107
+  .close          = eightsvx_decode_close,
107 108
   .long_name      = NULL_IF_CONFIG_SMALL("8SVX fibonacci"),
108 109
 };
109 110
 
... ...
@@ -114,5 +209,17 @@ AVCodec ff_eightsvx_exp_decoder = {
114 114
   .priv_data_size = sizeof (EightSvxContext),
115 115
   .init           = eightsvx_decode_init,
116 116
   .decode         = eightsvx_decode_frame,
117
+  .close          = eightsvx_decode_close,
117 118
   .long_name      = NULL_IF_CONFIG_SMALL("8SVX exponential"),
118 119
 };
120
+
121
+AVCodec ff_eightsvx_raw_decoder = {
122
+  .name           = "8svx_raw",
123
+  .type           = AVMEDIA_TYPE_AUDIO,
124
+  .id             = CODEC_ID_8SVX_RAW,
125
+  .priv_data_size = sizeof(EightSvxContext),
126
+  .init           = eightsvx_decode_init,
127
+  .decode         = eightsvx_decode_frame,
128
+  .close          = eightsvx_decode_close,
129
+  .long_name      = NULL_IF_CONFIG_SMALL("8SVX rawaudio"),
130
+};
... ...
@@ -136,6 +136,7 @@ OBJS-$(CONFIG_EATQI_DECODER)           += eatqi.o eaidct.o mpeg12.o \
136 136
 OBJS-$(CONFIG_EIGHTBPS_DECODER)        += 8bps.o
137 137
 OBJS-$(CONFIG_EIGHTSVX_EXP_DECODER)    += 8svx.o
138 138
 OBJS-$(CONFIG_EIGHTSVX_FIB_DECODER)    += 8svx.o
139
+OBJS-$(CONFIG_EIGHTSVX_RAW_DECODER)    += 8svx.o
139 140
 OBJS-$(CONFIG_ESCAPE124_DECODER)       += escape124.o
140 141
 OBJS-$(CONFIG_FFV1_DECODER)            += ffv1.o rangecoder.o
141 142
 OBJS-$(CONFIG_FFV1_ENCODER)            += ffv1.o rangecoder.o
... ...
@@ -104,6 +104,7 @@ void avcodec_register_all(void)
104 104
     REGISTER_DECODER (EIGHTBPS, eightbps);
105 105
     REGISTER_DECODER (EIGHTSVX_EXP, eightsvx_exp);
106 106
     REGISTER_DECODER (EIGHTSVX_FIB, eightsvx_fib);
107
+    REGISTER_DECODER (EIGHTSVX_RAW, eightsvx_raw);
107 108
     REGISTER_DECODER (ESCAPE124, escape124);
108 109
     REGISTER_ENCDEC  (FFV1, ffv1);
109 110
     REGISTER_ENCDEC  (FFVHUFF, ffvhuff);
... ...
@@ -204,6 +204,7 @@ enum CodecID {
204 204
     CODEC_ID_PRORES,
205 205
     CODEC_ID_JV,
206 206
     CODEC_ID_DFA,
207
+    CODEC_ID_8SVX_RAW,
207 208
 
208 209
     /* various PCM "codecs" */
209 210
     CODEC_ID_PCM_S16LE= 0x10000,
... ...
@@ -21,7 +21,7 @@
21 21
 #define AVCODEC_VERSION_H
22 22
 
23 23
 #define LIBAVCODEC_VERSION_MAJOR 53
24
-#define LIBAVCODEC_VERSION_MINOR  5
24
+#define LIBAVCODEC_VERSION_MINOR  6
25 25
 #define LIBAVCODEC_VERSION_MICRO  0
26 26
 
27 27
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
... ...
@@ -60,8 +60,6 @@
60 60
 #define RIGHT   4
61 61
 #define STEREO  6
62 62
 
63
-#define PACKET_SIZE 1024
64
-
65 63
 /**
66 64
  * This number of bytes if added at the beginning of each AVPacket
67 65
  * which contain additional information about video properties
... ...
@@ -97,19 +95,6 @@ typedef struct {
97 97
     unsigned  masking;      ///< masking method used
98 98
 } IffDemuxContext;
99 99
 
100
-
101
-static void interleave_stereo(const uint8_t *src, uint8_t *dest, int size)
102
-{
103
-    uint8_t *end = dest + size;
104
-    size = size>>1;
105
-
106
-    while(dest < end) {
107
-        *dest++ = *src;
108
-        *dest++ = *(src+size);
109
-        src++;
110
-    }
111
-}
112
-
113 100
 /* Metadata string read */
114 101
 static int get_metadata(AVFormatContext *s,
115 102
                         const char *const tag,
... ...
@@ -255,7 +240,7 @@ static int iff_read_header(AVFormatContext *s,
255 255
 
256 256
         switch (iff->svx8_compression) {
257 257
         case COMP_NONE:
258
-            st->codec->codec_id = CODEC_ID_PCM_S8;
258
+            st->codec->codec_id = CODEC_ID_8SVX_RAW;
259 259
             break;
260 260
         case COMP_FIB:
261 261
             st->codec->codec_id = CODEC_ID_8SVX_FIB;
... ...
@@ -330,15 +315,8 @@ static int iff_read_packet(AVFormatContext *s,
330 330
     if(iff->sent_bytes >= iff->body_size)
331 331
         return AVERROR(EIO);
332 332
 
333
-    if(st->codec->channels == 2) {
334
-        uint8_t sample_buffer[PACKET_SIZE];
335
-
336
-        ret = avio_read(pb, sample_buffer, PACKET_SIZE);
337
-        if(av_new_packet(pkt, PACKET_SIZE) < 0) {
338
-            av_log(s, AV_LOG_ERROR, "cannot allocate packet\n");
339
-            return AVERROR(ENOMEM);
340
-        }
341
-        interleave_stereo(sample_buffer, pkt->data, PACKET_SIZE);
333
+    if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
334
+        ret = av_get_packet(pb, pkt, iff->body_size);
342 335
     } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
343 336
         uint8_t *buf;
344 337
 
... ...
@@ -349,23 +327,13 @@ static int iff_read_packet(AVFormatContext *s,
349 349
         buf = pkt->data;
350 350
         bytestream_put_be16(&buf, 2);
351 351
         ret = avio_read(pb, buf, iff->body_size);
352
-    } else {
353
-        ret = av_get_packet(pb, pkt, PACKET_SIZE);
354 352
     }
355 353
 
356 354
     if(iff->sent_bytes == 0)
357 355
         pkt->flags |= AV_PKT_FLAG_KEY;
356
+    iff->sent_bytes = iff->body_size;
358 357
 
359
-    if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
360
-        iff->sent_bytes += PACKET_SIZE;
361
-    } else {
362
-        iff->sent_bytes = iff->body_size;
363
-    }
364 358
     pkt->stream_index = 0;
365
-    if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
366
-        pkt->pts = iff->audio_frame_count;
367
-        iff->audio_frame_count += ret / st->codec->channels;
368
-    }
369 359
     return ret;
370 360
 }
371 361
 
... ...
@@ -1 +1 @@
1
-e968a853779bb6438339e3b8d69d8d24
1
+e76b025238a6a27968f8644f4ccc3207