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