607 lines
16 KiB
C
607 lines
16 KiB
C
/*----------------------------------------------------------------------+
|
|
| msyuv.c - Microsoft YUV Codec |
|
|
| |
|
|
| Copyright (c) 1993 Microsoft Corporation. |
|
|
| All Rights Reserved. |
|
|
| |
|
|
+----------------------------------------------------------------------*/
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
//#include <mmsystem.h>
|
|
|
|
#ifndef _WIN32
|
|
#include "stdarg.h"
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
#include <memory.h> /* for memcpy */
|
|
#endif
|
|
|
|
#include "msyuv.h"
|
|
|
|
WCHAR szDescription[] = L"Toshiba YUV Codec";
|
|
WCHAR szName[] = L"Toshiba YUV411";
|
|
WCHAR szAbout[] = L"About";
|
|
|
|
#define VERSION 0x00010000 // 1.0
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
INSTINFO * NEAR PASCAL Open(ICOPEN FAR * icinfo)
|
|
{
|
|
INSTINFO * pinst;
|
|
|
|
//
|
|
// refuse to open if we are not being opened as a Video compressor
|
|
//
|
|
if (icinfo->fccType != ICTYPE_VIDEO)
|
|
return NULL;
|
|
|
|
//
|
|
// dwFlags contain wMode
|
|
//
|
|
if( icinfo->dwFlags != ICMODE_QUERY // Open for infomational purpose
|
|
&& icinfo->dwFlags != ICMODE_DECOMPRESS
|
|
|
|
#ifdef ICM_COMPRESS_SUPPORTED
|
|
&& icinfo->dwFlags != ICMODE_COMPRESS
|
|
#endif
|
|
|
|
#ifdef ICM_DRAW_SUPPORTED
|
|
&& icinfo->dwFlags != ICMODE_DRAW
|
|
#endif
|
|
) {
|
|
|
|
dprintf1((TEXT("Open: unsupported wMode=%d\n"), icinfo->dwFlags));
|
|
return NULL;
|
|
}
|
|
|
|
pinst = (INSTINFO *)LocalAlloc(LPTR, sizeof(INSTINFO));
|
|
|
|
if (!pinst) {
|
|
icinfo->dwError = (DWORD)ICERR_MEMORY;
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// init structure
|
|
//
|
|
pinst->dwFlags = icinfo->dwFlags;
|
|
pinst->pXlate = NULL;
|
|
|
|
//
|
|
// return success.
|
|
//
|
|
icinfo->dwError = ICERR_OK;
|
|
|
|
return pinst;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL Close(INSTINFO * pinst)
|
|
{
|
|
|
|
if (pinst->pXlate) {
|
|
DecompressEnd(pinst);
|
|
}
|
|
|
|
#if ICM_DRAW_SUPPORTED
|
|
if (pinst->vh) {
|
|
DrawEnd(pinst);
|
|
}
|
|
#endif
|
|
|
|
LocalFree((HLOCAL)pinst);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
|
|
BOOL NEAR PASCAL QueryAbout(INSTINFO * pinst)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD NEAR PASCAL About(INSTINFO * pinst, HWND hwnd)
|
|
{
|
|
MessageBoxW(hwnd,szDescription,szAbout,MB_OK|MB_ICONINFORMATION);
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
BOOL NEAR PASCAL QueryConfigure(INSTINFO * pinst)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD NEAR PASCAL Configure(INSTINFO * pinst, HWND hwnd)
|
|
{
|
|
return (TRUE);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
/*
|
|
* lossless translation - hence no need for state adjustments
|
|
*/
|
|
DWORD NEAR PASCAL GetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
|
|
{
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL SetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL GetInfo(INSTINFO * pinst, ICINFO FAR *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_YUV411;
|
|
icinfo->dwFlags = 0;
|
|
|
|
icinfo->dwVersion = VERSION;
|
|
icinfo->dwVersionICM = ICVERSION;
|
|
wcscpy(icinfo->szDescription, szDescription);
|
|
wcscpy(icinfo->szName, szName);
|
|
|
|
return sizeof(ICINFO);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD FAR PASCAL CompressQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
return ((DWORD) ICERR_BADFORMAT);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD FAR PASCAL CompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
|
|
return((DWORD) ICERR_BADFORMAT);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
|
|
|
|
DWORD FAR PASCAL CompressBegin(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
|
|
return((DWORD) ICERR_ERROR);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD FAR PASCAL CompressGetSize(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD FAR PASCAL Compress(INSTINFO * pinst, ICCOMPRESS FAR *icinfo, DWORD dwSize)
|
|
{
|
|
return((DWORD) ICERR_ERROR);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD FAR PASCAL CompressEnd(INSTINFO * pinst)
|
|
{
|
|
return (DWORD)ICERR_ERROR;
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL DecompressQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
//
|
|
// determine if the input DIB data is in a format we like.
|
|
//
|
|
#ifdef TOSHIBA
|
|
#if DBG
|
|
// DbgBreakPoint();
|
|
#endif
|
|
if (lpbiIn == NULL ||
|
|
( (lpbiIn->biCompression != FOURCC_YUV411) &&
|
|
(lpbiIn->biCompression != FOURCC_YUV422) &&
|
|
(lpbiIn->biCompression != FOURCC_YUV9) && // add YUV9
|
|
(lpbiIn->biCompression != FOURCC_YUV12 ))) { // add YUV12
|
|
#else //TOSHIBA
|
|
if (lpbiIn == NULL ||
|
|
(lpbiIn->biBitCount != 16) ||
|
|
( (lpbiIn->biCompression != FOURCC_YUV411) &&
|
|
(lpbiIn->biCompression != FOURCC_YUV422))) {
|
|
#endif//TOSHIBA
|
|
dprintf((TEXT("bad input format")));
|
|
return (DWORD)ICERR_BADFORMAT;
|
|
}
|
|
|
|
//
|
|
// are we being asked to query just the input format?
|
|
//
|
|
if (lpbiOut == NULL) {
|
|
return ICERR_OK;
|
|
}
|
|
|
|
// check output format to make sure we can convert to this
|
|
|
|
// must be full dib
|
|
if (lpbiOut->biCompression == BI_RGB) {
|
|
pinst->bRGB565 = FALSE;
|
|
#ifdef TOSHIBA
|
|
#ifdef COLOR_MODIFY
|
|
if (lpbiOut->biBitCount == 24) {
|
|
pinst->bRGB24 = TRUE;
|
|
} else {
|
|
pinst->bRGB24 = FALSE;
|
|
}
|
|
#endif//COLOR_MODIFY
|
|
#endif//TOSHIBA
|
|
} else if ((lpbiOut->biCompression == BI_BITFIELDS) &&
|
|
(lpbiOut->biBitCount == 16) &&
|
|
(((LPDWORD)(lpbiOut+1))[0] == 0x00f800) &&
|
|
(((LPDWORD)(lpbiOut+1))[1] == 0x0007e0) &&
|
|
(((LPDWORD)(lpbiOut+1))[2] == 0x00001f)) {
|
|
|
|
dprintf1((TEXT("rgb565 output")));
|
|
pinst->bRGB565 = TRUE;
|
|
#ifdef TOSHIBA
|
|
#ifdef COLOR_MODIFY
|
|
pinst->bRGB24 = FALSE;
|
|
#endif//COLOR_MODIFY
|
|
#endif//TOSHIBA
|
|
} else {
|
|
|
|
dprintf1((TEXT("bad compression for output")));
|
|
|
|
return (DWORD)ICERR_BADFORMAT;
|
|
}
|
|
|
|
/* must be 1:1 (no stretching) */
|
|
if ((lpbiOut->biWidth != lpbiIn->biWidth) ||
|
|
(lpbiOut->biHeight != lpbiIn->biHeight)) {
|
|
dprintf1((TEXT("YUV can't stretch: %dx%d->%dx%d"),
|
|
lpbiIn->biWidth, lpbiIn->biHeight,
|
|
lpbiOut->biWidth, lpbiOut->biHeight
|
|
));
|
|
|
|
return((DWORD) ICERR_BADFORMAT);
|
|
}
|
|
|
|
/*
|
|
* we translate to 16 bits
|
|
*/
|
|
|
|
#ifdef TOSHIBA
|
|
#ifdef COLOR_MODIFY
|
|
if ((lpbiOut->biBitCount != 16) &&
|
|
(lpbiOut->biBitCount != 24)) {
|
|
dprintf1((TEXT("YUV to 16 or 24 only")));
|
|
return((DWORD) ICERR_BADFORMAT);
|
|
}
|
|
#else //COLOR_MODIFY
|
|
if (lpbiOut->biBitCount != 16) {
|
|
dprintf1((TEXT("YUV 16:16 only")));
|
|
return((DWORD) ICERR_BADFORMAT);
|
|
}
|
|
#endif//COLOR_MODIFY
|
|
#else //TOSHIBA
|
|
if (lpbiOut->biBitCount != 16) {
|
|
dprintf1((TEXT("YUV 16:16 only")));
|
|
return((DWORD) ICERR_BADFORMAT);
|
|
}
|
|
#endif//TOSHIBA
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD DecompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
DWORD dw;
|
|
int dx,dy;
|
|
|
|
dw = DecompressQuery(pinst, lpbiIn, NULL);
|
|
if (dw != ICERR_OK) {
|
|
return dw;
|
|
}
|
|
|
|
//
|
|
// if lpbiOut == NULL then, return the size required to hold a output
|
|
// format
|
|
//
|
|
if (lpbiOut == NULL) {
|
|
dprintf2((TEXT("get format size query")));
|
|
return (int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
|
|
}
|
|
|
|
memcpy(lpbiOut, lpbiIn,
|
|
(int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
|
|
|
|
dx = (int)lpbiIn->biWidth & ~3;
|
|
dy = (int)lpbiIn->biHeight & ~3;
|
|
|
|
lpbiOut->biWidth = dx;
|
|
lpbiOut->biHeight = dy;
|
|
#ifdef TOSHIBA
|
|
lpbiOut->biBitCount = 16;
|
|
#else //TOSHIBA
|
|
lpbiOut->biBitCount = lpbiIn->biBitCount; // convert 16->16
|
|
#endif//TOSHIBA
|
|
|
|
lpbiOut->biCompression = BI_RGB;
|
|
lpbiOut->biSizeImage = dx*dy*2;
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL DecompressBegin(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
DWORD dw;
|
|
|
|
|
|
/* check that the conversion formats are valid */
|
|
dw = DecompressQuery(pinst, lpbiIn, lpbiOut);
|
|
if (dw != ICERR_OK) {
|
|
return dw;
|
|
}
|
|
|
|
/* init the yuv-to-rgb55 xlate table if not already inited */
|
|
|
|
/* free up the existing table if the formats differ */
|
|
if (lpbiIn->biCompression != pinst->dwFormat) {
|
|
if (pinst->pXlate != NULL) {
|
|
DecompressEnd(pinst);
|
|
}
|
|
}
|
|
|
|
if (pinst->pXlate == NULL) {
|
|
|
|
switch(lpbiIn->biCompression) {
|
|
case FOURCC_YUV411:
|
|
if (pinst->bRGB565) {
|
|
pinst->pXlate = BuildYUVToRGB565(pinst);
|
|
} else {
|
|
pinst->pXlate = BuildYUVToRGB555(pinst);
|
|
}
|
|
break;
|
|
|
|
case FOURCC_YUV422:
|
|
if (pinst->bRGB565) {
|
|
pinst->pXlate = BuildYUV422ToRGB565(pinst);
|
|
} else {
|
|
pinst->pXlate = BuildYUV422ToRGB555(pinst);
|
|
}
|
|
break;
|
|
|
|
#ifdef TOSHIBA
|
|
#ifdef COLOR_MODIFY
|
|
case FOURCC_YUV12:
|
|
pinst->pXlate = BuildYUVToRB(pinst);
|
|
break;
|
|
|
|
case FOURCC_YUV9:
|
|
pinst->pXlate = BuildYUVToRB(pinst); // same to YUV12
|
|
break;
|
|
#else //COLOR_MODIFY
|
|
case FOURCC_YUV12:
|
|
if (pinst->bRGB565) {
|
|
pinst->pXlate = BuildYUV12ToRGB565(pinst);
|
|
} else {
|
|
pinst->pXlate = BuildYUV12ToRGB555(pinst);
|
|
}
|
|
break;
|
|
|
|
case FOURCC_YUV9:
|
|
if (pinst->bRGB565) {
|
|
pinst->pXlate = BuildYUV12ToRGB565(pinst); // same to YUV12
|
|
} else {
|
|
pinst->pXlate = BuildYUV12ToRGB555(pinst); // same to YUV12
|
|
}
|
|
break;
|
|
#endif//COLOR_MODIFY
|
|
#endif//TOSHIBA
|
|
|
|
default:
|
|
return((DWORD) ICERR_BADFORMAT);
|
|
}
|
|
|
|
if (pinst->pXlate == NULL) {
|
|
return((DWORD) ICERR_MEMORY);
|
|
}
|
|
pinst->dwFormat = lpbiIn->biCompression;
|
|
}
|
|
|
|
return(ICERR_OK);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL Decompress(INSTINFO * pinst, ICDECOMPRESS FAR *icinfo, DWORD dwSize)
|
|
{
|
|
/* must have been a DecompressBegin first */
|
|
if (pinst->pXlate == NULL) {
|
|
return((DWORD) ICERR_ERROR);
|
|
}
|
|
|
|
#ifdef TOSHIBA
|
|
if (pinst->dwFormat == FOURCC_YUV9) {
|
|
|
|
#ifdef COLOR_MODIFY
|
|
if (pinst->bRGB24) {
|
|
YUV9ToRGB24(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
} else {
|
|
if (pinst->bRGB565) {
|
|
YUV9ToRGB565(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
} else {
|
|
YUV9ToRGB555(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
}
|
|
}
|
|
#else //COLOR_MODIFY
|
|
YUV9ToRGB(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
#endif//COLOR_MODIFY
|
|
|
|
} else
|
|
|
|
if (pinst->dwFormat == FOURCC_YUV12) {
|
|
|
|
#ifdef COLOR_MODIFY
|
|
if (pinst->bRGB24) {
|
|
YUV12ToRGB24(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
} else {
|
|
if (pinst->bRGB565) {
|
|
YUV12ToRGB565(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
} else {
|
|
YUV12ToRGB555(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
}
|
|
}
|
|
#else //COLOR_MODIFY
|
|
YUV12ToRGB(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
#endif//COLOR_MODIFY
|
|
|
|
} else
|
|
#endif//TOSHIBA
|
|
|
|
if (pinst->dwFormat == FOURCC_YUV411) {
|
|
|
|
YUV411ToRGB(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
} else {
|
|
|
|
/*
|
|
* for compatibility with 16-bit Spigot driver,
|
|
* check for Guard field at start of data
|
|
*/
|
|
LPDWORD lpInput = icinfo->lpInput;
|
|
|
|
if (*lpInput == FOURCC_YUV422) {
|
|
lpInput++;
|
|
}
|
|
|
|
|
|
YUV422ToRGB(pinst,
|
|
icinfo->lpbiInput,
|
|
icinfo->lpInput,
|
|
icinfo->lpbiOutput,
|
|
icinfo->lpOutput
|
|
);
|
|
}
|
|
|
|
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* DecompressGetPalette() implements ICM_GET_PALETTE
|
|
*
|
|
* This function has no Compress...() equivalent
|
|
*
|
|
* It is used to pull the palette from a frame in order to possibly do
|
|
* a palette change.
|
|
*
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL DecompressGetPalette(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
|
|
{
|
|
|
|
dprintf2((TEXT("DecompressGetPalette()")));
|
|
|
|
|
|
/*
|
|
* only applies to 8-bit output formats. We only decompress to 16 bits
|
|
*/
|
|
return((DWORD) ICERR_BADFORMAT);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
****************************************************************************/
|
|
DWORD NEAR PASCAL DecompressEnd(INSTINFO * pinst)
|
|
{
|
|
if (pinst->pXlate == NULL) {
|
|
return (DWORD)ICERR_ERROR;
|
|
}
|
|
|
|
FreeXlate(pinst);
|
|
pinst->dwFormat = 0;
|
|
|
|
return ICERR_OK;
|
|
}
|
|
|