Mercurial > libavcodec.hg
comparison msvideo1.c @ 1491:222643544cf1 libavcodec
New demuxers: Sega FILM/CPK, Westwood VQA & AUD; new decoders: MS RLE &
Video-1, Apple RPZA, Cinepak, Westwood IMA ADPCM
author | tmmm |
---|---|
date | Wed, 01 Oct 2003 04:39:38 +0000 |
parents | |
children | b2fecae88e84 |
comparison
equal
deleted
inserted
replaced
1490:0355f2b3519a | 1491:222643544cf1 |
---|---|
1 /* | |
2 * Microsoft Video-1 Decoder | |
3 * Copyright (C) 2003 the ffmpeg project | |
4 * | |
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. | |
9 * | |
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. | |
14 * | |
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 | |
18 * | |
19 */ | |
20 | |
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/ | |
26 * | |
27 * This decoder outputs either PAL8 or RGB555 data, depending on the | |
28 * whether a RGB palette was passed through via extradata; if the extradata | |
29 * is present, then the data is PAL8; RGB555 otherwise. | |
30 */ | |
31 | |
32 #include <stdio.h> | |
33 #include <stdlib.h> | |
34 #include <string.h> | |
35 #include <unistd.h> | |
36 | |
37 #include "common.h" | |
38 #include "avcodec.h" | |
39 #include "dsputil.h" | |
40 | |
41 #define PALETTE_COUNT 256 | |
42 #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) | |
43 #define CHECK_STREAM_PTR(n) \ | |
44 if ((stream_ptr + n) > s->size ) { \ | |
45 printf (" MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \ | |
46 stream_ptr + n, s->size); \ | |
47 return; \ | |
48 } | |
49 | |
50 #define COPY_PREV_BLOCK() \ | |
51 pixel_ptr = block_ptr; \ | |
52 for (pixel_y = 0; pixel_y < 4; pixel_y++) { \ | |
53 for (pixel_x = 0; pixel_x < 4; pixel_x++, pixel_ptr++) \ | |
54 pixels[pixel_ptr] = prev_pixels[pixel_ptr]; \ | |
55 pixel_ptr -= row_dec; \ | |
56 } | |
57 | |
58 typedef struct Msvideo1Context { | |
59 | |
60 AVCodecContext *avctx; | |
61 DSPContext dsp; | |
62 AVFrame frame; | |
63 AVFrame prev_frame; | |
64 | |
65 unsigned char *buf; | |
66 int size; | |
67 | |
68 int mode_8bit; /* if it's not 8-bit, it's 16-bit */ | |
69 unsigned char palette[PALETTE_COUNT * 4]; | |
70 | |
71 } Msvideo1Context; | |
72 | |
73 static int msvideo1_decode_init(AVCodecContext *avctx) | |
74 { | |
75 Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data; | |
76 int i; | |
77 unsigned char r, g, b; | |
78 unsigned char *raw_palette; | |
79 unsigned int *palette32; | |
80 | |
81 s->avctx = avctx; | |
82 | |
83 /* figure out the colorspace based on the presence of a palette in | |
84 * extradata */ | |
85 if (s->avctx->extradata_size) { | |
86 s->mode_8bit = 1; | |
87 /* load up the palette */ | |
88 palette32 = (unsigned int *)s->palette; | |
89 raw_palette = (unsigned char *)s->avctx->extradata; | |
90 for (i = 0; i < s->avctx->extradata_size / 4; i++) { | |
91 b = *raw_palette++; | |
92 g = *raw_palette++; | |
93 r = *raw_palette++; | |
94 raw_palette++; | |
95 palette32[i] = (r << 16) | (g << 8) | (b); | |
96 } | |
97 avctx->pix_fmt = PIX_FMT_PAL8; | |
98 } else { | |
99 s->mode_8bit = 0; | |
100 avctx->pix_fmt = PIX_FMT_RGB555; | |
101 } | |
102 | |
103 avctx->has_b_frames = 0; | |
104 dsputil_init(&s->dsp, avctx); | |
105 | |
106 s->frame.data[0] = s->prev_frame.data[0] = NULL; | |
107 | |
108 return 0; | |
109 } | |
110 | |
111 static void msvideo1_decode_8bit(Msvideo1Context *s) | |
112 { | |
113 int block_ptr, pixel_ptr; | |
114 int total_blocks; | |
115 int pixel_x, pixel_y; /* pixel width and height iterators */ | |
116 int block_x, block_y; /* block width and height iterators */ | |
117 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */ | |
118 int block_inc; | |
119 int row_dec; | |
120 | |
121 /* decoding parameters */ | |
122 int stream_ptr; | |
123 unsigned char byte_a, byte_b; | |
124 unsigned short flags; | |
125 int skip_blocks; | |
126 unsigned char colors[8]; | |
127 unsigned char *pixels = s->frame.data[0]; | |
128 unsigned char *prev_pixels = s->prev_frame.data[0]; | |
129 int stride = s->frame.linesize[0]; | |
130 | |
131 stream_ptr = 0; | |
132 skip_blocks = 0; | |
133 blocks_wide = s->avctx->width / 4; | |
134 blocks_high = s->avctx->height / 4; | |
135 total_blocks = blocks_wide * blocks_high; | |
136 block_inc = 4; | |
137 row_dec = stride + 4; | |
138 | |
139 for (block_y = blocks_high; block_y > 0; block_y--) { | |
140 block_ptr = ((block_y * 4) - 1) * stride; | |
141 for (block_x = blocks_wide; block_x > 0; block_x--) { | |
142 /* check if this block should be skipped */ | |
143 if (skip_blocks) { | |
144 COPY_PREV_BLOCK(); | |
145 block_ptr += block_inc; | |
146 skip_blocks--; | |
147 total_blocks--; | |
148 continue; | |
149 } | |
150 | |
151 pixel_ptr = block_ptr; | |
152 | |
153 /* get the next two bytes in the encoded data stream */ | |
154 CHECK_STREAM_PTR(2); | |
155 byte_a = s->buf[stream_ptr++]; | |
156 byte_b = s->buf[stream_ptr++]; | |
157 | |
158 /* check if the decode is finished */ | |
159 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) | |
160 return; | |
161 else if ((byte_b & 0xFC) == 0x84) { | |
162 /* skip code, but don't count the current block */ | |
163 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1; | |
164 COPY_PREV_BLOCK(); | |
165 } else if (byte_b < 0x80) { | |
166 /* 2-color encoding */ | |
167 flags = (byte_b << 8) | byte_a; | |
168 | |
169 CHECK_STREAM_PTR(2); | |
170 colors[0] = s->buf[stream_ptr++]; | |
171 colors[1] = s->buf[stream_ptr++]; | |
172 | |
173 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
174 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) | |
175 pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1]; | |
176 pixel_ptr -= row_dec; | |
177 } | |
178 } else if (byte_b >= 0x90) { | |
179 /* 8-color encoding */ | |
180 flags = (byte_b << 8) | byte_a; | |
181 | |
182 CHECK_STREAM_PTR(8); | |
183 memcpy(colors, &s->buf[stream_ptr], 8); | |
184 stream_ptr += 8; | |
185 | |
186 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
187 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) | |
188 pixels[pixel_ptr++] = | |
189 colors[((pixel_y & 0x2) << 1) + | |
190 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)]; | |
191 pixel_ptr -= row_dec; | |
192 } | |
193 } else { | |
194 /* 1-color encoding */ | |
195 colors[0] = byte_a; | |
196 | |
197 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
198 for (pixel_x = 0; pixel_x < 4; pixel_x++) | |
199 pixels[pixel_ptr++] = colors[0]; | |
200 pixel_ptr -= row_dec; | |
201 } | |
202 } | |
203 | |
204 block_ptr += block_inc; | |
205 total_blocks--; | |
206 } | |
207 } | |
208 | |
209 /* make the palette available on the way out */ | |
210 if (s->avctx->pix_fmt == PIX_FMT_PAL8) | |
211 memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4); | |
212 } | |
213 | |
214 static void msvideo1_decode_16bit(Msvideo1Context *s) | |
215 { | |
216 int block_ptr, pixel_ptr; | |
217 int total_blocks; | |
218 int pixel_x, pixel_y; /* pixel width and height iterators */ | |
219 int block_x, block_y; /* block width and height iterators */ | |
220 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */ | |
221 int block_inc; | |
222 int row_dec; | |
223 | |
224 /* decoding parameters */ | |
225 int stream_ptr; | |
226 unsigned char byte_a, byte_b; | |
227 unsigned short flags; | |
228 int skip_blocks; | |
229 unsigned short colors[8]; | |
230 unsigned short *pixels = (unsigned short *)s->frame.data[0]; | |
231 unsigned short *prev_pixels = (unsigned short *)s->prev_frame.data[0]; | |
232 int stride = s->frame.linesize[0] / 2; | |
233 | |
234 stream_ptr = 0; | |
235 skip_blocks = 0; | |
236 blocks_wide = s->avctx->width / 4; | |
237 blocks_high = s->avctx->height / 4; | |
238 total_blocks = blocks_wide * blocks_high; | |
239 block_inc = 4; | |
240 row_dec = stride + 4; | |
241 | |
242 for (block_y = blocks_high; block_y > 0; block_y--) { | |
243 block_ptr = ((block_y * 4) - 1) * stride; | |
244 for (block_x = blocks_wide; block_x > 0; block_x--) { | |
245 /* check if this block should be skipped */ | |
246 if (skip_blocks) { | |
247 COPY_PREV_BLOCK(); | |
248 block_ptr += block_inc; | |
249 skip_blocks--; | |
250 total_blocks--; | |
251 continue; | |
252 } | |
253 | |
254 pixel_ptr = block_ptr; | |
255 | |
256 /* get the next two bytes in the encoded data stream */ | |
257 CHECK_STREAM_PTR(2); | |
258 byte_a = s->buf[stream_ptr++]; | |
259 byte_b = s->buf[stream_ptr++]; | |
260 | |
261 /* check if the decode is finished */ | |
262 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) { | |
263 return; | |
264 } else if ((byte_b & 0xFC) == 0x84) { | |
265 /* skip code, but don't count the current block */ | |
266 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1; | |
267 COPY_PREV_BLOCK(); | |
268 } else if (byte_b < 0x80) { | |
269 /* 2- or 8-color encoding modes */ | |
270 flags = (byte_b << 8) | byte_a; | |
271 | |
272 CHECK_STREAM_PTR(4); | |
273 colors[0] = LE_16(&s->buf[stream_ptr]); | |
274 stream_ptr += 2; | |
275 colors[1] = LE_16(&s->buf[stream_ptr]); | |
276 stream_ptr += 2; | |
277 | |
278 if (colors[0] & 0x8000) { | |
279 /* 8-color encoding */ | |
280 CHECK_STREAM_PTR(12); | |
281 colors[2] = LE_16(&s->buf[stream_ptr]); | |
282 stream_ptr += 2; | |
283 colors[3] = LE_16(&s->buf[stream_ptr]); | |
284 stream_ptr += 2; | |
285 colors[4] = LE_16(&s->buf[stream_ptr]); | |
286 stream_ptr += 2; | |
287 colors[5] = LE_16(&s->buf[stream_ptr]); | |
288 stream_ptr += 2; | |
289 colors[6] = LE_16(&s->buf[stream_ptr]); | |
290 stream_ptr += 2; | |
291 colors[7] = LE_16(&s->buf[stream_ptr]); | |
292 stream_ptr += 2; | |
293 | |
294 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
295 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) | |
296 pixels[pixel_ptr++] = | |
297 colors[((pixel_y & 0x2) << 1) + | |
298 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)]; | |
299 pixel_ptr -= row_dec; | |
300 } | |
301 } else { | |
302 /* 2-color encoding */ | |
303 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
304 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1) | |
305 pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1]; | |
306 pixel_ptr -= row_dec; | |
307 } | |
308 } | |
309 } else { | |
310 /* otherwise, it's a 1-color block */ | |
311 colors[0] = (byte_b << 8) | byte_a; | |
312 | |
313 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
314 for (pixel_x = 0; pixel_x < 4; pixel_x++) | |
315 pixels[pixel_ptr++] = colors[0]; | |
316 pixel_ptr -= row_dec; | |
317 } | |
318 } | |
319 | |
320 block_ptr += block_inc; | |
321 total_blocks--; | |
322 } | |
323 } | |
324 } | |
325 | |
326 static int msvideo1_decode_frame(AVCodecContext *avctx, | |
327 void *data, int *data_size, | |
328 uint8_t *buf, int buf_size) | |
329 { | |
330 Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data; | |
331 | |
332 s->buf = buf; | |
333 s->size = buf_size; | |
334 | |
335 if (avctx->get_buffer(avctx, &s->frame)) { | |
336 printf (" MS Video-1 Video: get_buffer() failed\n"); | |
337 return -1; | |
338 } | |
339 | |
340 if (s->mode_8bit) | |
341 msvideo1_decode_8bit(s); | |
342 else | |
343 msvideo1_decode_16bit(s); | |
344 | |
345 if (s->prev_frame.data[0]) | |
346 avctx->release_buffer(avctx, &s->prev_frame); | |
347 | |
348 /* shuffle frames */ | |
349 s->prev_frame = s->frame; | |
350 | |
351 *data_size = sizeof(AVFrame); | |
352 *(AVFrame*)data = s->frame; | |
353 | |
354 /* report that the buffer was completely consumed */ | |
355 return buf_size; | |
356 } | |
357 | |
358 static int msvideo1_decode_end(AVCodecContext *avctx) | |
359 { | |
360 Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data; | |
361 | |
362 if (s->prev_frame.data[0]) | |
363 avctx->release_buffer(avctx, &s->prev_frame); | |
364 | |
365 return 0; | |
366 } | |
367 | |
368 AVCodec msvideo1_decoder = { | |
369 "msvideo1", | |
370 CODEC_TYPE_VIDEO, | |
371 CODEC_ID_MSVIDEO1, | |
372 sizeof(Msvideo1Context), | |
373 msvideo1_decode_init, | |
374 NULL, | |
375 msvideo1_decode_end, | |
376 msvideo1_decode_frame, | |
377 CODEC_CAP_DR1, | |
378 }; |