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