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