]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavcodec/xan.c
Avoid some code duplication in xan_unpack
[frescor/ffmpeg.git] / libavcodec / xan.c
1 /*
2  * Wing Commander/Xan Video Decoder
3  * Copyright (C) 2003 the ffmpeg project
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 /**
23  * @file libavcodec/xan.c
24  * Xan video decoder for Wing Commander III computer game
25  * by Mario Brito (mbrito@student.dei.uc.pt)
26  * and Mike Melanson (melanson@pcisys.net)
27  *
28  * The xan_wc3 decoder outputs PAL8 data.
29  */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 #include "libavutil/intreadwrite.h"
37 #include "avcodec.h"
38 // for av_memcpy_backptr
39 #include "libavutil/lzo.h"
40
41 typedef struct XanContext {
42
43     AVCodecContext *avctx;
44     AVFrame last_frame;
45     AVFrame current_frame;
46
47     const unsigned char *buf;
48     int size;
49
50     /* scratch space */
51     unsigned char *buffer1;
52     int buffer1_size;
53     unsigned char *buffer2;
54     int buffer2_size;
55
56     int frame_size;
57
58 } XanContext;
59
60 static av_cold int xan_decode_init(AVCodecContext *avctx)
61 {
62     XanContext *s = avctx->priv_data;
63
64     s->avctx = avctx;
65     s->frame_size = 0;
66
67     if ((avctx->codec->id == CODEC_ID_XAN_WC3) &&
68         (s->avctx->palctrl == NULL)) {
69         av_log(avctx, AV_LOG_ERROR, " WC3 Xan video: palette expected.\n");
70         return -1;
71     }
72
73     avctx->pix_fmt = PIX_FMT_PAL8;
74
75     if(avcodec_check_dimensions(avctx, avctx->width, avctx->height))
76         return -1;
77
78     s->buffer1_size = avctx->width * avctx->height;
79     s->buffer1 = av_malloc(s->buffer1_size);
80     s->buffer2_size = avctx->width * avctx->height;
81     s->buffer2 = av_malloc(s->buffer2_size + 130);
82     if (!s->buffer1 || !s->buffer2)
83         return -1;
84
85     return 0;
86 }
87
88 static int xan_huffman_decode(unsigned char *dest, const unsigned char *src,
89     int dest_len)
90 {
91     unsigned char byte = *src++;
92     unsigned char ival = byte + 0x16;
93     const unsigned char * ptr = src + byte*2;
94     unsigned char val = ival;
95     int counter = 0;
96     unsigned char *dest_end = dest + dest_len;
97
98     unsigned char bits = *ptr++;
99
100     while ( val != 0x16 ) {
101         if ( (1 << counter) & bits )
102             val = src[byte + val - 0x17];
103         else
104             val = src[val - 0x17];
105
106         if ( val < 0x16 ) {
107             if (dest + 1 > dest_end)
108                 return 0;
109             *dest++ = val;
110             val = ival;
111         }
112
113         if (counter++ == 7) {
114             counter = 0;
115             bits = *ptr++;
116         }
117     }
118
119     return 0;
120 }
121
122 /**
123  * unpack simple compression
124  *
125  * @param dest destination buffer of dest_len, must be padded with at least 130 bytes
126  */
127 static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
128 {
129     unsigned char opcode;
130     int size;
131     int offset;
132     int byte1, byte2, byte3;
133     unsigned char *dest_end = dest + dest_len;
134
135     while (dest < dest_end) {
136         opcode = *src++;
137
138         if (opcode < 0xe0) {
139            int size2, back;
140         if ( (opcode & 0x80) == 0 ) {
141
142             offset = *src++;
143
144             size = opcode & 3;
145
146             size2 = ((opcode & 0x1c) >> 2) + 3;
147             back = ((opcode & 0x60) << 3) + offset + 1;
148
149         } else if ( (opcode & 0x40) == 0 ) {
150
151             byte1 = *src++;
152             byte2 = *src++;
153
154             size = byte1 >> 6;
155
156             size2 = (opcode & 0x3f) + 4;
157             back = ((byte1 & 0x3f) << 8) + byte2 + 1;
158
159         } else {
160
161             byte1 = *src++;
162             byte2 = *src++;
163             byte3 = *src++;
164
165             size = opcode & 3;
166
167             size2 = byte3 + 5 + ((opcode & 0xc) << 6);
168             back = ((opcode & 0x10) << 12) + 1 + (byte1 << 8) + byte2;
169             if (dest >= dest_end || size > dest_end - dest)
170                 return;
171             }
172             memcpy(dest, src, size);  dest += size;  src += size;
173             av_memcpy_backptr(dest, back, size2);
174             dest += size2;
175         } else {
176             size = ((opcode & 0x1f) << 2) + 4;
177
178             if (size > 0x70)
179                 break;
180
181             memcpy(dest, src, size);  dest += size;  src += size;
182         }
183     }
184
185     size = opcode & 3;
186     memcpy(dest, src, size);  dest += size;  src += size;
187 }
188
189 static inline void xan_wc3_output_pixel_run(XanContext *s,
190     const unsigned char *pixel_buffer, int x, int y, int pixel_count)
191 {
192     int stride;
193     int line_inc;
194     int index;
195     int current_x;
196     int width = s->avctx->width;
197     unsigned char *palette_plane;
198
199     palette_plane = s->current_frame.data[0];
200     stride = s->current_frame.linesize[0];
201     line_inc = stride - width;
202     index = y * stride + x;
203     current_x = x;
204     while((pixel_count--) && (index < s->frame_size)) {
205
206         /* don't do a memcpy() here; keyframes generally copy an entire
207          * frame of data and the stride needs to be accounted for */
208         palette_plane[index++] = *pixel_buffer++;
209
210         current_x++;
211         if (current_x >= width) {
212             index += line_inc;
213             current_x = 0;
214         }
215     }
216 }
217
218 static inline void xan_wc3_copy_pixel_run(XanContext *s,
219     int x, int y, int pixel_count, int motion_x, int motion_y)
220 {
221     int stride;
222     int line_inc;
223     int curframe_index, prevframe_index;
224     int curframe_x, prevframe_x;
225     int width = s->avctx->width;
226     unsigned char *palette_plane, *prev_palette_plane;
227
228     palette_plane = s->current_frame.data[0];
229     prev_palette_plane = s->last_frame.data[0];
230     stride = s->current_frame.linesize[0];
231     line_inc = stride - width;
232     curframe_index = y * stride + x;
233     curframe_x = x;
234     prevframe_index = (y + motion_y) * stride + x + motion_x;
235     prevframe_x = x + motion_x;
236     while((pixel_count--) && (curframe_index < s->frame_size)) {
237
238         palette_plane[curframe_index++] =
239             prev_palette_plane[prevframe_index++];
240
241         curframe_x++;
242         if (curframe_x >= width) {
243             curframe_index += line_inc;
244             curframe_x = 0;
245         }
246
247         prevframe_x++;
248         if (prevframe_x >= width) {
249             prevframe_index += line_inc;
250             prevframe_x = 0;
251         }
252     }
253 }
254
255 static void xan_wc3_decode_frame(XanContext *s) {
256
257     int width = s->avctx->width;
258     int height = s->avctx->height;
259     int total_pixels = width * height;
260     unsigned char opcode;
261     unsigned char flag = 0;
262     int size = 0;
263     int motion_x, motion_y;
264     int x, y;
265
266     unsigned char *opcode_buffer = s->buffer1;
267     int opcode_buffer_size = s->buffer1_size;
268     const unsigned char *imagedata_buffer = s->buffer2;
269
270     /* pointers to segments inside the compressed chunk */
271     const unsigned char *huffman_segment;
272     const unsigned char *size_segment;
273     const unsigned char *vector_segment;
274     const unsigned char *imagedata_segment;
275
276     huffman_segment =   s->buf + AV_RL16(&s->buf[0]);
277     size_segment =      s->buf + AV_RL16(&s->buf[2]);
278     vector_segment =    s->buf + AV_RL16(&s->buf[4]);
279     imagedata_segment = s->buf + AV_RL16(&s->buf[6]);
280
281     xan_huffman_decode(opcode_buffer, huffman_segment, opcode_buffer_size);
282
283     if (imagedata_segment[0] == 2)
284         xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
285     else
286         imagedata_buffer = &imagedata_segment[1];
287
288     /* use the decoded data segments to build the frame */
289     x = y = 0;
290     while (total_pixels) {
291
292         opcode = *opcode_buffer++;
293         size = 0;
294
295         switch (opcode) {
296
297         case 0:
298             flag ^= 1;
299             continue;
300
301         case 1:
302         case 2:
303         case 3:
304         case 4:
305         case 5:
306         case 6:
307         case 7:
308         case 8:
309             size = opcode;
310             break;
311
312         case 12:
313         case 13:
314         case 14:
315         case 15:
316         case 16:
317         case 17:
318         case 18:
319             size += (opcode - 10);
320             break;
321
322         case 9:
323         case 19:
324             size = *size_segment++;
325             break;
326
327         case 10:
328         case 20:
329             size = AV_RB16(&size_segment[0]);
330             size_segment += 2;
331             break;
332
333         case 11:
334         case 21:
335             size = AV_RB24(size_segment);
336             size_segment += 3;
337             break;
338         }
339
340         if (opcode < 12) {
341             flag ^= 1;
342             if (flag) {
343                 /* run of (size) pixels is unchanged from last frame */
344                 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
345             } else {
346                 /* output a run of pixels from imagedata_buffer */
347                 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
348                 imagedata_buffer += size;
349             }
350         } else {
351             /* run-based motion compensation from last frame */
352             motion_x = (*vector_segment >> 4) & 0xF;
353             motion_y = *vector_segment & 0xF;
354             vector_segment++;
355
356             /* sign extension */
357             if (motion_x & 0x8)
358                 motion_x |= 0xFFFFFFF0;
359             if (motion_y & 0x8)
360                 motion_y |= 0xFFFFFFF0;
361
362             /* copy a run of pixels from the previous frame */
363             xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
364
365             flag = 0;
366         }
367
368         /* coordinate accounting */
369         total_pixels -= size;
370         while (size) {
371             if (x + size >= width) {
372                 y++;
373                 size -= (width - x);
374                 x = 0;
375             } else {
376                 x += size;
377                 size = 0;
378             }
379         }
380     }
381 }
382
383 static void xan_wc4_decode_frame(XanContext *s) {
384 }
385
386 static int xan_decode_frame(AVCodecContext *avctx,
387                             void *data, int *data_size,
388                             AVPacket *avpkt)
389 {
390     const uint8_t *buf = avpkt->data;
391     int buf_size = avpkt->size;
392     XanContext *s = avctx->priv_data;
393     AVPaletteControl *palette_control = avctx->palctrl;
394
395     if (avctx->get_buffer(avctx, &s->current_frame)) {
396         av_log(s->avctx, AV_LOG_ERROR, "  Xan Video: get_buffer() failed\n");
397         return -1;
398     }
399     s->current_frame.reference = 3;
400
401     if (!s->frame_size)
402         s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
403
404     palette_control->palette_changed = 0;
405     memcpy(s->current_frame.data[1], palette_control->palette,
406         AVPALETTE_SIZE);
407     s->current_frame.palette_has_changed = 1;
408
409     s->buf = buf;
410     s->size = buf_size;
411
412     if (avctx->codec->id == CODEC_ID_XAN_WC3)
413         xan_wc3_decode_frame(s);
414     else if (avctx->codec->id == CODEC_ID_XAN_WC4)
415         xan_wc4_decode_frame(s);
416
417     /* release the last frame if it is allocated */
418     if (s->last_frame.data[0])
419         avctx->release_buffer(avctx, &s->last_frame);
420
421     *data_size = sizeof(AVFrame);
422     *(AVFrame*)data = s->current_frame;
423
424     /* shuffle frames */
425     FFSWAP(AVFrame, s->current_frame, s->last_frame);
426
427     /* always report that the buffer was completely consumed */
428     return buf_size;
429 }
430
431 static av_cold int xan_decode_end(AVCodecContext *avctx)
432 {
433     XanContext *s = avctx->priv_data;
434
435     /* release the frames */
436     if (s->last_frame.data[0])
437         avctx->release_buffer(avctx, &s->last_frame);
438     if (s->current_frame.data[0])
439         avctx->release_buffer(avctx, &s->current_frame);
440
441     av_free(s->buffer1);
442     av_free(s->buffer2);
443
444     return 0;
445 }
446
447 AVCodec xan_wc3_decoder = {
448     "xan_wc3",
449     CODEC_TYPE_VIDEO,
450     CODEC_ID_XAN_WC3,
451     sizeof(XanContext),
452     xan_decode_init,
453     NULL,
454     xan_decode_end,
455     xan_decode_frame,
456     CODEC_CAP_DR1,
457     .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
458 };
459
460 /*
461 AVCodec xan_wc4_decoder = {
462     "xan_wc4",
463     CODEC_TYPE_VIDEO,
464     CODEC_ID_XAN_WC4,
465     sizeof(XanContext),
466     xan_decode_init,
467     NULL,
468     xan_decode_end,
469     xan_decode_frame,
470     CODEC_CAP_DR1,
471 };
472 */