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