r654: Initial revision
[cinelerra_cv.git] / quicktime / ffmpeg / libavcodec / msvideo1.c
blob518df0e52d0d89454f77949870b57873980263c3
1 /*
2 * Microsoft Video-1 Decoder
3 * Copyright (C) 2003 the ffmpeg project
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /**
22 * @file msvideo1.c
23 * Microsoft Video-1 Decoder by Mike Melanson (melanson@pcisys.net)
24 * For more information about the MS Video-1 format, visit:
25 * http://www.pcisys.net/~melanson/codecs/
27 * This decoder outputs either PAL8 or RGB555 data, depending on the
28 * whether a RGB palette was passed through palctrl;
29 * if it's present, then the data is PAL8; RGB555 otherwise.
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
37 #include "common.h"
38 #include "avcodec.h"
39 #include "dsputil.h"
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; \
49 typedef struct Msvideo1Context {
51 AVCodecContext *avctx;
52 DSPContext dsp;
53 AVFrame frame;
55 unsigned char *buf;
56 int size;
58 int mode_8bit; /* if it's not 8-bit, it's 16-bit */
60 } Msvideo1Context;
62 static int msvideo1_decode_init(AVCodecContext *avctx)
64 Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data;
66 s->avctx = avctx;
68 /* figure out the colorspace based on the presence of a palette */
69 if (s->avctx->palctrl) {
70 s->mode_8bit = 1;
71 avctx->pix_fmt = PIX_FMT_PAL8;
72 } else {
73 s->mode_8bit = 0;
74 avctx->pix_fmt = PIX_FMT_RGB555;
77 avctx->has_b_frames = 0;
78 dsputil_init(&s->dsp, avctx);
80 s->frame.data[0] = NULL;
82 return 0;
85 static void msvideo1_decode_8bit(Msvideo1Context *s)
87 int block_ptr, pixel_ptr;
88 int total_blocks;
89 int pixel_x, pixel_y; /* pixel width and height iterators */
90 int block_x, block_y; /* block width and height iterators */
91 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
92 int block_inc;
93 int row_dec;
95 /* decoding parameters */
96 int stream_ptr;
97 unsigned char byte_a, byte_b;
98 unsigned short flags;
99 int skip_blocks;
100 unsigned char colors[8];
101 unsigned char *pixels = s->frame.data[0];
102 int stride = s->frame.linesize[0];
104 stream_ptr = 0;
105 skip_blocks = 0;
106 blocks_wide = s->avctx->width / 4;
107 blocks_high = s->avctx->height / 4;
108 total_blocks = blocks_wide * blocks_high;
109 block_inc = 4;
110 row_dec = stride + 4;
112 for (block_y = blocks_high; block_y > 0; block_y--) {
113 block_ptr = ((block_y * 4) - 1) * stride;
114 for (block_x = blocks_wide; block_x > 0; block_x--) {
115 /* check if this block should be skipped */
116 if (skip_blocks) {
117 block_ptr += block_inc;
118 skip_blocks--;
119 total_blocks--;
120 continue;
123 pixel_ptr = block_ptr;
125 /* get the next two bytes in the encoded data stream */
126 CHECK_STREAM_PTR(2);
127 byte_a = s->buf[stream_ptr++];
128 byte_b = s->buf[stream_ptr++];
130 /* check if the decode is finished */
131 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
132 return;
133 else if ((byte_b & 0xFC) == 0x84) {
134 /* skip code, but don't count the current block */
135 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
136 } else if (byte_b < 0x80) {
137 /* 2-color encoding */
138 flags = (byte_b << 8) | byte_a;
140 CHECK_STREAM_PTR(2);
141 colors[0] = s->buf[stream_ptr++];
142 colors[1] = s->buf[stream_ptr++];
144 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
145 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
146 pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
147 pixel_ptr -= row_dec;
149 } else if (byte_b >= 0x90) {
150 /* 8-color encoding */
151 flags = (byte_b << 8) | byte_a;
153 CHECK_STREAM_PTR(8);
154 memcpy(colors, &s->buf[stream_ptr], 8);
155 stream_ptr += 8;
157 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
158 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
159 pixels[pixel_ptr++] =
160 colors[((pixel_y & 0x2) << 1) +
161 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
162 pixel_ptr -= row_dec;
164 } else {
165 /* 1-color encoding */
166 colors[0] = byte_a;
168 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
169 for (pixel_x = 0; pixel_x < 4; pixel_x++)
170 pixels[pixel_ptr++] = colors[0];
171 pixel_ptr -= row_dec;
175 block_ptr += block_inc;
176 total_blocks--;
180 /* make the palette available on the way out */
181 if (s->avctx->pix_fmt == PIX_FMT_PAL8) {
182 memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
183 if (s->avctx->palctrl->palette_changed) {
184 s->frame.palette_has_changed = 1;
185 s->avctx->palctrl->palette_changed = 0;
190 static void msvideo1_decode_16bit(Msvideo1Context *s)
192 int block_ptr, pixel_ptr;
193 int total_blocks;
194 int pixel_x, pixel_y; /* pixel width and height iterators */
195 int block_x, block_y; /* block width and height iterators */
196 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
197 int block_inc;
198 int row_dec;
200 /* decoding parameters */
201 int stream_ptr;
202 unsigned char byte_a, byte_b;
203 unsigned short flags;
204 int skip_blocks;
205 unsigned short colors[8];
206 unsigned short *pixels = (unsigned short *)s->frame.data[0];
207 int stride = s->frame.linesize[0] / 2;
209 stream_ptr = 0;
210 skip_blocks = 0;
211 blocks_wide = s->avctx->width / 4;
212 blocks_high = s->avctx->height / 4;
213 total_blocks = blocks_wide * blocks_high;
214 block_inc = 4;
215 row_dec = stride + 4;
217 for (block_y = blocks_high; block_y > 0; block_y--) {
218 block_ptr = ((block_y * 4) - 1) * stride;
219 for (block_x = blocks_wide; block_x > 0; block_x--) {
220 /* check if this block should be skipped */
221 if (skip_blocks) {
222 block_ptr += block_inc;
223 skip_blocks--;
224 total_blocks--;
225 continue;
228 pixel_ptr = block_ptr;
230 /* get the next two bytes in the encoded data stream */
231 CHECK_STREAM_PTR(2);
232 byte_a = s->buf[stream_ptr++];
233 byte_b = s->buf[stream_ptr++];
235 /* check if the decode is finished */
236 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
237 return;
238 } else if ((byte_b & 0xFC) == 0x84) {
239 /* skip code, but don't count the current block */
240 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
241 } else if (byte_b < 0x80) {
242 /* 2- or 8-color encoding modes */
243 flags = (byte_b << 8) | byte_a;
245 CHECK_STREAM_PTR(4);
246 colors[0] = LE_16(&s->buf[stream_ptr]);
247 stream_ptr += 2;
248 colors[1] = LE_16(&s->buf[stream_ptr]);
249 stream_ptr += 2;
251 if (colors[0] & 0x8000) {
252 /* 8-color encoding */
253 CHECK_STREAM_PTR(12);
254 colors[2] = LE_16(&s->buf[stream_ptr]);
255 stream_ptr += 2;
256 colors[3] = LE_16(&s->buf[stream_ptr]);
257 stream_ptr += 2;
258 colors[4] = LE_16(&s->buf[stream_ptr]);
259 stream_ptr += 2;
260 colors[5] = LE_16(&s->buf[stream_ptr]);
261 stream_ptr += 2;
262 colors[6] = LE_16(&s->buf[stream_ptr]);
263 stream_ptr += 2;
264 colors[7] = LE_16(&s->buf[stream_ptr]);
265 stream_ptr += 2;
267 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
268 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
269 pixels[pixel_ptr++] =
270 colors[((pixel_y & 0x2) << 1) +
271 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
272 pixel_ptr -= row_dec;
274 } else {
275 /* 2-color encoding */
276 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
277 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
278 pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
279 pixel_ptr -= row_dec;
282 } else {
283 /* otherwise, it's a 1-color block */
284 colors[0] = (byte_b << 8) | byte_a;
286 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
287 for (pixel_x = 0; pixel_x < 4; pixel_x++)
288 pixels[pixel_ptr++] = colors[0];
289 pixel_ptr -= row_dec;
293 block_ptr += block_inc;
294 total_blocks--;
299 static int msvideo1_decode_frame(AVCodecContext *avctx,
300 void *data, int *data_size,
301 uint8_t *buf, int buf_size)
303 Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data;
305 s->buf = buf;
306 s->size = buf_size;
308 s->frame.reference = 1;
309 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
310 if (avctx->reget_buffer(avctx, &s->frame)) {
311 av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
312 return -1;
315 if (s->mode_8bit)
316 msvideo1_decode_8bit(s);
317 else
318 msvideo1_decode_16bit(s);
320 *data_size = sizeof(AVFrame);
321 *(AVFrame*)data = s->frame;
323 /* report that the buffer was completely consumed */
324 return buf_size;
327 static int msvideo1_decode_end(AVCodecContext *avctx)
329 Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data;
331 if (s->frame.data[0])
332 avctx->release_buffer(avctx, &s->frame);
334 return 0;
337 AVCodec msvideo1_decoder = {
338 "msvideo1",
339 CODEC_TYPE_VIDEO,
340 CODEC_ID_MSVIDEO1,
341 sizeof(Msvideo1Context),
342 msvideo1_decode_init,
343 NULL,
344 msvideo1_decode_end,
345 msvideo1_decode_frame,
346 CODEC_CAP_DR1,