Libav 0.7.1
|
00001 /* 00002 * Cinepak Video Decoder 00003 * Copyright (C) 2003 the ffmpeg project 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00032 #include <stdio.h> 00033 #include <stdlib.h> 00034 #include <string.h> 00035 00036 #include "libavutil/intreadwrite.h" 00037 #include "avcodec.h" 00038 00039 00040 typedef struct { 00041 uint8_t y0, y1, y2, y3; 00042 uint8_t u, v; 00043 } cvid_codebook; 00044 00045 #define MAX_STRIPS 32 00046 00047 typedef struct { 00048 uint16_t id; 00049 uint16_t x1, y1; 00050 uint16_t x2, y2; 00051 cvid_codebook v4_codebook[256]; 00052 cvid_codebook v1_codebook[256]; 00053 } cvid_strip; 00054 00055 typedef struct CinepakContext { 00056 00057 AVCodecContext *avctx; 00058 AVFrame frame; 00059 00060 const unsigned char *data; 00061 int size; 00062 00063 int width, height; 00064 00065 int palette_video; 00066 cvid_strip strips[MAX_STRIPS]; 00067 00068 int sega_film_skip_bytes; 00069 00070 uint32_t pal[256]; 00071 } CinepakContext; 00072 00073 static void cinepak_decode_codebook (cvid_codebook *codebook, 00074 int chunk_id, int size, const uint8_t *data) 00075 { 00076 const uint8_t *eod = (data + size); 00077 uint32_t flag, mask; 00078 int i, n; 00079 00080 /* check if this chunk contains 4- or 6-element vectors */ 00081 n = (chunk_id & 0x04) ? 4 : 6; 00082 flag = 0; 00083 mask = 0; 00084 00085 for (i=0; i < 256; i++) { 00086 if ((chunk_id & 0x01) && !(mask >>= 1)) { 00087 if ((data + 4) > eod) 00088 break; 00089 00090 flag = AV_RB32 (data); 00091 data += 4; 00092 mask = 0x80000000; 00093 } 00094 00095 if (!(chunk_id & 0x01) || (flag & mask)) { 00096 if ((data + n) > eod) 00097 break; 00098 00099 if (n == 6) { 00100 codebook[i].y0 = *data++; 00101 codebook[i].y1 = *data++; 00102 codebook[i].y2 = *data++; 00103 codebook[i].y3 = *data++; 00104 codebook[i].u = 128 + *data++; 00105 codebook[i].v = 128 + *data++; 00106 } else { 00107 /* this codebook type indicates either greyscale or 00108 * palettized video; if palettized, U & V components will 00109 * not be used so it is safe to set them to 128 for the 00110 * benefit of greyscale rendering in YUV420P */ 00111 codebook[i].y0 = *data++; 00112 codebook[i].y1 = *data++; 00113 codebook[i].y2 = *data++; 00114 codebook[i].y3 = *data++; 00115 codebook[i].u = 128; 00116 codebook[i].v = 128; 00117 } 00118 } 00119 } 00120 } 00121 00122 static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip, 00123 int chunk_id, int size, const uint8_t *data) 00124 { 00125 const uint8_t *eod = (data + size); 00126 uint32_t flag, mask; 00127 cvid_codebook *codebook; 00128 unsigned int x, y; 00129 uint32_t iy[4]; 00130 uint32_t iu[2]; 00131 uint32_t iv[2]; 00132 00133 flag = 0; 00134 mask = 0; 00135 00136 for (y=strip->y1; y < strip->y2; y+=4) { 00137 00138 iy[0] = strip->x1 + (y * s->frame.linesize[0]); 00139 iy[1] = iy[0] + s->frame.linesize[0]; 00140 iy[2] = iy[1] + s->frame.linesize[0]; 00141 iy[3] = iy[2] + s->frame.linesize[0]; 00142 iu[0] = (strip->x1/2) + ((y/2) * s->frame.linesize[1]); 00143 iu[1] = iu[0] + s->frame.linesize[1]; 00144 iv[0] = (strip->x1/2) + ((y/2) * s->frame.linesize[2]); 00145 iv[1] = iv[0] + s->frame.linesize[2]; 00146 00147 for (x=strip->x1; x < strip->x2; x+=4) { 00148 if ((chunk_id & 0x01) && !(mask >>= 1)) { 00149 if ((data + 4) > eod) 00150 return -1; 00151 00152 flag = AV_RB32 (data); 00153 data += 4; 00154 mask = 0x80000000; 00155 } 00156 00157 if (!(chunk_id & 0x01) || (flag & mask)) { 00158 if (!(chunk_id & 0x02) && !(mask >>= 1)) { 00159 if ((data + 4) > eod) 00160 return -1; 00161 00162 flag = AV_RB32 (data); 00163 data += 4; 00164 mask = 0x80000000; 00165 } 00166 00167 if ((chunk_id & 0x02) || (~flag & mask)) { 00168 if (data >= eod) 00169 return -1; 00170 00171 codebook = &strip->v1_codebook[*data++]; 00172 s->frame.data[0][iy[0] + 0] = codebook->y0; 00173 s->frame.data[0][iy[0] + 1] = codebook->y0; 00174 s->frame.data[0][iy[1] + 0] = codebook->y0; 00175 s->frame.data[0][iy[1] + 1] = codebook->y0; 00176 if (!s->palette_video) { 00177 s->frame.data[1][iu[0]] = codebook->u; 00178 s->frame.data[2][iv[0]] = codebook->v; 00179 } 00180 00181 s->frame.data[0][iy[0] + 2] = codebook->y1; 00182 s->frame.data[0][iy[0] + 3] = codebook->y1; 00183 s->frame.data[0][iy[1] + 2] = codebook->y1; 00184 s->frame.data[0][iy[1] + 3] = codebook->y1; 00185 if (!s->palette_video) { 00186 s->frame.data[1][iu[0] + 1] = codebook->u; 00187 s->frame.data[2][iv[0] + 1] = codebook->v; 00188 } 00189 00190 s->frame.data[0][iy[2] + 0] = codebook->y2; 00191 s->frame.data[0][iy[2] + 1] = codebook->y2; 00192 s->frame.data[0][iy[3] + 0] = codebook->y2; 00193 s->frame.data[0][iy[3] + 1] = codebook->y2; 00194 if (!s->palette_video) { 00195 s->frame.data[1][iu[1]] = codebook->u; 00196 s->frame.data[2][iv[1]] = codebook->v; 00197 } 00198 00199 s->frame.data[0][iy[2] + 2] = codebook->y3; 00200 s->frame.data[0][iy[2] + 3] = codebook->y3; 00201 s->frame.data[0][iy[3] + 2] = codebook->y3; 00202 s->frame.data[0][iy[3] + 3] = codebook->y3; 00203 if (!s->palette_video) { 00204 s->frame.data[1][iu[1] + 1] = codebook->u; 00205 s->frame.data[2][iv[1] + 1] = codebook->v; 00206 } 00207 00208 } else if (flag & mask) { 00209 if ((data + 4) > eod) 00210 return -1; 00211 00212 codebook = &strip->v4_codebook[*data++]; 00213 s->frame.data[0][iy[0] + 0] = codebook->y0; 00214 s->frame.data[0][iy[0] + 1] = codebook->y1; 00215 s->frame.data[0][iy[1] + 0] = codebook->y2; 00216 s->frame.data[0][iy[1] + 1] = codebook->y3; 00217 if (!s->palette_video) { 00218 s->frame.data[1][iu[0]] = codebook->u; 00219 s->frame.data[2][iv[0]] = codebook->v; 00220 } 00221 00222 codebook = &strip->v4_codebook[*data++]; 00223 s->frame.data[0][iy[0] + 2] = codebook->y0; 00224 s->frame.data[0][iy[0] + 3] = codebook->y1; 00225 s->frame.data[0][iy[1] + 2] = codebook->y2; 00226 s->frame.data[0][iy[1] + 3] = codebook->y3; 00227 if (!s->palette_video) { 00228 s->frame.data[1][iu[0] + 1] = codebook->u; 00229 s->frame.data[2][iv[0] + 1] = codebook->v; 00230 } 00231 00232 codebook = &strip->v4_codebook[*data++]; 00233 s->frame.data[0][iy[2] + 0] = codebook->y0; 00234 s->frame.data[0][iy[2] + 1] = codebook->y1; 00235 s->frame.data[0][iy[3] + 0] = codebook->y2; 00236 s->frame.data[0][iy[3] + 1] = codebook->y3; 00237 if (!s->palette_video) { 00238 s->frame.data[1][iu[1]] = codebook->u; 00239 s->frame.data[2][iv[1]] = codebook->v; 00240 } 00241 00242 codebook = &strip->v4_codebook[*data++]; 00243 s->frame.data[0][iy[2] + 2] = codebook->y0; 00244 s->frame.data[0][iy[2] + 3] = codebook->y1; 00245 s->frame.data[0][iy[3] + 2] = codebook->y2; 00246 s->frame.data[0][iy[3] + 3] = codebook->y3; 00247 if (!s->palette_video) { 00248 s->frame.data[1][iu[1] + 1] = codebook->u; 00249 s->frame.data[2][iv[1] + 1] = codebook->v; 00250 } 00251 00252 } 00253 } 00254 00255 iy[0] += 4; iy[1] += 4; 00256 iy[2] += 4; iy[3] += 4; 00257 iu[0] += 2; iu[1] += 2; 00258 iv[0] += 2; iv[1] += 2; 00259 } 00260 } 00261 00262 return 0; 00263 } 00264 00265 static int cinepak_decode_strip (CinepakContext *s, 00266 cvid_strip *strip, const uint8_t *data, int size) 00267 { 00268 const uint8_t *eod = (data + size); 00269 int chunk_id, chunk_size; 00270 00271 /* coordinate sanity checks */ 00272 if (strip->x1 >= s->width || strip->x2 > s->width || 00273 strip->y1 >= s->height || strip->y2 > s->height || 00274 strip->x1 >= strip->x2 || strip->y1 >= strip->y2) 00275 return -1; 00276 00277 while ((data + 4) <= eod) { 00278 chunk_id = data[0]; 00279 chunk_size = AV_RB24 (&data[1]) - 4; 00280 if(chunk_size < 0) 00281 return -1; 00282 00283 data += 4; 00284 chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size; 00285 00286 switch (chunk_id) { 00287 00288 case 0x20: 00289 case 0x21: 00290 case 0x24: 00291 case 0x25: 00292 cinepak_decode_codebook (strip->v4_codebook, chunk_id, 00293 chunk_size, data); 00294 break; 00295 00296 case 0x22: 00297 case 0x23: 00298 case 0x26: 00299 case 0x27: 00300 cinepak_decode_codebook (strip->v1_codebook, chunk_id, 00301 chunk_size, data); 00302 break; 00303 00304 case 0x30: 00305 case 0x31: 00306 case 0x32: 00307 return cinepak_decode_vectors (s, strip, chunk_id, 00308 chunk_size, data); 00309 } 00310 00311 data += chunk_size; 00312 } 00313 00314 return -1; 00315 } 00316 00317 static int cinepak_decode (CinepakContext *s) 00318 { 00319 const uint8_t *eod = (s->data + s->size); 00320 int i, result, strip_size, frame_flags, num_strips; 00321 int y0 = 0; 00322 int encoded_buf_size; 00323 00324 if (s->size < 10) 00325 return -1; 00326 00327 frame_flags = s->data[0]; 00328 num_strips = AV_RB16 (&s->data[8]); 00329 encoded_buf_size = ((s->data[1] << 16) | AV_RB16 (&s->data[2])); 00330 00331 /* if this is the first frame, check for deviant Sega FILM data */ 00332 if (s->sega_film_skip_bytes == -1) { 00333 if (encoded_buf_size != s->size) { 00334 /* If the encoded frame size differs from the frame size as indicated 00335 * by the container file, this data likely comes from a Sega FILM/CPK file. 00336 * If the frame header is followed by the bytes FE 00 00 06 00 00 then 00337 * this is probably one of the two known files that have 6 extra bytes 00338 * after the frame header. Else, assume 2 extra bytes. */ 00339 if (s->size >= 16 && 00340 (s->data[10] == 0xFE) && 00341 (s->data[11] == 0x00) && 00342 (s->data[12] == 0x00) && 00343 (s->data[13] == 0x06) && 00344 (s->data[14] == 0x00) && 00345 (s->data[15] == 0x00)) 00346 s->sega_film_skip_bytes = 6; 00347 else 00348 s->sega_film_skip_bytes = 2; 00349 } else 00350 s->sega_film_skip_bytes = 0; 00351 } 00352 00353 s->data += 10 + s->sega_film_skip_bytes; 00354 00355 if (num_strips > MAX_STRIPS) 00356 num_strips = MAX_STRIPS; 00357 00358 for (i=0; i < num_strips; i++) { 00359 if ((s->data + 12) > eod) 00360 return -1; 00361 00362 s->strips[i].id = s->data[0]; 00363 s->strips[i].y1 = y0; 00364 s->strips[i].x1 = 0; 00365 s->strips[i].y2 = y0 + AV_RB16 (&s->data[8]); 00366 s->strips[i].x2 = s->avctx->width; 00367 00368 strip_size = AV_RB24 (&s->data[1]) - 12; 00369 s->data += 12; 00370 strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size; 00371 00372 if ((i > 0) && !(frame_flags & 0x01)) { 00373 memcpy (s->strips[i].v4_codebook, s->strips[i-1].v4_codebook, 00374 sizeof(s->strips[i].v4_codebook)); 00375 memcpy (s->strips[i].v1_codebook, s->strips[i-1].v1_codebook, 00376 sizeof(s->strips[i].v1_codebook)); 00377 } 00378 00379 result = cinepak_decode_strip (s, &s->strips[i], s->data, strip_size); 00380 00381 if (result != 0) 00382 return result; 00383 00384 s->data += strip_size; 00385 y0 = s->strips[i].y2; 00386 } 00387 return 0; 00388 } 00389 00390 static av_cold int cinepak_decode_init(AVCodecContext *avctx) 00391 { 00392 CinepakContext *s = avctx->priv_data; 00393 00394 s->avctx = avctx; 00395 s->width = (avctx->width + 3) & ~3; 00396 s->height = (avctx->height + 3) & ~3; 00397 s->sega_film_skip_bytes = -1; /* uninitialized state */ 00398 00399 // check for paletted data 00400 if (avctx->bits_per_coded_sample != 8) { 00401 s->palette_video = 0; 00402 avctx->pix_fmt = PIX_FMT_YUV420P; 00403 } else { 00404 s->palette_video = 1; 00405 avctx->pix_fmt = PIX_FMT_PAL8; 00406 } 00407 00408 s->frame.data[0] = NULL; 00409 00410 return 0; 00411 } 00412 00413 static int cinepak_decode_frame(AVCodecContext *avctx, 00414 void *data, int *data_size, 00415 AVPacket *avpkt) 00416 { 00417 const uint8_t *buf = avpkt->data; 00418 int buf_size = avpkt->size; 00419 CinepakContext *s = avctx->priv_data; 00420 00421 s->data = buf; 00422 s->size = buf_size; 00423 00424 s->frame.reference = 1; 00425 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | 00426 FF_BUFFER_HINTS_REUSABLE; 00427 if (avctx->reget_buffer(avctx, &s->frame)) { 00428 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 00429 return -1; 00430 } 00431 00432 if (s->palette_video) { 00433 const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL); 00434 if (pal) { 00435 s->frame.palette_has_changed = 1; 00436 memcpy(s->pal, pal, AVPALETTE_SIZE); 00437 } 00438 } 00439 00440 cinepak_decode(s); 00441 00442 if (s->palette_video) 00443 memcpy (s->frame.data[1], s->pal, AVPALETTE_SIZE); 00444 00445 *data_size = sizeof(AVFrame); 00446 *(AVFrame*)data = s->frame; 00447 00448 /* report that the buffer was completely consumed */ 00449 return buf_size; 00450 } 00451 00452 static av_cold int cinepak_decode_end(AVCodecContext *avctx) 00453 { 00454 CinepakContext *s = avctx->priv_data; 00455 00456 if (s->frame.data[0]) 00457 avctx->release_buffer(avctx, &s->frame); 00458 00459 return 0; 00460 } 00461 00462 AVCodec ff_cinepak_decoder = { 00463 "cinepak", 00464 AVMEDIA_TYPE_VIDEO, 00465 CODEC_ID_CINEPAK, 00466 sizeof(CinepakContext), 00467 cinepak_decode_init, 00468 NULL, 00469 cinepak_decode_end, 00470 cinepak_decode_frame, 00471 CODEC_CAP_DR1, 00472 .long_name = NULL_IF_CONFIG_SMALL("Cinepak"), 00473 };