1/* 2 * Microsoft Video-1 Decoder 3 * Copyright (C) 2003 the ffmpeg project 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * Microsoft Video-1 Decoder by Mike Melanson (melanson@pcisys.net) 25 * For more information about the MS Video-1 format, visit: 26 * http://www.pcisys.net/~melanson/codecs/ 27 * 28 */ 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33 34#include "libavutil/internal.h" 35#include "libavutil/intreadwrite.h" 36#include "avcodec.h" 37#include "internal.h" 38 39#define PALETTE_COUNT 256 40#define CHECK_STREAM_PTR(n) \ 41 if ((stream_ptr + n) > s->size ) { \ 42 av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \ 43 stream_ptr + n, s->size); \ 44 return; \ 45 } 46 47typedef struct Msvideo1Context { 48 49 AVCodecContext *avctx; 50 AVFrame *frame; 51 52 const unsigned char *buf; 53 int size; 54 55 int mode_8bit; /* if it's not 8-bit, it's 16-bit */ 56 57 uint32_t pal[256]; 58} Msvideo1Context; 59 60static av_cold int msvideo1_decode_init(AVCodecContext *avctx) 61{ 62 Msvideo1Context *s = avctx->priv_data; 63 64 s->avctx = avctx; 65 66 /* figure out the colorspace based on the presence of a palette */ 67 if (s->avctx->bits_per_coded_sample == 8) { 68 s->mode_8bit = 1; 69 avctx->pix_fmt = AV_PIX_FMT_PAL8; 70 if (avctx->extradata_size >= AVPALETTE_SIZE) 71 memcpy(s->pal, avctx->extradata, AVPALETTE_SIZE); 72 } else { 73 s->mode_8bit = 0; 74 avctx->pix_fmt = AV_PIX_FMT_RGB555; 75 } 76 77 s->frame = av_frame_alloc(); 78 if (!s->frame) 79 return AVERROR(ENOMEM); 80 81 return 0; 82} 83 84static void msvideo1_decode_8bit(Msvideo1Context *s) 85{ 86 int block_ptr, pixel_ptr; 87 int total_blocks; 88 int pixel_x, pixel_y; /* pixel width and height iterators */ 89 int block_x, block_y; /* block width and height iterators */ 90 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */ 91 int block_inc; 92 int row_dec; 93 94 /* decoding parameters */ 95 int stream_ptr; 96 unsigned char byte_a, byte_b; 97 unsigned short flags; 98 int skip_blocks; 99 unsigned char colors[8]; 100 unsigned char *pixels = s->frame->data[0]; 101 int stride = s->frame->linesize[0]; 102 103 stream_ptr = 0; 104 skip_blocks = 0; 105 blocks_wide = s->avctx->width / 4; 106 blocks_high = s->avctx->height / 4; 107 total_blocks = blocks_wide * blocks_high; 108 block_inc = 4; 109 row_dec = stride + 4; 110 111 for (block_y = blocks_high; block_y > 0; block_y--) { 112 block_ptr = ((block_y * 4) - 1) * stride; 113 for (block_x = blocks_wide; block_x > 0; block_x--) { 114 /* check if this block should be skipped */ 115 if (skip_blocks) { 116 block_ptr += block_inc; 117 skip_blocks--; 118 total_blocks--; 119 continue; 120 } 121 122 pixel_ptr = block_ptr; 123 124 /* get the next two bytes in the encoded data stream */ 125 CHECK_STREAM_PTR(2); 126 byte_a = s->buf[stream_ptr++]; 127 byte_b = s->buf[stream_ptr++]; 128 129 /* check if the decode is finished */ 130 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) 131 return; 132 else if ((byte_b & 0xFC) == 0x84) { 133 /* skip code, but don't count the current block */ 134 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1; 135 } else if (byte_b < 0x80) { 136 /* 2-color encoding */ 137 flags = (byte_b << 8) | byte_a; 138 139 CHECK_STREAM_PTR(2); 140 colors[0] = s->buf[stream_ptr++]; 141 colors[1] = s->buf[stream_ptr++]; 142 143 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 144 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) 145 pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1]; 146 pixel_ptr -= row_dec; 147 } 148 } else if (byte_b >= 0x90) { 149 /* 8-color encoding */ 150 flags = (byte_b << 8) | byte_a; 151 152 CHECK_STREAM_PTR(8); 153 memcpy(colors, &s->buf[stream_ptr], 8); 154 stream_ptr += 8; 155 156 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 157 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) 158 pixels[pixel_ptr++] = 159 colors[((pixel_y & 0x2) << 1) + 160 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)]; 161 pixel_ptr -= row_dec; 162 } 163 } else { 164 /* 1-color encoding */ 165 colors[0] = byte_a; 166 167 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 168 for (pixel_x = 0; pixel_x < 4; pixel_x++) 169 pixels[pixel_ptr++] = colors[0]; 170 pixel_ptr -= row_dec; 171 } 172 } 173 174 block_ptr += block_inc; 175 total_blocks--; 176 } 177 } 178 179 /* make the palette available on the way out */ 180 if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8) 181 memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); 182} 183 184static void msvideo1_decode_16bit(Msvideo1Context *s) 185{ 186 int block_ptr, pixel_ptr; 187 int total_blocks; 188 int pixel_x, pixel_y; /* pixel width and height iterators */ 189 int block_x, block_y; /* block width and height iterators */ 190 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */ 191 int block_inc; 192 int row_dec; 193 194 /* decoding parameters */ 195 int stream_ptr; 196 unsigned char byte_a, byte_b; 197 unsigned short flags; 198 int skip_blocks; 199 unsigned short colors[8]; 200 unsigned short *pixels = (unsigned short *)s->frame->data[0]; 201 int stride = s->frame->linesize[0] / 2; 202 203 stream_ptr = 0; 204 skip_blocks = 0; 205 blocks_wide = s->avctx->width / 4; 206 blocks_high = s->avctx->height / 4; 207 total_blocks = blocks_wide * blocks_high; 208 block_inc = 4; 209 row_dec = stride + 4; 210 211 for (block_y = blocks_high; block_y > 0; block_y--) { 212 block_ptr = ((block_y * 4) - 1) * stride; 213 for (block_x = blocks_wide; block_x > 0; block_x--) { 214 /* check if this block should be skipped */ 215 if (skip_blocks) { 216 block_ptr += block_inc; 217 skip_blocks--; 218 total_blocks--; 219 continue; 220 } 221 222 pixel_ptr = block_ptr; 223 224 /* get the next two bytes in the encoded data stream */ 225 CHECK_STREAM_PTR(2); 226 byte_a = s->buf[stream_ptr++]; 227 byte_b = s->buf[stream_ptr++]; 228 229 /* check if the decode is finished */ 230 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) { 231 return; 232 } else if ((byte_b & 0xFC) == 0x84) { 233 /* skip code, but don't count the current block */ 234 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1; 235 } else if (byte_b < 0x80) { 236 /* 2- or 8-color encoding modes */ 237 flags = (byte_b << 8) | byte_a; 238 239 CHECK_STREAM_PTR(4); 240 colors[0] = AV_RL16(&s->buf[stream_ptr]); 241 stream_ptr += 2; 242 colors[1] = AV_RL16(&s->buf[stream_ptr]); 243 stream_ptr += 2; 244 245 if (colors[0] & 0x8000) { 246 /* 8-color encoding */ 247 CHECK_STREAM_PTR(12); 248 colors[2] = AV_RL16(&s->buf[stream_ptr]); 249 stream_ptr += 2; 250 colors[3] = AV_RL16(&s->buf[stream_ptr]); 251 stream_ptr += 2; 252 colors[4] = AV_RL16(&s->buf[stream_ptr]); 253 stream_ptr += 2; 254 colors[5] = AV_RL16(&s->buf[stream_ptr]); 255 stream_ptr += 2; 256 colors[6] = AV_RL16(&s->buf[stream_ptr]); 257 stream_ptr += 2; 258 colors[7] = AV_RL16(&s->buf[stream_ptr]); 259 stream_ptr += 2; 260 261 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 262 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) 263 pixels[pixel_ptr++] = 264 colors[((pixel_y & 0x2) << 1) + 265 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)]; 266 pixel_ptr -= row_dec; 267 } 268 } else { 269 /* 2-color encoding */ 270 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 271 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) 272 pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1]; 273 pixel_ptr -= row_dec; 274 } 275 } 276 } else { 277 /* otherwise, it's a 1-color block */ 278 colors[0] = (byte_b << 8) | byte_a; 279 280 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 281 for (pixel_x = 0; pixel_x < 4; pixel_x++) 282 pixels[pixel_ptr++] = colors[0]; 283 pixel_ptr -= row_dec; 284 } 285 } 286 287 block_ptr += block_inc; 288 total_blocks--; 289 } 290 } 291} 292 293static int msvideo1_decode_frame(AVCodecContext *avctx, 294 void *data, int *got_frame, 295 AVPacket *avpkt) 296{ 297 const uint8_t *buf = avpkt->data; 298 int buf_size = avpkt->size; 299 Msvideo1Context *s = avctx->priv_data; 300 int ret; 301 302 s->buf = buf; 303 s->size = buf_size; 304 305 if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) 306 return ret; 307 308 if (s->mode_8bit) { 309 const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL); 310 311 if (pal) { 312 memcpy(s->pal, pal, AVPALETTE_SIZE); 313 s->frame->palette_has_changed = 1; 314 } 315 } 316 317 if (s->mode_8bit) 318 msvideo1_decode_8bit(s); 319 else 320 msvideo1_decode_16bit(s); 321 322 if ((ret = av_frame_ref(data, s->frame)) < 0) 323 return ret; 324 325 *got_frame = 1; 326 327 /* report that the buffer was completely consumed */ 328 return buf_size; 329} 330 331static av_cold int msvideo1_decode_end(AVCodecContext *avctx) 332{ 333 Msvideo1Context *s = avctx->priv_data; 334 335 av_frame_free(&s->frame); 336 337 return 0; 338} 339 340AVCodec ff_msvideo1_decoder = { 341 .name = "msvideo1", 342 .long_name = NULL_IF_CONFIG_SMALL("Microsoft Video 1"), 343 .type = AVMEDIA_TYPE_VIDEO, 344 .id = AV_CODEC_ID_MSVIDEO1, 345 .priv_data_size = sizeof(Msvideo1Context), 346 .init = msvideo1_decode_init, 347 .close = msvideo1_decode_end, 348 .decode = msvideo1_decode_frame, 349 .capabilities = CODEC_CAP_DR1, 350}; 351