home *** CD-ROM | disk | FTP | other *** search
/ Spidla DivX / DivX.bin / LocoCodec / lococodec.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2003-04-27  |  44.0 KB  |  1,198 lines

  1. //
  2. // lococodec v0.1 based on:
  3. //
  4. // Huffyuv v2.1.1, by Ben Rudiak-Gould.
  5. // http://www.math.berkeley.edu/~benrg/huffyuv.html
  6. //
  7. // Based on MSYUV sample code, which is:
  8. // Copyright (c) 1993 Microsoft Corporation.
  9. // All Rights Reserved.
  10. //
  11. // Changes copyright 2000 Ben Rudiak-Gould, and distributed under
  12. // the terms of the GNU General Public License, v2 or later.  See
  13. // http://www.gnu.org/copyleft/gpl.html.
  14. //
  15. // I edit these files in 10-point Verdana, a proportionally-spaced font.
  16. // You may notice formatting oddities if you use a monospaced font.
  17. //
  18.  
  19.  
  20. extern "C" {
  21. #include "loco.h"
  22. }
  23.  
  24. #include "lococodec.h"
  25. #include "lococodec_a.h"
  26. #include "resource.h"
  27.  
  28. #include <crtdbg.h>
  29.  
  30. #include <stdio.h>
  31.  
  32. #include <commctrl.h>
  33.  
  34. TCHAR szDescription[] = TEXT("LOCO Codec Version 0.2"); // Moh
  35. TCHAR szName[]        = TEXT("lococodec");
  36.  
  37. #define VERSION         0x00000002      // 0.2; version number changes when file format changes
  38.  
  39.  
  40. /********************************************************************
  41. ********************************************************************/
  42.  
  43. // these tables are generated at runtime from the data in tables.cpp
  44.  
  45.  
  46. CodecInst *encode_table_owner, *decode_table_owner;
  47.  
  48. /********************************************************************
  49. ********************************************************************/
  50.  
  51. void Msg(const char fmt[], ...) {
  52.   static int debug = GetPrivateProfileInt("debug", "log", 0, INI_FILE);
  53.   if (!debug) return;
  54.  
  55.   DWORD written;
  56.   char buf[2000];
  57.   va_list val;
  58.   
  59.   va_start(val, fmt);
  60.   wvsprintf(buf, fmt, val);
  61.  
  62.   const COORD _80x50 = {80,5000};
  63.   static BOOL startup = (AllocConsole(), SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), _80x50));
  64.   WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), buf, lstrlen(buf), &written, 0);
  65. }
  66.  
  67.  
  68. int AppFlags() {
  69.   static int flags = -1;
  70.   if (flags < 0) {
  71.     flags = 0;
  72.     TCHAR apppath[MAX_PATH];
  73.     if (GetModuleFileName(NULL, apppath, MAX_PATH)) {
  74.       TCHAR* appname = strrchr(apppath, '\\');
  75.       appname = appname ? appname+1 : apppath;
  76.       Msg("App name is %s; ", appname);
  77.       if (!lstrcmpi(appname, TEXT("premiere.exe")))
  78.         flags = 1;
  79.       if (!lstrcmpi(appname, TEXT("veditor.exe")))
  80.         flags = 1;
  81.       if (!lstrcmpi(appname, TEXT("avi2mpg2_vfw.exe")))
  82.         flags = 1;
  83.       if (!lstrcmpi(appname, TEXT("bink.exe")))
  84.         flags = 1;
  85.       if (!lstrcmpi(appname, TEXT("afterfx.exe")))
  86.         flags = 2;
  87.       // new flag for ccesp/ccesp trial for buggy YUY2 handling - bastel
  88.       if (!lstrcmpi(appname, TEXT("cctsp.exe")) || !lstrcmpi(appname, TEXT("cctspt.exe")))
  89.         flags = 4;
  90.       Msg("flags=%d\n", flags);
  91.     }
  92.   }
  93.   return flags;
  94. }
  95.  
  96. bool SuggestRGB() {
  97.   return !!GetPrivateProfileInt("debug", "rgboutput", AppFlags()&1, INI_FILE);
  98. }
  99.  
  100. bool AllowRGBA() {
  101.   return !!GetPrivateProfileInt("general", "enable_rgba", AppFlags()&2, INI_FILE);
  102. }
  103.  
  104. // ignore top-down (i.e. negative height) - bastel
  105. bool IgnoreTopDown() {
  106.   return !!GetPrivateProfileInt("debug", "ignore_topdown", AppFlags()&4, INI_FILE);
  107. }
  108.  
  109.  
  110. /********************************************************************
  111. ********************************************************************/
  112.  
  113. CodecInst* Open(ICOPEN* icinfo) {
  114.   if (icinfo && icinfo->fccType != ICTYPE_VIDEO)
  115.       return NULL;
  116.  
  117.   CodecInst* pinst = new CodecInst();
  118.  
  119.   if (icinfo) icinfo->dwError = pinst ? ICERR_OK : ICERR_MEMORY;
  120.   
  121.   return pinst;
  122. }
  123.  
  124. DWORD Close(CodecInst* pinst) {
  125. //    delete pinst;       // this caused problems when deleting at app close time
  126.     return 1;
  127. }
  128.  
  129. /********************************************************************
  130. ********************************************************************/
  131.  
  132. enum {
  133.   methodAsRGB=0, 
  134.   methodConvertToYUY2=-1
  135. };
  136.  
  137. static inline int GetLocoOutputType(LPBITMAPINFOHEADER lpbi) {
  138.   if (lpbi->biCompression == FOURCC_LOCO && lpbi->biSize > sizeof(BITMAPINFOHEADER)+sizeof(int)*1) {
  139.     int output_type = *((int*)((char*)lpbi + sizeof(BITMAPINFOHEADER) + sizeof(int)*1));
  140.     if (output_type)
  141.       return output_type;
  142.   }
  143.   return 0;
  144. }
  145.  
  146. static inline int GetBitCount(LPBITMAPINFOHEADER lpbi) {
  147.   return lpbi->biBitCount;
  148. }
  149.  
  150. struct MethodName { int method; const char* name; };
  151.  
  152. MethodName rgb_method_names[] = {
  153.   { methodAsRGB, "As RGB (not recommended)" },
  154.   { methodConvertToYUY2, "Convert to YUY2" }
  155. };
  156.  
  157. MethodName max_losses[] = {
  158.     { 0, "0" },
  159.     { 1, "1" },
  160.     { 2, "2" },
  161.     { 3, "3" },
  162.     { 4, "4" },
  163.     { 5, "5" }
  164. };
  165.  
  166. struct { UINT item; UINT tip; } item2tip[] = {
  167.     { IDC_RGBMETHOD,        IDS_TIP_METHOD_RGB        },
  168.     { IDC_IS_INTERLACED,    IDS_TIP_SOURCE_IS_INTERLACED    },
  169.     { IDC_RGBOUTPUT,        IDS_TIP_RGB_ONLY        },
  170.     { IDC_RGBA,                IDS_TIP_RGBA_COMPR        },
  171.     { IDC_SWAPFIELDS,        IDS_TIP_SWAPFIELDS        },
  172.     { IDC_LOG,                IDS_TIP_LOG                },
  173.     { IDC_FULL_SIZE_BUFFER,    IDS_TIP_FULL_SIZE_BUFFER},
  174.     { IDC_MAX_LOSS,    IDS_TIP_MAX_LOSS},
  175.     { 0,0 }
  176. };
  177.  
  178.  
  179.  
  180. /********************************************************************
  181. ********************************************************************/
  182.  
  183. BOOL CodecInst::QueryAbout() { return TRUE; }
  184.  
  185. BOOL CodecInst::QueryConfigure() { return TRUE; }
  186.  
  187. static BOOL CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  188.   if (uMsg == WM_COMMAND) {
  189.     switch (LOWORD(wParam)) {
  190.     case IDOK:
  191.       EndDialog(hwndDlg, 0);
  192.       break;
  193.     case IDC_HOMEPAGE:
  194.       ShellExecute(NULL, NULL, "http://www.math.berkeley.edu/~benrg/huffyuv.html", NULL, NULL, SW_SHOW);
  195.       break;
  196.     case IDC_EMAIL:
  197.       ShellExecute(NULL, NULL, "mailto:mrezaei@sourceforge.net", NULL, NULL, SW_SHOW);
  198.       break;
  199.     }
  200.   }
  201.   return FALSE;
  202. }
  203.  
  204.  
  205. // add a tooltip to a tooltip control, might be buggy, though - bastel
  206. int AddTooltip(HWND tooltip, HWND client, UINT stringid)
  207. {
  208.     HINSTANCE ghThisInstance=(HINSTANCE)GetWindowLong(client, GWL_HINSTANCE);
  209.  
  210.     TOOLINFO                ti;            // struct specifying info about tool in tooltip control
  211.     static unsigned int        uid    = 0;    // for ti initialization
  212.     RECT                    rect;        // for client area coordinates
  213.     TCHAR                    buf[2000];    // a static buffer is sufficent, TTM_ADDTOOL seems to copy it
  214.  
  215.     // load the string manually, passing the id directly to TTM_ADDTOOL truncates the message :(
  216.     if ( !LoadString(ghThisInstance, stringid, buf, 2000) ) return -1;
  217.  
  218.     // get coordinates of the main client area
  219.     GetClientRect(client, &rect);
  220.     
  221.     // initialize members of the toolinfo structure
  222.     ti.cbSize        = sizeof(TOOLINFO);
  223.     ti.uFlags        = TTF_SUBCLASS;
  224.     ti.hwnd            = client;
  225.     ti.hinst        = ghThisInstance;        // not necessary if lpszText is not a resource id
  226.     ti.uId            = uid;
  227.     ti.lpszText        = buf;
  228.  
  229.     // Tooltip control will cover the whole window
  230.     ti.rect.left    = rect.left;    
  231.     ti.rect.top        = rect.top;
  232.     ti.rect.right    = rect.right;
  233.     ti.rect.bottom    = rect.bottom;
  234.     
  235.     // send a addtool message to the tooltip control window
  236.     SendMessage(tooltip, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);    
  237.     return uid++;
  238.  
  239. // create a tooltip control over the entire window area - bastel
  240. HWND CreateTooltip(HWND hwnd)
  241. {
  242.     // initialize common controls
  243.     INITCOMMONCONTROLSEX    iccex;        // struct specifying control classes to register
  244.     iccex.dwICC        = ICC_WIN95_CLASSES;
  245.     iccex.dwSize    = sizeof(INITCOMMONCONTROLSEX);
  246.     InitCommonControlsEx(&iccex);
  247.  
  248.  
  249.     HINSTANCE    ghThisInstance=(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
  250.     HWND        hwndTT;                    // handle to the tooltip control
  251.  
  252.     // create a tooltip window
  253.     hwndTT = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
  254.                             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  255.                             hwnd, NULL, ghThisInstance, NULL);
  256.     
  257.     SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  258.  
  259.     // set some timeouts so tooltips appear fast and stay long (32767 seems to be a limit here)
  260.     SendMessage(hwndTT, TTM_SETDELAYTIME, (WPARAM)(DWORD)TTDT_INITIAL, (LPARAM)10);
  261.     SendMessage(hwndTT, TTM_SETDELAYTIME, (WPARAM)(DWORD)TTDT_AUTOPOP, (LPARAM)30*1000);
  262.  
  263.     return hwndTT;
  264. }
  265.  
  266.  
  267. static BOOL CALLBACK ConfigureDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  268.   if (uMsg == WM_INITDIALOG) {
  269.  
  270.  
  271.     HWND hctlRGBMethod = GetDlgItem(hwndDlg, IDC_RGBMETHOD);
  272.     int rgbmethod = GetPrivateProfileInt("general", "rgbmethod", methodConvertToYUY2, INI_FILE);
  273.     for (int j = 0; j < sizeof(rgb_method_names)/sizeof(rgb_method_names[0]); ++j) {
  274.       SendMessage(hctlRGBMethod, CB_ADDSTRING, 0, (LPARAM)rgb_method_names[j].name);
  275.       if (rgb_method_names[j].method == rgbmethod)
  276.         SendMessage(hctlRGBMethod, CB_SETCURSEL, j, 0);
  277.     }
  278.  
  279.     HWND    hctlMaxLoss    = GetDlgItem(hwndDlg, IDC_MAX_LOSS);
  280.     int        maxLoss            = GetPrivateProfileInt("general", "max_loss", 0, INI_FILE);
  281.     char    temp[12]            = {0};
  282.     bool    dupe                = false;
  283.   int k;
  284.  
  285.     _snprintf(temp, 11, "%d", maxLoss);
  286.     SendMessage(hctlMaxLoss, CB_LIMITTEXT, 11, 0);
  287.     for (k = 0; k < sizeof(max_losses)/sizeof(max_losses[0]); k++) {
  288.         SendMessage(hctlMaxLoss, CB_ADDSTRING, 0, (LPARAM)max_losses[k].name);
  289.         if ( max_losses[k].method==maxLoss ) dupe=true;
  290.     }
  291.     if ( !dupe) SendMessage(hctlMaxLoss, CB_ADDSTRING, 0, (LPARAM)temp);
  292.     SendMessage(hctlMaxLoss, CB_SETCURSEL, SendMessage(hctlMaxLoss, CB_FINDSTRINGEXACT, -1, (LPARAM)temp), 0);
  293.  
  294.  
  295.     CheckDlgButton(hwndDlg, IDC_IS_INTERLACED,
  296.       GetPrivateProfileInt("general", "source_interlaced", false, INI_FILE) ? BST_CHECKED : BST_UNCHECKED);
  297.     CheckDlgButton(hwndDlg, IDC_RGBOUTPUT,
  298.       GetPrivateProfileInt("debug", "rgboutput", false, INI_FILE) ? BST_CHECKED : BST_UNCHECKED);
  299.     CheckDlgButton(hwndDlg, IDC_RGBA,
  300.       GetPrivateProfileInt("general", "enable_rgba", false, INI_FILE) ? BST_CHECKED : BST_UNCHECKED);
  301.     CheckDlgButton(hwndDlg, IDC_SWAPFIELDS,
  302.       GetPrivateProfileInt("debug", "decomp_swap_fields", false, INI_FILE) ? BST_CHECKED : BST_UNCHECKED);
  303.     CheckDlgButton(hwndDlg, IDC_LOG,
  304.       GetPrivateProfileInt("debug", "log", false, INI_FILE) ? BST_CHECKED : BST_UNCHECKED);
  305.     CheckDlgButton(hwndDlg, IDC_FULL_SIZE_BUFFER,
  306.       GetPrivateProfileInt("debug", "full_size_buffer", FULL_SIZE_BUFFER, INI_FILE) ? BST_CHECKED : BST_UNCHECKED);
  307.  
  308.  
  309.     // create a tooltip window and add tooltips - bastel
  310.     HWND hwndTip = CreateTooltip(hwndDlg);
  311.     for (int l=0; item2tip[l].item; l++ )
  312.         AddTooltip(hwndTip, GetDlgItem(hwndDlg, item2tip[l].item),    item2tip[l].tip);
  313.     SendMessage(hwndTip, TTM_SETMAXTIPWIDTH, 0, (LPARAM)(INT)350);    // ah well this is totally wrong but works
  314.   }
  315.  
  316.   else if (uMsg == WM_COMMAND) {
  317.  
  318.     switch (LOWORD(wParam)) {
  319.  
  320.     case IDOK:
  321.       {
  322.         char methodstring[4];
  323.         wsprintf(methodstring, "%d",
  324.           rgb_method_names[SendMessage(GetDlgItem(hwndDlg, IDC_RGBMETHOD), CB_GETCURSEL, 0, 0)].method);
  325.         WritePrivateProfileString("general", "rgbmethod", methodstring, INI_FILE);
  326.       }
  327.       WritePrivateProfileString("general", "source_interlaced",
  328.         (IsDlgButtonChecked(hwndDlg, IDC_IS_INTERLACED) == BST_CHECKED) ? "1" : "0", INI_FILE);
  329.       WritePrivateProfileString("debug", "rgboutput",
  330.         (IsDlgButtonChecked(hwndDlg, IDC_RGBOUTPUT) == BST_CHECKED) ? "1" : NULL, INI_FILE);
  331.       WritePrivateProfileString("general", "enable_rgba",
  332.         (IsDlgButtonChecked(hwndDlg, IDC_RGBA) == BST_CHECKED) ? "1" : NULL, INI_FILE);
  333.       WritePrivateProfileString("debug", "decomp_swap_fields",
  334.         (IsDlgButtonChecked(hwndDlg, IDC_SWAPFIELDS) == BST_CHECKED) ? "1" : "0", INI_FILE);
  335.       WritePrivateProfileString("debug", "log",
  336.         (IsDlgButtonChecked(hwndDlg, IDC_LOG) == BST_CHECKED) ? "1" : "0", INI_FILE);
  337.       WritePrivateProfileString("debug", "full_size_buffer",
  338.         (IsDlgButtonChecked(hwndDlg, IDC_FULL_SIZE_BUFFER) == BST_CHECKED) ? "1" : "0", INI_FILE);
  339.  
  340.         
  341.       // write max loss setting. accept only if numeric and 0 < ft <= 100
  342.         {
  343.             char    temp[12]= {0};
  344.             char*    endp    = 0;
  345.             SendMessage(GetDlgItem(hwndDlg, IDC_MAX_LOSS), WM_GETTEXT, 11, (LPARAM)temp);
  346.             int max_loss    = strtoul(temp, &endp, 10);
  347.             if ( strchr(" \t\r\n", *endp) && max_loss>=0 && max_loss<=100 ) {
  348.                 // could pass old temp, but this way whitespace is removed
  349.                 _snprintf(temp, 11, "%d", max_loss);        
  350.                 WritePrivateProfileString("general", "max_loss", temp, INI_FILE);
  351.             }
  352.       }
  353.  
  354.     case IDCANCEL:
  355.       EndDialog(hwndDlg, 0);
  356.       break;
  357.  
  358.     default:
  359.       return AboutDialogProc(hwndDlg, uMsg, wParam, lParam);    // handle email and home-page buttons
  360.     }
  361.   }
  362.   return FALSE;
  363. }
  364.  
  365. DWORD CodecInst::About(HWND hwnd) {
  366.   DialogBox(hmoduleLocoCodec, MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDialogProc);
  367.   return ICERR_OK;
  368. }
  369.  
  370. DWORD CodecInst::Configure(HWND hwnd) {
  371.   DialogBox(hmoduleLocoCodec, MAKEINTRESOURCE(IDD_CONFIGURE), hwnd, ConfigureDialogProc);
  372.   return ICERR_OK;
  373. }
  374.  
  375.  
  376.  
  377. /********************************************************************
  378. ********************************************************************/
  379.  
  380.  
  381. // we have no state information which needs to be stored
  382.  
  383. DWORD CodecInst::GetState(LPVOID pv, DWORD dwSize) { return 0; }
  384.  
  385. DWORD CodecInst::SetState(LPVOID pv, DWORD dwSize) { return 0; }
  386.  
  387.  
  388. DWORD CodecInst::GetInfo(ICINFO* icinfo, DWORD dwSize) {
  389.   if (icinfo == NULL)
  390.     return sizeof(ICINFO);
  391.  
  392.   if (dwSize < sizeof(ICINFO))
  393.     return 0;
  394.  
  395.   icinfo->dwSize            = sizeof(ICINFO);
  396.   icinfo->fccType           = ICTYPE_VIDEO;
  397.   icinfo->fccHandler        = FOURCC_LOCO;
  398.   icinfo->dwFlags           = 0;
  399.  
  400.   icinfo->dwVersion         = VERSION;
  401.   icinfo->dwVersionICM      = ICVERSION;
  402.   MultiByteToWideChar(CP_ACP, 0, szDescription, -1, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
  403.   MultiByteToWideChar(CP_ACP, 0, szName, -1, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
  404.  
  405.   return sizeof(ICINFO);
  406. }
  407.  
  408.  
  409. /********************************************************************
  410. ********************************************************************/
  411.  
  412.  
  413. struct PrintBitmapType {
  414.   char s[32];
  415.   PrintBitmapType(LPBITMAPINFOHEADER lpbi) {
  416.     if (!lpbi)
  417.       strcpy(s,  "(null)");
  418.     else {
  419.       *(DWORD*)s = lpbi->biCompression;
  420.       s[4] = 0;
  421.       if (!isalnum(s[0]) || !isalnum(s[1]) || !isalnum(s[2]) || !isalnum(s[3]))
  422.         wsprintfA(s, "%x", lpbi->biCompression);
  423.       wsprintfA(strchr(s, 0), ", %d bits", GetBitCount(lpbi));
  424.       if (lpbi->biCompression == FOURCC_LOCO && GetLocoOutputType(lpbi))
  425.         wsprintfA(strchr(s, 0), ", output_type %d", GetLocoOutputType(lpbi));
  426.     }
  427.   }
  428. };
  429.  
  430.  
  431. // fast clipping of values to unsigned char range
  432.  
  433. static unsigned char clip[896];
  434.  
  435. static void InitClip() {
  436.   memset(clip, 0, 320);
  437.   for (int i=0; i<256; ++i) clip[i+320] = i;
  438.   memset(clip+320+256, 255, 320);
  439. }
  440.  
  441. static inline unsigned char Clip(int x)
  442.   { return clip[320 + ((x+0x8000) >> 16)]; }
  443.  
  444.  
  445. /********************************************************************
  446. ********************************************************************/
  447.  
  448.  
  449.  
  450. // 0=unknown, -1=compressed YUY2, -2=compressed RGB, -3=compressed RGBA, 1=YUY2, 2=UYVY, 3=RGB 24-bit, 4=RGB 32-bit
  451. static int GetBitmapType(LPBITMAPINFOHEADER lpbi) {
  452.   if (!lpbi)
  453.     return BITMAP_TYPE_UNKNOWN;
  454.   const int fourcc = lpbi->biCompression;
  455.   if (fourcc == FOURCC_VYUY || fourcc == FOURCC_YUY2)
  456.     return BITMAP_TYPE_YUY2;
  457.   if (fourcc == FOURCC_UYVY)
  458.     return BITMAP_TYPE_UYVY;
  459.   if (fourcc == FOURCC_YV12)
  460.     return BITMAP_TYPE_YV12;
  461.   const int bitcount = GetBitCount(lpbi);
  462.   if (fourcc == 0 || fourcc == ' BID')
  463.     return (bitcount == 24) ? BITMAP_TYPE_RGB : (bitcount == 32) ? BITMAP_TYPE_RGBA : 0;
  464.   if (fourcc == FOURCC_LOCO)
  465.   {
  466.       return GetLocoOutputType(lpbi);
  467.   }
  468.   return 0;
  469. }
  470.  
  471.  
  472. static bool CanCompress(LPBITMAPINFOHEADER lpbiIn) {
  473.   int intype = GetBitmapType(lpbiIn);
  474.   return (intype == BITMAP_TYPE_YUY2 || intype == BITMAP_TYPE_UYVY 
  475.       || intype == BITMAP_TYPE_RGB || intype == BITMAP_TYPE_YV12 || (intype == BITMAP_TYPE_RGBA && AllowRGBA()));
  476. }
  477.  
  478.  
  479. static bool CanCompress(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  480.   if (!lpbiOut) return CanCompress(lpbiIn);
  481.  
  482.   int intype = GetBitmapType(lpbiIn);
  483.   int outtype = GetBitmapType(lpbiOut);
  484.  
  485.   switch (intype) {
  486.     case BITMAP_TYPE_YUY2: case BITMAP_TYPE_UYVY:
  487.       return (outtype == BITMAP_TYPE_COMPRESSED_YUY2);
  488.     case BITMAP_TYPE_RGB:
  489.       return (outtype == BITMAP_TYPE_YUY2 || outtype == BITMAP_TYPE_COMPRESSED_YUY2 
  490.           || outtype == BITMAP_TYPE_COMPRESSED_RGB);
  491.     case BITMAP_TYPE_RGBA:
  492.       return (outtype == BITMAP_TYPE_COMPRESSED_RGBA && AllowRGBA());
  493.     case BITMAP_TYPE_YV12:
  494.       return (outtype == BITMAP_TYPE_COMPRESSED_YV12);
  495.     default:
  496.       return false;
  497.   }
  498. }
  499.  
  500.  
  501. /********************************************************************
  502. ********************************************************************/
  503.  
  504.  
  505.  
  506. #define HUFFTABLE_CLASSIC_YUV ((const unsigned char*)-1)
  507. #define HUFFTABLE_CLASSIC_RGB ((const unsigned char*)-2)
  508. #define HUFFTABLE_CLASSIC_YUV_CHROMA ((const unsigned char*)-3)
  509.  
  510.  
  511.  
  512. DWORD CodecInst::CompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  513.   Msg("CompressQuery: input = %s, output = %s\n", &PrintBitmapType(lpbiIn), &PrintBitmapType(lpbiOut));
  514.   return CanCompress(lpbiIn, lpbiOut) ? ICERR_OK : ICERR_BADFORMAT;
  515. }
  516.  
  517. #define EXTRA_INFO_SIZE        sizeof(int)*4
  518. #define EXTRA_INFO_VERSION    2
  519.  
  520. DWORD CodecInst::CompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  521.   if (!CanCompress(lpbiIn))
  522.     return ICERR_BADFORMAT;
  523.  
  524.   int intype = GetBitmapType(lpbiIn);
  525.  
  526.   bool compress_as_yuy2 = (intype == BITMAP_TYPE_YUY2 || intype == BITMAP_TYPE_UYVY);
  527.   int output_type = 0;
  528.   if (!compress_as_yuy2 && (intype == BITMAP_TYPE_RGB || intype == BITMAP_TYPE_RGBA)) {
  529.     int method = GetPrivateProfileInt("general", "rgbmethod", methodConvertToYUY2, INI_FILE);
  530.     if (method==methodConvertToYUY2)
  531.       {
  532.         compress_as_yuy2 = true;
  533.       }
  534.       else
  535.       {
  536.           if (intype == BITMAP_TYPE_RGB) output_type = BITMAP_TYPE_COMPRESSED_RGB;
  537.           if (intype == BITMAP_TYPE_RGBA) output_type = BITMAP_TYPE_COMPRESSED_RGBA;
  538.       }
  539.   }
  540.  
  541.   if (compress_as_yuy2)
  542.       output_type = BITMAP_TYPE_COMPRESSED_YUY2;
  543.   if (intype == BITMAP_TYPE_YV12) output_type = BITMAP_TYPE_COMPRESSED_YV12;
  544.  
  545.   int total_size = sizeof(BITMAPINFOHEADER)+EXTRA_INFO_SIZE;
  546.   if (!lpbiOut)
  547.     return total_size;
  548.  
  549.   int real_bit_count = (intype==BITMAP_TYPE_RGBA) ? 32 : (compress_as_yuy2 || intype == BITMAP_TYPE_YV12) ? 16 : 24;
  550.   max_loss = GetPrivateProfileInt("general", "max_loss", 0, INI_FILE);
  551.   source_interlaced = GetPrivateProfileInt("general", "source_interlaced", 0, INI_FILE) == 1 ? true : false;
  552.  
  553.   *lpbiOut = *lpbiIn;
  554.   lpbiOut->biSize = total_size;
  555.   lpbiOut->biCompression = FOURCC_LOCO;
  556.   lpbiOut->biClrImportant = lpbiOut->biClrUsed = 0;
  557.   lpbiOut->biPlanes = 1;
  558.   lpbiOut->biBitCount = max(24, real_bit_count);
  559.   int* extra_data = (int*)((unsigned char*)lpbiOut + sizeof(BITMAPINFOHEADER));
  560.   extra_data[0] = EXTRA_INFO_VERSION;
  561.   extra_data[1] = output_type;
  562.   extra_data[2] = max_loss;
  563.   extra_data[3] = source_interlaced ? 1 : 0;
  564.   return ICERR_OK;
  565. }
  566.  
  567.  
  568. const unsigned char* GetEmbeddedHuffmanTable(LPBITMAPINFOHEADER lpbi) {
  569.   if (lpbi->biSize == sizeof(BITMAPINFOHEADER) && !(lpbi->biBitCount&7))
  570.     return lpbi->biBitCount>=24 ? HUFFTABLE_CLASSIC_RGB : HUFFTABLE_CLASSIC_YUV;
  571.   else
  572.     return (const unsigned char*)lpbi + sizeof(BITMAPINFOHEADER) + ((lpbi->biBitCount&7) ? 0 : 4);
  573. }
  574.  
  575.  
  576. DWORD CodecInst::CompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  577.   Msg("CompressBegin: input = %s, output = %s\n", &PrintBitmapType(lpbiIn), &PrintBitmapType(lpbiOut));
  578.  
  579.   if (!CanCompress(lpbiIn, lpbiOut))
  580.     return ICERR_BADFORMAT;
  581.  
  582.   CompressEnd();  // free resources if necessary
  583.  
  584.   int intype = GetBitmapType(lpbiIn);
  585.   int outtype = GetLocoOutputType(lpbiOut);
  586.  
  587.   // load field threshold - bastel
  588.   source_interlaced = GetPrivateProfileInt("general", "source_interlaced", 0, INI_FILE) == 1 ? true : false;
  589.   max_loss = GetPrivateProfileInt("general", "max_loss", 0, INI_FILE);
  590.   Msg("CompressBegin: source interlaced  %s\n",
  591.       source_interlaced ? "yes" : "no");
  592.  
  593.   // allocate buffer if compressing RGB->YUY2->HFYU
  594.   if (outtype == BITMAP_TYPE_COMPRESSED_YUY2 && intype == BITMAP_TYPE_RGB)
  595.     yuy2_buffer = new unsigned char[lpbiIn->biWidth * lpbiIn->biHeight * 2 + 4];
  596.  
  597.   InitClip();
  598.  
  599.   return ICERR_OK;
  600. }
  601.  
  602. DWORD CodecInst::CompressGetSize(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  603.   // Assume 24 bpp worst-case for YUY2 input, 40 bpp for RGB.
  604.   // The actual worst case is 43/51 bpp currently, but this is exceedingly improbable
  605.   // (probably impossible with real captured video)
  606.   // bastel: never say impossible. try to capture static noise with the original huffyuv and be surprised.
  607.   //         virtualdub has a workaround for it. avi_io not. anyway, i don't think it slows down processing.
  608.   //         if you think it does you can still enable the old behaviour. full buffer costs memory, though :)
  609.   int fullsize = GetPrivateProfileInt("debug", "full_size_buffer", FULL_SIZE_BUFFER, INI_FILE);
  610.   return fullsize    ? ((lpbiIn->biWidth * lpbiIn->biHeight * ((GetBitmapType(lpbiIn) <= 2) ? 43 : 51)) + 7) / 8
  611.                     :    lpbiIn->biWidth * lpbiIn->biHeight * ((GetBitmapType(lpbiIn) <= 2) ? 3 : 5);
  612. }
  613.  
  614.  
  615. template<typename T> static inline T* Align8(T* ptr) { return (T*)((unsigned(ptr)+7)&~7); }
  616.  
  617.  
  618. DWORD CodecInst::Compress(ICCOMPRESS* icinfo, DWORD dwSize) {
  619.  
  620.   if (icinfo->lpckid)
  621.     *icinfo->lpckid = FOURCC_LOCO;
  622.   *icinfo->lpdwFlags = AVIIF_KEYFRAME;
  623.  
  624.   int intype = GetBitmapType(icinfo->lpbiInput);
  625.   int outtype = GetLocoOutputType(icinfo->lpbiOutput);
  626.  
  627.   if (outtype < 0) {    // compressing (as opposed to converting RGB->YUY2)
  628.  
  629.  
  630.     unsigned char* in = (unsigned char*)icinfo->lpInput;
  631.     unsigned long* out = (unsigned long*)icinfo->lpOutput;
  632.  
  633.     unsigned long* out_end = out;
  634.  
  635.     if (outtype == BITMAP_TYPE_COMPRESSED_YUY2) {    // compressing to LOCOYUY2 (4:2:2 YUV)
  636.       int rowsize = icinfo->lpbiInput->biWidth * 2;
  637.       int yStep = 1;
  638. #ifdef LATER
  639.       if (icinfo->lpbiInput->biHeight > field_threshold) yStep = 2;    // if image is interlaced, double stride so fields are treated separately
  640. #endif
  641.       unsigned char* yuy2in = in;
  642.  
  643.       if (intype == BITMAP_TYPE_RGB) {    // RGB24->YUY2->LOCOYUY2
  644.         ConvertRGB24toYUY2(in, yuy2_buffer, icinfo->lpbiInput->biWidth, icinfo->lpbiInput->biHeight);
  645.         yuy2in = yuy2_buffer;
  646.       }
  647.       if (intype==BITMAP_TYPE_UYVY) {    // UYVY->LOCOYUY2
  648.           
  649.         // first Y
  650.         out_end = (unsigned long *)loco_codec_compress_lossy(yuy2in, (unsigned char *)out_end, icinfo->lpbiInput->biHeight, rowsize,
  651.               1, 2, 0, yStep, max_loss);
  652.         // then U:
  653.         out_end = (unsigned long *)loco_codec_compress_lossy(yuy2in, (unsigned char *)out_end, icinfo->lpbiInput->biHeight, rowsize,
  654.               0, 4, 0, yStep, max_loss);
  655.         // then V:
  656.         out_end = (unsigned long *)loco_codec_compress_lossy(yuy2in, (unsigned char *)out_end, icinfo->lpbiInput->biHeight, rowsize,
  657.               2, 4, 0, yStep, max_loss);
  658.         
  659.       } else {    // YUY2->HFYU16
  660.         // first Y
  661.         out_end = (unsigned long *)loco_codec_compress_lossy(yuy2in, (unsigned char *)out_end, icinfo->lpbiInput->biHeight, rowsize,
  662.               0, 2, 0, yStep, max_loss);
  663.         // then U:
  664.         out_end = (unsigned long *)loco_codec_compress_lossy(yuy2in, (unsigned char *)out_end, icinfo->lpbiInput->biHeight, rowsize,
  665.               1, 4, 0, yStep, max_loss);
  666.         // then V:
  667.         out_end = (unsigned long *)loco_codec_compress_lossy(yuy2in, (unsigned char *)out_end, icinfo->lpbiInput->biHeight, rowsize,
  668.               3, 4, 0, yStep, max_loss);
  669.         
  670.       }
  671.     }
  672.     else if (outtype == BITMAP_TYPE_COMPRESSED_YV12)    // compressing to LOCO YV12
  673.       {
  674.       int rowsize = icinfo->lpbiInput->biWidth;
  675.       int yStep = 1;
  676.       unsigned long* out_temp;
  677.       // Y:
  678.         out_end = (unsigned long *)loco_codec_compress(in, (unsigned char *)out_end, 
  679.         icinfo->lpbiInput->biHeight, rowsize, 0, 1, 0, yStep);
  680.       out_temp = out_end;
  681.       rowsize = icinfo->lpbiInput->biWidth >> 1;
  682.       // V:
  683.       in += icinfo->lpbiInput->biHeight*icinfo->lpbiInput->biWidth; 
  684.       out_end = (unsigned long *)loco_codec_compress(in,
  685.         (unsigned char *)out_end, icinfo->lpbiInput->biHeight >> 1, rowsize, 0, 1, 0, yStep);
  686.       // U:
  687.       in += (icinfo->lpbiInput->biHeight*icinfo->lpbiInput->biWidth) >> 2; 
  688.       out_end = (unsigned long *)loco_codec_compress(in,
  689.         (unsigned char *)out_end, icinfo->lpbiInput->biHeight >> 1, rowsize, 0, 1, 0, yStep);
  690.     }
  691.     else if (outtype == BITMAP_TYPE_COMPRESSED_RGB) {    // compressing to LOCO RGB24
  692.       int xStep = 3;
  693.       int rowsize = icinfo->lpbiInput->biWidth * xStep;
  694.       int size = rowsize * icinfo->lpbiInput->biHeight;
  695.       int yStep = 1;
  696. #ifdef LATER
  697.       if (icinfo->lpbiInput->biHeight > field_threshold) stride *= 2;    // if image is interlaced, double stride so fields are treated separately
  698. #endif
  699.  
  700.       out_end = (unsigned long *)loco_codec_compress_lossy(in, (unsigned char *)out_end, 
  701.         icinfo->lpbiInput->biHeight, rowsize, 0, xStep, 0, yStep, max_loss);
  702.  
  703.       out_end = (unsigned long *)loco_codec_compress_lossy(in, (unsigned char *)out_end, 
  704.         icinfo->lpbiInput->biHeight, rowsize, 1, xStep, 0, yStep, max_loss);
  705.  
  706.       out_end = (unsigned long *)loco_codec_compress_lossy(in, (unsigned char *)out_end, 
  707.         icinfo->lpbiInput->biHeight, rowsize, 2, xStep, 0, yStep, max_loss);
  708.  
  709.  
  710.     }
  711.     else if (outtype == BITMAP_TYPE_COMPRESSED_RGBA) {    // compressing to LOCO RGBA
  712.       int xStep = 4;
  713.       int rowsize = icinfo->lpbiInput->biWidth * xStep;
  714.       int size = rowsize * icinfo->lpbiInput->biHeight;
  715.       int yStep = 1;
  716. #ifdef LATER
  717.       if (icinfo->lpbiInput->biHeight > field_threshold) stride *= 2;    // if image is interlaced, double stride so fields are treated separately
  718. #endif
  719.       out_end = (unsigned long *)loco_codec_compress_lossy(in, (unsigned char *)out_end, 
  720.         icinfo->lpbiInput->biHeight, rowsize, 0, xStep, 0, yStep, max_loss);
  721.  
  722.       out_end = (unsigned long *)loco_codec_compress_lossy(in, (unsigned char *)out_end, 
  723.         icinfo->lpbiInput->biHeight, rowsize, 1, xStep, 0, yStep, max_loss);
  724.  
  725.       out_end = (unsigned long *)loco_codec_compress_lossy(in, (unsigned char *)out_end, 
  726.         icinfo->lpbiInput->biHeight, rowsize, 2, xStep, 0, yStep, max_loss);
  727.  
  728.       out_end = (unsigned long *)loco_codec_compress_lossy(in, (unsigned char *)out_end, 
  729.         icinfo->lpbiInput->biHeight, rowsize, 3, xStep, 0, yStep, max_loss);
  730.     }
  731.     icinfo->lpbiOutput->biSizeImage = DWORD(out_end) - DWORD(out);
  732.     return ICERR_OK;
  733.   }
  734.   else if (outtype == 1) {    // RGB24->YUY2
  735.     ConvertRGB24toYUY2((unsigned char*)icinfo->lpInput, (unsigned char*)icinfo->lpOutput,
  736.       icinfo->lpbiInput->biWidth, icinfo->lpbiInput->biHeight);
  737.     icinfo->lpbiOutput->biSizeImage = (icinfo->lpbiOutput->biWidth * icinfo->lpbiOutput->biHeight * GetBitCount(icinfo->lpbiOutput)) >> 3;
  738.     return ICERR_OK;
  739.   }
  740.   else
  741.     return ICERR_BADFORMAT;
  742. }
  743.  
  744.  
  745. void CodecInst::ConvertRGB24toYUY2(const unsigned char* src, unsigned char* dst, int width, int height) {
  746.   const int cyb = int(0.114*219/255*65536+0.5);
  747.   const int cyg = int(0.587*219/255*65536+0.5);
  748.   const int cyr = int(0.299*219/255*65536+0.5);
  749.  
  750.   for (int row = 0; row < height; ++row) {
  751.     const unsigned char* rgb = src + width * 3 * (height-1-row);
  752.     unsigned char* yuv = dst + width * 2 * row;
  753.     for (int col = 0; col < width; col += 2) {
  754.       // y1 and y2 can't overflow
  755.       int y1 = (cyb*rgb[0] + cyg*rgb[1] + cyr*rgb[2] + 0x108000) >> 16;
  756.       yuv[0] = y1;
  757.       int y2 = (cyb*rgb[3] + cyg*rgb[4] + cyr*rgb[5] + 0x108000) >> 16;
  758.       yuv[2] = y2;
  759.       int scaled_y = (y1+y2 - 32) * int(255.0/219.0*32768+0.5);
  760.       int b_y = ((rgb[0]+rgb[3]) << 15) - scaled_y;
  761.       yuv[1] = Clip((b_y >> 10) * int(1/2.018*1024+0.5) + 0x800000);  // u
  762.       int r_y = ((rgb[2]+rgb[5]) << 15) - scaled_y;
  763.       yuv[3] = Clip((r_y >> 10) * int(1/1.596*1024+0.5) + 0x800000);  // v
  764.       yuv += 4;
  765.       rgb += 6;
  766.     }
  767.   }
  768. }
  769.  
  770.  
  771. DWORD CodecInst::CompressEnd() {
  772.   if (yuy2_buffer) {
  773.     delete[] yuy2_buffer;
  774.     yuy2_buffer = 0;
  775.   }
  776.   if (median_buffer) {
  777.     delete[] median_buffer;
  778.     median_buffer = 0;
  779.   }
  780.   if (rgb_buffer) {
  781.     delete[] rgb_buffer;
  782.     rgb_buffer = 0;
  783.   }
  784.   return ICERR_OK;
  785. }
  786.  
  787.  
  788. /********************************************************************
  789. ********************************************************************/
  790.  
  791. static bool CanDecompress(LPBITMAPINFOHEADER lpbiIn) {
  792.   int intype = GetBitmapType(lpbiIn);
  793.   if (intype < 0) // one of our compressed formats
  794.     return true;
  795.   else
  796.     return (intype == BITMAP_TYPE_YUY2 || intype == BITMAP_TYPE_UYVY);
  797. }
  798.  
  799.  
  800. static bool CanDecompress(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  801.   if (!lpbiOut)
  802.     return CanDecompress(lpbiIn);
  803.  
  804.   // ccesp sets negative output height with YUY2 - a request for a top-down bitmap.
  805.   // but what it really wants is a bottom-up bitmap. this is fine with huffyuv, so we change it. - bastel
  806.   lpbiOut->biHeight = IgnoreTopDown() ? abs(lpbiOut->biHeight) : lpbiOut->biHeight;
  807.  
  808.   Msg("CanDecompress %d %d %d %d\n",lpbiOut->biWidth,lpbiIn->biWidth ,lpbiOut->biHeight,lpbiIn->biHeight);
  809.   // must be 1:1 (no stretching)
  810.   if (lpbiOut && (lpbiOut->biWidth != lpbiIn->biWidth || lpbiOut->biHeight != lpbiIn->biHeight))
  811.     return false;
  812.  
  813.   int intype = GetBitmapType(lpbiIn);
  814.   int outtype = GetBitmapType(lpbiOut);
  815.  
  816.   Msg("CanDecompress: input = %d, output = %d\n", intype,outtype);
  817.  
  818.   switch (intype) {
  819.     case BITMAP_TYPE_COMPRESSED_YUY2:
  820.       // YUY2, RGB-24, RGB-32 output for compressed YUY2
  821.       return (outtype == BITMAP_TYPE_YUY2 || outtype == BITMAP_TYPE_RGB);
  822.     case BITMAP_TYPE_COMPRESSED_RGB: case BITMAP_TYPE_YUY2: case BITMAP_TYPE_UYVY:
  823.       // RGB-24, RGB-32 output only for YUY2/UYVY and compressed RGB
  824.       return (outtype == BITMAP_TYPE_RGB);
  825.     case BITMAP_TYPE_COMPRESSED_RGBA:
  826.       // RGB-32 output for compressed RGBA
  827.       return (outtype == BITMAP_TYPE_RGBA);
  828.     case BITMAP_TYPE_COMPRESSED_YV12:
  829.       return (outtype == BITMAP_TYPE_YV12 || outtype == BITMAP_TYPE_YUY2
  830.         || outtype == BITMAP_TYPE_RGB );
  831.     default:
  832.       return false;
  833.   }
  834. }
  835.  
  836. /********************************************************************
  837. ********************************************************************/
  838.  
  839.  
  840. DWORD CodecInst::DecompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  841.   Msg("DecompressQuery: input = %s, output = %s\n", &PrintBitmapType(lpbiIn), &PrintBitmapType(lpbiOut));
  842.   return CanDecompress(lpbiIn, lpbiOut) ? ICERR_OK : ICERR_BADFORMAT;
  843. }
  844.  
  845.  
  846. // This function should return "the output format which preserves the most
  847. // information."  However, I now provide the option to return RGB format
  848. // instead, since some programs treat the default format as the ONLY format.
  849.  
  850. DWORD CodecInst::DecompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  851.  
  852.   Msg("DecompressGetFormat: input = %s, output = %s\n", &PrintBitmapType(lpbiIn), &PrintBitmapType(lpbiOut));
  853.   // if lpbiOut == NULL, then return the size required to hold an output format struct
  854.   if (lpbiOut == NULL)
  855.     return sizeof(BITMAPINFOHEADER);
  856.  
  857.   if (!CanDecompress(lpbiIn))
  858.     return ICERR_BADFORMAT;
  859.  
  860.   *lpbiOut = *lpbiIn;
  861.   lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
  862.   lpbiOut->biPlanes = 1;
  863.  
  864.   int intype = GetBitmapType(lpbiIn);
  865.   if (intype == BITMAP_TYPE_COMPRESSED_RGBA) {
  866.     lpbiOut->biBitCount = 32;   // RGBA
  867.     lpbiOut->biCompression = 0;
  868.     lpbiOut->biSizeImage = lpbiIn->biWidth * lpbiIn->biHeight * 4;
  869.   } else if (intype == BITMAP_TYPE_COMPRESSED_RGB || intype == BITMAP_TYPE_YUY2 || 
  870.       intype == BITMAP_TYPE_UYVY || SuggestRGB()) {
  871.     lpbiOut->biBitCount = 24;   // RGB
  872.     lpbiOut->biCompression = 0;
  873.     lpbiOut->biSizeImage = lpbiIn->biWidth * lpbiIn->biHeight * 3;
  874.   } else if (intype == BITMAP_TYPE_COMPRESSED_YV12) {
  875.     lpbiOut->biBitCount = 12;       // YV12
  876.     lpbiOut->biCompression = FOURCC_YV12;
  877.     lpbiOut->biSizeImage = lpbiIn->biWidth * lpbiIn->biHeight * 3/2;
  878.   }
  879.   else  {
  880.     lpbiOut->biBitCount = 16;       // YUY2
  881.     lpbiOut->biCompression = FOURCC_YUY2;
  882.     lpbiOut->biSizeImage = lpbiIn->biWidth * lpbiIn->biHeight * 2;
  883.   }
  884.   Msg("DecompressGetFormat: input = %s, output = %s\n", &PrintBitmapType(lpbiIn), &PrintBitmapType(lpbiOut));
  885.  
  886.   return ICERR_OK;
  887. }
  888.  
  889.  
  890.  
  891.  
  892. DWORD CodecInst::DecompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  893.   Msg("DecompressBegin: input = %s, output = %s\n", &PrintBitmapType(lpbiIn), &PrintBitmapType(lpbiOut));
  894.  
  895.   DecompressEnd();  // free resources if necessary
  896.  
  897.   if (!CanDecompress(lpbiIn, lpbiOut))
  898.     return ICERR_BADFORMAT;
  899.  
  900.   // ccesp keeps the in CanDecompress() overwritten output height atm,
  901.   // so we are gonna have postive height in CodecInst::Decompress().
  902.   // but to be sure it is stored in the instance here and accessed in CodecInst::Decompress() - bastel
  903.   ignoretopdown = IgnoreTopDown();
  904.   Msg("DecompressBegin: Top-Down output requests are %s.\n",
  905.       ignoretopdown ? "converted to bottum-up" : "processed normal");
  906.  
  907.   decompressing = true;
  908.  
  909.   int intype = GetBitmapType(lpbiIn);
  910.   int outtype = GetBitmapType(lpbiOut);
  911.  
  912.   int sourceInterlacedInt = *((int*)((char*)(lpbiIn) + sizeof(BITMAPINFOHEADER) + sizeof(int)*3));
  913.  
  914.   source_interlaced = (sourceInterlacedInt == 1) ? true : false;
  915.   Msg("DecompressBegin: source interlaced =  %s\n",
  916.       source_interlaced ? "yes" : "no");
  917.  
  918.   // allocate buffer if decompressing HFYU->YUY2->RGB
  919.   if ((intype == BITMAP_TYPE_COMPRESSED_YUY2 || intype == BITMAP_TYPE_COMPRESSED_YV12)
  920.       && (outtype == BITMAP_TYPE_RGB || outtype == BITMAP_TYPE_RGBA))
  921.     decompress_yuy2_buffer = new unsigned char[lpbiIn->biWidth * lpbiIn->biHeight * 2];
  922.  
  923.   InitClip();
  924.  
  925.   swapfields = !!GetPrivateProfileInt("debug", "decomp_swap_fields", false, INI_FILE);
  926.  
  927.   return ICERR_OK;
  928. }
  929.  
  930.  
  931. static DWORD ConvertYUY2toRGB(LPBITMAPINFOHEADER lpbiOutput, void* _src, void* _dst) {
  932.   const unsigned char* src = (const unsigned char*)_src;
  933.   unsigned char* dst = (unsigned char*)_dst;
  934.   int stride = lpbiOutput->biWidth * 2;
  935.   const unsigned char* src_end = src + stride*lpbiOutput->biHeight;
  936.   if (lpbiOutput->biBitCount == 32)
  937.     mmx_YUY2toRGB32(src, dst, src_end, stride);
  938.   else
  939.     mmx_YUY2toRGB24(src, dst, src_end, stride);
  940.   return ICERR_OK;
  941. }
  942.  
  943. static DWORD ConvertUYVYtoRGB(LPBITMAPINFOHEADER lpbiOutput, void* _src, void* _dst) {
  944.   const unsigned char* src = (const unsigned char*)_src;
  945.   unsigned char* dst = (unsigned char*)_dst;
  946.   int stride = lpbiOutput->biWidth * 2;
  947.   const unsigned char* src_end = src + stride*lpbiOutput->biHeight;
  948.   if (lpbiOutput->biBitCount == 32)
  949.     mmx_UYVYtoRGB32(src, dst, src_end, stride);
  950.   else
  951.     mmx_UYVYtoRGB24(src, dst, src_end, stride);
  952.   return ICERR_OK;
  953. }
  954.  
  955.  
  956. static void ExpandYV12toYUY2Interlaced(LPBITMAPINFOHEADER lpbiOutput, void* src) {
  957.  
  958.   int i,j;
  959.   int rowsize = lpbiOutput->biWidth << 1;
  960.   unsigned char *dest_row;
  961.   unsigned char *src_row;
  962.  
  963.   i = lpbiOutput->biHeight-1;
  964.   dest_row = (unsigned char *) src;
  965.   dest_row += rowsize * (i); // this is odd.
  966.   src_row = (unsigned char *) src;
  967.   src_row += rowsize * ((i >> 1) & (~1));
  968.   // copy the last 2 lines. they can't be averaged.
  969.   for(j=1;j<rowsize;j+=2)
  970.   {
  971.     dest_row[j] = src_row[j];
  972.   }
  973.   dest_row -= rowsize;
  974.   src_row -= rowsize;
  975.   for(j=1;j<rowsize;j+=2)
  976.   {
  977.     dest_row[j] = src_row[j];
  978.   }
  979.  
  980.   dest_row -= rowsize;
  981.   dest_row -= rowsize;
  982.  
  983.   for(i=lpbiOutput->biHeight-4;i > 1;i-=4)
  984.   {
  985.     for(j=1;j<rowsize;j+=2)
  986.     {
  987.       dest_row[j] = dest_row[j - (rowsize << 1)] = src_row[j+rowsize]; 
  988.       dest_row[j+rowsize] = dest_row[j-rowsize] = src_row[j];
  989.     }
  990.     dest_row -= rowsize << 2;
  991.     src_row -= rowsize;
  992.     src_row -= rowsize;
  993.   }
  994.  
  995.  
  996. }
  997.  
  998. static void ExpandYV12toYUY2(LPBITMAPINFOHEADER lpbiOutput, void* src) {
  999.  
  1000.   int i,j;
  1001.   int rowsize = lpbiOutput->biWidth << 1;
  1002.   unsigned char *dest_row;
  1003.   unsigned char *src_row;
  1004.  
  1005.   i = lpbiOutput->biHeight-1;
  1006.   dest_row = (unsigned char *) src;
  1007.   dest_row += rowsize * (i); // this is odd.
  1008.   src_row = (unsigned char *) src;
  1009.   src_row += rowsize * (i >> 1);
  1010.  
  1011.   for(i=lpbiOutput->biHeight-1;i > 0;i-=2)
  1012.   {
  1013.     for(j=1;j<rowsize;j+=2)
  1014.     {
  1015.       dest_row[j] = dest_row[j - rowsize] = src_row[j]; 
  1016.     }
  1017.     dest_row -= rowsize << 1;
  1018.     src_row -= rowsize;
  1019.   }
  1020.  
  1021. }
  1022.  
  1023. DWORD CodecInst::Decompress(ICDECOMPRESS* icinfo, DWORD dwSize) {
  1024.  
  1025.   // If you insert a Huffyuv-compressed AVI to a Premiere project and then
  1026.   // drag it on to the timeline, the following dialogue occurs:
  1027.   //
  1028.   // 1. Premiere calls ICDecompressBegin, asking Huffyuv to decompress
  1029.   //    to a bitmap with different dimensions than the compressed frame.
  1030.   //
  1031.   // 2. Huffyuv can't resize, so it returns ICERR_BADFORMAT.
  1032.   //
  1033.   // 3. Premiere calls ICDecompress without making another call to
  1034.   //    ICDecompressBegin.
  1035.   //
  1036.   // Therefore I now check for this case and compensate for Premiere's
  1037.   // negligence by making the DecompressBegin call myself.
  1038.  
  1039.   if (!decompressing) {
  1040.     DWORD retval = DecompressBegin(icinfo->lpbiInput, icinfo->lpbiOutput);
  1041.     if (retval != ICERR_OK)
  1042.       return retval;
  1043.   }
  1044.  
  1045.   // we change a top-down output request to a bottom-up one here. - bastel
  1046.   // (imho it should be possible to always do this, this code should never be reached with a negative height)
  1047.   if ( ignoretopdown ) icinfo->lpbiOutput->biHeight = abs(icinfo->lpbiOutput->biHeight);
  1048.  
  1049.   icinfo->lpbiOutput->biSizeImage = (icinfo->lpbiOutput->biWidth * icinfo->lpbiOutput->biHeight * icinfo->lpbiOutput->biBitCount) >> 3;
  1050.   int maxLoss = *((int*)((char*)(icinfo->lpbiInput) + sizeof(BITMAPINFOHEADER) + sizeof(int)*2));
  1051.   int extraVersion = *((int*)((char*)(icinfo->lpbiInput) + sizeof(BITMAPINFOHEADER)));
  1052.   if (extraVersion == 1) maxLoss = 0;
  1053.  
  1054.   int intype = GetBitmapType(icinfo->lpbiInput);
  1055.   if (intype < 0) {
  1056.     int outtype = GetBitmapType(icinfo->lpbiOutput);
  1057.  
  1058.     unsigned char* in = (unsigned char*)icinfo->lpInput;
  1059.     unsigned char* out = (unsigned char*)icinfo->lpOutput;
  1060.     unsigned char* in_end = in;
  1061.     unsigned char* out_end = out;
  1062.  
  1063.     if (intype == BITMAP_TYPE_COMPRESSED_YUY2) {   // decompressing LOCO YUY2
  1064.       int rowsize = icinfo->lpbiOutput->biWidth * 2;
  1065.       int yStep = 1;
  1066. #ifdef LATER
  1067.       if (icinfo->lpbiOutput->biHeight > field_threshold) stride *= 2;      // if image is interlaced, double stride so fields are treated separately
  1068. #endif
  1069.  
  1070.       unsigned char* yuy2 = (outtype == BITMAP_TYPE_RGB || outtype == BITMAP_TYPE_RGBA) ? decompress_yuy2_buffer : out;
  1071.     //memset((void *) yuy2, 128, icinfo->lpbiOutput->biHeight*icinfo->lpbiOutput->biWidth*2);
  1072.  
  1073.       // first Y
  1074.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)yuy2, icinfo->lpbiOutput->biHeight, rowsize,
  1075.             0, 2, 0, yStep, maxLoss);
  1076.       // then U:
  1077.  
  1078.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)yuy2, icinfo->lpbiInput->biHeight, rowsize,
  1079.             1, 4, 0, yStep, maxLoss);
  1080.  
  1081.   // then V:
  1082.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)yuy2, icinfo->lpbiInput->biHeight, rowsize,
  1083.             3, 4, 0, yStep, maxLoss);
  1084.  
  1085.       if (outtype == BITMAP_TYPE_RGB || outtype == BITMAP_TYPE_RGBA)    // LOCO YUY2->RGB
  1086.         ConvertYUY2toRGB(icinfo->lpbiOutput, yuy2, out);
  1087.     }
  1088.     else if (intype == BITMAP_TYPE_COMPRESSED_YV12)  // decompressing LOCO YV12
  1089.     {
  1090.       if (outtype == BITMAP_TYPE_YV12)
  1091.       {
  1092.         int rowsize = icinfo->lpbiOutput->biWidth;
  1093.         int yStep = 1;
  1094.         // first Y
  1095.         in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)out_end, icinfo->lpbiOutput->biHeight, rowsize,
  1096.               0, 1, 0, yStep, maxLoss);
  1097.  
  1098.         // then U:
  1099.         out_end += rowsize*icinfo->lpbiInput->biHeight;
  1100.         rowsize = icinfo->lpbiInput->biWidth >> 1;
  1101.  
  1102.         in_end = (unsigned char *)loco_codec_decompress(in_end, 
  1103.           (unsigned char *)out_end, icinfo->lpbiInput->biHeight >> 1, rowsize, 0, 1, 0, yStep, maxLoss);
  1104.  
  1105.         out_end += (rowsize*icinfo->lpbiInput->biHeight) >> 1;
  1106.  
  1107.         // then V:
  1108.         in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)out_end, 
  1109.           icinfo->lpbiInput->biHeight >> 1, rowsize, 0, 1, 0, yStep, maxLoss);
  1110.         #ifdef GREY
  1111.           memset(out+icinfo->lpbiOutput->biWidth*icinfo->lpbiInput->biHeight,128,(rowsize*icinfo->lpbiInput->biHeight)* sizeof(char));
  1112.         #endif
  1113.       }
  1114.       else if (outtype == BITMAP_TYPE_YUY2 || outtype == BITMAP_TYPE_RGB)
  1115.       {
  1116.         int rowsize = icinfo->lpbiOutput->biWidth << 1;
  1117.         int yStep = 1;
  1118.         // first Y
  1119.         unsigned char* yuy2 = (outtype == BITMAP_TYPE_RGB || outtype == BITMAP_TYPE_RGBA) ? decompress_yuy2_buffer : out;
  1120.   
  1121.         in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)yuy2, 
  1122.             icinfo->lpbiOutput->biHeight, rowsize, 0, 2, 0, yStep, maxLoss);
  1123.  
  1124.         // then V:
  1125.         in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)yuy2, 
  1126.             icinfo->lpbiOutput->biHeight >> 1, rowsize, 3, 4, 0, yStep, maxLoss);
  1127.         
  1128.         // then U:
  1129.         in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)yuy2, 
  1130.             icinfo->lpbiOutput->biHeight >> 1, rowsize, 1, 4, 0, yStep, maxLoss);
  1131.  
  1132.         if (source_interlaced) ExpandYV12toYUY2Interlaced(icinfo->lpbiOutput, yuy2);
  1133.         else ExpandYV12toYUY2(icinfo->lpbiOutput, yuy2);
  1134.  
  1135.         if (outtype == BITMAP_TYPE_RGB || outtype == BITMAP_TYPE_RGBA)    // LOCO YUY2->RGB
  1136.           ConvertYUY2toRGB(icinfo->lpbiOutput, yuy2, out);
  1137.       }
  1138.     }
  1139.     else if (intype == BITMAP_TYPE_COMPRESSED_RGB) { // LOCO RGB24
  1140.       int rowsize = icinfo->lpbiOutput->biWidth * 3;
  1141.       int yStep = 1;
  1142.  
  1143.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)out_end, 
  1144.         icinfo->lpbiOutput->biHeight, rowsize, 0, 3, 0, yStep, maxLoss);
  1145.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)out_end, 
  1146.         icinfo->lpbiOutput->biHeight, rowsize, 1, 3, 0, yStep, maxLoss);
  1147.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)out_end, 
  1148.         icinfo->lpbiOutput->biHeight, rowsize, 2, 3, 0, yStep, maxLoss);
  1149.     }
  1150.     else if (intype == BITMAP_TYPE_COMPRESSED_RGBA) {    // LOCO RGB32
  1151.       int rowsize = icinfo->lpbiOutput->biWidth * 4;
  1152.       int yStep = 1;
  1153.  
  1154.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)out_end, 
  1155.         icinfo->lpbiOutput->biHeight, rowsize, 0, 4, 0, yStep, maxLoss);
  1156.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)out_end, 
  1157.         icinfo->lpbiOutput->biHeight, rowsize, 1, 4, 0, yStep, maxLoss);
  1158.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)out_end, 
  1159.         icinfo->lpbiOutput->biHeight, rowsize, 2, 4, 0, yStep, maxLoss);
  1160.       in_end = (unsigned char *)loco_codec_decompress(in_end, (unsigned char *)out_end, 
  1161.         icinfo->lpbiOutput->biHeight, rowsize, 3, 4, 0, yStep, maxLoss);
  1162.     }
  1163.  
  1164.     if (swapfields && source_interlaced)
  1165.       asm_SwapFields(out, out+icinfo->lpbiOutput->biSizeImage,
  1166.        (icinfo->lpbiOutput->biWidth * icinfo->lpbiOutput->biBitCount) >> 3);
  1167.  
  1168.     return ICERR_OK;
  1169.   }
  1170.   else if (intype == BITMAP_TYPE_YUY2) {   // YUY2->RGB
  1171.     return ConvertYUY2toRGB(icinfo->lpbiOutput, icinfo->lpInput, icinfo->lpOutput);
  1172.   }
  1173.   else if (intype == BITMAP_TYPE_UYVY) {   // UYVY->RGB
  1174.     return ConvertUYVYtoRGB(icinfo->lpbiOutput, icinfo->lpInput, icinfo->lpOutput);
  1175.   }
  1176.   else
  1177.     return ICERR_BADFORMAT;
  1178. }
  1179.  
  1180.  
  1181. // palette-mapped output only
  1182. DWORD CodecInst::DecompressGetPalette(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
  1183.   return ICERR_BADFORMAT;
  1184. }
  1185.  
  1186.  
  1187. DWORD CodecInst::DecompressEnd() {
  1188.   if (decompress_yuy2_buffer) {
  1189.     delete[] decompress_yuy2_buffer;
  1190.     decompress_yuy2_buffer = 0;
  1191.   }
  1192.   decompressing = false;
  1193.   return ICERR_OK;
  1194. }
  1195.  
  1196.  
  1197.