#ifndef __AVIUTIL_H__ #define __AVIUTIL_H__ #define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. #include using namespace std; #include #include #include BOOL AVI_Init() { /* first let's make sure we are running on 1.1 */ WORD wVer = HIWORD(VideoForWindowsVersion()); if (wVer < 0x010a){ /* oops, we are too old, blow out of here */ //MessageBeep(MB_ICONHAND); MessageBox(NULL, L"Cant't init AVI File - Video for Windows version is to old", L"Error", MB_OK|MB_ICONSTOP); return FALSE; } AVIFileInit(); return TRUE; } BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename) { HRESULT hr = AVIFileOpen(pfile, // returned file pointer wxString::FromUTF8(filename), // file name OF_WRITE | OF_CREATE, // mode to open file with NULL); // use handler determined // from file extension.... if (hr != AVIERR_OK) return FALSE; return TRUE; } DWORD getFOURCC(const char* value) { if(_stricmp(value, "DIB") == 0) { return mmioFOURCC(value[0],value[1],value[2],' '); } else if((_stricmp(value, "CVID") == 0) || (_stricmp(value, "IV32") == 0) || (_stricmp(value, "MSVC") == 0) || (_stricmp(value, "IV50") == 0)) { return mmioFOURCC(value[0],value[1],value[2],value[3]); } else { return NULL; } } // Fill in the header for the video stream.... // The video stream will run in rate ths of a second.... BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second unsigned long buffersize, int rectwidth, int rectheight, const char* _compressor) { AVISTREAMINFO strhdr; memset(&strhdr, 0, sizeof(strhdr)); strhdr.fccType = streamtypeVIDEO;// stream type strhdr.fccHandler = getFOURCC(_compressor); //strhdr.fccHandler = 0; // no compression! //strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed //strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak //strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 //strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 //strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 //strhdr.dwFlags = AVISTREAMINFO_DISABLED; //strhdr.dwCaps = //strhdr.wPriority = //strhdr.wLanguage = strhdr.dwScale = 1; strhdr.dwRate = rate; // rate fps //strhdr.dwStart = //strhdr.dwLength = //strhdr.dwInitialFrames = strhdr.dwSuggestedBufferSize = buffersize; strhdr.dwQuality = -1; // use the default //strhdr.dwSampleSize = SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream (int) rectwidth, (int) rectheight); //strhdr.dwEditCount = //strhdr.dwFormatChangeCount = //strcpy(strhdr.szName, "Full Frames (Uncompressed)"); // And create the stream; HRESULT hr = AVIFileCreateStream(pfile, // file pointer ps, // returned stream pointer &strhdr); // stream header if (hr != AVIERR_OK) { return FALSE; } return TRUE; } string getFOURCCVAsString(DWORD value) { string returnValue = ""; if( value == 0 ) return returnValue; DWORD ch0 = value & 0x000000FF; returnValue.push_back((char) ch0); DWORD ch1 = (value & 0x0000FF00)>>8; returnValue.push_back((char) ch1); DWORD ch2 = (value & 0x00FF0000)>>16; returnValue.push_back((char) ch2); DWORD ch3 = (value & 0xFF000000)>>24; returnValue.push_back((char) ch3); return returnValue; } string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts) { char tmp[255]; string returnValue = "Dump of AVICOMPRESSOPTIONS\n"; returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n"; returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n"; _snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery); returnValue += tmp; _snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality); returnValue += tmp; _snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond); returnValue += tmp; if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");} else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");} else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");} else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");} else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);} returnValue += tmp; _snprintf(tmp, 255, "LPVOID lpFormat = %d\n", (int)opts.lpFormat); returnValue += tmp; _snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat); returnValue += tmp; _snprintf(tmp, 255, "LPVOID lpParms = %d\n", (int)opts.lpParms); returnValue += tmp; _snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms); returnValue += tmp; _snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery); returnValue += tmp; return returnValue; } BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi, const char* _compressor) { AVICOMPRESSOPTIONS opts; AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts}; memset(&opts, 0, sizeof(opts)); opts.fccType = streamtypeVIDEO; opts.fccHandler = getFOURCC(_compressor); //opts.fccHandler = 0; //opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed //opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak //opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 //opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 //opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 //opts.dwKeyFrameEvery = 5; //opts.dwQuality //opts.dwBytesPerSecond //opts.dwFlags = AVICOMPRESSF_KEYFRAMES; //opts.lpFormat //opts.cbFormat //opts.lpParms //opts.cbParms //opts.dwInterleaveEvery /* display the compression options dialog box if specified compressor is unknown */ if(getFOURCC(_compressor) == NULL) { if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) { return FALSE; } //printf("%s", dumpAVICOMPRESSOPTIONS(opts)); //MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK); } HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL); if (hr != AVIERR_OK) { return FALSE; } hr = AVIStreamSetFormat(*psCompressed, 0, lpbi, // stream format lpbi->biSize // format size + lpbi->biClrUsed * sizeof(RGBQUAD) ); if (hr != AVIERR_OK) { return FALSE; } return TRUE; } BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight) { // Fill in the stream header for the text stream.... AVISTREAMINFO strhdr; DWORD dwTextFormat; // The text stream is in 60ths of a second.... memset(&strhdr, 0, sizeof(strhdr)); strhdr.fccType = streamtypeTEXT; strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W'); strhdr.dwScale = 1; strhdr.dwRate = 60; strhdr.dwSuggestedBufferSize = sizeof(szText); SetRect(&strhdr.rcFrame, 0, (int) height, (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20 // ....and create the stream. HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr); if (hr != AVIERR_OK) { return FALSE; } dwTextFormat = sizeof(dwTextFormat); hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat)); if (hr != AVIERR_OK) { return FALSE; } return TRUE; } BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi) { int ImageSize = lpbi->biSizeImage; if (ImageSize == 0) { if (lpbi->biBitCount == 24) { ImageSize = lpbi->biWidth * lpbi->biHeight * 3; } } HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer time, // time of this frame 1, // number to write (LPBYTE) lpbi + // pointer to data lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD), ImageSize, // lpbi->biSizeImage, // size of this frame AVIIF_KEYFRAME, // flags.... NULL, NULL); if (hr != AVIERR_OK) { TCHAR strMsg[255]; _snwprintf(strMsg, 255, L"Error: AVIStreamWrite, error %d",hr); MessageBox(NULL, strMsg, L"", MB_OK); return FALSE; } return TRUE; } BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText) { int iLen = (int)strlen(szText); HRESULT hr = AVIStreamWrite(psText, time, 1, szText, iLen + 1, AVIIF_KEYFRAME, NULL, NULL); if (hr != AVIERR_OK) return FALSE; return TRUE; } BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText) { if (ps) AVIStreamClose(ps); if (psCompressed) AVIStreamClose(psCompressed); if (psText) AVIStreamClose(psText); return TRUE; } BOOL AVI_CloseFile(PAVIFILE pfile) { if (pfile) AVIFileClose(pfile); return TRUE; } BOOL AVI_Exit() { AVIFileExit(); return TRUE; } /* Here are the additional functions we need! */ static PAVIFILE pfile = NULL; static PAVISTREAM ps = NULL; static PAVISTREAM psCompressed = NULL; static int avi_count = 0; // Initialization... bool START_AVI(const char* file_name) { if(! AVI_Init()) { //printf("Error - AVI_Init()\n"); return false; } if(! AVI_FileOpenWrite(&pfile, file_name)) { //printf("Error - AVI_FileOpenWrite()\n"); return false; } return true; } bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata) { if(avi_count == 0) { if(! AVI_CreateStream(pfile, &ps, _frameRate, width*height/bits, width, height, _compressor)) { //printf("Error - AVI_CreateStream()\n"); return false; } BITMAPINFOHEADER bi; memset(&bi, 0, sizeof(bi)); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = width; bi.biHeight = height; bi.biPlanes = 1; bi.biBitCount = bits; bi.biCompression = BI_RGB; bi.biSizeImage = width * height * bits /8; if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor)) { return false; } } HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer avi_count, // time of this frame 1, // number to write pdata, width*height/8, // lpbi->biSizeImage, // size of this frame AVIIF_KEYFRAME, // flags.... NULL, NULL); if (hr != AVIERR_OK) { TCHAR strMsg[255]; _snwprintf(strMsg, 255, L"Error: AVIStreamWrite, error %d",hr); MessageBox(NULL, strMsg, L"", MB_OK); return FALSE; } avi_count++; return true; } //Now we can add frames // ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25); bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate) { LPBITMAPINFOHEADER lpbi; if(avi_count == 0) { lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); if(! AVI_CreateStream(pfile, &ps, _frameRate, (unsigned long) lpbi->biSizeImage, (int) lpbi->biWidth, (int) lpbi->biHeight, _compressor)) { //printf("Error - AVI_CreateStream()\n"); GlobalUnlock(lpbi); return false; } if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor)) { //printf("Error - AVI_SetOptions()\n"); GlobalUnlock(lpbi); return false; } GlobalUnlock(lpbi); } lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); if(! AVI_AddFrame(psCompressed, avi_count * 1, lpbi)) { //printf("Error - AVI_AddFrame()\n"); GlobalUnlock(lpbi); return false; } GlobalUnlock(lpbi); avi_count++; return true; } // The end... bool STOP_AVI() { if(! AVI_CloseStream(ps, psCompressed, NULL)) { //printf("Error - AVI_CloseStream()\n"); return false; } if(! AVI_CloseFile(pfile)) { //printf("Error - AVI_CloseFile()\n"); return false; } if(! AVI_Exit()) { //printf("Error - AVI_Exit()\n"); return false; } return true; } #endif