home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0480 - 0489 / ibm0480-0489 / ibm0483.tar / ibm0483 / TTN95DDV.ZIP / W95DDK.A30 / DDK / MMEDIA / SAMPLES / ICSAMPLE / ICSAMPLE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  52.4 KB  |  1,767 lines

  1. /****************************************************************************
  2.  *
  3.  *   icsample.c
  4.  * 
  5.  *   ICSAMPLE is a sample installable compressor for Video for Windows.
  6.  ***************************************************************************/
  7. /**************************************************************************
  8.  *
  9.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  10.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  11.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  12.  *  PURPOSE.
  13.  *
  14.  *  Copyright (c) 1992 - 1995  Microsoft Corporation.  All Rights Reserved.
  15.  * 
  16.  **************************************************************************/
  17.  
  18. #include <windows.h>
  19. #include <windowsx.h>
  20. #include <mmsystem.h>
  21. #include <compddk.h>
  22.  
  23. #include <string.h> // for wcscpy()
  24. #include "icsample.h"
  25.  
  26. /*****************************************************************************
  27.  *
  28.  * Sample video compressor. This code demonstrates how to implement an
  29.  * installable compressor.
  30.  *
  31.  * The alogorithm we use is very simple:
  32.  * (1)  Keep one out of every 'n' pixels where 'n' is configurable.
  33.  *      Compression is done on a scan-line basis.
  34.  *
  35.  * (2)  For true-color images (16 or 24 bits) give the option of dropping
  36.  *      some of the lower bits.
  37.  *
  38.  ****************************************************************************/
  39.  
  40. typedef BYTE _huge  *HPBYTE ;
  41. typedef WORD _huge  *HPWORD ;
  42. typedef DWORD _huge *HPDWORD ;
  43.  
  44. #define MODNAME         "ICSAMPLE"
  45.  
  46. #ifdef _WIN32
  47. WCHAR   szDescription[] = L"Microsoft 32-bit Sample Compressor";
  48. WCHAR   szName[]        = L"MS-Samp";
  49. #else
  50. char    szDescription[] = "Microsoft Sample Compressor";
  51. char    szName[]        = "MS-Samp";
  52. #endif
  53. #define FOURCC_SAMP     mmioFOURCC('S','A','M','P')
  54. #define TWOCC_SAMP      aviTWOCC('d', 'c')
  55. #define BI_SAMP         mmioFOURCC('S','m','p','1')
  56. #define VERSION_SAMP    0x00040000      // 4.00
  57.  
  58. extern HANDLE ghModule ;
  59.  
  60. /*****************************************************************************
  61.  *
  62.  * DefaultState holds the compression handler.
  63.  *
  64.  ****************************************************************************/
  65.  
  66. ICSTATE DefaultState = {FOURCC_SAMP,2,0};
  67.  
  68. /*****************************************************************************
  69.  *
  70.  * DefaultDecompressFmt are the default options that will be used if the user
  71.  * compresses an image without configuring us at all first. In the case of
  72.  * the sample compressor, it is the pixel keep ratio.
  73.  *
  74.  ****************************************************************************/
  75. BOOL FAR PASCAL _loadds ConfigureDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LONG lParam);
  76.  
  77. /*****************************************************************************
  78.  *
  79.  * Various macros that are useful when dealing with bitmaps.
  80.  *
  81.  ****************************************************************************/
  82.  
  83. #define ALIGNULONG(i)     (((i)+3)&(0xFFFFFFFC))          /* ULONG aligned ! */
  84. #define WIDTHBYTES(i)     ((unsigned)(((i)+31)&(~31))/8)  /* ULONG aligned ! */
  85. #define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  86.  
  87. /*****************************************************************************
  88.  *
  89.  * Function for buffering bits
  90.  *
  91.  ****************************************************************************/
  92.  
  93. typedef struct tagBitBuffer
  94. {
  95.     HPWORD          lpwBuffer ;
  96.     DWORD           dwStored ;
  97.     WORD            wMask ;
  98.     WORD            wFile ;
  99. } BITBUFFER, FAR *LPBITBUFFER ;
  100.  
  101. #define MAX_MASK    (0x8000L)
  102.  
  103. void InitBitBuffer( LPBITBUFFER lpbb,void _huge *lpwBuffer )
  104. {
  105.     /*
  106.     ** Same code is valid for both input and output
  107.     */
  108.     lpbb->lpwBuffer = lpwBuffer ;
  109.     lpbb->dwStored = 0 ;
  110.     lpbb->wMask = MAX_MASK ;
  111.     lpbb->wFile = 0 ;
  112. }
  113.  
  114. void OutputBits( LPBITBUFFER lpbb, WORD wBits, WORD wCount )
  115. {
  116.     WORD    wMask ;
  117.  
  118.     wMask = 1 << (wCount-1) ;
  119.     while (wMask)
  120.     {
  121.         if (wMask&wBits)
  122.             lpbb->wFile |= lpbb->wMask ;
  123.         lpbb->wMask >>= 1 ;
  124.         if ( !lpbb->wMask )
  125.         {
  126.             *lpbb->lpwBuffer++ = lpbb->wFile ;
  127.             lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
  128.             lpbb->wFile = 0 ;
  129.             lpbb->wMask = MAX_MASK ;
  130.         }
  131.         wMask >>= 1 ;
  132.     }
  133. }
  134.  
  135. void OutputBitsFlush( LPBITBUFFER lpbb )
  136. {
  137.     if (lpbb->wMask != MAX_MASK)
  138.     {
  139.         *lpbb->lpwBuffer++ = lpbb->wFile ;
  140.         lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
  141.     }
  142. }
  143.  
  144. WORD InputBits( LPBITBUFFER lpbb, WORD wCount )
  145. {
  146.     WORD    wMask ;
  147.     WORD    wRet ;
  148.  
  149.     wMask = 1 << (wCount-1) ;
  150.     wRet = 0 ;
  151.     while (wMask)
  152.     {
  153.         if (lpbb->wMask == MAX_MASK)
  154.         {
  155.             lpbb->wFile = *lpbb->lpwBuffer++ ;
  156.             lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
  157.         }
  158.         if (lpbb->wFile&lpbb->wMask)
  159.             wRet |= wMask ;
  160.         wMask >>= 1 ;
  161.         lpbb->wMask >>= 1 ;
  162.         if (!lpbb->wMask)
  163.             lpbb->wMask = MAX_MASK ;
  164.     }
  165.  
  166.     return wRet ;
  167. }
  168.  
  169. /*****************************************************************************
  170.  *
  171.  * getDecompressFmtPtr()
  172.  *
  173.  * This routine returns a pointer to the location of the decompression
  174.  * format relative to the specified bitmapinfo header pointer.
  175.  *
  176.  ****************************************************************************/
  177. LPDECOMP_FMT getDecompressFmtPtr(
  178.     LPBITMAPINFOHEADER lpbiSrc)
  179. {
  180.     LPDECOMP_FMT  lpDecompressFmt;
  181.  
  182.     lpbiSrc++;
  183.     lpDecompressFmt = (LPDECOMP_FMT)lpbiSrc;
  184.     lpDecompressFmt->dwSize = sizeof(DECOMPRESS_INFO);
  185.     lpbiSrc--;
  186.     return lpDecompressFmt;
  187. }
  188.  
  189.  
  190.  
  191. /*****************************************************************************
  192.  *
  193.  * MyCompress8
  194.  *
  195.  * This routine handles the actual compression of the bitmap. Note:
  196.  *
  197.  * 1) The use of _huge pointers as the bitmaps are likely to exceed 64k.
  198.  *
  199.  * 2) We must set the biCompression field of the output header.
  200.  *
  201.  * 3) We must set the biSizeImage field of the output header.
  202.  *
  203.  * 4) Uncompressed bitmap scan lines are padded out to the next DWORD
  204.  *    boundry.
  205.  *
  206.  ****************************************************************************/
  207. DWORD NEAR PASCAL MyCompress8(
  208.     INSTINFO * pinst,
  209.     LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
  210.     LPBITMAPINFOHEADER lpbiOutput,HPBYTE hpOutput)
  211. {
  212.     WORD    wRealLineSize ;
  213.     WORD    wLinePad ;
  214.     WORD    wWidth = (WORD)lpbiInput->biWidth ;
  215.     WORD    wHeight = (WORD)lpbiInput->biHeight ;
  216.     WORD    x,y ;
  217.     WORD    wPixRatio = pinst->CurrentState.dInfo.wPixelKeepRatio;
  218.     LPDECOMP_FMT  lpDecompressFmt;
  219.  
  220.     DPF("Compress8()");
  221.  
  222.     //
  223.     // Initialize the pointer to the decompression format which
  224.     // is located after the BITMAPINFOHEADER.
  225.     //
  226.     lpDecompressFmt = getDecompressFmtPtr(lpbiOutput);
  227.  
  228.     //
  229.     // Set the decompression format in the output header.  Colors to 
  230.     // drop is not used in the decompression of 8 bit, so set it to 0.
  231.     //
  232.     lpDecompressFmt->dInfo.wPixelKeepRatio = wPixRatio;
  233.     lpDecompressFmt->dInfo.wColorBitsToDrop = 0;
  234.     
  235.     //
  236.     // Set the bit count, the compression, and the size of the compressed
  237.     // data.  
  238.     //
  239.     lpbiOutput->biBitCount    = 8;
  240.     lpbiOutput->biCompression = BI_SAMP;
  241.     lpbiOutput->biSizeImage   = sizeof(WORD)+((wWidth+wPixRatio-1)/wPixRatio)*(DWORD)wHeight;
  242.     lpbiOutput->biSize        = sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT);
  243.  
  244.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth) ;
  245.     wLinePad      = wRealLineSize-wWidth ;
  246.  
  247.     for (y=0; y<wHeight; y++ )
  248.     {
  249.     //
  250.     // Report status every STATUS_EVERY lines.  This is done by
  251.     // invoking the Status function that is set in response to the 
  252.     // ICM_SET_STATUS_PROC message.
  253.     //
  254.         if (pinst->Status && ((y % STATUS_EVERY) == 0)) {
  255.         if (pinst->Status(pinst->lParam,
  256.                   ICSTATUS_STATUS,
  257.                   (y * 100) / wHeight) != 0)
  258.         return (DWORD) ICERR_ABORT;
  259.     }
  260.  
  261.         for (x=0; x<wWidth; x += wPixRatio)
  262.         {
  263.             *hpOutput++ = *hpInput ;
  264.             hpInput += min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
  265.         }
  266.  
  267.         hpInput += wLinePad ;
  268.     }
  269.  
  270.     return 0;
  271. }
  272.  
  273. /*****************************************************************************
  274.  *
  275.  * 16/24 bit compression. Same thing; we just deal with a 2 or 3 bytes per pixel
  276.  * instead of a byte.
  277.  *
  278.  * Note that 8-bit pixel values are indices into a palette; 16-bit and
  279.  * about are actual color values. In particular, 16-bit values are
  280.  * stored as:
  281.  *
  282.  * +-+-----+-----+-----+
  283.  * | |  R  |  G  |  B  |
  284.  * +-+-----+-----+-----+
  285.  *  1 1   1
  286.  *  5 4   0 9   5 4   0
  287.  *
  288.  * Bit 15 is unused; each of red, green, and blue get 5 bits of color data
  289.  * (0-31).
  290.  *
  291.  * For 24 bit images, each pixel is three bytes long. The bytes hold
  292.  * the blue, green, and red values respectively (NOTE THE ORDER IS
  293.  * OPPOSITE OF RGB!)
  294.  *
  295.  ****************************************************************************/
  296. DWORD NEAR PASCAL MyCompress16(
  297.     INSTINFO * pinst,
  298.     LPBITMAPINFOHEADER lpbiInput, HPWORD hpInput,
  299.     LPBITMAPINFOHEADER lpbiOutput,HPWORD hpOutput)
  300. {
  301.     WORD        wRealLineSize ;
  302.     WORD        wLinePad ;
  303.     WORD        wWidth = (WORD)lpbiInput->biWidth ;
  304.     WORD        wHeight = (WORD)lpbiInput->biHeight ;
  305.     WORD        x,y ;
  306.     WORD        wPixRatio=pinst->CurrentState.dInfo.wPixelKeepRatio;
  307.     WORD        wDropBits=pinst->CurrentState.dInfo.wColorBitsToDrop;
  308.     WORD        wKeepBits;
  309.     WORD        r,g,b ;
  310.     LPDECOMP_FMT lpDecompressFmt;
  311.     BITBUFFER   bb ;
  312.  
  313.     DPF("Compress16()") ;
  314.     
  315.     //
  316.     // Initialize the pointer to the decompression format which
  317.     // is located after the BITMAPINFOHEADER.
  318.     //
  319.     lpDecompressFmt = getDecompressFmtPtr(lpbiOutput);
  320.  
  321.     //
  322.     // Set the decompression format in the output header.  
  323.     //
  324.     lpDecompressFmt->dInfo.wPixelKeepRatio = wPixRatio;
  325.     lpDecompressFmt->dInfo.wColorBitsToDrop = wDropBits;
  326.     wKeepBits = 5 - wDropBits;
  327.  
  328.     //
  329.     // Set the bit count, the compression, and the size of the compressed
  330.     // data.  
  331.     //
  332.     lpbiOutput->biBitCount    = 16;
  333.     lpbiOutput->biCompression = BI_SAMP;
  334.     lpbiOutput->biSizeImage   = sizeof(WORD)+2*((wWidth+wPixRatio-1)/wPixRatio)*(DWORD)wHeight;
  335.     lpbiOutput->biSize        = sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT);
  336.  
  337.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*2) ;
  338.     wLinePad      = wRealLineSize - (wWidth*2) ;
  339.  
  340.     InitBitBuffer( &bb,hpOutput ) ;
  341.     
  342.     for (y=0; y<wHeight; y++ )
  343.     {
  344.     //
  345.     // Report status every STATUS_EVERY lines.  This is done by
  346.     // invoking the Status function that is set in response to the 
  347.     // ICM_SET_STATUS_PROC message.
  348.     //
  349.     if (pinst->Status && ((y % STATUS_EVERY) == 0)) {
  350.         if (pinst->Status(pinst->lParam,
  351.                   ICSTATUS_STATUS,
  352.                   (y * 100) / wHeight) != 0)
  353.         return (DWORD) ICERR_ABORT;
  354.     }
  355.  
  356.         for (x=0; x<wWidth; x += wPixRatio)
  357.         {
  358.             r = ((*hpInput>>10)&0x1F)>>wDropBits ;
  359.             g = ((*hpInput>>5)&0x1F)>>wDropBits ;
  360.             b = (*hpInput&0x1F)>>wDropBits ;
  361.             hpInput += min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
  362.  
  363.             OutputBits( &bb, r, wKeepBits ) ;
  364.             OutputBits( &bb, g, wKeepBits ) ;
  365.             OutputBits( &bb, b, wKeepBits ) ; 
  366.         }
  367.  
  368.         hpInput += wLinePad ;
  369.     }
  370.  
  371.     OutputBitsFlush(&bb) ;
  372.  
  373.     lpbiOutput->biSizeImage = bb.dwStored ;
  374.  
  375.     return 0;
  376. }   
  377.     
  378. DWORD NEAR PASCAL MyCompress24(
  379.     INSTINFO * pinst,
  380.     LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
  381.     LPBITMAPINFOHEADER lpbiOutput,HPBYTE hpOutput)
  382. {
  383.     WORD        wRealLineSize ;
  384.     WORD        wLinePad ;
  385.     WORD        wWidth = (WORD)lpbiInput->biWidth ;
  386.     WORD        wHeight = (WORD)lpbiInput->biHeight ;
  387.     WORD        x,y ;
  388.     WORD        wPixRatio=pinst->CurrentState.dInfo.wPixelKeepRatio;
  389.     WORD        wDropBits=pinst->CurrentState.dInfo.wColorBitsToDrop;
  390.     WORD        wKeepBits;
  391.     WORD        r,g,b ;
  392.     LPDECOMP_FMT  lpDecompressFmt;
  393.     BITBUFFER   bb ;
  394.  
  395.     DPF("Compress24()") ;
  396.     
  397.     //
  398.     // Initialize the pointer to the decompression format which
  399.     // is located after the BITMAPINFOHEADER.
  400.     //
  401.     lpDecompressFmt = getDecompressFmtPtr(lpbiOutput);
  402.  
  403.     //
  404.     // Set the decompression format in the output header.  
  405.     //
  406.     lpDecompressFmt->dInfo.wPixelKeepRatio = wPixRatio;
  407.     lpDecompressFmt->dInfo.wColorBitsToDrop = wDropBits;
  408.     wKeepBits = 8 - wDropBits;
  409.  
  410.     //
  411.     // Set the bit count and the compression.
  412.     //
  413.     lpbiOutput->biBitCount    = 24 ;
  414.     lpbiOutput->biCompression = BI_SAMP;
  415.     lpbiOutput->biSize        = sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT);
  416.  
  417.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*3) ;
  418.     wLinePad      = wRealLineSize - (wWidth * 3);
  419.  
  420.     InitBitBuffer( &bb,hpOutput ) ;
  421.     
  422.     for (y=0; y<wHeight; y++ )
  423.     {
  424.     //
  425.     // Report status every STATUS_EVERY lines.  This is done by
  426.     // invoking the Status function that is set in response to the 
  427.     // ICM_SET_STATUS_PROC message.
  428.     //
  429.     if (pinst->Status && ((y % STATUS_EVERY) == 0)) {
  430.         if (pinst->Status(pinst->lParam,
  431.                   ICSTATUS_STATUS,
  432.                   (y * 100) / wHeight) != 0)
  433.         return (DWORD) ICERR_ABORT;
  434.     }
  435.  
  436.         for (x=0; x<wWidth; x += wPixRatio)
  437.         {
  438.             b = (hpInput[0])>>wDropBits ;
  439.             g = (hpInput[1])>>wDropBits ;
  440.             r = (hpInput[2])>>wDropBits ;
  441.             hpInput += 3 * min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
  442.  
  443.             OutputBits( &bb, r, wKeepBits ) ;
  444.             OutputBits( &bb, g, wKeepBits ) ;
  445.             OutputBits( &bb, b, wKeepBits ) ; 
  446.         }
  447.  
  448.         ((HPBYTE)hpInput) += wLinePad ;
  449.     }
  450.     OutputBitsFlush(&bb) ;
  451.  
  452.     lpbiOutput->biSizeImage = bb.dwStored ;
  453.  
  454.     return 0;
  455. }
  456.  
  457. /**************************************************************************
  458. compute a pointer into a DIB handling correctly "upside" down DIBs
  459. ***************************************************************************/
  460.  
  461. static LPVOID DibXY(LPBITMAPINFOHEADER lpbi, LPVOID lpBits, LONG x, LONG y, int FAR *pWidthBytes)
  462. {
  463.     int WidthBytes;
  464.  
  465.     if (x > 0)
  466.         ((BYTE FAR *)lpBits) += ((int)x * (int)lpbi->biBitCount) >> 3;
  467.  
  468.     WidthBytes = (((((int)lpbi->biWidth * (int)lpbi->biBitCount) >> 3) + 3)&~3);
  469.  
  470.     if (lpbi->biHeight < 0)
  471.     {
  472.         ((BYTE _huge *)lpBits) += (long)(lpbi->biSizeImage - WidthBytes);
  473.         WidthBytes = -WidthBytes;
  474.     }
  475.  
  476.     if (y > 0)
  477.         ((BYTE _huge *)lpBits) += ((long)y * WidthBytes);
  478.  
  479.     if (pWidthBytes)
  480.         *pWidthBytes = WidthBytes;
  481.  
  482.     return lpBits;
  483. }
  484.  
  485. #pragma optimize("", off)           //huge pointer math geting hosed
  486.     
  487. /*****************************************************************************
  488.  *
  489.  * MyDecompress
  490.  *
  491.  * This function is the inverse of MyCompress and follows the same caveats.
  492.  *
  493.  * We shouldn't depend on the state to accurately tell us how to
  494.  * decompress; this info needs to come totally from the compressed data!
  495.  *
  496.  ****************************************************************************/
  497. void NEAR PASCAL MyDecompress8(
  498.     INSTINFO * pinst,
  499.     LPBITMAPINFOHEADER lpbiInput,  HPBYTE hpInput,
  500.     LPBITMAPINFOHEADER lpbiOutput, HPBYTE hpOutput, int x, int y)
  501. {
  502.     int         xrun ;
  503.     int         wRealLineSize ;
  504.     long        wLinePad ;
  505.     LPDECOMP_FMT lpDecompressFmt;
  506.     int         wWidth  = (int)lpbiInput->biWidth;
  507.     int         wHeight = (int)lpbiInput->biHeight;
  508.  
  509.     hpOutput = DibXY(lpbiOutput, hpOutput, x, y, &wRealLineSize);
  510.     wLinePad = wRealLineSize - wWidth;
  511.  
  512.     //
  513.     // Initialize the pointer to the decompression format which
  514.     // follows the bitmapinfo header.
  515.     //
  516.     lpDecompressFmt = getDecompressFmtPtr(lpbiInput);
  517.     for (y=0; y < wHeight; y++)
  518.     {
  519.         for (x=0; x<wWidth; )
  520.         {
  521.             xrun = min(wWidth-x,(int)lpDecompressFmt->dInfo.wPixelKeepRatio) ;
  522.             x += xrun ;
  523.             while (xrun--)
  524.                 *hpOutput++ = *hpInput ;
  525.  
  526.             hpInput++ ;
  527.         }
  528.  
  529.         hpOutput += wLinePad ;
  530.     }
  531. }
  532.  
  533. void NEAR PASCAL MyDecompress16(
  534.     INSTINFO * pinst,
  535.     LPBITMAPINFOHEADER lpbiInput,  HPWORD hpInput,
  536.     LPBITMAPINFOHEADER lpbiOutput, HPWORD hpOutput, int x, int y)
  537. {
  538.     int         xrun ;
  539.     int         wRealLineSize ;
  540.     long        wLinePad ;
  541.     LPDECOMP_FMT lpDecompressFmt;
  542.     int         wWidth  = (int)lpbiInput->biWidth ;
  543.     int         wHeight = (int)lpbiInput->biHeight ;
  544.     UINT        wDropBits ;
  545.     WORD        wKeepBits ;
  546.     WORD        r,g,b,color ;
  547.     BITBUFFER   bb ;
  548.  
  549.     hpOutput = DibXY(lpbiOutput, hpOutput, x, y, &wRealLineSize);
  550.     wLinePad = wRealLineSize - (wWidth*2) ;
  551.  
  552.     //
  553.     // Initialize the pointer to the decompression format which
  554.     // follows the bitmapinfo header.
  555.     //
  556.     lpDecompressFmt = getDecompressFmtPtr(lpbiInput);
  557.  
  558.     wDropBits = lpDecompressFmt->dInfo.wColorBitsToDrop ;
  559.     wKeepBits = 5 - wDropBits ;
  560.  
  561.     InitBitBuffer( &bb, hpInput ) ;
  562.  
  563.     for (y=0; y < wHeight; y++)
  564.     {
  565.         for (x=0; x<wWidth; )
  566.         {
  567.             r = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  568.             g = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  569.             b = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  570.  
  571.             color = (r << 10) | (g << 5) | b ;
  572.             
  573.             xrun = min(wWidth-x,(int)lpDecompressFmt->dInfo.wPixelKeepRatio) ;
  574.             x += xrun ;
  575.             while (xrun--)
  576.                 *hpOutput++ = color ;
  577.         }
  578.  
  579.         ((BYTE _huge *)hpOutput) += wLinePad ;
  580.     }
  581. }
  582.  
  583. void NEAR PASCAL MyDecompress24(
  584.     INSTINFO * pinst,
  585.     LPBITMAPINFOHEADER lpbiInput,  HPBYTE hpInput,
  586.     LPBITMAPINFOHEADER lpbiOutput, HPBYTE hpOutput, int x, int y)
  587. {
  588.     int         xrun ;
  589.     int         wRealLineSize ;
  590.     long        wLinePad ;
  591.     LPDECOMP_FMT lpDecompressFmt;
  592.     int         wWidth  = (int)lpbiInput->biWidth ;
  593.     int         wHeight = (int)lpbiInput->biHeight ;
  594.     WORD        wDropBits ;  
  595.     WORD        wKeepBits ;
  596.     WORD        r,g,b ;
  597.     BITBUFFER   bb ;
  598.  
  599.     hpOutput = DibXY(lpbiOutput, hpOutput, x, y, &wRealLineSize);
  600.     wLinePad = wRealLineSize - (wWidth*3);
  601.  
  602.     //
  603.     // Initialize the pointer to the decompression format which
  604.     // follows the bitmapinfo header.
  605.     //
  606.     lpDecompressFmt = getDecompressFmtPtr(lpbiInput);
  607.  
  608.     wDropBits = lpDecompressFmt->dInfo.wColorBitsToDrop ;
  609.     wKeepBits = 8 - wDropBits ;
  610.  
  611.     InitBitBuffer( &bb, hpInput ) ;
  612.  
  613.     for (y=0; y < wHeight; y++)
  614.     {
  615.         for (x=0; x<wWidth; )
  616.         {
  617.             r = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  618.             g = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  619.             b = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  620.  
  621.             xrun = min(wWidth-x,(int)lpDecompressFmt->dInfo.wPixelKeepRatio) ;
  622.             x += xrun ;
  623.             while (xrun--)
  624.             {
  625.                 *hpOutput++ = (BYTE)b ;
  626.                 *hpOutput++ = (BYTE)g ;
  627.                 *hpOutput++ = (BYTE)r ;
  628.             }
  629.         }
  630.  
  631.         hpOutput += wLinePad ;
  632.     }
  633. }
  634.  
  635. #pragma optimize("", on)           //huge pointer math geting hosed
  636.  
  637. /*****************************************************************************
  638.  *
  639.  * Load() is called from the DRV_LOAD message.
  640.  *
  641.  * Tasks such as allocating global memory that is non-instance specific
  642.  * or initializing coprocessor hardware may be performed here.
  643.  *
  644.  * Our simple case needs none of this.
  645.  *
  646.  ****************************************************************************/
  647. BOOL NEAR PASCAL Load(void)
  648. {
  649.     DPF("Load()");
  650.     return TRUE;
  651. }
  652.  
  653. /*****************************************************************************
  654.  *
  655.  * Free() is called from the DRV_FREE message.
  656.  *
  657.  * It should totally reverse the effects of Load() in preparation for
  658.  * the DRV being removed from memory.
  659.  *
  660.  ****************************************************************************/
  661. void NEAR PASCAL Free()
  662. {
  663.     DPF("Free()");
  664. }
  665.  
  666. /*****************************************************************************
  667.  *
  668.  * Open() is called from the ICM_OPEN message
  669.  *
  670.  * This message will be sent for a particular compress/decompress session.
  671.  * Our code must verify that we are indeed being called as a video
  672.  * compressor and create/initialize a state structure. The ICM will
  673.  * give us back the pointer to that structure on every message dealing
  674.  * with this session.
  675.  *
  676.  ****************************************************************************/
  677. INSTINFO * NEAR PASCAL Open(ICOPEN FAR * icinfo)
  678. {
  679.     INSTINFO *  pinst;
  680.  
  681.     DPF("Open('%4.4ls', '%4.4ls')", (LPSTR)&icinfo->fccType, (LPSTR)&icinfo->fccHandler);
  682.  
  683.     //
  684.     // refuse to open if we are not being opened as a Video compressor
  685.     //
  686.     if (icinfo->fccType != ICTYPE_VIDEO)
  687.         return NULL;
  688.  
  689.     pinst = (INSTINFO *)LocalAlloc(LPTR, sizeof(INSTINFO));
  690.  
  691.     if (!pinst)
  692.     {
  693.         icinfo->dwError = ICERR_MEMORY;
  694.         return NULL;
  695.     }
  696.  
  697.     //
  698.     // init structure
  699.     //
  700.     pinst->fccType = ICTYPE_VIDEO;
  701.     pinst->dwFlags = icinfo->dwFlags;
  702.     pinst->fCompress   = FALSE;
  703.     pinst->fDecompress = FALSE;
  704.     pinst->fDrawBegun  = FALSE;
  705.  
  706.     //
  707.     // set the default state.
  708.     //
  709.     SetState(pinst, NULL, 0);
  710.  
  711.     //
  712.     // return success.
  713.     //
  714.     icinfo->dwError = ICERR_OK;
  715.  
  716.     return pinst;
  717. }
  718.  
  719. /*****************************************************************************
  720.  *
  721.  * Close() is called on the ICM_CLOSE message.
  722.  *
  723.  * This message is the complement to ICM_OPEN and marks the end
  724.  * of a compress/decompress session. We kill any in-progress operations
  725.  * (although this shouldn't be needed) and free our instance structure.
  726.  *
  727.  ****************************************************************************/
  728. DWORD NEAR PASCAL Close(INSTINFO * pinst)
  729. {
  730.     DPF("Close()");
  731.  
  732.     if (pinst->fCompress)
  733.         CompressEnd(pinst);
  734.  
  735.     if (pinst->fDecompress)
  736.         DecompressEnd(pinst);
  737.  
  738.     if (pinst->fDrawBegun)
  739.         DrawEnd(pinst);
  740.    
  741.     LocalFree((HLOCAL)pinst);
  742.     
  743.     return 1;
  744. }
  745.  
  746. /*****************************************************************************
  747.  *
  748.  * QueryAbout() and About() handle the ICM_ABOUT message.
  749.  *
  750.  * QueryAbout() returns TRUE to indicate we support an about box.
  751.  * About() displays the box.
  752.  *
  753.  ****************************************************************************/
  754. BOOL NEAR PASCAL QueryAbout(INSTINFO * pinst)
  755. {
  756.     DPF("QueryAbout()");
  757.  
  758.     return TRUE;
  759. }
  760.  
  761. DWORD NEAR PASCAL About(INSTINFO * pinst, HWND hwnd)
  762. {
  763.     #ifdef _WIN32
  764.     // max byte size of dst Windows DBCS string same as UNICODE src
  765.     char szAnsiDesc[sizeof szDescription];
  766.     char szAnsiName[sizeof szName];
  767.     #endif
  768.     
  769.     DPF("About()");
  770.     #ifdef _WIN32
  771.     WideCharToMultiByte(
  772.         CP_ACP,    // code page 
  773.         0,    // performance and mapping flags 
  774.         szDescription,    // address of wide-character string 
  775.         -1,    // -1 means null-term string number of characters in string
  776.         szAnsiDesc,    // address of buffer for new string 
  777.         sizeof szAnsiDesc,    // size of buffer 
  778.         NULL,    // address of default for unmappable characters  
  779.         NULL);     // address of flag set when default char. used 
  780.     WideCharToMultiByte(
  781.         CP_ACP,    // code page 
  782.         0,    // performance and mapping flags 
  783.         szName,    // address of wide-character string 
  784.         -1,    // -1 means null-term string number of characters in string
  785.         szAnsiName,    // address of buffer for new string 
  786.         sizeof szAnsiDesc,    // size of buffer 
  787.         NULL,    // address of default for unmappable characters  
  788.         NULL);     // address of flag set when default char. used 
  789.             
  790.     MessageBox(hwnd,szAnsiDesc,szAnsiName,MB_OK|MB_ICONINFORMATION);
  791.     #else
  792.     MessageBox(hwnd,szDescription,szName,MB_OK|MB_ICONINFORMATION);
  793.     #endif
  794.     return ICERR_OK;
  795. }
  796.  
  797. /*****************************************************************************
  798.  *
  799.  * QueryConfigure() and Configure() implement the ICM_CONFIGURE message.
  800.  *
  801.  * These functions put up a dialog that allows the user, if he so
  802.  * chooses, to modify the configuration portion of our state info.
  803.  * 
  804.  ****************************************************************************/
  805. BOOL NEAR PASCAL QueryConfigure(INSTINFO * pinst)
  806. {
  807.     DPF("QueryConfigure()");
  808.     return TRUE;
  809. }
  810.  
  811. DWORD NEAR PASCAL Configure(INSTINFO * pinst, HWND hwnd)
  812. {
  813.     DPF("Configure()");
  814.     //@@BEGIN_MSINTERNAL
  815.     //It's generally a bad idea to pass near pointers. No problem in WIN32,
  816.     //but perhaps the win16 sample should be fixed -gtb
  817.     //@@END_MSINTERNAL
  818.     return DialogBoxParam(ghModule,"Configure",hwnd,ConfigureDlgProc, (UINT)pinst);
  819. }
  820.  
  821. /*****************************************************************************
  822.  *
  823.  * GetState() implements the ICM_GETSTATE message.
  824.  * 
  825.  * We copy our configuration information and return how many bytes it took.
  826.  *
  827.  ****************************************************************************/
  828. DWORD NEAR PASCAL GetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
  829. {
  830.     DPF("GetState(%08lX, %ld)", pv, dwSize);
  831.  
  832.     if (pv == NULL || dwSize == 0)
  833.         return sizeof(ICSTATE);
  834.  
  835.     if (dwSize < sizeof(ICSTATE))
  836.         return 0;
  837.  
  838.     *((ICSTATE FAR *)pv) = pinst->CurrentState;
  839.  
  840.     // return number of bytes copied
  841.     return sizeof(ICSTATE);
  842. }
  843.  
  844. /*****************************************************************************
  845.  *
  846.  * SetState() implements the ICM_SETSTATE message.
  847.  *
  848.  * The ICM is giving us configuration information saved by GetState()
  849.  * earlier.
  850.  *
  851.  ****************************************************************************/
  852. DWORD NEAR PASCAL SetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
  853. {
  854.     DPF("SetState(%08lX, %ld)", pv, dwSize);
  855.  
  856.     //
  857.     //  make sure we created this state information.
  858.     //
  859.     if (pv && ((ICSTATE FAR *)pv)->fccHandler != FOURCC_SAMP)
  860.         return 0;
  861.  
  862.     if (pv == NULL)
  863.         pinst->CurrentState = DefaultState;
  864.     else if (dwSize >= sizeof(ICSTATE))
  865.         pinst->CurrentState = *((ICSTATE FAR *)pv);
  866.     else
  867.         return 0;
  868.  
  869.     // return number of bytes copied
  870.     return sizeof(ICSTATE);
  871. }
  872.  
  873. /*****************************************************************************
  874.  *
  875.  * GetInfo() implements the ICM_GETINFO message
  876.  *
  877.  * We just fill in the structure to tell the ICM what we can do. The flags
  878.  * (none of which this sample supports) mean the following :
  879.  *
  880.  * VIDCF_QUALITY - we support the quality variable. This means we look at
  881.  *                 dwQuality in the ICINFO structure when compressing and
  882.  *                 make a concious decision to trade quality for space.
  883.  *                 (higher values of dwQuality mean quality is more
  884.  *                 important). dwQuality is set by the ICM.
  885.  *
  886.  * VIDCF_TEMPORAL - We do interframe compression. In this algorithm, not
  887.  *                  every frame is a "key frame"; some frames depend on
  888.  *                  other frames to be generated. An example of this might
  889.  *                  be to store frame buffer differences until the
  890.  *                  differences are big enough to no longer make this
  891.  *                  worthwhile, then storing another complete frame and
  892.  *                  starting over. In this case, the complete frames that
  893.  *                  are stored are key frames and should be flagged as
  894.  *                  such.
  895.  *
  896.  * VIDCF_DRAW -     We will draw the decompressed image on our own. This is
  897.  *                  useful if the decompression is assisted by the video
  898.  *                  hardware.
  899.  *
  900.  ****************************************************************************/
  901. DWORD NEAR PASCAL GetInfo(INSTINFO * pinst, ICINFO FAR *icinfo, DWORD dwSize)
  902. {
  903.     DPF("GetInfo()");
  904.  
  905.     if (icinfo == NULL)
  906.         return sizeof(ICINFO);
  907.  
  908.     if (dwSize < sizeof(ICINFO))
  909.         return 0;
  910.  
  911.     icinfo->dwSize            = sizeof(ICINFO);
  912.     icinfo->fccType           = ICTYPE_VIDEO;
  913.     icinfo->fccHandler        = FOURCC_SAMP;
  914.     icinfo->dwFlags           = 0;
  915.  
  916.                 //              VIDCF_QUALITY    // supports quality
  917.                 //              VIDCF_TEMPORAL   // supports inter-frame
  918.                 //              VIDCF_DRAW       // supports drawing
  919.  
  920.     icinfo->dwVersion         = VERSION_SAMP;
  921.     icinfo->dwVersionICM      = ICVERSION;
  922.     wcscpy(icinfo->szDescription, szDescription);
  923.     wcscpy(icinfo->szName, szName);
  924.  
  925.     return sizeof(ICINFO);
  926. }
  927.  
  928. /*****************************************************************************
  929.  *
  930.  * CompressQuery() handles the ICM_COMPRESSQUERY message
  931.  *
  932.  * This message basically asks, "Can you compress this into this?"
  933.  *
  934.  * We look at the input and output bitmap info headers and determine
  935.  * if we can.
  936.  *
  937.  ****************************************************************************/
  938. LRESULT NEAR PASCAL CompressQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  939. {
  940.     DPF("CompressQuery()");
  941.  
  942.     //
  943.     // determine if the input DIB data is in a format we like.
  944.     //
  945.     if (lpbiIn == NULL ||
  946.         (lpbiIn->biBitCount != 8 && lpbiIn->biBitCount != 16 && lpbiIn->biBitCount != 24) ||
  947.         lpbiIn->biCompression != BI_RGB)
  948.     {
  949.         return ICERR_BADFORMAT;
  950.     }
  951.  
  952.     //
  953.     //  are we being asked to query just the input format?
  954.     //
  955.     if (lpbiOut == NULL)
  956.         return ICERR_OK;
  957.  
  958.     //
  959.     // make sure we can handle the format to compress to also.
  960.     //
  961.     if (lpbiOut->biCompression != BI_SAMP ||    // must be 'Smp1'
  962.         lpbiOut->biBitCount != lpbiIn->biBitCount ||
  963.         lpbiOut->biSize != (sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT)) ||
  964.         lpbiOut->biWidth  != lpbiIn->biWidth || // must be 1:1 (no stretch)
  965.         lpbiOut->biHeight != lpbiIn->biHeight)
  966.     {
  967.         return ICERR_BADFORMAT;
  968.     }
  969.  
  970.     return ICERR_OK;
  971. }
  972.  
  973. /*****************************************************************************
  974.  *
  975.  * CompressGetFormat() implements ICM_GETFORMAT
  976.  *
  977.  * This message asks, "If I gave you this bitmap, how much memory would it
  978.  * be compressed?"
  979.  *
  980.  * If the output bitmap info header is NULL, we just return how big the
  981.  * header would be (header + format information (if any) + palette, actually).  
  982.  * The format is any information that the decompressor might need to 
  983.  * decompress the data.
  984.  *
  985.  * Otherwise, we fill in the header, most importantly the biSizeImage.
  986.  * This field must contain an upper bound on the size of the compressed
  987.  * frame. A value that is too high here will result in inefficient
  988.  * memory allocation at compression time, but will not be reflected
  989.  * to the stored bitmap - the compression algorithm may chop biSizeImage
  990.  * down to the actual amount with no ill effects.
  991.  * 
  992.  ****************************************************************************/
  993. LRESULT NEAR PASCAL CompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  994. {
  995.     DWORD dw;
  996.     LPDECOMP_FMT  lpDecompressFmt;
  997.  
  998.     DPF("CompressGetFormat()");
  999.  
  1000.     if (dw = CompressQuery(pinst, lpbiIn, NULL))
  1001.         return dw;
  1002.  
  1003.     //
  1004.     // if lpbiOut == NULL then, return the size required to hold a output
  1005.     // format.  Remember, if you have decompress format information
  1006.     // in the header, then make room for it.    
  1007.     //
  1008.     if (lpbiOut == NULL)
  1009.         return (int)sizeof(BITMAPINFOHEADER) + (int)sizeof(DECOMP_FORMAT) +
  1010.                (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
  1011.  
  1012.     // 
  1013.     // First copy the bitmapinfo header.
  1014.     //
  1015.     hmemcpy(lpbiOut, lpbiIn, (int)lpbiIn->biSize);
  1016.     
  1017.     //
  1018.     // Now copy the decompression formation information.
  1019.     //
  1020.     lpDecompressFmt = getDecompressFmtPtr(lpbiOut);
  1021.     lpDecompressFmt->dInfo.wPixelKeepRatio  = pinst->CurrentState.dInfo.wPixelKeepRatio;
  1022.     lpDecompressFmt->dInfo.wColorBitsToDrop = pinst->CurrentState.dInfo.wColorBitsToDrop;
  1023.     lpDecompressFmt->dwSize                 = sizeof(DECOMPRESS_INFO);
  1024.  
  1025.     //
  1026.     // Copy the colors. 
  1027.     //
  1028.     lpbiOut->biSize = sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT);
  1029.  
  1030.     hmemcpy(
  1031.         (LPBYTE)lpbiOut + (int)lpbiOut->biSize,
  1032.         (LPBYTE)lpbiIn + (int)lpbiIn->biSize,
  1033.         (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
  1034.  
  1035.     lpbiOut->biBitCount    = lpbiIn->biBitCount;
  1036.     lpbiOut->biCompression = BI_SAMP;
  1037.     lpbiOut->biSizeImage   = CompressGetSize(pinst, lpbiIn, lpbiOut); 
  1038.  
  1039.     return ICERR_OK;
  1040. }
  1041.  
  1042. /*****************************************************************************
  1043.  *
  1044.  * CompressBegin() implements ICM_COMPRESSBEGIN
  1045.  *
  1046.  * We're about to start compressing, initialize coprocessor, etc.
  1047.  * 
  1048.  ****************************************************************************/
  1049. LRESULT NEAR PASCAL CompressBegin(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1050. {
  1051.     DWORD dw;
  1052.  
  1053.     DPF("CompressBegin()");
  1054.  
  1055.     if (dw = CompressQuery(pinst, lpbiIn, lpbiOut))
  1056.         return dw;
  1057.  
  1058.     //
  1059.     // initialize for compression, for real....
  1060.     //
  1061.  
  1062.     pinst->fCompress = TRUE;
  1063.  
  1064.     return ICERR_OK;
  1065. }
  1066.  
  1067. /*****************************************************************************
  1068.  *
  1069.  * CompressGetSize() implements ICM_COMPRESS_GET_SIZE
  1070.  *
  1071.  * This function returns how much (upper bound) memory a compressed frame
  1072.  * will take.
  1073.  *
  1074.  ****************************************************************************/
  1075. LRESULT NEAR PASCAL CompressGetSize(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1076. {
  1077.     int dx,dy;
  1078.     WORD    wPixelSize ;
  1079.  
  1080.     DPF("CompressGetSize()");
  1081.  
  1082.     dx = (int)lpbiIn->biWidth;
  1083.     dy = (int)lpbiIn->biHeight;
  1084.  
  1085.     wPixelSize = (lpbiOut->biBitCount+7)/8 ;
  1086.  
  1087.     return wPixelSize*(DWORD)dx*dy ;
  1088. }
  1089.  
  1090. /*****************************************************************************
  1091.  *
  1092.  * Compress() implements ICM_COMPRESS
  1093.  *
  1094.  * Everything is set up; call the actual compression routine.
  1095.  *
  1096.  * Note:
  1097.  *
  1098.  * 1) We set the ckid in icinfo to a two-character code indicating how we
  1099.  *    compressed. This code will be returned to us at decompress time to
  1100.  *    allow us to pick a decompression algorithm to match. This is different
  1101.  *    from icinfo->fccHandler, which tells which driver to use!
  1102.  *
  1103.  * 2) We set the key-frame flag on every frame since we do no
  1104.  *    temporal (inter-frame) compression.
  1105.  *
  1106.  ****************************************************************************/
  1107. LRESULT NEAR PASCAL Compress(INSTINFO * pinst, ICCOMPRESS FAR *icinfo, DWORD dwSize)
  1108. {
  1109.     DWORD dw;
  1110.     BOOL  fBegin;
  1111.  
  1112.     DPF("Compress()");
  1113.  
  1114.     if (dw = CompressQuery(pinst, icinfo->lpbiInput, icinfo->lpbiOutput))
  1115.         return dw;
  1116.  
  1117.     //
  1118.     // check for being called without a BEGIN message
  1119.     //
  1120.     if (!(fBegin = pinst->fCompress))
  1121.     {
  1122.         if (dw = CompressBegin(pinst, icinfo->lpbiInput, icinfo->lpbiOutput))
  1123.             return dw;
  1124.     }
  1125.  
  1126.     if (pinst->Status)
  1127.     //
  1128.     // Start the intervals to the Status procedure.
  1129.     //
  1130.     pinst->Status(pinst->lParam, ICSTATUS_START, 0);
  1131.     
  1132.     /* do the compression */
  1133.     switch(icinfo->lpbiInput->biBitCount)
  1134.     {
  1135.         case 8 :
  1136.             dw = MyCompress8(pinst,icinfo->lpbiInput, icinfo->lpInput, 
  1137.                 icinfo->lpbiOutput, icinfo->lpOutput);
  1138.             break;
  1139.  
  1140.         case 16 :
  1141.             dw = MyCompress16(pinst,icinfo->lpbiInput, icinfo->lpInput, 
  1142.                 icinfo->lpbiOutput, icinfo->lpOutput);
  1143.             break;
  1144.  
  1145.         case 24 :
  1146.             dw = MyCompress24(pinst,icinfo->lpbiInput, icinfo->lpInput, 
  1147.                 icinfo->lpbiOutput, icinfo->lpOutput);
  1148.             break;
  1149.     }
  1150.  
  1151.     //
  1152.     // Stop the intervals to the Status procedure.
  1153.     //
  1154.     if (pinst->Status)
  1155.     pinst->Status(pinst->lParam, ICSTATUS_END, 0);
  1156.     
  1157.     //
  1158.     // return the chunk id
  1159.     //
  1160.     if (icinfo->lpckid)
  1161.         *icinfo->lpckid = TWOCC_SAMP;
  1162.  
  1163.     //
  1164.     // set the AVI index flags,
  1165.     //
  1166.     //    make it a keyframe
  1167.     //
  1168.     if (icinfo->lpdwFlags)
  1169.         *icinfo->lpdwFlags = AVIIF_KEYFRAME;
  1170.  
  1171.     //
  1172.     // do a CompressEnd() for the caller if needed
  1173.     //
  1174.     if (!fBegin)
  1175.     {
  1176.         CompressEnd(pinst);
  1177.     }
  1178.  
  1179.     return dw;
  1180. }
  1181.  
  1182. /*****************************************************************************
  1183.  *
  1184.  * CompressEnd() is called on ICM_COMPRESS_END
  1185.  *
  1186.  * This function is a chance to flush buffers, deinit hardware, etc.
  1187.  * after compressing a single frame.
  1188.  *
  1189.  ****************************************************************************/
  1190. LRESULT NEAR PASCAL CompressEnd(INSTINFO * pinst)
  1191. {
  1192.     DPF("CompressEnd()");
  1193.  
  1194.     if (!pinst->fCompress)
  1195.         return ICERR_ERROR;
  1196.  
  1197.     /* *** your code to clean up here *** */
  1198.  
  1199.     pinst->fCompress = FALSE;
  1200.  
  1201.     return ICERR_OK;
  1202. }
  1203.  
  1204. /*****************************************************************************
  1205.  ****************************************************************************/
  1206. LRESULT NEAR PASCAL DecompressQueryFmt(
  1207.     INSTINFO * pinst,
  1208.     LPBITMAPINFOHEADER lpbiSrc)
  1209. {
  1210.     //
  1211.     // determine if the input DIB data is in a format we like.
  1212.     //
  1213.     if (lpbiSrc == NULL ||
  1214.         !(lpbiSrc->biBitCount == 24 ||
  1215.           lpbiSrc->biBitCount == 16 ||
  1216.           lpbiSrc->biBitCount == 8) ||
  1217.         lpbiSrc->biCompression != BI_SAMP ||
  1218.         lpbiSrc->biSize != (sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT))) {
  1219.         return ICERR_BADFORMAT;
  1220.     }
  1221.     return ICERR_OK;
  1222. }
  1223.  
  1224. /*****************************************************************************
  1225.  *
  1226.  * DecompressQuery() implements ICM_DECOMPRESS_QUERY
  1227.  *
  1228.  * See CompressQuery()
  1229.  * 
  1230.  ****************************************************************************/
  1231. LRESULT NEAR PASCAL DecompressQuery(
  1232.     INSTINFO * pinst,
  1233.     DWORD dwFlags,
  1234.     LPBITMAPINFOHEADER lpbiSrc,
  1235.     LPVOID pSrc,
  1236.     int xSrc,
  1237.     int ySrc,
  1238.     int dxSrc,
  1239.     int dySrc,
  1240.     LPBITMAPINFOHEADER lpbiDst,
  1241.     LPVOID pDst,
  1242.     int xDst,
  1243.     int yDst,
  1244.     int dxDst,
  1245.     int dyDst)
  1246. {
  1247.     LRESULT l;
  1248.  
  1249.     DPF("DecompressQuery()");
  1250.  
  1251.     if (l = DecompressQueryFmt(pinst, lpbiSrc))
  1252.         return l;
  1253.  
  1254.     //
  1255.     // allow (-1) as a default width/height
  1256.     //
  1257.     if (dxSrc == -1)
  1258.         dxSrc = (int)lpbiSrc->biWidth;
  1259.  
  1260.     if (dySrc == -1)
  1261.         dySrc = (int)lpbiSrc->biHeight;
  1262.  
  1263.     //
  1264.     //  we cant clip the source.
  1265.     //
  1266.     if (xSrc != 0 || ySrc != 0) 
  1267.         return ICERR_BADPARAM;
  1268.  
  1269.     if (dxSrc != (int)lpbiSrc->biWidth || dySrc != (int)lpbiSrc->biHeight)
  1270.         return ICERR_BADPARAM;
  1271.  
  1272.     //
  1273.     //  are we being asked to query just the input format?
  1274.     //
  1275.     if (lpbiDst == NULL)
  1276.         return ICERR_OK;
  1277.  
  1278.     //
  1279.     // allow (-1) as a default width/height
  1280.     //
  1281.     if (dxDst == -1)
  1282.         dxDst = (int)lpbiDst->biWidth;
  1283.  
  1284.     if (dyDst == -1)
  1285.         dyDst = abs((int)lpbiDst->biHeight);
  1286.  
  1287.     //
  1288.     // make sure we can handle the format to decompress too.
  1289.     //
  1290.     if (lpbiDst->biCompression != BI_RGB ||             // must be full dib
  1291.         lpbiDst->biBitCount != lpbiSrc->biBitCount ||   // must be same bpp
  1292.         lpbiDst->biSize != sizeof(BITMAPINFOHEADER) ||
  1293.         dxSrc != dxDst || dySrc != dyDst)               // must be 1:1 (no stretch)
  1294.     {
  1295.         return ICERR_BADFORMAT;
  1296.     }
  1297.  
  1298.     return ICERR_OK;
  1299. }
  1300.  
  1301. /*****************************************************************************
  1302.  *
  1303.  * DecompressGetFormat() implements ICM_DECOMPRESS_GET_FORMAT
  1304.  *
  1305.  * See CompressGetFormat()
  1306.  *
  1307.  ****************************************************************************/
  1308. LRESULT NEAR PASCAL DecompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1309. {
  1310.     DWORD dw;
  1311.     int dx,dy;
  1312.     WORD    wBytesPerPixel ;
  1313.  
  1314.     DPF("DecompressGetFormat()");
  1315.  
  1316.     if (dw = DecompressQueryFmt(pinst, lpbiIn))
  1317.         return dw;
  1318.  
  1319.     //
  1320.     // if lpbiOut == NULL then, return the size required to hold an output
  1321.     // format.  Remember to copy the bitmapinfo header and the colors,
  1322.     // but not the decompression format which gives the driver information
  1323.     // on how to decompress the data.  
  1324.     //
  1325.     if (lpbiOut == NULL)
  1326.         return (int)sizeof(BITMAPINFOHEADER) + 
  1327.                (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
  1328.  
  1329.     //
  1330.     // First copy the bitmapinfo header, then skip over the decompression
  1331.     // information in the IN buffer, and copy the colors.  The decompression
  1332.     // information is not part of the decompression format.
  1333.     //
  1334.     hmemcpy(lpbiOut, lpbiIn,
  1335.         (int)sizeof(BITMAPINFOHEADER));
  1336.  
  1337.     lpbiOut->biSize        = sizeof(BITMAPINFOHEADER);
  1338.     lpbiOut->biClrUsed     = lpbiIn->biClrUsed;
  1339.     lpbiOut->biBitCount    = lpbiIn->biBitCount ; 
  1340.     lpbiOut->biCompression = BI_RGB;
  1341.  
  1342.     dx = (int)lpbiIn->biWidth;
  1343.     dy = (int)lpbiIn->biHeight;
  1344.     wBytesPerPixel = (lpbiIn->biBitCount+7)/8 ;
  1345.     
  1346.     lpbiOut->biSizeImage   = wBytesPerPixel*(DWORD)dy*(DWORD)((dx+3)&~3);
  1347.  
  1348.     hmemcpy(
  1349.         (LPBYTE)lpbiOut + (int)lpbiOut->biSize,
  1350.         (LPBYTE)lpbiIn  + (int)lpbiIn->biSize,
  1351.         (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
  1352.  
  1353.     return ICERR_OK;
  1354. }
  1355.  
  1356. /*****************************************************************************
  1357.  *
  1358.  * DecompressGetPalette() implements ICM_GET_PALETTE
  1359.  *
  1360.  * This function has no Compress...() equivalent
  1361.  *
  1362.  * It is used to pull the palette from a frame in order to possibly do
  1363.  * a palette change.
  1364.  * 
  1365.  ****************************************************************************/
  1366. LRESULT NEAR PASCAL DecompressGetPalette(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1367. {
  1368.     DWORD dw;
  1369.  
  1370.     DPF("DecompressGetPalette()");
  1371.  
  1372.     if (dw = DecompressQueryFmt(pinst, lpbiIn))
  1373.         return dw;
  1374.  
  1375.     if (lpbiOut->biBitCount != 8) {
  1376.         return ICERR_BADFORMAT;
  1377.     }
  1378.  
  1379.     //
  1380.     // if you decompress full-color to 8 bit you need to put the "dither"
  1381.     // palette in lpbiOut
  1382.     //
  1383.     if (lpbiIn->biBitCount != 8) {
  1384.         return ICERR_BADFORMAT;
  1385.     }
  1386.     if (lpbiIn->biClrUsed == 0)
  1387.         lpbiIn->biClrUsed = 256;
  1388.  
  1389.     //
  1390.     // return the 8bit palette used for decompression.  
  1391.     //
  1392.     lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
  1393.     hmemcpy(
  1394.         (LPBYTE)lpbiOut + (int)lpbiOut->biSize,
  1395.         (LPBYTE)lpbiIn + (int)lpbiIn->biSize,
  1396.         (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
  1397.  
  1398.     lpbiOut->biClrUsed = lpbiIn->biClrUsed;
  1399.  
  1400.     return ICERR_OK;
  1401. }
  1402.  
  1403. /*****************************************************************************
  1404.  *
  1405.  * DecompressBegin() implements ICM_DECOMPRESS_BEGIN
  1406.  *
  1407.  * See CompressBegin()
  1408.  * 
  1409.  ****************************************************************************/
  1410. LRESULT NEAR PASCAL DecompressBegin(
  1411.     INSTINFO * pinst,
  1412.     DWORD dwFlags,
  1413.     LPBITMAPINFOHEADER lpbiSrc,
  1414.     LPVOID pSrc,
  1415.     int xSrc,
  1416.     int ySrc,
  1417.     int dxSrc,
  1418.     int dySrc,
  1419.     LPBITMAPINFOHEADER lpbiDst,
  1420.     LPVOID pDst,
  1421.     int xDst,
  1422.     int yDst,
  1423.     int dxDst,
  1424.     int dyDst)
  1425. {
  1426.     LONG l;
  1427.  
  1428.     if (l = DecompressQuery(pinst, dwFlags, lpbiSrc, pSrc, xSrc, ySrc, dxSrc, dySrc, lpbiDst, pDst, xDst, yDst, dxDst, dyDst))
  1429.         return l;
  1430.  
  1431.     //
  1432.     //  make sure biSizeImage is set, the decompress code needs it to be
  1433.     //
  1434.     if (lpbiDst->biSizeImage == 0)
  1435.         lpbiDst->biSizeImage = (DWORD)(WORD)abs((int)lpbiDst->biHeight)*(DWORD)(WORD)DIBWIDTHBYTES(*lpbiDst);
  1436.  
  1437.     pinst->fDecompress = TRUE;
  1438.  
  1439.     return ICERR_OK;
  1440. }
  1441.  
  1442. /*****************************************************************************
  1443.  *
  1444.  * Decompress() implements ICM_DECOMPRESS
  1445.  *
  1446.  * See DecompressBegin()
  1447.  * 
  1448.  ****************************************************************************/
  1449. LRESULT NEAR PASCAL Decompress(
  1450.     INSTINFO * pinst,
  1451.     DWORD dwFlags,
  1452.     LPBITMAPINFOHEADER lpbiSrc,
  1453.     LPVOID lpSrc,
  1454.     int xSrc,
  1455.     int ySrc,
  1456.     int dxSrc,
  1457.     int dySrc,
  1458.     LPBITMAPINFOHEADER lpbiDst,
  1459.     LPVOID lpDst,
  1460.     int xDst,
  1461.     int yDst,
  1462.     int dxDst,
  1463.     int dyDst)
  1464. {
  1465.     BOOL    fBegin;
  1466.  
  1467.     //
  1468.     //  if we are called without a begin do the begin now, but dont make
  1469.     //  the begin "stick"
  1470.     //
  1471.     if (!(fBegin = pinst->fDecompress))
  1472.     {
  1473.         LRESULT l;
  1474.  
  1475.         if (l = DecompressBegin(pinst, dwFlags, lpbiSrc, lpSrc, xSrc, ySrc, dxSrc, dySrc, lpbiDst, lpDst, xDst, yDst, dxDst, dyDst))
  1476.             return l;
  1477.  
  1478.     }
  1479.  
  1480.     //
  1481.     //  because 'SAMP' frames are key frames we dont need to do any thing if
  1482.     //  behind.
  1483.     //
  1484.     if (dwFlags & ICDECOMPRESS_HURRYUP)
  1485.         return ICERR_OK;
  1486.  
  1487.     /* do the decompression */
  1488.     switch(lpbiSrc->biBitCount)
  1489.     {
  1490.         case 8 :
  1491.             MyDecompress8(pinst,lpbiSrc, lpSrc, lpbiDst, lpDst, xDst, yDst);
  1492.             break ;
  1493.  
  1494.         case 16 :
  1495.             MyDecompress16(pinst,lpbiSrc, lpSrc, lpbiDst, lpDst, xDst, yDst);
  1496.             break ;
  1497.  
  1498.         case 24 :
  1499.             MyDecompress24(pinst,lpbiSrc, lpSrc, lpbiDst, lpDst, xDst, yDst);
  1500.             break ;
  1501.  
  1502.     }
  1503.  
  1504.     if (!fBegin)
  1505.     DecompressEnd(pinst);
  1506.  
  1507.     return ICERR_OK;
  1508. }
  1509.  
  1510. /*****************************************************************************
  1511.  *
  1512.  * DecompressEnd() implements ICM_DECOMPRESS_END
  1513.  *
  1514.  * See CompressEnd()
  1515.  *
  1516.  ****************************************************************************/
  1517. LRESULT NEAR PASCAL DecompressEnd(INSTINFO * pinst)
  1518. {
  1519.     DPF("DecompressEnd()");
  1520.  
  1521.     if (!pinst->fDecompress)
  1522.         return ICERR_ERROR;
  1523.  
  1524.     //
  1525.     //  clean up decompress stuff.
  1526.     //
  1527.  
  1528.     pinst->fDecompress = FALSE;
  1529.     return ICERR_OK;
  1530. }
  1531.  
  1532. /*****************************************************************************
  1533.  *
  1534.  * DrawQuery() implements ICM_DRAW_QUERY
  1535.  *
  1536.  ****************************************************************************/
  1537. BOOL NEAR PASCAL DrawQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiInput)
  1538. {
  1539.     return FALSE;
  1540. }
  1541.  
  1542. /*****************************************************************************
  1543.  *
  1544.  * DrawBegin() implements ICM_DRAW_BEGIN
  1545.  *
  1546.  * This is just like DecompressBegin() except that we also must prepare to
  1547.  * actually draw the bitmap on the screen. ICDRAWBEGIN provides info specific
  1548.  * to this task.
  1549.  *
  1550.  ****************************************************************************/
  1551. LRESULT NEAR PASCAL DrawBegin(INSTINFO * pinst,ICDRAWBEGIN FAR *icinfo, DWORD dwSize)
  1552. {
  1553.     DPF("DrawBegin()");
  1554.  
  1555.     if (1)  // we dont draw!
  1556.         return ICERR_UNSUPPORTED;
  1557.  
  1558.     if (pinst->fDrawBegun)
  1559.         return ICERR_OK;
  1560.  
  1561.     pinst->fDrawBegun = TRUE;
  1562.     
  1563.     //
  1564.     // but if we did draw we would get ready to draw here
  1565.     //
  1566.  
  1567.     return ICERR_OK;
  1568. }
  1569.  
  1570. /*****************************************************************************
  1571.  *
  1572.  * Draw implements ICM_DRAW
  1573.  *
  1574.  * Decompress and draw
  1575.  *
  1576.  ****************************************************************************/
  1577. LRESULT NEAR PASCAL Draw(INSTINFO * pinst, ICDRAW FAR *icinfo, DWORD dwSize)
  1578. {
  1579.     DPF("Draw()");
  1580.  
  1581.     if (!pinst->fDrawBegun)
  1582.         return ICERR_ERROR;
  1583.  
  1584.     return ICERR_UNSUPPORTED;
  1585. }
  1586.  
  1587. /*****************************************************************************
  1588.  *
  1589.  * DrawEnd() implements ICM_DRAW_END
  1590.  *
  1591.  * See DecompressEnd()
  1592.  *
  1593.  ****************************************************************************/
  1594. LRESULT NEAR PASCAL DrawEnd(INSTINFO * pinst)
  1595. {
  1596.     DPF("DrawEnd()");
  1597.  
  1598.     if (1)  // we dont draw!
  1599.         return ICERR_UNSUPPORTED;
  1600.  
  1601.     if (!pinst->fDrawBegun)
  1602.         return ICERR_ERROR;
  1603.  
  1604.     pinst->fDrawBegun = FALSE;
  1605.  
  1606.     //
  1607.     // but if we did we would clean up here
  1608.     //
  1609.  
  1610.     return ICERR_OK;
  1611. }
  1612.  
  1613. /*****************************************************************************
  1614.  *
  1615.  * ConfigureDlgProc() is called by Configure
  1616.  *
  1617.  * This is a standard dialog proc which allows the user to
  1618.  * pick config options for the driver.
  1619.  *
  1620.  ****************************************************************************/
  1621. BOOL FAR PASCAL _loadds ConfigureDlgProc(
  1622. HWND hdlg, 
  1623. UINT msg, 
  1624. WPARAM wParam, 
  1625. LONG lParam)
  1626. {
  1627.     int             id;
  1628.     static int      s1;
  1629.     static int      s2;
  1630.     HWND            hsb;
  1631.     char            ach[10];
  1632.     
  1633.     static INSTINFO *pinst;
  1634.  
  1635.     #define SCROLL_MIN  1       
  1636.     #define SCROLL_MAX  16      
  1637.  
  1638.     #define SCROLL2_MIN  0       
  1639.     #define SCROLL2_MAX  4      
  1640.  
  1641.         
  1642.     switch (msg)
  1643.     {
  1644.         case WM_COMMAND:
  1645.             switch(GET_WM_COMMAND_ID(wParam, lParam))
  1646.             {
  1647.                 case IDOK:
  1648.                     hsb = GetDlgItem(hdlg,ID_SCROLL);
  1649.                     pinst->CurrentState.dInfo.wPixelKeepRatio = s1 ;
  1650.                     hsb = GetDlgItem(hdlg,ID_SCROLL2);
  1651.                     pinst->CurrentState.dInfo.wColorBitsToDrop = s2 ;
  1652.                     EndDialog(hdlg,TRUE);
  1653.                     break;
  1654.  
  1655.                 case IDCANCEL:
  1656.                     EndDialog(hdlg,FALSE);
  1657.                     break;
  1658.             }
  1659.             break;
  1660.  
  1661.         case WM_HSCROLL:
  1662.             hsb = GET_WM_HSCROLL_HWND(wParam, lParam);
  1663.             id = GetDlgCtrlID(hsb);
  1664.  
  1665.             switch( id )
  1666.             {
  1667.                 case ID_SCROLL:
  1668.                     s1 = GetScrollPos(hsb,SB_CTL);
  1669.  
  1670.                     switch (GET_WM_HSCROLL_CODE(wParam, lParam))
  1671.                     {
  1672.                         case SB_LINEDOWN:      s1 += 1; break;
  1673.                         case SB_LINEUP:        s1 -= 1; break;
  1674.                         case SB_PAGEDOWN:      s1 += 4; break;
  1675.                         case SB_PAGEUP:        s1 -= 4; break;
  1676.                         case SB_THUMBTRACK:
  1677.                         case SB_THUMBPOSITION: s1 = (short)GET_WM_HSCROLL_POS(wParam, lParam); break;
  1678.                         default:               return TRUE;
  1679.                     }           
  1680.                 
  1681.                     s1 = max(SCROLL_MIN,min(SCROLL_MAX,s1));
  1682.                     SetScrollPos(hsb,SB_CTL,s1,TRUE);
  1683.                     wsprintf(ach, "%02d", s1);
  1684.                     SetDlgItemText(hdlg,ID_TEXT,ach);
  1685.                     return TRUE;
  1686.  
  1687.                 case ID_SCROLL2:
  1688.                     s2 = GetScrollPos(hsb,SB_CTL);
  1689.  
  1690.                     switch (GET_WM_HSCROLL_CODE(wParam, lParam))
  1691.                     {
  1692.                         case SB_LINEDOWN:      s2 += 1; break;
  1693.                         case SB_LINEUP:        s2 -= 1; break;
  1694.                         case SB_PAGEDOWN:      s2 += 4; break;
  1695.                         case SB_PAGEUP:        s2 -= 4; break;
  1696.                         case SB_THUMBTRACK:
  1697.                         case SB_THUMBPOSITION: s2 = (short)GET_WM_HSCROLL_POS(wParam, lParam); break;
  1698.                         default:               return TRUE;
  1699.                     }           
  1700.  
  1701.                     s2 = max(SCROLL2_MIN,min(SCROLL2_MAX,s2));
  1702.                     SetScrollPos(hsb,SB_CTL,s2,TRUE);
  1703.                     wsprintf(ach, "%02d", s2);
  1704.                     SetDlgItemText(hdlg,ID_TEXT2,ach);
  1705.                     return TRUE;
  1706.  
  1707.             }
  1708.             return TRUE ;
  1709.  
  1710.  
  1711.         case WM_INITDIALOG:
  1712.             pinst = (INSTINFO *)lParam;
  1713.  
  1714.             hsb = GetDlgItem(hdlg,ID_SCROLL);
  1715.             s1 = pinst->CurrentState.dInfo.wPixelKeepRatio;
  1716.             SetScrollRange(hsb,SB_CTL,SCROLL_MIN, SCROLL_MAX, TRUE);
  1717.             SetScrollPos(hsb,SB_CTL,s1,TRUE);
  1718.             wsprintf(ach, "%02d", s1);
  1719.             SetDlgItemText(hdlg,ID_TEXT,ach);
  1720.  
  1721.             hsb = GetDlgItem(hdlg,ID_SCROLL2);
  1722.             s2 = pinst->CurrentState.dInfo.wColorBitsToDrop;
  1723.             SetScrollRange(hsb,SB_CTL,SCROLL2_MIN, SCROLL2_MAX, TRUE);
  1724.             SetScrollPos(hsb,SB_CTL,s2,TRUE);
  1725.             wsprintf(ach, "%02d", s2);
  1726.             SetDlgItemText(hdlg,ID_TEXT2,ach);
  1727.  
  1728.             return TRUE;
  1729.     }
  1730.     return FALSE;
  1731. }
  1732.  
  1733. /*****************************************************************************
  1734.  *
  1735.  * dprintf() is called by the DPF macro if DEBUG is defined at compile time.
  1736.  *
  1737.  * The messages will be send to COM1: like any debug message. To 
  1738.  * enable debug output, add the following to WIN.INI :
  1739.  *
  1740.  * [debug]
  1741.  * ICSAMPLE=1
  1742.  *
  1743.  ****************************************************************************/
  1744.  
  1745. #ifdef DEBUG
  1746.  
  1747. void FAR cdecl dprintf(LPSTR szFormat, ...)
  1748. {
  1749.     char ach[128];
  1750.  
  1751.     static BOOL fDebug = -1;
  1752.  
  1753.     if (fDebug == -1)
  1754.         fDebug = GetProfileInt("Debug", MODNAME, FALSE);
  1755.  
  1756.     if (!fDebug)
  1757.         return;
  1758.  
  1759.     lstrcpy(ach, MODNAME ": ");
  1760.     wvsprintf(ach+lstrlen(ach),szFormat,(LPSTR)(&szFormat+1));
  1761.     lstrcat(ach, "\r\n");
  1762.  
  1763.     OutputDebugString(ach);
  1764. }
  1765.  
  1766. #endif
  1767.