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#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32 33#include "libavutil/internal.h" 34#include "libavutil/intreadwrite.h" 35#include "avcodec.h" 36#include "codec_internal.h" 37#include "decode.h" 38#include "internal.h" 39 40#define PALETTE_COUNT 256 41#define CHECK_STREAM_PTR(n) \ 42 if ((stream_ptr + n) > s->size ) { \ 43 av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \ 44 stream_ptr + n, s->size); \ 45 return; \ 46 } 47 48typedef struct Msvideo1Context { 49 50 AVCodecContext *avctx; 51 AVFrame *frame; 52 53 const unsigned char *buf; 54 int size; 55 56 int mode_8bit; /* if it's not 8-bit, it's 16-bit */ 57 58 uint32_t pal[256]; 59} Msvideo1Context; 60 61static av_cold int msvideo1_decode_init(AVCodecContext *avctx) 62{ 63 Msvideo1Context *s = avctx->priv_data; 64 65 s->avctx = avctx; 66 67 if (avctx->width < 4 || avctx->height < 4) 68 return AVERROR_INVALIDDATA; 69 70 /* figure out the colorspace based on the presence of a palette */ 71 if (s->avctx->bits_per_coded_sample == 8) { 72 s->mode_8bit = 1; 73 avctx->pix_fmt = AV_PIX_FMT_PAL8; 74 if (avctx->extradata_size >= AVPALETTE_SIZE) 75 memcpy(s->pal, avctx->extradata, AVPALETTE_SIZE); 76 } else { 77 s->mode_8bit = 0; 78 avctx->pix_fmt = AV_PIX_FMT_RGB555; 79 } 80 81 s->frame = av_frame_alloc(); 82 if (!s->frame) 83 return AVERROR(ENOMEM); 84 85 return 0; 86} 87 88static void msvideo1_decode_8bit(Msvideo1Context *s) 89{ 90 int block_ptr, pixel_ptr; 91 int total_blocks; 92 int pixel_x, pixel_y; /* pixel width and height iterators */ 93 int block_x, block_y; /* block width and height iterators */ 94 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */ 95 int block_inc; 96 int row_dec; 97 98 /* decoding parameters */ 99 int stream_ptr; 100 unsigned char byte_a, byte_b; 101 unsigned short flags; 102 int skip_blocks; 103 unsigned char colors[8]; 104 unsigned char *pixels = s->frame->data[0]; 105 int stride = s->frame->linesize[0]; 106 107 stream_ptr = 0; 108 skip_blocks = 0; 109 blocks_wide = s->avctx->width / 4; 110 blocks_high = s->avctx->height / 4; 111 total_blocks = blocks_wide * blocks_high; 112 block_inc = 4; 113 row_dec = stride + 4; 114 115 for (block_y = blocks_high; block_y > 0; block_y--) { 116 block_ptr = ((block_y * 4) - 1) * stride; 117 for (block_x = blocks_wide; block_x > 0; block_x--) { 118 /* check if this block should be skipped */ 119 if (skip_blocks) { 120 block_ptr += block_inc; 121 skip_blocks--; 122 total_blocks--; 123 continue; 124 } 125 126 pixel_ptr = block_ptr; 127 128 /* get the next two bytes in the encoded data stream */ 129 CHECK_STREAM_PTR(2); 130 byte_a = s->buf[stream_ptr++]; 131 byte_b = s->buf[stream_ptr++]; 132 133 /* check if the decode is finished */ 134 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) 135 return; 136 else if ((byte_b & 0xFC) == 0x84) { 137 /* skip code, but don't count the current block */ 138 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1; 139 } else if (byte_b < 0x80) { 140 /* 2-color encoding */ 141 flags = (byte_b << 8) | byte_a; 142 143 CHECK_STREAM_PTR(2); 144 colors[0] = s->buf[stream_ptr++]; 145 colors[1] = s->buf[stream_ptr++]; 146 147 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 148 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) 149 pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1]; 150 pixel_ptr -= row_dec; 151 } 152 } else if (byte_b >= 0x90) { 153 /* 8-color encoding */ 154 flags = (byte_b << 8) | byte_a; 155 156 CHECK_STREAM_PTR(8); 157 memcpy(colors, &s->buf[stream_ptr], 8); 158 stream_ptr += 8; 159 160 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 161 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) 162 pixels[pixel_ptr++] = 163 colors[((pixel_y & 0x2) << 1) + 164 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)]; 165 pixel_ptr -= row_dec; 166 } 167 } else { 168 /* 1-color encoding */ 169 colors[0] = byte_a; 170 171 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 172 for (pixel_x = 0; pixel_x < 4; pixel_x++) 173 pixels[pixel_ptr++] = colors[0]; 174 pixel_ptr -= row_dec; 175 } 176 } 177 178 block_ptr += block_inc; 179 total_blocks--; 180 } 181 } 182 183 /* make the palette available on the way out */ 184 if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8) 185 memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); 186} 187 188static void msvideo1_decode_16bit(Msvideo1Context *s) 189{ 190 int block_ptr, pixel_ptr; 191 int total_blocks; 192 int pixel_x, pixel_y; /* pixel width and height iterators */ 193 int block_x, block_y; /* block width and height iterators */ 194 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */ 195 int block_inc; 196 int row_dec; 197 198 /* decoding parameters */ 199 int stream_ptr; 200 unsigned char byte_a, byte_b; 201 unsigned short flags; 202 int skip_blocks; 203 unsigned short colors[8]; 204 unsigned short *pixels = (unsigned short *)s->frame->data[0]; 205 int stride = s->frame->linesize[0] / 2; 206 207 stream_ptr = 0; 208 skip_blocks = 0; 209 blocks_wide = s->avctx->width / 4; 210 blocks_high = s->avctx->height / 4; 211 total_blocks = blocks_wide * blocks_high; 212 block_inc = 4; 213 row_dec = stride + 4; 214 215 for (block_y = blocks_high; block_y > 0; block_y--) { 216 block_ptr = ((block_y * 4) - 1) * stride; 217 for (block_x = blocks_wide; block_x > 0; block_x--) { 218 /* check if this block should be skipped */ 219 if (skip_blocks) { 220 block_ptr += block_inc; 221 skip_blocks--; 222 total_blocks--; 223 continue; 224 } 225 226 pixel_ptr = block_ptr; 227 228 /* get the next two bytes in the encoded data stream */ 229 CHECK_STREAM_PTR(2); 230 byte_a = s->buf[stream_ptr++]; 231 byte_b = s->buf[stream_ptr++]; 232 233 /* check if the decode is finished */ 234 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) { 235 return; 236 } else if ((byte_b & 0xFC) == 0x84) { 237 /* skip code, but don't count the current block */ 238 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1; 239 } else if (byte_b < 0x80) { 240 /* 2- or 8-color encoding modes */ 241 flags = (byte_b << 8) | byte_a; 242 243 CHECK_STREAM_PTR(4); 244 colors[0] = AV_RL16(&s->buf[stream_ptr]); 245 stream_ptr += 2; 246 colors[1] = AV_RL16(&s->buf[stream_ptr]); 247 stream_ptr += 2; 248 249 if (colors[0] & 0x8000) { 250 /* 8-color encoding */ 251 CHECK_STREAM_PTR(12); 252 colors[2] = AV_RL16(&s->buf[stream_ptr]); 253 stream_ptr += 2; 254 colors[3] = AV_RL16(&s->buf[stream_ptr]); 255 stream_ptr += 2; 256 colors[4] = AV_RL16(&s->buf[stream_ptr]); 257 stream_ptr += 2; 258 colors[5] = AV_RL16(&s->buf[stream_ptr]); 259 stream_ptr += 2; 260 colors[6] = AV_RL16(&s->buf[stream_ptr]); 261 stream_ptr += 2; 262 colors[7] = AV_RL16(&s->buf[stream_ptr]); 263 stream_ptr += 2; 264 265 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 266 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) 267 pixels[pixel_ptr++] = 268 colors[((pixel_y & 0x2) << 1) + 269 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)]; 270 pixel_ptr -= row_dec; 271 } 272 } else { 273 /* 2-color encoding */ 274 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 275 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) 276 pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1]; 277 pixel_ptr -= row_dec; 278 } 279 } 280 } else { 281 /* otherwise, it's a 1-color block */ 282 colors[0] = (byte_b << 8) | byte_a; 283 284 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 285 for (pixel_x = 0; pixel_x < 4; pixel_x++) 286 pixels[pixel_ptr++] = colors[0]; 287 pixel_ptr -= row_dec; 288 } 289 } 290 291 block_ptr += block_inc; 292 total_blocks--; 293 } 294 } 295} 296 297static int msvideo1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 298 int *got_frame, AVPacket *avpkt) 299{ 300 const uint8_t *buf = avpkt->data; 301 int buf_size = avpkt->size; 302 Msvideo1Context *s = avctx->priv_data; 303 int ret; 304 305 s->buf = buf; 306 s->size = buf_size; 307 308 // Discard frame if its smaller than the minimum frame size 309 if (buf_size < (avctx->width/4) * (avctx->height/4) / 512) { 310 av_log(avctx, AV_LOG_ERROR, "Packet is too small\n"); 311 return AVERROR_INVALIDDATA; 312 } 313 314 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 315 return ret; 316 317 if (s->mode_8bit) { 318 s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx); 319 } 320 321 if (s->mode_8bit) 322 msvideo1_decode_8bit(s); 323 else 324 msvideo1_decode_16bit(s); 325 326 if ((ret = av_frame_ref(rframe, s->frame)) < 0) 327 return ret; 328 329 *got_frame = 1; 330 331 /* report that the buffer was completely consumed */ 332 return buf_size; 333} 334 335static av_cold int msvideo1_decode_end(AVCodecContext *avctx) 336{ 337 Msvideo1Context *s = avctx->priv_data; 338 339 av_frame_free(&s->frame); 340 341 return 0; 342} 343 344const FFCodec ff_msvideo1_decoder = { 345 .p.name = "msvideo1", 346 .p.long_name = NULL_IF_CONFIG_SMALL("Microsoft Video 1"), 347 .p.type = AVMEDIA_TYPE_VIDEO, 348 .p.id = AV_CODEC_ID_MSVIDEO1, 349 .priv_data_size = sizeof(Msvideo1Context), 350 .init = msvideo1_decode_init, 351 .close = msvideo1_decode_end, 352 FF_CODEC_DECODE_CB(msvideo1_decode_frame), 353 .p.capabilities = AV_CODEC_CAP_DR1, 354 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 355}; 356