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

Generated on Fri Sep 16 2011 17:17:38 for FFmpeg by  doxygen 1.7.1