Browse code

Xan4 decoder

Signed-off-by: Ronald S. Bultje <rsbultje@gmail.com>
(cherry picked from commit 44ddfd47d671d2587903d94c8b565f68f45bd4bc)

Kostya Shishkov authored on 2011/02/05 07:41:07
Showing 6 changed files
... ...
@@ -74,6 +74,7 @@ version <next>:
74 74
 - Lagarith decoder
75 75
 - ffmpeg -copytb option added
76 76
 - IVF muxer added
77
+- Wing Commander IV movies decoder added
77 78
 
78 79
 
79 80
 version 0.6:
... ...
@@ -511,6 +511,8 @@ following image formats are supported:
511 511
     @tab not completely working
512 512
 @item Wing Commander III / Xan  @tab     @tab  X
513 513
     @tab Used in Wing Commander III .MVE files.
514
+@item Wing Commander IV / Xan  @tab     @tab  X
515
+    @tab Used in Wing Commander IV.
514 516
 @item Winnov WNV1            @tab     @tab  X
515 517
 @item WMV7                   @tab  X  @tab  X
516 518
 @item YAMAHA SMAF            @tab  X  @tab  X
... ...
@@ -415,7 +415,7 @@ OBJS-$(CONFIG_WNV1_DECODER)            += wnv1.o
415 415
 OBJS-$(CONFIG_WS_SND1_DECODER)         += ws-snd1.o
416 416
 OBJS-$(CONFIG_XAN_DPCM_DECODER)        += dpcm.o
417 417
 OBJS-$(CONFIG_XAN_WC3_DECODER)         += xan.o
418
-OBJS-$(CONFIG_XAN_WC4_DECODER)         += xan.o
418
+OBJS-$(CONFIG_XAN_WC4_DECODER)         += xxan.o
419 419
 OBJS-$(CONFIG_XL_DECODER)              += xl.o
420 420
 OBJS-$(CONFIG_XSUB_DECODER)            += xsubdec.o
421 421
 OBJS-$(CONFIG_XSUB_ENCODER)            += xsubenc.o
... ...
@@ -214,6 +214,7 @@ void avcodec_register_all(void)
214 214
     REGISTER_DECODER (WMV3_VDPAU, wmv3_vdpau);
215 215
     REGISTER_DECODER (WNV1, wnv1);
216 216
     REGISTER_DECODER (XAN_WC3, xan_wc3);
217
+    REGISTER_DECODER (XAN_WC4, xan_wc4);
217 218
     REGISTER_DECODER (XL, xl);
218 219
     REGISTER_DECODER (YOP, yop);
219 220
     REGISTER_ENCDEC  (ZLIB, zlib);
... ...
@@ -32,7 +32,7 @@
32 32
 #include "libavutil/cpu.h"
33 33
 
34 34
 #define LIBAVCODEC_VERSION_MAJOR 52
35
-#define LIBAVCODEC_VERSION_MINOR 109
35
+#define LIBAVCODEC_VERSION_MINOR 110
36 36
 #define LIBAVCODEC_VERSION_MICRO  0
37 37
 
