1/* 2 * Sierra VMD video decoder 3 * Copyright (c) 2004 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 * Sierra VMD video decoder 25 * by Vladimir "VAG" Gneushev (vagsoft at mail.ru) 26 * for more information on the Sierra VMD format, visit: 27 * http://www.pcisys.net/~melanson/codecs/ 28 * 29 * The video decoder outputs PAL8 colorspace data. The decoder expects 30 * a 0x330-byte VMD file header to be transmitted via extradata during 31 * codec initialization. Each encoded frame that is sent to this decoder 32 * is expected to be prepended with the appropriate 16-byte frame 33 * information record from the VMD file. 34 */ 35 36#include <string.h> 37 38#include "libavutil/common.h" 39#include "libavutil/intreadwrite.h" 40 41#include "avcodec.h" 42#include "codec_internal.h" 43#include "internal.h" 44#include "bytestream.h" 45 46#define VMD_HEADER_SIZE 0x330 47#define PALETTE_COUNT 256 48 49typedef struct VmdVideoContext { 50 51 AVCodecContext *avctx; 52 AVFrame *prev_frame; 53 54 const unsigned char *buf; 55 int size; 56 57 unsigned char palette[PALETTE_COUNT * 4]; 58 unsigned char *unpack_buffer; 59 int unpack_buffer_size; 60 61 int x_off, y_off; 62} VmdVideoContext; 63 64#define QUEUE_SIZE 0x1000 65#define QUEUE_MASK 0x0FFF 66 67static int lz_unpack(const unsigned char *src, int src_len, 68 unsigned char *dest, int dest_len) 69{ 70 unsigned char *d; 71 unsigned char *d_end; 72 unsigned char queue[QUEUE_SIZE]; 73 unsigned int qpos; 74 unsigned int dataleft; 75 unsigned int chainofs; 76 unsigned int chainlen; 77 unsigned int speclen; 78 unsigned char tag; 79 unsigned int i, j; 80 GetByteContext gb; 81 82 bytestream2_init(&gb, src, src_len); 83 d = dest; 84 d_end = d + dest_len; 85 dataleft = bytestream2_get_le32(&gb); 86 memset(queue, 0x20, QUEUE_SIZE); 87 if (bytestream2_get_bytes_left(&gb) < 4) 88 return AVERROR_INVALIDDATA; 89 if (bytestream2_peek_le32(&gb) == 0x56781234) { 90 bytestream2_skipu(&gb, 4); 91 qpos = 0x111; 92 speclen = 0xF + 3; 93 } else { 94 qpos = 0xFEE; 95 speclen = 100; /* no speclen */ 96 } 97 98 while (dataleft > 0 && bytestream2_get_bytes_left(&gb) > 0) { 99 tag = bytestream2_get_byteu(&gb); 100 if ((tag == 0xFF) && (dataleft > 8)) { 101 if (d_end - d < 8 || bytestream2_get_bytes_left(&gb) < 8) 102 return AVERROR_INVALIDDATA; 103 for (i = 0; i < 8; i++) { 104 queue[qpos++] = *d++ = bytestream2_get_byteu(&gb); 105 qpos &= QUEUE_MASK; 106 } 107 dataleft -= 8; 108 } else { 109 for (i = 0; i < 8; i++) { 110 if (dataleft == 0) 111 break; 112 if (tag & 0x01) { 113 if (d_end - d < 1 || bytestream2_get_bytes_left(&gb) < 1) 114 return AVERROR_INVALIDDATA; 115 queue[qpos++] = *d++ = bytestream2_get_byteu(&gb); 116 qpos &= QUEUE_MASK; 117 dataleft--; 118 } else { 119 chainofs = bytestream2_get_byte(&gb); 120 chainofs |= ((bytestream2_peek_byte(&gb) & 0xF0) << 4); 121 chainlen = (bytestream2_get_byte(&gb) & 0x0F) + 3; 122 if (chainlen == speclen) { 123 chainlen = bytestream2_get_byte(&gb) + 0xF + 3; 124 } 125 if (d_end - d < chainlen) 126 return AVERROR_INVALIDDATA; 127 for (j = 0; j < chainlen; j++) { 128 *d = queue[chainofs++ & QUEUE_MASK]; 129 queue[qpos++] = *d++; 130 qpos &= QUEUE_MASK; 131 } 132 dataleft -= chainlen; 133 } 134 tag >>= 1; 135 } 136 } 137 } 138 return d - dest; 139} 140static int rle_unpack(const unsigned char *src, unsigned char *dest, 141 int src_count, int src_size, int dest_len) 142{ 143 unsigned char *pd; 144 int i, l, used = 0; 145 unsigned char *dest_end = dest + dest_len; 146 GetByteContext gb; 147 uint16_t run_val; 148 149 bytestream2_init(&gb, src, src_size); 150 pd = dest; 151 if (src_count & 1) { 152 if (bytestream2_get_bytes_left(&gb) < 1) 153 return 0; 154 *pd++ = bytestream2_get_byteu(&gb); 155 used++; 156 } 157 158 do { 159 if (bytestream2_get_bytes_left(&gb) < 1) 160 break; 161 l = bytestream2_get_byteu(&gb); 162 if (l & 0x80) { 163 l = (l & 0x7F) * 2; 164 if (dest_end - pd < l || bytestream2_get_bytes_left(&gb) < l) 165 return bytestream2_tell(&gb); 166 bytestream2_get_bufferu(&gb, pd, l); 167 pd += l; 168 } else { 169 if (dest_end - pd < 2*l || bytestream2_get_bytes_left(&gb) < 2) 170 return bytestream2_tell(&gb); 171 run_val = bytestream2_get_ne16(&gb); 172 for (i = 0; i < l; i++) { 173 AV_WN16(pd, run_val); 174 pd += 2; 175 } 176 l *= 2; 177 } 178 used += l; 179 } while (used < src_count); 180 181 return bytestream2_tell(&gb); 182} 183 184static int vmd_decode(VmdVideoContext *s, AVFrame *frame) 185{ 186 int i; 187 unsigned int *palette32; 188 unsigned char r, g, b; 189 190 GetByteContext gb; 191 192 unsigned char meth; 193 unsigned char *dp; /* pointer to current frame */ 194 unsigned char *pp; /* pointer to previous frame */ 195 unsigned char len; 196 int ofs; 197 198 int frame_x, frame_y, prev_linesize; 199 int frame_width, frame_height; 200 201 frame_x = AV_RL16(&s->buf[6]); 202 frame_y = AV_RL16(&s->buf[8]); 203 frame_width = AV_RL16(&s->buf[10]) - frame_x + 1; 204 frame_height = AV_RL16(&s->buf[12]) - frame_y + 1; 205 206 if ((frame_width == s->avctx->width && frame_height == s->avctx->height) && 207 (frame_x || frame_y)) { 208 209 s->x_off = frame_x; 210 s->y_off = frame_y; 211 } 212 frame_x -= s->x_off; 213 frame_y -= s->y_off; 214 215 if (frame_x < 0 || frame_width < 0 || 216 frame_x >= s->avctx->width || 217 frame_width > s->avctx->width || 218 frame_x + frame_width > s->avctx->width) { 219 av_log(s->avctx, AV_LOG_ERROR, 220 "Invalid horizontal range %d-%d\n", 221 frame_x, frame_width); 222 return AVERROR_INVALIDDATA; 223 } 224 if (frame_y < 0 || frame_height < 0 || 225 frame_y >= s->avctx->height || 226 frame_height > s->avctx->height || 227 frame_y + frame_height > s->avctx->height) { 228 av_log(s->avctx, AV_LOG_ERROR, 229 "Invalid vertical range %d-%d\n", 230 frame_y, frame_height); 231 return AVERROR_INVALIDDATA; 232 } 233 234 /* if only a certain region will be updated, copy the entire previous 235 * frame before the decode */ 236 if (s->prev_frame->data[0] && 237 (frame_x || frame_y || (frame_width != s->avctx->width) || 238 (frame_height != s->avctx->height))) { 239 240 memcpy(frame->data[0], s->prev_frame->data[0], 241 s->avctx->height * frame->linesize[0]); 242 } 243 244 /* check if there is a new palette */ 245 bytestream2_init(&gb, s->buf + 16, s->size - 16); 246 if (s->buf[15] & 0x02) { 247 bytestream2_skip(&gb, 2); 248 palette32 = (unsigned int *)s->palette; 249 if (bytestream2_get_bytes_left(&gb) >= PALETTE_COUNT * 3) { 250 for (i = 0; i < PALETTE_COUNT; i++) { 251 r = bytestream2_get_byteu(&gb) * 4; 252 g = bytestream2_get_byteu(&gb) * 4; 253 b = bytestream2_get_byteu(&gb) * 4; 254 palette32[i] = 0xFFU << 24 | (r << 16) | (g << 8) | (b); 255 palette32[i] |= palette32[i] >> 6 & 0x30303; 256 } 257 } else { 258 av_log(s->avctx, AV_LOG_ERROR, "Incomplete palette\n"); 259 return AVERROR_INVALIDDATA; 260 } 261 } 262 263 if (!s->size) 264 return 0; 265 266 /* originally UnpackFrame in VAG's code */ 267 if (bytestream2_get_bytes_left(&gb) < 1) 268 return AVERROR_INVALIDDATA; 269 meth = bytestream2_get_byteu(&gb); 270 if (meth & 0x80) { 271 int size; 272 if (!s->unpack_buffer_size) { 273 av_log(s->avctx, AV_LOG_ERROR, 274 "Trying to unpack LZ-compressed frame with no LZ buffer\n"); 275 return AVERROR_INVALIDDATA; 276 } 277 size = lz_unpack(gb.buffer, bytestream2_get_bytes_left(&gb), 278 s->unpack_buffer, s->unpack_buffer_size); 279 if (size < 0) 280 return size; 281 meth &= 0x7F; 282 bytestream2_init(&gb, s->unpack_buffer, size); 283 } 284 285 dp = &frame->data[0][frame_y * frame->linesize[0] + frame_x]; 286 if (s->prev_frame->data[0]) { 287 prev_linesize = s->prev_frame->linesize[0]; 288 pp = s->prev_frame->data[0] + frame_y * prev_linesize + frame_x; 289 } else { 290 pp = NULL; 291 prev_linesize = 0; 292 } 293 switch (meth) { 294 case 1: 295 for (i = 0; i < frame_height; i++) { 296 ofs = 0; 297 do { 298 len = bytestream2_get_byte(&gb); 299 if (len & 0x80) { 300 len = (len & 0x7F) + 1; 301 if (ofs + len > frame_width || 302 bytestream2_get_bytes_left(&gb) < len) 303 return AVERROR_INVALIDDATA; 304 bytestream2_get_bufferu(&gb, &dp[ofs], len); 305 ofs += len; 306 } else { 307 /* interframe pixel copy */ 308 if (ofs + len + 1 > frame_width || !pp) 309 return AVERROR_INVALIDDATA; 310 memcpy(&dp[ofs], &pp[ofs], len + 1); 311 ofs += len + 1; 312 } 313 } while (ofs < frame_width); 314 if (ofs > frame_width) { 315 av_log(s->avctx, AV_LOG_ERROR, 316 "offset > width (%d > %d)\n", 317 ofs, frame_width); 318 return AVERROR_INVALIDDATA; 319 } 320 dp += frame->linesize[0]; 321 pp = FF_PTR_ADD(pp, prev_linesize); 322 } 323 break; 324 325 case 2: 326 for (i = 0; i < frame_height; i++) { 327 bytestream2_get_buffer(&gb, dp, frame_width); 328 dp += frame->linesize[0]; 329 } 330 break; 331 332 case 3: 333 for (i = 0; i < frame_height; i++) { 334 ofs = 0; 335 do { 336 len = bytestream2_get_byte(&gb); 337 if (len & 0x80) { 338 len = (len & 0x7F) + 1; 339 if (bytestream2_peek_byte(&gb) == 0xFF) { 340 int slen = len; 341 bytestream2_get_byte(&gb); 342 len = rle_unpack(gb.buffer, &dp[ofs], 343 len, bytestream2_get_bytes_left(&gb), 344 frame_width - ofs); 345 ofs += slen; 346 bytestream2_skip(&gb, len); 347 } else { 348 if (ofs + len > frame_width || 349 bytestream2_get_bytes_left(&gb) < len) 350 return AVERROR_INVALIDDATA; 351 bytestream2_get_buffer(&gb, &dp[ofs], len); 352 ofs += len; 353 } 354 } else { 355 /* interframe pixel copy */ 356 if (ofs + len + 1 > frame_width || !pp) 357 return AVERROR_INVALIDDATA; 358 memcpy(&dp[ofs], &pp[ofs], len + 1); 359 ofs += len + 1; 360 } 361 } while (ofs < frame_width); 362 if (ofs > frame_width) { 363 av_log(s->avctx, AV_LOG_ERROR, 364 "offset > width (%d > %d)\n", 365 ofs, frame_width); 366 return AVERROR_INVALIDDATA; 367 } 368 dp += frame->linesize[0]; 369 pp = FF_PTR_ADD(pp, prev_linesize); 370 } 371 break; 372 } 373 return 0; 374} 375 376static av_cold int vmdvideo_decode_end(AVCodecContext *avctx) 377{ 378 VmdVideoContext *s = avctx->priv_data; 379 380 av_frame_free(&s->prev_frame); 381 av_freep(&s->unpack_buffer); 382 s->unpack_buffer_size = 0; 383 384 return 0; 385} 386 387static av_cold int vmdvideo_decode_init(AVCodecContext *avctx) 388{ 389 VmdVideoContext *s = avctx->priv_data; 390 int i; 391 unsigned int *palette32; 392 int palette_index = 0; 393 unsigned char r, g, b; 394 unsigned char *vmd_header; 395 unsigned char *raw_palette; 396 397 s->avctx = avctx; 398 avctx->pix_fmt = AV_PIX_FMT_PAL8; 399 400 /* make sure the VMD header made it */ 401 if (s->avctx->extradata_size != VMD_HEADER_SIZE) { 402 av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n", 403 VMD_HEADER_SIZE); 404 return AVERROR_INVALIDDATA; 405 } 406 vmd_header = (unsigned char *)avctx->extradata; 407 408 s->unpack_buffer_size = AV_RL32(&vmd_header[800]); 409 if (s->unpack_buffer_size) { 410 s->unpack_buffer = av_malloc(s->unpack_buffer_size); 411 if (!s->unpack_buffer) 412 return AVERROR(ENOMEM); 413 } 414 415 /* load up the initial palette */ 416 raw_palette = &vmd_header[28]; 417 palette32 = (unsigned int *)s->palette; 418 for (i = 0; i < PALETTE_COUNT; i++) { 419 r = raw_palette[palette_index++] * 4; 420 g = raw_palette[palette_index++] * 4; 421 b = raw_palette[palette_index++] * 4; 422 palette32[i] = 0xFFU << 24 | (r << 16) | (g << 8) | (b); 423 palette32[i] |= palette32[i] >> 6 & 0x30303; 424 } 425 426 s->prev_frame = av_frame_alloc(); 427 if (!s->prev_frame) 428 return AVERROR(ENOMEM); 429 430 return 0; 431} 432 433static int vmdvideo_decode_frame(AVCodecContext *avctx, AVFrame *frame, 434 int *got_frame, AVPacket *avpkt) 435{ 436 const uint8_t *buf = avpkt->data; 437 int buf_size = avpkt->size; 438 VmdVideoContext *s = avctx->priv_data; 439 int ret; 440 441 s->buf = buf; 442 s->size = buf_size; 443 444 if (buf_size < 16) 445 return AVERROR_INVALIDDATA; 446 447 if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) 448 return ret; 449 450 if ((ret = vmd_decode(s, frame)) < 0) 451 return ret; 452 453 /* make the palette available on the way out */ 454 memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4); 455 456 /* shuffle frames */ 457 av_frame_unref(s->prev_frame); 458 if ((ret = av_frame_ref(s->prev_frame, frame)) < 0) 459 return ret; 460 461 *got_frame = 1; 462 463 /* report that the buffer was completely consumed */ 464 return buf_size; 465} 466 467const FFCodec ff_vmdvideo_decoder = { 468 .p.name = "vmdvideo", 469 .p.long_name = NULL_IF_CONFIG_SMALL("Sierra VMD video"), 470 .p.type = AVMEDIA_TYPE_VIDEO, 471 .p.id = AV_CODEC_ID_VMDVIDEO, 472 .priv_data_size = sizeof(VmdVideoContext), 473 .init = vmdvideo_decode_init, 474 .close = vmdvideo_decode_end, 475 FF_CODEC_DECODE_CB(vmdvideo_decode_frame), 476 .p.capabilities = AV_CODEC_CAP_DR1, 477 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 478}; 479