////////////////////////////////////////////////////////////////////////// // // 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 #include "unixstuff.h" #endif #include 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; }