📄 huffyuv.cpp
字号:
//
// Huffyuv v2.1.1, by Ben Rudiak-Gould.
// http://www.math.berkeley.edu/~benrg/huffyuv.html
//
// Based on MSYUV sample code, which is:
// Copyright (c) 1993 Microsoft Corporation.
// All Rights Reserved.
//
// Changes copyright 2000 Ben Rudiak-Gould, and distributed under
// the terms of the GNU General Public License, v2 or later. See
// http://www.gnu.org/copyleft/gpl.html.
//
// I edit these files in 10-point Verdana, a proportionally-spaced font.
// You may notice formatting oddities if you use a monospaced font.
//
#include "huffyuv.h"
#include "huffyuv_a.h"
#include "resource.h"
#include <crtdbg.h>
TCHAR szDescription[] = TEXT("Huffyuv v2.1.1");
TCHAR szName[] = TEXT("Huffyuv");
#define VERSION 0x00020001 // 2.1
/********************************************************************
********************************************************************/
// these tables are generated at runtime from the data in tables.cpp
unsigned char encode1_shift[256];
unsigned encode1_add_shifted[256];
unsigned char encode2_shift[256];
unsigned encode2_add_shifted[256];
unsigned char encode3_shift[256];
unsigned encode3_add_shifted[256];
unsigned char decode1_shift[256];
unsigned char decode2_shift[256];
unsigned char decode3_shift[256];
DecodeTable decode1, decode2, decode3;
CodecInst *encode_table_owner, *decode_table_owner;
/********************************************************************
********************************************************************/
void Msg(const char fmt[], ...) {
static int debug = GetPrivateProfileInt("debug", "log", 0, "huffyuv.ini");
if (!debug) return;
DWORD written;
char buf[2000];
va_list val;
va_start(val, fmt);
wvsprintf(buf, fmt, val);
const COORD _80x50 = {80,50};
static BOOL startup = (AllocConsole(), SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), _80x50));
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), buf, lstrlen(buf), &written, 0);
}
int AppFlags() {
static int flags = -1;
if (flags < 0) {
flags = 0;
TCHAR apppath[MAX_PATH];
if (GetModuleFileName(NULL, apppath, MAX_PATH)) {
TCHAR* appname = strrchr(apppath, '\\');
appname = appname ? appname+1 : apppath;
Msg("App name is %s; ", appname);
if (!lstrcmpi(appname, TEXT("premiere.exe")))
flags = 1;
if (!lstrcmpi(appname, TEXT("veditor.exe")))
flags = 1;
if (!lstrcmpi(appname, TEXT("avi2mpg2_vfw.exe")))
flags = 1;
if (!lstrcmpi(appname, TEXT("bink.exe")))
flags = 1;
if (!lstrcmpi(appname, TEXT("afterfx.exe")))
flags = 2;
Msg("flags=%d\n", flags);
}
}
return flags;
}
bool SuggestRGB() {
return !!GetPrivateProfileInt("debug", "rgboutput", AppFlags()&1, "huffyuv.ini");
}
bool AllowRGBA() {
return !!GetPrivateProfileInt("general", "enable_rgba", AppFlags()&2, "huffyuv.ini");
}
/********************************************************************
********************************************************************/
CodecInst* Open(ICOPEN* icinfo) {
if (icinfo && icinfo->fccType != ICTYPE_VIDEO)
return NULL;
CodecInst* pinst = new CodecInst();
if (icinfo) icinfo->dwError = pinst ? ICERR_OK : ICERR_MEMORY;
return pinst;
}
DWORD Close(CodecInst* pinst) {
// delete pinst; // this caused problems when deleting at app close time
return 1;
}
/********************************************************************
********************************************************************/
enum {
methodLeft=0, methodGrad=1, methodMedian=2,
methodConvertToYUY2=-1, methodOld=-2,
flagDecorrelate=64
};
int ConvertOldMethod(int bitcount) {
switch (bitcount&7) {
case 1: return methodLeft;
case 2: return methodLeft|flagDecorrelate;
case 3: return (bitcount>=24) ? methodGrad+flagDecorrelate : methodGrad;
case 4: return methodMedian;
default: return methodOld;
}
}
static inline int GetMethod(LPBITMAPINFOHEADER lpbi) {
if (lpbi->biCompression == FOURCC_HFYU) {
if (lpbi->biBitCount & 7)
return ConvertOldMethod(lpbi->biBitCount);
else if (lpbi->biSize > sizeof(BITMAPINFOHEADER))
return *((unsigned char*)lpbi + sizeof(BITMAPINFOHEADER));
}
return methodOld;
}
static inline int GetBitCount(LPBITMAPINFOHEADER lpbi) {
if (lpbi->biCompression == FOURCC_HFYU && lpbi->biSize > sizeof(BITMAPINFOHEADER)+1) {
int bpp_override = *((char*)lpbi + sizeof(BITMAPINFOHEADER) + 1);
if (bpp_override)
return bpp_override;
}
return lpbi->biBitCount;
}
struct MethodName { int method; const char* name; };
MethodName yuv_method_names[] = {
{ methodLeft, "Predict left (fastest)" },
{ methodGrad, "Predict gradient" },
{ methodMedian, "Predict median (best)" }
};
MethodName rgb_method_names[] = {
{ methodLeft, "Predict left/no decorr. (fastest)" },
{ methodLeft+flagDecorrelate, "Predict left" },
{ methodGrad+flagDecorrelate, "Predict gradient (best)" },
{ methodConvertToYUY2, "<-- Convert to YUY2" }
};
bool IsLegalMethod(int method, bool rgb) {
if (rgb) {
return (method == methodOld || method == methodLeft
|| method == methodLeft+flagDecorrelate || method == methodGrad+flagDecorrelate);
}
else {
return (method == methodOld || method == methodLeft
|| method == methodGrad || method == methodMedian);
}
}
/********************************************************************
********************************************************************/
BOOL CodecInst::QueryAbout() { return TRUE; }
static BOOL CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_COMMAND) {
switch (LOWORD(wParam)) {
case IDOK:
EndDialog(hwndDlg, 0);
break;
case IDC_HOMEPAGE:
ShellExecute(NULL, NULL, "http://www.math.berkeley.edu/~benrg/huffyuv.html", NULL, NULL, SW_SHOW);
break;
case IDC_EMAIL:
ShellExecute(NULL, NULL, "mailto:benrg@math.berkeley.edu", NULL, NULL, SW_SHOW);
break;
}
}
return FALSE;
}
DWORD CodecInst::About(HWND hwnd) {
DialogBox(hmoduleHuffyuv, MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDialogProc);
return ICERR_OK;
}
static BOOL CALLBACK ConfigureDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_INITDIALOG) {
HWND hctlYUY2Method = GetDlgItem(hwndDlg, IDC_YUY2METHOD);
int yuy2method = GetPrivateProfileInt("general", "yuy2method", methodMedian, "huffyuv.ini");
for (int i = 0; i < sizeof(yuv_method_names)/sizeof(yuv_method_names[0]); ++i) {
SendMessage(hctlYUY2Method, CB_ADDSTRING, 0, (LPARAM)yuv_method_names[i].name);
if (yuv_method_names[i].method == yuy2method)
SendMessage(hctlYUY2Method, CB_SETCURSEL, i, 0);
}
HWND hctlRGBMethod = GetDlgItem(hwndDlg, IDC_RGBMETHOD);
int rgbmethod = GetPrivateProfileInt("general", "rgbmethod", methodGrad+flagDecorrelate, "huffyuv.ini");
for (int j = 0; j < sizeof(rgb_method_names)/sizeof(rgb_method_names[0]); ++j) {
SendMessage(hctlRGBMethod, CB_ADDSTRING, 0, (LPARAM)rgb_method_names[j].name);
if (rgb_method_names[j].method == rgbmethod)
SendMessage(hctlRGBMethod, CB_SETCURSEL, j, 0);
}
CheckDlgButton(hwndDlg, IDC_RGBOUTPUT,
GetPrivateProfileInt("debug", "rgboutput", false, "huffyuv.ini") ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hwndDlg, IDC_RGBA,
GetPrivateProfileInt("general", "enable_rgba", false, "huffyuv.ini") ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hwndDlg, IDC_SWAPFIELDS,
GetPrivateProfileInt("debug", "decomp_swap_fields", false, "huffyuv.ini") ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hwndDlg, IDC_LOG,
GetPrivateProfileInt("debug", "log", false, "huffyuv.ini") ? BST_CHECKED : BST_UNCHECKED);
}
else if (uMsg == WM_COMMAND) {
switch (LOWORD(wParam)) {
case IDOK:
{
char methodstring[4];
wsprintf(methodstring, "%d",
yuv_method_names[SendMessage(GetDlgItem(hwndDlg, IDC_YUY2METHOD), CB_GETCURSEL, 0, 0)].method);
WritePrivateProfileString("general", "yuy2method", methodstring, "huffyuv.ini");
wsprintf(methodstring, "%d",
rgb_method_names[SendMessage(GetDlgItem(hwndDlg, IDC_RGBMETHOD), CB_GETCURSEL, 0, 0)].method);
WritePrivateProfileString("general", "rgbmethod", methodstring, "huffyuv.ini");
}
WritePrivateProfileString("debug", "rgboutput",
(IsDlgButtonChecked(hwndDlg, IDC_RGBOUTPUT) == BST_CHECKED) ? "1" : NULL, "huffyuv.ini");
WritePrivateProfileString("general", "enable_rgba",
(IsDlgButtonChecked(hwndDlg, IDC_RGBA) == BST_CHECKED) ? "1" : NULL, "huffyuv.ini");
WritePrivateProfileString("debug", "decomp_swap_fields",
(IsDlgButtonChecked(hwndDlg, IDC_SWAPFIELDS) == BST_CHECKED) ? "1" : "0", "huffyuv.ini");
WritePrivateProfileString("debug", "log",
(IsDlgButtonChecked(hwndDlg, IDC_LOG) == BST_CHECKED) ? "1" : "0", "huffyuv.ini");
case IDCANCEL:
EndDialog(hwndDlg, 0);
break;
default:
return AboutDialogProc(hwndDlg, uMsg, wParam, lParam); // handle email and home-page buttons
}
}
return FALSE;
}
BOOL CodecInst::QueryConfigure() { return TRUE; }
DWORD CodecInst::Configure(HWND hwnd) {
DialogBox(hmoduleHuffyuv, MAKEINTRESOURCE(IDD_CONFIGURE), hwnd, ConfigureDialogProc);
return ICERR_OK;
}
/********************************************************************
********************************************************************/
// we have no state information which needs to be stored
DWORD CodecInst::GetState(LPVOID pv, DWORD dwSize) { return 0; }
DWORD CodecInst::SetState(LPVOID pv, DWORD dwSize) { return 0; }
DWORD CodecInst::GetInfo(ICINFO* icinfo, DWORD dwSize) {
if (icinfo == NULL)
return sizeof(ICINFO);
if (dwSize < sizeof(ICINFO))
return 0;
icinfo->dwSize = sizeof(ICINFO);
icinfo->fccType = ICTYPE_VIDEO;
icinfo->fccHandler = FOURCC_HFYU;
icinfo->dwFlags = 0;
icinfo->dwVersion = VERSION;
icinfo->dwVersionICM = ICVERSION;
MultiByteToWideChar(CP_ACP, 0, szDescription, -1, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, szName, -1, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
return sizeof(ICINFO);
}
/********************************************************************
********************************************************************/
struct PrintBitmapType {
char s[32];
PrintBitmapType(LPBITMAPINFOHEADER lpbi) {
if (!lpbi)
strcpy(s, "(null)");
else {
*(DWORD*)s = lpbi->biCompression;
s[4] = 0;
if (!isalnum(s[0]) || !isalnum(s[1]) || !isalnum(s[2]) || !isalnum(s[3]))
wsprintfA(s, "%x", lpbi->biCompression);
wsprintfA(strchr(s, 0), ", %d bits", GetBitCount(lpbi));
if (lpbi->biCompression == FOURCC_HFYU && !(lpbi->biBitCount&7) && lpbi->biSize > sizeof(BITMAPINFOHEADER))
wsprintfA(strchr(s, 0), ", method %d", *((unsigned char*)lpbi + sizeof(BITMAPINFOHEADER)));
}
}
};
// fast clipping of values to unsigned char range
static unsigned char clip[896];
static void InitClip() {
memset(clip, 0, 320);
for (int i=0; i<256; ++i) clip[i+320] = i;
memset(clip+320+256, 255, 320);
}
static inline unsigned char Clip(int x)
{ return clip[320 + ((x+0x8000) >> 16)]; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -