New demuxers: Sega FILM/CPK, Westwood VQA & AUD; new decoders: MS RLE &
[ffmpeg.git] / libavcodec / cinepak.c
1 /*
2  * Cinepak Video Decoder
3  * Copyright (C) 2003 the ffmpeg project
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 /**
22  * @file cinepak.c
23  * Cinepak video decoder
24  * by Ewald Snel <ewald@rambo.its.tudelft.nl>
25  * For more information on the Cinepak algorithm, visit:
26  *   http://www.csse.monash.edu.au/~timf/
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include "common.h"
35 #include "avcodec.h"
36 #include "dsputil.h"
37
38 #define PALETTE_COUNT 256
39
40 #define BE_16(x)  ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])
41 #define BE_32(x)  ((((uint8_t*)(x))[0] << 24) | \
42                    (((uint8_t*)(x))[1] << 16) | \
43                    (((uint8_t*)(x))[2] << 8) | \
44                     ((uint8_t*)(x))[3])
45
46 typedef struct {
47     uint8_t  y0, y1, y2, y3;
48     uint8_t  u, v;
49 } cvid_codebook_t;
50
51 #define MAX_STRIPS      32
52
53 typedef struct {
54     uint16_t          id;
55     uint16_t          x1, y1;
56     uint16_t          x2, y2;
57     cvid_codebook_t   v4_codebook[256];
58     cvid_codebook_t   v1_codebook[256];
59 } cvid_strip_t;
60
61 typedef struct CinepakContext {
62
63     AVCodecContext *avctx;
64     DSPContext dsp;
65     AVFrame frame;
66     AVFrame prev_frame;
67
68     unsigned char *data;
69     int size;
70
71     unsigned char palette[PALETTE_COUNT * 4];
72     int palette_video;
73     cvid_strip_t strips[MAX_STRIPS];
74
75 } CinepakContext;
76
77 static void cinepak_decode_codebook (cvid_codebook_t *codebook,
78                                      int chunk_id, int size, uint8_t *data)
79 {
80     uint8_t *eod = (data + size);
81     uint32_t flag, mask;
82     int      i, n;
83
84     /* check if this chunk contains 4- or 6-element vectors */
85     n    = (chunk_id & 0x0400) ? 4 : 6;
86     flag = 0;
87     mask = 0;
88
89     for (i=0; i < 256; i++) {
90         if ((chunk_id & 0x0100) && !(mask >>= 1)) {
91             if ((data + 4) > eod)
92                 break;
93
94             flag  = BE_32 (data);
95             data += 4;
96             mask  = 0x80000000;
97         }
98
99         if (!(chunk_id & 0x0100) || (flag & mask)) {
100             if ((data + n) > eod)
101                 break;
102
103             if (n == 6) {
104                 codebook[i].y0 = *data++;
105                 codebook[i].y1 = *data++;
106                 codebook[i].y2 = *data++;
107                 codebook[i].y3 = *data++;
108                 codebook[i].u  = 128 + *data++;
109                 codebook[i].v  = 128 + *data++;
110             } else {
111                 /* this codebook type indicates either greyscale or 
112                  * palettized video; if palettized, U & V components will
113                  * not be used so it is safe to set them to 128 for the
114                  * benefit of greyscale rendering in YUV420P */
115                 codebook[i].y0 = *data++;
116                 codebook[i].y1 = *data++;
117                 codebook[i].y2 = *data++;
118                 codebook[i].y3 = *data++;
119                 codebook[i].u  = 128;
120                 codebook[i].v  = 128;
121             }
122         }
123     }
124 }
125
126 static int cinepak_decode_vectors (CinepakContext *s, cvid_strip_t *strip,
127                                    int chunk_id, int size, uint8_t *data)
128 {
129     uint8_t         *eod = (data + size);
130     uint32_t         flag, mask;
131     cvid_codebook_t *codebook;
132     unsigned int     i, j, x, y;
133     uint32_t         iy[4];
134     uint32_t         iu[2];
135     uint32_t         iv[2];
136
137     flag = 0;
138     mask = 0;
139
140     for (y=strip->y1; y < strip->y2; y+=4) {
141
142         iy[0] = strip->x1 + (y * s->frame.linesize[0]);
143         iy[1] = iy[0] + s->frame.linesize[0];
144         iy[2] = iy[1] + s->frame.linesize[0];
145         iy[3] = iy[2] + s->frame.linesize[0];
146         iu[0] = (strip->x1/2) + ((y/2) * s->frame.linesize[1]);
147         iu[1] = iu[0] + s->frame.linesize[1];
148         iv[0] = (strip->x1/2) + ((y/2) * s->frame.linesize[2]);
149         iv[1] = iv[0] + s->frame.linesize[2];
150
151         for (x=strip->x1; x < strip->x2; x+=4) {
152             if ((chunk_id & 0x0100) && !(mask >>= 1)) {
153                 if ((data + 4) > eod)
154                     return -1;
155
156                 flag  = BE_32 (data);
157                 data += 4;
158                 mask  = 0x80000000;
159             }
160
161             if (!(chunk_id & 0x0100) || (flag & mask)) {
162                 if (!(chunk_id & 0x0200) && !(mask >>= 1)) {
163                     if ((data + 4) > eod)
164                         return -1;
165
166                     flag  = BE_32 (data);
167                     data += 4;
168                     mask  = 0x80000000;
169                 }
170
171                 if ((chunk_id & 0x0200) || (~flag & mask)) {
172                     if (data >= eod)
173                         return -1;
174
175                     codebook = &strip->v1_codebook[*data++];
176                     s->frame.data[0][iy[0] + 0] = codebook->y0;
177                     s->frame.data[0][iy[0] + 1] = codebook->y0;
178                     s->frame.data[0][iy[1] + 0] = codebook->y0;
179                     s->frame.data[0][iy[1] + 1] = codebook->y0;
180                     if (!s->palette_video) {
181                         s->frame.data[1][iu[0]] = codebook->u;
182                         s->frame.data[2][iv[0]] = codebook->v;
183                     }
184
185                     s->frame.data[0][iy[0] + 2] = codebook->y0;
186                     s->frame.data[0][iy[0] + 3] = codebook->y0;
187                     s->frame.data[0][iy[1] + 2] = codebook->y0;
188                     s->frame.data[0][iy[1] + 3] = codebook->y0;
189                     if (!s->palette_video) {
190                         s->frame.data[1][iu[0] + 1] = codebook->u;
191                         s->frame.data[2][iv[0] + 1] = codebook->v;
192                     }
193
194                     s->frame.data[0][iy[2] + 0] = codebook->y0;
195                     s->frame.data[0][iy[2] + 1] = codebook->y0;
196                     s->frame.data[0][iy[3] + 0] = codebook->y0;
197                     s->frame.data[0][iy[3] + 1] = codebook->y0;
198                     if (!s->palette_video) {
199                         s->frame.data[1][iu[1]] = codebook->u;
200                         s->frame.data[2][iv[1]] = codebook->v;
201                     }
202
203                     s->frame.data[0][iy[2] + 2] = codebook->y0;
204                     s->frame.data[0][iy[2] + 3] = codebook->y0;
205                     s->frame.data[0][iy[3] + 2] = codebook->y0;
206                     s->frame.data[0][iy[3] + 3] = codebook->y0;
207                     if (!s->palette_video) {
208                         s->frame.data[1][iu[1] + 1] = codebook->u;
209                         s->frame.data[2][iv[1] + 1] = codebook->v;
210                     }
211
212                 } else if (flag & mask) {
213                     if ((data + 4) > eod)
214                         return -1;
215
216                     codebook = &strip->v4_codebook[*data++];
217                     s->frame.data[0][iy[0] + 0] = codebook->y0;
218                     s->frame.data[0][iy[0] + 1] = codebook->y1;
219                     s->frame.data[0][iy[1] + 0] = codebook->y2;
220                     s->frame.data[0][iy[1] + 1] = codebook->y3;
221                     if (!s->palette_video) {
222                         s->frame.data[1][iu[0]] = codebook->u;
223                         s->frame.data[2][iv[0]] = codebook->v;
224                     }
225
226                     codebook = &strip->v4_codebook[*data++];
227                     s->frame.data[0][iy[0] + 2] = codebook->y0;
228                     s->frame.data[0][iy[0] + 3] = codebook->y1;
229                     s->frame.data[0][iy[1] + 2] = codebook->y2;
230                     s->frame.data[0][iy[1] + 3] = codebook->y3;
231                     if (!s->palette_video) {
232                         s->frame.data[1][iu[0] + 1] = codebook->u;
233                         s->frame.data[2][iv[0] + 1] = codebook->v;
234                     }
235
236                     codebook = &strip->v4_codebook[*data++];
237                     s->frame.data[0][iy[2] + 0] = codebook->y0;
238                     s->frame.data[0][iy[2] + 1] = codebook->y1;
239                     s->frame.data[0][iy[3] + 0] = codebook->y2;
240                     s->frame.data[0][iy[3] + 1] = codebook->y3;
241                     if (!s->palette_video) {
242                         s->frame.data[1][iu[1]] = codebook->u;
243                         s->frame.data[2][iv[1]] = codebook->v;
244                     }
245
246                     codebook = &strip->v4_codebook[*data++];
247                     s->frame.data[0][iy[2] + 2] = codebook->y0;
248                     s->frame.data[0][iy[2] + 3] = codebook->y1;
249                     s->frame.data[0][iy[3] + 2] = codebook->y2;
250                     s->frame.data[0][iy[3] + 3] = codebook->y3;
251                     if (!s->palette_video) {
252                         s->frame.data[1][iu[1] + 1] = codebook->u;
253                         s->frame.data[2][iv[1] + 1] = codebook->v;
254                     }
255
256                 }
257             } else {
258                 /* copy from the previous frame */
259                 for (i = 0; i < 4; i++) {
260                     for (j = 0; j < 4; j++) {
261                         s->frame.data[0][iy[i] + j] =
262                             s->prev_frame.data[0][iy[i] + j];
263                     }
264                 }
265                 for (i = 0; i < 2; i++) {
266                     for (j = 0; j < 2; j++) {
267                         s->frame.data[1][iu[i] + j] =
268                             s->prev_frame.data[1][iu[i] + j];
269                         s->frame.data[2][iv[i] + j] =
270                             s->prev_frame.data[2][iv[i] + j];
271                     }
272                 }
273             }
274
275             iy[0] += 4;  iy[1] += 4;
276             iy[2] += 4;  iy[3] += 4;
277             iu[0] += 2;  iu[1] += 2;
278             iv[0] += 2;  iv[1] += 2;
279         }
280     }
281
282     return 0;
283 }
284
285 static int cinepak_decode_strip (CinepakContext *s,
286                                  cvid_strip_t *strip, uint8_t *data, int size)
287 {
288     uint8_t *eod = (data + size);
289     int      chunk_id, chunk_size;
290
291     /* coordinate sanity checks */
292     if (strip->x1 >= s->avctx->width  || strip->x2 > s->avctx->width  ||
293         strip->y1 >= s->avctx->height || strip->y2 > s->avctx->height ||
294         strip->x1 >= strip->x2        || strip->y1 >= strip->y2)
295         return -1;
296
297     while ((data + 4) <= eod) {
298         chunk_id   = BE_16 (&data[0]);
299         chunk_size = BE_16 (&data[2]) - 4;
300         data      += 4;
301         chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size;
302
303         switch (chunk_id) {
304
305         case 0x2000:
306         case 0x2100:
307         case 0x2400:
308         case 0x2500:
309             cinepak_decode_codebook (strip->v4_codebook, chunk_id, 
310                 chunk_size, data);
311             break;
312
313         case 0x2200:
314         case 0x2300:
315         case 0x2600:
316         case 0x2700:
317             cinepak_decode_codebook (strip->v1_codebook, chunk_id, 
318                 chunk_size, data);
319             break;
320
321         case 0x3000:
322         case 0x3100:
323         case 0x3200:
324             return cinepak_decode_vectors (s, strip, chunk_id, 
325                 chunk_size, data);
326         }
327
328         data += chunk_size;
329     }
330
331     return -1;
332 }
333
334 static int cinepak_decode (CinepakContext *s)
335 {
336     uint8_t      *eod = (s->data + s->size);
337     int           i, result, strip_size, frame_flags, num_strips;
338     int           y0 = 0;
339
340     if (s->size < 10)
341         return -1;
342
343     frame_flags = s->data[0];
344     num_strips  = BE_16 (&s->data[8]);
345     s->data    += 10;
346
347     if (num_strips > MAX_STRIPS)
348         num_strips = MAX_STRIPS;
349
350     for (i=0; i < num_strips; i++) {
351         if ((s->data + 12) > eod)
352             return -1;
353
354         s->strips[i].id = BE_16 (s->data);
355         s->strips[i].y1 = y0;
356         s->strips[i].x1 = 0;
357         s->strips[i].y2 = y0 + BE_16 (&s->data[8]);
358         s->strips[i].x2 = s->avctx->width;
359
360         strip_size = BE_16 (&s->data[2]) - 12;
361         s->data   += 12;
362         strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size;
363
364         if ((i > 0) && !(frame_flags & 0x01)) {
365             memcpy (s->strips[i].v4_codebook, s->strips[i-1].v4_codebook,
366                 sizeof(s->strips[i].v4_codebook));
367             memcpy (s->strips[i].v1_codebook, s->strips[i-1].v1_codebook,
368                 sizeof(s->strips[i].v1_codebook));
369         }
370
371         result = cinepak_decode_strip (s, &s->strips[i], s->data, strip_size);
372
373         if (result != 0)
374             return result;
375
376         s->data += strip_size;
377         y0    = s->strips[i].y2;
378     }
379     return 0;
380 }
381
382 static int cinepak_decode_init(AVCodecContext *avctx)
383 {
384     CinepakContext *s = (CinepakContext *)avctx->priv_data;
385 /*
386     int i;
387     unsigned char r, g, b;
388     unsigned char *raw_palette;
389     unsigned int *palette32;
390 */
391
392     s->avctx = avctx;
393
394 // check for paletted data
395 s->palette_video = 0;
396
397
398     avctx->pix_fmt = PIX_FMT_YUV420P;
399     avctx->has_b_frames = 0;
400     dsputil_init(&s->dsp, avctx);
401
402     s->frame.data[0] = s->prev_frame.data[0] = NULL;
403
404     return 0;
405 }
406
407 static int cinepak_decode_frame(AVCodecContext *avctx,
408                                 void *data, int *data_size,
409                                 uint8_t *buf, int buf_size)
410 {
411     CinepakContext *s = (CinepakContext *)avctx->priv_data;
412
413     s->data = buf;
414     s->size = buf_size;
415
416     if (avctx->get_buffer(avctx, &s->frame)) {
417         printf ("  Cinepak: get_buffer() failed\n");
418         return -1;
419     }
420
421     cinepak_decode(s);
422
423     if (s->prev_frame.data[0])
424         avctx->release_buffer(avctx, &s->prev_frame);
425
426     /* shuffle frames */
427     s->prev_frame = s->frame;
428
429     *data_size = sizeof(AVFrame);
430     *(AVFrame*)data = s->frame;
431
432     /* report that the buffer was completely consumed */
433     return buf_size;
434 }
435
436 static int cinepak_decode_end(AVCodecContext *avctx)
437 {
438     CinepakContext *s = (CinepakContext *)avctx->priv_data;
439
440     if (s->prev_frame.data[0])
441         avctx->release_buffer(avctx, &s->prev_frame);
442
443     return 0;
444 }
445
446 AVCodec cinepak_decoder = {
447     "cinepak",
448     CODEC_TYPE_VIDEO,
449     CODEC_ID_CINEPAK,
450     sizeof(CinepakContext),
451     cinepak_decode_init,
452     NULL,
453     cinepak_decode_end,
454     cinepak_decode_frame,
455     CODEC_CAP_DR1,
456 };