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