1/* 2 * Interplay MVE Video Decoder 3 * Copyright (C) 2003 the ffmpeg project 4 * 5 * This file is part of Libav. 6 * 7 * Libav 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 * Libav 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 Libav; 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 * Interplay MVE Video Decoder by Mike Melanson (melanson@pcisys.net) 25 * For more information about the Interplay MVE format, visit: 26 * http://www.pcisys.net/~melanson/codecs/interplay-mve.txt 27 * This code is written in such a way that the identifiers match up 28 * with the encoding descriptions in the document. 29 * 30 * This decoder presently only supports a PAL8 output colorspace. 31 * 32 * An Interplay video frame consists of 2 parts: The decoding map and 33 * the video data. A demuxer must load these 2 parts together in a single 34 * buffer before sending it through the stream to this decoder. 35 */ 36 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40 41#include "avcodec.h" 42#include "bytestream.h" 43#include "dsputil.h" 44#define BITSTREAM_READER_LE 45#include "get_bits.h" 46 47#define PALETTE_COUNT 256 48 49typedef struct IpvideoContext { 50 51 AVCodecContext *avctx; 52 DSPContext dsp; 53 AVFrame second_last_frame; 54 AVFrame last_frame; 55 AVFrame current_frame; 56 const unsigned char *decoding_map; 57 int decoding_map_size; 58 59 const unsigned char *buf; 60 int size; 61 62 int is_16bpp; 63 const unsigned char *stream_ptr; 64 const unsigned char *stream_end; 65 const uint8_t *mv_ptr; 66 const uint8_t *mv_end; 67 unsigned char *pixel_ptr; 68 int line_inc; 69 int stride; 70 int upper_motion_limit_offset; 71 72 uint32_t pal[256]; 73} IpvideoContext; 74 75#define CHECK_STREAM_PTR(stream_ptr, stream_end, n) \ 76 if (stream_end - stream_ptr < n) { \ 77 av_log(s->avctx, AV_LOG_ERROR, "Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \ 78 stream_ptr + n, stream_end); \ 79 return -1; \ 80 } 81 82static int copy_from(IpvideoContext *s, AVFrame *src, int delta_x, int delta_y) 83{ 84 int current_offset = s->pixel_ptr - s->current_frame.data[0]; 85 int motion_offset = current_offset + delta_y * s->current_frame.linesize[0] 86 + delta_x * (1 + s->is_16bpp); 87 if (motion_offset < 0) { 88 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset); 89 return -1; 90 } else if (motion_offset > s->upper_motion_limit_offset) { 91 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n", 92 motion_offset, s->upper_motion_limit_offset); 93 return -1; 94 } 95 if (src->data[0] == NULL) { 96 av_log(s->avctx, AV_LOG_ERROR, "Invalid decode type, corrupted header?\n"); 97 return AVERROR(EINVAL); 98 } 99 s->dsp.put_pixels_tab[!s->is_16bpp][0](s->pixel_ptr, src->data[0] + motion_offset, 100 s->current_frame.linesize[0], 8); 101 return 0; 102} 103 104static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s) 105{ 106 return copy_from(s, &s->last_frame, 0, 0); 107} 108 109static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s) 110{ 111 return copy_from(s, &s->second_last_frame, 0, 0); 112} 113 114static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s) 115{ 116 unsigned char B; 117 int x, y; 118 119 /* copy block from 2 frames ago using a motion vector; need 1 more byte */ 120 if (!s->is_16bpp) { 121 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1); 122 B = *s->stream_ptr++; 123 } else { 124 CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1); 125 B = *s->mv_ptr++; 126 } 127 128 if (B < 56) { 129 x = 8 + (B % 7); 130 y = B / 7; 131 } else { 132 x = -14 + ((B - 56) % 29); 133 y = 8 + ((B - 56) / 29); 134 } 135 136 av_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); 137 return copy_from(s, &s->second_last_frame, x, y); 138} 139 140static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s) 141{ 142 unsigned char B; 143 int x, y; 144 145 /* copy 8x8 block from current frame from an up/left block */ 146 147 /* need 1 more byte for motion */ 148 if (!s->is_16bpp) { 149 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1); 150 B = *s->stream_ptr++; 151 } else { 152 CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1); 153 B = *s->mv_ptr++; 154 } 155 156 if (B < 56) { 157 x = -(8 + (B % 7)); 158 y = -(B / 7); 159 } else { 160 x = -(-14 + ((B - 56) % 29)); 161 y = -( 8 + ((B - 56) / 29)); 162 } 163 164 av_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); 165 return copy_from(s, &s->current_frame, x, y); 166} 167 168static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s) 169{ 170 int x, y; 171 unsigned char B, BL, BH; 172 173 /* copy a block from the previous frame; need 1 more byte */ 174 if (!s->is_16bpp) { 175 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1); 176 B = *s->stream_ptr++; 177 } else { 178 CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1); 179 B = *s->mv_ptr++; 180 } 181 182 BL = B & 0x0F; 183 BH = (B >> 4) & 0x0F; 184 x = -8 + BL; 185 y = -8 + BH; 186 187 av_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); 188 return copy_from(s, &s->last_frame, x, y); 189} 190 191static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s) 192{ 193 signed char x, y; 194 195 /* copy a block from the previous frame using an expanded range; 196 * need 2 more bytes */ 197 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 198 199 x = *s->stream_ptr++; 200 y = *s->stream_ptr++; 201 202 av_dlog(NULL, " motion bytes = %d, %d\n", x, y); 203 return copy_from(s, &s->last_frame, x, y); 204} 205 206static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s) 207{ 208 /* mystery opcode? skip multiple blocks? */ 209 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: Help! Mystery opcode 0x6 seen\n"); 210 211 /* report success */ 212 return 0; 213} 214 215static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s) 216{ 217 int x, y; 218 unsigned char P[2]; 219 unsigned int flags; 220 221 /* 2-color encoding */ 222 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 223 224 P[0] = *s->stream_ptr++; 225 P[1] = *s->stream_ptr++; 226 227 if (P[0] <= P[1]) { 228 229 /* need 8 more bytes from the stream */ 230 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 231 232 for (y = 0; y < 8; y++) { 233 flags = *s->stream_ptr++ | 0x100; 234 for (; flags != 1; flags >>= 1) 235 *s->pixel_ptr++ = P[flags & 1]; 236 s->pixel_ptr += s->line_inc; 237 } 238 239 } else { 240 241 /* need 2 more bytes from the stream */ 242 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 243 244 flags = bytestream_get_le16(&s->stream_ptr); 245 for (y = 0; y < 8; y += 2) { 246 for (x = 0; x < 8; x += 2, flags >>= 1) { 247 s->pixel_ptr[x ] = 248 s->pixel_ptr[x + 1 ] = 249 s->pixel_ptr[x + s->stride] = 250 s->pixel_ptr[x + 1 + s->stride] = P[flags & 1]; 251 } 252 s->pixel_ptr += s->stride * 2; 253 } 254 } 255 256 /* report success */ 257 return 0; 258} 259 260static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s) 261{ 262 int x, y; 263 unsigned char P[2]; 264 unsigned int flags = 0; 265 266 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on 267 * either top and bottom or left and right halves */ 268 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 269 270 P[0] = *s->stream_ptr++; 271 P[1] = *s->stream_ptr++; 272 273 if (P[0] <= P[1]) { 274 275 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 14); 276 s->stream_ptr -= 2; 277 278 for (y = 0; y < 16; y++) { 279 // new values for each 4x4 block 280 if (!(y & 3)) { 281 P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++; 282 flags = bytestream_get_le16(&s->stream_ptr); 283 } 284 285 for (x = 0; x < 4; x++, flags >>= 1) 286 *s->pixel_ptr++ = P[flags & 1]; 287 s->pixel_ptr += s->stride - 4; 288 // switch to right half 289 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4; 290 } 291 292 } else { 293 294 /* need 10 more bytes */ 295 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 10); 296 297 if (s->stream_ptr[4] <= s->stream_ptr[5]) { 298 299 flags = bytestream_get_le32(&s->stream_ptr); 300 301 /* vertical split; left & right halves are 2-color encoded */ 302 303 for (y = 0; y < 16; y++) { 304 for (x = 0; x < 4; x++, flags >>= 1) 305 *s->pixel_ptr++ = P[flags & 1]; 306 s->pixel_ptr += s->stride - 4; 307 // switch to right half 308 if (y == 7) { 309 s->pixel_ptr -= 8 * s->stride - 4; 310 P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++; 311 flags = bytestream_get_le32(&s->stream_ptr); 312 } 313 } 314 315 } else { 316 317 /* horizontal split; top & bottom halves are 2-color encoded */ 318 319 for (y = 0; y < 8; y++) { 320 if (y == 4) { 321 P[0] = *s->stream_ptr++; 322 P[1] = *s->stream_ptr++; 323 } 324 flags = *s->stream_ptr++ | 0x100; 325 326 for (; flags != 1; flags >>= 1) 327 *s->pixel_ptr++ = P[flags & 1]; 328 s->pixel_ptr += s->line_inc; 329 } 330 } 331 } 332 333 /* report success */ 334 return 0; 335} 336 337static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s) 338{ 339 int x, y; 340 unsigned char P[4]; 341 342 /* 4-color encoding */ 343 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 344 345 memcpy(P, s->stream_ptr, 4); 346 s->stream_ptr += 4; 347 348 if (P[0] <= P[1]) { 349 if (P[2] <= P[3]) { 350 351 /* 1 of 4 colors for each pixel, need 16 more bytes */ 352 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16); 353 354 for (y = 0; y < 8; y++) { 355 /* get the next set of 8 2-bit flags */ 356 int flags = bytestream_get_le16(&s->stream_ptr); 357 for (x = 0; x < 8; x++, flags >>= 2) 358 *s->pixel_ptr++ = P[flags & 0x03]; 359 s->pixel_ptr += s->line_inc; 360 } 361 362 } else { 363 uint32_t flags; 364 365 /* 1 of 4 colors for each 2x2 block, need 4 more bytes */ 366 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 367 368 flags = bytestream_get_le32(&s->stream_ptr); 369 370 for (y = 0; y < 8; y += 2) { 371 for (x = 0; x < 8; x += 2, flags >>= 2) { 372 s->pixel_ptr[x ] = 373 s->pixel_ptr[x + 1 ] = 374 s->pixel_ptr[x + s->stride] = 375 s->pixel_ptr[x + 1 + s->stride] = P[flags & 0x03]; 376 } 377 s->pixel_ptr += s->stride * 2; 378 } 379 380 } 381 } else { 382 uint64_t flags; 383 384 /* 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes */ 385 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 386 387 flags = bytestream_get_le64(&s->stream_ptr); 388 if (P[2] <= P[3]) { 389 for (y = 0; y < 8; y++) { 390 for (x = 0; x < 8; x += 2, flags >>= 2) { 391 s->pixel_ptr[x ] = 392 s->pixel_ptr[x + 1] = P[flags & 0x03]; 393 } 394 s->pixel_ptr += s->stride; 395 } 396 } else { 397 for (y = 0; y < 8; y += 2) { 398 for (x = 0; x < 8; x++, flags >>= 2) { 399 s->pixel_ptr[x ] = 400 s->pixel_ptr[x + s->stride] = P[flags & 0x03]; 401 } 402 s->pixel_ptr += s->stride * 2; 403 } 404 } 405 } 406 407 /* report success */ 408 return 0; 409} 410 411static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s) 412{ 413 int x, y; 414 unsigned char P[4]; 415 int flags = 0; 416 417 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on 418 * either top and bottom or left and right halves */ 419 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24); 420 421 if (s->stream_ptr[0] <= s->stream_ptr[1]) { 422 423 /* 4-color encoding for each quadrant; need 32 bytes */ 424 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32); 425 426 for (y = 0; y < 16; y++) { 427 // new values for each 4x4 block 428 if (!(y & 3)) { 429 memcpy(P, s->stream_ptr, 4); 430 s->stream_ptr += 4; 431 flags = bytestream_get_le32(&s->stream_ptr); 432 } 433 434 for (x = 0; x < 4; x++, flags >>= 2) 435 *s->pixel_ptr++ = P[flags & 0x03]; 436 437 s->pixel_ptr += s->stride - 4; 438 // switch to right half 439 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4; 440 } 441 442 } else { 443 // vertical split? 444 int vert = s->stream_ptr[12] <= s->stream_ptr[13]; 445 uint64_t flags = 0; 446 447 /* 4-color encoding for either left and right or top and bottom 448 * halves */ 449 450 for (y = 0; y < 16; y++) { 451 // load values for each half 452 if (!(y & 7)) { 453 memcpy(P, s->stream_ptr, 4); 454 s->stream_ptr += 4; 455 flags = bytestream_get_le64(&s->stream_ptr); 456 } 457 458 for (x = 0; x < 4; x++, flags >>= 2) 459 *s->pixel_ptr++ = P[flags & 0x03]; 460 461 if (vert) { 462 s->pixel_ptr += s->stride - 4; 463 // switch to right half 464 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4; 465 } else if (y & 1) s->pixel_ptr += s->line_inc; 466 } 467 } 468 469 /* report success */ 470 return 0; 471} 472 473static int ipvideo_decode_block_opcode_0xB(IpvideoContext *s) 474{ 475 int y; 476 477 /* 64-color encoding (each pixel in block is a different color) */ 478 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 64); 479 480 for (y = 0; y < 8; y++) { 481 memcpy(s->pixel_ptr, s->stream_ptr, 8); 482 s->stream_ptr += 8; 483 s->pixel_ptr += s->stride; 484 } 485 486 /* report success */ 487 return 0; 488} 489 490static int ipvideo_decode_block_opcode_0xC(IpvideoContext *s) 491{ 492 int x, y; 493 494 /* 16-color block encoding: each 2x2 block is a different color */ 495 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16); 496 497 for (y = 0; y < 8; y += 2) { 498 for (x = 0; x < 8; x += 2) { 499 s->pixel_ptr[x ] = 500 s->pixel_ptr[x + 1 ] = 501 s->pixel_ptr[x + s->stride] = 502 s->pixel_ptr[x + 1 + s->stride] = *s->stream_ptr++; 503 } 504 s->pixel_ptr += s->stride * 2; 505 } 506 507 /* report success */ 508 return 0; 509} 510 511static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s) 512{ 513 int y; 514 unsigned char P[2]; 515 516 /* 4-color block encoding: each 4x4 block is a different color */ 517 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 518 519 for (y = 0; y < 8; y++) { 520 if (!(y & 3)) { 521 P[0] = *s->stream_ptr++; 522 P[1] = *s->stream_ptr++; 523 } 524 memset(s->pixel_ptr, P[0], 4); 525 memset(s->pixel_ptr + 4, P[1], 4); 526 s->pixel_ptr += s->stride; 527 } 528 529 /* report success */ 530 return 0; 531} 532 533static int ipvideo_decode_block_opcode_0xE(IpvideoContext *s) 534{ 535 int y; 536 unsigned char pix; 537 538 /* 1-color encoding: the whole block is 1 solid color */ 539 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1); 540 pix = *s->stream_ptr++; 541 542 for (y = 0; y < 8; y++) { 543 memset(s->pixel_ptr, pix, 8); 544 s->pixel_ptr += s->stride; 545 } 546 547 /* report success */ 548 return 0; 549} 550 551static int ipvideo_decode_block_opcode_0xF(IpvideoContext *s) 552{ 553 int x, y; 554 unsigned char sample[2]; 555 556 /* dithered encoding */ 557 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 558 sample[0] = *s->stream_ptr++; 559 sample[1] = *s->stream_ptr++; 560 561 for (y = 0; y < 8; y++) { 562 for (x = 0; x < 8; x += 2) { 563 *s->pixel_ptr++ = sample[ y & 1 ]; 564 *s->pixel_ptr++ = sample[!(y & 1)]; 565 } 566 s->pixel_ptr += s->line_inc; 567 } 568 569 /* report success */ 570 return 0; 571} 572 573static int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s) 574{ 575 signed char x, y; 576 577 /* copy a block from the second last frame using an expanded range */ 578 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 579 580 x = *s->stream_ptr++; 581 y = *s->stream_ptr++; 582 583 av_dlog(NULL, " motion bytes = %d, %d\n", x, y); 584 return copy_from(s, &s->second_last_frame, x, y); 585} 586 587static int ipvideo_decode_block_opcode_0x7_16(IpvideoContext *s) 588{ 589 int x, y; 590 uint16_t P[2]; 591 unsigned int flags; 592 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 593 594 /* 2-color encoding */ 595 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 596 597 P[0] = bytestream_get_le16(&s->stream_ptr); 598 P[1] = bytestream_get_le16(&s->stream_ptr); 599 600 if (!(P[0] & 0x8000)) { 601 602 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 603 604 for (y = 0; y < 8; y++) { 605 flags = *s->stream_ptr++ | 0x100; 606 for (; flags != 1; flags >>= 1) 607 *pixel_ptr++ = P[flags & 1]; 608 pixel_ptr += s->line_inc; 609 } 610 611 } else { 612 613 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 614 615 flags = bytestream_get_le16(&s->stream_ptr); 616 for (y = 0; y < 8; y += 2) { 617 for (x = 0; x < 8; x += 2, flags >>= 1) { 618 pixel_ptr[x ] = 619 pixel_ptr[x + 1 ] = 620 pixel_ptr[x + s->stride] = 621 pixel_ptr[x + 1 + s->stride] = P[flags & 1]; 622 } 623 pixel_ptr += s->stride * 2; 624 } 625 } 626 627 return 0; 628} 629 630static int ipvideo_decode_block_opcode_0x8_16(IpvideoContext *s) 631{ 632 int x, y; 633 uint16_t P[2]; 634 unsigned int flags = 0; 635 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 636 637 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on 638 * either top and bottom or left and right halves */ 639 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 640 641 P[0] = bytestream_get_le16(&s->stream_ptr); 642 P[1] = bytestream_get_le16(&s->stream_ptr); 643 644 if (!(P[0] & 0x8000)) { 645 646 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24); 647 s->stream_ptr -= 4; 648 649 for (y = 0; y < 16; y++) { 650 // new values for each 4x4 block 651 if (!(y & 3)) { 652 P[0] = bytestream_get_le16(&s->stream_ptr); 653 P[1] = bytestream_get_le16(&s->stream_ptr); 654 flags = bytestream_get_le16(&s->stream_ptr); 655 } 656 657 for (x = 0; x < 4; x++, flags >>= 1) 658 *pixel_ptr++ = P[flags & 1]; 659 pixel_ptr += s->stride - 4; 660 // switch to right half 661 if (y == 7) pixel_ptr -= 8 * s->stride - 4; 662 } 663 664 } else { 665 666 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 12); 667 668 if (!(AV_RL16(s->stream_ptr + 4) & 0x8000)) { 669 670 flags = bytestream_get_le32(&s->stream_ptr); 671 672 /* vertical split; left & right halves are 2-color encoded */ 673 674 for (y = 0; y < 16; y++) { 675 for (x = 0; x < 4; x++, flags >>= 1) 676 *pixel_ptr++ = P[flags & 1]; 677 pixel_ptr += s->stride - 4; 678 // switch to right half 679 if (y == 7) { 680 pixel_ptr -= 8 * s->stride - 4; 681 P[0] = bytestream_get_le16(&s->stream_ptr); 682 P[1] = bytestream_get_le16(&s->stream_ptr); 683 flags = bytestream_get_le32(&s->stream_ptr); 684 } 685 } 686 687 } else { 688 689 /* horizontal split; top & bottom halves are 2-color encoded */ 690 691 for (y = 0; y < 8; y++) { 692 if (y == 4) { 693 P[0] = bytestream_get_le16(&s->stream_ptr); 694 P[1] = bytestream_get_le16(&s->stream_ptr); 695 } 696 flags = *s->stream_ptr++ | 0x100; 697 698 for (; flags != 1; flags >>= 1) 699 *pixel_ptr++ = P[flags & 1]; 700 pixel_ptr += s->line_inc; 701 } 702 } 703 } 704 705 /* report success */ 706 return 0; 707} 708 709static int ipvideo_decode_block_opcode_0x9_16(IpvideoContext *s) 710{ 711 int x, y; 712 uint16_t P[4]; 713 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 714 715 /* 4-color encoding */ 716 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 717 718 for (x = 0; x < 4; x++) 719 P[x] = bytestream_get_le16(&s->stream_ptr); 720 721 if (!(P[0] & 0x8000)) { 722 if (!(P[2] & 0x8000)) { 723 724 /* 1 of 4 colors for each pixel */ 725 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16); 726 727 for (y = 0; y < 8; y++) { 728 /* get the next set of 8 2-bit flags */ 729 int flags = bytestream_get_le16(&s->stream_ptr); 730 for (x = 0; x < 8; x++, flags >>= 2) 731 *pixel_ptr++ = P[flags & 0x03]; 732 pixel_ptr += s->line_inc; 733 } 734 735 } else { 736 uint32_t flags; 737 738 /* 1 of 4 colors for each 2x2 block */ 739 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 740 741 flags = bytestream_get_le32(&s->stream_ptr); 742 743 for (y = 0; y < 8; y += 2) { 744 for (x = 0; x < 8; x += 2, flags >>= 2) { 745 pixel_ptr[x ] = 746 pixel_ptr[x + 1 ] = 747 pixel_ptr[x + s->stride] = 748 pixel_ptr[x + 1 + s->stride] = P[flags & 0x03]; 749 } 750 pixel_ptr += s->stride * 2; 751 } 752 753 } 754 } else { 755 uint64_t flags; 756 757 /* 1 of 4 colors for each 2x1 or 1x2 block */ 758 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 759 760 flags = bytestream_get_le64(&s->stream_ptr); 761 if (!(P[2] & 0x8000)) { 762 for (y = 0; y < 8; y++) { 763 for (x = 0; x < 8; x += 2, flags >>= 2) { 764 pixel_ptr[x ] = 765 pixel_ptr[x + 1] = P[flags & 0x03]; 766 } 767 pixel_ptr += s->stride; 768 } 769 } else { 770 for (y = 0; y < 8; y += 2) { 771 for (x = 0; x < 8; x++, flags >>= 2) { 772 pixel_ptr[x ] = 773 pixel_ptr[x + s->stride] = P[flags & 0x03]; 774 } 775 pixel_ptr += s->stride * 2; 776 } 777 } 778 } 779 780 /* report success */ 781 return 0; 782} 783 784static int ipvideo_decode_block_opcode_0xA_16(IpvideoContext *s) 785{ 786 int x, y; 787 uint16_t P[4]; 788 int flags = 0; 789 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 790 791 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on 792 * either top and bottom or left and right halves */ 793 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24); 794 795 if (!(AV_RL16(s->stream_ptr) & 0x8000)) { 796 797 /* 4-color encoding for each quadrant */ 798 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 48); 799 800 for (y = 0; y < 16; y++) { 801 // new values for each 4x4 block 802 if (!(y & 3)) { 803 for (x = 0; x < 4; x++) 804 P[x] = bytestream_get_le16(&s->stream_ptr); 805 flags = bytestream_get_le32(&s->stream_ptr); 806 } 807 808 for (x = 0; x < 4; x++, flags >>= 2) 809 *pixel_ptr++ = P[flags & 0x03]; 810 811 pixel_ptr += s->stride - 4; 812 // switch to right half 813 if (y == 7) pixel_ptr -= 8 * s->stride - 4; 814 } 815 816 } else { 817 // vertical split? 818 int vert = !(AV_RL16(s->stream_ptr + 16) & 0x8000); 819 uint64_t flags = 0; 820 821 /* 4-color encoding for either left and right or top and bottom 822 * halves */ 823 824 for (y = 0; y < 16; y++) { 825 // load values for each half 826 if (!(y & 7)) { 827 for (x = 0; x < 4; x++) 828 P[x] = bytestream_get_le16(&s->stream_ptr); 829 flags = bytestream_get_le64(&s->stream_ptr); 830 } 831 832 for (x = 0; x < 4; x++, flags >>= 2) 833 *pixel_ptr++ = P[flags & 0x03]; 834 835 if (vert) { 836 pixel_ptr += s->stride - 4; 837 // switch to right half 838 if (y == 7) pixel_ptr -= 8 * s->stride - 4; 839 } else if (y & 1) pixel_ptr += s->line_inc; 840 } 841 } 842 843 /* report success */ 844 return 0; 845} 846 847static int ipvideo_decode_block_opcode_0xB_16(IpvideoContext *s) 848{ 849 int x, y; 850 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 851 852 /* 64-color encoding (each pixel in block is a different color) */ 853 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 128); 854 855 for (y = 0; y < 8; y++) { 856 for (x = 0; x < 8; x++) 857 pixel_ptr[x] = bytestream_get_le16(&s->stream_ptr); 858 pixel_ptr += s->stride; 859 } 860 861 /* report success */ 862 return 0; 863} 864 865static int ipvideo_decode_block_opcode_0xC_16(IpvideoContext *s) 866{ 867 int x, y; 868 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 869 870 /* 16-color block encoding: each 2x2 block is a different color */ 871 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32); 872 873 for (y = 0; y < 8; y += 2) { 874 for (x = 0; x < 8; x += 2) { 875 pixel_ptr[x ] = 876 pixel_ptr[x + 1 ] = 877 pixel_ptr[x + s->stride] = 878 pixel_ptr[x + 1 + s->stride] = bytestream_get_le16(&s->stream_ptr); 879 } 880 pixel_ptr += s->stride * 2; 881 } 882 883 /* report success */ 884 return 0; 885} 886 887static int ipvideo_decode_block_opcode_0xD_16(IpvideoContext *s) 888{ 889 int x, y; 890 uint16_t P[2]; 891 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 892 893 /* 4-color block encoding: each 4x4 block is a different color */ 894 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 895 896 for (y = 0; y < 8; y++) { 897 if (!(y & 3)) { 898 P[0] = bytestream_get_le16(&s->stream_ptr); 899 P[1] = bytestream_get_le16(&s->stream_ptr); 900 } 901 for (x = 0; x < 8; x++) 902 pixel_ptr[x] = P[x >> 2]; 903 pixel_ptr += s->stride; 904 } 905 906 /* report success */ 907 return 0; 908} 909 910static int ipvideo_decode_block_opcode_0xE_16(IpvideoContext *s) 911{ 912 int x, y; 913 uint16_t pix; 914 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 915 916 /* 1-color encoding: the whole block is 1 solid color */ 917 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 918 pix = bytestream_get_le16(&s->stream_ptr); 919 920 for (y = 0; y < 8; y++) { 921 for (x = 0; x < 8; x++) 922 pixel_ptr[x] = pix; 923 pixel_ptr += s->stride; 924 } 925 926 /* report success */ 927 return 0; 928} 929 930static int (* const ipvideo_decode_block[])(IpvideoContext *s) = { 931 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1, 932 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3, 933 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5, 934 ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7, 935 ipvideo_decode_block_opcode_0x8, ipvideo_decode_block_opcode_0x9, 936 ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB, 937 ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD, 938 ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF, 939}; 940 941static int (* const ipvideo_decode_block16[])(IpvideoContext *s) = { 942 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1, 943 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3, 944 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5, 945 ipvideo_decode_block_opcode_0x6_16, ipvideo_decode_block_opcode_0x7_16, 946 ipvideo_decode_block_opcode_0x8_16, ipvideo_decode_block_opcode_0x9_16, 947 ipvideo_decode_block_opcode_0xA_16, ipvideo_decode_block_opcode_0xB_16, 948 ipvideo_decode_block_opcode_0xC_16, ipvideo_decode_block_opcode_0xD_16, 949 ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1, 950}; 951 952static void ipvideo_decode_opcodes(IpvideoContext *s) 953{ 954 int x, y; 955 unsigned char opcode; 956 int ret; 957 static int frame = 0; 958 GetBitContext gb; 959 960 av_dlog(NULL, "------------------ frame %d\n", frame); 961 frame++; 962 963 if (!s->is_16bpp) { 964 /* this is PAL8, so make the palette available */ 965 memcpy(s->current_frame.data[1], s->pal, AVPALETTE_SIZE); 966 967 s->stride = s->current_frame.linesize[0]; 968 s->stream_ptr = s->buf + 14; /* data starts 14 bytes in */ 969 s->stream_end = s->buf + s->size; 970 } else { 971 s->stride = s->current_frame.linesize[0] >> 1; 972 s->stream_ptr = s->buf + 16; 973 s->stream_end = 974 s->mv_ptr = s->buf + 14 + AV_RL16(s->buf+14); 975 s->mv_end = s->buf + s->size; 976 } 977 s->line_inc = s->stride - 8; 978 s->upper_motion_limit_offset = (s->avctx->height - 8) * s->current_frame.linesize[0] 979 + (s->avctx->width - 8) * (1 + s->is_16bpp); 980 981 init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8); 982 for (y = 0; y < s->avctx->height; y += 8) { 983 for (x = 0; x < s->avctx->width; x += 8) { 984 opcode = get_bits(&gb, 4); 985 986 av_dlog(NULL, " block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n", 987 x, y, opcode, s->stream_ptr); 988 989 if (!s->is_16bpp) { 990 s->pixel_ptr = s->current_frame.data[0] + x 991 + y*s->current_frame.linesize[0]; 992 ret = ipvideo_decode_block[opcode](s); 993 } else { 994 s->pixel_ptr = s->current_frame.data[0] + x*2 995 + y*s->current_frame.linesize[0]; 996 ret = ipvideo_decode_block16[opcode](s); 997 } 998 if (ret != 0) { 999 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n", 1000 frame, x, y); 1001 return; 1002 } 1003 } 1004 } 1005 if (s->stream_end - s->stream_ptr > 1) { 1006 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %td bytes left over\n", 1007 s->stream_end - s->stream_ptr); 1008 } 1009} 1010 1011static av_cold int ipvideo_decode_init(AVCodecContext *avctx) 1012{ 1013 IpvideoContext *s = avctx->priv_data; 1014 1015 s->avctx = avctx; 1016 1017 s->is_16bpp = avctx->bits_per_coded_sample == 16; 1018 avctx->pix_fmt = s->is_16bpp ? PIX_FMT_RGB555 : PIX_FMT_PAL8; 1019 1020 dsputil_init(&s->dsp, avctx); 1021 1022 s->current_frame.data[0] = s->last_frame.data[0] = 1023 s->second_last_frame.data[0] = NULL; 1024 1025 return 0; 1026} 1027 1028static int ipvideo_decode_frame(AVCodecContext *avctx, 1029 void *data, int *data_size, 1030 AVPacket *avpkt) 1031{ 1032 const uint8_t *buf = avpkt->data; 1033 int buf_size = avpkt->size; 1034 IpvideoContext *s = avctx->priv_data; 1035 1036 /* decoding map contains 4 bits of information per 8x8 block */ 1037 s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2); 1038 1039 /* compressed buffer needs to be large enough to at least hold an entire 1040 * decoding map */ 1041 if (buf_size < s->decoding_map_size) 1042 return buf_size; 1043 1044 s->decoding_map = buf; 1045 s->buf = buf + s->decoding_map_size; 1046 s->size = buf_size - s->decoding_map_size; 1047 1048 s->current_frame.reference = 3; 1049 if (avctx->get_buffer(avctx, &s->current_frame)) { 1050 av_log(avctx, AV_LOG_ERROR, " Interplay Video: get_buffer() failed\n"); 1051 return -1; 1052 } 1053 1054 if (!s->is_16bpp) { 1055 const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL); 1056 if (pal) { 1057 s->current_frame.palette_has_changed = 1; 1058 memcpy(s->pal, pal, AVPALETTE_SIZE); 1059 } 1060 } 1061 1062 ipvideo_decode_opcodes(s); 1063 1064 *data_size = sizeof(AVFrame); 1065 *(AVFrame*)data = s->current_frame; 1066 1067 /* shuffle frames */ 1068 if (s->second_last_frame.data[0]) 1069 avctx->release_buffer(avctx, &s->second_last_frame); 1070 s->second_last_frame = s->last_frame; 1071 s->last_frame = s->current_frame; 1072 s->current_frame.data[0] = NULL; /* catch any access attempts */ 1073 1074 /* report that the buffer was completely consumed */ 1075 return buf_size; 1076} 1077 1078static av_cold int ipvideo_decode_end(AVCodecContext *avctx) 1079{ 1080 IpvideoContext *s = avctx->priv_data; 1081 1082 /* release the last frame */ 1083 if (s->last_frame.data[0]) 1084 avctx->release_buffer(avctx, &s->last_frame); 1085 if (s->second_last_frame.data[0]) 1086 avctx->release_buffer(avctx, &s->second_last_frame); 1087 1088 return 0; 1089} 1090 1091AVCodec ff_interplay_video_decoder = { 1092 .name = "interplayvideo", 1093 .type = AVMEDIA_TYPE_VIDEO, 1094 .id = CODEC_ID_INTERPLAY_VIDEO, 1095 .priv_data_size = sizeof(IpvideoContext), 1096 .init = ipvideo_decode_init, 1097 .close = ipvideo_decode_end, 1098 .decode = ipvideo_decode_frame, 1099 .capabilities = CODEC_CAP_DR1 | CODEC_CAP_PARAM_CHANGE, 1100 .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"), 1101}; 1102