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 24 * Cinepak video decoder 25 * @author Ewald Snel <ewald@rambo.its.tudelft.nl> 26 * 27 * @see For more information on the Cinepak algorithm, visit: 28 * http://www.csse.monash.edu.au/~timf/ 29 * @see For more information on the quirky data inside Sega FILM/CPK files, visit: 30 * http://wiki.multimedia.cx/index.php?title=Sega_FILM 31 * 32 * Cinepak colorspace support (c) 2013 Rl, Aetey Global Technologies AB 33 * @author Cinepak colorspace, Rl, Aetey Global Technologies AB 34 */ 35 36#include <stdio.h> 37#include <stdlib.h> 38#include <string.h> 39 40#include "libavutil/common.h" 41#include "libavutil/intreadwrite.h" 42#include "avcodec.h" 43#include "codec_internal.h" 44#include "decode.h" 45#include "internal.h" 46 47 48typedef uint8_t cvid_codebook[12]; 49 50#define MAX_STRIPS 32 51 52typedef struct cvid_strip { 53 uint16_t id; 54 uint16_t x1, y1; 55 uint16_t x2, y2; 56 cvid_codebook v4_codebook[256]; 57 cvid_codebook v1_codebook[256]; 58} cvid_strip; 59 60typedef struct CinepakContext { 61 62 AVCodecContext *avctx; 63 AVFrame *frame; 64 65 const unsigned char *data; 66 int size; 67 68 int width, height; 69 70 int palette_video; 71 cvid_strip strips[MAX_STRIPS]; 72 73 int sega_film_skip_bytes; 74 75 uint32_t pal[256]; 76} CinepakContext; 77 78static void cinepak_decode_codebook (cvid_codebook *codebook, 79 int chunk_id, int size, const uint8_t *data) 80{ 81 const uint8_t *eod = (data + size); 82 uint32_t flag, mask; 83 int i, n; 84 uint8_t *p; 85 86 /* check if this chunk contains 4- or 6-element vectors */ 87 n = (chunk_id & 0x04) ? 4 : 6; 88 flag = 0; 89 mask = 0; 90 91 p = codebook[0]; 92 for (i=0; i < 256; i++) { 93 if ((chunk_id & 0x01) && !(mask >>= 1)) { 94 if ((data + 4) > eod) 95 break; 96 97 flag = AV_RB32 (data); 98 data += 4; 99 mask = 0x80000000; 100 } 101 102 if (!(chunk_id & 0x01) || (flag & mask)) { 103 int k, kk; 104 105 if ((data + n) > eod) 106 break; 107 108 for (k = 0; k < 4; ++k) { 109 int r = *data++; 110 for (kk = 0; kk < 3; ++kk) 111 *p++ = r; 112 } 113 if (n == 6) { 114 int r, g, b, u, v; 115 u = *(int8_t *)data++; 116 v = *(int8_t *)data++; 117 p -= 12; 118 for(k=0; k<4; ++k) { 119 r = *p++ + v*2; 120 g = *p++ - (u/2) - v; 121 b = *p + u*2; 122 p -= 2; 123 *p++ = av_clip_uint8(r); 124 *p++ = av_clip_uint8(g); 125 *p++ = av_clip_uint8(b); 126 } 127 } 128 } else { 129 p += 12; 130 } 131 } 132} 133 134static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip, 135 int chunk_id, int size, const uint8_t *data) 136{ 137 const uint8_t *eod = (data + size); 138 uint32_t flag, mask; 139 uint8_t *cb0, *cb1, *cb2, *cb3; 140 int x, y; 141 char *ip0, *ip1, *ip2, *ip3; 142 143 flag = 0; 144 mask = 0; 145 146 for (y=strip->y1; y < strip->y2; y+=4) { 147 148/* take care of y dimension not being multiple of 4, such streams exist */ 149 ip0 = ip1 = ip2 = ip3 = s->frame->data[0] + 150 (s->palette_video?strip->x1:strip->x1*3) + (y * s->frame->linesize[0]); 151 if(s->avctx->height - y > 1) { 152 ip1 = ip0 + s->frame->linesize[0]; 153 if(s->avctx->height - y > 2) { 154 ip2 = ip1 + s->frame->linesize[0]; 155 if(s->avctx->height - y > 3) { 156 ip3 = ip2 + s->frame->linesize[0]; 157 } 158 } 159 } 160/* to get the correct picture for not-multiple-of-4 cases let us fill each 161 * block from the bottom up, thus possibly overwriting the bottommost line 162 * more than once but ending with the correct data in place 163 * (instead of in-loop checking) */ 164 165 for (x=strip->x1; x < strip->x2; x+=4) { 166 if ((chunk_id & 0x01) && !(mask >>= 1)) { 167 if ((data + 4) > eod) 168 return AVERROR_INVALIDDATA; 169 170 flag = AV_RB32 (data); 171 data += 4; 172 mask = 0x80000000; 173 } 174 175 if (!(chunk_id & 0x01) || (flag & mask)) { 176 if (!(chunk_id & 0x02) && !(mask >>= 1)) { 177 if ((data + 4) > eod) 178 return AVERROR_INVALIDDATA; 179 180 flag = AV_RB32 (data); 181 data += 4; 182 mask = 0x80000000; 183 } 184 185 if ((chunk_id & 0x02) || (~flag & mask)) { 186 uint8_t *p; 187 if (data >= eod) 188 return AVERROR_INVALIDDATA; 189 190 p = strip->v1_codebook[*data++]; 191 if (s->palette_video) { 192 ip3[0] = ip3[1] = ip2[0] = ip2[1] = p[6]; 193 ip3[2] = ip3[3] = ip2[2] = ip2[3] = p[9]; 194 ip1[0] = ip1[1] = ip0[0] = ip0[1] = p[0]; 195 ip1[2] = ip1[3] = ip0[2] = ip0[3] = p[3]; 196 } else { 197 p += 6; 198 memcpy(ip3 + 0, p, 3); memcpy(ip3 + 3, p, 3); 199 memcpy(ip2 + 0, p, 3); memcpy(ip2 + 3, p, 3); 200 p += 3; /* ... + 9 */ 201 memcpy(ip3 + 6, p, 3); memcpy(ip3 + 9, p, 3); 202 memcpy(ip2 + 6, p, 3); memcpy(ip2 + 9, p, 3); 203 p -= 9; /* ... + 0 */ 204 memcpy(ip1 + 0, p, 3); memcpy(ip1 + 3, p, 3); 205 memcpy(ip0 + 0, p, 3); memcpy(ip0 + 3, p, 3); 206 p += 3; /* ... + 3 */ 207 memcpy(ip1 + 6, p, 3); memcpy(ip1 + 9, p, 3); 208 memcpy(ip0 + 6, p, 3); memcpy(ip0 + 9, p, 3); 209 } 210 211 } else if (flag & mask) { 212 if ((data + 4) > eod) 213 return AVERROR_INVALIDDATA; 214 215 cb0 = strip->v4_codebook[*data++]; 216 cb1 = strip->v4_codebook[*data++]; 217 cb2 = strip->v4_codebook[*data++]; 218 cb3 = strip->v4_codebook[*data++]; 219 if (s->palette_video) { 220 uint8_t *p; 221 p = ip3; 222 *p++ = cb2[6]; 223 *p++ = cb2[9]; 224 *p++ = cb3[6]; 225 *p = cb3[9]; 226 p = ip2; 227 *p++ = cb2[0]; 228 *p++ = cb2[3]; 229 *p++ = cb3[0]; 230 *p = cb3[3]; 231 p = ip1; 232 *p++ = cb0[6]; 233 *p++ = cb0[9]; 234 *p++ = cb1[6]; 235 *p = cb1[9]; 236 p = ip0; 237 *p++ = cb0[0]; 238 *p++ = cb0[3]; 239 *p++ = cb1[0]; 240 *p = cb1[3]; 241 } else { 242 memcpy(ip3 + 0, cb2 + 6, 6); 243 memcpy(ip3 + 6, cb3 + 6, 6); 244 memcpy(ip2 + 0, cb2 + 0, 6); 245 memcpy(ip2 + 6, cb3 + 0, 6); 246 memcpy(ip1 + 0, cb0 + 6, 6); 247 memcpy(ip1 + 6, cb1 + 6, 6); 248 memcpy(ip0 + 0, cb0 + 0, 6); 249 memcpy(ip0 + 6, cb1 + 0, 6); 250 } 251 252 } 253 } 254 255 if (s->palette_video) { 256 ip0 += 4; ip1 += 4; 257 ip2 += 4; ip3 += 4; 258 } else { 259 ip0 += 12; ip1 += 12; 260 ip2 += 12; ip3 += 12; 261 } 262 } 263 } 264 265 return 0; 266} 267 268static int cinepak_decode_strip (CinepakContext *s, 269 cvid_strip *strip, const uint8_t *data, int size) 270{ 271 const uint8_t *eod = (data + size); 272 int chunk_id, chunk_size; 273 274 /* coordinate sanity checks */ 275 if (strip->x2 > s->width || 276 strip->y2 > s->height || 277 strip->x1 >= strip->x2 || strip->y1 >= strip->y2) 278 return AVERROR_INVALIDDATA; 279 280 while ((data + 4) <= eod) { 281 chunk_id = data[0]; 282 chunk_size = AV_RB24 (&data[1]) - 4; 283 if(chunk_size < 0) 284 return AVERROR_INVALIDDATA; 285 286 data += 4; 287 chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size; 288 289 switch (chunk_id) { 290 291 case 0x20: 292 case 0x21: 293 case 0x24: 294 case 0x25: 295 cinepak_decode_codebook (strip->v4_codebook, chunk_id, 296 chunk_size, data); 297 break; 298 299 case 0x22: 300 case 0x23: 301 case 0x26: 302 case 0x27: 303 cinepak_decode_codebook (strip->v1_codebook, chunk_id, 304 chunk_size, data); 305 break; 306 307 case 0x30: 308 case 0x31: 309 case 0x32: 310 return cinepak_decode_vectors (s, strip, chunk_id, 311 chunk_size, data); 312 } 313 314 data += chunk_size; 315 } 316 317 return AVERROR_INVALIDDATA; 318} 319 320static int cinepak_predecode_check (CinepakContext *s) 321{ 322 int num_strips; 323 int encoded_buf_size; 324 325 num_strips = AV_RB16 (&s->data[8]); 326 encoded_buf_size = AV_RB24(&s->data[1]); 327 328 if (s->size < encoded_buf_size * (int64_t)(100 - s->avctx->discard_damaged_percentage) / 100) 329 return AVERROR_INVALIDDATA; 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) { 334 avpriv_request_sample(s->avctx, "encoded_buf_size 0"); 335 return AVERROR_PATCHWELCOME; 336 } 337 if (encoded_buf_size != s->size && (s->size % encoded_buf_size) != 0) { 338 /* If the encoded frame size differs from the frame size as indicated 339 * by the container file, this data likely comes from a Sega FILM/CPK file. 340 * If the frame header is followed by the bytes FE 00 00 06 00 00 then 341 * this is probably one of the two known files that have 6 extra bytes 342 * after the frame header. Else, assume 2 extra bytes. The container 343 * size also cannot be a multiple of the encoded size. */ 344 if (s->size >= 16 && 345 (s->data[10] == 0xFE) && 346 (s->data[11] == 0x00) && 347 (s->data[12] == 0x00) && 348 (s->data[13] == 0x06) && 349 (s->data[14] == 0x00) && 350 (s->data[15] == 0x00)) 351 s->sega_film_skip_bytes = 6; 352 else 353 s->sega_film_skip_bytes = 2; 354 } else 355 s->sega_film_skip_bytes = 0; 356 } 357 358 if (s->size < 10 + s->sega_film_skip_bytes + num_strips * 12) 359 return AVERROR_INVALIDDATA; 360 361 if (num_strips) { 362 const uint8_t *data = s->data + 10 + s->sega_film_skip_bytes; 363 int strip_size = AV_RB24 (data + 1); 364 if (strip_size < 12 || strip_size > encoded_buf_size) 365 return AVERROR_INVALIDDATA; 366 } 367 368 return 0; 369} 370 371static int cinepak_decode (CinepakContext *s) 372{ 373 const uint8_t *eod = (s->data + s->size); 374 int i, result, strip_size, frame_flags, num_strips; 375 int y0 = 0; 376 377 frame_flags = s->data[0]; 378 num_strips = AV_RB16 (&s->data[8]); 379 380 s->data += 10 + s->sega_film_skip_bytes; 381 382 num_strips = FFMIN(num_strips, MAX_STRIPS); 383 384 s->frame->key_frame = 0; 385 386 for (i=0; i < num_strips; i++) { 387 if ((s->data + 12) > eod) 388 return AVERROR_INVALIDDATA; 389 390 s->strips[i].id = s->data[0]; 391/* zero y1 means "relative to the previous stripe" */ 392 if (!(s->strips[i].y1 = AV_RB16 (&s->data[4]))) 393 s->strips[i].y2 = (s->strips[i].y1 = y0) + AV_RB16 (&s->data[8]); 394 else 395 s->strips[i].y2 = AV_RB16 (&s->data[8]); 396 s->strips[i].x1 = AV_RB16 (&s->data[6]); 397 s->strips[i].x2 = AV_RB16 (&s->data[10]); 398 399 if (s->strips[i].id == 0x10) 400 s->frame->key_frame = 1; 401 402 strip_size = AV_RB24 (&s->data[1]) - 12; 403 if (strip_size < 0) 404 return AVERROR_INVALIDDATA; 405 s->data += 12; 406 strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size; 407 408 if ((i > 0) && !(frame_flags & 0x01)) { 409 memcpy (s->strips[i].v4_codebook, s->strips[i-1].v4_codebook, 410 sizeof(s->strips[i].v4_codebook)); 411 memcpy (s->strips[i].v1_codebook, s->strips[i-1].v1_codebook, 412 sizeof(s->strips[i].v1_codebook)); 413 } 414 415 result = cinepak_decode_strip (s, &s->strips[i], s->data, strip_size); 416 417 if (result != 0) 418 return result; 419 420 s->data += strip_size; 421 y0 = s->strips[i].y2; 422 } 423 return 0; 424} 425 426static av_cold int cinepak_decode_init(AVCodecContext *avctx) 427{ 428 CinepakContext *s = avctx->priv_data; 429 430 s->avctx = avctx; 431 s->width = (avctx->width + 3) & ~3; 432 s->height = (avctx->height + 3) & ~3; 433 434 s->sega_film_skip_bytes = -1; /* uninitialized state */ 435 436 // check for paletted data 437 if (avctx->bits_per_coded_sample != 8) { 438 s->palette_video = 0; 439 avctx->pix_fmt = AV_PIX_FMT_RGB24; 440 } else { 441 s->palette_video = 1; 442 avctx->pix_fmt = AV_PIX_FMT_PAL8; 443 } 444 445 s->frame = av_frame_alloc(); 446 if (!s->frame) 447 return AVERROR(ENOMEM); 448 449 return 0; 450} 451 452static int cinepak_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 453 int *got_frame, AVPacket *avpkt) 454{ 455 const uint8_t *buf = avpkt->data; 456 int ret = 0, buf_size = avpkt->size; 457 CinepakContext *s = avctx->priv_data; 458 int num_strips; 459 460 s->data = buf; 461 s->size = buf_size; 462 463 if (s->size < 10) 464 return AVERROR_INVALIDDATA; 465 466 num_strips = AV_RB16 (&s->data[8]); 467 468 //Empty frame, do not waste time 469 if (!num_strips && (!s->palette_video || !av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL))) 470 return buf_size; 471 472 if ((ret = cinepak_predecode_check(s)) < 0) { 473 av_log(avctx, AV_LOG_ERROR, "cinepak_predecode_check failed\n"); 474 return ret; 475 } 476 477 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 478 return ret; 479 480 if (s->palette_video) { 481 s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx); 482 } 483 484 if ((ret = cinepak_decode(s)) < 0) { 485 av_log(avctx, AV_LOG_ERROR, "cinepak_decode failed\n"); 486 } 487 488 if (s->palette_video) 489 memcpy (s->frame->data[1], s->pal, AVPALETTE_SIZE); 490 491 if ((ret = av_frame_ref(rframe, s->frame)) < 0) 492 return ret; 493 494 *got_frame = 1; 495 496 /* report that the buffer was completely consumed */ 497 return buf_size; 498} 499 500static av_cold int cinepak_decode_end(AVCodecContext *avctx) 501{ 502 CinepakContext *s = avctx->priv_data; 503 504 av_frame_free(&s->frame); 505 506 return 0; 507} 508 509const FFCodec ff_cinepak_decoder = { 510 .p.name = "cinepak", 511 .p.long_name = NULL_IF_CONFIG_SMALL("Cinepak"), 512 .p.type = AVMEDIA_TYPE_VIDEO, 513 .p.id = AV_CODEC_ID_CINEPAK, 514 .priv_data_size = sizeof(CinepakContext), 515 .init = cinepak_decode_init, 516 .close = cinepak_decode_end, 517 FF_CODEC_DECODE_CB(cinepak_decode_frame), 518 .p.capabilities = AV_CODEC_CAP_DR1, 519 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 520}; 521