Libav
|
00001 /* 00002 * Interplay MVE Video Decoder 00003 * Copyright (C) 2003 the ffmpeg project 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00037 #include <stdio.h> 00038 #include <stdlib.h> 00039 #include <string.h> 00040 00041 #include "avcodec.h" 00042 #include "bytestream.h" 00043 #include "dsputil.h" 00044 #define ALT_BITSTREAM_READER_LE 00045 #include "get_bits.h" 00046 00047 #define PALETTE_COUNT 256 00048 00049 /* debugging support */ 00050 #define DEBUG_INTERPLAY 0 00051 #if DEBUG_INTERPLAY 00052 #define debug_interplay(x,...) av_log(NULL, AV_LOG_DEBUG, x, __VA_ARGS__) 00053 #else 00054 static inline void debug_interplay(const char *format, ...) { } 00055 #endif 00056 00057 typedef struct IpvideoContext { 00058 00059 AVCodecContext *avctx; 00060 DSPContext dsp; 00061 AVFrame second_last_frame; 00062 AVFrame last_frame; 00063 AVFrame current_frame; 00064 const unsigned char *decoding_map; 00065 int decoding_map_size; 00066 00067 const unsigned char *buf; 00068 int size; 00069 00070 int is_16bpp; 00071 const unsigned char *stream_ptr; 00072 const unsigned char *stream_end; 00073 const uint8_t *mv_ptr; 00074 const uint8_t *mv_end; 00075 unsigned char *pixel_ptr; 00076 int line_inc; 00077 int stride; 00078 int upper_motion_limit_offset; 00079 00080 } IpvideoContext; 00081 00082 #define CHECK_STREAM_PTR(stream_ptr, stream_end, n) \ 00083 if (stream_end - stream_ptr < n) { \ 00084 av_log(s->avctx, AV_LOG_ERROR, "Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \ 00085 stream_ptr + n, stream_end); \ 00086 return -1; \ 00087 } 00088 00089 static int copy_from(IpvideoContext *s, AVFrame *src, int delta_x, int delta_y) 00090 { 00091 int current_offset = s->pixel_ptr - s->current_frame.data[0]; 00092 int motion_offset = current_offset + delta_y * s->current_frame.linesize[0] 00093 + delta_x * (1 + s->is_16bpp); 00094 if (motion_offset < 0) { 00095 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset); 00096 return -1; 00097 } else if (motion_offset > s->upper_motion_limit_offset) { 00098 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n", 00099 motion_offset, s->upper_motion_limit_offset); 00100 return -1; 00101 } 00102 s->dsp.put_pixels_tab[!s->is_16bpp][0](s->pixel_ptr, src->data[0] + motion_offset, 00103 s->current_frame.linesize[0], 8); 00104 return 0; 00105 } 00106 00107 static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s) 00108 { 00109 return copy_from(s, &s->last_frame, 0, 0); 00110 } 00111 00112 static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s) 00113 { 00114 return copy_from(s, &s->second_last_frame, 0, 0); 00115 } 00116 00117 static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s) 00118 { 00119 unsigned char B; 00120 int x, y; 00121 00122 /* copy block from 2 frames ago using a motion vector; need 1 more byte */ 00123 if (!s->is_16bpp) { 00124 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1); 00125 B = *s->stream_ptr++; 00126 } else { 00127 CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1); 00128 B = *s->mv_ptr++; 00129 } 00130 00131 if (B < 56) { 00132 x = 8 + (B % 7); 00133 y = B / 7; 00134 } else { 00135 x = -14 + ((B - 56) % 29); 00136 y = 8 + ((B - 56) / 29); 00137 } 00138 00139 debug_interplay (" motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); 00140 return copy_from(s, &s->second_last_frame, x, y); 00141 } 00142 00143 static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s) 00144 { 00145 unsigned char B; 00146 int x, y; 00147 00148 /* copy 8x8 block from current frame from an up/left block */ 00149 00150 /* need 1 more byte for motion */ 00151 if (!s->is_16bpp) { 00152 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1); 00153 B = *s->stream_ptr++; 00154 } else { 00155 CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1); 00156 B = *s->mv_ptr++; 00157 } 00158 00159 if (B < 56) { 00160 x = -(8 + (B % 7)); 00161 y = -(B / 7); 00162 } else { 00163 x = -(-14 + ((B - 56) % 29)); 00164 y = -( 8 + ((B - 56) / 29)); 00165 } 00166 00167 debug_interplay (" motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); 00168 return copy_from(s, &s->current_frame, x, y); 00169 } 00170 00171 static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s) 00172 { 00173 int x, y; 00174 unsigned char B, BL, BH; 00175 00176 /* copy a block from the previous frame; need 1 more byte */ 00177 if (!s->is_16bpp) { 00178 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1); 00179 B = *s->stream_ptr++; 00180 } else { 00181 CHECK_STREAM_PTR(s->mv_ptr, s->mv_end, 1); 00182 B = *s->mv_ptr++; 00183 } 00184 00185 BL = B & 0x0F; 00186 BH = (B >> 4) & 0x0F; 00187 x = -8 + BL; 00188 y = -8 + BH; 00189 00190 debug_interplay (" motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); 00191 return copy_from(s, &s->last_frame, x, y); 00192 } 00193 00194 static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s) 00195 { 00196 signed char x, y; 00197 00198 /* copy a block from the previous frame using an expanded range; 00199 * need 2 more bytes */ 00200 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 00201 00202 x = *s->stream_ptr++; 00203 y = *s->stream_ptr++; 00204 00205 debug_interplay (" motion bytes = %d, %d\n", x, y); 00206 return copy_from(s, &s->last_frame, x, y); 00207 } 00208 00209 static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s) 00210 { 00211 /* mystery opcode? skip multiple blocks? */ 00212 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: Help! Mystery opcode 0x6 seen\n"); 00213 00214 /* report success */ 00215 return 0; 00216 } 00217 00218 static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s) 00219 { 00220 int x, y; 00221 unsigned char P[2]; 00222 unsigned int flags; 00223 00224 /* 2-color encoding */ 00225 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 00226 00227 P[0] = *s->stream_ptr++; 00228 P[1] = *s->stream_ptr++; 00229 00230 if (P[0] <= P[1]) { 00231 00232 /* need 8 more bytes from the stream */ 00233 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 00234 00235 for (y = 0; y < 8; y++) { 00236 flags = *s->stream_ptr++ | 0x100; 00237 for (; flags != 1; flags >>= 1) 00238 *s->pixel_ptr++ = P[flags & 1]; 00239 s->pixel_ptr += s->line_inc; 00240 } 00241 00242 } else { 00243 00244 /* need 2 more bytes from the stream */ 00245 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 00246 00247 flags = bytestream_get_le16(&s->stream_ptr); 00248 for (y = 0; y < 8; y += 2) { 00249 for (x = 0; x < 8; x += 2, flags >>= 1) { 00250 s->pixel_ptr[x ] = 00251 s->pixel_ptr[x + 1 ] = 00252 s->pixel_ptr[x + s->stride] = 00253 s->pixel_ptr[x + 1 + s->stride] = P[flags & 1]; 00254 } 00255 s->pixel_ptr += s->stride * 2; 00256 } 00257 } 00258 00259 /* report success */ 00260 return 0; 00261 } 00262 00263 static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s) 00264 { 00265 int x, y; 00266 unsigned char P[2]; 00267 unsigned int flags = 0; 00268 00269 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on 00270 * either top and bottom or left and right halves */ 00271 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 00272 00273 P[0] = *s->stream_ptr++; 00274 P[1] = *s->stream_ptr++; 00275 00276 if (P[0] <= P[1]) { 00277 00278 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 14); 00279 s->stream_ptr -= 2; 00280 00281 for (y = 0; y < 16; y++) { 00282 // new values for each 4x4 block 00283 if (!(y & 3)) { 00284 P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++; 00285 flags = bytestream_get_le16(&s->stream_ptr); 00286 } 00287 00288 for (x = 0; x < 4; x++, flags >>= 1) 00289 *s->pixel_ptr++ = P[flags & 1]; 00290 s->pixel_ptr += s->stride - 4; 00291 // switch to right half 00292 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4; 00293 } 00294 00295 } else { 00296 00297 /* need 10 more bytes */ 00298 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 10); 00299 00300 if (s->stream_ptr[4] <= s->stream_ptr[5]) { 00301 00302 flags = bytestream_get_le32(&s->stream_ptr); 00303 00304 /* vertical split; left & right halves are 2-color encoded */ 00305 00306 for (y = 0; y < 16; y++) { 00307 for (x = 0; x < 4; x++, flags >>= 1) 00308 *s->pixel_ptr++ = P[flags & 1]; 00309 s->pixel_ptr += s->stride - 4; 00310 // switch to right half 00311 if (y == 7) { 00312 s->pixel_ptr -= 8 * s->stride - 4; 00313 P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++; 00314 flags = bytestream_get_le32(&s->stream_ptr); 00315 } 00316 } 00317 00318 } else { 00319 00320 /* horizontal split; top & bottom halves are 2-color encoded */ 00321 00322 for (y = 0; y < 8; y++) { 00323 if (y == 4) { 00324 P[0] = *s->stream_ptr++; 00325 P[1] = *s->stream_ptr++; 00326 } 00327 flags = *s->stream_ptr++ | 0x100; 00328 00329 for (; flags != 1; flags >>= 1) 00330 *s->pixel_ptr++ = P[flags & 1]; 00331 s->pixel_ptr += s->line_inc; 00332 } 00333 } 00334 } 00335 00336 /* report success */ 00337 return 0; 00338 } 00339 00340 static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s) 00341 { 00342 int x, y; 00343 unsigned char P[4]; 00344 00345 /* 4-color encoding */ 00346 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 00347 00348 memcpy(P, s->stream_ptr, 4); 00349 s->stream_ptr += 4; 00350 00351 if (P[0] <= P[1]) { 00352 if (P[2] <= P[3]) { 00353 00354 /* 1 of 4 colors for each pixel, need 16 more bytes */ 00355 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16); 00356 00357 for (y = 0; y < 8; y++) { 00358 /* get the next set of 8 2-bit flags */ 00359 int flags = bytestream_get_le16(&s->stream_ptr); 00360 for (x = 0; x < 8; x++, flags >>= 2) 00361 *s->pixel_ptr++ = P[flags & 0x03]; 00362 s->pixel_ptr += s->line_inc; 00363 } 00364 00365 } else { 00366 uint32_t flags; 00367 00368 /* 1 of 4 colors for each 2x2 block, need 4 more bytes */ 00369 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 00370 00371 flags = bytestream_get_le32(&s->stream_ptr); 00372 00373 for (y = 0; y < 8; y += 2) { 00374 for (x = 0; x < 8; x += 2, flags >>= 2) { 00375 s->pixel_ptr[x ] = 00376 s->pixel_ptr[x + 1 ] = 00377 s->pixel_ptr[x + s->stride] = 00378 s->pixel_ptr[x + 1 + s->stride] = P[flags & 0x03]; 00379 } 00380 s->pixel_ptr += s->stride * 2; 00381 } 00382 00383 } 00384 } else { 00385 uint64_t flags; 00386 00387 /* 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes */ 00388 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 00389 00390 flags = bytestream_get_le64(&s->stream_ptr); 00391 if (P[2] <= P[3]) { 00392 for (y = 0; y < 8; y++) { 00393 for (x = 0; x < 8; x += 2, flags >>= 2) { 00394 s->pixel_ptr[x ] = 00395 s->pixel_ptr[x + 1] = P[flags & 0x03]; 00396 } 00397 s->pixel_ptr += s->stride; 00398 } 00399 } else { 00400 for (y = 0; y < 8; y += 2) { 00401 for (x = 0; x < 8; x++, flags >>= 2) { 00402 s->pixel_ptr[x ] = 00403 s->pixel_ptr[x + s->stride] = P[flags & 0x03]; 00404 } 00405 s->pixel_ptr += s->stride * 2; 00406 } 00407 } 00408 } 00409 00410 /* report success */ 00411 return 0; 00412 } 00413 00414 static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s) 00415 { 00416 int x, y; 00417 unsigned char P[4]; 00418 int flags = 0; 00419 00420 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on 00421 * either top and bottom or left and right halves */ 00422 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24); 00423 00424 if (s->stream_ptr[0] <= s->stream_ptr[1]) { 00425 00426 /* 4-color encoding for each quadrant; need 32 bytes */ 00427 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32); 00428 00429 for (y = 0; y < 16; y++) { 00430 // new values for each 4x4 block 00431 if (!(y & 3)) { 00432 memcpy(P, s->stream_ptr, 4); 00433 s->stream_ptr += 4; 00434 flags = bytestream_get_le32(&s->stream_ptr); 00435 } 00436 00437 for (x = 0; x < 4; x++, flags >>= 2) 00438 *s->pixel_ptr++ = P[flags & 0x03]; 00439 00440 s->pixel_ptr += s->stride - 4; 00441 // switch to right half 00442 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4; 00443 } 00444 00445 } else { 00446 // vertical split? 00447 int vert = s->stream_ptr[12] <= s->stream_ptr[13]; 00448 uint64_t flags = 0; 00449 00450 /* 4-color encoding for either left and right or top and bottom 00451 * halves */ 00452 00453 for (y = 0; y < 16; y++) { 00454 // load values for each half 00455 if (!(y & 7)) { 00456 memcpy(P, s->stream_ptr, 4); 00457 s->stream_ptr += 4; 00458 flags = bytestream_get_le64(&s->stream_ptr); 00459 } 00460 00461 for (x = 0; x < 4; x++, flags >>= 2) 00462 *s->pixel_ptr++ = P[flags & 0x03]; 00463 00464 if (vert) { 00465 s->pixel_ptr += s->stride - 4; 00466 // switch to right half 00467 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4; 00468 } else if (y & 1) s->pixel_ptr += s->line_inc; 00469 } 00470 } 00471 00472 /* report success */ 00473 return 0; 00474 } 00475 00476 static int ipvideo_decode_block_opcode_0xB(IpvideoContext *s) 00477 { 00478 int y; 00479 00480 /* 64-color encoding (each pixel in block is a different color) */ 00481 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 64); 00482 00483 for (y = 0; y < 8; y++) { 00484 memcpy(s->pixel_ptr, s->stream_ptr, 8); 00485 s->stream_ptr += 8; 00486 s->pixel_ptr += s->stride; 00487 } 00488 00489 /* report success */ 00490 return 0; 00491 } 00492 00493 static int ipvideo_decode_block_opcode_0xC(IpvideoContext *s) 00494 { 00495 int x, y; 00496 00497 /* 16-color block encoding: each 2x2 block is a different color */ 00498 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16); 00499 00500 for (y = 0; y < 8; y += 2) { 00501 for (x = 0; x < 8; x += 2) { 00502 s->pixel_ptr[x ] = 00503 s->pixel_ptr[x + 1 ] = 00504 s->pixel_ptr[x + s->stride] = 00505 s->pixel_ptr[x + 1 + s->stride] = *s->stream_ptr++; 00506 } 00507 s->pixel_ptr += s->stride * 2; 00508 } 00509 00510 /* report success */ 00511 return 0; 00512 } 00513 00514 static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s) 00515 { 00516 int y; 00517 unsigned char P[2]; 00518 00519 /* 4-color block encoding: each 4x4 block is a different color */ 00520 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 00521 00522 for (y = 0; y < 8; y++) { 00523 if (!(y & 3)) { 00524 P[0] = *s->stream_ptr++; 00525 P[1] = *s->stream_ptr++; 00526 } 00527 memset(s->pixel_ptr, P[0], 4); 00528 memset(s->pixel_ptr + 4, P[1], 4); 00529 s->pixel_ptr += s->stride; 00530 } 00531 00532 /* report success */ 00533 return 0; 00534 } 00535 00536 static int ipvideo_decode_block_opcode_0xE(IpvideoContext *s) 00537 { 00538 int y; 00539 unsigned char pix; 00540 00541 /* 1-color encoding: the whole block is 1 solid color */ 00542 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1); 00543 pix = *s->stream_ptr++; 00544 00545 for (y = 0; y < 8; y++) { 00546 memset(s->pixel_ptr, pix, 8); 00547 s->pixel_ptr += s->stride; 00548 } 00549 00550 /* report success */ 00551 return 0; 00552 } 00553 00554 static int ipvideo_decode_block_opcode_0xF(IpvideoContext *s) 00555 { 00556 int x, y; 00557 unsigned char sample[2]; 00558 00559 /* dithered encoding */ 00560 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 00561 sample[0] = *s->stream_ptr++; 00562 sample[1] = *s->stream_ptr++; 00563 00564 for (y = 0; y < 8; y++) { 00565 for (x = 0; x < 8; x += 2) { 00566 *s->pixel_ptr++ = sample[ y & 1 ]; 00567 *s->pixel_ptr++ = sample[!(y & 1)]; 00568 } 00569 s->pixel_ptr += s->line_inc; 00570 } 00571 00572 /* report success */ 00573 return 0; 00574 } 00575 00576 static int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s) 00577 { 00578 signed char x, y; 00579 00580 /* copy a block from the second last frame using an expanded range */ 00581 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 00582 00583 x = *s->stream_ptr++; 00584 y = *s->stream_ptr++; 00585 00586 debug_interplay (" motion bytes = %d, %d\n", x, y); 00587 return copy_from(s, &s->second_last_frame, x, y); 00588 } 00589 00590 static int ipvideo_decode_block_opcode_0x7_16(IpvideoContext *s) 00591 { 00592 int x, y; 00593 uint16_t P[2]; 00594 unsigned int flags; 00595 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 00596 00597 /* 2-color encoding */ 00598 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 00599 00600 P[0] = bytestream_get_le16(&s->stream_ptr); 00601 P[1] = bytestream_get_le16(&s->stream_ptr); 00602 00603 if (!(P[0] & 0x8000)) { 00604 00605 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 00606 00607 for (y = 0; y < 8; y++) { 00608 flags = *s->stream_ptr++ | 0x100; 00609 for (; flags != 1; flags >>= 1) 00610 *pixel_ptr++ = P[flags & 1]; 00611 pixel_ptr += s->line_inc; 00612 } 00613 00614 } else { 00615 00616 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 00617 00618 flags = bytestream_get_le16(&s->stream_ptr); 00619 for (y = 0; y < 8; y += 2) { 00620 for (x = 0; x < 8; x += 2, flags >>= 1) { 00621 pixel_ptr[x ] = 00622 pixel_ptr[x + 1 ] = 00623 pixel_ptr[x + s->stride] = 00624 pixel_ptr[x + 1 + s->stride] = P[flags & 1]; 00625 } 00626 pixel_ptr += s->stride * 2; 00627 } 00628 } 00629 00630 return 0; 00631 } 00632 00633 static int ipvideo_decode_block_opcode_0x8_16(IpvideoContext *s) 00634 { 00635 int x, y; 00636 uint16_t P[2]; 00637 unsigned int flags = 0; 00638 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 00639 00640 /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on 00641 * either top and bottom or left and right halves */ 00642 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 00643 00644 P[0] = bytestream_get_le16(&s->stream_ptr); 00645 P[1] = bytestream_get_le16(&s->stream_ptr); 00646 00647 if (!(P[0] & 0x8000)) { 00648 00649 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24); 00650 s->stream_ptr -= 4; 00651 00652 for (y = 0; y < 16; y++) { 00653 // new values for each 4x4 block 00654 if (!(y & 3)) { 00655 P[0] = bytestream_get_le16(&s->stream_ptr); 00656 P[1] = bytestream_get_le16(&s->stream_ptr); 00657 flags = bytestream_get_le16(&s->stream_ptr); 00658 } 00659 00660 for (x = 0; x < 4; x++, flags >>= 1) 00661 *pixel_ptr++ = P[flags & 1]; 00662 pixel_ptr += s->stride - 4; 00663 // switch to right half 00664 if (y == 7) pixel_ptr -= 8 * s->stride - 4; 00665 } 00666 00667 } else { 00668 00669 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 12); 00670 00671 if (!(AV_RL16(s->stream_ptr + 4) & 0x8000)) { 00672 00673 flags = bytestream_get_le32(&s->stream_ptr); 00674 00675 /* vertical split; left & right halves are 2-color encoded */ 00676 00677 for (y = 0; y < 16; y++) { 00678 for (x = 0; x < 4; x++, flags >>= 1) 00679 *pixel_ptr++ = P[flags & 1]; 00680 pixel_ptr += s->stride - 4; 00681 // switch to right half 00682 if (y == 7) { 00683 pixel_ptr -= 8 * s->stride - 4; 00684 P[0] = bytestream_get_le16(&s->stream_ptr); 00685 P[1] = bytestream_get_le16(&s->stream_ptr); 00686 flags = bytestream_get_le32(&s->stream_ptr); 00687 } 00688 } 00689 00690 } else { 00691 00692 /* horizontal split; top & bottom halves are 2-color encoded */ 00693 00694 for (y = 0; y < 8; y++) { 00695 if (y == 4) { 00696 P[0] = bytestream_get_le16(&s->stream_ptr); 00697 P[1] = bytestream_get_le16(&s->stream_ptr); 00698 } 00699 flags = *s->stream_ptr++ | 0x100; 00700 00701 for (; flags != 1; flags >>= 1) 00702 *pixel_ptr++ = P[flags & 1]; 00703 pixel_ptr += s->line_inc; 00704 } 00705 } 00706 } 00707 00708 /* report success */ 00709 return 0; 00710 } 00711 00712 static int ipvideo_decode_block_opcode_0x9_16(IpvideoContext *s) 00713 { 00714 int x, y; 00715 uint16_t P[4]; 00716 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 00717 00718 /* 4-color encoding */ 00719 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 00720 00721 for (x = 0; x < 4; x++) 00722 P[x] = bytestream_get_le16(&s->stream_ptr); 00723 00724 if (!(P[0] & 0x8000)) { 00725 if (!(P[2] & 0x8000)) { 00726 00727 /* 1 of 4 colors for each pixel */ 00728 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16); 00729 00730 for (y = 0; y < 8; y++) { 00731 /* get the next set of 8 2-bit flags */ 00732 int flags = bytestream_get_le16(&s->stream_ptr); 00733 for (x = 0; x < 8; x++, flags >>= 2) 00734 *pixel_ptr++ = P[flags & 0x03]; 00735 pixel_ptr += s->line_inc; 00736 } 00737 00738 } else { 00739 uint32_t flags; 00740 00741 /* 1 of 4 colors for each 2x2 block */ 00742 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4); 00743 00744 flags = bytestream_get_le32(&s->stream_ptr); 00745 00746 for (y = 0; y < 8; y += 2) { 00747 for (x = 0; x < 8; x += 2, flags >>= 2) { 00748 pixel_ptr[x ] = 00749 pixel_ptr[x + 1 ] = 00750 pixel_ptr[x + s->stride] = 00751 pixel_ptr[x + 1 + s->stride] = P[flags & 0x03]; 00752 } 00753 pixel_ptr += s->stride * 2; 00754 } 00755 00756 } 00757 } else { 00758 uint64_t flags; 00759 00760 /* 1 of 4 colors for each 2x1 or 1x2 block */ 00761 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 00762 00763 flags = bytestream_get_le64(&s->stream_ptr); 00764 if (!(P[2] & 0x8000)) { 00765 for (y = 0; y < 8; y++) { 00766 for (x = 0; x < 8; x += 2, flags >>= 2) { 00767 pixel_ptr[x ] = 00768 pixel_ptr[x + 1] = P[flags & 0x03]; 00769 } 00770 pixel_ptr += s->stride; 00771 } 00772 } else { 00773 for (y = 0; y < 8; y += 2) { 00774 for (x = 0; x < 8; x++, flags >>= 2) { 00775 pixel_ptr[x ] = 00776 pixel_ptr[x + s->stride] = P[flags & 0x03]; 00777 } 00778 pixel_ptr += s->stride * 2; 00779 } 00780 } 00781 } 00782 00783 /* report success */ 00784 return 0; 00785 } 00786 00787 static int ipvideo_decode_block_opcode_0xA_16(IpvideoContext *s) 00788 { 00789 int x, y; 00790 uint16_t P[4]; 00791 int flags = 0; 00792 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 00793 00794 /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on 00795 * either top and bottom or left and right halves */ 00796 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24); 00797 00798 if (!(AV_RL16(s->stream_ptr) & 0x8000)) { 00799 00800 /* 4-color encoding for each quadrant */ 00801 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 48); 00802 00803 for (y = 0; y < 16; y++) { 00804 // new values for each 4x4 block 00805 if (!(y & 3)) { 00806 for (x = 0; x < 4; x++) 00807 P[x] = bytestream_get_le16(&s->stream_ptr); 00808 flags = bytestream_get_le32(&s->stream_ptr); 00809 } 00810 00811 for (x = 0; x < 4; x++, flags >>= 2) 00812 *pixel_ptr++ = P[flags & 0x03]; 00813 00814 pixel_ptr += s->stride - 4; 00815 // switch to right half 00816 if (y == 7) pixel_ptr -= 8 * s->stride - 4; 00817 } 00818 00819 } else { 00820 // vertical split? 00821 int vert = !(AV_RL16(s->stream_ptr + 16) & 0x8000); 00822 uint64_t flags = 0; 00823 00824 /* 4-color encoding for either left and right or top and bottom 00825 * halves */ 00826 00827 for (y = 0; y < 16; y++) { 00828 // load values for each half 00829 if (!(y & 7)) { 00830 for (x = 0; x < 4; x++) 00831 P[x] = bytestream_get_le16(&s->stream_ptr); 00832 flags = bytestream_get_le64(&s->stream_ptr); 00833 } 00834 00835 for (x = 0; x < 4; x++, flags >>= 2) 00836 *pixel_ptr++ = P[flags & 0x03]; 00837 00838 if (vert) { 00839 pixel_ptr += s->stride - 4; 00840 // switch to right half 00841 if (y == 7) pixel_ptr -= 8 * s->stride - 4; 00842 } else if (y & 1) pixel_ptr += s->line_inc; 00843 } 00844 } 00845 00846 /* report success */ 00847 return 0; 00848 } 00849 00850 static int ipvideo_decode_block_opcode_0xB_16(IpvideoContext *s) 00851 { 00852 int x, y; 00853 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 00854 00855 /* 64-color encoding (each pixel in block is a different color) */ 00856 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 128); 00857 00858 for (y = 0; y < 8; y++) { 00859 for (x = 0; x < 8; x++) 00860 pixel_ptr[x] = bytestream_get_le16(&s->stream_ptr); 00861 pixel_ptr += s->stride; 00862 } 00863 00864 /* report success */ 00865 return 0; 00866 } 00867 00868 static int ipvideo_decode_block_opcode_0xC_16(IpvideoContext *s) 00869 { 00870 int x, y; 00871 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 00872 00873 /* 16-color block encoding: each 2x2 block is a different color */ 00874 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32); 00875 00876 for (y = 0; y < 8; y += 2) { 00877 for (x = 0; x < 8; x += 2) { 00878 pixel_ptr[x ] = 00879 pixel_ptr[x + 1 ] = 00880 pixel_ptr[x + s->stride] = 00881 pixel_ptr[x + 1 + s->stride] = bytestream_get_le16(&s->stream_ptr); 00882 } 00883 pixel_ptr += s->stride * 2; 00884 } 00885 00886 /* report success */ 00887 return 0; 00888 } 00889 00890 static int ipvideo_decode_block_opcode_0xD_16(IpvideoContext *s) 00891 { 00892 int x, y; 00893 uint16_t P[2]; 00894 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 00895 00896 /* 4-color block encoding: each 4x4 block is a different color */ 00897 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8); 00898 00899 for (y = 0; y < 8; y++) { 00900 if (!(y & 3)) { 00901 P[0] = bytestream_get_le16(&s->stream_ptr); 00902 P[1] = bytestream_get_le16(&s->stream_ptr); 00903 } 00904 for (x = 0; x < 8; x++) 00905 pixel_ptr[x] = P[x >> 2]; 00906 pixel_ptr += s->stride; 00907 } 00908 00909 /* report success */ 00910 return 0; 00911 } 00912 00913 static int ipvideo_decode_block_opcode_0xE_16(IpvideoContext *s) 00914 { 00915 int x, y; 00916 uint16_t pix; 00917 uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 00918 00919 /* 1-color encoding: the whole block is 1 solid color */ 00920 CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2); 00921 pix = bytestream_get_le16(&s->stream_ptr); 00922 00923 for (y = 0; y < 8; y++) { 00924 for (x = 0; x < 8; x++) 00925 pixel_ptr[x] = pix; 00926 pixel_ptr += s->stride; 00927 } 00928 00929 /* report success */ 00930 return 0; 00931 } 00932 00933 static int (* const ipvideo_decode_block[])(IpvideoContext *s) = { 00934 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1, 00935 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3, 00936 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5, 00937 ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7, 00938 ipvideo_decode_block_opcode_0x8, ipvideo_decode_block_opcode_0x9, 00939 ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB, 00940 ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD, 00941 ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF, 00942 }; 00943 00944 static int (* const ipvideo_decode_block16[])(IpvideoContext *s) = { 00945 ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1, 00946 ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3, 00947 ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5, 00948 ipvideo_decode_block_opcode_0x6_16, ipvideo_decode_block_opcode_0x7_16, 00949 ipvideo_decode_block_opcode_0x8_16, ipvideo_decode_block_opcode_0x9_16, 00950 ipvideo_decode_block_opcode_0xA_16, ipvideo_decode_block_opcode_0xB_16, 00951 ipvideo_decode_block_opcode_0xC_16, ipvideo_decode_block_opcode_0xD_16, 00952 ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1, 00953 }; 00954 00955 static void ipvideo_decode_opcodes(IpvideoContext *s) 00956 { 00957 int x, y; 00958 unsigned char opcode; 00959 int ret; 00960 static int frame = 0; 00961 GetBitContext gb; 00962 00963 debug_interplay("------------------ frame %d\n", frame); 00964 frame++; 00965 00966 if (!s->is_16bpp) { 00967 /* this is PAL8, so make the palette available */ 00968 memcpy(s->current_frame.data[1], s->avctx->palctrl->palette, PALETTE_COUNT * 4); 00969 00970 s->stride = s->current_frame.linesize[0]; 00971 s->stream_ptr = s->buf + 14; /* data starts 14 bytes in */ 00972 s->stream_end = s->buf + s->size; 00973 } else { 00974 s->stride = s->current_frame.linesize[0] >> 1; 00975 s->stream_ptr = s->buf + 16; 00976 s->stream_end = 00977 s->mv_ptr = s->buf + 14 + AV_RL16(s->buf+14); 00978 s->mv_end = s->buf + s->size; 00979 } 00980 s->line_inc = s->stride - 8; 00981 s->upper_motion_limit_offset = (s->avctx->height - 8) * s->current_frame.linesize[0] 00982 + (s->avctx->width - 8) * (1 + s->is_16bpp); 00983 00984 init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8); 00985 for (y = 0; y < s->avctx->height; y += 8) { 00986 for (x = 0; x < s->avctx->width; x += 8) { 00987 opcode = get_bits(&gb, 4); 00988 00989 debug_interplay(" block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n", 00990 x, y, opcode, s->stream_ptr); 00991 00992 if (!s->is_16bpp) { 00993 s->pixel_ptr = s->current_frame.data[0] + x 00994 + y*s->current_frame.linesize[0]; 00995 ret = ipvideo_decode_block[opcode](s); 00996 } else { 00997 s->pixel_ptr = s->current_frame.data[0] + x*2 00998 + y*s->current_frame.linesize[0]; 00999 ret = ipvideo_decode_block16[opcode](s); 01000 } 01001 if (ret != 0) { 01002 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n", 01003 frame, x, y); 01004 return; 01005 } 01006 } 01007 } 01008 if (s->stream_end - s->stream_ptr > 1) { 01009 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %td bytes left over\n", 01010 s->stream_end - s->stream_ptr); 01011 } 01012 } 01013 01014 static av_cold int ipvideo_decode_init(AVCodecContext *avctx) 01015 { 01016 IpvideoContext *s = avctx->priv_data; 01017 01018 s->avctx = avctx; 01019 01020 s->is_16bpp = avctx->bits_per_coded_sample == 16; 01021 avctx->pix_fmt = s->is_16bpp ? PIX_FMT_RGB555 : PIX_FMT_PAL8; 01022 if (!s->is_16bpp && s->avctx->palctrl == NULL) { 01023 av_log(avctx, AV_LOG_ERROR, " Interplay video: palette expected.\n"); 01024 return -1; 01025 } 01026 01027 dsputil_init(&s->dsp, avctx); 01028 01029 /* decoding map contains 4 bits of information per 8x8 block */ 01030 s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2); 01031 01032 s->current_frame.data[0] = s->last_frame.data[0] = 01033 s->second_last_frame.data[0] = NULL; 01034 01035 return 0; 01036 } 01037 01038 static int ipvideo_decode_frame(AVCodecContext *avctx, 01039 void *data, int *data_size, 01040 AVPacket *avpkt) 01041 { 01042 const uint8_t *buf = avpkt->data; 01043 int buf_size = avpkt->size; 01044 IpvideoContext *s = avctx->priv_data; 01045 AVPaletteControl *palette_control = avctx->palctrl; 01046 01047 /* compressed buffer needs to be large enough to at least hold an entire 01048 * decoding map */ 01049 if (buf_size < s->decoding_map_size) 01050 return buf_size; 01051 01052 s->decoding_map = buf; 01053 s->buf = buf + s->decoding_map_size; 01054 s->size = buf_size - s->decoding_map_size; 01055 01056 s->current_frame.reference = 3; 01057 if (avctx->get_buffer(avctx, &s->current_frame)) { 01058 av_log(avctx, AV_LOG_ERROR, " Interplay Video: get_buffer() failed\n"); 01059 return -1; 01060 } 01061 01062 ipvideo_decode_opcodes(s); 01063 01064 if (!s->is_16bpp && palette_control->palette_changed) { 01065 palette_control->palette_changed = 0; 01066 s->current_frame.palette_has_changed = 1; 01067 } 01068 01069 *data_size = sizeof(AVFrame); 01070 *(AVFrame*)data = s->current_frame; 01071 01072 /* shuffle frames */ 01073 if (s->second_last_frame.data[0]) 01074 avctx->release_buffer(avctx, &s->second_last_frame); 01075 s->second_last_frame = s->last_frame; 01076 s->last_frame = s->current_frame; 01077 s->current_frame.data[0] = NULL; /* catch any access attempts */ 01078 01079 /* report that the buffer was completely consumed */ 01080 return buf_size; 01081 } 01082 01083 static av_cold int ipvideo_decode_end(AVCodecContext *avctx) 01084 { 01085 IpvideoContext *s = avctx->priv_data; 01086 01087 /* release the last frame */ 01088 if (s->last_frame.data[0]) 01089 avctx->release_buffer(avctx, &s->last_frame); 01090 if (s->second_last_frame.data[0]) 01091 avctx->release_buffer(avctx, &s->second_last_frame); 01092 01093 return 0; 01094 } 01095 01096 AVCodec interplay_video_decoder = { 01097 "interplayvideo", 01098 AVMEDIA_TYPE_VIDEO, 01099 CODEC_ID_INTERPLAY_VIDEO, 01100 sizeof(IpvideoContext), 01101 ipvideo_decode_init, 01102 NULL, 01103 ipvideo_decode_end, 01104 ipvideo_decode_frame, 01105 CODEC_CAP_DR1, 01106 .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"), 01107 };