• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • 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 #include <unistd.h>
00041 
00042 #include "avcodec.h"
00043 #include "bytestream.h"
00044 #include "dsputil.h"
00045 
00046 #define PALETTE_COUNT 256
00047 
00048 /* debugging support */
00049 #define DEBUG_INTERPLAY 0
00050 #if DEBUG_INTERPLAY
00051 #define debug_interplay(x,...) av_log(NULL, AV_LOG_DEBUG, x, __VA_ARGS__)
00052 #else
00053 static inline void debug_interplay(const char *format, ...) { }
00054 #endif
00055 
00056 typedef struct IpvideoContext {
00057 
00058     AVCodecContext *avctx;
00059     DSPContext dsp;
00060     AVFrame second_last_frame;
00061     AVFrame last_frame;
00062     AVFrame current_frame;
00063     const unsigned char *decoding_map;
00064     int decoding_map_size;
00065 
00066     const unsigned char *buf;
00067     int size;
00068 
00069     const unsigned char *stream_ptr;
00070     const unsigned char *stream_end;
00071     unsigned char *pixel_ptr;
00072     int line_inc;
00073     int stride;
00074     int upper_motion_limit_offset;
00075 
00076 } IpvideoContext;
00077 
00078 #define CHECK_STREAM_PTR(n) \
00079   if ((s->stream_ptr + n) > s->stream_end) { \
00080     av_log(s->avctx, AV_LOG_ERROR, "Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \
00081       s->stream_ptr + n, s->stream_end); \
00082     return -1; \
00083   }
00084 
00085 #define COPY_FROM_CURRENT() \
00086     motion_offset = current_offset; \
00087     motion_offset += y * s->stride; \
00088     motion_offset += x; \
00089     if (motion_offset < 0) { \
00090         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset); \
00091         return -1; \
00092     } else if (motion_offset > s->upper_motion_limit_offset) { \
00093         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n", \
00094             motion_offset, s->upper_motion_limit_offset); \
00095         return -1; \
00096     } \
00097     s->dsp.put_pixels_tab[0][0](s->pixel_ptr, \
00098         s->current_frame.data[0] + motion_offset, s->stride, 8);
00099 
00100 #define COPY_FROM_PREVIOUS() \
00101     motion_offset = current_offset; \
00102     motion_offset += y * s->stride; \
00103     motion_offset += x; \
00104     if (motion_offset < 0) { \
00105         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset); \
00106         return -1; \
00107     } else if (motion_offset > s->upper_motion_limit_offset) { \
00108         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n", \
00109             motion_offset, s->upper_motion_limit_offset); \
00110         return -1; \
00111     } \
00112     s->dsp.put_pixels_tab[0][0](s->pixel_ptr, \
00113         s->last_frame.data[0] + motion_offset, s->stride, 8);
00114 
00115 #define COPY_FROM_SECOND_LAST() \
00116     motion_offset = current_offset; \
00117     motion_offset += y * s->stride; \
00118     motion_offset += x; \
00119     if (motion_offset < 0) { \
00120         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset); \
00121         return -1; \
00122     } else if (motion_offset > s->upper_motion_limit_offset) { \
00123         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n", \
00124             motion_offset, s->upper_motion_limit_offset); \
00125         return -1; \
00126     } \
00127     s->dsp.put_pixels_tab[0][0](s->pixel_ptr, \
00128         s->second_last_frame.data[0] + motion_offset, s->stride, 8);
00129 
00130 static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s)
00131 {
00132     int x, y;
00133     int motion_offset;
00134     int current_offset = s->pixel_ptr - s->current_frame.data[0];
00135 
00136     /* copy a block from the previous frame */
00137     x = y = 0;
00138     COPY_FROM_PREVIOUS();
00139 
00140     /* report success */
00141     return 0;
00142 }
00143 
00144 static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s)
00145 {
00146     int x, y;
00147     int motion_offset;
00148     int current_offset = s->pixel_ptr - s->current_frame.data[0];
00149 
00150     /* copy block from 2 frames ago */
00151     x = y = 0;
00152     COPY_FROM_SECOND_LAST();
00153 
00154     /* report success */
00155     return 0;
00156 }
00157 
00158 static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s)
00159 {
00160     unsigned char B;
00161     int x, y;
00162     int motion_offset;
00163     int current_offset = s->pixel_ptr - s->current_frame.data[0];
00164 
00165     /* copy block from 2 frames ago using a motion vector; need 1 more byte */
00166     CHECK_STREAM_PTR(1);
00167     B = *s->stream_ptr++;
00168 
00169     if (B < 56) {
00170         x = 8 + (B % 7);
00171         y = B / 7;
00172     } else {
00173         x = -14 + ((B - 56) % 29);
00174         y =   8 + ((B - 56) / 29);
00175     }
00176 
00177     debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
00178     COPY_FROM_SECOND_LAST();
00179 
00180     /* report success */
00181     return 0;
00182 }
00183 
00184 static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s)
00185 {
00186     unsigned char B;
00187     int x, y;
00188     int motion_offset;
00189     int current_offset = s->pixel_ptr - s->current_frame.data[0];
00190 
00191     /* copy 8x8 block from current frame from an up/left block */
00192 
00193     /* need 1 more byte for motion */
00194     CHECK_STREAM_PTR(1);
00195     B = *s->stream_ptr++;
00196 
00197     if (B < 56) {
00198         x = -(8 + (B % 7));
00199         y = -(B / 7);
00200     } else {
00201         x = -(-14 + ((B - 56) % 29));
00202         y = -(  8 + ((B - 56) / 29));
00203     }
00204 
00205     debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
00206     COPY_FROM_CURRENT();
00207 
00208     /* report success */
00209     return 0;
00210 }
00211 
00212 static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s)
00213 {
00214     int x, y;
00215     unsigned char B, BL, BH;
00216     int motion_offset;
00217     int current_offset = s->pixel_ptr - s->current_frame.data[0];
00218 
00219     /* copy a block from the previous frame; need 1 more byte */
00220     CHECK_STREAM_PTR(1);
00221 
00222     B = *s->stream_ptr++;
00223     BL = B & 0x0F;
00224     BH = (B >> 4) & 0x0F;
00225     x = -8 + BL;
00226     y = -8 + BH;
00227 
00228     debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
00229     COPY_FROM_PREVIOUS();
00230 
00231     /* report success */
00232     return 0;
00233 }
00234 
00235 static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s)
00236 {
00237     signed char x, y;
00238     int motion_offset;
00239     int current_offset = s->pixel_ptr - s->current_frame.data[0];
00240 
00241     /* copy a block from the previous frame using an expanded range;
00242      * need 2 more bytes */
00243     CHECK_STREAM_PTR(2);
00244 
00245     x = *s->stream_ptr++;
00246     y = *s->stream_ptr++;
00247 
00248     debug_interplay ("    motion bytes = %d, %d\n", x, y);
00249     COPY_FROM_PREVIOUS();
00250 
00251     /* report success */
00252     return 0;
00253 }
00254 
00255 static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s)
00256 {
00257     /* mystery opcode? skip multiple blocks? */
00258     av_log(s->avctx, AV_LOG_ERROR, "  Interplay video: Help! Mystery opcode 0x6 seen\n");
00259 
00260     /* report success */
00261     return 0;
00262 }
00263 
00264 static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s)
00265 {
00266     int x, y;
00267     unsigned char P0, P1;
00268     unsigned char B[8];
00269     unsigned int flags;
00270     int bitmask;
00271 
00272     /* 2-color encoding */
00273     CHECK_STREAM_PTR(2);
00274 
00275     P0 = *s->stream_ptr++;
00276     P1 = *s->stream_ptr++;
00277 
00278     if (P0 <= P1) {
00279 
00280         /* need 8 more bytes from the stream */
00281         CHECK_STREAM_PTR(8);
00282         for (y = 0; y < 8; y++)
00283             B[y] = *s->stream_ptr++;
00284 
00285         for (y = 0; y < 8; y++) {
00286             flags = B[y];
00287             for (x = 0x01; x <= 0x80; x <<= 1) {
00288                 if (flags & x)
00289                     *s->pixel_ptr++ = P1;
00290                 else
00291                     *s->pixel_ptr++ = P0;
00292             }
00293             s->pixel_ptr += s->line_inc;
00294         }
00295 
00296     } else {
00297 
00298         /* need 2 more bytes from the stream */
00299         CHECK_STREAM_PTR(2);
00300 
00301         flags = bytestream_get_le16(&s->stream_ptr);
00302         bitmask = 0x0001;
00303         for (y = 0; y < 8; y += 2) {
00304             for (x = 0; x < 8; x += 2, bitmask <<= 1) {
00305                 if (flags & bitmask) {
00306                     *(s->pixel_ptr + x) = P1;
00307                     *(s->pixel_ptr + x + 1) = P1;
00308                     *(s->pixel_ptr + s->stride + x) = P1;
00309                     *(s->pixel_ptr + s->stride + x + 1) = P1;
00310                 } else {
00311                     *(s->pixel_ptr + x) = P0;
00312                     *(s->pixel_ptr + x + 1) = P0;
00313                     *(s->pixel_ptr + s->stride + x) = P0;
00314                     *(s->pixel_ptr + s->stride + x + 1) = P0;
00315                 }
00316             }
00317             s->pixel_ptr += s->stride * 2;
00318         }
00319     }
00320 
00321     /* report success */
00322     return 0;
00323 }
00324 
00325 static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s)
00326 {
00327     int x, y;
00328     unsigned char P[8];
00329     unsigned char B[8];
00330     unsigned int flags = 0;
00331     unsigned int bitmask = 0;
00332     unsigned char P0 = 0, P1 = 0;
00333     int lower_half = 0;
00334 
00335     /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
00336      * either top and bottom or left and right halves */
00337     CHECK_STREAM_PTR(2);
00338 
00339     P[0] = *s->stream_ptr++;
00340     P[1] = *s->stream_ptr++;
00341 
00342     if (P[0] <= P[1]) {
00343 
00344         /* need 12 more bytes */
00345         CHECK_STREAM_PTR(12);
00346         B[0] = *s->stream_ptr++;  B[1] = *s->stream_ptr++;
00347         P[2] = *s->stream_ptr++;  P[3] = *s->stream_ptr++;
00348         B[2] = *s->stream_ptr++;  B[3] = *s->stream_ptr++;
00349         P[4] = *s->stream_ptr++;  P[5] = *s->stream_ptr++;
00350         B[4] = *s->stream_ptr++;  B[5] = *s->stream_ptr++;
00351         P[6] = *s->stream_ptr++;  P[7] = *s->stream_ptr++;
00352         B[6] = *s->stream_ptr++;  B[7] = *s->stream_ptr++;
00353 
00354         for (y = 0; y < 8; y++) {
00355 
00356             /* time to reload flags? */
00357             if (y == 0) {
00358                 flags =
00359                     ((B[0] & 0xF0) <<  4) | ((B[4] & 0xF0) <<  8) |
00360                     ((B[0] & 0x0F)      ) | ((B[4] & 0x0F) <<  4) |
00361                     ((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
00362                     ((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
00363                 bitmask = 0x00000001;
00364                 lower_half = 0;  /* still on top half */
00365             } else if (y == 4) {
00366                 flags =
00367                     ((B[2] & 0xF0) <<  4) | ((B[6] & 0xF0) <<  8) |
00368                     ((B[2] & 0x0F)      ) | ((B[6] & 0x0F) <<  4) |
00369                     ((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
00370                     ((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
00371                 bitmask = 0x00000001;
00372                 lower_half = 2;
00373             }
00374 
00375             for (x = 0; x < 8; x++, bitmask <<= 1) {
00376                 /* get the pixel values ready for this quadrant */
00377                 if (x == 0) {
00378                     P0 = P[lower_half + 0];
00379                     P1 = P[lower_half + 1];
00380                 } else if (x == 4) {
00381                     P0 = P[lower_half + 4];
00382                     P1 = P[lower_half + 5];
00383                 }
00384 
00385                 if (flags & bitmask)
00386                     *s->pixel_ptr++ = P1;
00387                 else
00388                     *s->pixel_ptr++ = P0;
00389             }
00390             s->pixel_ptr += s->line_inc;
00391         }
00392 
00393     } else {
00394 
00395         /* need 10 more bytes */
00396         CHECK_STREAM_PTR(10);
00397         B[0] = *s->stream_ptr++;  B[1] = *s->stream_ptr++;
00398         B[2] = *s->stream_ptr++;  B[3] = *s->stream_ptr++;
00399         P[2] = *s->stream_ptr++;  P[3] = *s->stream_ptr++;
00400         B[4] = *s->stream_ptr++;  B[5] = *s->stream_ptr++;
00401         B[6] = *s->stream_ptr++;  B[7] = *s->stream_ptr++;
00402 
00403         if (P[2] <= P[3]) {
00404 
00405             /* vertical split; left & right halves are 2-color encoded */
00406 
00407             for (y = 0; y < 8; y++) {
00408 
00409                 /* time to reload flags? */
00410                 if (y == 0) {
00411                     flags =
00412                         ((B[0] & 0xF0) <<  4) | ((B[4] & 0xF0) <<  8) |
00413                         ((B[0] & 0x0F)      ) | ((B[4] & 0x0F) <<  4) |
00414                         ((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
00415                         ((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
00416                     bitmask = 0x00000001;
00417                 } else if (y == 4) {
00418                     flags =
00419                         ((B[2] & 0xF0) <<  4) | ((B[6] & 0xF0) <<  8) |
00420                         ((B[2] & 0x0F)      ) | ((B[6] & 0x0F) <<  4) |
00421                         ((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
00422                         ((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
00423                     bitmask = 0x00000001;
00424                 }
00425 
00426                 for (x = 0; x < 8; x++, bitmask <<= 1) {
00427                     /* get the pixel values ready for this half */
00428                     if (x == 0) {
00429                         P0 = P[0];
00430                         P1 = P[1];
00431                     } else if (x == 4) {
00432                         P0 = P[2];
00433                         P1 = P[3];
00434                     }
00435 
00436                     if (flags & bitmask)
00437                         *s->pixel_ptr++ = P1;
00438                     else
00439                         *s->pixel_ptr++ = P0;
00440                 }
00441                 s->pixel_ptr += s->line_inc;
00442             }
00443 
00444         } else {
00445 
00446             /* horizontal split; top & bottom halves are 2-color encoded */
00447 
00448             for (y = 0; y < 8; y++) {
00449 
00450                 flags = B[y];
00451                 if (y == 0) {
00452                     P0 = P[0];
00453                     P1 = P[1];
00454                 } else if (y == 4) {
00455                     P0 = P[2];
00456                     P1 = P[3];
00457                 }
00458 
00459                 for (bitmask = 0x01; bitmask <= 0x80; bitmask <<= 1) {
00460 
00461                     if (flags & bitmask)
00462                         *s->pixel_ptr++ = P1;
00463                     else
00464                         *s->pixel_ptr++ = P0;
00465                 }
00466                 s->pixel_ptr += s->line_inc;
00467             }
00468         }
00469     }
00470 
00471     /* report success */
00472     return 0;
00473 }
00474 
00475 static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
00476 {
00477     int x, y;
00478     unsigned char P[4];
00479     unsigned int flags = 0;
00480     int shifter = 0;
00481     unsigned char pix;
00482 
00483     /* 4-color encoding */
00484     CHECK_STREAM_PTR(4);
00485 
00486     for (y = 0; y < 4; y++)
00487         P[y] = *s->stream_ptr++;
00488 
00489     if ((P[0] <= P[1]) && (P[2] <= P[3])) {
00490 
00491         /* 1 of 4 colors for each pixel, need 16 more bytes */
00492         CHECK_STREAM_PTR(16);
00493 
00494         for (y = 0; y < 8; y++) {
00495             /* get the next set of 8 2-bit flags */
00496             flags = bytestream_get_le16(&s->stream_ptr);
00497             for (x = 0, shifter = 0; x < 8; x++, shifter += 2) {
00498                 *s->pixel_ptr++ = P[(flags >> shifter) & 0x03];
00499             }
00500             s->pixel_ptr += s->line_inc;
00501         }
00502 
00503     } else if ((P[0] <= P[1]) && (P[2] > P[3])) {
00504 
00505         /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
00506         CHECK_STREAM_PTR(4);
00507 
00508         flags = bytestream_get_le32(&s->stream_ptr);
00509         shifter = 0;
00510 
00511         for (y = 0; y < 8; y += 2) {
00512             for (x = 0; x < 8; x += 2, shifter += 2) {
00513                 pix = P[(flags >> shifter) & 0x03];
00514                 *(s->pixel_ptr + x) = pix;
00515                 *(s->pixel_ptr + x + 1) = pix;
00516                 *(s->pixel_ptr + s->stride + x) = pix;
00517                 *(s->pixel_ptr + s->stride + x + 1) = pix;
00518             }
00519             s->pixel_ptr += s->stride * 2;
00520         }
00521 
00522     } else if ((P[0] > P[1]) && (P[2] <= P[3])) {
00523 
00524         /* 1 of 4 colors for each 2x1 block, need 8 more bytes */
00525         CHECK_STREAM_PTR(8);
00526 
00527         for (y = 0; y < 8; y++) {
00528             /* time to reload flags? */
00529             if ((y == 0) || (y == 4)) {
00530                 flags = bytestream_get_le32(&s->stream_ptr);
00531                 shifter = 0;
00532             }
00533             for (x = 0; x < 8; x += 2, shifter += 2) {
00534                 pix = P[(flags >> shifter) & 0x03];
00535                 *(s->pixel_ptr + x) = pix;
00536                 *(s->pixel_ptr + x + 1) = pix;
00537             }
00538             s->pixel_ptr += s->stride;
00539         }
00540 
00541     } else {
00542 
00543         /* 1 of 4 colors for each 1x2 block, need 8 more bytes */
00544         CHECK_STREAM_PTR(8);
00545 
00546         for (y = 0; y < 8; y += 2) {
00547             /* time to reload flags? */
00548             if ((y == 0) || (y == 4)) {
00549                 flags = bytestream_get_le32(&s->stream_ptr);
00550                 shifter = 0;
00551             }
00552             for (x = 0; x < 8; x++, shifter += 2) {
00553                 pix = P[(flags >> shifter) & 0x03];
00554                 *(s->pixel_ptr + x) = pix;
00555                 *(s->pixel_ptr + s->stride + x) = pix;
00556             }
00557             s->pixel_ptr += s->stride * 2;
00558         }
00559     }
00560 
00561     /* report success */
00562     return 0;
00563 }
00564 
00565 static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s)
00566 {
00567     int x, y;
00568     unsigned char P[16];
00569     unsigned char B[16];
00570     int flags = 0;
00571     int shifter = 0;
00572     int index;
00573     int split;
00574     int lower_half;
00575 
00576     /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
00577      * either top and bottom or left and right halves */
00578     CHECK_STREAM_PTR(4);
00579 
00580     for (y = 0; y < 4; y++)
00581         P[y] = *s->stream_ptr++;
00582 
00583     if (P[0] <= P[1]) {
00584 
00585         /* 4-color encoding for each quadrant; need 28 more bytes */
00586         CHECK_STREAM_PTR(28);
00587 
00588         for (y = 0; y < 4; y++)
00589             B[y] = *s->stream_ptr++;
00590         for (y = 4; y < 16; y += 4) {
00591             for (x = y; x < y + 4; x++)
00592                 P[x] = *s->stream_ptr++;
00593             for (x = y; x < y + 4; x++)
00594                 B[x] = *s->stream_ptr++;
00595         }
00596 
00597         for (y = 0; y < 8; y++) {
00598 
00599             lower_half = (y >= 4) ? 4 : 0;
00600             flags = (B[y + 8] << 8) | B[y];
00601 
00602             for (x = 0, shifter = 0; x < 8; x++, shifter += 2) {
00603                 split = (x >= 4) ? 8 : 0;
00604                 index = split + lower_half + ((flags >> shifter) & 0x03);
00605                 *s->pixel_ptr++ = P[index];
00606             }
00607 
00608             s->pixel_ptr += s->line_inc;
00609         }
00610 
00611     } else {
00612 
00613         /* 4-color encoding for either left and right or top and bottom
00614          * halves; need 20 more bytes */
00615         CHECK_STREAM_PTR(20);
00616 
00617         for (y = 0; y < 8; y++)
00618             B[y] = *s->stream_ptr++;
00619         for (y = 4; y < 8; y++)
00620             P[y] = *s->stream_ptr++;
00621         for (y = 8; y < 16; y++)
00622             B[y] = *s->stream_ptr++;
00623 
00624         if (P[4] <= P[5]) {
00625 
00626             /* block is divided into left and right halves */
00627             for (y = 0; y < 8; y++) {
00628 
00629                 flags = (B[y + 8] << 8) | B[y];
00630                 split = 0;
00631 
00632                 for (x = 0, shifter = 0; x < 8; x++, shifter += 2) {
00633                     if (x == 4)
00634                         split = 4;
00635                     *s->pixel_ptr++ = P[split + ((flags >> shifter) & 0x03)];
00636                 }
00637 
00638                 s->pixel_ptr += s->line_inc;
00639             }
00640 
00641         } else {
00642 
00643             /* block is divided into top and bottom halves */
00644             split = 0;
00645             for (y = 0; y < 8; y++) {
00646 
00647                 flags = (B[y * 2 + 1] << 8) | B[y * 2];
00648                 if (y == 4)
00649                     split = 4;
00650 
00651                 for (x = 0, shifter = 0; x < 8; x++, shifter += 2)
00652                     *s->pixel_ptr++ = P[split + ((flags >> shifter) & 0x03)];
00653 
00654                 s->pixel_ptr += s->line_inc;
00655             }
00656         }
00657     }
00658 
00659     /* report success */
00660     return 0;
00661 }
00662 
00663 static int ipvideo_decode_block_opcode_0xB(IpvideoContext *s)
00664 {
00665     int x, y;
00666 
00667     /* 64-color encoding (each pixel in block is a different color) */
00668     CHECK_STREAM_PTR(64);
00669 
00670     for (y = 0; y < 8; y++) {
00671         for (x = 0; x < 8; x++) {
00672             *s->pixel_ptr++ = *s->stream_ptr++;
00673         }
00674         s->pixel_ptr += s->line_inc;
00675     }
00676 
00677     /* report success */
00678     return 0;
00679 }
00680 
00681 static int ipvideo_decode_block_opcode_0xC(IpvideoContext *s)
00682 {
00683     int x, y;
00684     unsigned char pix;
00685 
00686     /* 16-color block encoding: each 2x2 block is a different color */
00687     CHECK_STREAM_PTR(16);
00688 
00689     for (y = 0; y < 8; y += 2) {
00690         for (x = 0; x < 8; x += 2) {
00691             pix = *s->stream_ptr++;
00692             *(s->pixel_ptr + x) = pix;
00693             *(s->pixel_ptr + x + 1) = pix;
00694             *(s->pixel_ptr + s->stride + x) = pix;
00695             *(s->pixel_ptr + s->stride + x + 1) = pix;
00696         }
00697         s->pixel_ptr += s->stride * 2;
00698     }
00699 
00700     /* report success */
00701     return 0;
00702 }
00703 
00704 static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s)
00705 {
00706     int x, y;
00707     unsigned char P[4];
00708     unsigned char index = 0;
00709 
00710     /* 4-color block encoding: each 4x4 block is a different color */
00711     CHECK_STREAM_PTR(4);
00712 
00713     for (y = 0; y < 4; y++)
00714         P[y] = *s->stream_ptr++;
00715 
00716     for (y = 0; y < 8; y++) {
00717         if (y < 4)
00718             index = 0;
00719         else
00720             index = 2;
00721 
00722         for (x = 0; x < 8; x++) {
00723             if (x == 4)
00724                 index++;
00725             *s->pixel_ptr++ = P[index];
00726         }
00727         s->pixel_ptr += s->line_inc;
00728     }
00729 
00730     /* report success */
00731     return 0;
00732 }
00733 
00734 static int ipvideo_decode_block_opcode_0xE(IpvideoContext *s)
00735 {
00736     int x, y;
00737     unsigned char pix;
00738 
00739     /* 1-color encoding: the whole block is 1 solid color */
00740     CHECK_STREAM_PTR(1);
00741     pix = *s->stream_ptr++;
00742 
00743     for (y = 0; y < 8; y++) {
00744         for (x = 0; x < 8; x++) {
00745             *s->pixel_ptr++ = pix;
00746         }
00747         s->pixel_ptr += s->line_inc;
00748     }
00749 
00750     /* report success */
00751     return 0;
00752 }
00753 
00754 static int ipvideo_decode_block_opcode_0xF(IpvideoContext *s)
00755 {
00756     int x, y;
00757     unsigned char sample0, sample1;
00758 
00759     /* dithered encoding */
00760     CHECK_STREAM_PTR(2);
00761     sample0 = *s->stream_ptr++;
00762     sample1 = *s->stream_ptr++;
00763 
00764     for (y = 0; y < 8; y++) {
00765         for (x = 0; x < 8; x += 2) {
00766             if (y & 1) {
00767                 *s->pixel_ptr++ = sample1;
00768                 *s->pixel_ptr++ = sample0;
00769             } else {
00770                 *s->pixel_ptr++ = sample0;
00771                 *s->pixel_ptr++ = sample1;
00772             }
00773         }
00774         s->pixel_ptr += s->line_inc;
00775     }
00776 
00777     /* report success */
00778     return 0;
00779 }
00780 
00781 static int (*ipvideo_decode_block[16])(IpvideoContext *s);
00782 
00783 static void ipvideo_decode_opcodes(IpvideoContext *s)
00784 {
00785     int x, y;
00786     int index = 0;
00787     unsigned char opcode;
00788     int ret;
00789     int code_counts[16];
00790     static int frame = 0;
00791 
00792     debug_interplay("------------------ frame %d\n", frame);
00793     frame++;
00794 
00795     for (x = 0; x < 16; x++)
00796         code_counts[x] = 0;
00797 
00798     /* this is PAL8, so make the palette available */
00799     memcpy(s->current_frame.data[1], s->avctx->palctrl->palette, PALETTE_COUNT * 4);
00800 
00801     s->stride = s->current_frame.linesize[0];
00802     s->stream_ptr = s->buf + 14;  /* data starts 14 bytes in */
00803     s->stream_end = s->buf + s->size;
00804     s->line_inc = s->stride - 8;
00805     s->upper_motion_limit_offset = (s->avctx->height - 8) * s->stride
00806         + s->avctx->width - 8;
00807 
00808     for (y = 0; y < (s->stride * s->avctx->height); y += s->stride * 8) {
00809         for (x = y; x < y + s->avctx->width; x += 8) {
00810             /* bottom nibble first, then top nibble (which makes it
00811              * hard to use a GetBitcontext) */
00812             if (index & 1)
00813                 opcode = s->decoding_map[index >> 1] >> 4;
00814             else
00815                 opcode = s->decoding_map[index >> 1] & 0xF;
00816             index++;
00817 
00818             debug_interplay("  block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n",
00819                 x - y, y / s->stride, opcode, s->stream_ptr);
00820             code_counts[opcode]++;
00821 
00822             s->pixel_ptr = s->current_frame.data[0] + x;
00823             ret = ipvideo_decode_block[opcode](s);
00824             if (ret != 0) {
00825                 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
00826                     frame, x - y, y / s->stride);
00827                 return;
00828             }
00829         }
00830     }
00831     if ((s->stream_ptr != s->stream_end) &&
00832         (s->stream_ptr + 1 != s->stream_end)) {
00833         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %td bytes left over\n",
00834             s->stream_end - s->stream_ptr);
00835     }
00836 }
00837 
00838 static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
00839 {
00840     IpvideoContext *s = avctx->priv_data;
00841 
00842     s->avctx = avctx;
00843 
00844     if (s->avctx->palctrl == NULL) {
00845         av_log(avctx, AV_LOG_ERROR, " Interplay video: palette expected.\n");
00846         return -1;
00847     }
00848 
00849     avctx->pix_fmt = PIX_FMT_PAL8;
00850     dsputil_init(&s->dsp, avctx);
00851 
00852     /* decoding map contains 4 bits of information per 8x8 block */
00853     s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2);
00854 
00855     /* assign block decode functions */
00856     ipvideo_decode_block[0x0] = ipvideo_decode_block_opcode_0x0;
00857     ipvideo_decode_block[0x1] = ipvideo_decode_block_opcode_0x1;
00858     ipvideo_decode_block[0x2] = ipvideo_decode_block_opcode_0x2;
00859     ipvideo_decode_block[0x3] = ipvideo_decode_block_opcode_0x3;
00860     ipvideo_decode_block[0x4] = ipvideo_decode_block_opcode_0x4;
00861     ipvideo_decode_block[0x5] = ipvideo_decode_block_opcode_0x5;
00862     ipvideo_decode_block[0x6] = ipvideo_decode_block_opcode_0x6;
00863     ipvideo_decode_block[0x7] = ipvideo_decode_block_opcode_0x7;
00864     ipvideo_decode_block[0x8] = ipvideo_decode_block_opcode_0x8;
00865     ipvideo_decode_block[0x9] = ipvideo_decode_block_opcode_0x9;
00866     ipvideo_decode_block[0xA] = ipvideo_decode_block_opcode_0xA;
00867     ipvideo_decode_block[0xB] = ipvideo_decode_block_opcode_0xB;
00868     ipvideo_decode_block[0xC] = ipvideo_decode_block_opcode_0xC;
00869     ipvideo_decode_block[0xD] = ipvideo_decode_block_opcode_0xD;
00870     ipvideo_decode_block[0xE] = ipvideo_decode_block_opcode_0xE;
00871     ipvideo_decode_block[0xF] = ipvideo_decode_block_opcode_0xF;
00872 
00873     s->current_frame.data[0] = s->last_frame.data[0] =
00874     s->second_last_frame.data[0] = NULL;
00875 
00876     return 0;
00877 }
00878 
00879 static int ipvideo_decode_frame(AVCodecContext *avctx,
00880                                 void *data, int *data_size,
00881                                 const uint8_t *buf, int buf_size)
00882 {
00883     IpvideoContext *s = avctx->priv_data;
00884     AVPaletteControl *palette_control = avctx->palctrl;
00885 
00886     /* compressed buffer needs to be large enough to at least hold an entire
00887      * decoding map */
00888     if (buf_size < s->decoding_map_size)
00889         return buf_size;
00890 
00891     s->decoding_map = buf;
00892     s->buf = buf + s->decoding_map_size;
00893     s->size = buf_size - s->decoding_map_size;
00894 
00895     s->current_frame.reference = 3;
00896     if (avctx->get_buffer(avctx, &s->current_frame)) {
00897         av_log(avctx, AV_LOG_ERROR, "  Interplay Video: get_buffer() failed\n");
00898         return -1;
00899     }
00900 
00901     ipvideo_decode_opcodes(s);
00902 
00903     if (palette_control->palette_changed) {
00904         palette_control->palette_changed = 0;
00905         s->current_frame.palette_has_changed = 1;
00906     }
00907 
00908     *data_size = sizeof(AVFrame);
00909     *(AVFrame*)data = s->current_frame;
00910 
00911     /* shuffle frames */
00912     if (s->second_last_frame.data[0])
00913         avctx->release_buffer(avctx, &s->second_last_frame);
00914     s->second_last_frame = s->last_frame;
00915     s->last_frame = s->current_frame;
00916     s->current_frame.data[0] = NULL;  /* catch any access attempts */
00917 
00918     /* report that the buffer was completely consumed */
00919     return buf_size;
00920 }
00921 
00922 static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
00923 {
00924     IpvideoContext *s = avctx->priv_data;
00925 
00926     /* release the last frame */
00927     if (s->last_frame.data[0])
00928         avctx->release_buffer(avctx, &s->last_frame);
00929     if (s->second_last_frame.data[0])
00930         avctx->release_buffer(avctx, &s->second_last_frame);
00931 
00932     return 0;
00933 }
00934 
00935 AVCodec interplay_video_decoder = {
00936     "interplayvideo",
00937     CODEC_TYPE_VIDEO,
00938     CODEC_ID_INTERPLAY_VIDEO,
00939     sizeof(IpvideoContext),
00940     ipvideo_decode_init,
00941     NULL,
00942     ipvideo_decode_end,
00943     ipvideo_decode_frame,
00944     CODEC_CAP_DR1,
00945     .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"),
00946 };

Generated on Tue Nov 4 2014 12:59:22 for ffmpeg by  doxygen 1.7.1