Added OLEIVERB_UIACTIVATE handling.
[wine] / dlls / 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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  
42 #include "mmsystem.h"
43  
44 #include "wine/debug.h"
45  
46 WINE_DEFAULT_DEBUG_CHANNEL(msvidc32); 
47
48 #define CRAM_MAGIC mmioFOURCC('C', 'R', 'A', 'M')
49 #define MSVC_MAGIC mmioFOURCC('M', 'S', 'V', 'C')
50 #define WHAM_MAGIC mmioFOURCC('W', 'H', 'A', 'M')
51
52 #define PALETTE_COUNT 256
53 #define LE_16(x)  ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
54
55 /* FIXME - check the stream size */
56 #define CHECK_STREAM_PTR(n) \
57   if ((stream_ptr + n) > buf_size ) { \
58     WARN("stream_ptr out of bounds (%d >= %d)\n", \
59       stream_ptr + n, buf_size); \
60     return; \
61   }
62
63 typedef BYTE uint8_t;
64
65 typedef struct Msvideo1Context {
66     DWORD dwMagic;
67     int mode_8bit;  /* if it's not 8-bit, it's 16-bit */
68 } Msvideo1Context;
69
70 static void 
71 msvideo1_decode_8bit( int width, int height, unsigned char *buf, int buf_size,
72                       unsigned char *pixels, int stride)
73 {
74     int block_ptr, pixel_ptr;
75     int total_blocks;
76     int pixel_x, pixel_y;  /* pixel width and height iterators */
77     int block_x, block_y;  /* block width and height iterators */
78     int blocks_wide, blocks_high;  /* width and height in 4x4 blocks */
79     int block_inc;
80     int row_dec;
81
82     /* decoding parameters */
83     int stream_ptr;
84     unsigned char byte_a, byte_b;
85     unsigned short flags;
86     int skip_blocks;
87     unsigned char colors[8];
88
89     stream_ptr = 0;
90     skip_blocks = 0;
91     blocks_wide = width / 4;
92     blocks_high = height / 4;
93     total_blocks = blocks_wide * blocks_high;
94     block_inc = 4;
95     row_dec = stride + 4;
96
97     for (block_y = blocks_high; block_y > 0; block_y--) {
98         block_ptr = ((block_y * 4) - 1) * stride;
99         for (block_x = blocks_wide; block_x > 0; block_x--) {
100             /* check if this block should be skipped */
101             if (skip_blocks) {
102                 block_ptr += block_inc;
103                 skip_blocks--;
104                 total_blocks--;
105                 continue;
106             }
107
108             pixel_ptr = block_ptr;
109
110             /* get the next two bytes in the encoded data stream */
111             CHECK_STREAM_PTR(2);
112             byte_a = buf[stream_ptr++];
113             byte_b = buf[stream_ptr++];
114
115             /* check if the decode is finished */
116             if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
117                 return;
118             else if ((byte_b & 0xFC) == 0x84) {
119                 /* skip code, but don't count the current block */
120                 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
121             } else if (byte_b < 0x80) {
122                 /* 2-color encoding */
123                 flags = (byte_b << 8) | byte_a;
124
125                 CHECK_STREAM_PTR(2);
126                 colors[0] = buf[stream_ptr++];
127                 colors[1] = buf[stream_ptr++];
128
129                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
130                     for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
131                     {
132 #if ORIGINAL
133                         pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
134 #else
135                         pixels[width*(height-(pixel_ptr/width)-1) + 
136                                pixel_ptr%width] = 
137                                colors[(flags & 0x1) ^ 1];
138                         pixel_ptr++;
139 #endif
140                     }
141                     pixel_ptr -= row_dec;
142                 }
143             } else if (byte_b >= 0x90) {
144                 /* 8-color encoding */
145                 flags = (byte_b << 8) | byte_a;
146
147                 CHECK_STREAM_PTR(8);
148                 memcpy(colors, &buf[stream_ptr], 8);
149                 stream_ptr += 8;
150
151                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
152                     for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
153                     {
154 #if ORIGINAL
155                         pixels[pixel_ptr++] = 
156                             colors[((pixel_y & 0x2) << 1) + 
157                                 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
158 #else
159                         pixels[width*(height-(pixel_ptr/width)-1) + 
160                                pixel_ptr%width] = 
161                             colors[((pixel_y & 0x2) << 1) + 
162                                 (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
163                         pixel_ptr++;
164 #endif
165                     }
166                     pixel_ptr -= row_dec;
167                 }
168             } else {
169                 /* 1-color encoding */
170                 colors[0] = byte_a;
171
172                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
173                     for (pixel_x = 0; pixel_x < 4; pixel_x++)
174                     {
175 #if ORIGINAL
176                         pixels[pixel_ptr++] = colors[0];
177 #else
178                         pixels[width*(height-(pixel_ptr/width)-1) + 
179                                pixel_ptr%width] = colors[0];
180                         pixel_ptr++;
181 #endif
182                     }
183                     pixel_ptr -= row_dec;
184                 }
185             }
186
187             block_ptr += block_inc;
188             total_blocks--;
189         }
190     }
191 }
192
193 static void
194 msvideo1_decode_16bit( int width, int height, unsigned char *buf, int buf_size,
195                        unsigned short *pixels, int stride)
196 {
197     int block_ptr, pixel_ptr;
198     int total_blocks;
199     int pixel_x, pixel_y;  /* pixel width and height iterators */
200     int block_x, block_y;  /* block width and height iterators */
201     int blocks_wide, blocks_high;  /* width and height in 4x4 blocks */
202     int block_inc;
203     int row_dec;
204
205     /* decoding parameters */
206     int stream_ptr;
207     unsigned char byte_a, byte_b;
208     unsigned short flags;
209     int skip_blocks;
210     unsigned short colors[8];
211
212     stream_ptr = 0;
213     skip_blocks = 0;
214     blocks_wide = width / 4;
215     blocks_high = height / 4;
216     total_blocks = blocks_wide * blocks_high;
217     block_inc = 4;
218     row_dec = stride + 4;
219
220     for (block_y = blocks_high; block_y > 0; block_y--) {
221         block_ptr = ((block_y * 4) - 1) * stride;
222         for (block_x = blocks_wide; block_x > 0; block_x--) {
223             /* check if this block should be skipped */
224             if (skip_blocks) {
225                 block_ptr += block_inc;
226                 skip_blocks--;
227                 total_blocks--;
228                 continue;
229             }
230
231             pixel_ptr = block_ptr;
232
233             /* get the next two bytes in the encoded data stream */
234             CHECK_STREAM_PTR(2);
235             byte_a = buf[stream_ptr++];
236             byte_b = buf[stream_ptr++];
237
238             /* check if the decode is finished */
239             if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
240                 return;
241             } else if ((byte_b & 0xFC) == 0x84) {
242                 /* skip code, but don't count the current block */
243                 skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
244             } else if (byte_b < 0x80) {
245                 /* 2- or 8-color encoding modes */
246                 flags = (byte_b << 8) | byte_a;
247
248                 CHECK_STREAM_PTR(4);
249                 colors[0] = LE_16(&buf[stream_ptr]);
250                 stream_ptr += 2;
251                 colors[1] = LE_16(&buf[stream_ptr]);
252                 stream_ptr += 2;
253
254                 if (colors[0] & 0x8000) {
255                     /* 8-color encoding */
256                     CHECK_STREAM_PTR(12);
257                     colors[2] = LE_16(&buf[stream_ptr]);
258                     stream_ptr += 2;
259                     colors[3] = LE_16(&buf[stream_ptr]);
260                     stream_ptr += 2;
261                     colors[4] = LE_16(&buf[stream_ptr]);
262                     stream_ptr += 2;
263                     colors[5] = LE_16(&buf[stream_ptr]);
264                     stream_ptr += 2;
265                     colors[6] = LE_16(&buf[stream_ptr]);
266                     stream_ptr += 2;
267                     colors[7] = LE_16(&buf[stream_ptr]);
268                     stream_ptr += 2;
269
270                     for (pixel_y = 0; pixel_y < 4; pixel_y++) {
271                         for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
272                             pixels[pixel_ptr++] = 
273                                 colors[((pixel_y & 0x2) << 1) + 
274                                     (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
275                         pixel_ptr -= row_dec;
276                     }
277                 } else {
278                     /* 2-color encoding */
279                     for (pixel_y = 0; pixel_y < 4; pixel_y++) {
280                         for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
281                             pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
282                         pixel_ptr -= row_dec;
283                     }
284                 }
285             } else {
286                 /* otherwise, it's a 1-color block */
287                 colors[0] = (byte_b << 8) | byte_a;
288
289                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
290                     for (pixel_x = 0; pixel_x < 4; pixel_x++)
291                         pixels[pixel_ptr++] = colors[0];
292                     pixel_ptr -= row_dec;
293                 }
294             }
295
296             block_ptr += block_inc;
297             total_blocks--;
298         }
299     }
300 }
301
302 static LRESULT
303 CRAM_DecompressQuery( Msvideo1Context *info, LPBITMAPINFO in, LPBITMAPINFO out )
304 {
305     TRACE("ICM_DECOMPRESS_QUERY %p %p %p\n", info, in, out);
306
307     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
308         return ICERR_BADPARAM;
309
310     TRACE("planes = %d\n", in->bmiHeader.biPlanes );
311     TRACE("bpp    = %d\n", in->bmiHeader.biBitCount );
312     TRACE("height = %ld\n", in->bmiHeader.biHeight );
313     TRACE("width  = %ld\n", in->bmiHeader.biWidth );
314     TRACE("compr  = %lx\n", in->bmiHeader.biCompression );
315
316     if( ( in->bmiHeader.biCompression != CRAM_MAGIC ) &&
317         ( in->bmiHeader.biCompression != MSVC_MAGIC ) &&
318         ( in->bmiHeader.biCompression != WHAM_MAGIC ) )
319         return ICERR_UNSUPPORTED;
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_UNSUPPORTED;
326     }
327
328     /* output must be same dimensions as input */
329     if( out )
330     {
331         if( in->bmiHeader.biBitCount != out->bmiHeader.biBitCount )
332             return ICERR_UNSUPPORTED;
333         if( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes )
334             return ICERR_UNSUPPORTED;
335         if( in->bmiHeader.biHeight != out->bmiHeader.biHeight )
336             return ICERR_UNSUPPORTED;
337         if( in->bmiHeader.biWidth != out->bmiHeader.biWidth )
338             return ICERR_UNSUPPORTED;
339     }
340
341     TRACE("OK!\n");
342
343     return ICERR_OK;
344 }
345
346 static LRESULT 
347 CRAM_DecompressGetFormat( Msvideo1Context *info, LPBITMAPINFO in, LPBITMAPINFO out )
348 {
349     DWORD size;
350
351     TRACE("ICM_DECOMPRESS_GETFORMAT %p %p %p\n", info, in, out);
352
353     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
354         return ICERR_BADPARAM;
355
356     size = in->bmiHeader.biSize;
357     if (in->bmiHeader.biBitCount <= 8)
358         size += in->bmiHeader.biClrUsed * sizeof(RGBQUAD);
359
360     if( out )
361     {
362         memcpy( out, in, size );
363         out->bmiHeader.biCompression = BI_RGB;
364         out->bmiHeader.biSizeImage = in->bmiHeader.biHeight
365                                    * in->bmiHeader.biWidth *4;
366         return ICERR_OK;
367     }
368
369     return size;
370 }
371
372 LRESULT CRAM_DecompressBegin( Msvideo1Context *info, LPBITMAPINFO in, LPBITMAPINFO out )
373 {
374     TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", info, in, out);
375
376     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
377         return ICERR_BADPARAM;
378
379     TRACE("bitmap is %d bpp\n", in->bmiHeader.biBitCount);
380     if( in->bmiHeader.biBitCount == 8 )
381         info->mode_8bit = 1;
382     else if( in->bmiHeader.biBitCount == 16 )
383         info->mode_8bit = 0;
384     else
385     {
386         ERR("Bad output format\n");
387         return ICERR_BADPARAM;
388     }
389
390     return ICERR_OK;
391 }
392
393 LRESULT CRAM_Decompress( Msvideo1Context *info, ICDECOMPRESS *icd, DWORD size )
394 {
395     LONG width, height, stride, sz;
396     WORD bit_per_pixel;
397
398     TRACE("ICM_DECOMPRESS %p %p %ld\n", info, icd, size);
399
400     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
401         return ICERR_BADPARAM;
402
403     /* FIXME: flags are ignored */
404
405     width  = icd->lpbiInput->biWidth;
406     height = icd->lpbiInput->biHeight;
407     bit_per_pixel = icd->lpbiInput->biBitCount;
408     stride = width*bit_per_pixel/8;
409     sz = icd->lpbiInput->biSizeImage;
410
411     if (info->mode_8bit)
412     {
413         msvideo1_decode_8bit( width, height, icd->lpInput, sz,
414                               icd->lpOutput, stride);
415     }
416     else
417     {
418         msvideo1_decode_16bit( width, height, icd->lpInput, sz,
419                                icd->lpOutput, stride);
420     }
421
422     return ICERR_OK;
423 }
424
425 LRESULT CRAM_DecompressEx( Msvideo1Context *info, ICDECOMPRESSEX *icd, DWORD size )
426 {
427     LONG width, height, stride, sz;
428     WORD bit_per_pixel;
429
430     TRACE("ICM_DECOMPRESSEX %p %p %ld\n", info, icd, size);
431
432     if( (info==NULL) || (info->dwMagic!=CRAM_MAGIC) )
433         return ICERR_BADPARAM;
434
435     /* FIXME: flags are ignored */
436
437     width  = icd->lpbiSrc->biWidth;
438     height = icd->lpbiSrc->biHeight;
439     bit_per_pixel = icd->lpbiSrc->biBitCount;
440     stride = width*bit_per_pixel/8;
441     sz = icd->lpbiSrc->biSizeImage;
442
443     if (info->mode_8bit)
444     {
445         msvideo1_decode_8bit( width, height, icd->lpSrc, sz, 
446                              icd->lpDst, stride);
447     }
448     else
449     {
450         msvideo1_decode_16bit( width, height, icd->lpSrc, sz,
451                               icd->lpDst, stride);
452     }
453
454     return ICERR_OK;
455 }
456
457 /***********************************************************************
458  *              DriverProc (MSVIDC32.@)
459  */
460 LRESULT WINAPI CRAM_DriverProc( DWORD dwDriverId, HDRVR hdrvr, UINT msg,
461                                   LONG lParam1, LONG lParam2)
462 {
463     Msvideo1Context *info = (Msvideo1Context *) dwDriverId;
464     LRESULT r = 0;
465
466     TRACE("%ld %p %d %ld %ld\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
467
468     switch( msg )
469     {
470     case DRV_LOAD:
471         TRACE("Loaded\n");
472         r = 1;
473         break;
474
475     case DRV_ENABLE:
476         break;
477
478     case DRV_OPEN:
479         TRACE("Opened\n");
480         info = HeapAlloc( GetProcessHeap(), 0, sizeof (Msvideo1Context) );
481         if( info )
482         {
483             memset( info, 0, sizeof info );
484             info->dwMagic = CRAM_MAGIC;
485         }
486         r = (LRESULT) info;
487         break;
488
489     case ICM_DECOMPRESS_QUERY:
490         r = CRAM_DecompressQuery( info, (LPBITMAPINFO) lParam1,
491                                        (LPBITMAPINFO) lParam2 );
492         break;
493
494     case ICM_DECOMPRESS_GET_FORMAT:
495         r = CRAM_DecompressGetFormat( info, (LPBITMAPINFO) lParam1,
496                                        (LPBITMAPINFO) lParam2 );
497         break;
498
499     case ICM_DECOMPRESS_GET_PALETTE:
500         FIXME("ICM_DECOMPRESS_GET_PALETTE\n");
501         break;
502
503     case ICM_DECOMPRESSEX_QUERY:
504         FIXME("ICM_DECOMPRESSEX_QUERY\n");
505         break;
506
507     case ICM_DECOMPRESS:
508         r = CRAM_Decompress( info, (ICDECOMPRESS*) lParam1,
509                                   (DWORD) lParam2 );
510         break;
511
512     case ICM_DECOMPRESS_BEGIN:
513         r = CRAM_DecompressBegin( info, (LPBITMAPINFO) lParam1,
514                                        (LPBITMAPINFO) lParam2 );
515         break;
516
517     case ICM_DECOMPRESSEX:
518         r = CRAM_DecompressEx( info, (ICDECOMPRESSEX*) lParam1,
519                                   (DWORD) lParam2 );
520         break;
521
522     case DRV_CLOSE:
523         HeapFree( GetProcessHeap(), 0, info );
524         break;
525
526     case DRV_DISABLE:
527         break;
528
529     case DRV_FREE:
530         break;
531
532     default:
533         FIXME("Unknown message: %04x %ld %ld\n", msg, lParam1, lParam2);
534     }
535
536     return r;
537 }