|  | /* | 
|  | * Radius Cinepak Video Decoder | 
|  | * | 
|  | * Copyright 2001 Dr. Tim Ferguson (see below) | 
|  | * Portions Copyright 2003 Mike McCormack for CodeWeavers | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | /* Copyright notice from original source: | 
|  | * ------------------------------------------------------------------------ | 
|  | * Radius Cinepak Video Decoder | 
|  | * | 
|  | * Dr. Tim Ferguson, 2001. | 
|  | * For more details on the algorithm: | 
|  | *         http://www.csse.monash.edu.au/~timf/videocodec.html | 
|  | * | 
|  | * This is basically a vector quantiser with adaptive vector density.  The | 
|  | * frame is segmented into 4x4 pixel blocks, and each block is coded using | 
|  | * either 1 or 4 vectors. | 
|  | * | 
|  | * There are still some issues with this code yet to be resolved.  In | 
|  | * particular with decoding in the strip boundaries.  However, I have not | 
|  | * yet found a sequence it doesn't work on.  Ill keep trying :) | 
|  | * | 
|  | * You may freely use this source code.  I only ask that you reference its | 
|  | * source in your projects documentation: | 
|  | *       Tim Ferguson: http://www.csse.monash.edu.au/~timf/ | 
|  | * ------------------------------------------------------------------------ */ | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "commdlg.h" | 
|  | #include "vfw.h" | 
|  | #include "mmsystem.h" | 
|  | #include "iccvid_private.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(iccvid); | 
|  |  | 
|  | static HINSTANCE ICCVID_hModule; | 
|  |  | 
|  | #define ICCVID_MAGIC mmioFOURCC('c', 'v', 'i', 'd') | 
|  | #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) | 
|  |  | 
|  | #define DBUG    0 | 
|  | #define MAX_STRIPS 32 | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | typedef struct | 
|  | { | 
|  | unsigned char y0, y1, y2, y3; | 
|  | char u, v; | 
|  | unsigned char r[4], g[4], b[4]; | 
|  | } cvid_codebook; | 
|  |  | 
|  | typedef struct { | 
|  | cvid_codebook *v4_codebook[MAX_STRIPS]; | 
|  | cvid_codebook *v1_codebook[MAX_STRIPS]; | 
|  | unsigned int strip_num; | 
|  | } cinepak_info; | 
|  |  | 
|  | typedef struct _ICCVID_Info | 
|  | { | 
|  | DWORD         dwMagic; | 
|  | int           bits_per_pixel; | 
|  | cinepak_info *cvinfo; | 
|  | } ICCVID_Info; | 
|  |  | 
|  | static inline LPVOID heap_alloc( size_t size ) | 
|  | { | 
|  | return HeapAlloc( GetProcessHeap(), 0, size ); | 
|  | } | 
|  |  | 
|  | static inline BOOL heap_free( LPVOID ptr ) | 
|  | { | 
|  | return HeapFree( GetProcessHeap(), 0, ptr ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | static unsigned char *in_buffer, uiclip[1024], *uiclp = NULL; | 
|  |  | 
|  | #define get_byte() *(in_buffer++) | 
|  | #define skip_byte() in_buffer++ | 
|  | #define get_word() ((unsigned short)(in_buffer += 2, \ | 
|  | (in_buffer[-2] << 8 | in_buffer[-1]))) | 
|  | #define get_long() ((unsigned long)(in_buffer += 4, \ | 
|  | (in_buffer[-4] << 24 | in_buffer[-3] << 16 | in_buffer[-2] << 8 | in_buffer[-1]))) | 
|  |  | 
|  |  | 
|  | /* ---------------------------------------------------------------------- */ | 
|  | static inline void read_codebook(cvid_codebook *c, int mode) | 
|  | { | 
|  | int uvr, uvg, uvb; | 
|  |  | 
|  | if(mode)        /* black and white */ | 
|  | { | 
|  | c->y0 = get_byte(); | 
|  | c->y1 = get_byte(); | 
|  | c->y2 = get_byte(); | 
|  | c->y3 = get_byte(); | 
|  | c->u = c->v = 0; | 
|  |  | 
|  | c->r[0] = c->g[0] = c->b[0] = c->y0; | 
|  | c->r[1] = c->g[1] = c->b[1] = c->y1; | 
|  | c->r[2] = c->g[2] = c->b[2] = c->y2; | 
|  | c->r[3] = c->g[3] = c->b[3] = c->y3; | 
|  | } | 
|  | else            /* colour */ | 
|  | { | 
|  | c->y0 = get_byte();  /* luma */ | 
|  | c->y1 = get_byte(); | 
|  | c->y2 = get_byte(); | 
|  | c->y3 = get_byte(); | 
|  | c->u = get_byte(); /* chroma */ | 
|  | c->v = get_byte(); | 
|  |  | 
|  | uvr = c->v << 1; | 
|  | uvg = -((c->u+1) >> 1) - c->v; | 
|  | uvb = c->u << 1; | 
|  |  | 
|  | c->r[0] = uiclp[c->y0 + uvr]; c->g[0] = uiclp[c->y0 + uvg]; c->b[0] = uiclp[c->y0 + uvb]; | 
|  | c->r[1] = uiclp[c->y1 + uvr]; c->g[1] = uiclp[c->y1 + uvg]; c->b[1] = uiclp[c->y1 + uvb]; | 
|  | c->r[2] = uiclp[c->y2 + uvr]; c->g[2] = uiclp[c->y2 + uvg]; c->b[2] = uiclp[c->y2 + uvb]; | 
|  | c->r[3] = uiclp[c->y3 + uvr]; c->g[3] = uiclp[c->y3 + uvg]; c->b[3] = uiclp[c->y3 + uvb]; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | #define MAKECOLOUR32(r,g,b) (((r) << 16) | ((g) << 8) | (b)) | 
|  | /*#define MAKECOLOUR24(r,g,b) (((r) << 16) | ((g) << 8) | (b))*/ | 
|  | #define MAKECOLOUR16(r,g,b) (((r) >> 3) << 11)| (((g) >> 2) << 5)| (((b) >> 3) << 0) | 
|  | #define MAKECOLOUR15(r,g,b) (((r) >> 3) << 10)| (((g) >> 3) << 5)| (((b) >> 3) << 0) | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | static void cvid_v1_32(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb) | 
|  | { | 
|  | unsigned long *vptr = (unsigned long *)frm; | 
|  | #ifndef ORIGINAL | 
|  | int row_inc = -stride/4; | 
|  | #else | 
|  | int row_inc = stride/4; | 
|  | #endif | 
|  | int x, y; | 
|  |  | 
|  | /* fill 4x4 block of pixels with colour values from codebook */ | 
|  | for (y = 0; y < 4; y++) | 
|  | { | 
|  | if (&vptr[y*row_inc] < (unsigned long *)limit) return; | 
|  | for (x = 0; x < 4; x++) | 
|  | vptr[y*row_inc + x] = MAKECOLOUR32(cb->r[x/2+(y/2)*2], cb->g[x/2+(y/2)*2], cb->b[x/2+(y/2)*2]); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | static void cvid_v4_32(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0, | 
|  | cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3) | 
|  | { | 
|  | unsigned long *vptr = (unsigned long *)frm; | 
|  | #ifndef ORIGINAL | 
|  | int row_inc = -stride/4; | 
|  | #else | 
|  | int row_inc = stride/4; | 
|  | #endif | 
|  | int x, y; | 
|  | cvid_codebook * cb[] = {cb0,cb1,cb2,cb3}; | 
|  |  | 
|  | /* fill 4x4 block of pixels with colour values from codebooks */ | 
|  | for (y = 0; y < 4; y++) | 
|  | { | 
|  | if (&vptr[y*row_inc] < (unsigned long *)limit) return; | 
|  | for (x = 0; x < 4; x++) | 
|  | vptr[y*row_inc + x] = MAKECOLOUR32(cb[x/2+(y/2)*2]->r[x%2+(y%2)*2], cb[x/2+(y/2)*2]->g[x%2+(y%2)*2], cb[x/2+(y/2)*2]->b[x%2+(y%2)*2]); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | static void cvid_v1_24(unsigned char *vptr, unsigned char *limit, int stride, cvid_codebook *cb) | 
|  | { | 
|  | #ifndef ORIGINAL | 
|  | int row_inc = -stride; | 
|  | #else | 
|  | int row_inc = stride; | 
|  | #endif | 
|  | int x, y; | 
|  |  | 
|  | /* fill 4x4 block of pixels with colour values from codebook */ | 
|  | for (y = 0; y < 4; y++) | 
|  | { | 
|  | if (&vptr[y*row_inc] < limit) return; | 
|  | for (x = 0; x < 4; x++) | 
|  | { | 
|  | vptr[y*row_inc + x*3 + 0] = cb->b[x/2+(y/2)*2]; | 
|  | vptr[y*row_inc + x*3 + 1] = cb->g[x/2+(y/2)*2]; | 
|  | vptr[y*row_inc + x*3 + 2] = cb->r[x/2+(y/2)*2]; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | static void cvid_v4_24(unsigned char *vptr, unsigned char *limit, int stride, cvid_codebook *cb0, | 
|  | cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3) | 
|  | { | 
|  | #ifndef ORIGINAL | 
|  | int row_inc = -stride; | 
|  | #else | 
|  | int row_inc = stride; | 
|  | #endif | 
|  | cvid_codebook * cb[] = {cb0,cb1,cb2,cb3}; | 
|  | int x, y; | 
|  |  | 
|  | /* fill 4x4 block of pixels with colour values from codebooks */ | 
|  | for (y = 0; y < 4; y++) | 
|  | { | 
|  | if (&vptr[y*row_inc] < limit) return; | 
|  | for (x = 0; x < 4; x++) | 
|  | { | 
|  | vptr[y*row_inc + x*3 + 0] = cb[x/2+(y/2)*2]->b[x%2+(y%2)*2]; | 
|  | vptr[y*row_inc + x*3 + 1] = cb[x/2+(y/2)*2]->g[x%2+(y%2)*2]; | 
|  | vptr[y*row_inc + x*3 + 2] = cb[x/2+(y/2)*2]->r[x%2+(y%2)*2]; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | static void cvid_v1_16(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb) | 
|  | { | 
|  | unsigned short *vptr = (unsigned short *)frm; | 
|  | #ifndef ORIGINAL | 
|  | int row_inc = -stride/2; | 
|  | #else | 
|  | int row_inc = stride/2; | 
|  | #endif | 
|  | int x, y; | 
|  |  | 
|  | /* fill 4x4 block of pixels with colour values from codebook */ | 
|  | for (y = 0; y < 4; y++) | 
|  | { | 
|  | if (&vptr[y*row_inc] < (unsigned short *)limit) return; | 
|  | for (x = 0; x < 4; x++) | 
|  | vptr[y*row_inc + x] = MAKECOLOUR16(cb->r[x/2+(y/2)*2], cb->g[x/2+(y/2)*2], cb->b[x/2+(y/2)*2]); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | static void cvid_v4_16(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0, | 
|  | cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3) | 
|  | { | 
|  | unsigned short *vptr = (unsigned short *)frm; | 
|  | #ifndef ORIGINAL | 
|  | int row_inc = -stride/2; | 
|  | #else | 
|  | int row_inc = stride/2; | 
|  | #endif | 
|  | cvid_codebook * cb[] = {cb0,cb1,cb2,cb3}; | 
|  | int x, y; | 
|  |  | 
|  | /* fill 4x4 block of pixels with colour values from codebooks */ | 
|  | for (y = 0; y < 4; y++) | 
|  | { | 
|  | if (&vptr[y*row_inc] < (unsigned short *)limit) return; | 
|  | for (x = 0; x < 4; x++) | 
|  | vptr[y*row_inc + x] = MAKECOLOUR16(cb[x/2+(y/2)*2]->r[x%2+(y%2)*2], cb[x/2+(y/2)*2]->g[x%2+(y%2)*2], cb[x/2+(y/2)*2]->b[x%2+(y%2)*2]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | static void cvid_v1_15(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb) | 
|  | { | 
|  | unsigned short *vptr = (unsigned short *)frm; | 
|  | #ifndef ORIGINAL | 
|  | int row_inc = -stride/2; | 
|  | #else | 
|  | int row_inc = stride/2; | 
|  | #endif | 
|  | int x, y; | 
|  |  | 
|  | /* fill 4x4 block of pixels with colour values from codebook */ | 
|  | for (y = 0; y < 4; y++) | 
|  | { | 
|  | if (&vptr[y*row_inc] < (unsigned short *)limit) return; | 
|  | for (x = 0; x < 4; x++) | 
|  | vptr[y*row_inc + x] = MAKECOLOUR15(cb->r[x/2+(y/2)*2], cb->g[x/2+(y/2)*2], cb->b[x/2+(y/2)*2]); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------------------ */ | 
|  | static void cvid_v4_15(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0, | 
|  | cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3) | 
|  | { | 
|  | unsigned short *vptr = (unsigned short *)frm; | 
|  | #ifndef ORIGINAL | 
|  | int row_inc = -stride/2; | 
|  | #else | 
|  | int row_inc = stride/2; | 
|  | #endif | 
|  | cvid_codebook * cb[] = {cb0,cb1,cb2,cb3}; | 
|  | int x, y; | 
|  |  | 
|  | /* fill 4x4 block of pixels with colour values from codebooks */ | 
|  | for (y = 0; y < 4; y++) | 
|  | { | 
|  | if (&vptr[y*row_inc] < (unsigned short *)limit) return; | 
|  | for (x = 0; x < 4; x++) | 
|  | vptr[y*row_inc + x] = MAKECOLOUR15(cb[x/2+(y/2)*2]->r[x%2+(y%2)*2], cb[x/2+(y/2)*2]->g[x%2+(y%2)*2], cb[x/2+(y/2)*2]->b[x%2+(y%2)*2]); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ------------------------------------------------------------------------ | 
|  | * Call this function once at the start of the sequence and save the | 
|  | * returned context for calls to decode_cinepak(). | 
|  | */ | 
|  | static cinepak_info *decode_cinepak_init(void) | 
|  | { | 
|  | cinepak_info *cvinfo; | 
|  | int i; | 
|  |  | 
|  | cvinfo = heap_alloc( sizeof (cinepak_info) ); | 
|  | if( !cvinfo ) | 
|  | return NULL; | 
|  | cvinfo->strip_num = 0; | 
|  |  | 
|  | if(uiclp == NULL) | 
|  | { | 
|  | uiclp = uiclip+512; | 
|  | for(i = -512; i < 512; i++) | 
|  | uiclp[i] = (i < 0 ? 0 : (i > 255 ? 255 : i)); | 
|  | } | 
|  |  | 
|  | return cvinfo; | 
|  | } | 
|  |  | 
|  | static void free_cvinfo( cinepak_info *cvinfo ) | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | for( i=0; i<cvinfo->strip_num; i++ ) | 
|  | { | 
|  | heap_free(cvinfo->v4_codebook[i]); | 
|  | heap_free(cvinfo->v1_codebook[i]); | 
|  | } | 
|  | heap_free( cvinfo ); | 
|  | } | 
|  |  | 
|  | typedef void (*fn_cvid_v1)(unsigned char *frm, unsigned char *limit, | 
|  | int stride, cvid_codebook *cb); | 
|  | typedef void (*fn_cvid_v4)(unsigned char *frm, unsigned char *limit, int stride, | 
|  | cvid_codebook *cb0, cvid_codebook *cb1, | 
|  | cvid_codebook *cb2, cvid_codebook *cb3); | 
|  |  | 
|  | /* ------------------------------------------------------------------------ | 
|  | * This function decodes a buffer containing a Cinepak encoded frame. | 
|  | * | 
|  | * context - the context created by decode_cinepak_init(). | 
|  | * buf - the input buffer to be decoded | 
|  | * size - the size of the input buffer | 
|  | * frame - the output frame buffer (24 or 32 bit per pixel) | 
|  | * width - the width of the output frame | 
|  | * height - the height of the output frame | 
|  | * bit_per_pixel - the number of bits per pixel allocated to the output | 
|  | *   frame (only 24 or 32 bpp are supported) | 
|  | */ | 
|  | static void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size, | 
|  | unsigned char *frame, unsigned int width, unsigned int height, int bit_per_pixel) | 
|  | { | 
|  | cvid_codebook *v4_codebook, *v1_codebook, *codebook = NULL; | 
|  | unsigned long x, y, y_bottom, frame_flags, strips, cv_width, cv_height, | 
|  | cnum, strip_id, chunk_id, x0, y0, x1, y1, ci, flag, mask; | 
|  | long len, top_size, chunk_size; | 
|  | unsigned char *frm_ptr; | 
|  | unsigned int i, cur_strip; | 
|  | int d0, d1, d2, d3, frm_stride, bpp = 3; | 
|  | fn_cvid_v1 cvid_v1 = cvid_v1_24; | 
|  | fn_cvid_v4 cvid_v4 = cvid_v4_24; | 
|  |  | 
|  | y = 0; | 
|  | y_bottom = 0; | 
|  | in_buffer = buf; | 
|  |  | 
|  | frame_flags = get_byte(); | 
|  | len = get_byte() << 16; | 
|  | len |= get_byte() << 8; | 
|  | len |= get_byte(); | 
|  |  | 
|  | switch(bit_per_pixel) | 
|  | { | 
|  | case 15: | 
|  | bpp = 2; | 
|  | cvid_v1 = cvid_v1_15; | 
|  | cvid_v4 = cvid_v4_15; | 
|  | break; | 
|  | case 16: | 
|  | bpp = 2; | 
|  | cvid_v1 = cvid_v1_16; | 
|  | cvid_v4 = cvid_v4_16; | 
|  | break; | 
|  | case 24: | 
|  | bpp = 3; | 
|  | cvid_v1 = cvid_v1_24; | 
|  | cvid_v4 = cvid_v4_24; | 
|  | break; | 
|  | case 32: | 
|  | bpp = 4; | 
|  | cvid_v1 = cvid_v1_32; | 
|  | cvid_v4 = cvid_v4_32; | 
|  | break; | 
|  | } | 
|  |  | 
|  | frm_stride = width * bpp; | 
|  | frm_ptr = frame; | 
|  |  | 
|  | if(len != size) | 
|  | { | 
|  | if(len & 0x01) len++; /* AVIs tend to have a size mismatch */ | 
|  | if(len != size) | 
|  | { | 
|  | ERR("CVID: corruption %d (QT/AVI) != %ld (CV)\n", size, len); | 
|  | /* return; */ | 
|  | } | 
|  | } | 
|  |  | 
|  | cv_width = get_word(); | 
|  | cv_height = get_word(); | 
|  | strips = get_word(); | 
|  |  | 
|  | if(strips > cvinfo->strip_num) | 
|  | { | 
|  | if(strips >= MAX_STRIPS) | 
|  | { | 
|  | ERR("CVID: strip overflow (more than %d)\n", MAX_STRIPS); | 
|  | return; | 
|  | } | 
|  |  | 
|  | for(i = cvinfo->strip_num; i < strips; i++) | 
|  | { | 
|  | if((cvinfo->v4_codebook[i] = heap_alloc(sizeof(cvid_codebook) * 260)) == NULL) | 
|  | { | 
|  | ERR("CVID: codebook v4 alloc err\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if((cvinfo->v1_codebook[i] = heap_alloc(sizeof(cvid_codebook) * 260)) == NULL) | 
|  | { | 
|  | ERR("CVID: codebook v1 alloc err\n"); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | cvinfo->strip_num = strips; | 
|  |  | 
|  | TRACE("CVID: <%ld,%ld> strips %ld\n", cv_width, cv_height, strips); | 
|  |  | 
|  | for(cur_strip = 0; cur_strip < strips; cur_strip++) | 
|  | { | 
|  | v4_codebook = cvinfo->v4_codebook[cur_strip]; | 
|  | v1_codebook = cvinfo->v1_codebook[cur_strip]; | 
|  |  | 
|  | if((cur_strip > 0) && (!(frame_flags & 0x01))) | 
|  | { | 
|  | memcpy(cvinfo->v4_codebook[cur_strip], cvinfo->v4_codebook[cur_strip-1], 260 * sizeof(cvid_codebook)); | 
|  | memcpy(cvinfo->v1_codebook[cur_strip], cvinfo->v1_codebook[cur_strip-1], 260 * sizeof(cvid_codebook)); | 
|  | } | 
|  |  | 
|  | strip_id = get_word();        /* 1000 = key strip, 1100 = iter strip */ | 
|  | top_size = get_word(); | 
|  | y0 = get_word();        /* FIXME: most of these are ignored at the moment */ | 
|  | x0 = get_word(); | 
|  | y1 = get_word(); | 
|  | x1 = get_word(); | 
|  |  | 
|  | y_bottom += y1; | 
|  | top_size -= 12; | 
|  | x = 0; | 
|  | if(x1 != width) | 
|  | WARN("CVID: Warning x1 (%ld) != width (%d)\n", x1, width); | 
|  |  | 
|  | TRACE("   %d) %04lx %04ld <%ld,%ld> <%ld,%ld> yt %ld\n", | 
|  | cur_strip, strip_id, top_size, x0, y0, x1, y1, y_bottom); | 
|  |  | 
|  | while(top_size > 0) | 
|  | { | 
|  | chunk_id  = get_word(); | 
|  | chunk_size = get_word(); | 
|  |  | 
|  | TRACE("        %04lx %04ld\n", chunk_id, chunk_size); | 
|  | top_size -= chunk_size; | 
|  | chunk_size -= 4; | 
|  |  | 
|  | switch(chunk_id) | 
|  | { | 
|  | /* -------------------- Codebook Entries -------------------- */ | 
|  | case 0x2000: | 
|  | case 0x2200: | 
|  | codebook = (chunk_id == 0x2200 ? v1_codebook : v4_codebook); | 
|  | cnum = chunk_size/6; | 
|  | for(i = 0; i < cnum; i++) read_codebook(codebook+i, 0); | 
|  | break; | 
|  |  | 
|  | case 0x2400: | 
|  | case 0x2600:        /* 8 bit per pixel */ | 
|  | codebook = (chunk_id == 0x2600 ? v1_codebook : v4_codebook); | 
|  | cnum = chunk_size/4; | 
|  | for(i = 0; i < cnum; i++) read_codebook(codebook+i, 1); | 
|  | break; | 
|  |  | 
|  | case 0x2100: | 
|  | case 0x2300: | 
|  | codebook = (chunk_id == 0x2300 ? v1_codebook : v4_codebook); | 
|  |  | 
|  | ci = 0; | 
|  | while(chunk_size > 0) | 
|  | { | 
|  | flag = get_long(); | 
|  | chunk_size -= 4; | 
|  |  | 
|  | for(i = 0; i < 32; i++) | 
|  | { | 
|  | if(flag & 0x80000000) | 
|  | { | 
|  | chunk_size -= 6; | 
|  | read_codebook(codebook+ci, 0); | 
|  | } | 
|  |  | 
|  | ci++; | 
|  | flag <<= 1; | 
|  | } | 
|  | } | 
|  | while(chunk_size > 0) { skip_byte(); chunk_size--; } | 
|  | break; | 
|  |  | 
|  | case 0x2500: | 
|  | case 0x2700:        /* 8 bit per pixel */ | 
|  | codebook = (chunk_id == 0x2700 ? v1_codebook : v4_codebook); | 
|  |  | 
|  | ci = 0; | 
|  | while(chunk_size > 0) | 
|  | { | 
|  | flag = get_long(); | 
|  | chunk_size -= 4; | 
|  |  | 
|  | for(i = 0; i < 32; i++) | 
|  | { | 
|  | if(flag & 0x80000000) | 
|  | { | 
|  | chunk_size -= 4; | 
|  | read_codebook(codebook+ci, 1); | 
|  | } | 
|  |  | 
|  | ci++; | 
|  | flag <<= 1; | 
|  | } | 
|  | } | 
|  | while(chunk_size > 0) { skip_byte(); chunk_size--; } | 
|  | break; | 
|  |  | 
|  | /* -------------------- Frame -------------------- */ | 
|  | case 0x3000: | 
|  | while((chunk_size > 0) && (y < y_bottom)) | 
|  | { | 
|  | flag = get_long(); | 
|  | chunk_size -= 4; | 
|  |  | 
|  | for(i = 0; i < 32; i++) | 
|  | { | 
|  | if(y >= y_bottom) break; | 
|  | if(flag & 0x80000000)    /* 4 bytes per block */ | 
|  | { | 
|  | d0 = get_byte(); | 
|  | d1 = get_byte(); | 
|  | d2 = get_byte(); | 
|  | d3 = get_byte(); | 
|  | chunk_size -= 4; | 
|  | #ifdef ORIGINAL | 
|  | cvid_v4(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3); | 
|  | #else | 
|  | cvid_v4(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3); | 
|  | #endif | 
|  | } | 
|  | else        /* 1 byte per block */ | 
|  | { | 
|  | #ifdef ORIGINAL | 
|  | cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte()); | 
|  | #else | 
|  | cvid_v1(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v1_codebook + get_byte()); | 
|  | #endif | 
|  | chunk_size--; | 
|  | } | 
|  |  | 
|  | x += 4; | 
|  | if(x >= width) | 
|  | { | 
|  | x = 0; | 
|  | y += 4; | 
|  | } | 
|  | flag <<= 1; | 
|  | } | 
|  | } | 
|  | while(chunk_size > 0) { skip_byte(); chunk_size--; } | 
|  | break; | 
|  |  | 
|  | case 0x3100: | 
|  | while((chunk_size > 0) && (y < y_bottom)) | 
|  | { | 
|  | /* ---- flag bits: 0 = SKIP, 10 = V1, 11 = V4 ---- */ | 
|  | flag = get_long(); | 
|  | chunk_size -= 4; | 
|  | mask = 0x80000000; | 
|  |  | 
|  | while((mask) && (y < y_bottom)) | 
|  | { | 
|  | if(flag & mask) | 
|  | { | 
|  | if(mask == 1) | 
|  | { | 
|  | if(chunk_size < 0) break; | 
|  | flag = get_long(); | 
|  | chunk_size -= 4; | 
|  | mask = 0x80000000; | 
|  | } | 
|  | else mask >>= 1; | 
|  |  | 
|  | if(flag & mask)        /* V4 */ | 
|  | { | 
|  | d0 = get_byte(); | 
|  | d1 = get_byte(); | 
|  | d2 = get_byte(); | 
|  | d3 = get_byte(); | 
|  | chunk_size -= 4; | 
|  | #ifdef ORIGINAL | 
|  | cvid_v4(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3); | 
|  | #else | 
|  | cvid_v4(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3); | 
|  | #endif | 
|  | } | 
|  | else        /* V1 */ | 
|  | { | 
|  | chunk_size--; | 
|  | #ifdef ORIGINAL | 
|  | cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte()); | 
|  | #else | 
|  | cvid_v1(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v1_codebook + get_byte()); | 
|  | #endif | 
|  | } | 
|  | }        /* else SKIP */ | 
|  |  | 
|  | mask >>= 1; | 
|  | x += 4; | 
|  | if(x >= width) | 
|  | { | 
|  | x = 0; | 
|  | y += 4; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | while(chunk_size > 0) { skip_byte(); chunk_size--; } | 
|  | break; | 
|  |  | 
|  | case 0x3200:        /* each byte is a V1 codebook */ | 
|  | while((chunk_size > 0) && (y < y_bottom)) | 
|  | { | 
|  | #ifdef ORIGINAL | 
|  | cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte()); | 
|  | #else | 
|  | cvid_v1(frm_ptr + ((height - 1 - y) * frm_stride + x * bpp), frame, frm_stride, v1_codebook + get_byte()); | 
|  | #endif | 
|  | chunk_size--; | 
|  | x += 4; | 
|  | if(x >= width) | 
|  | { | 
|  | x = 0; | 
|  | y += 4; | 
|  | } | 
|  | } | 
|  | while(chunk_size > 0) { skip_byte(); chunk_size--; } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | ERR("CVID: unknown chunk_id %08lx\n", chunk_id); | 
|  | while(chunk_size > 0) { skip_byte(); chunk_size--; } | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if(len != size) | 
|  | { | 
|  | if(len & 0x01) len++; /* AVIs tend to have a size mismatch */ | 
|  | if(len != size) | 
|  | { | 
|  | long xlen; | 
|  | skip_byte(); | 
|  | xlen = get_byte() << 16; | 
|  | xlen |= get_byte() << 8; | 
|  | xlen |= get_byte(); /* Read Len */ | 
|  | WARN("CVID: END INFO chunk size %d cvid size1 %ld cvid size2 %ld\n", | 
|  | size, len, xlen); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void ICCVID_dump_BITMAPINFO(const BITMAPINFO * bmi) | 
|  | { | 
|  | TRACE( | 
|  | "planes = %d\n" | 
|  | "bpp    = %d\n" | 
|  | "height = %d\n" | 
|  | "width  = %d\n" | 
|  | "compr  = %s\n", | 
|  | bmi->bmiHeader.biPlanes, | 
|  | bmi->bmiHeader.biBitCount, | 
|  | bmi->bmiHeader.biHeight, | 
|  | bmi->bmiHeader.biWidth, | 
|  | debugstr_an( (const char *)&bmi->bmiHeader.biCompression, 4 ) ); | 
|  | } | 
|  |  | 
|  | static inline int ICCVID_CheckMask(RGBQUAD bmiColors[3], COLORREF redMask, COLORREF blueMask, COLORREF greenMask) | 
|  | { | 
|  | COLORREF realRedMask = MAKECOLOUR32(bmiColors[0].rgbRed, bmiColors[0].rgbGreen, bmiColors[0].rgbBlue); | 
|  | COLORREF realBlueMask = MAKECOLOUR32(bmiColors[1].rgbRed, bmiColors[1].rgbGreen, bmiColors[1].rgbBlue); | 
|  | COLORREF realGreenMask = MAKECOLOUR32(bmiColors[2].rgbRed, bmiColors[2].rgbGreen, bmiColors[2].rgbBlue); | 
|  |  | 
|  | TRACE("\nbmiColors[0] = 0x%08x\nbmiColors[1] = 0x%08x\nbmiColors[2] = 0x%08x\n", | 
|  | realRedMask, realBlueMask, realGreenMask); | 
|  |  | 
|  | if ((realRedMask == redMask) && | 
|  | (realBlueMask == blueMask) && | 
|  | (realGreenMask == greenMask)) | 
|  | return TRUE; | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | static LRESULT ICCVID_DecompressQuery( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out ) | 
|  | { | 
|  | TRACE("ICM_DECOMPRESS_QUERY %p %p %p\n", info, in, out); | 
|  |  | 
|  | if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) ) | 
|  | return ICERR_BADPARAM; | 
|  |  | 
|  | TRACE("in: "); | 
|  | ICCVID_dump_BITMAPINFO(in); | 
|  |  | 
|  | if( in->bmiHeader.biCompression != ICCVID_MAGIC ) | 
|  | return ICERR_BADFORMAT; | 
|  |  | 
|  | if( out ) | 
|  | { | 
|  | TRACE("out: "); | 
|  | ICCVID_dump_BITMAPINFO(out); | 
|  |  | 
|  | if( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes ) | 
|  | return ICERR_BADFORMAT; | 
|  | if( in->bmiHeader.biHeight != out->bmiHeader.biHeight ) | 
|  | return ICERR_BADFORMAT; | 
|  | if( in->bmiHeader.biWidth != out->bmiHeader.biWidth ) | 
|  | return ICERR_BADFORMAT; | 
|  |  | 
|  | switch( out->bmiHeader.biBitCount ) | 
|  | { | 
|  | case 16: | 
|  | if ( out->bmiHeader.biCompression == BI_BITFIELDS ) | 
|  | { | 
|  | if ( !ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) && | 
|  | !ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) ) | 
|  | { | 
|  | TRACE("unsupported output bit field(s) for 16-bit colors\n"); | 
|  | return ICERR_BADFORMAT; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case 24: | 
|  | case 32: | 
|  | break; | 
|  | default: | 
|  | TRACE("unsupported output bitcount = %d\n", out->bmiHeader.biBitCount ); | 
|  | return ICERR_BADFORMAT; | 
|  | } | 
|  | } | 
|  |  | 
|  | return ICERR_OK; | 
|  | } | 
|  |  | 
|  | static LRESULT ICCVID_DecompressGetFormat( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out ) | 
|  | { | 
|  | DWORD size; | 
|  |  | 
|  | TRACE("ICM_DECOMPRESS_GETFORMAT %p %p %p\n", info, in, out); | 
|  |  | 
|  | if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) ) | 
|  | return ICERR_BADPARAM; | 
|  |  | 
|  | size = in->bmiHeader.biSize; | 
|  | if (in->bmiHeader.biBitCount <= 8) | 
|  | size += in->bmiHeader.biClrUsed * sizeof(RGBQUAD); | 
|  |  | 
|  | if( out ) | 
|  | { | 
|  | memcpy( out, in, size ); | 
|  | out->bmiHeader.biCompression = BI_RGB; | 
|  | out->bmiHeader.biSizeImage = in->bmiHeader.biHeight | 
|  | * in->bmiHeader.biWidth *4; | 
|  | return ICERR_OK; | 
|  | } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | static LRESULT ICCVID_DecompressBegin( ICCVID_Info *info, LPBITMAPINFO in, LPBITMAPINFO out ) | 
|  | { | 
|  | TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", info, in, out); | 
|  |  | 
|  | if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) ) | 
|  | return ICERR_BADPARAM; | 
|  |  | 
|  | info->bits_per_pixel = out->bmiHeader.biBitCount; | 
|  |  | 
|  | if (info->bits_per_pixel == 16) | 
|  | { | 
|  | if ( out->bmiHeader.biCompression == BI_BITFIELDS ) | 
|  | { | 
|  | if ( ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) ) | 
|  | info->bits_per_pixel = 15; | 
|  | else if ( ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) ) | 
|  | info->bits_per_pixel = 16; | 
|  | else | 
|  | { | 
|  | TRACE("unsupported output bit field(s) for 16-bit colors\n"); | 
|  | return ICERR_UNSUPPORTED; | 
|  | } | 
|  | } | 
|  | else | 
|  | info->bits_per_pixel = 15; | 
|  | } | 
|  |  | 
|  | TRACE("bit_per_pixel = %d\n", info->bits_per_pixel); | 
|  |  | 
|  | if( info->cvinfo ) | 
|  | free_cvinfo( info->cvinfo ); | 
|  | info->cvinfo = decode_cinepak_init(); | 
|  |  | 
|  | return ICERR_OK; | 
|  | } | 
|  |  | 
|  | static LRESULT ICCVID_Decompress( ICCVID_Info *info, ICDECOMPRESS *icd, DWORD size ) | 
|  | { | 
|  | LONG width, height; | 
|  |  | 
|  | TRACE("ICM_DECOMPRESS %p %p %d\n", info, icd, size); | 
|  |  | 
|  | if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) ) | 
|  | return ICERR_BADPARAM; | 
|  | if (info->cvinfo==NULL) | 
|  | { | 
|  | ERR("ICM_DECOMPRESS sent after ICM_DECOMPRESS_END\n"); | 
|  | return ICERR_BADPARAM; | 
|  | } | 
|  |  | 
|  | width  = icd->lpbiInput->biWidth; | 
|  | height = icd->lpbiInput->biHeight; | 
|  |  | 
|  | decode_cinepak(info->cvinfo, icd->lpInput, icd->lpbiInput->biSizeImage, | 
|  | icd->lpOutput, width, height, info->bits_per_pixel); | 
|  |  | 
|  | return ICERR_OK; | 
|  | } | 
|  |  | 
|  | static LRESULT ICCVID_DecompressEx( ICCVID_Info *info, ICDECOMPRESSEX *icd, DWORD size ) | 
|  | { | 
|  | LONG width, height; | 
|  |  | 
|  | TRACE("ICM_DECOMPRESSEX %p %p %d\n", info, icd, size); | 
|  |  | 
|  | if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) ) | 
|  | return ICERR_BADPARAM; | 
|  | if (info->cvinfo==NULL) | 
|  | { | 
|  | ERR("ICM_DECOMPRESSEX sent after ICM_DECOMPRESS_END\n"); | 
|  | return ICERR_BADPARAM; | 
|  | } | 
|  |  | 
|  | /* FIXME: flags are ignored */ | 
|  |  | 
|  | width  = icd->lpbiSrc->biWidth; | 
|  | height = icd->lpbiSrc->biHeight; | 
|  |  | 
|  | decode_cinepak(info->cvinfo, icd->lpSrc, icd->lpbiSrc->biSizeImage, | 
|  | icd->lpDst, width, height, info->bits_per_pixel); | 
|  |  | 
|  | return ICERR_OK; | 
|  | } | 
|  |  | 
|  | static LRESULT ICCVID_Close( ICCVID_Info *info ) | 
|  | { | 
|  | if( (info==NULL) || (info->dwMagic!=ICCVID_MAGIC) ) | 
|  | return 0; | 
|  | if( info->cvinfo ) | 
|  | free_cvinfo( info->cvinfo ); | 
|  | heap_free( info ); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static LRESULT ICCVID_GetInfo( ICCVID_Info *info, ICINFO *icinfo, DWORD dwSize ) | 
|  | { | 
|  | if (!icinfo) return sizeof(ICINFO); | 
|  | if (dwSize < sizeof(ICINFO)) return 0; | 
|  |  | 
|  | icinfo->dwSize = sizeof(ICINFO); | 
|  | icinfo->fccType = ICTYPE_VIDEO; | 
|  | icinfo->fccHandler = info ? info->dwMagic : ICCVID_MAGIC; | 
|  | icinfo->dwFlags = 0; | 
|  | icinfo->dwVersion = ICVERSION; | 
|  | icinfo->dwVersionICM = ICVERSION; | 
|  |  | 
|  | LoadStringW(ICCVID_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR)); | 
|  | LoadStringW(ICCVID_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR)); | 
|  | /* msvfw32 will fill icinfo->szDriver for us */ | 
|  |  | 
|  | return sizeof(ICINFO); | 
|  | } | 
|  |  | 
|  | static LRESULT ICCVID_DecompressEnd( ICCVID_Info *info ) | 
|  | { | 
|  | if( info->cvinfo ) | 
|  | { | 
|  | free_cvinfo( info->cvinfo ); | 
|  | info->cvinfo = NULL; | 
|  | } | 
|  | return ICERR_OK; | 
|  | } | 
|  |  | 
|  | LRESULT WINAPI ICCVID_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, | 
|  | LPARAM lParam1, LPARAM lParam2) | 
|  | { | 
|  | ICCVID_Info *info = (ICCVID_Info *) dwDriverId; | 
|  |  | 
|  | TRACE("%ld %p %d %ld %ld\n", dwDriverId, hdrvr, msg, lParam1, lParam2); | 
|  |  | 
|  | switch( msg ) | 
|  | { | 
|  | case DRV_LOAD: | 
|  | TRACE("Loaded\n"); | 
|  | return 1; | 
|  | case DRV_ENABLE: | 
|  | return 0; | 
|  | case DRV_DISABLE: | 
|  | return 0; | 
|  | case DRV_FREE: | 
|  | return 0; | 
|  |  | 
|  | case DRV_OPEN: | 
|  | { | 
|  | ICINFO *icinfo = (ICINFO *)lParam2; | 
|  |  | 
|  | TRACE("Opened\n"); | 
|  |  | 
|  | if (icinfo && compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return 0; | 
|  |  | 
|  | info = heap_alloc( sizeof (ICCVID_Info) ); | 
|  | if( info ) | 
|  | { | 
|  | info->dwMagic = ICCVID_MAGIC; | 
|  | info->cvinfo = NULL; | 
|  | } | 
|  | return (LRESULT) info; | 
|  | } | 
|  |  | 
|  | case DRV_CLOSE: | 
|  | return ICCVID_Close( info ); | 
|  |  | 
|  | case ICM_GETINFO: | 
|  | return ICCVID_GetInfo( info, (ICINFO *)lParam1, (DWORD)lParam2 ); | 
|  |  | 
|  | case ICM_DECOMPRESS_QUERY: | 
|  | return ICCVID_DecompressQuery( info, (LPBITMAPINFO) lParam1, | 
|  | (LPBITMAPINFO) lParam2 ); | 
|  | case ICM_DECOMPRESS_GET_FORMAT: | 
|  | return ICCVID_DecompressGetFormat( info, (LPBITMAPINFO) lParam1, | 
|  | (LPBITMAPINFO) lParam2 ); | 
|  | case ICM_DECOMPRESS_BEGIN: | 
|  | return ICCVID_DecompressBegin( info, (LPBITMAPINFO) lParam1, | 
|  | (LPBITMAPINFO) lParam2 ); | 
|  | case ICM_DECOMPRESS: | 
|  | return ICCVID_Decompress( info, (ICDECOMPRESS*) lParam1, | 
|  | (DWORD) lParam2 ); | 
|  | case ICM_DECOMPRESSEX: | 
|  | return ICCVID_DecompressEx( info, (ICDECOMPRESSEX*) lParam1, | 
|  | (DWORD) lParam2 ); | 
|  |  | 
|  | case ICM_DECOMPRESS_END: | 
|  | return ICCVID_DecompressEnd( info ); | 
|  |  | 
|  | case ICM_COMPRESS_QUERY: | 
|  | FIXME("compression not implemented\n"); | 
|  | return ICERR_BADFORMAT; | 
|  |  | 
|  | case ICM_CONFIGURE: | 
|  | return ICERR_UNSUPPORTED; | 
|  |  | 
|  | default: | 
|  | FIXME("Unknown message: %04x %ld %ld\n", msg, lParam1, lParam2); | 
|  | } | 
|  | return ICERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) | 
|  | { | 
|  | TRACE("(%p,%d,%p)\n", hModule, dwReason, lpReserved); | 
|  |  | 
|  | switch (dwReason) | 
|  | { | 
|  | case DLL_PROCESS_ATTACH: | 
|  | DisableThreadLibraryCalls(hModule); | 
|  | ICCVID_hModule = hModule; | 
|  | break; | 
|  |  | 
|  | case DLL_PROCESS_DETACH: | 
|  | break; | 
|  | } | 
|  | return TRUE; | 
|  | } |