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