38 38
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
39 39
new file mode 100644
... ...
@@ -0,0 +1,429 @@
0
+/*
1
+ * Wing Commander/Xan Video Decoder
2
+ * Copyright (C) 2011 Konstantin Shishkov
3
+ * based on work by Mike Melanson
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#include "avcodec.h"
23
+#include "libavutil/intreadwrite.h"
24
+#include "bytestream.h"
25
+#define ALT_BITSTREAM_READER_LE
26
+#include "get_bits.h"
27
+// for av_memcpy_backptr
28
+#include "libavutil/lzo.h"
29
+
30
+typedef struct XanContext {
31
+    AVCodecContext *avctx;
32
+    AVFrame pic;
33
+
34
+    uint8_t *y_buffer;
35
+    uint8_t *scratch_buffer;
36
+    int     buffer_size;
37
+} XanContext;
38
+
39
+static av_cold int xan_decode_init(AVCodecContext *avctx)
40
+{
41
+    XanContext *s = avctx->priv_data;
42
+
43
+    s->avctx = avctx;
44
+
45
+    avctx->pix_fmt = PIX_FMT_YUV420P;
46
+
47
+    s->buffer_size = avctx->width * avctx->height;
48
+    s->y_buffer = av_malloc(s->buffer_size);
49
+    if (!s->y_buffer)
50
+        return AVERROR(ENOMEM);
51
+    s->scratch_buffer = av_malloc(s->buffer_size + 130);
52
+    if (!s->scratch_buffer) {
53
+        av_freep(&s->y_buffer);
54
+        return AVERROR(ENOMEM);
55
+    }
56
+
57
+    return 0;
58
+}
59
+
60
+static int xan_unpack_luma(const uint8_t *src, const int src_size,
61
+                           uint8_t *dst, const int dst_size)
62
+{
63
+   int tree_size, eof;
64
+   const uint8_t *tree;
65
+   int bits, mask;
66
+   int tree_root, node;
67
+   const uint8_t *dst_end = dst + dst_size;
68
+   const uint8_t *src_end = src + src_size;
69
+
70
+   tree_size = *src++;
71
+   eof       = *src++;
72
+   tree      = src - eof * 2 - 2;
73
+   tree_root = eof + tree_size;
74
+   src += tree_size * 2;
75
+
76
+   node = tree_root;
77
+   bits = *src++;
78
+   mask = 0x80;
79
+   for (;;) {
80
+       int bit = !!(bits & mask);
81
+       mask >>= 1;
82
+       node = tree[node*2 + bit];
83
+       if (node == eof)
84
+           break;
85
+       if (node < eof) {
86
+           *dst++ = node;
87
+           if (dst > dst_end)
88
+               break;
89
+           node = tree_root;
90
+       }
91
+       if (!mask) {
92
+           bits = *src++;
93
+           if (src > src_end)
94
+               break;
95
+           mask = 0x80;
96
+       }
97
+   }
98
+   return dst != dst_end;
99
+}
100
+
101
+/* almost the same as in xan_wc3 decoder */
102
+static int xan_unpack(uint8_t *dest, const int dest_len,
103
+                      const uint8_t *src, const int src_len)
104
+{
105
+    uint8_t opcode;
106
+    int size;
107
+    uint8_t *orig_dest = dest;
108
+    const uint8_t *src_end = src + src_len;
109
+    const uint8_t *dest_end = dest + dest_len;
110
+
111
+    while (dest < dest_end) {
112
+        opcode = *src++;
113
+
114
+        if (opcode < 0xe0) {
115
+            int size2, back;
116
+            if ((opcode & 0x80) == 0) {
117
+                size  = opcode & 3;
118
+                back  = ((opcode & 0x60) << 3) + *src++ + 1;
119
+                size2 = ((opcode & 0x1c) >> 2) + 3;
120
+            } else if ((opcode & 0x40) == 0) {
121
+                size  = *src >> 6;
122
+                back  = (bytestream_get_be16(&src) & 0x3fff) + 1;
123
+                size2 = (opcode & 0x3f) + 4;
124
+            } else {
125
+                size  = opcode & 3;
126
+                back  = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
127
+                size2 = ((opcode & 0x0c) <<  6) + *src++ + 5;
128
+                if (size + size2 > dest_end - dest)
129
+                    break;
130
+            }
131
+            if (src + size > src_end || dest + size + size2 > dest_end)
132
+                return -1;
133
+            bytestream_get_buffer(&src, dest, size);
134
+            dest += size;
135
+            av_memcpy_backptr(dest, back, size2);
136
+            dest += size2;
137
+        } else {
138
+            int finish = opcode >= 0xfc;
139
+
140
+            size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
141
+            if (src + size > src_end || dest + size > dest_end)
142
+                return -1;
143
+            bytestream_get_buffer(&src, dest, size);
144
+            dest += size;
145
+            if (finish)
146
+                break;
147
+        }
148
+    }
149
+    return dest - orig_dest;
150
+}
151
+
152
+static int xan_decode_chroma(AVCodecContext *avctx, AVPacket *avpkt)
153
+{
154
+    const uint8_t *buf = avpkt->data;
155
+    XanContext *s = avctx->priv_data;
156
+    uint8_t *U, *V;
157
+    unsigned chroma_off;
158
+    int val, uval, vval;
159
+    int i, j;
160
+    const uint8_t *src, *src_end;
161
+    const uint8_t *table;
162
+    int mode, offset, dec_size;
163
+
164
+    chroma_off = AV_RL32(buf + 4);
165
+    if (!chroma_off)
166
+        return 0;
167
+    if (chroma_off + 10 >= avpkt->size) {
168
+        av_log(avctx, AV_LOG_ERROR, "Invalid chroma block position\n");
169
+        return -1;
170
+    }
171
+    src    = avpkt->data + 4 + chroma_off;
172
+    table  = src + 2;
173
+    mode   = bytestream_get_le16(&src);
174
+    offset = bytestream_get_le16(&src) * 2;
175
+
176
+    if (src - avpkt->data >= avpkt->size - offset) {
177
+        av_log(avctx, AV_LOG_ERROR, "Invalid chroma block offset\n");
178
+        return -1;
179
+    }
180
+
181
+    memset(s->scratch_buffer, 0, s->buffer_size);
182
+    dec_size = xan_unpack(s->scratch_buffer, s->buffer_size, src + offset,
183
+                          avpkt->size - offset - (src - avpkt->data));
184
+    if (dec_size < 0) {
185
+        av_log(avctx, AV_LOG_ERROR, "Chroma unpacking failed\n");
186
+        return -1;
187
+    }
188
+
189
+    U = s->pic.data[1];
190
+    V = s->pic.data[2];
191
+    src     = s->scratch_buffer;
192
+    src_end = src + dec_size;
193
+    if (mode) {
194
+        for (j = 0; j < avctx->height >> 1; j++) {
195
+            for (i = 0; i < avctx->width >> 1; i++) {
196
+                val = *src++;
197
+                if (val) {
198
+                    val  = AV_RL16(table + (val << 1));
199
+                    uval = (val >> 3) & 0xF8;
200
+                    vval = (val >> 8) & 0xF8;
201
+                    U[i] = uval | (uval >> 5);
202
+                    V[i] = vval | (vval >> 5);
203
+                }
204
+                if (src == src_end)
205
+                    return 0;
206
+            }
207
+            U += s->pic.linesize[1];
208
+            V += s->pic.linesize[2];
209
+        }
210
+    } else {
211
+        uint8_t *U2 = U + s->pic.linesize[1];
212
+        uint8_t *V2 = V + s->pic.linesize[2];
213
+
214
+        for (j = 0; j < avctx->height >> 2; j++) {
215
+            for (i = 0; i < avctx->width >> 1; i += 2) {
216
+                val = *src++;
217
+                if (val) {
218
+                    val  = AV_RL16(table + (val << 1));
219
+                    uval = (val >> 3) & 0xF8;
220
+                    vval = (val >> 8) & 0xF8;
221
+                    U[i] = U[i+1] = U2[i] = U2[i+1] = uval | (uval >> 5);
222
+                    V[i] = V[i+1] = V2[i] = V2[i+1] = vval | (vval >> 5);
223
+                }
224
+            }
225
+            U  += s->pic.linesize[1] * 2;
226
+            V  += s->pic.linesize[2] * 2;
227
+            U2 += s->pic.linesize[1] * 2;
228
+            V2 += s->pic.linesize[2] * 2;
229
+        }
230
+    }
231
+
232
+    return 0;
233
+}
234
+
235
+static int xan_decode_frame_type0(AVCodecContext *avctx, AVPacket *avpkt)
236
+{
237
+    const uint8_t *buf = avpkt->data;
238
+    XanContext *s = avctx->priv_data;
239
+    uint8_t *ybuf, *prev_buf, *src = s->scratch_buffer;
240
+    unsigned  chroma_off, corr_off;
241
+    int cur, last, size;
242
+    int i, j;
243
+    int ret;
244
+
245
+    corr_off   = AV_RL32(buf + 8);
246
+    chroma_off = AV_RL32(buf + 4);
247
+
248
+    if ((ret = xan_decode_chroma(avctx, avpkt)) != 0)
249
+        return ret;
250
+
251
+    size = avpkt->size - 4;
252
+    if (corr_off >= avpkt->size) {
253
+        av_log(avctx, AV_LOG_WARNING, "Ignoring invalid correction block position\n");
254
+        corr_off = 0;
255
+    }
256
+    if (corr_off)
257
+        size = corr_off;
258
+    if (chroma_off)
259
+        size = FFMIN(size, chroma_off);
260
+    ret = xan_unpack_luma(buf + 12, size, src, s->buffer_size >> 1);
261
+    if (ret) {
262
+        av_log(avctx, AV_LOG_ERROR, "Luma decoding failed\n");
263
+        return ret;
264
+    }
265
+
266
+    ybuf = s->y_buffer;
267
+    last = *src++;
268
+    ybuf[0] = last << 1;
269
+    for (j = 1; j < avctx->width - 1; j += 2) {
270
+        cur = (last + *src++) & 0x1F;
271
+        ybuf[j]   = last + cur;
272
+        ybuf[j+1] = cur << 1;
273
+        last = cur;
274
+    }
275
+    ybuf[j]  = last << 1;
276
+    prev_buf = ybuf;
277
+    ybuf += avctx->width;
278
+
279
+    for (i = 1; i < avctx->height; i++) {
280
+        last = ((prev_buf[0] >> 1) + *src++) & 0x1F;
281
+        ybuf[0] = last << 1;
282
+        for (j = 1; j < avctx->width - 1; j += 2) {
283
+            cur = ((prev_buf[j + 1] >> 1) + *src++) & 0x1F;
284
+            ybuf[j]   = last + cur;
285
+            ybuf[j+1] = cur << 1;
286
+            last = cur;
287
+        }
288
+        ybuf[j] = last << 1;
289
+        prev_buf = ybuf;
290
+        ybuf += avctx->width;
291
+    }
292
+
293
+    if (corr_off) {
294
+        int corr_end, dec_size;
295
+
296
+        corr_end = avpkt->size;
297
+        if (chroma_off > corr_off)
298
+            corr_end = chroma_off;
299
+        dec_size = xan_unpack(s->scratch_buffer, s->buffer_size,
300
+                              avpkt->data + 8 + corr_off,
301
+                              corr_end - corr_off);
302
+        if (dec_size < 0)
303
+            dec_size = 0;
304
+        for (i = 0; i < dec_size; i++)
305
+            s->y_buffer[i*2+1] = (s->y_buffer[i*2+1] + (s->scratch_buffer[i] << 1)) & 0x3F;
306
+    }
307
+
308
+    src  = s->y_buffer;
309
+    ybuf = s->pic.data[0];
310
+    for (j = 0; j < avctx->height; j++) {
311
+        for (i = 0; i < avctx->width; i++)
312
+            ybuf[i] = (src[i] << 2) | (src[i] >> 3);
313
+        src  += avctx->width;
314
+        ybuf += s->pic.linesize[0];
315
+    }
316
+
317
+    return 0;
318
+}
319
+
320
+static int xan_decode_frame_type1(AVCodecContext *avctx, AVPacket *avpkt)
321
+{
322
+    const uint8_t *buf = avpkt->data;
323
+    XanContext *s = avctx->priv_data;
324
+    uint8_t *ybuf, *src = s->scratch_buffer;
325
+    int cur, last;
326
+    int i, j;
327
+    int ret;
328
+
329
+    if ((ret = xan_decode_chroma(avctx, avpkt)) != 0)
330
+        return ret;
331
+
332
+    ret = xan_unpack_luma(buf + 16, avpkt->size - 16, src,
333
+                          s->buffer_size >> 1);
334
+    if (ret) {
335
+        av_log(avctx, AV_LOG_ERROR, "Luma decoding failed\n");
336
+        return ret;
337
+    }
338
+
339
+    ybuf = s->y_buffer;
340
+    for (i = 0; i < avctx->height; i++) {
341
+        last = (ybuf[0] + (*src++ << 1)) & 0x3F;
342
+        ybuf[0] = last;
343
+        for (j = 1; j < avctx->width - 1; j += 2) {
344
+            cur = (ybuf[j + 1] + (*src++ << 1)) & 0x3F;
345
+            ybuf[j]   = (last + cur) >> 1;
346
+            ybuf[j+1] = cur;
347
+            last = cur;
348
+        }
349
+        ybuf[j] = last;
350
+        ybuf += avctx->width;
351
+    }
352
+
353
+    src = s->y_buffer;
354
+    ybuf = s->pic.data[0];
355
+    for (j = 0; j < avctx->height; j++) {
356
+        for (i = 0; i < avctx->width; i++)
357
+            ybuf[i] = (src[i] << 2) | (src[i] >> 3);
358
+        src  += avctx->width;
359
+        ybuf += s->pic.linesize[0];
360
+    }
361
+
362
+    return 0;
363
+}
364
+
365
+static int xan_decode_frame(AVCodecContext *avctx,
366
+                            void *data, int *data_size,
367
+                            AVPacket *avpkt)
368
+{
369
+    XanContext *s = avctx->priv_data;
370
+    int ftype;
371
+    int ret;
372
+
373
+    s->pic.reference = 1;
374
+    s->pic.buffer_hints = FF_BUFFER_HINTS_VALID |
375
+                          FF_BUFFER_HINTS_PRESERVE |
376
+                          FF_BUFFER_HINTS_REUSABLE;
377
+    if ((ret = avctx->reget_buffer(avctx, &s->pic))) {
378
+        av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
379
+        return ret;
380
+    }
381
+
382
+    ftype = AV_RL32(avpkt->data);
383
+    switch (ftype) {
384
+    case 0:
385
+        ret = xan_decode_frame_type0(avctx, avpkt);
386
+        break;
387
+    case 1:
388
+        ret = xan_decode_frame_type1(avctx, avpkt);
389
+        break;
390
+    default:
391
+        av_log(avctx, AV_LOG_ERROR, "Unknown frame type %d\n", ftype);
392
+        return -1;
393
+    }
394
+    if (ret)
395
+        return ret;
396
+
397
+    *data_size = sizeof(AVFrame);
398
+    *(AVFrame*)data = s->pic;
399
+
400
+    return avpkt->size;
401
+}
402
+
403
+static av_cold int xan_decode_end(AVCodecContext *avctx)
404
+{
405
+    XanContext *s = avctx->priv_data;
406
+
407
+    if (s->pic.data[0])
408
+        avctx->release_buffer(avctx, &s->pic);
409
+
410
+    av_freep(&s->y_buffer);
411
+    av_freep(&s->scratch_buffer);
412
+
413
+    return 0;
414
+}
415
+
416
+AVCodec ff_xan_wc4_decoder = {
417
+    "xan_wc4",
418
+    AVMEDIA_TYPE_VIDEO,
419
+    CODEC_ID_XAN_WC4,
420
+    sizeof(XanContext),
421
+    xan_decode_init,
422
+    NULL,
423
+    xan_decode_end,
424
+    xan_decode_frame,
425
+    CODEC_CAP_DR1,
426
+    .long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"),
427
+};
428
+