[MSVIDC32]
[reactos.git] / reactos / dll / win32 / msvidc32 / msvideo1.c
1 /*
2 * Microsoft Video-1 Decoder
3 * Copyright (C) 2003 the ffmpeg project
4 *
5 * Portions Copyright (C) 2004 Mike McCormack for CodeWeavers
6 *
7 * This library 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 * This library 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 this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 */
22
23 /**
24 * @file msvideo1.c
25 * Microsoft Video-1 Decoder by Mike Melanson (melanson@pcisys.net)
26 * For more information about the MS Video-1 format, visit:
27 * http://www.pcisys.net/~melanson/codecs/
28 *
29 * This decoder outputs either PAL8 or RGB555 data, depending on the
30 * whether a RGB palette was passed through palctrl;
31 * if it's present, then the data is PAL8; RGB555 otherwise.
32 */
33
34 #define WIN32_NO_STATUS
35 #define _INC_WINDOWS
36 #define COM_NO_WINDOWS_H
37
38 #include <stdarg.h>
39 #include <windef.h>
40 #include <winbase.h>
41 #include <wingdi.h>
42 //#include "winuser.h"
43 //#include "commdlg.h"
44 #include <vfw.h>
45 //#include "mmsystem.h"
46 #include "msvidc32_private.h"
47
48 #include <wine/debug.h>
49
50 WINE_DEFAULT_DEBUG_CHANNEL(msvidc32);
51
52 static HINSTANCE MSVIDC32_hModule;
53
54 #define CRAM_MAGIC mmioFOURCC('C', 'R', 'A', 'M')
55 #define MSVC_MAGIC mmioFOURCC('M', 'S', 'V', 'C')
56 #define WHAM_MAGIC mmioFOURCC('W', 'H', 'A', 'M')
57 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
58
59 #define PALETTE_COUNT 256
60 #define LE_16(x) ((((const uint8_t *)(x))[1] << 8) | ((const uint8_t *)(x))[0])
61
62 /* FIXME - check the stream size */
63 #define CHECK_STREAM_PTR(n) \
64 if ((stream_ptr + n) > buf_size ) { \
65 WARN("stream_ptr out of bounds (%d >= %d)\n", \
66 stream_ptr + n, buf_size); \
67 return; \
68 }
69
70 typedef BYTE uint8_t;
71
72 typedef struct Msvideo1Context {
73 DWORD dwMagic;
74 BOOL mode_8bit; /* if it's not 8-bit, it's 16-bit */
75 } Msvideo1Context;
76
77 static void
78 msvideo1_decode_8bit( int width, int height, const unsigned char *buf, int buf_size,
79 unsigned char *pixels, int stride)
80 {
81 int block_ptr, pixel_ptr;
82 int total_blocks;
83 int pixel_x, pixel_y; /* pixel width and height iterators */
84 int block_x, block_y; /* block width and height iterators */
85 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
86 int block_inc;
87 int row_dec;
88
89 /* decoding parameters */
90 int stream_ptr;
91 unsigned char byte_a, byte_b;
92 unsigned short flags;
93 int skip_blocks;
94 unsigned char colors[8];
95
96 stream_ptr = 0;
97 skip_blocks = 0;
98 blocks_wide = width / 4;
99 blocks_high = height / 4;
100 total_blocks = blocks_wide * blocks_high;
101 block_inc = 4;
102 #ifdef ORIGINAL
103 row_dec = stride + 4;
104 #else
105 row_dec = - (stride - 4); /* such that -row_dec > 0 */
106 #endif
107
108 for (block_y = blocks_high; block_y > 0; block_y--) {
109 #ifdef ORIGINAL
110 block_ptr = ((block_y * 4) - 1) * stride;
111 #else
112 block_ptr = ((blocks_high - block_y) * 4) * stride;
113 #endif
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;
121 }
122
123 pixel_ptr = block_ptr;
124
125 /* get the next two bytes in the encoded data stream */
126 CHECK_STREAM_PTR(2);
127 byte_a = buf[stream_ptr++];
128 byte_b = buf[stream_ptr++];
129
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;
139
140 CHECK_STREAM_PTR(2);
141 colors[0] = buf[stream_ptr++];
142 colors[1] = buf[stream_ptr++];
143
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;
148 }
149 } else if (byte_b >= 0x90) {
150 /* 8-color encoding */
151 flags = (byte_b << 8) | byte_a;
152
153 CHECK_STREAM_PTR(8);
154 memcpy(colors, &buf[stream_ptr], 8);
155 stream_ptr += 8;
156
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;
163 }
164 } else {
165 /* 1-color encoding */
166 colors[0] = byte_a;
167
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;
172 }
173 }
174
175 block_ptr += block_inc;
176 total_blocks--;
177 }
178 }
179 }
180
181 static void
182 msvideo1_decode_16bit( int width, int height, const unsigned char *buf, int buf_size,
183 unsigned short *pixels, int stride)
184 {
185 int block_ptr, pixel_ptr;
186 int total_blocks;
187 int pixel_x, pixel_y; /* pixel width and height iterators */
188 int block_x, block_y; /* block width and height iterators */
189 int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
190 int block_inc;
191 int row_dec;
192
193 /* decoding parameters */
194 int stream_ptr;
195 unsigned char byte_a, byte_b;
196 unsigned short flags;
197 int skip_blocks;
198 unsigned short colors[8];
199
200 stream_ptr = 0;
201 skip_blocks = 0;
202 blocks_wide = width / 4;
203 blocks_high = height / 4;
204 total_blocks = blocks_wide * blocks_high;
205 block_inc = 4;
206 #ifdef ORIGINAL
207 row_dec = stride + 4;
208 #else
209 row_dec = - (stride - 4); /* such that -row_dec > 0 */
210 #endif
211
212 for (block_y = blocks_high; block_y > 0; block_y--) {
213 #ifdef ORIGINAL
214 block_ptr = ((block_y * 4) - 1) * stride;
215 #else
216 block_ptr = ((blocks_high - block_y) * 4) * stride;
217 #endif
218 for (block_x = blocks_wide; block_x > 0; block_x--) {
219 /* check if this block should be skipped */
220 if (skip_blocks) {
221 block_ptr += block_inc;
222 skip_blocks--;
223 total_blocks--;
224 continue;
225 }
226
227 pixel_ptr = block_ptr;
228
229 /* get the next two bytes in the encoded data stream */
230 CHECK_STREAM_PTR(2);
231 byte_a = buf[stream_ptr++];
232 byte_b = buf[stream_ptr++];
233
234 /* check if the decode is finished */
235 if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
236 return;
237 } else if ((byte_b & 0xFC) == 0x84) {
238 /* skip code, but don't count the current block */
239 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
240 } else if (byte_b < 0x80) {
241 /* 2- or 8-color encoding modes */
242 flags = (byte_b << 8) | byte_a;
243
244 CHECK_STREAM_PTR(4);
245 colors[0] = LE_16(&buf[stream_ptr]);
246 stream_ptr += 2;
247 colors[1] = LE_16(&buf[stream_ptr]);
248 stream_ptr += 2;
249
250 if (colors[0] & 0x8000) {
251 /* 8-color encoding */
252 CHECK_STREAM_PTR(12);
253 colors[2] = LE_16(&buf[stream_ptr]);
254 stream_ptr += 2;
255 colors[3] = LE_16(&buf[stream_ptr]);
256 stream_ptr += 2;
257 colors[4] = LE_16(&buf[stream_ptr]);
258 stream_ptr += 2;
259 colors[5] = LE_16(&buf[stream_ptr]);
260 stream_ptr += 2;
261 colors[6] = LE_16(&buf[stream_ptr]);
262 stream_ptr += 2;
263 colors[7] = LE_16(&buf[stream_ptr]);
264 stream_ptr += 2;
265
266 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
267 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
268 pixels[pixel_ptr++] =
269 colors[((pixel_y & 0x2) << 1) +
270 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
271 pixel_ptr -= row_dec;
272 }
273 } else {
274 /* 2-color encoding */
275 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
276 for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
277 pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
278 pixel_ptr -= row_dec;
279 }
280 }
281 } else {
282 /* otherwise, it's a 1-color block */
283 colors[0] = (byte_b << 8) | byte_a;
284
285 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
286 for (pixel_x = 0; pixel_x < 4; pixel_x++)
287 pixels[pixel_ptr++] = colors[0];
288 pixel_ptr -= row_dec;
289 }
290 }
291
292 block_ptr += block_inc;
293 total_blocks--;
294 }
295 }
296 }
297
298 static LRESULT
299 CRAM_DecompressQuery( Msvideo1Context *info, LPBITMAPINFO in, LPBITMAPINFO out )
300 {
301 TRACE("ICM_DECOMPRESS_QUERY %p %p %p\n", info, in, out);
302
303 if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
304 return ICERR_BADPARAM;
305
306 TRACE("planes = %d\n", in->bmiHeader.biPlanes );
307 TRACE("bpp = %d\n", in->bmiHeader.biBitCount );
308 TRACE("height = %d\n", in->bmiHeader.biHeight );
309 TRACE("width = %d\n", in->bmiHeader.biWidth );
310 TRACE("compr = %x\n", in->bmiHeader.biCompression );
311
312 if( ( in->bmiHeader.biCompression != CRAM_MAGIC ) &&
313 ( in->bmiHeader.biCompression != MSVC_MAGIC ) &&
314 ( in->bmiHeader.biCompression != WHAM_MAGIC ) )
315 return ICERR_BADFORMAT;
316
317 if( ( in->bmiHeader.biBitCount != 16 ) &&
318 ( in->bmiHeader.biBitCount != 8 ) )
319 {
320 TRACE("can't do %d bpp\n", in->bmiHeader.biBitCount );
321 return ICERR_BADFORMAT;
322 }
323
324 /* output must be same dimensions as input */
325 if( out )
326 {
327 if( in->bmiHeader.biBitCount != out->bmiHeader.biBitCount )
328 return ICERR_BADFORMAT;
329 if( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes )
330 return ICERR_BADFORMAT;
331 if( in->bmiHeader.biHeight != out->bmiHeader.biHeight )
332 return ICERR_BADFORMAT;
333 if( in->bmiHeader.biWidth != out->bmiHeader.biWidth )
334 return ICERR_BADFORMAT;
335 }
336
337 TRACE("OK!\n");
338
339 return ICERR_OK;
340 }
341
342 static LRESULT
343 CRAM_DecompressGetFormat( Msvideo1Context *info, LPBITMAPINFO in, LPBITMAPINFO out )
344 {
345 DWORD size;
346
347 TRACE("ICM_DECOMPRESS_GETFORMAT %p %p %p\n", info, in, out);
348
349 if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
350 return ICERR_BADPARAM;
351
352 size = in->bmiHeader.biSize;
353 if (in->bmiHeader.biBitCount <= 8)
354 size += in->bmiHeader.biClrUsed * sizeof(RGBQUAD);
355
356 if( out )
357 {
358 memcpy( out, in, size );
359 out->bmiHeader.biCompression = BI_RGB;
360 out->bmiHeader.biSizeImage = in->bmiHeader.biHeight
361 * in->bmiHeader.biWidth *4;
362 return ICERR_OK;
363 }
364
365 return size;
366 }
367
368 static LRESULT CRAM_DecompressBegin( Msvideo1Context *info, LPBITMAPINFO in, LPBITMAPINFO out )
369 {
370 TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", info, in, out);
371
372 if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
373 return ICERR_BADPARAM;
374
375 TRACE("bitmap is %d bpp\n", in->bmiHeader.biBitCount);
376 if( in->bmiHeader.biBitCount == 8 )
377 info->mode_8bit = TRUE;
378 else if( in->bmiHeader.biBitCount == 16 )
379 info->mode_8bit = FALSE;
380 else
381 {
382 info->mode_8bit = FALSE;
383 FIXME("Unsupported output format %i\n", in->bmiHeader.biBitCount);
384 }
385
386 return ICERR_OK;
387 }
388
389 static LRESULT CRAM_Decompress( Msvideo1Context *info, ICDECOMPRESS *icd, DWORD size )
390 {
391 LONG width, height, stride, sz;
392
393 TRACE("ICM_DECOMPRESS %p %p %d\n", info, icd, size);
394
395 if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
396 return ICERR_BADPARAM;
397
398 /* FIXME: flags are ignored */
399
400 width = icd->lpbiInput->biWidth;
401 height = icd->lpbiInput->biHeight;
402 stride = width; /* in bytes or 16bit words */
403 sz = icd->lpbiInput->biSizeImage;
404
405 if (info->mode_8bit)
406 {
407 msvideo1_decode_8bit( width, height, icd->lpInput, sz,
408 icd->lpOutput, stride);
409 }
410 else
411 {
412 msvideo1_decode_16bit( width, height, icd->lpInput, sz,
413 icd->lpOutput, stride);
414 }
415
416 return ICERR_OK;
417 }
418
419 static LRESULT CRAM_DecompressEx( Msvideo1Context *info, ICDECOMPRESSEX *icd, DWORD size )
420 {
421 LONG width, height, stride, sz;
422
423 TRACE("ICM_DECOMPRESSEX %p %p %d\n", info, icd, size);
424
425 if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
426 return ICERR_BADPARAM;
427
428 /* FIXME: flags are ignored */
429
430 width = icd->lpbiSrc->biWidth;
431 height = icd->lpbiSrc->biHeight;
432 stride = width;
433 sz = icd->lpbiSrc->biSizeImage;
434
435 if (info->mode_8bit)
436 {
437 msvideo1_decode_8bit( width, height, icd->lpSrc, sz,
438 icd->lpDst, stride);
439 }
440 else
441 {
442 msvideo1_decode_16bit( width, height, icd->lpSrc, sz,
443 icd->lpDst, stride);
444 }
445
446 return ICERR_OK;
447 }
448
449 static LRESULT CRAM_GetInfo( const Msvideo1Context *info, ICINFO *icinfo, DWORD dwSize )
450 {
451 if (!icinfo) return sizeof(ICINFO);
452 if (dwSize < sizeof(ICINFO)) return 0;
453
454 icinfo->dwSize = sizeof(ICINFO);
455 icinfo->fccType = ICTYPE_VIDEO;
456 icinfo->fccHandler = info ? info->dwMagic : CRAM_MAGIC;
457 icinfo->dwFlags = 0;
458 icinfo->dwVersion = ICVERSION;
459 icinfo->dwVersionICM = ICVERSION;
460
461 LoadStringW(MSVIDC32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
462 LoadStringW(MSVIDC32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
463 /* msvfw32 will fill icinfo->szDriver for us */
464
465 return sizeof(ICINFO);
466 }
467
468 /***********************************************************************
469 * DriverProc (MSVIDC32.@)
470 */
471 LRESULT WINAPI CRAM_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg,
472 LPARAM lParam1, LPARAM lParam2 )
473 {
474 Msvideo1Context *info = (Msvideo1Context *) dwDriverId;
475 LRESULT r = ICERR_UNSUPPORTED;
476
477 TRACE("%ld %p %04x %08lx %08lx\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
478
479 switch( msg )
480 {
481 case DRV_LOAD:
482 TRACE("Loaded\n");
483 r = 1;
484 break;
485
486 case DRV_ENABLE:
487 break;
488
489 case DRV_OPEN:
490 {
491 ICINFO *icinfo = (ICINFO *)lParam2;
492
493 TRACE("Opened\n");
494
495 if (icinfo && compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return 0;
496
497 info = HeapAlloc( GetProcessHeap(), 0, sizeof (Msvideo1Context) );
498 if( info )
499 {
500 memset( info, 0, sizeof *info );
501 info->dwMagic = CRAM_MAGIC;
502 }
503 r = (LRESULT) info;
504 break;
505 }
506
507 case DRV_CLOSE:
508 HeapFree( GetProcessHeap(), 0, info );
509 break;
510
511 case DRV_DISABLE:
512 break;
513
514 case DRV_FREE:
515 break;
516
517 case ICM_GETINFO:
518 r = CRAM_GetInfo( info, (ICINFO *)lParam1, (DWORD)lParam2 );
519 break;
520
521 case ICM_DECOMPRESS_QUERY:
522 r = CRAM_DecompressQuery( info, (LPBITMAPINFO) lParam1,
523 (LPBITMAPINFO) lParam2 );
524 break;
525
526 case ICM_DECOMPRESS_GET_FORMAT:
527 r = CRAM_DecompressGetFormat( info, (LPBITMAPINFO) lParam1,
528 (LPBITMAPINFO) lParam2 );
529 break;
530
531 case ICM_DECOMPRESS_GET_PALETTE:
532 FIXME("ICM_DECOMPRESS_GET_PALETTE\n");
533 break;
534
535 case ICM_DECOMPRESSEX_QUERY:
536 FIXME("ICM_DECOMPRESSEX_QUERY\n");
537 break;
538
539 case ICM_DECOMPRESS:
540 r = CRAM_Decompress( info, (ICDECOMPRESS*) lParam1,
541 (DWORD) lParam2 );
542 break;
543
544 case ICM_DECOMPRESS_BEGIN:
545 r = CRAM_DecompressBegin( info, (LPBITMAPINFO) lParam1,
546 (LPBITMAPINFO) lParam2 );
547 break;
548
549 case ICM_DECOMPRESSEX:
550 r = CRAM_DecompressEx( info, (ICDECOMPRESSEX*) lParam1,
551 (DWORD) lParam2 );
552 break;
553
554 case ICM_DECOMPRESS_END:
555 r = ICERR_OK;
556 break;
557
558 case ICM_COMPRESS_QUERY:
559 FIXME("compression not implemented\n");
560 r = ICERR_BADFORMAT;
561 break;
562
563 case ICM_CONFIGURE:
564 r = ICERR_UNSUPPORTED;
565 break;
566
567 default:
568 FIXME("Unknown message: %04x %ld %ld\n", msg, lParam1, lParam2);
569 }
570
571 return r;
572 }
573
574 /***********************************************************************
575 * DllMain
576 */
577 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
578 {
579 TRACE("(%p,%d,%p)\n", hModule, dwReason, lpReserved);
580
581 switch (dwReason)
582 {
583 case DLL_PROCESS_ATTACH:
584 DisableThreadLibraryCalls(hModule);
585 MSVIDC32_hModule = hModule;
586 break;
587 }
588 return TRUE;
589 }