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