2 * Microsoft Video-1 Decoder
3 * Copyright (C) 2003 the ffmpeg project
5 * Portions Copyright (C) 2004 Mike McCormack for CodeWeavers
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.
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.
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
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/
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.
42 #include "msvidc32_private.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(msvidc32
);
48 static HINSTANCE MSVIDC32_hModule
;
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)
55 #define PALETTE_COUNT 256
56 #define LE_16(x) ((((const uint8_t *)(x))[1] << 8) | ((const uint8_t *)(x))[0])
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); \
68 typedef struct Msvideo1Context
{
73 static inline int get_stride(int width
, int depth
)
75 return ((depth
* width
+ 31) >> 3) & ~3;
79 msvideo1_decode_8bit( int width
, int height
, const unsigned char *buf
, int buf_size
,
80 unsigned char *pixels
, int stride
)
82 int block_ptr
, pixel_ptr
;
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 */
90 /* decoding parameters */
92 unsigned char byte_a
, byte_b
;
95 unsigned char colors
[8];
99 blocks_wide
= width
/ 4;
100 blocks_high
= height
/ 4;
101 total_blocks
= blocks_wide
* blocks_high
;
104 row_dec
= stride
+ 4;
106 row_dec
= - (stride
- 4); /* such that -row_dec > 0 */
109 for (block_y
= blocks_high
; block_y
> 0; block_y
--) {
111 block_ptr
= ((block_y
* 4) - 1) * stride
;
113 block_ptr
= ((blocks_high
- block_y
) * 4) * stride
;
115 for (block_x
= blocks_wide
; block_x
> 0; block_x
--) {
116 /* check if this block should be skipped */
118 block_ptr
+= block_inc
;
124 pixel_ptr
= block_ptr
;
126 /* get the next two bytes in the encoded data stream */
128 byte_a
= buf
[stream_ptr
++];
129 byte_b
= buf
[stream_ptr
++];
131 /* check if the decode is finished */
132 if ((byte_a
== 0) && (byte_b
== 0) && (total_blocks
== 0))
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
;
142 colors
[0] = buf
[stream_ptr
++];
143 colors
[1] = buf
[stream_ptr
++];
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
;
150 } else if (byte_b
>= 0x90) {
151 /* 8-color encoding */
152 flags
= (byte_b
<< 8) | byte_a
;
155 memcpy(colors
, &buf
[stream_ptr
], 8);
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
;
166 /* 1-color encoding */
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
;
176 block_ptr
+= block_inc
;
183 msvideo1_decode_16bit( int width
, int height
, const unsigned char *buf
, int buf_size
,
184 unsigned short *pixels
, int stride
)
186 int block_ptr
, pixel_ptr
;
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 */
194 /* decoding parameters */
196 unsigned char byte_a
, byte_b
;
197 unsigned short flags
;
199 unsigned short colors
[8];
203 blocks_wide
= width
/ 4;
204 blocks_high
= height
/ 4;
205 total_blocks
= blocks_wide
* blocks_high
;
208 row_dec
= stride
+ 4;
210 row_dec
= - (stride
- 4); /* such that -row_dec > 0 */
213 for (block_y
= blocks_high
; block_y
> 0; block_y
--) {
215 block_ptr
= ((block_y
* 4) - 1) * stride
;
217 block_ptr
= ((blocks_high
- block_y
) * 4) * stride
;
219 for (block_x
= blocks_wide
; block_x
> 0; block_x
--) {
220 /* check if this block should be skipped */
222 block_ptr
+= block_inc
;
228 pixel_ptr
= block_ptr
;
230 /* get the next two bytes in the encoded data stream */
232 byte_a
= buf
[stream_ptr
++];
233 byte_b
= buf
[stream_ptr
++];
235 /* check if the decode is finished */
236 if ((byte_a
== 0) && (byte_b
== 0) && (total_blocks
== 0)) {
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
;
246 colors
[0] = LE_16(&buf
[stream_ptr
]);
248 colors
[1] = LE_16(&buf
[stream_ptr
]);
251 if (colors
[0] & 0x8000) {
252 /* 8-color encoding */
253 CHECK_STREAM_PTR(12);
254 colors
[2] = LE_16(&buf
[stream_ptr
]);
256 colors
[3] = LE_16(&buf
[stream_ptr
]);
258 colors
[4] = LE_16(&buf
[stream_ptr
]);
260 colors
[5] = LE_16(&buf
[stream_ptr
]);
262 colors
[6] = LE_16(&buf
[stream_ptr
]);
264 colors
[7] = LE_16(&buf
[stream_ptr
]);
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
;
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
;
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
;
300 CRAM_DecompressQuery( Msvideo1Context
*info
, LPBITMAPINFO in
, LPBITMAPINFO out
)
302 TRACE("ICM_DECOMPRESS_QUERY %p %p %p\n", info
, in
, out
);
304 if( (info
==NULL
) || (info
->dwMagic
!=CRAM_MAGIC
) )
305 return ICERR_BADPARAM
;
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
);
313 if( ( in
->bmiHeader
.biCompression
!= CRAM_MAGIC
) &&
314 ( in
->bmiHeader
.biCompression
!= MSVC_MAGIC
) &&
315 ( in
->bmiHeader
.biCompression
!= WHAM_MAGIC
) )
317 TRACE("can't do 0x%x compression\n", in
->bmiHeader
.biCompression
);
318 return ICERR_BADFORMAT
;
321 if( ( in
->bmiHeader
.biBitCount
!= 16 ) &&
322 ( in
->bmiHeader
.biBitCount
!= 8 ) )
324 TRACE("can't do %d bpp\n", in
->bmiHeader
.biBitCount
);
325 return ICERR_BADFORMAT
;
328 /* output must be same dimensions as input */
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
);
336 if ((in
->bmiHeader
.biBitCount
!= out
->bmiHeader
.biBitCount
) &&
337 (in
->bmiHeader
.biBitCount
!= 16 || out
->bmiHeader
.biBitCount
!= 24))
339 TRACE("incompatible depth requested\n");
340 return ICERR_BADFORMAT
;
343 if(( in
->bmiHeader
.biPlanes
!= out
->bmiHeader
.biPlanes
) ||
344 ( in
->bmiHeader
.biHeight
!= out
->bmiHeader
.biHeight
) ||
345 ( in
->bmiHeader
.biWidth
!= out
->bmiHeader
.biWidth
))
347 TRACE("incompatible output requested\n");
348 return ICERR_BADFORMAT
;
357 CRAM_DecompressGetFormat( Msvideo1Context
*info
, LPBITMAPINFO in
, LPBITMAPINFO out
)
361 TRACE("ICM_DECOMPRESS_GETFORMAT %p %p %p\n", info
, in
, out
);
363 if( (info
==NULL
) || (info
->dwMagic
!=CRAM_MAGIC
) )
364 return ICERR_BADPARAM
;
366 size
= in
->bmiHeader
.biSize
;
367 if (in
->bmiHeader
.biBitCount
<= 8)
368 size
+= in
->bmiHeader
.biClrUsed
* sizeof(RGBQUAD
);
370 if (in
->bmiHeader
.biBitCount
!= 8 && in
->bmiHeader
.biBitCount
!= 16)
371 return ICERR_BADFORMAT
;
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
);
387 static LRESULT
CRAM_DecompressBegin( Msvideo1Context
*info
, LPBITMAPINFO in
, LPBITMAPINFO out
)
389 TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", info
, in
, out
);
391 if( (info
==NULL
) || (info
->dwMagic
!=CRAM_MAGIC
) )
392 return ICERR_BADPARAM
;
394 TRACE("bitmap is %d bpp\n", in
->bmiHeader
.biBitCount
);
395 if( in
->bmiHeader
.biBitCount
== 8 )
397 else if( in
->bmiHeader
.biBitCount
== 16 )
402 FIXME("Unsupported output format %i\n", in
->bmiHeader
.biBitCount
);
408 static void convert_depth(char *input
, int depth_in
, char *output
, BITMAPINFOHEADER
*out_hdr
)
411 int stride_in
= get_stride(out_hdr
->biWidth
, depth_in
);
412 int stride_out
= get_stride(out_hdr
->biWidth
, out_hdr
->biBitCount
);
414 if (depth_in
== 16 && out_hdr
->biBitCount
== 24)
416 static const unsigned char convert_5to8
[] =
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,
424 for (y
= 0; y
< out_hdr
->biHeight
; y
++)
426 WORD
*src_row
= (WORD
*)(input
+ y
* stride_in
);
427 char *out_row
= output
+ y
* stride_out
;
429 for (x
= 0; x
< out_hdr
->biWidth
; x
++)
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
)];
439 FIXME("Conversion from %d to %d bit unimplemented\n", depth_in
, out_hdr
->biBitCount
);
442 static LRESULT
CRAM_Decompress( Msvideo1Context
*info
, ICDECOMPRESS
*icd
, DWORD size
)
444 LONG width
, height
, stride
, sz
;
447 TRACE("ICM_DECOMPRESS %p %p %d\n", info
, icd
, size
);
449 if( (info
==NULL
) || (info
->dwMagic
!=CRAM_MAGIC
) )
450 return ICERR_BADPARAM
;
452 /* FIXME: flags are ignored */
454 width
= icd
->lpbiInput
->biWidth
;
455 height
= icd
->lpbiInput
->biHeight
;
456 sz
= icd
->lpbiInput
->biSizeImage
;
458 output
= icd
->lpOutput
;
460 if (icd
->lpbiOutput
->biBitCount
!= info
->depth
)
462 output
= HeapAlloc(GetProcessHeap(), 0, icd
->lpbiOutput
->biWidth
* icd
->lpbiOutput
->biHeight
* info
->depth
/ 8);
463 if (!output
) return ICERR_MEMORY
;
466 if (info
->depth
== 8)
468 stride
= get_stride(width
, 8);
469 msvideo1_decode_8bit( width
, height
, icd
->lpInput
, sz
,
474 stride
= get_stride(width
, 16) / 2;
475 msvideo1_decode_16bit( width
, height
, icd
->lpInput
, sz
,
479 if (icd
->lpbiOutput
->biBitCount
!= info
->depth
)
481 convert_depth(output
, info
->depth
, icd
->lpOutput
, icd
->lpbiOutput
);
482 HeapFree(GetProcessHeap(), 0, output
);
488 static LRESULT
CRAM_DecompressEx( Msvideo1Context
*info
, ICDECOMPRESSEX
*icd
, DWORD size
)
490 LONG width
, height
, stride
, sz
;
493 TRACE("ICM_DECOMPRESSEX %p %p %d\n", info
, icd
, size
);
495 if( (info
==NULL
) || (info
->dwMagic
!=CRAM_MAGIC
) )
496 return ICERR_BADPARAM
;
498 /* FIXME: flags are ignored */
500 width
= icd
->lpbiSrc
->biWidth
;
501 height
= icd
->lpbiSrc
->biHeight
;
502 sz
= icd
->lpbiSrc
->biSizeImage
;
506 if (icd
->lpbiDst
->biBitCount
!= info
->depth
)
508 output
= HeapAlloc(GetProcessHeap(), 0, icd
->lpbiDst
->biWidth
* icd
->lpbiDst
->biHeight
* info
->depth
/ 8);
509 if (!output
) return ICERR_MEMORY
;
512 if (info
->depth
== 8)
514 stride
= get_stride(width
, 8);
515 msvideo1_decode_8bit( width
, height
, icd
->lpSrc
, sz
,
520 stride
= get_stride(width
, 16) / 2;
521 msvideo1_decode_16bit( width
, height
, icd
->lpSrc
, sz
,
525 if (icd
->lpbiDst
->biBitCount
!= info
->depth
)
527 convert_depth(output
, info
->depth
, icd
->lpDst
, icd
->lpbiDst
);
528 HeapFree(GetProcessHeap(), 0, output
);
534 static LRESULT
CRAM_GetInfo( const Msvideo1Context
*info
, ICINFO
*icinfo
, DWORD dwSize
)
536 if (!icinfo
) return sizeof(ICINFO
);
537 if (dwSize
< sizeof(ICINFO
)) return 0;
539 icinfo
->dwSize
= sizeof(ICINFO
);
540 icinfo
->fccType
= ICTYPE_VIDEO
;
541 icinfo
->fccHandler
= info
? info
->dwMagic
: CRAM_MAGIC
;
543 icinfo
->dwVersion
= ICVERSION
;
544 icinfo
->dwVersionICM
= ICVERSION
;
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 */
550 return sizeof(ICINFO
);
553 /***********************************************************************
554 * DriverProc (MSVIDC32.@)
556 LRESULT WINAPI
CRAM_DriverProc( DWORD_PTR dwDriverId
, HDRVR hdrvr
, UINT msg
,
557 LPARAM lParam1
, LPARAM lParam2
)
559 Msvideo1Context
*info
= (Msvideo1Context
*) dwDriverId
;
560 LRESULT r
= ICERR_UNSUPPORTED
;
562 TRACE("%ld %p %04x %08lx %08lx\n", dwDriverId
, hdrvr
, msg
, lParam1
, lParam2
);
576 ICINFO
*icinfo
= (ICINFO
*)lParam2
;
580 if (icinfo
&& compare_fourcc(icinfo
->fccType
, ICTYPE_VIDEO
)) return 0;
582 info
= HeapAlloc( GetProcessHeap(), 0, sizeof (Msvideo1Context
) );
585 memset( info
, 0, sizeof *info
);
586 info
->dwMagic
= CRAM_MAGIC
;
593 HeapFree( GetProcessHeap(), 0, info
);
603 r
= CRAM_GetInfo( info
, (ICINFO
*)lParam1
, (DWORD
)lParam2
);
606 case ICM_DECOMPRESS_QUERY
:
607 r
= CRAM_DecompressQuery( info
, (LPBITMAPINFO
) lParam1
,
608 (LPBITMAPINFO
) lParam2
);
611 case ICM_DECOMPRESS_GET_FORMAT
:
612 r
= CRAM_DecompressGetFormat( info
, (LPBITMAPINFO
) lParam1
,
613 (LPBITMAPINFO
) lParam2
);
616 case ICM_DECOMPRESS_GET_PALETTE
:
617 FIXME("ICM_DECOMPRESS_GET_PALETTE\n");
620 case ICM_DECOMPRESSEX_QUERY
:
621 FIXME("ICM_DECOMPRESSEX_QUERY\n");
625 r
= CRAM_Decompress( info
, (ICDECOMPRESS
*) lParam1
,
629 case ICM_DECOMPRESS_BEGIN
:
630 r
= CRAM_DecompressBegin( info
, (LPBITMAPINFO
) lParam1
,
631 (LPBITMAPINFO
) lParam2
);
634 case ICM_DECOMPRESSEX
:
635 r
= CRAM_DecompressEx( info
, (ICDECOMPRESSEX
*) lParam1
,
639 case ICM_DECOMPRESS_END
:
643 case ICM_COMPRESS_QUERY
:
646 case ICM_COMPRESS_GET_FORMAT
:
647 case ICM_COMPRESS_END
:
649 FIXME("compression not implemented\n");
656 FIXME("Unknown message: %04x %ld %ld\n", msg
, lParam1
, lParam2
);
662 /***********************************************************************
665 BOOL WINAPI
DllMain(HINSTANCE hModule
, DWORD dwReason
, LPVOID lpReserved
)
667 TRACE("(%p,%d,%p)\n", hModule
, dwReason
, lpReserved
);
671 case DLL_PROCESS_ATTACH
:
672 DisableThreadLibraryCalls(hModule
);
673 MSVIDC32_hModule
= hModule
;