1/* 2 * Cinepak 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/cinepak.c 24 * Cinepak video decoder 25 * by Ewald Snel <ewald@rambo.its.tudelft.nl> 26 * For more information on the Cinepak algorithm, visit: 27 * http://www.csse.monash.edu.au/~timf/ 28 * For more information on the quirky data inside Sega FILM/CPK files, visit: 29 * http://wiki.multimedia.cx/index.php?title=Sega_FILM 30 */ 31 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35#include <unistd.h> 36 37#include "libavutil/intreadwrite.h" 38#include "avcodec.h" 39 40 41typedef struct { 42 uint8_t y0, y1, y2, y3; 43 uint8_t u, v; 44} cvid_codebook; 45 46#define MAX_STRIPS 32 47 48typedef struct { 49 uint16_t id; 50 uint16_t x1, y1; 51 uint16_t x2, y2; 52 cvid_codebook v4_codebook[256]; 53 cvid_codebook v1_codebook[256]; 54} cvid_strip; 55 56typedef struct CinepakContext { 57 58 AVCodecContext *avctx; 59 AVFrame frame; 60 61 const unsigned char *data; 62 int size; 63 64 int width, height; 65 66 int palette_video; 67 cvid_strip strips[MAX_STRIPS]; 68 69 int sega_film_skip_bytes; 70 71} CinepakContext; 72 73static void cinepak_decode_codebook (cvid_codebook *codebook, 74 int chunk_id, int size, const uint8_t *data) 75{ 76 const uint8_t *eod = (data + size); 77 uint32_t flag, mask; 78 int i, n; 79 80 /* check if this chunk contains 4- or 6-element vectors */ 81 n = (chunk_id & 0x04) ? 4 : 6; 82 flag = 0; 83 mask = 0; 84 85 for (i=0; i < 256; i++) { 86 if ((chunk_id & 0x01) && !(mask >>= 1)) { 87 if ((data + 4) > eod) 88 break; 89 90 flag = AV_RB32 (data); 91 data += 4; 92 mask = 0x80000000; 93 } 94 95 if (!(chunk_id & 0x01) || (flag & mask)) { 96 if ((data + n) > eod) 97 break; 98 99 if (n == 6) { 100 codebook[i].y0 = *data++; 101 codebook[i].y1 = *data++; 102 codebook[i].y2 = *data++; 103 codebook[i].y3 = *data++; 104 codebook[i].u = 128 + *data++; 105 codebook[i].v = 128 + *data++; 106 } else { 107 /* this codebook type indicates either greyscale or 108 * palettized video; if palettized, U & V components will 109 * not be used so it is safe to set them to 128 for the 110 * benefit of greyscale rendering in YUV420P */ 111 codebook[i].y0 = *data++; 112 codebook[i].y1 = *data++; 113 codebook[i].y2 = *data++; 114 codebook[i].y3 = *data++; 115 codebook[i].u = 128; 116 codebook[i].v = 128; 117 } 118 } 119 } 120} 121 122static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip, 123 int chunk_id, int size, const uint8_t *data) 124{ 125 const uint8_t *eod = (data + size); 126 uint32_t flag, mask; 127 cvid_codebook *codebook; 128 unsigned int x, y; 129 uint32_t iy[4]; 130 uint32_t iu[2]; 131 uint32_t iv[2]; 132 133 flag = 0; 134 mask = 0; 135 136 for (y=strip->y1; y < strip->y2; y+=4) { 137 138 iy[0] = strip->x1 + (y * s->frame.linesize[0]); 139 iy[1] = iy[0] + s->frame.linesize[0]; 140 iy[2] = iy[1] + s->frame.linesize[0]; 141 iy[3] = iy[2] + s->frame.linesize[0]; 142 iu[0] = (strip->x1/2) + ((y/2) * s->frame.linesize[1]); 143 iu[1] = iu[0] + s->frame.linesize[1]; 144 iv[0] = (strip->x1/2) + ((y/2) * s->frame.linesize[2]); 145 iv[1] = iv[0] + s->frame.linesize[2]; 146 147 for (x=strip->x1; x < strip->x2; x+=4) { 148 if ((chunk_id & 0x01) && !(mask >>= 1)) { 149 if ((data + 4) > eod) 150 return -1; 151 152 flag = AV_RB32 (data); 153 data += 4; 154 mask = 0x80000000; 155 } 156 157 if (!(chunk_id & 0x01) || (flag & mask)) { 158 if (!(chunk_id & 0x02) && !(mask >>= 1)) { 159 if ((data + 4) > eod) 160 return -1; 161 162 flag = AV_RB32 (data); 163 data += 4; 164 mask = 0x80000000; 165 } 166 167 if ((chunk_id & 0x02) || (~flag & mask)) { 168 if (data >= eod) 169 return -1; 170 171 codebook = &strip->v1_codebook[*data++]; 172 s->frame.data[0][iy[0] + 0] = codebook->y0; 173 s->frame.data[0][iy[0] + 1] = codebook->y0; 174 s->frame.data[0][iy[1] + 0] = codebook->y0; 175 s->frame.data[0][iy[1] + 1] = codebook->y0; 176 if (!s->palette_video) { 177 s->frame.data[1][iu[0]] = codebook->u; 178 s->frame.data[2][iv[0]] = codebook->v; 179 } 180 181 s->frame.data[0][iy[0] + 2] = codebook->y1; 182 s->frame.data[0][iy[0] + 3] = codebook->y1; 183 s->frame.data[0][iy[1] + 2] = codebook->y1; 184 s->frame.data[0][iy[1] + 3] = codebook->y1; 185 if (!s->palette_video) { 186 s->frame.data[1][iu[0] + 1] = codebook->u; 187 s->frame.data[2][iv[0] + 1] = codebook->v; 188 } 189 190 s->frame.data[0][iy[2] + 0] = codebook->y2; 191 s->frame.data[0][iy[2] + 1] = codebook->y2; 192 s->frame.data[0][iy[3] + 0] = codebook->y2; 193 s->frame.data[0][iy[3] + 1] = codebook->y2; 194 if (!s->palette_video) { 195 s->frame.data[1][iu[1]] = codebook->u; 196 s->frame.data[2][iv[1]] = codebook->v; 197 } 198 199 s->frame.data[0][iy[2] + 2] = codebook->y3; 200 s->frame.data[0][iy[2] + 3] = codebook->y3; 201 s->frame.data[0][iy[3] + 2] = codebook->y3; 202 s->frame.data[0][iy[3] + 3] = codebook->y3; 203 if (!s->palette_video) { 204 s->frame.data[1][iu[1] + 1] = codebook->u; 205 s->frame.data[2][iv[1] + 1] = codebook->v; 206 } 207 208 } else if (flag & mask) { 209 if ((data + 4) > eod) 210 return -1; 211 212 codebook = &strip->v4_codebook[*data++]; 213 s->frame.data[0][iy[0] + 0] = codebook->y0; 214 s->frame.data[0][iy[0] + 1] = codebook->y1; 215 s->frame.data[0][iy[1] + 0] = codebook->y2; 216 s->frame.data[0][iy[1] + 1] = codebook->y3; 217 if (!s->palette_video) { 218 s->frame.data[1][iu[0]] = codebook->u; 219 s->frame.data[2][iv[0]] = codebook->v; 220 } 221 222 codebook = &strip->v4_codebook[*data++]; 223 s->frame.data[0][iy[0] + 2] = codebook->y0; 224 s->frame.data[0][iy[0] + 3] = codebook->y1; 225 s->frame.data[0][iy[1] + 2] = codebook->y2; 226 s->frame.data[0][iy[1] + 3] = codebook->y3; 227 if (!s->palette_video) { 228 s->frame.data[1][iu[0] + 1] = codebook->u; 229 s->frame.data[2][iv[0] + 1] = codebook->v; 230 } 231 232 codebook = &strip->v4_codebook[*data++]; 233 s->frame.data[0][iy[2] + 0] = codebook->y0; 234 s->frame.data[0][iy[2] + 1] = codebook->y1; 235 s->frame.data[0][iy[3] + 0] = codebook->y2; 236 s->frame.data[0][iy[3] + 1] = codebook->y3; 237 if (!s->palette_video) { 238 s->frame.data[1][iu[1]] = codebook->u; 239 s->frame.data[2][iv[1]] = codebook->v; 240 } 241 242 codebook = &strip->v4_codebook[*data++]; 243 s->frame.data[0][iy[2] + 2] = codebook->y0; 244 s->frame.data[0][iy[2] + 3] = codebook->y1; 245 s->frame.data[0][iy[3] + 2] = codebook->y2; 246 s->frame.data[0][iy[3] + 3] = codebook->y3; 247 if (!s->palette_video) { 248 s->frame.data[1][iu[1] + 1] = codebook->u; 249 s->frame.data[2][iv[1] + 1] = codebook->v; 250 } 251 252 } 253 } 254 255 iy[0] += 4; iy[1] += 4; 256 iy[2] += 4; iy[3] += 4; 257 iu[0] += 2; iu[1] += 2; 258 iv[0] += 2; iv[1] += 2; 259 } 260 } 261 262 return 0; 263} 264 265static int cinepak_decode_strip (CinepakContext *s, 266 cvid_strip *strip, const uint8_t *data, int size) 267{ 268 const uint8_t *eod = (data + size); 269 int chunk_id, chunk_size; 270 271 /* coordinate sanity checks */ 272 if (strip->x1 >= s->width || strip->x2 > s->width || 273 strip->y1 >= s->height || strip->y2 > s->height || 274 strip->x1 >= strip->x2 || strip->y1 >= strip->y2) 275 return -1; 276 277 while ((data + 4) <= eod) { 278 chunk_id = data[0]; 279 chunk_size = AV_RB24 (&data[1]) - 4; 280 if(chunk_size < 0) 281 return -1; 282 283 data += 4; 284 chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size; 285 286 switch (chunk_id) { 287 288 case 0x20: 289 case 0x21: 290 case 0x24: 291 case 0x25: 292 cinepak_decode_codebook (strip->v4_codebook, chunk_id, 293 chunk_size, data); 294 break; 295 296 case 0x22: 297 case 0x23: 298 case 0x26: 299 case 0x27: 300 cinepak_decode_codebook (strip->v1_codebook, chunk_id, 301 chunk_size, data); 302 break; 303 304 case 0x30: 305 case 0x31: 306 case 0x32: 307 return cinepak_decode_vectors (s, strip, chunk_id, 308 chunk_size, data); 309 } 310 311 data += chunk_size; 312 } 313 314 return -1; 315} 316 317static int cinepak_decode (CinepakContext *s) 318{ 319 const uint8_t *eod = (s->data + s->size); 320 int i, result, strip_size, frame_flags, num_strips; 321 int y0 = 0; 322 int encoded_buf_size; 323 324 if (s->size < 10) 325 return -1; 326 327 frame_flags = s->data[0]; 328 num_strips = AV_RB16 (&s->data[8]); 329 encoded_buf_size = ((s->data[1] << 16) | AV_RB16 (&s->data[2])); 330 331 /* if this is the first frame, check for deviant Sega FILM data */ 332 if (s->sega_film_skip_bytes == -1) { 333 if (encoded_buf_size != s->size) { 334 /* If the encoded frame size differs from the frame size as indicated 335 * by the container file, this data likely comes from a Sega FILM/CPK file. 336 * If the frame header is followed by the bytes FE 00 00 06 00 00 then 337 * this is probably one of the two known files that have 6 extra bytes 338 * after the frame header. Else, assume 2 extra bytes. */ 339 if ((s->data[10] == 0xFE) && 340 (s->data[11] == 0x00) && 341 (s->data[12] == 0x00) && 342 (s->data[13] == 0x06) && 343 (s->data[14] == 0x00) && 344 (s->data[15] == 0x00)) 345 s->sega_film_skip_bytes = 6; 346 else 347 s->sega_film_skip_bytes = 2; 348 } else 349 s->sega_film_skip_bytes = 0; 350 } 351 352 s->data += 10 + s->sega_film_skip_bytes; 353 354 if (num_strips > MAX_STRIPS) 355 num_strips = MAX_STRIPS; 356 357 for (i=0; i < num_strips; i++) { 358 if ((s->data + 12) > eod) 359 return -1; 360 361 s->strips[i].id = s->data[0]; 362 s->strips[i].y1 = y0; 363 s->strips[i].x1 = 0; 364 s->strips[i].y2 = y0 + AV_RB16 (&s->data[8]); 365 s->strips[i].x2 = s->avctx->width; 366 367 strip_size = AV_RB24 (&s->data[1]) - 12; 368 s->data += 12; 369 strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size; 370 371 if ((i > 0) && !(frame_flags & 0x01)) { 372 memcpy (s->strips[i].v4_codebook, s->strips[i-1].v4_codebook, 373 sizeof(s->strips[i].v4_codebook)); 374 memcpy (s->strips[i].v1_codebook, s->strips[i-1].v1_codebook, 375 sizeof(s->strips[i].v1_codebook)); 376 } 377 378 result = cinepak_decode_strip (s, &s->strips[i], s->data, strip_size); 379 380 if (result != 0) 381 return result; 382 383 s->data += strip_size; 384 y0 = s->strips[i].y2; 385 } 386 return 0; 387} 388 389static av_cold int cinepak_decode_init(AVCodecContext *avctx) 390{ 391 CinepakContext *s = avctx->priv_data; 392 393 s->avctx = avctx; 394 s->width = (avctx->width + 3) & ~3; 395 s->height = (avctx->height + 3) & ~3; 396 s->sega_film_skip_bytes = -1; /* uninitialized state */ 397 398 // check for paletted data 399 if ((avctx->palctrl == NULL) || (avctx->bits_per_coded_sample == 40)) { 400 s->palette_video = 0; 401 avctx->pix_fmt = PIX_FMT_YUV420P; 402 } else { 403 s->palette_video = 1; 404 avctx->pix_fmt = PIX_FMT_PAL8; 405 } 406 407 s->frame.data[0] = NULL; 408 409 return 0; 410} 411 412static int cinepak_decode_frame(AVCodecContext *avctx, 413 void *data, int *data_size, 414 const uint8_t *buf, int buf_size) 415{ 416 CinepakContext *s = avctx->priv_data; 417 418 s->data = buf; 419 s->size = buf_size; 420 421 s->frame.reference = 1; 422 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | 423 FF_BUFFER_HINTS_REUSABLE; 424 if (avctx->reget_buffer(avctx, &s->frame)) { 425 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 426 return -1; 427 } 428 429 cinepak_decode(s); 430 431 if (s->palette_video) { 432 memcpy (s->frame.data[1], avctx->palctrl->palette, AVPALETTE_SIZE); 433 if (avctx->palctrl->palette_changed) { 434 s->frame.palette_has_changed = 1; 435 avctx->palctrl->palette_changed = 0; 436 } else 437 s->frame.palette_has_changed = 0; 438 } 439 440 *data_size = sizeof(AVFrame); 441 *(AVFrame*)data = s->frame; 442 443 /* report that the buffer was completely consumed */ 444 return buf_size; 445} 446 447static av_cold int cinepak_decode_end(AVCodecContext *avctx) 448{ 449 CinepakContext *s = avctx->priv_data; 450 451 if (s->frame.data[0]) 452 avctx->release_buffer(avctx, &s->frame); 453 454 return 0; 455} 456 457AVCodec cinepak_decoder = { 458 "cinepak", 459 CODEC_TYPE_VIDEO, 460 CODEC_ID_CINEPAK, 461 sizeof(CinepakContext), 462 cinepak_decode_init, 463 NULL, 464 cinepak_decode_end, 465 cinepak_decode_frame, 466 CODEC_CAP_DR1, 467 .long_name = NULL_IF_CONFIG_SMALL("Cinepak"), 468}; 469