Windows2000/private/shell/comctl32/rlefile.cpp
2020-09-30 17:12:32 +02:00

644 lines
14 KiB
C++

// handle AVI RLE files with custom code.
// use this code to deal with .AVI files without the MCIAVI runtime
// restrictions:
// AVI file must be a simple DIB format (RLE or none)
// AVI file must fit into memory.
// ToddLa
#include "ctlspriv.h"
extern "C" {
#include "rlefile.h"
}
#ifdef UNIX
#include <mwavi.h>
#include "unixstuff.h"
#endif
#include <lendian.hpp>
extern "C"
BOOL RleFile_Init(RLEFILE *prle, LPVOID pFile, HANDLE hRes, DWORD dwFileLen);
LPVOID LoadFile(LPCTSTR szFile, DWORD * pFileLength)
{
LPVOID pFile;
HANDLE hFile;
HANDLE h;
DWORD FileLength;
#ifdef WIN32
#ifndef MAINWIN
hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
#else
// sunos5 does not want to map NFS files when there is locking on them
hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
#endif
if (hFile == INVALID_HANDLE_VALUE)
return 0;
FileLength = (LONG)GetFileSize(hFile, NULL);
if (pFileLength)
*pFileLength = FileLength ;
h = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!h)
{
CloseHandle(hFile);
return 0;
}
pFile = MapViewOfFile(h, FILE_MAP_READ, 0, 0, 0);
CloseHandle(hFile);
CloseHandle(h);
if (pFile == NULL)
return 0;
#else
hFile = (HANDLE)_lopen(szFile, OF_READ);
if (hFile == (HANDLE)-1)
return 0;
FileLength = _llseek((int)hFile, 0, SEEK_END);
_llseek((int)hFile, 0, SEEK_SET);
pFile = GlobalAllocPtr(GHND, FileLength);
if (pFile && _hread((int)hFile, pFile, FileLength) != FileLength)
{
GlobalFreePtr(pFile);
pFile = NULL;
}
_lclose((int)hFile);
#endif
return pFile;
}
// RleFile_OpenFromFile
// load a .AVI file into memory and setup all of our pointers so we
// know how to deal with it.
extern "C"
BOOL RleFile_OpenFromFile(RLEFILE *prle, LPCTSTR szFile)
{
DWORD dwFileLen;
LPVOID pFile;
// MAKEINTRESOURCE() things can't come from files
if (IS_INTRESOURCE(szFile))
return FALSE;
if (pFile = LoadFile(szFile, &dwFileLen))
return RleFile_Init(prle, pFile, NULL, dwFileLen);
else
return FALSE;
}
// RleFile_OpenFromResource
// load a .AVI file into memory and setup all of our pointers so we
// know how to deal with it.
extern "C"
BOOL RleFile_OpenFromResource(RLEFILE *prle, HINSTANCE hInstance, LPCTSTR szName, LPCTSTR szType)
{
HRSRC h;
HANDLE hRes;
// not a MAKEINTRESOURCE(), and points to NULL
#ifndef MAINWIN
if (!IS_INTRESOURCE(szName) && (*szName == 0))
return FALSE;
#else
if (!MwIsIntegerResource(szName) && (*szName == 0))
return FALSE;
#endif
h = FindResource(hInstance, szName, szType);
if (h == NULL)
return FALSE;
if (hRes = LoadResource(hInstance, h))
return RleFile_Init(prle, LockResource(hRes), hRes, 0);
else
return FALSE;
}
// RleFile_Close
// nuke all stuff we did to open the file.
extern "C"
BOOL RleFile_Close(RLEFILE *prle)
{
if (prle->hpal)
DeleteObject(prle->hpal);
if (prle->pFile)
{
#ifdef WIN32
if (prle->hRes)
{
#ifdef UNIX
UnlockResource(prle->hRes);
#endif
FreeResource(prle->hRes);
}
else
UnmapViewOfFile(prle->pFile);
#else
GlobalFreePtr(prle->pFile);
#endif
}
#ifdef UNIX
CHECK_FREE( prle->pStream );
CHECK_FREE( prle->pFormat );
#endif
prle->hpal = NULL;
prle->pFile = NULL;
prle->hRes = NULL;
prle->pMainHeader = NULL;
prle->pStream = NULL;
prle->pFormat = NULL;
prle->pMovie = NULL;
prle->pIndex = NULL;
return TRUE;
}
// RleFile_Init
extern "C"
BOOL RleFile_Init(RLEFILE *prle, LPVOID pFile, HANDLE hRes, DWORD dwFileLen)
{
DWORD_LENDIAN UNALIGNED *pdw;
DWORD_LENDIAN UNALIGNED *pdwEnd;
DWORD dwRiff;
DWORD dwType;
DWORD dwLength;
int stream;
if (prle->pFile == pFile)
return TRUE;
RleFile_Close(prle);
prle->pFile = pFile;
prle->hRes = hRes;
if (prle->pFile == NULL)
return FALSE;
// now that the file is in memory walk the memory image filling in
// interesting stuff.
pdw = (DWORD_LENDIAN UNALIGNED *)prle->pFile;
dwRiff = *pdw++;
dwLength = *pdw++;
dwType = *pdw++;
#ifndef UNIX
if ((dwFileLen > 0) && (dwLength > dwFileLen)) {
// File is physically shorter than the length written in its header.
// Can't handle it.
goto exit;
}
#endif
if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F'))
goto exit; // not even a RIFF file
if (dwType != formtypeAVI)
goto exit; // not a AVI file
pdwEnd = (DWORD_LENDIAN UNALIGNED *)((BYTE PTR *)pdw + dwLength-4);
stream = 0;
while (pdw < pdwEnd)
{
dwType = *pdw++;
dwLength = *pdw++;
switch (dwType)
{
case mmioFOURCC('L', 'I', 'S', 'T'):
dwType = *pdw++;
dwLength -= 4;
switch (dwType)
{
case listtypeAVIMOVIE:
prle->pMovie = (LPVOID)pdw;
break;
case listtypeSTREAMHEADER:
case listtypeAVIHEADER:
dwLength = 0; // decend
break;
default:
break; // ignore
}
break;
case ckidAVIMAINHDR:
{
#ifdef UNIX
MainAVIHeader mavih;
prle->pMainHeader=&mavih;
MwReadMainAVIHeader( (BYTE*) pdw,
sizeof(*prle->pMainHeader),
prle->pMainHeader );
#else
prle->pMainHeader = (MainAVIHeader PTR *)pdw;
#endif
prle->NumFrames = (int)prle->pMainHeader->dwTotalFrames;
prle->Width = (int)prle->pMainHeader->dwWidth;
prle->Height = (int)prle->pMainHeader->dwHeight;
prle->Rate = (int)(prle->pMainHeader->dwMicroSecPerFrame/1000);
if (prle->pMainHeader->dwInitialFrames != 0)
goto exit;
if (prle->pMainHeader->dwStreams > 2)
goto exit;
}
break;
case ckidSTREAMHEADER:
{
#ifdef UNIX
AVIStreamHeader *paviSH;
#endif
stream++;
if (prle->pStream != NULL)
break;
#ifndef UNIX
if (((AVIStreamHeader PTR *)pdw)->fccType != streamtypeVIDEO)
break;
#else
paviSH = (AVIStreamHeader*) malloc(sizeof(AVIStreamHeader));
if ( paviSH == NULL )
break;
MwReadAVIStreamHeader( (BYTE*) pdw,sizeof(*paviSH),paviSH );
if (paviSH->fccType != streamtypeVIDEO) {
CHECK_FREE( paviSH );
break;
}
#endif
prle->iStream = stream-1;
#ifndef UNIX
prle->pStream = (AVIStreamHeader PTR*)pdw;
#else
prle->pStream = paviSH;
#endif
if (prle->pStream->dwFlags & AVISF_VIDEO_PALCHANGES)
goto exit;
}
break;
case ckidSTREAMFORMAT:
if (prle->pFormat != NULL)
break;
if (prle->pStream == NULL)
break;
#ifdef UNIX
prle->pFormat = (LPBITMAPINFOHEADER) malloc( dwLength );
if ( prle->pFormat == NULL )
goto exit;
MwReadBITMAPINFO( (BYTE*) pdw, dwLength,
(BITMAPINFO*) prle->pFormat );
#else
prle->pFormat = (LPBITMAPINFOHEADER)pdw;
#endif
if (prle->pFormat->biSize != sizeof(BITMAPINFOHEADER))
goto exit;
if (prle->pFormat->biCompression != 0 &&
prle->pFormat->biCompression != BI_RLE8)
goto exit;
if (prle->pFormat->biWidth != prle->Width)
goto exit;
if (prle->pFormat->biHeight != prle->Height)
goto exit;
hmemcpy(&prle->bi, prle->pFormat, dwLength);
prle->bi.biSizeImage = 0;
prle->FullSizeImage = ((prle->bi.biWidth * prle->bi.biBitCount + 31) & ~31)/8U * prle->bi.biHeight;
break;
case ckidAVINEWINDEX:
// we dont convert indexes because we dont know how many there are
// but we will have to convert each usage of it
prle->pIndex = (AVIINDEXENTRY PTR *)pdw;
break;
}
pdw = (DWORD_LENDIAN *)((BYTE PTR *)pdw + ((dwLength+1)&~1));
}
// if the file has nothing in it we care about get out, note
// we dont need a index, we do need some data though.
if (prle->NumFrames == 0 ||
prle->pMainHeader == NULL ||
prle->pStream == NULL ||
prle->pFormat == NULL ||
prle->pMovie == NULL )
{
goto exit;
}
// if we cared about a palette we would create it here.
// file open'ed ok seek to the first frame.
prle->iFrame = -42;
RleFile_Seek(prle, 0);
return TRUE;
exit:
RleFile_Close(prle);
return FALSE;
}
// RleFile_ChangeColor
// change the color table of the AVI
extern "C"
BOOL RleFile_ChangeColor(RLEFILE *prle, COLORREF rgbS, COLORREF rgbD)
{
#ifndef UNIX
DWORD dwS;
DWORD dwD;
DWORD PTR *ColorTable;
int i;
dwS = RGB(GetBValue(rgbS), GetGValue(rgbS), GetRValue(rgbS));
dwD = RGB(GetBValue(rgbD), GetGValue(rgbD), GetRValue(rgbD));
if (prle == NULL || prle->pFormat == NULL)
return FALSE;
ColorTable = (DWORD PTR *)((BYTE PTR *)&prle->bi + prle->bi.biSize);
for (i=0; i<(int)prle->bi.biClrUsed; i++)
{
if (ColorTable[i] == dwS)
ColorTable[i] = dwD;
}
return TRUE;
#else
RGBQUAD dwS;
RGBQUAD dwD;
RGBQUAD PTR *ColorTable;
int i;
dwS.rgbRed = GetRValue(rgbS);
dwS.rgbGreen = GetGValue(rgbS);
dwS.rgbBlue = GetBValue(rgbS);
dwS.rgbReserved = 0;
dwD.rgbRed = GetRValue(rgbD);
dwD.rgbGreen = GetGValue(rgbD);
dwD.rgbBlue = GetBValue(rgbD);
// Support for CDE colormap index colors (davidd)
dwD.rgbReserved = (BYTE)(rgbD >> 24);
if (prle == NULL || prle->pFormat == NULL)
return FALSE;
ColorTable = (RGBQUAD PTR *)((BYTE PTR *)&prle->bi + prle->bi.biSize);
for (i=0; i<(int)prle->bi.biClrUsed; i++)
{
if ((ColorTable[i].rgbRed == dwS.rgbRed) &&
(ColorTable[i].rgbGreen == dwS.rgbGreen) &&
(ColorTable[i].rgbBlue == dwS.rgbBlue)) {
ColorTable[i] = dwD;
}
}
return TRUE;
#endif
}
// RleFile_Seek
// find the data for the specifed frame.
extern "C"
BOOL RleFile_Seek(RLEFILE *prle, int iFrame)
{
int n;
if (prle == NULL || prle->pMovie == NULL)
return FALSE;
#if 0
if (iFrame == FRAME_CURRENT)
iFrame = prle->iFrame;
if (iFrame == FRAME_NEXT)
{
iFrame = prle->iFrame+1;
if (iFrame >= prle->NumFrames)
iFrame = 0;
}
if (iFrame == FRAME_PREV)
{
iFrame = prle->iFrame-1;
if (iFrame == -1)
iFrame = prle->NumFrames-1;
}
#endif
if (iFrame >= prle->NumFrames)
return FALSE;
if (iFrame < 0)
return FALSE;
if (iFrame == prle->iFrame)
return TRUE;
if (prle->iFrame >= 0 && prle->iFrame < iFrame)
{
n = prle->nFrame; // start where you left off last time
}
else
{
n = -1; // start at the begining
prle->iFrame = -1; // current frame
prle->iKeyFrame = 0; // current key
}
while (prle->iFrame < iFrame)
{
n++;
if (StreamFromFOURCC(*(DWORD_LENDIAN UNALIGNED *)(&prle->pIndex[n].ckid)) == (UINT)prle->iStream)
{
prle->iFrame++; // new frame
if ((long)(*(DWORD_LENDIAN UNALIGNED *)(&prle->pIndex[n].dwFlags)) & AVIIF_KEYFRAME)
prle->iKeyFrame = prle->iFrame; /* // new key frame */
}
}
prle->nFrame = n;
/* warning this points to bitmap bits in wintel format ! */
prle->pFrame = (BYTE PTR *)prle->pMovie +
(int)(*(DWORD_LENDIAN UNALIGNED *)(&prle->pIndex[n].dwChunkOffset)) + 4;
prle->cbFrame = *(DWORD_LENDIAN UNALIGNED *)(&prle->pIndex[n].dwChunkLength);
ASSERT( (DWORD)(*(DWORD_LENDIAN UNALIGNED *)&(((DWORD PTR *)prle->pFrame)[-1])) == (DWORD)prle->cbFrame);
ASSERT( (DWORD)(*(DWORD_LENDIAN UNALIGNED *)&(((DWORD PTR *)prle->pFrame)[-2])) == (DWORD)*(DWORD_LENDIAN UNALIGNED *)(&prle->pIndex[n].ckid));
prle->bi.biSizeImage = prle->cbFrame;
if (prle->cbFrame == prle->FullSizeImage)
prle->bi.biCompression = 0;
else
prle->bi.biCompression = BI_RLE8;
return TRUE;
}
// RleFile_Paint
// draw the specifed frame, makes sure the entire frame is updated
// dealing with non-key frames correctly.
extern "C"
BOOL RleFile_Paint(RLEFILE *prle, HDC hdc, int iFrame, int x, int y)
{
int i;
BOOL f;
if (prle == NULL || prle->pMovie == NULL)
return FALSE;
if (f = RleFile_Seek(prle, iFrame))
{
iFrame = prle->iFrame;
for (i=prle->iKeyFrame; i<=iFrame; i++)
RleFile_Draw(prle, hdc, i, x, y);
}
return f;
}
// RleFile_Draw
// draw the data for a specifed frame
extern "C"
BOOL RleFile_Draw(RLEFILE *prle, HDC hdc, int iFrame, int x, int y)
{
BOOL f;
if (prle == NULL || prle->pMovie == NULL)
return FALSE;
if (prle->hpal)
{
SelectPalette(hdc, prle->hpal, FALSE);
RealizePalette(hdc);
}
if (f = RleFile_Seek(prle, iFrame))
{
if (prle->cbFrame > 0)
{
StretchDIBits(hdc,
x, y, prle->Width, prle->Height,
0, 0, prle->Width, prle->Height,
prle->pFrame, (LPBITMAPINFO)&prle->bi,
DIB_RGB_COLORS, SRCCOPY);
}
}
return f;
}