00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 
00034 #include "libavutil/internal.h"
00035 #include "libavutil/intreadwrite.h"
00036 #include "avcodec.h"
00037 
00038 #define PALETTE_COUNT 256
00039 #define CHECK_STREAM_PTR(n) \
00040   if ((stream_ptr + n) > s->size ) { \
00041     av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \
00042       stream_ptr + n, s->size); \
00043     return; \
00044   }
00045 
00046 typedef struct Msvideo1Context {
00047 
00048     AVCodecContext *avctx;
00049     AVFrame frame;
00050 
00051     const unsigned char *buf;
00052     int size;
00053 
00054     int mode_8bit;  
00055 
00056     uint32_t pal[256];
00057 } Msvideo1Context;
00058 
00059 static av_cold int msvideo1_decode_init(AVCodecContext *avctx)
00060 {
00061     Msvideo1Context *s = avctx->priv_data;
00062 
00063     s->avctx = avctx;
00064 
00065     
00066     if (s->avctx->bits_per_coded_sample == 8) {
00067         s->mode_8bit = 1;
00068         avctx->pix_fmt = PIX_FMT_PAL8;
00069     } else {
00070         s->mode_8bit = 0;
00071         avctx->pix_fmt = PIX_FMT_RGB555;
00072     }
00073 
00074     avcodec_get_frame_defaults(&s->frame);
00075     s->frame.data[0] = NULL;
00076 
00077     return 0;
00078 }
00079 
00080 static void msvideo1_decode_8bit(Msvideo1Context *s)
00081 {
00082     int block_ptr, pixel_ptr;
00083     int total_blocks;
00084     int pixel_x, pixel_y;  
00085     int block_x, block_y;  
00086     int blocks_wide, blocks_high;  
00087     int block_inc;
00088     int row_dec;
00089 
00090     
00091     int stream_ptr;
00092     unsigned char byte_a, byte_b;
00093     unsigned short flags;
00094     int skip_blocks;
00095     unsigned char colors[8];
00096     unsigned char *pixels = s->frame.data[0];
00097     int stride = s->frame.linesize[0];
00098 
00099     stream_ptr = 0;
00100     skip_blocks = 0;
00101     blocks_wide = s->avctx->width / 4;
00102     blocks_high = s->avctx->height / 4;
00103     total_blocks = blocks_wide * blocks_high;
00104     block_inc = 4;
00105     row_dec = stride + 4;
00106 
00107     for (block_y = blocks_high; block_y > 0; block_y--) {
00108         block_ptr = ((block_y * 4) - 1) * stride;
00109         for (block_x = blocks_wide; block_x > 0; block_x--) {
00110             
00111             if (skip_blocks) {
00112                 block_ptr += block_inc;
00113                 skip_blocks--;
00114                 total_blocks--;
00115                 continue;
00116             }
00117 
00118             pixel_ptr = block_ptr;
00119 
00120             
00121             CHECK_STREAM_PTR(2);
00122             byte_a = s->buf[stream_ptr++];
00123             byte_b = s->buf[stream_ptr++];
00124 
00125             
00126             if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
00127                 return;
00128             else if ((byte_b & 0xFC) == 0x84) {
00129                 
00130                 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
00131             } else if (byte_b < 0x80) {
00132                 
00133                 flags = (byte_b << 8) | byte_a;
00134 
00135                 CHECK_STREAM_PTR(2);
00136                 colors[0] = s->buf[stream_ptr++];
00137                 colors[1] = s->buf[stream_ptr++];
00138 
00139                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00140                     for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
00141                         pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
00142                     pixel_ptr -= row_dec;
00143                 }
00144             } else if (byte_b >= 0x90) {
00145                 
00146                 flags = (byte_b << 8) | byte_a;
00147 
00148                 CHECK_STREAM_PTR(8);
00149                 memcpy(colors, &s->buf[stream_ptr], 8);
00150                 stream_ptr += 8;
00151 
00152                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00153                     for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
00154                         pixels[pixel_ptr++] =
00155                             colors[((pixel_y & 0x2) << 1) +
00156                                 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
00157                     pixel_ptr -= row_dec;
00158                 }
00159             } else {
00160                 
00161                 colors[0] = byte_a;
00162 
00163                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00164                     for (pixel_x = 0; pixel_x < 4; pixel_x++)
00165                         pixels[pixel_ptr++] = colors[0];
00166                     pixel_ptr -= row_dec;
00167                 }
00168             }
00169 
00170             block_ptr += block_inc;
00171             total_blocks--;
00172         }
00173     }
00174 
00175     
00176     if (s->avctx->pix_fmt == PIX_FMT_PAL8)
00177         memcpy(s->frame.data[1], s->pal, AVPALETTE_SIZE);
00178 }
00179 
00180 static void msvideo1_decode_16bit(Msvideo1Context *s)
00181 {
00182     int block_ptr, pixel_ptr;
00183     int total_blocks;
00184     int pixel_x, pixel_y;  
00185     int block_x, block_y;  
00186     int blocks_wide, blocks_high;  
00187     int block_inc;
00188     int row_dec;
00189 
00190     
00191     int stream_ptr;
00192     unsigned char byte_a, byte_b;
00193     unsigned short flags;
00194     int skip_blocks;
00195     unsigned short colors[8];
00196     unsigned short *pixels = (unsigned short *)s->frame.data[0];
00197     int stride = s->frame.linesize[0] / 2;
00198 
00199     stream_ptr = 0;
00200     skip_blocks = 0;
00201     blocks_wide = s->avctx->width / 4;
00202     blocks_high = s->avctx->height / 4;
00203     total_blocks = blocks_wide * blocks_high;
00204     block_inc = 4;
00205     row_dec = stride + 4;
00206 
00207     for (block_y = blocks_high; block_y > 0; block_y--) {
00208         block_ptr = ((block_y * 4) - 1) * stride;
00209         for (block_x = blocks_wide; block_x > 0; block_x--) {
00210             
00211             if (skip_blocks) {
00212                 block_ptr += block_inc;
00213                 skip_blocks--;
00214                 total_blocks--;
00215                 continue;
00216             }
00217 
00218             pixel_ptr = block_ptr;
00219 
00220             
00221             CHECK_STREAM_PTR(2);
00222             byte_a = s->buf[stream_ptr++];
00223             byte_b = s->buf[stream_ptr++];
00224 
00225             
00226             if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
00227                 return;
00228             } else if ((byte_b & 0xFC) == 0x84) {
00229                 
00230                 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
00231             } else if (byte_b < 0x80) {
00232                 
00233                 flags = (byte_b << 8) | byte_a;
00234 
00235                 CHECK_STREAM_PTR(4);
00236                 colors[0] = AV_RL16(&s->buf[stream_ptr]);
00237                 stream_ptr += 2;
00238                 colors[1] = AV_RL16(&s->buf[stream_ptr]);
00239                 stream_ptr += 2;
00240 
00241                 if (colors[0] & 0x8000) {
00242                     
00243                     CHECK_STREAM_PTR(12);
00244                     colors[2] = AV_RL16(&s->buf[stream_ptr]);
00245                     stream_ptr += 2;
00246                     colors[3] = AV_RL16(&s->buf[stream_ptr]);
00247                     stream_ptr += 2;
00248                     colors[4] = AV_RL16(&s->buf[stream_ptr]);
00249                     stream_ptr += 2;
00250                     colors[5] = AV_RL16(&s->buf[stream_ptr]);
00251                     stream_ptr += 2;
00252                     colors[6] = AV_RL16(&s->buf[stream_ptr]);
00253                     stream_ptr += 2;
00254                     colors[7] = AV_RL16(&s->buf[stream_ptr]);
00255                     stream_ptr += 2;
00256 
00257                     for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00258                         for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
00259                             pixels[pixel_ptr++] =
00260                                 colors[((pixel_y & 0x2) << 1) +
00261                                     (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
00262                         pixel_ptr -= row_dec;
00263                     }
00264                 } else {
00265                     
00266                     for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00267                         for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
00268                             pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
00269                         pixel_ptr -= row_dec;
00270                     }
00271                 }
00272             } else {
00273                 
00274                 colors[0] = (byte_b << 8) | byte_a;
00275 
00276                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00277                     for (pixel_x = 0; pixel_x < 4; pixel_x++)
00278                         pixels[pixel_ptr++] = colors[0];
00279                     pixel_ptr -= row_dec;
00280                 }
00281             }
00282 
00283             block_ptr += block_inc;
00284             total_blocks--;
00285         }
00286     }
00287 }
00288 
00289 static int msvideo1_decode_frame(AVCodecContext *avctx,
00290                                 void *data, int *data_size,
00291                                 AVPacket *avpkt)
00292 {
00293     const uint8_t *buf = avpkt->data;
00294     int buf_size = avpkt->size;
00295     Msvideo1Context *s = avctx->priv_data;
00296 
00297     s->buf = buf;
00298     s->size = buf_size;
00299 
00300     s->frame.reference = 3;
00301     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00302     if (avctx->reget_buffer(avctx, &s->frame)) {
00303         av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00304         return -1;
00305     }
00306 
00307     if (s->mode_8bit) {
00308         const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
00309 
00310         if (pal) {
00311             memcpy(s->pal, pal, AVPALETTE_SIZE);
00312             s->frame.palette_has_changed = 1;
00313         }
00314     }
00315 
00316     if (s->mode_8bit)
00317         msvideo1_decode_8bit(s);
00318     else
00319         msvideo1_decode_16bit(s);
00320 
00321     *data_size = sizeof(AVFrame);
00322     *(AVFrame*)data = s->frame;
00323 
00324     
00325     return buf_size;
00326 }
00327 
00328 static av_cold int msvideo1_decode_end(AVCodecContext *avctx)
00329 {
00330     Msvideo1Context *s = avctx->priv_data;
00331 
00332     if (s->frame.data[0])
00333         avctx->release_buffer(avctx, &s->frame);
00334 
00335     return 0;
00336 }
00337 
00338 AVCodec ff_msvideo1_decoder = {
00339     .name           = "msvideo1",
00340     .type           = AVMEDIA_TYPE_VIDEO,
00341     .id             = AV_CODEC_ID_MSVIDEO1,
00342     .priv_data_size = sizeof(Msvideo1Context),
00343     .init           = msvideo1_decode_init,
00344     .close          = msvideo1_decode_end,
00345     .decode         = msvideo1_decode_frame,
00346     .capabilities   = CODEC_CAP_DR1,
00347     .long_name      = NULL_IF_CONFIG_SMALL("Microsoft Video 1"),
00348 };