#include <mil.h>
#include <queue>
#if M_MIL_USE_WINDOWS
#include <windows.h>
#else
#include <pthread.h>
#endif
#define BUFFERING_SIZE_MAX 50
MIL_UINT32 MFTYPE DiskBufferingThread(void *TPar);
typedef struct ThreadParam
{
MIL_TEXT_PTR pFileName;
MIL_INT SequenceSizeBand, SequenceSizeX, SequenceSizeY;
MIL_INT FrameCount;
std::queue<MIL_ID> FifoDecompression;
std::queue<MIL_ID> FifoDisplay;
#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
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);
MdispAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_DEFAULT, &MilDisplay);
MdispControl(MilDisplay, M_NO_TEARING, M_ENABLE);
MdispInquire(MilDisplay, M_DISPLAY_TYPE, &DisplayType);
#if M_MIL_USE_WINDOWS
OPENFILENAME ofn;
MIL_TEXT_CHAR szFile[MAX_PATH];
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"));
BOOL FileNameFound = false;
DWORD lRetVal = 1;
do
{
FileNameFound = GetOpenFileName(&ofn);
if(!FileNameFound)
{
lRetVal = CommDlgExtendedError();
if(lRetVal == 0)
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
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);
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;
}
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);
#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);
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++;
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);
}
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);
}
#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
MbufCopy(MilBufferToDisplay, MilImageDisp);
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
}
if(!(DisplayType & M_AUXILIARY))
{
MappTimer(M_DEFAULT, M_TIMER_READ, &TimeSequence);
TimeWait = ((1/FrameRate) - (TimeSequence - TotalReplay));
MappTimer(M_DEFAULT, M_TIMER_WAIT, &TimeWait);
}
}
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;
}
MIL_UINT32 MFTYPE DiskBufferingThread(void *ThreadParameters)
{
THREAD_PARAM *pThreadParam = (THREAD_PARAM *) ThreadParameters;
MIL_ID CompressionBuffer = M_NULL;
MIL_INT n = 0;
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);
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;
MbufImportSequence(pThreadParam->pFileName, M_DEFAULT, M_LOAD,
M_NULL, &CompressionBuffer, n % pThreadParam->FrameCount, 1, M_READ);
n++;
while(pThreadParam->FifoDecompression.size() <= 1 && !pThreadParam->Exit)
MosSleep(10);
if(pThreadParam->Exit) break;
#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
MbufCopy(CompressionBuffer, MilBuf);
#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
}
MbufImportSequence(pThreadParam->pFileName, M_DEFAULT, M_NULL,
M_NULL, M_NULL, M_NULL, M_NULL, M_CLOSE);
MbufFree(CompressionBuffer);
return 0;
}