Go to the documentation of this file.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 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;
00083 int block_x, block_y;
00084 int blocks_wide, blocks_high;
00085 int block_inc;
00086 int row_dec;
00087
00088
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
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
00119 CHECK_STREAM_PTR(2);
00120 byte_a = s->buf[stream_ptr++];
00121 byte_b = s->buf[stream_ptr++];
00122
00123
00124 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
00125 return;
00126 else if ((byte_b & 0xFC) == 0x84) {
00127
00128 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
00129 } else if (byte_b < 0x80) {
00130
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
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
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
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;
00183 int block_x, block_y;
00184 int blocks_wide, blocks_high;
00185 int block_inc;
00186 int row_dec;
00187
00188
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
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
00219 CHECK_STREAM_PTR(2);
00220 byte_a = s->buf[stream_ptr++];
00221 byte_b = s->buf[stream_ptr++];
00222
00223
00224 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
00225 return;
00226 } else if ((byte_b & 0xFC) == 0x84) {
00227
00228 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
00229 } else if (byte_b < 0x80) {
00230
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
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
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
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
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 .name = "msvideo1",
00338 .type = AVMEDIA_TYPE_VIDEO,
00339 .id = CODEC_ID_MSVIDEO1,
00340 .priv_data_size = sizeof(Msvideo1Context),
00341 .init = msvideo1_decode_init,
00342 .close = msvideo1_decode_end,
00343 .decode = msvideo1_decode_frame,
00344 .capabilities = CODEC_CAP_DR1,
00345 .long_name= NULL_IF_CONFIG_SMALL("Microsoft Video 1"),
00346 };