• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

libavcodec/interplayvideo.c

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

Generated on Wed Apr 11 2012 07:31:33 for FFmpeg by  doxygen 1.7.1