////////////////////////////////////////////////////////////////////////// // // 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" } #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; hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 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; 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 if (!IS_INTRESOURCE(szName) && (*szName == 0)) return FALSE; 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) { if (prle->hRes) { FreeResource(prle->hRes); } else UnmapViewOfFile(prle->pFile); } 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++; if ((dwFileLen > 0) && (dwLength > dwFileLen)) { // File is physically shorter than the length written in its header. // Can't handle it. goto exit; } 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: { prle->pMainHeader = (MainAVIHeader PTR *)pdw; 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: { stream++; if (prle->pStream != NULL) break; if (((AVIStreamHeader PTR *)pdw)->fccType != streamtypeVIDEO) break; prle->iStream = stream-1; prle->pStream = (AVIStreamHeader PTR*)pdw; if (prle->pStream->dwFlags & AVISF_VIDEO_PALCHANGES) goto exit; } break; case ckidSTREAMFORMAT: if (prle->pFormat != NULL) break; if (prle->pStream == NULL) break; prle->pFormat = (LPBITMAPINFOHEADER)pdw; 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) { prle->clrKey = rgbS; return TRUE; } ////////////////////////////////////////////////////////////////////////// // // 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 (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)) { HDC h = CreateCompatibleDC(hdc); if (h) { HBITMAP hbmp = CreateCompatibleBitmap(hdc, prle->Width, prle->Height); if (hbmp) { HBITMAP hbmpOld = (HBITMAP)SelectObject(h, hbmp); iFrame = prle->iFrame; for (i=prle->iKeyFrame; i<=iFrame; i++) RleFile_Draw(prle, h, i, 0, 0); GdiTransparentBlt(hdc, x, y, prle->Width, prle->Height, h, 0, 0, prle->Width, prle->Height, prle->clrKey); SelectObject(h, hbmpOld); DeleteObject(hbmp); } DeleteDC(h); } } 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; }