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