Click here to show toolbars of the Web Online Help System: show toolbars |
/*****************************************************************************************/ /* * File name: VioPlayback.cpp * Location: See Matrox Example Launcher in the MIL Control Center * * * Synopsis: This example demonstrates how to: * - playback a compressed sequence on the VIO system. * * This program uses 2 threads: * * - The DiskBuffering thread is responsible to read each compressed image * from disk, decompress it and put it in a FIFO. * * - The main thread is responsible to take an image from the FIFO and copy * it into the display. * */ // Headers. #include <mil.h> #include <queue> #if M_MIL_USE_WINDOWS #include <windows.h> #else #include <pthread.h> #endif // Number of images in the buffering grab queue. #define BUFFERING_SIZE_MAX 50 MIL_UINT32 MFTYPE DiskBufferingThread(void *TPar); // Thread parameters structure. typedef struct ThreadParam { MIL_TEXT_PTR pFileName; MIL_INT SequenceSizeBand, SequenceSizeX, SequenceSizeY; MIL_INT FrameCount; std::queue<MIL_ID> FifoDecompression; // FIFO containing buffers to be decompressed. std::queue<MIL_ID> FifoDisplay; // FIFO containing buffers to be displayed. #if M_MIL_USE_WINDOWS CRITICAL_SECTION FifoLock; #else pthread_mutex_t FifoLock; #endif MIL_INT Exit; } THREAD_PARAM; #if M_MIL_USE_LINUX int ExecuteCommand (const char *cmd, char **buffer, int *bufferSize) { FILE *sysCmdOutput = popen (cmd, "r"); int bufferIndex = 0; while (*bufferSize == fread (&((*buffer)[bufferIndex]), sizeof (char), *bufferSize, sysCmdOutput)) { char *tmp = new char [(*bufferSize)*2]; bufferIndex += *bufferSize; if (tmp == NULL) { fprintf (stderr,"Unable to allocate memory to read file in one buffer %i\n", (*bufferSize)*2); return -1; } memset(tmp, 0, (*bufferSize)*2); memcpy(tmp, *buffer, *bufferSize); delete [] *buffer; *buffer = tmp; *bufferSize *= 2; } pclose (sysCmdOutput); return 0; } #endif // Main function. int MosMain(int argc, char *argv[]) { MIL_ID MilApplication = M_NULL; MIL_ID MilSystem = M_NULL; MIL_ID MilDisplay = M_NULL; MIL_ID DiskBufferingThreadId = M_NULL; MIL_ID MilImageDisp = M_NULL; MIL_INT DisplaySizeBand, DisplaySizeX, DisplaySizeY; MIL_INT FrameCount=0, NbFramesReplayed=0; MIL_UINT BufferingSize = BUFFERING_SIZE_MAX; MIL_INT DisplayType = 0; double FrameRate; double TimeSequence, TimeWait = 0; double TotalReplay = 0.0; MIL_UINT i = 0; THREAD_PARAM ThreadParam; MappAlloc(M_NULL, M_DEFAULT, &MilApplication); MsysAlloc(M_DEFAULT, M_SYSTEM_VIO, M_DEFAULT, M_DEFAULT, &MilSystem); // Allocate VIO display auxiliary output. MdispAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_DEFAULT, &MilDisplay); // Enable no tearing on auxiliary display. MdispControl(MilDisplay, M_NO_TEARING, M_ENABLE); // Inquire information about the display. MdispInquire(MilDisplay, M_DISPLAY_TYPE, &DisplayType); // Select the file that we want to decompress. #if M_MIL_USE_WINDOWS OPENFILENAME ofn; MIL_TEXT_CHAR szFile[MAX_PATH]; // Initialize OPENFILENAME ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.lpstrFile = szFile; ofn.lpstrFile[0] = '\0'; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = MIL_TEXT("Avi Files\0*.avi\0All Files\0*.*\0"); ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; MosPrintf(MIL_TEXT("Please select avi file to replay.\n")); // Display the Open dialog box. BOOL FileNameFound = false; DWORD lRetVal = 1; do { FileNameFound = GetOpenFileName(&ofn); if(!FileNameFound) { lRetVal = CommDlgExtendedError(); if(lRetVal == 0) // Cancel Selected. break; } } while(!FileNameFound); if(lRetVal == 0) goto EXIT; ThreadParam.pFileName = ofn.lpstrFile; #else MosPrintf(MIL_TEXT("Please select avi file to replay.\n")); char FileDialogChooser[] = "zenity --title=\"Please select avi file to replay\" --file-selection"; int FilenameLength = 512; char *Filename = new char[FilenameLength]; bool bValidFilename = false; while(!bValidFilename) { memset(Filename, 0, FilenameLength); ExecuteCommand(FileDialogChooser, &Filename, &FilenameLength); if(strlen(Filename)) { char *NewLine = strchr(Filename, '\n'); *NewLine = 0; ThreadParam.pFileName = Filename; bValidFilename= true; } else { goto EXIT; } } #endif // Inquire information about the sequence. MbufDiskInquire(ThreadParam.pFileName, M_NUMBER_OF_IMAGES, &FrameCount); MbufDiskInquire(ThreadParam.pFileName, M_FRAME_RATE, &FrameRate); ThreadParam.FrameCount = FrameCount; MbufDiskInquire(ThreadParam.pFileName, M_SIZE_BAND, &ThreadParam.SequenceSizeBand); MbufDiskInquire(ThreadParam.pFileName, M_SIZE_X, &ThreadParam.SequenceSizeX); MbufDiskInquire(ThreadParam.pFileName, M_SIZE_Y, &ThreadParam.SequenceSizeY); // Allocate buffers for buffering. for(i = 0; i < BufferingSize; i++) { MIL_ID BufferingBuffer = M_NULL; MbufAllocColor(MilSystem, ThreadParam.SequenceSizeBand, ThreadParam.SequenceSizeX, ThreadParam.SequenceSizeY, 8 + M_UNSIGNED, M_IMAGE + (ThreadParam.SequenceSizeBand == 3 ? (M_YUV16 + M_PACKED): 0), &BufferingBuffer); MbufClear(BufferingBuffer, M_COLOR_BLACK); if(BufferingBuffer) ThreadParam.FifoDecompression.push(BufferingBuffer); else break; } // Allocate display buffer. if(MdispInquire(MilDisplay, M_DISPLAY_TYPE, 0) == M_AUXILIARY) { DisplaySizeBand = MdispInquire(MilDisplay, M_SIZE_BAND, 0); DisplaySizeX = MdispInquire(MilDisplay, M_SIZE_X, 0); DisplaySizeY = MdispInquire(MilDisplay, M_SIZE_Y, 0); } else { DisplaySizeBand = ThreadParam.SequenceSizeBand; DisplaySizeX = ThreadParam.SequenceSizeX; DisplaySizeY = ThreadParam.SequenceSizeY; } MbufAllocColor(MilSystem, DisplaySizeBand, DisplaySizeX, DisplaySizeY, 8 + M_UNSIGNED, M_IMAGE + M_DISP + (DisplaySizeBand == 3 ? (M_YUV16 + M_PACKED): 0), &MilImageDisp); MbufClear(MilImageDisp, M_COLOR_BLACK); MdispSelect(MilDisplay, MilImageDisp); MosPrintf(MIL_TEXT("Sequence: %s \n"), ThreadParam.pFileName); MosPrintf(MIL_TEXT("Sequence SizeX: %d SizeY: %d \n"), ThreadParam.SequenceSizeX, ThreadParam.SequenceSizeY); MosPrintf(MIL_TEXT("Frame count: %d\n"), FrameCount); MosPrintf(MIL_TEXT("Frame rate: %2.1f f/s\n"), FrameRate); MosPrintf(MIL_TEXT("Buffering Size: %d buffers\n"), BufferingSize); // Allocate disk buffering thread. #if M_MIL_USE_WINDOWS InitializeCriticalSection(&ThreadParam.FifoLock); #else pthread_mutex_init(&ThreadParam.FifoLock, NULL); #endif ThreadParam.Exit = false; MthrAlloc(MilSystem, M_THREAD, M_DEFAULT, &DiskBufferingThread, &ThreadParam, &DiskBufferingThreadId); // Wait for the disk buffering thread to fill the buffers. do { MosSleep(100); MosPrintf(MIL_TEXT("\rLoading %2.0f%% "), ((ThreadParam.FifoDisplay.size()*100.0) / BufferingSize)); } while(ThreadParam.FifoDisplay.size() < BufferingSize-1); MosPrintf(MIL_TEXT("Done.\n\n")); NbFramesReplayed = 0; MappTimer(M_DEFAULT, M_TIMER_RESET, M_NULL); while (!MosKbhit()) { MIL_ID MilBufferToDisplay = M_NULL; NbFramesReplayed++; // Wait if buffering FIFO is empty. while(ThreadParam.FifoDisplay.empty()) { MosPrintf(MIL_TEXT("\n\nCannot display sequence at the recorded frame rate.\n")); MosPrintf(MIL_TEXT("Disk access and JPEG decompression operations on this system ") MIL_TEXT("are too slow.\n\n")); TotalReplay = 0.0; MosSleep(1000); } // Print statistics. MappTimer(M_DEFAULT, M_TIMER_READ, &TotalReplay); if((NbFramesReplayed % 10) == 0) { MosPrintf(MIL_TEXT("Frame #: %d, Frame rate: %.1f fps, Buffering: %.0f%% \r"), NbFramesReplayed, NbFramesReplayed/TotalReplay, (ThreadParam.FifoDisplay.size()* 100.0) / BufferingSize); } // Get buffer from UsedPool FIFO. #if M_MIL_USE_WINDOWS EnterCriticalSection(&ThreadParam.FifoLock); #else pthread_mutex_lock(&ThreadParam.FifoLock); #endif MilBufferToDisplay = ThreadParam.FifoDisplay.front(); ThreadParam.FifoDisplay.pop(); #if M_MIL_USE_WINDOWS LeaveCriticalSection(&ThreadParam.FifoLock); #else pthread_mutex_unlock(&ThreadParam.FifoLock); #endif // Copy to the display. MbufCopy(MilBufferToDisplay, MilImageDisp); // Put buffer back in FreePool FIFO. if(MilBufferToDisplay) { #if M_MIL_USE_WINDOWS EnterCriticalSection(&ThreadParam.FifoLock); #else pthread_mutex_lock(&ThreadParam.FifoLock); #endif ThreadParam.FifoDecompression.push(MilBufferToDisplay); #if M_MIL_USE_WINDOWS LeaveCriticalSection(&ThreadParam.FifoLock); #else pthread_mutex_unlock(&ThreadParam.FifoLock); #endif } // Wait to have a proper frame rate when in windowed mode. // Not needed in auxiliary display mode. if(!(DisplayType & M_AUXILIARY)) { MappTimer(M_DEFAULT, M_TIMER_READ, &TimeSequence); TimeWait = ((1/FrameRate) - (TimeSequence - TotalReplay)); MappTimer(M_DEFAULT, M_TIMER_WAIT, &TimeWait); } } // Close buffering thread. ThreadParam.Exit = true; MthrWait(DiskBufferingThreadId, M_THREAD_END_WAIT, M_NULL); MthrFree(DiskBufferingThreadId); MosGetchar(); while(!ThreadParam.FifoDisplay.empty()) { MbufFree(ThreadParam.FifoDisplay.front()); ThreadParam.FifoDisplay.pop(); } while(!ThreadParam.FifoDecompression.empty()) { MbufFree(ThreadParam.FifoDecompression.front()); ThreadParam.FifoDecompression.pop(); } #if M_MIL_USE_WINDOWS DeleteCriticalSection(&ThreadParam.FifoLock); #else pthread_mutex_destroy(&ThreadParam.FifoLock); #endif MbufFree(MilImageDisp); EXIT: MdispFree(MilDisplay); MsysFree(MilSystem); MappFree(MilApplication); return 0; } ///////////////////////////////////////////////////////////////////////// // The DiskBuffering thread is responsible to read each compressed image // from disk, decompress it and put it in a FIFO. MIL_UINT32 MFTYPE DiskBufferingThread(void *ThreadParameters) { THREAD_PARAM *pThreadParam = (THREAD_PARAM *) ThreadParameters; MIL_ID CompressionBuffer = M_NULL; MIL_INT n = 0; // Allocate compression buffer. MbufAllocColor(M_DEFAULT_HOST, pThreadParam->SequenceSizeBand, pThreadParam->SequenceSizeX, pThreadParam->SequenceSizeY, 8 + M_UNSIGNED, M_IMAGE + M_COMPRESS + M_JPEG_LOSSY + ((pThreadParam->SequenceSizeBand == 3) ?M_YUV16 + M_PACKED: 0), &CompressionBuffer); // Open the sequence file. MbufImportSequence(pThreadParam->pFileName, M_DEFAULT, M_NULL, M_NULL, M_NULL, M_NULL, M_NULL, M_OPEN); while(!pThreadParam->Exit) { MIL_ID MilBuf = M_NULL; // Read image from disk. MbufImportSequence(pThreadParam->pFileName, M_DEFAULT, M_LOAD, M_NULL, &CompressionBuffer, n % pThreadParam->FrameCount, 1, M_READ); n++; // Decompress image from disk and put it in the FIFO. // Wait if there are no free buffers. while(pThreadParam->FifoDecompression.size() <= 1 && !pThreadParam->Exit) MosSleep(10); if(pThreadParam->Exit) break; // Get a free buffer from the FreePool FIFO. #if M_MIL_USE_WINDOWS EnterCriticalSection(&pThreadParam->FifoLock); #else pthread_mutex_lock(&pThreadParam->FifoLock); #endif MilBuf = pThreadParam->FifoDecompression.front(); pThreadParam->FifoDecompression.pop(); #if M_MIL_USE_WINDOWS LeaveCriticalSection(&pThreadParam->FifoLock); #else pthread_mutex_unlock(&pThreadParam->FifoLock); #endif // Decompress the image. MbufCopy(CompressionBuffer, MilBuf); // Put the decompressed image in the UsedPool FIFO. #if M_MIL_USE_WINDOWS EnterCriticalSection(&pThreadParam->FifoLock); #else pthread_mutex_lock(&pThreadParam->FifoLock); #endif pThreadParam->FifoDisplay.push(MilBuf); #if M_MIL_USE_WINDOWS LeaveCriticalSection(&pThreadParam->FifoLock); #else pthread_mutex_unlock(&pThreadParam->FifoLock); #endif } // Close the sequence file. MbufImportSequence(pThreadParam->pFileName, M_DEFAULT, M_NULL, M_NULL, M_NULL, M_NULL, M_NULL, M_CLOSE); // Free compress buffer. MbufFree(CompressionBuffer); return 0; }