Click here to show toolbars of the Web Online Help System: show toolbars |
/*****************************************************************************************/ /* * File name: VioFeaturesDemo.cpp * Location: See Matrox Example Launcher in the MIL Control Center * * * Synopsis: This example demonstrates how to: * - set the Matrox Vio in minimum-latency pass-through mode; * - set the color overlay in the Matrox auxiliary display; * - detect when the video input source is plugged and unplugged by * hooking on the camera present event; * - display a splash screen when the video input source is not * present or unplugged; * - grab in host memory using MdigProcess; * - display live video on a windowed display. * * If you have the compression/decompression runtime license * package installed: * - compress the grab buffers in JPEG format and save them to disk; * * This example is based on MDigProcess.cpp * * It is recommended to have at least 256 MB of MIL non-paged memory. * See MilConfig utility in the "Non-paged memory" page. */ // Headers. #include <mil.h> #include <queue> #if M_MIL_USE_WINDOWS #include <windows.h> #define MosRefresh() #else #include <stdlib.h> #include <ncurses.h> #include <pthread.h> #include <X11/Xlib.h> // use printw curses function #define MosPrintf printw #define MosRefresh refresh #endif // Number of images in the buffering grab queue. #define BUFFERING_SIZE_MAX 24 #define PROC_BUFFERING_SIZE_MAX 50 // Splash Screen image file. #define SPLASH_SCREEN_IMAGE_FILE M_IMAGE_PATH MIL_TEXT("imaginglogo.mim") // JPEG AVI file name. #define SEQUENCE_FILE MIL_TEXT("MilVIOSequence.avi") // Saved image file name. #define IMAGE_FILE MIL_TEXT("MilVIOImage") // Quantization factor to use during the compression. // Valid values are 1 to 99 (higher to lower quality). #define COMPRESSION_Q_FACTOR 50 // Scale factor for the thumbnail. #define SCALE_FACTOR 3 #define OFFSET_X 10 #define OFFSET_Y 10 #define EVERY_THUMNAIL_IMAGES 10 // User's processing function hook data structure. typedef struct { MIL_ID MilSystem; MIL_ID MilDigitizer; MIL_ID MilDisplay; MIL_ID MilImageDispSplashScreen; MIL_ID MilWindowedDisplay; MIL_ID MilImageWindowedDisp; MIL_ID MilImageDispOvr; MIL_INT CameraPresent; MIL_INT SaveSequenceToDisk; MIL_INT SaveAnImageToDisk; MIL_INT ProcessedImageCount; double DisplayUpdateTime; MIL_INT Exit; } HookDataStruct; typedef struct { // Host YUV16 buffer used for compression. MIL_ID MilBufHostYUV16; double MilBufHostYUV16SizeInMB; // Host BGR32 image used for the thumbnail display. MIL_ID MilBufHostScaled; double MilBufHostScaledSizeInMB; bool MilBufHostScaledInUse; MIL_INT MilBufHostScaledSizeX; MIL_INT MilBufHostScaledSizeY; // Compression buffer. MIL_ID MilCompressedImage; } BUFFERINGDATASTRUCT; // User's processing function prototype. MIL_INT MFTYPE ProcessingFunction(MIL_INT HookType, MIL_ID HookId, void* HookDataPtr); MIL_UINT32 MFTYPE ProcessingThread(void *TPar); MIL_INT MFTYPE CameraPresentHook(MIL_INT HookType, MIL_ID EventId, void* UserStructPtr); void OverlayDraw(MIL_ID MilDisplay); std::queue<BUFFERINGDATASTRUCT> FifoGrabInUse; std::queue<BUFFERINGDATASTRUCT> FifoGrabFree; #if M_MIL_USE_WINDOWS CRITICAL_SECTION FifoLock; #else pthread_mutex_t FifoLock; #endif // Main function. int MosMain(void) { HookDataStruct UserHookData; MIL_ID MilApplication = M_NULL; MIL_ID MilSystem = M_NULL; MIL_ID MilDigitizer = M_NULL; MIL_ID MilDisplay = M_NULL; MIL_ID MilImageDispSplashScreen = M_NULL; MIL_ID MilImageDispSplashScreenChild = M_NULL; MIL_ID MilWindowedDisplay = M_NULL; MIL_ID MilImageWindowedDisp = M_NULL; MIL_ID MilImageDispOvr = M_NULL; MIL_ID MilGrabBufferList[BUFFERING_SIZE_MAX] = { 0 }; MIL_ID ProcessingThreadId = M_NULL; BUFFERINGDATASTRUCT BufferingDataStruct[PROC_BUFFERING_SIZE_MAX]; MIL_INT SaveSequenceToDisk = false, JPEGLicensePresent = false, LicenseModules; double ProcessFrameRate = 0; MIL_INT MilGrabBufferListSize = 0; MIL_INT MilProcListSize = 0; MIL_INT ProcessFrameMissed = 0, ProcessFrameCount = 0, NbFrames = 0; MIL_INT i = 0, SizeBand = 0, SizeX = 0, SizeY = 0, SPSizeX = 0, SPSizeY = 0; MIL_TEXT_CHAR DisplayFormat[512] = {0}; MIL_TEXT_CHAR DigitizerFormat[512] = {0}; MIL_TEXT_CHAR SplashScreenImageFile[512] = {0}; MIL_INT c = 0; #if M_MIL_USE_WINDOWS InitializeCriticalSection(&FifoLock); #else initscr(); move(0,0); pthread_mutex_init(&FifoLock, NULL); #endif MappAlloc(M_NULL, M_DEFAULT, &MilApplication); MsysAlloc(M_DEFAULT, M_SYSTEM_VIO , M_DEV0, M_DEFAULT, &MilSystem); // Allocate digitizer. MdigAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_DEFAULT, &MilDigitizer); SizeBand = MdigInquire(MilDigitizer, M_SIZE_BAND, M_NULL); SizeX = MdigInquire(MilDigitizer, M_SIZE_X, M_NULL); SizeY = MdigInquire(MilDigitizer, M_SIZE_Y, M_NULL); // Allocate VIO display output. MdispAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_AUXILIARY, &MilDisplay); // Allocate windowed display in no tearing mode. MdispAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_WINDOWED, &MilWindowedDisplay); // We try to enable no-tearing feature by default, but it is not // supported by all displays adapters. MappControl(M_DEFAULT, M_ERROR, M_PRINT_DISABLE); MdispControl(MilWindowedDisplay, M_NO_TEARING, M_ENABLE); MappControl(M_DEFAULT, M_ERROR, M_PRINT_ENABLE); // Allocate display buffer for Vio splash screen and select it. MbufAllocColor(MilSystem, MdispInquire(MilDisplay, M_SIZE_BAND, M_NULL), MdispInquire(MilDisplay, M_SIZE_X, M_NULL), MdispInquire(MilDisplay, M_SIZE_Y, M_NULL), 8+M_UNSIGNED, M_IMAGE + M_DISP + M_PROC, &MilImageDispSplashScreen); MbufClear(MilImageDispSplashScreen, 255); // Allocate display buffer for the display screen and select it. MappControl(M_DEFAULT, M_ERROR, M_PRINT_DISABLE); MbufAllocColor(MilSystem, SizeBand, SizeX, SizeY, 8L+M_UNSIGNED, M_IMAGE + M_DISP + (SizeBand == 3? M_YUV16 + M_PACKED:0) + M_NON_PAGED + M_VIDEO_MEMORY, &MilImageWindowedDisp); MappControl(M_DEFAULT, M_ERROR, M_PRINT_ENABLE); // If it is not possible to allocate directly in the video memory, // allocate in the host memory. if(MilImageWindowedDisp == M_NULL) MbufAllocColor(MilSystem, SizeBand, SizeX, SizeY, 8L+M_UNSIGNED, M_IMAGE + M_DISP + (SizeBand == 3? M_YUV16 + M_PACKED:0) + M_NON_PAGED, &MilImageWindowedDisp); MbufClear(MilImageWindowedDisp, M_COLOR_BLACK); // Load splash screen. MosStrcpy(SplashScreenImageFile, 512, SPLASH_SCREEN_IMAGE_FILE); MappControl(M_DEFAULT, M_ERROR, M_PRINT_DISABLE); if(MbufDiskInquire(SplashScreenImageFile, M_FILE_FORMAT, M_NULL) == M_INVALID) { MosStrcpy(SplashScreenImageFile, 512, MIL_TEXT("..\\")); MosStrcat(SplashScreenImageFile, 512, SPLASH_SCREEN_IMAGE_FILE); } MappControl(M_DEFAULT, M_ERROR, M_PRINT_ENABLE); MbufDiskInquire(SplashScreenImageFile, M_SIZE_X, &SPSizeX); MbufDiskInquire(SplashScreenImageFile, M_SIZE_Y, &SPSizeY); MbufChild2d(MilImageDispSplashScreen, SizeX/2 - SPSizeX/2, SizeY/2 - SPSizeY/2, SPSizeX, SPSizeY, &MilImageDispSplashScreenChild); MbufLoad(SplashScreenImageFile, MilImageDispSplashScreenChild); MbufFree(MilImageDispSplashScreenChild); // Select the splash screen on auxiliary display MdispSelect(MilDisplay, MilImageDispSplashScreen); UserHookData.MilSystem = MilSystem; UserHookData.MilDigitizer = MilDigitizer; UserHookData.MilDisplay = MilDisplay; MdispInquire(MilDisplay, M_FORMAT, (MIL_TEXT_PTR)&DisplayFormat); MdigInquire(MilDigitizer, M_FORMAT, (MIL_TEXT_PTR)&DigitizerFormat); MosPrintf(MIL_TEXT("This example demonstrates the features of the Matrox Vio.\n\n")); MosPrintf(MIL_TEXT("The currently selected DCF is:\n%s\n\n"), DigitizerFormat); MosPrintf(MIL_TEXT("The currently selected VCF is: \n%s\n\n"), DisplayFormat); MappInquire(M_DEFAULT, M_LICENSE_MODULES, &LicenseModules); if(LicenseModules & M_LICENSE_JPEGSTD) { MosPrintf(MIL_TEXT("\nDo you want to compress and archive the input video? (y/n)\n\n")); MosRefresh(); if(MosGetch() == 'y') { MosPrintf(MIL_TEXT("AVI file: %s\n\n"), SEQUENCE_FILE); SaveSequenceToDisk = true; MbufExportSequence(SEQUENCE_FILE, M_DEFAULT, M_NULL, M_NULL, M_DEFAULT, M_OPEN); } } MosRefresh(); // Allocated host buffer for compression and to display the thumbnail. for(MilProcListSize = 0; MilProcListSize < PROC_BUFFERING_SIZE_MAX; MilProcListSize++) { MbufAllocColor(MilSystem, SizeBand, SizeX, SizeY, 8+M_UNSIGNED, M_IMAGE + M_NON_PAGED + (SizeBand == 3? M_YUV16 + M_PACKED:0), &BufferingDataStruct[MilProcListSize].MilBufHostYUV16); BufferingDataStruct[MilProcListSize].MilBufHostYUV16SizeInMB = (SizeX * SizeY * (SizeBand == 3? 2:1)) / (1024.0*1024.0); BufferingDataStruct[MilProcListSize].MilBufHostScaledInUse = false; BufferingDataStruct[MilProcListSize].MilBufHostScaledSizeInMB = (((SizeX * SizeY * (SizeBand == 3? 4:1)) / (1024.0*1024.0)))/ (SCALE_FACTOR*SCALE_FACTOR); BufferingDataStruct[MilProcListSize].MilBufHostScaledSizeX = (MIL_INT) (SizeX / SCALE_FACTOR); BufferingDataStruct[MilProcListSize].MilBufHostScaledSizeY = (MIL_INT) (SizeY / SCALE_FACTOR); MbufAllocColor(MilSystem, SizeBand, BufferingDataStruct[MilProcListSize].MilBufHostScaledSizeX, BufferingDataStruct[MilProcListSize].MilBufHostScaledSizeY, 8+M_UNSIGNED, M_IMAGE + M_NON_PAGED + (SizeBand == 3 ? M_BGR32 + M_PACKED:0), &BufferingDataStruct[MilProcListSize].MilBufHostScaled); if(SaveSequenceToDisk) { MbufAllocColor(MilSystem, SizeBand, SizeX, SizeY, 8+M_UNSIGNED, M_IMAGE + M_COMPRESS + M_JPEG_LOSSY + (SizeBand == 3 ? M_YUV16+M_PACKED:0), &BufferingDataStruct[MilProcListSize].MilCompressedImage); MbufControl(BufferingDataStruct[MilProcListSize].MilCompressedImage, M_Q_FACTOR, COMPRESSION_Q_FACTOR); } else BufferingDataStruct[MilProcListSize].MilCompressedImage = M_NULL; FifoGrabFree.push(BufferingDataStruct[MilProcListSize]); } if(MappGetError(M_DEFAULT, M_CURRENT,M_NULL) == 0) { // Allocate the grab buffers and clear them. MappControl(M_DEFAULT, M_ERROR, M_PRINT_DISABLE); for(MilGrabBufferListSize = 0; MilGrabBufferListSize < BUFFERING_SIZE_MAX; MilGrabBufferListSize++) { MbufAllocColor(MilSystem, SizeBand, SizeX, SizeY, 8+M_UNSIGNED, M_IMAGE + M_GRAB + M_ON_BOARD + (SizeBand == 3 ? M_YUV16 + M_PACKED:0), &MilGrabBufferList[MilGrabBufferListSize]); if(MilGrabBufferList[MilGrabBufferListSize]) MbufClear(MilGrabBufferList[MilGrabBufferListSize], 0xFF); else break; } MappControl(M_DEFAULT, M_ERROR, M_PRINT_ENABLE); // Free a buffer to leave space for possible temporary buffer. MilGrabBufferListSize--; MbufFree(MilGrabBufferList[MilGrabBufferListSize]); // Enable display overlay annotations on auxiliary display. MdispControl(MilDisplay, M_OVERLAY, M_ENABLE); // Inquire the Vio overlay buffer associated with the display. MdispInquire(MilDisplay, M_OVERLAY_ID, &MilImageDispOvr); // Clear the overlay to transparent. MdispControl(MilDisplay, M_OVERLAY_CLEAR, M_DEFAULT); // Enable overlay annotations. MdispControl(MilDisplay, M_OVERLAY_SHOW, M_ENABLE); // Set graphic text to transparent background. MgraControl(M_DEFAULT, M_BACKGROUND_MODE, M_TRANSPARENT); // Set drawing color to red. MgraColor(M_DEFAULT, M_COLOR_WHITE); // This control enables direct acquisition to display. MdispControl(MilDisplay, M_SELECT_VIDEO_SOURCE, MilDigitizer); // Change display window title. MdispControl(MilWindowedDisplay, M_TITLE, M_PTR_TO_DOUBLE(MIL_TEXT("Display Window"))); MdispSelect(MilWindowedDisplay, MilImageWindowedDisp); // Initialize the User's processing function data structure. UserHookData.ProcessedImageCount = 0; UserHookData.MilSystem = MilSystem; UserHookData.MilDigitizer = MilDigitizer; UserHookData.MilDisplay = MilDisplay; UserHookData.MilImageDispSplashScreen = MilImageDispSplashScreen; UserHookData.MilWindowedDisplay = MilWindowedDisplay; UserHookData.MilImageWindowedDisp = MilImageWindowedDisp; UserHookData.MilImageDispOvr = MilImageDispOvr; UserHookData.CameraPresent = true; UserHookData.SaveSequenceToDisk = SaveSequenceToDisk; UserHookData.SaveAnImageToDisk = false; UserHookData.Exit = false; // Add hook on camera present. It is used to display the splash screen when the // input source is unplugged. MdigHookFunction(MilDigitizer, M_CAMERA_PRESENT, CameraPresentHook, (void *)(&UserHookData)); // Draw Overlay. OverlayDraw(MilImageDispOvr); // Print a message. MosPrintf(MIL_TEXT("The Matrox Vio is now:\n")); MosPrintf(MIL_TEXT(" - grabbing in a windowed display\n")); MosPrintf(MIL_TEXT(" - displaying the input video on the auxiliary display in\n")); MosPrintf(MIL_TEXT(" minimum-latency pass-through mode with overlay\n")); if(SaveSequenceToDisk) MosPrintf(MIL_TEXT(" - compressing and archiving the grabbed video\n")); MosPrintf(MIL_TEXT("\nPress 's' to save the current image to disk.\n")); MosPrintf(MIL_TEXT("Press 'q' to stop grabbing.\n\n")); MosRefresh(); // Allocate compress and disk buffering thread. MthrAlloc(M_DEFAULT, M_THREAD, M_DEFAULT, &ProcessingThread, &UserHookData, &ProcessingThreadId); MappControl(M_DEFAULT, M_ERROR, M_PRINT_DISABLE); // Start the processing. The processing function is called for every frame grabbed. MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize, M_START, M_DEFAULT, ProcessingFunction, &UserHookData); while(!MosKbhit()) { c = MosGetch(); if(c == 's') UserHookData.SaveAnImageToDisk = true; // exit. if(c == 'q') break; } #if M_MIL_USE_LINUX clear(); move(0,0); MosRefresh(); #endif // Stop the processing thread. UserHookData.Exit = true; MthrWait(ProcessingThreadId, M_THREAD_END_WAIT, M_NULL); MthrFree(ProcessingThreadId); // Stop the processing. MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize, M_STOP, M_DEFAULT, ProcessingFunction, &UserHookData); MappControl(M_DEFAULT, M_ERROR, M_PRINT_ENABLE); // Unhook camera present hook. MdigHookFunction(MilDigitizer, M_CAMERA_PRESENT + M_UNHOOK, CameraPresentHook, (void *)(&UserHookData)); // Print statistics. MdigInquire(MilDigitizer, M_PROCESS_FRAME_COUNT, &ProcessFrameCount); MdigInquire(MilDigitizer, M_PROCESS_FRAME_RATE, &ProcessFrameRate); MdigInquire(MilDigitizer, M_PROCESS_FRAME_MISSED, &ProcessFrameMissed); MosPrintf(MIL_TEXT("\n\n%ld frames grabbed at %.1f frames/sec (%.1f ms/frame).\n") MIL_TEXT("Frame(s) missed:%d .\n"), ProcessFrameCount, ProcessFrameRate, 1000.0/ProcessFrameRate, ProcessFrameMissed); // Close the windowed display. MdispSelect(MilWindowedDisplay, M_NULL); // Select auxiliary display option on exit. MosPrintf(MIL_TEXT("\nSelect auxiliary display option on exit:\n")); MosPrintf(MIL_TEXT("1: Splash screen visible (default)\n")); MosPrintf(MIL_TEXT("2: Live video with overlay\n")); MosPrintf(MIL_TEXT("3: Live video without overlay\n")); MosPrintf(MIL_TEXT("4: Auxiliary display disabled\n")); MosRefresh(); c = MosGetch(); switch(c) { case '1': // Splash-Screen. default: MdispControl(MilDisplay, M_OVERLAY, M_DISABLE); MdispControl(MilDisplay, M_OVERLAY_SHOW, M_DISABLE); MdispControl(MilDisplay, M_SELECT_VIDEO_SOURCE, M_NULL); MdispControl(MilDisplay, M_AUXILIARY_KEEP_DISPLAY_ALIVE, M_ENABLE); break; case '2': // Live video (with overlay). MdispControl(MilDisplay, M_OVERLAY, M_ENABLE); MdispControl(MilDisplay, M_OVERLAY_SHOW, M_ENABLE); MdispControl(MilDisplay, M_SELECT_VIDEO_SOURCE, MilDigitizer); MdispControl(MilDisplay, M_AUXILIARY_KEEP_DISPLAY_ALIVE, M_ENABLE); break; case '3': // Live video (without overlay). MdispControl(MilDisplay, M_OVERLAY, M_DISABLE); MdispControl(MilDisplay, M_OVERLAY_SHOW, M_DISABLE); MdispControl(MilDisplay, M_SELECT_VIDEO_SOURCE, MilDigitizer); MdispControl(MilDisplay, M_AUXILIARY_KEEP_DISPLAY_ALIVE, M_ENABLE); break; case '4': // Auxiliary display disabled. MdispControl(MilDisplay, M_SELECT_VIDEO_SOURCE, MilDigitizer); MdispControl(MilDisplay, M_AUXILIARY_KEEP_DISPLAY_ALIVE, M_DISABLE); break; } } MthrWait(M_DEFAULT, M_THREAD_WAIT, M_NULL); // Sequence file closing if required. if(SaveSequenceToDisk) MbufExportSequence(SEQUENCE_FILE, M_DEFAULT, M_NULL, M_NULL, ProcessFrameRate, M_CLOSE); // Free the grab buffers. while(MilGrabBufferListSize > 0) { MbufFree(MilGrabBufferList[--MilGrabBufferListSize]); }; // Free the compress and host buffers. while(MilProcListSize>0) { MilProcListSize--; MbufFree(BufferingDataStruct[MilProcListSize].MilBufHostYUV16); MbufFree(BufferingDataStruct[MilProcListSize].MilBufHostScaled); MbufFree(BufferingDataStruct[MilProcListSize].MilCompressedImage); }; if(MilWindowedDisplay) MdispFree(MilWindowedDisplay); #if M_MIL_USE_WINDOWS DeleteCriticalSection(&FifoLock); #else pthread_mutex_destroy(&FifoLock); endwin(); #endif MdispFree(MilDisplay); MdigFree(MilDigitizer); MbufFree(MilImageDispSplashScreen); MbufFree(MilImageWindowedDisp); MsysFree(MilSystem); MappFree(MilApplication); return 0; } // User's processing function called every time a grab buffer is modified. // ----------------------------------------------------------------------- MIL_INT MFTYPE ProcessingFunction(MIL_INT HookType, MIL_ID HookId, void* HookDataPtr) { HookDataStruct *UserHookDataPtr = (HookDataStruct *)HookDataPtr; BUFFERINGDATASTRUCT BufferingDataStruct; MIL_ID ModifiedBufferId; double TimeS, TimeE; MIL_INT CameraPresent = false; if(UserHookDataPtr->Exit) return 0; // Inquire if the camera is present. MdigInquire(UserHookDataPtr->MilDigitizer, M_CAMERA_PRESENT, &CameraPresent); // If the state of camera present does not match the state of the CameraPresentHook // callback function, call it to enable/disable the splash screen. if((CameraPresent != UserHookDataPtr->CameraPresent)) { MosSleep(300); // Wait a little for the camera present circuitry to stabilize. CameraPresentHook(M_CAMERA_PRESENT, 0, HookDataPtr); } // Retrieve the MIL_ID of the grabbed buffer. MdigGetHookInfo(HookId, M_MODIFIED_BUFFER+M_BUFFER_ID, &ModifiedBufferId); while(FifoGrabFree.empty() && !UserHookDataPtr->Exit) MosSleep(1); if(UserHookDataPtr->Exit) return 0; // If camera is not present, skip. if(!UserHookDataPtr->CameraPresent || !CameraPresent) return 0; // Retrieve a free host buffer to copy the on-board buffer into it. #if M_MIL_USE_WINDOWS EnterCriticalSection(&FifoLock); #else pthread_mutex_lock(&FifoLock); #endif BufferingDataStruct = FifoGrabFree.front(); FifoGrabFree.pop(); #if M_MIL_USE_WINDOWS LeaveCriticalSection(&FifoLock); #else pthread_mutex_unlock(&FifoLock); #endif // Copy the grab image to the host buffer. MbufCopy(ModifiedBufferId, BufferingDataStruct.MilBufHostYUV16); // Copy to display of the VGA display. MappTimer(M_DEFAULT, M_TIMER_READ, &TimeS); MbufCopy(ModifiedBufferId, UserHookDataPtr->MilImageWindowedDisp); MappTimer(M_DEFAULT, M_TIMER_READ, &TimeE); UserHookDataPtr->DisplayUpdateTime = TimeE - TimeS; // Copy the thumbnail scaled image to the host. if((UserHookDataPtr->ProcessedImageCount % EVERY_THUMNAIL_IMAGES) == 0) { BufferingDataStruct.MilBufHostScaledInUse = true; MbufTransfer(ModifiedBufferId, BufferingDataStruct.MilBufHostScaled, 0, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT, BufferingDataStruct.MilBufHostScaledSizeX, BufferingDataStruct.MilBufHostScaledSizeY, M_DEFAULT, M_COPY + M_SCALE, M_DRIVER_MODE, M_DEFAULT, M_NULL); } else { BufferingDataStruct.MilBufHostScaledInUse = false; } #if M_MIL_USE_WINDOWS EnterCriticalSection(&FifoLock); #else pthread_mutex_lock(&FifoLock); #endif FifoGrabInUse.push(BufferingDataStruct); #if M_MIL_USE_WINDOWS LeaveCriticalSection(&FifoLock); #else pthread_mutex_unlock(&FifoLock); #endif return 0; } // User's processing thread called every time a host buffer is modified. // ----------------------------------------------------------------------- MIL_UINT32 MFTYPE ProcessingThread(void *HookDataPtr) { HookDataStruct *UserHookDataPtr = (HookDataStruct *)HookDataPtr; BUFFERINGDATASTRUCT BufferingDataStruct; double TimeS, TimeE; double CompressionTime = 0.0; static double TumbnailUpdateTime = 0.0; double DisplayUpdateTime = 0.0; MIL_INT SavedImageIndex = 0; while(!UserHookDataPtr->Exit) { while(FifoGrabInUse.empty() && !UserHookDataPtr->Exit) MosSleep(1); if(UserHookDataPtr->Exit) break; UserHookDataPtr->ProcessedImageCount++; // Retrieve a previously grabbed buffer to process it. #if M_MIL_USE_WINDOWS EnterCriticalSection(&FifoLock); #else pthread_mutex_lock(&FifoLock); #endif BufferingDataStruct = FifoGrabInUse.front(); FifoGrabInUse.pop(); #if M_MIL_USE_WINDOWS LeaveCriticalSection(&FifoLock); #else pthread_mutex_unlock(&FifoLock); #endif // Compress and save compressed image. if(UserHookDataPtr->SaveSequenceToDisk) { MappTimer(M_DEFAULT, M_TIMER_READ, &TimeS); MbufCopy(BufferingDataStruct.MilBufHostYUV16, BufferingDataStruct.MilCompressedImage); MbufExportSequence(SEQUENCE_FILE, M_DEFAULT, &BufferingDataStruct.MilCompressedImage, 1, M_DEFAULT, M_WRITE); MappTimer(M_DEFAULT, M_TIMER_READ, &TimeE); CompressionTime = (TimeE - TimeS); } // Save the host image to disk when 's' is pressed. if(UserHookDataPtr->SaveAnImageToDisk) { MIL_TEXT_CHAR FileName[512]; #if M_MIL_USE_WINDOWS COORD Coord; Coord.X = 0; Coord.Y = 24; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Coord); #endif MosSprintf(FileName, 512, MIL_TEXT("%s%d.mim"), IMAGE_FILE, SavedImageIndex++); MbufSave(FileName, BufferingDataStruct.MilBufHostYUV16); MosPrintf(MIL_TEXT("* Saved image in file: %s"), FileName); UserHookDataPtr->SaveAnImageToDisk = false; MosRefresh(); } // Update the thumbnail on the overlay buffer. if((BufferingDataStruct.MilBufHostScaledInUse) && (UserHookDataPtr->CameraPresent)) { MappTimer(M_DEFAULT, M_TIMER_READ, &TimeS); MbufCopyColor2d(BufferingDataStruct.MilBufHostScaled, UserHookDataPtr->MilImageDispOvr, M_ALL_BANDS,OFFSET_X,OFFSET_Y, M_ALL_BANDS,0,0, BufferingDataStruct.MilBufHostScaledSizeX - (OFFSET_X*2), BufferingDataStruct.MilBufHostScaledSizeY -(OFFSET_Y*2)); MappTimer(M_DEFAULT, M_TIMER_READ, &TimeE); TumbnailUpdateTime = (TimeE - TimeS); } // Update the statistics every 10 frames. if(UserHookDataPtr->ProcessedImageCount % 10 == 0) { #if M_MIL_USE_WINDOWS COORD Coord; Coord.X = 0; Coord.Y = 26; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Coord); #else move(11,0); #endif MosPrintf(MIL_TEXT("Frames grabbed:\t%d \n"), UserHookDataPtr->ProcessedImageCount); MosPrintf(MIL_TEXT("Frames missed:\t%d \n\n"), MdigInquire(UserHookDataPtr->MilDigitizer, M_PROCESS_FRAME_MISSED, M_NULL)); MosPrintf(MIL_TEXT("VGA display update time:\t%3.1f ms \n"), UserHookDataPtr->DisplayUpdateTime * 1000.0); MosPrintf(MIL_TEXT("VGA display update rate:\t%3.1f MB/s \n\n"), BufferingDataStruct.MilBufHostYUV16SizeInMB / UserHookDataPtr->DisplayUpdateTime); if(UserHookDataPtr->SaveSequenceToDisk) { MosPrintf(MIL_TEXT("Compression time:\t%3.1f ms \n"), CompressionTime * 1000.0); MosPrintf(MIL_TEXT("Compression rate:\t%3.1f MB/s \n\n"), BufferingDataStruct.MilBufHostYUV16SizeInMB / CompressionTime); } MosPrintf(MIL_TEXT("Thumbnail update time:\t%3.1f ms \n"), TumbnailUpdateTime * 1000.0); MosPrintf(MIL_TEXT("Thumbnail update rate:\t%3.1f MB/s \n\n"), BufferingDataStruct.MilBufHostScaledSizeInMB / TumbnailUpdateTime); MosRefresh(); } // Put back the previously grabbed buffer into the Free buffer list. #if M_MIL_USE_WINDOWS EnterCriticalSection(&FifoLock); #else pthread_mutex_lock(&FifoLock); #endif FifoGrabFree.push(BufferingDataStruct); #if M_MIL_USE_WINDOWS LeaveCriticalSection(&FifoLock); #else pthread_mutex_unlock(&FifoLock); #endif } return 0; } // CameraPresent hook function. Called every time the camera is plugged and unplugged // ------------------------------------------------------------------------------- MIL_INT MFTYPE CameraPresentHook(MIL_INT HookType, MIL_ID EventId, void* UserStructPtr) { HookDataStruct *UserHookDataPtr = (HookDataStruct *)UserStructPtr; MIL_ID MilDigitizer = UserHookDataPtr->MilDigitizer; MIL_ID MilDisplay = UserHookDataPtr->MilDisplay; MIL_INT CameraPresent = 0; // Inquire if the camera is present or not. MdigInquire(MilDigitizer, M_CAMERA_PRESENT, &CameraPresent); // No change, return. if(CameraPresent == UserHookDataPtr->CameraPresent) return 0; #if M_MIL_USE_WINDOWS COORD Coord; Coord.X = 0; Coord.Y = 23; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Coord); #endif if(CameraPresent) { // Camera is present, sync display on video input and enable overlay. MosPrintf(MIL_TEXT("* Camera is present, displaying video source. \n")); MdispControl(MilDisplay, M_SELECT_VIDEO_SOURCE, MilDigitizer); MdispControl(MilDisplay, M_OVERLAY_SHOW, M_ENABLE); UserHookDataPtr->CameraPresent = true; } else { // Camera is not present, display splash screen and disable overlay. UserHookDataPtr->CameraPresent = false; MosPrintf(MIL_TEXT("* Camera is disconnected, displaying splash screen. \n")); MdispControl(MilDisplay, M_SELECT_VIDEO_SOURCE, M_NULL); MdispControl(MilDisplay, M_OVERLAY_SHOW, M_DISABLE); } return 0; } // This function draws annotations in the display overlay. // ----------------------------------------------------------------------------------------- void OverlayDraw(MIL_ID MilOverlayImage) { MIL_INT ImageWidth, ImageHeight; MIL_INT32 Count; MIL_TEXT_CHAR chText[80]; // Inquire overlay size. ImageWidth = MbufInquire(MilOverlayImage, M_SIZE_X, M_NULL); ImageHeight = MbufInquire(MilOverlayImage, M_SIZE_Y, M_NULL); /// Draw MIL overlay annotations. ////////////////////////////////// if(ImageWidth > 768) MgraFont(M_DEFAULT, M_FONT_DEFAULT_LARGE); // Set the graphic text background to transparent. MgraControl(M_DEFAULT, M_BACKGROUND_MODE, M_TRANSPARENT); // Print a white string in the overlay image buffer. MgraColor(M_DEFAULT, M_COLOR_WHITE); MgraText(M_DEFAULT, MilOverlayImage, ImageWidth/9, ImageHeight/5, MIL_TEXT(" -------------------- ")); MgraText(M_DEFAULT, MilOverlayImage, ImageWidth/9, ImageHeight/5+25, MIL_TEXT(" - MIL Overlay Text - ")); MgraText(M_DEFAULT, MilOverlayImage, ImageWidth/9, ImageHeight/5+50, MIL_TEXT(" -------------------- ")); // Print a green string in the overlay image buffer. MgraColor(M_DEFAULT, M_COLOR_GREEN); MgraText(M_DEFAULT, MilOverlayImage, ImageWidth*11/18, ImageHeight/5, MIL_TEXT(" ---------------------")); MgraText(M_DEFAULT, MilOverlayImage, ImageWidth*11/18, ImageHeight/5+25, MIL_TEXT(" - MIL Overlay Text - ")); MgraText(M_DEFAULT, MilOverlayImage, ImageWidth*11/18, ImageHeight/5+50, MIL_TEXT(" ---------------------")); // Draw GDI color overlay annotation. //////////////////////////////////// #if M_MIL_USE_WINDOWS // Create a device context to draw in the overlay buffer with GDI. MbufControl(MilOverlayImage, M_DC_ALLOC, M_DEFAULT); // Inquire the device context. HDC hCustomDC = ((HDC)MbufInquire(MilOverlayImage, M_DC_HANDLE, M_NULL)); // Perform operation if GDI drawing is supported. if (hCustomDC) { POINT Hor[2]; POINT Ver[2]; SIZE TxtSz; RECT Txt; // Draw a blue cross. HPEN hpen = CreatePen(PS_SOLID, 2, RGB(0, 0, 255)); HPEN hpenOld = (HPEN)SelectObject(hCustomDC, hpen); Hor[0].x = 0; Hor[0].y = (LONG)ImageHeight/2; Hor[1].x = (LONG)ImageWidth; Hor[1].y = (LONG)ImageHeight/2; Polyline(hCustomDC, Hor, 2); Ver[0].x = (LONG)ImageWidth/2; Ver[0].y = 0; Ver[1].x = (LONG)ImageWidth/2; Ver[1].y = (LONG)ImageHeight; Polyline(hCustomDC, Ver, 2); SelectObject(hCustomDC, hpenOld); DeleteObject(hpen); // Prepare transparent text annotations. SetBkMode(hCustomDC, TRANSPARENT); MosStrcpy(chText, 80, MIL_TEXT("GDI Overlay Text")); Count = (MIL_INT32)MosStrlen(chText); GetTextExtentPoint(hCustomDC, chText, Count, &TxtSz); // Write red text. Txt.left = (LONG)ImageWidth*3/18; Txt.top = (LONG)ImageHeight*17/24; Txt.right = Txt.left + TxtSz.cx; Txt.bottom = Txt.top + TxtSz.cy; SetTextColor(hCustomDC,RGB(255, 0, 0)); DrawText(hCustomDC, chText, Count, &Txt, DT_RIGHT); // Write yellow text. Txt.left = (LONG)ImageWidth*12/18; Txt.top = (LONG)ImageHeight*17/24; Txt.right = Txt.left + TxtSz.cx; Txt.bottom = Txt.top + TxtSz.cy; SetTextColor(hCustomDC, RGB(255, 255, 0)); DrawText(hCustomDC, chText, Count, &Txt, DT_RIGHT); // Delete device context. MbufControl(MilOverlayImage, M_DC_FREE, M_DEFAULT); // Signal MIL that the overlay buffer was modified. MbufControl(MilOverlayImage, M_MODIFIED, M_DEFAULT); } #else move(2,0); /* Try to create an XPixmap to draw in the overlay buffer with XLib. */ /* can fail on a 16-bit display */ MappControl(M_DEFAULT, M_ERROR, M_PRINT_DISABLE); MbufControl(MilOverlayImage, M_XPIXMAP_ALLOC, M_COMPENSATION_ENABLE); MappControl(M_DEFAULT, M_ERROR, M_PRINT_ENABLE); /* Inquire the XPixmap. */ Pixmap XPixmap = ((Pixmap)MbufInquire(MilOverlayImage, M_XPIXMAP_HANDLE, M_NULL)); if(XPixmap) { /* init X */ Display *dpy = XOpenDisplay(""); int screen = DefaultScreen(dpy); GC gc = XCreateGC(dpy,XPixmap,0,0); XColor xcolors[3],exact; XPoint Hor[2]; XPoint Ver[2]; int i; const char *color_names[] = { "red", "yellow", "blue", }; /* allocate colors */ for(i=0;i<3;i++) { if(!XAllocNamedColor(dpy,DefaultColormap(dpy,screen),color_names[i], &xcolors[i],&exact)) { fprintf(stderr, "cant't alloc color %s\n", color_names[i]); exit (1); } } /* Write a blue cross. */ XSetForeground(dpy,gc, xcolors[2].pixel); Hor[0].x = 0; Hor[0].y = ImageHeight/2; Hor[1].x = ImageWidth; Hor[1].y = ImageHeight/2; XDrawLines(dpy,XPixmap,gc,Hor, 2, CoordModeOrigin); Ver[0].x = ImageWidth/2; Ver[0].y = 0; Ver[1].x = ImageWidth/2; Ver[1].y = ImageHeight; XDrawLines(dpy,XPixmap,gc,Ver, 2, CoordModeOrigin); /* Write Red text. */ XSetForeground(dpy,gc, xcolors[0].pixel); MosStrcpy(chText, 80, MIL_TEXT("X Overlay Text")); Count = MosStrlen(chText); XDrawString(dpy,XPixmap,gc, ImageWidth*3/18, ImageHeight*17/24, chText,Count); /* Write yellow text. */ XSetForeground(dpy,gc, xcolors[1].pixel); XDrawString(dpy,XPixmap,gc, ImageWidth*12/18, ImageHeight*17/24, chText,Count); XSetForeground(dpy,gc, BlackPixel(dpy,screen)); XFlush(dpy); XFreeGC(dpy,gc); XCloseDisplay(dpy); /* Delete device context. */ MbufControl(MilOverlayImage, M_XPIXMAP_FREE, M_DEFAULT); /* Signal MIL that the overlay buffer was modified. */ MbufControl(MilOverlayImage, M_MODIFIED, M_DEFAULT); } #endif MgraColor(M_DEFAULT, M_COLOR_WHITE); MgraFont(M_DEFAULT, M_FONT_DEFAULT_LARGE); MgraControl(M_DEFAULT, M_BACKGROUND_MODE, M_DEFAULT); }