2
* Cinepak Video Decoder
3
* Copyright (C) 2003 the ffmpeg project
5
* This file is part of FFmpeg.
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.
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.
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
25
* Cinepak video decoder
26
* by Ewald Snel <ewald@rambo.its.tudelft.nl>
27
* For more information on the Cinepak algorithm, visit:
28
* http://www.csse.monash.edu.au/~timf/
29
* For more information on the quirky data inside Sega FILM/CPK files, visit:
30
* http://wiki.multimedia.cx/index.php?title=Sega_FILM
44
uint8_t y0, y1, y2, y3;
54
cvid_codebook_t v4_codebook[256];
55
cvid_codebook_t v1_codebook[256];
58
typedef struct CinepakContext {
60
AVCodecContext *avctx;
70
cvid_strip_t strips[MAX_STRIPS];
72
int sega_film_skip_bytes;
76
static void cinepak_decode_codebook (cvid_codebook_t *codebook,
77
int chunk_id, int size, uint8_t *data)
79
uint8_t *eod = (data + size);
83
/* check if this chunk contains 4- or 6-element vectors */
84
n = (chunk_id & 0x0400) ? 4 : 6;
88
for (i=0; i < 256; i++) {
89
if ((chunk_id & 0x0100) && !(mask >>= 1)) {
93
flag = AV_RB32 (data);
98
if (!(chunk_id & 0x0100) || (flag & mask)) {
103
codebook[i].y0 = *data++;
104
codebook[i].y1 = *data++;
105
codebook[i].y2 = *data++;
106
codebook[i].y3 = *data++;
107
codebook[i].u = 128 + *data++;
108
codebook[i].v = 128 + *data++;
110
/* this codebook type indicates either greyscale or
111
* palettized video; if palettized, U & V components will
112
* not be used so it is safe to set them to 128 for the
113
* benefit of greyscale rendering in YUV420P */
114
codebook[i].y0 = *data++;
115
codebook[i].y1 = *data++;
116
codebook[i].y2 = *data++;
117
codebook[i].y3 = *data++;
125
static int cinepak_decode_vectors (CinepakContext *s, cvid_strip_t *strip,
126
int chunk_id, int size, uint8_t *data)
128
uint8_t *eod = (data + size);
130
cvid_codebook_t *codebook;
139
for (y=strip->y1; y < strip->y2; y+=4) {
141
iy[0] = strip->x1 + (y * s->frame.linesize[0]);
142
iy[1] = iy[0] + s->frame.linesize[0];
143
iy[2] = iy[1] + s->frame.linesize[0];
144
iy[3] = iy[2] + s->frame.linesize[0];
145
iu[0] = (strip->x1/2) + ((y/2) * s->frame.linesize[1]);
146
iu[1] = iu[0] + s->frame.linesize[1];
147
iv[0] = (strip->x1/2) + ((y/2) * s->frame.linesize[2]);
148
iv[1] = iv[0] + s->frame.linesize[2];
150
for (x=strip->x1; x < strip->x2; x+=4) {
151
if ((chunk_id & 0x0100) && !(mask >>= 1)) {
152
if ((data + 4) > eod)
155
flag = AV_RB32 (data);
160
if (!(chunk_id & 0x0100) || (flag & mask)) {
161
if (!(chunk_id & 0x0200) && !(mask >>= 1)) {
162
if ((data + 4) > eod)
165
flag = AV_RB32 (data);
170
if ((chunk_id & 0x0200) || (~flag & mask)) {
174
codebook = &strip->v1_codebook[*data++];
175
s->frame.data[0][iy[0] + 0] = codebook->y0;
176
s->frame.data[0][iy[0] + 1] = codebook->y0;
177
s->frame.data[0][iy[1] + 0] = codebook->y0;
178
s->frame.data[0][iy[1] + 1] = codebook->y0;
179
if (!s->palette_video) {
180
s->frame.data[1][iu[0]] = codebook->u;
181
s->frame.data[2][iv[0]] = codebook->v;
184
s->frame.data[0][iy[0] + 2] = codebook->y1;
185
s->frame.data[0][iy[0] + 3] = codebook->y1;
186
s->frame.data[0][iy[1] + 2] = codebook->y1;
187
s->frame.data[0][iy[1] + 3] = codebook->y1;
188
if (!s->palette_video) {
189
s->frame.data[1][iu[0] + 1] = codebook->u;
190
s->frame.data[2][iv[0] + 1] = codebook->v;
193
s->frame.data[0][iy[2] + 0] = codebook->y2;
194
s->frame.data[0][iy[2] + 1] = codebook->y2;
195
s->frame.data[0][iy[3] + 0] = codebook->y2;
196
s->frame.data[0][iy[3] + 1] = codebook->y2;
197
if (!s->palette_video) {
198
s->frame.data[1][iu[1]] = codebook->u;
199
s->frame.data[2][iv[1]] = codebook->v;
202
s->frame.data[0][iy[2] + 2] = codebook->y3;
203
s->frame.data[0][iy[2] + 3] = codebook->y3;
204
s->frame.data[0][iy[3] + 2] = codebook->y3;
205
s->frame.data[0][iy[3] + 3] = codebook->y3;
206
if (!s->palette_video) {
207
s->frame.data[1][iu[1] + 1] = codebook->u;
208
s->frame.data[2][iv[1] + 1] = codebook->v;
211
} else if (flag & mask) {
212
if ((data + 4) > eod)
215
codebook = &strip->v4_codebook[*data++];
216
s->frame.data[0][iy[0] + 0] = codebook->y0;
217
s->frame.data[0][iy[0] + 1] = codebook->y1;
218
s->frame.data[0][iy[1] + 0] = codebook->y2;
219
s->frame.data[0][iy[1] + 1] = codebook->y3;
220
if (!s->palette_video) {
221
s->frame.data[1][iu[0]] = codebook->u;
222
s->frame.data[2][iv[0]] = codebook->v;
225
codebook = &strip->v4_codebook[*data++];
226
s->frame.data[0][iy[0] + 2] = codebook->y0;
227
s->frame.data[0][iy[0] + 3] = codebook->y1;
228
s->frame.data[0][iy[1] + 2] = codebook->y2;
229
s->frame.data[0][iy[1] + 3] = codebook->y3;
230
if (!s->palette_video) {
231
s->frame.data[1][iu[0] + 1] = codebook->u;
232
s->frame.data[2][iv[0] + 1] = codebook->v;
235
codebook = &strip->v4_codebook[*data++];
236
s->frame.data[0][iy[2] + 0] = codebook->y0;
237
s->frame.data[0][iy[2] + 1] = codebook->y1;
238
s->frame.data[0][iy[3] + 0] = codebook->y2;
239
s->frame.data[0][iy[3] + 1] = codebook->y3;
240
if (!s->palette_video) {
241
s->frame.data[1][iu[1]] = codebook->u;
242
s->frame.data[2][iv[1]] = codebook->v;
245
codebook = &strip->v4_codebook[*data++];
246
s->frame.data[0][iy[2] + 2] = codebook->y0;
247
s->frame.data[0][iy[2] + 3] = codebook->y1;
248
s->frame.data[0][iy[3] + 2] = codebook->y2;
249
s->frame.data[0][iy[3] + 3] = codebook->y3;
250
if (!s->palette_video) {
251
s->frame.data[1][iu[1] + 1] = codebook->u;
252
s->frame.data[2][iv[1] + 1] = codebook->v;
258
iy[0] += 4; iy[1] += 4;
259
iy[2] += 4; iy[3] += 4;
260
iu[0] += 2; iu[1] += 2;
261
iv[0] += 2; iv[1] += 2;
268
static int cinepak_decode_strip (CinepakContext *s,
269
cvid_strip_t *strip, uint8_t *data, int size)
271
uint8_t *eod = (data + size);
272
int chunk_id, chunk_size;
274
/* coordinate sanity checks */
275
if (strip->x1 >= s->width || strip->x2 > s->width ||
276
strip->y1 >= s->height || strip->y2 > s->height ||
277
strip->x1 >= strip->x2 || strip->y1 >= strip->y2)
280
while ((data + 4) <= eod) {
281
chunk_id = AV_RB16 (&data[0]);
282
chunk_size = AV_RB16 (&data[2]) - 4;
287
chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size;
295
cinepak_decode_codebook (strip->v4_codebook, chunk_id,
303
cinepak_decode_codebook (strip->v1_codebook, chunk_id,
310
return cinepak_decode_vectors (s, strip, chunk_id,
320
static int cinepak_decode (CinepakContext *s)
322
uint8_t *eod = (s->data + s->size);
323
int i, result, strip_size, frame_flags, num_strips;
325
int encoded_buf_size;
330
frame_flags = s->data[0];
331
num_strips = AV_RB16 (&s->data[8]);
332
encoded_buf_size = ((s->data[1] << 16) | AV_RB16 (&s->data[2]));
334
/* if this is the first frame, check for deviant Sega FILM data */
335
if (s->sega_film_skip_bytes == -1) {
336
if (encoded_buf_size != s->size) {
337
/* If the encoded frame size differs from the frame size as indicated
338
* by the container file, this data likely comes from a Sega FILM/CPK file.
339
* If the frame header is followed by the bytes FE 00 00 06 00 00 then
340
* this is probably one of the two known files that have 6 extra bytes
341
* after the frame header. Else, assume 2 extra bytes. */
342
if ((s->data[10] == 0xFE) &&
343
(s->data[11] == 0x00) &&
344
(s->data[12] == 0x00) &&
345
(s->data[13] == 0x06) &&
346
(s->data[14] == 0x00) &&
347
(s->data[15] == 0x00))
348
s->sega_film_skip_bytes = 6;
350
s->sega_film_skip_bytes = 2;
352
s->sega_film_skip_bytes = 0;
355
s->data += 10 + s->sega_film_skip_bytes;
357
if (num_strips > MAX_STRIPS)
358
num_strips = MAX_STRIPS;
360
for (i=0; i < num_strips; i++) {
361
if ((s->data + 12) > eod)
364
s->strips[i].id = AV_RB16 (s->data);
365
s->strips[i].y1 = y0;
367
s->strips[i].y2 = y0 + AV_RB16 (&s->data[8]);
368
s->strips[i].x2 = s->avctx->width;
370
strip_size = AV_RB16 (&s->data[2]) - 12;
372
strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size;
374
if ((i > 0) && !(frame_flags & 0x01)) {
375
memcpy (s->strips[i].v4_codebook, s->strips[i-1].v4_codebook,
376
sizeof(s->strips[i].v4_codebook));
377
memcpy (s->strips[i].v1_codebook, s->strips[i-1].v1_codebook,
378
sizeof(s->strips[i].v1_codebook));
381
result = cinepak_decode_strip (s, &s->strips[i], s->data, strip_size);
386
s->data += strip_size;
387
y0 = s->strips[i].y2;
392
static int cinepak_decode_init(AVCodecContext *avctx)
394
CinepakContext *s = (CinepakContext *)avctx->priv_data;
397
s->width = (avctx->width + 3) & ~3;
398
s->height = (avctx->height + 3) & ~3;
399
s->sega_film_skip_bytes = -1; /* uninitialized state */
401
// check for paletted data
402
if ((avctx->palctrl == NULL) || (avctx->bits_per_sample == 40)) {
403
s->palette_video = 0;
404
avctx->pix_fmt = PIX_FMT_YUV420P;
406
s->palette_video = 1;
407
avctx->pix_fmt = PIX_FMT_PAL8;
410
avctx->has_b_frames = 0;
411
dsputil_init(&s->dsp, avctx);
413
s->frame.data[0] = NULL;
418
static int cinepak_decode_frame(AVCodecContext *avctx,
419
void *data, int *data_size,
420
uint8_t *buf, int buf_size)
422
CinepakContext *s = (CinepakContext *)avctx->priv_data;
427
s->frame.reference = 1;
428
s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
429
FF_BUFFER_HINTS_REUSABLE;
430
if (avctx->reget_buffer(avctx, &s->frame)) {
431
av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
437
if (s->palette_video) {
438
memcpy (s->frame.data[1], avctx->palctrl->palette, AVPALETTE_SIZE);
439
if (avctx->palctrl->palette_changed) {
440
s->frame.palette_has_changed = 1;
441
avctx->palctrl->palette_changed = 0;
443
s->frame.palette_has_changed = 0;
446
*data_size = sizeof(AVFrame);
447
*(AVFrame*)data = s->frame;
449
/* report that the buffer was completely consumed */
453
static int cinepak_decode_end(AVCodecContext *avctx)
455
CinepakContext *s = (CinepakContext *)avctx->priv_data;
457
if (s->frame.data[0])
458
avctx->release_buffer(avctx, &s->frame);
463
AVCodec cinepak_decoder = {
467
sizeof(CinepakContext),
471
cinepak_decode_frame,