xref: /reactos/dll/win32/msvidc32/msvideo1.c (revision cdf90707)
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 #include <stdarg.h>
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "commdlg.h"
40 #include "vfw.h"
41 #include "mmsystem.h"
42 #include "msvidc32_private.h"
43 
44 #include "wine/debug.h"
45 
46 WINE_DEFAULT_DEBUG_CHANNEL(msvidc32);
47 
48 static HINSTANCE MSVIDC32_hModule;
49 
50 #define CRAM_MAGIC mmioFOURCC('C', 'R', 'A', 'M')
51 #define MSVC_MAGIC mmioFOURCC('M', 'S', 'V', 'C')
52 #define WHAM_MAGIC mmioFOURCC('W', 'H', 'A', 'M')
53 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
54 
55 #define PALETTE_COUNT 256
56 #define LE_16(x)  ((((const uint8_t *)(x))[1] << 8) | ((const uint8_t *)(x))[0])
57 
58 /* FIXME - check the stream size */
59 #define CHECK_STREAM_PTR(n) \
60   if ((stream_ptr + n) > buf_size ) { \
61     WARN("stream_ptr out of bounds (%d >= %d)\n", \
62       stream_ptr + n, buf_size); \
63     return; \
64   }
65 
66 typedef BYTE uint8_t;
67 
68 typedef struct Msvideo1Context {
69     DWORD dwMagic;
70     int depth;
71 } Msvideo1Context;
72 
73 static inline int get_stride(int width, int depth)
74 {
75     return ((depth * width + 31) >> 3) & ~3;
76 }
77 
78 static void
79 msvideo1_decode_8bit( int width, int height, const unsigned char *buf, int buf_size,
80                       unsigned char *pixels, int stride)
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 
97     stream_ptr = 0;
98     skip_blocks = 0;
99     blocks_wide = width / 4;
100     blocks_high = height / 4;
101     total_blocks = blocks_wide * blocks_high;
102     block_inc = 4;
103 #ifdef ORIGINAL
104     row_dec = stride + 4;
105 #else
106     row_dec = - (stride - 4); /* such that -row_dec > 0 */
107 #endif
108 
109     for (block_y = blocks_high; block_y > 0; block_y--) {
110 #ifdef ORIGINAL
111         block_ptr = ((block_y * 4) - 1) * stride;
112 #else
113         block_ptr = ((blocks_high - block_y) * 4) * stride;
114 #endif
115         for (block_x = blocks_wide; block_x > 0; block_x--) {
116             /* check if this block should be skipped */
117             if (skip_blocks) {
118                 block_ptr += block_inc;
119                 skip_blocks--;
120                 total_blocks--;
121                 continue;
122             }
123 
124             pixel_ptr = block_ptr;
125 
126             /* get the next two bytes in the encoded data stream */
127             CHECK_STREAM_PTR(2);
128             byte_a = buf[stream_ptr++];
129             byte_b = buf[stream_ptr++];
130 
131             /* check if the decode is finished */
132             if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
133                 return;
134             else if ((byte_b & 0xFC) == 0x84) {
135                 /* skip code, but don't count the current block */
136                 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
137             } else if (byte_b < 0x80) {
138                 /* 2-color encoding */
139                 flags = (byte_b << 8) | byte_a;
140 
141                 CHECK_STREAM_PTR(2);
142                 colors[0] = buf[stream_ptr++];
143                 colors[1] = buf[stream_ptr++];
144 
145                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
146                     for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
147                         pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
148                     pixel_ptr -= row_dec;
149                 }
150             } else if (byte_b >= 0x90) {
151                 /* 8-color encoding */
152                 flags = (byte_b << 8) | byte_a;
153 
154                 CHECK_STREAM_PTR(8);
155                 memcpy(colors, &buf[stream_ptr], 8);
156                 stream_ptr += 8;
157 
158                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
159                     for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
160                         pixels[pixel_ptr++] =
161                             colors[((pixel_y & 0x2) << 1) +
162                                 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
163                     pixel_ptr -= row_dec;
164                 }
165             } else {
166                 /* 1-color encoding */
167                 colors[0] = byte_a;
168 
169                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
170                     for (pixel_x = 0; pixel_x < 4; pixel_x++)
171                         pixels[pixel_ptr++] = colors[0];
172                     pixel_ptr -= row_dec;
173                 }
174             }
175 
176             block_ptr += block_inc;
177             total_blocks--;
178         }
179     }
180 }
181 
182 static void
183 msvideo1_decode_16bit( int width, int height, const unsigned char *buf, int buf_size,
184                        unsigned short *pixels, int stride)
185 {
186     int block_ptr, pixel_ptr;
187     int total_blocks;
188     int pixel_x, pixel_y;  /* pixel width and height iterators */
189     int block_x, block_y;  /* block width and height iterators */
190     int blocks_wide, blocks_high;  /* width and height in 4x4 blocks */
191     int block_inc;
192     int row_dec;
193 
194     /* decoding parameters */
195     int stream_ptr;
196     unsigned char byte_a, byte_b;
197     unsigned short flags;
198     int skip_blocks;
199     unsigned short colors[8];
200 
201     stream_ptr = 0;
202     skip_blocks = 0;
203     blocks_wide = width / 4;
204     blocks_high = height / 4;
205     total_blocks = blocks_wide * blocks_high;
206     block_inc = 4;
207 #ifdef ORIGINAL
208     row_dec = stride + 4;
209 #else
210     row_dec = - (stride - 4); /* such that -row_dec > 0 */
211 #endif
212 
213     for (block_y = blocks_high; block_y > 0; block_y--) {
214 #ifdef ORIGINAL
215         block_ptr = ((block_y * 4) - 1) * stride;
216 #else
217         block_ptr = ((blocks_high - block_y) * 4) * stride;
218 #endif
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;
226             }
227 
228             pixel_ptr = block_ptr;
229 
230             /* get the next two bytes in the encoded data stream */
231             CHECK_STREAM_PTR(2);
232             byte_a = buf[stream_ptr++];
233             byte_b = buf[stream_ptr++];
234 
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;
244 
245                 CHECK_STREAM_PTR(4);
246                 colors[0] = LE_16(&buf[stream_ptr]);
247                 stream_ptr += 2;
248                 colors[1] = LE_16(&buf[stream_ptr]);
249                 stream_ptr += 2;
250 
251                 if (colors[0] & 0x8000) {
252                     /* 8-color encoding */
253                     CHECK_STREAM_PTR(12);
254                     colors[2] = LE_16(&buf[stream_ptr]);
255                     stream_ptr += 2;
256                     colors[3] = LE_16(&buf[stream_ptr]);
257                     stream_ptr += 2;
258                     colors[4] = LE_16(&buf[stream_ptr]);
259                     stream_ptr += 2;
260                     colors[5] = LE_16(&buf[stream_ptr]);
261                     stream_ptr += 2;
262                     colors[6] = LE_16(&buf[stream_ptr]);
263                     stream_ptr += 2;
264                     colors[7] = LE_16(&buf[stream_ptr]);
265                     stream_ptr += 2;
266 
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;
273                     }
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;
280                     }
281                 }
282             } else {
283                 /* otherwise, it's a 1-color block */
284                 colors[0] = (byte_b << 8) | byte_a;
285 
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;
290                 }
291             }
292 
293             block_ptr += block_inc;
294             total_blocks--;
295         }
296     }
297 }
298 
299 static LRESULT
300 CRAM_DecompressQuery( Msvideo1Context *info, LPBITMAPINFO in, LPBITMAPINFO out )
301 {
302     TRACE("ICM_DECOMPRESS_QUERY %p %p %p\n", info, in, out);
303 
304     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
305         return ICERR_BADPARAM;
306 
307     TRACE("in->planes  = %d\n", in->bmiHeader.biPlanes );
308     TRACE("in->bpp     = %d\n", in->bmiHeader.biBitCount );
309     TRACE("in->height  = %d\n", in->bmiHeader.biHeight );
310     TRACE("in->width   = %d\n", in->bmiHeader.biWidth );
311     TRACE("in->compr   = 0x%x\n", in->bmiHeader.biCompression );
312 
313     if( ( in->bmiHeader.biCompression != CRAM_MAGIC ) &&
314         ( in->bmiHeader.biCompression != MSVC_MAGIC ) &&
315         ( in->bmiHeader.biCompression != WHAM_MAGIC ) )
316     {
317         TRACE("can't do 0x%x compression\n", in->bmiHeader.biCompression);
318         return ICERR_BADFORMAT;
319     }
320 
321     if( ( in->bmiHeader.biBitCount != 16 ) &&
322         ( in->bmiHeader.biBitCount != 8 ) )
323     {
324         TRACE("can't do %d bpp\n", in->bmiHeader.biBitCount );
325         return ICERR_BADFORMAT;
326     }
327 
328     /* output must be same dimensions as input */
329     if( out )
330     {
331         TRACE("out->planes = %d\n", out->bmiHeader.biPlanes );
332         TRACE("out->bpp    = %d\n", out->bmiHeader.biBitCount );
333         TRACE("out->height = %d\n", out->bmiHeader.biHeight );
334         TRACE("out->width  = %d\n", out->bmiHeader.biWidth );
335 
336         if ((in->bmiHeader.biBitCount != out->bmiHeader.biBitCount) &&
337             (in->bmiHeader.biBitCount != 16 || out->bmiHeader.biBitCount != 24))
338         {
339             TRACE("incompatible depth requested\n");
340             return ICERR_BADFORMAT;
341         }
342 
343         if(( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes ) ||
344           ( in->bmiHeader.biHeight != out->bmiHeader.biHeight ) ||
345           ( in->bmiHeader.biWidth != out->bmiHeader.biWidth ))
346         {
347             TRACE("incompatible output requested\n");
348             return ICERR_BADFORMAT;
349         }
350     }
351 
352     TRACE("OK!\n");
353     return ICERR_OK;
354 }
355 
356 static LRESULT
357 CRAM_DecompressGetFormat( Msvideo1Context *info, LPBITMAPINFO in, LPBITMAPINFO out )
358 {
359     DWORD size;
360 
361     TRACE("ICM_DECOMPRESS_GETFORMAT %p %p %p\n", info, in, out);
362 
363     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
364         return ICERR_BADPARAM;
365 
366     size = in->bmiHeader.biSize;
367     if (in->bmiHeader.biBitCount <= 8)
368         size += in->bmiHeader.biClrUsed * sizeof(RGBQUAD);
369 
370     if (in->bmiHeader.biBitCount != 8 && in->bmiHeader.biBitCount != 16)
371         return ICERR_BADFORMAT;
372 
373     if( out )
374     {
375         memcpy( out, in, size );
376         out->bmiHeader.biWidth = in->bmiHeader.biWidth & ~1;
377         out->bmiHeader.biHeight = in->bmiHeader.biHeight & ~1;
378         out->bmiHeader.biCompression = BI_RGB;
379         out->bmiHeader.biSizeImage = in->bmiHeader.biHeight *
380                                      get_stride(out->bmiHeader.biWidth, out->bmiHeader.biBitCount);
381         return ICERR_OK;
382     }
383 
384     return size;
385 }
386 
387 static LRESULT CRAM_DecompressBegin( Msvideo1Context *info, LPBITMAPINFO in, LPBITMAPINFO out )
388 {
389     TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", info, in, out);
390 
391     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
392         return ICERR_BADPARAM;
393 
394     TRACE("bitmap is %d bpp\n", in->bmiHeader.biBitCount);
395     if( in->bmiHeader.biBitCount == 8 )
396         info->depth = 8;
397     else if( in->bmiHeader.biBitCount == 16 )
398         info->depth = 16;
399     else
400     {
401         info->depth = 0;
402         FIXME("Unsupported output format %i\n", in->bmiHeader.biBitCount);
403     }
404 
405     return ICERR_OK;
406 }
407 
408 static void convert_depth(char *input, int depth_in, char *output, BITMAPINFOHEADER *out_hdr)
409 {
410     int x, y;
411     int stride_in  = get_stride(out_hdr->biWidth, depth_in);
412     int stride_out = get_stride(out_hdr->biWidth, out_hdr->biBitCount);
413 
414     if (depth_in == 16 && out_hdr->biBitCount == 24)
415     {
416         static const unsigned char convert_5to8[] =
417         {
418             0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
419             0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
420             0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
421             0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
422         };
423 
424         for (y = 0; y < out_hdr->biHeight; y++)
425         {
426             WORD *src_row = (WORD *)(input + y * stride_in);
427             char *out_row = output + y * stride_out;
428 
429             for (x = 0; x < out_hdr->biWidth; x++)
430             {
431                 WORD pixel = *src_row++;
432                 *out_row++ = convert_5to8[(pixel & 0x7c00u) >> 10];
433                 *out_row++ = convert_5to8[(pixel & 0x03e0u) >> 5];
434                 *out_row++ = convert_5to8[(pixel & 0x001fu)];
435             }
436         }
437     }
438     else
439         FIXME("Conversion from %d to %d bit unimplemented\n", depth_in, out_hdr->biBitCount);
440 }
441 
442 static LRESULT CRAM_Decompress( Msvideo1Context *info, ICDECOMPRESS *icd, DWORD size )
443 {
444     LONG width, height, stride, sz;
445     void *output;
446 
447     TRACE("ICM_DECOMPRESS %p %p %d\n", info, icd, size);
448 
449     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
450         return ICERR_BADPARAM;
451 
452     /* FIXME: flags are ignored */
453 
454     width  = icd->lpbiInput->biWidth;
455     height = icd->lpbiInput->biHeight;
456     sz = icd->lpbiInput->biSizeImage;
457 
458     output = icd->lpOutput;
459 
460     if (icd->lpbiOutput->biBitCount != info->depth)
461     {
462         output = HeapAlloc(GetProcessHeap(), 0, icd->lpbiOutput->biWidth * icd->lpbiOutput->biHeight * info->depth / 8);
463         if (!output) return ICERR_MEMORY;
464     }
465 
466     if (info->depth == 8)
467     {
468         stride = get_stride(width, 8);
469         msvideo1_decode_8bit( width, height, icd->lpInput, sz,
470                               output, stride );
471     }
472     else
473     {
474         stride = get_stride(width, 16) / 2;
475         msvideo1_decode_16bit( width, height, icd->lpInput, sz,
476                                output, stride );
477     }
478 
479     if (icd->lpbiOutput->biBitCount != info->depth)
480     {
481         convert_depth(output, info->depth, icd->lpOutput, icd->lpbiOutput);
482         HeapFree(GetProcessHeap(), 0, output);
483     }
484 
485     return ICERR_OK;
486 }
487 
488 static LRESULT CRAM_DecompressEx( Msvideo1Context *info, ICDECOMPRESSEX *icd, DWORD size )
489 {
490     LONG width, height, stride, sz;
491     void *output;
492 
493     TRACE("ICM_DECOMPRESSEX %p %p %d\n", info, icd, size);
494 
495     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
496         return ICERR_BADPARAM;
497 
498     /* FIXME: flags are ignored */
499 
500     width  = icd->lpbiSrc->biWidth;
501     height = icd->lpbiSrc->biHeight;
502     sz = icd->lpbiSrc->biSizeImage;
503 
504     output = icd->lpDst;
505 
506     if (icd->lpbiDst->biBitCount != info->depth)
507     {
508         output = HeapAlloc(GetProcessHeap(), 0, icd->lpbiDst->biWidth * icd->lpbiDst->biHeight * info->depth / 8);
509         if (!output) return ICERR_MEMORY;
510     }
511 
512     if (info->depth == 8)
513     {
514         stride = get_stride(width, 8);
515         msvideo1_decode_8bit( width, height, icd->lpSrc, sz,
516                               output, stride );
517     }
518     else
519     {
520         stride = get_stride(width, 16) / 2;
521         msvideo1_decode_16bit( width, height, icd->lpSrc, sz,
522                                output, stride );
523     }
524 
525     if (icd->lpbiDst->biBitCount != info->depth)
526     {
527         convert_depth(output, info->depth, icd->lpDst, icd->lpbiDst);
528         HeapFree(GetProcessHeap(), 0, output);
529     }
530 
531     return ICERR_OK;
532 }
533 
534 static LRESULT CRAM_GetInfo( const Msvideo1Context *info, ICINFO *icinfo, DWORD dwSize )
535 {
536     if (!icinfo) return sizeof(ICINFO);
537     if (dwSize < sizeof(ICINFO)) return 0;
538 
539     icinfo->dwSize = sizeof(ICINFO);
540     icinfo->fccType = ICTYPE_VIDEO;
541     icinfo->fccHandler = info ? info->dwMagic : CRAM_MAGIC;
542     icinfo->dwFlags = 0;
543     icinfo->dwVersion = ICVERSION;
544     icinfo->dwVersionICM = ICVERSION;
545 
546     LoadStringW(MSVIDC32_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName));
547     LoadStringW(MSVIDC32_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(icinfo->szDescription));
548     /* msvfw32 will fill icinfo->szDriver for us */
549 
550     return sizeof(ICINFO);
551 }
552 
553 /***********************************************************************
554  *		DriverProc (MSVIDC32.@)
555  */
556 LRESULT WINAPI CRAM_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg,
557                                 LPARAM lParam1, LPARAM lParam2 )
558 {
559     Msvideo1Context *info = (Msvideo1Context *) dwDriverId;
560     LRESULT r = ICERR_UNSUPPORTED;
561 
562     TRACE("%ld %p %04x %08lx %08lx\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
563 
564     switch( msg )
565     {
566     case DRV_LOAD:
567         TRACE("Loaded\n");
568         r = 1;
569         break;
570 
571     case DRV_ENABLE:
572         break;
573 
574     case DRV_OPEN:
575     {
576         ICINFO *icinfo = (ICINFO *)lParam2;
577 
578         TRACE("Opened\n");
579 
580         if (icinfo && compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return 0;
581 
582         info = HeapAlloc( GetProcessHeap(), 0, sizeof (Msvideo1Context) );
583         if( info )
584         {
585             memset( info, 0, sizeof *info );
586             info->dwMagic = CRAM_MAGIC;
587         }
588         r = (LRESULT) info;
589         break;
590     }
591 
592     case DRV_CLOSE:
593         HeapFree( GetProcessHeap(), 0, info );
594         break;
595 
596     case DRV_DISABLE:
597         break;
598 
599     case DRV_FREE:
600         break;
601 
602     case ICM_GETINFO:
603         r = CRAM_GetInfo( info, (ICINFO *)lParam1, (DWORD)lParam2 );
604         break;
605 
606     case ICM_DECOMPRESS_QUERY:
607         r = CRAM_DecompressQuery( info, (LPBITMAPINFO) lParam1,
608                                        (LPBITMAPINFO) lParam2 );
609         break;
610 
611     case ICM_DECOMPRESS_GET_FORMAT:
612         r = CRAM_DecompressGetFormat( info, (LPBITMAPINFO) lParam1,
613                                        (LPBITMAPINFO) lParam2 );
614         break;
615 
616     case ICM_DECOMPRESS_GET_PALETTE:
617         FIXME("ICM_DECOMPRESS_GET_PALETTE\n");
618         break;
619 
620     case ICM_DECOMPRESSEX_QUERY:
621         FIXME("ICM_DECOMPRESSEX_QUERY\n");
622         break;
623 
624     case ICM_DECOMPRESS:
625         r = CRAM_Decompress( info, (ICDECOMPRESS*) lParam1,
626                                   (DWORD) lParam2 );
627         break;
628 
629     case ICM_DECOMPRESS_BEGIN:
630         r = CRAM_DecompressBegin( info, (LPBITMAPINFO) lParam1,
631                                        (LPBITMAPINFO) lParam2 );
632         break;
633 
634     case ICM_DECOMPRESSEX:
635         r = CRAM_DecompressEx( info, (ICDECOMPRESSEX*) lParam1,
636                                   (DWORD) lParam2 );
637         break;
638 
639     case ICM_DECOMPRESS_END:
640         r = ICERR_OK;
641         break;
642 
643     case ICM_COMPRESS_QUERY:
644         r = ICERR_BADFORMAT;
645         /* fall through */
646     case ICM_COMPRESS_GET_FORMAT:
647     case ICM_COMPRESS_END:
648     case ICM_COMPRESS:
649         FIXME("compression not implemented\n");
650         break;
651 
652     case ICM_CONFIGURE:
653         break;
654 
655     default:
656         FIXME("Unknown message: %04x %ld %ld\n", msg, lParam1, lParam2);
657     }
658 
659     return r;
660 }
661 
662 /***********************************************************************
663  *		DllMain
664  */
665 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
666 {
667     TRACE("(%p,%d,%p)\n", hModule, dwReason, lpReserved);
668 
669     switch (dwReason)
670     {
671     case DLL_PROCESS_ATTACH:
672         DisableThreadLibraryCalls(hModule);
673         MSVIDC32_hModule = hModule;
674         break;
675     }
676     return TRUE;
677 }
678