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