📄 huffyuv.cpp
字号:
int scaled_y = (y1+y2 - 32) * int(255.0/219.0*32768+0.5);
int b_y = ((rgb[0]+rgb[3]) << 15) - scaled_y;
yuv[1] = Clip((b_y >> 10) * int(1/2.018*1024+0.5) + 0x800000); // u
int r_y = ((rgb[2]+rgb[5]) << 15) - scaled_y;
yuv[3] = Clip((r_y >> 10) * int(1/1.596*1024+0.5) + 0x800000); // v
yuv += 4;
rgb += 6;
}
}
}
DWORD CodecInst::CompressEnd() {
if (yuy2_buffer) {
delete[] yuy2_buffer;
yuy2_buffer = 0;
}
if (median_buffer) {
delete[] median_buffer;
median_buffer = 0;
}
if (rgb_buffer) {
delete[] rgb_buffer;
rgb_buffer = 0;
}
return ICERR_OK;
}
/********************************************************************
********************************************************************/
static bool CanDecompress(LPBITMAPINFOHEADER lpbiIn) {
int intype = GetBitmapType(lpbiIn);
if (intype < 0)
return IsLegalMethod(GetMethod(lpbiIn), intype != -1);
else
return (intype == 1 || intype == 2);
}
static bool CanDecompress(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
if (!lpbiOut)
return CanDecompress(lpbiIn);
// must be 1:1 (no stretching)
if (lpbiOut && (lpbiOut->biWidth != lpbiIn->biWidth || lpbiOut->biHeight != lpbiIn->biHeight))
return false;
int intype = GetBitmapType(lpbiIn);
int outtype = GetBitmapType(lpbiOut);
if (intype < 0) {
if (!IsLegalMethod(GetMethod(lpbiIn), intype != -1))
return false;
}
switch (intype) {
case -1:
// YUY2, RGB-24, RGB-32 output for compressed YUY2
return (outtype == 1 || outtype == 3 || outtype == 4);
case -2: case 1: case 2:
// RGB-24, RGB-32 output only for YUY2/UYVY and compressed RGB
return (outtype == 3 || outtype == 4);
case -3:
// RGB-32 output for compressed RGBA
return (outtype == 4);
default:
return false;
}
}
/********************************************************************
********************************************************************/
DWORD CodecInst::DecompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
Msg("DecompressQuery: input = %s, output = %s\n", &PrintBitmapType(lpbiIn), &PrintBitmapType(lpbiOut));
return CanDecompress(lpbiIn, lpbiOut) ? ICERR_OK : ICERR_BADFORMAT;
}
// This function should return "the output format which preserves the most
// information." However, I now provide the option to return RGB format
// instead, since some programs treat the default format as the ONLY format.
DWORD CodecInst::DecompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
// if lpbiOut == NULL, then return the size required to hold an output format struct
if (lpbiOut == NULL)
return sizeof(BITMAPINFOHEADER);
if (!CanDecompress(lpbiIn))
return ICERR_BADFORMAT;
*lpbiOut = *lpbiIn;
lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
lpbiOut->biPlanes = 1;
int intype = GetBitmapType(lpbiIn);
if (intype == -3) {
lpbiOut->biBitCount = 32; // RGBA
lpbiOut->biCompression = 0;
lpbiOut->biSizeImage = lpbiIn->biWidth * lpbiIn->biHeight * 4;
} else if (intype == -2 || intype == 1 || intype == 2 || SuggestRGB()) {
lpbiOut->biBitCount = 24; // RGB
lpbiOut->biCompression = 0;
lpbiOut->biSizeImage = lpbiIn->biWidth * lpbiIn->biHeight * 3;
} else {
lpbiOut->biBitCount = 16; // YUY2
lpbiOut->biCompression = FOURCC_YUY2;
lpbiOut->biSizeImage = lpbiIn->biWidth * lpbiIn->biHeight * 2;
}
return ICERR_OK;
}
const unsigned char* InitializeDecodeTable(const unsigned char* hufftable, unsigned char* shift, DecodeTable* decode_table) {
unsigned add_shifted[256];
hufftable = InitializeShiftAddTables(hufftable, shift, add_shifted);
char code_lengths[256];
char code_firstbits[256];
char table_lengths[32];
memset(table_lengths,-1,32);
int all_zero_code=-1;
for (int i=0; i<256; ++i) {
if (add_shifted[i]) {
for (int firstbit=31; firstbit>=0; firstbit--) {
if (add_shifted[i] & (1<<firstbit)) {
code_firstbits[i] = firstbit;
int length = shift[i] - (32-firstbit);
code_lengths[i] = length;
table_lengths[firstbit] = max(table_lengths[firstbit], length);
break;
}
}
} else {
all_zero_code = i;
}
}
unsigned char* p = decode_table->table_data;
*p++ = 31;
*p++ = all_zero_code;
for (int j=0; j<32; ++j) {
if (table_lengths[j] == -1) {
decode_table->table_pointers[j] = decode_table->table_data;
} else {
decode_table->table_pointers[j] = p;
*p++ = j-table_lengths[j];
p += 1<<table_lengths[j];
}
}
for (int k=0; k<256; ++k) {
if (add_shifted[k]) {
int firstbit = code_firstbits[k];
int val = add_shifted[k] - (1<<firstbit);
unsigned char* table = decode_table->table_pointers[firstbit];
memset(&table[1+(val>>table[0])],
k, 1<<(table_lengths[firstbit]-code_lengths[k]));
}
}
return hufftable;
}
const unsigned char* InitializeDecodeTables(const unsigned char* hufftable) {
hufftable = InitializeDecodeTable(hufftable, decode1_shift, &decode1);
hufftable = InitializeDecodeTable(hufftable, decode2_shift, &decode2);
hufftable = InitializeDecodeTable(hufftable, decode3_shift, &decode3);
return hufftable;
}
DWORD CodecInst::DecompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
Msg("DecompressBegin: input = %s, output = %s\n", &PrintBitmapType(lpbiIn), &PrintBitmapType(lpbiOut));
DecompressEnd(); // free resources if necessary
if (!CanDecompress(lpbiIn, lpbiOut))
return ICERR_BADFORMAT;
decompressing = true;
int intype = GetBitmapType(lpbiIn);
int outtype = GetBitmapType(lpbiOut);
int method = GetMethod(lpbiIn);
if (intype < 0) {
InitializeDecodeTables(GetEmbeddedHuffmanTable(lpbiIn));
decode_table_owner = this;
}
// allocate buffer if decompressing HFYU->YUY2->RGB
if (intype == -1 && outtype >= 3)
decompress_yuy2_buffer = new unsigned char[lpbiIn->biWidth * lpbiIn->biHeight * 2];
InitClip();
swapfields = !!GetPrivateProfileInt("debug", "decomp_swap_fields", false, "huffyuv.ini");
return ICERR_OK;
}
static DWORD ConvertYUY2toRGB(LPBITMAPINFOHEADER lpbiOutput, void* _src, void* _dst) {
const unsigned char* src = (const unsigned char*)_src;
unsigned char* dst = (unsigned char*)_dst;
int stride = lpbiOutput->biWidth * 2;
const unsigned char* src_end = src + stride*lpbiOutput->biHeight;
if (lpbiOutput->biBitCount == 32)
mmx_YUY2toRGB32(src, dst, src_end, stride);
else
mmx_YUY2toRGB24(src, dst, src_end, stride);
return ICERR_OK;
}
static DWORD ConvertUYVYtoRGB(LPBITMAPINFOHEADER lpbiOutput, void* _src, void* _dst) {
const unsigned char* src = (const unsigned char*)_src;
unsigned char* dst = (unsigned char*)_dst;
int stride = lpbiOutput->biWidth * 2;
const unsigned char* src_end = src + stride*lpbiOutput->biHeight;
if (lpbiOutput->biBitCount == 32)
mmx_UYVYtoRGB32(src, dst, src_end, stride);
else
mmx_UYVYtoRGB24(src, dst, src_end, stride);
return ICERR_OK;
}
DWORD CodecInst::Decompress(ICDECOMPRESS* icinfo, DWORD dwSize) {
// If you insert a Huffyuv-compressed AVI to a Premiere project and then
// drag it on to the timeline, the following dialogue occurs:
//
// 1. Premiere calls ICDecompressBegin, asking Huffyuv to decompress
// to a bitmap with different dimensions than the compressed frame.
//
// 2. Huffyuv can't resize, so it returns ICERR_BADFORMAT.
//
// 3. Premiere calls ICDecompress without making another call to
// ICDecompressBegin.
//
// Therefore I now check for this case and compensate for Premiere's
// negligence by making the DecompressBegin call myself.
if (!decompressing) {
DWORD retval = DecompressBegin(icinfo->lpbiInput, icinfo->lpbiOutput);
if (retval != ICERR_OK)
return retval;
}
icinfo->lpbiOutput->biSizeImage = (icinfo->lpbiOutput->biWidth * icinfo->lpbiOutput->biHeight * icinfo->lpbiOutput->biBitCount) >> 3;
int intype = GetBitmapType(icinfo->lpbiInput);
if (intype < 0) {
int method = GetMethod(icinfo->lpbiInput);
int outtype = GetBitmapType(icinfo->lpbiOutput);
if (decode_table_owner != this) {
InitializeDecodeTables(GetEmbeddedHuffmanTable(icinfo->lpbiInput));
decode_table_owner = this;
}
const unsigned long* const in = (unsigned long*)icinfo->lpInput;
unsigned char* const out = (unsigned char*)icinfo->lpOutput;
if (intype == -1) { // decompressing HFYU16
int stride = icinfo->lpbiOutput->biWidth * 2;
const int size = stride * icinfo->lpbiOutput->biHeight;
if (icinfo->lpbiOutput->biHeight > 288) stride *= 2; // if image is interlaced, double stride so fields are treated separately
unsigned char* const yuy2 = outtype>1 ? decompress_yuy2_buffer : out;
if (method == methodMedian) {
asm_DecompressHFYU16(in, yuy2, yuy2+size);
asm_MedianRestore(yuy2, yuy2+size, stride);
}
else {
asm_DecompressHFYU16Delta(in, yuy2, yuy2+size);
if (method == methodGrad)
mmx_RowAccum(yuy2, yuy2+size, stride);
}
if (outtype>1) // HFYU16->RGB
ConvertYUY2toRGB(icinfo->lpbiOutput, yuy2, out);
}
else { // decompressing HFYU24/HFYU32
int stride = (icinfo->lpbiOutput->biWidth * icinfo->lpbiOutput->biBitCount) >> 3;
const int size = stride * icinfo->lpbiOutput->biHeight;
if (icinfo->lpbiOutput->biHeight > 288) stride *= 2; // if image is interlaced, double stride so fields are treated separately
if (intype == -2) { // HFYU24->RGB
if (outtype == 4) {
if (method == methodLeft || method == methodOld)
asm_DecompressHFYU24To32Delta(in, out, out+size);
else
asm_DecompressHFYU24To32DeltaDecorrelate(in, out, out+size);
} else {
if (method == methodLeft || method == methodOld)
asm_DecompressHFYU24To24Delta(in, out, out+size);
else
asm_DecompressHFYU24To24DeltaDecorrelate(in, out, out+size);
}
}
else if (intype == -3) { // HFYU32->RGBA
if (method == methodLeft || method == methodOld)
asm_DecompressHFYU32To32Delta(in, out, out+size);
else
asm_DecompressHFYU32To32DeltaDecorrelate(in, out, out+size);
}
else
return ICERR_BADFORMAT;
if ((method&~flagDecorrelate) == methodGrad)
mmx_RowAccum(out, out+size, stride);
}
if (swapfields && icinfo->lpbiOutput->biHeight > 288)
asm_SwapFields(out, out+icinfo->lpbiOutput->biSizeImage,
(icinfo->lpbiOutput->biWidth * icinfo->lpbiOutput->biBitCount) >> 3);
return ICERR_OK;
}
else if (intype == 1) { // YUY2->RGB
return ConvertYUY2toRGB(icinfo->lpbiOutput, icinfo->lpInput, icinfo->lpOutput);
}
else if (intype == 2) { // UYVY->RGB
return ConvertUYVYtoRGB(icinfo->lpbiOutput, icinfo->lpInput, icinfo->lpOutput);
}
else
return ICERR_BADFORMAT;
}
// palette-mapped output only
DWORD CodecInst::DecompressGetPalette(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
return ICERR_BADFORMAT;
}
DWORD CodecInst::DecompressEnd() {
if (decompress_yuy2_buffer) {
delete[] decompress_yuy2_buffer;
decompress_yuy2_buffer = 0;
}
decompressing = false;
return ICERR_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -