644 lines
14 KiB
C++
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;
|
|
}
|