/********************************************************************************/ /* * File name: MDigGrabSequence.c * * Synopsis: This example shows how to grab a sequence, archive it, and play * it back in real time from an AVI file. It supports compressed * or uncompressed sequences and parallelized compression/decompression * with disk access to optimize the use of hardware resources * when possible. If this is not necessary, the example can be simplified. * * NOTE: This example assumes that the hard disk is sufficiently fast * to keep up with the grab. Also, removing the sequence display or * the text annotation while grabbing will reduce the CPU usage and * might help if some frames are missed during acquisition. * If the disk or system are not fast enough, set GRAB_SCALE to 0.5, * FRAME_NUMBER_ANNOTATION to M_NO or SAVE_SEQUENCE_TO_DISK to M_NO. */ #include #include #include /* Sequence file name.*/ #define SEQUENCE_FILE M_IMAGE_PATH MIL_TEXT("MilSequence.avi") /* Image acquisition scale. */ #define GRAB_SCALE 1.0 /* Quantization factor to use during the compression. Valid values are 1 to 99 (higher to lower quality). */ #define COMPRESSION_Q_FACTOR 50 /* Annotation flag. Set to M_YES to draw the frame number in the saved image. */ #define FRAME_NUMBER_ANNOTATION M_YES /* Archive flag. Set to M_NO to disable AVI Import/Export to disk. */ #if (!M_MIL_USE_CE) #define SAVE_SEQUENCE_TO_DISK M_YES #else #define SAVE_SEQUENCE_TO_DISK M_NO #endif /* Maximum number of images for the multiple buffering grab. */ #define NB_GRAB_IMAGE_MAX 20 /* User's archive hook function prototype (called for every grabbed frame). */ long MFTYPE ArchiveFunction(long HookType, MIL_ID HookId, void MPTYPE *HookDataPtr); /* User's archive function hook data structure. */ typedef struct { MIL_ID MilSystem; MIL_ID MilDisplay; MIL_ID MilImageDisp; MIL_ID *MilCompressedImage; long NbGrabbedFrames; long NbArchivedFrames; long SaveSequenceToDisk; long OnBoardAttribute; } HookDataStruct; /* Main function. */ /* -------------- */ void main(void) { MIL_ID MilApplication, MilSystem, MilDigitizer, MilDisplay, MilImageDisp; MIL_ID MilGrabImages[NB_GRAB_IMAGE_MAX+1]; MIL_ID MilCompressedImage[2] = {0, 0}; long CompressAttribute=0, OnBoardAttribute=0; long NbFrames=0, Selection=1, LicenseModules=0, n=0; long FrameCount=0, FrameMissed=0, NbFramesReplayed=0, Exit=0; double FrameRate=0, TimeWait=0, TotalReplay=0; double GrabScale=GRAB_SCALE; long SaveSequenceToDisk = SAVE_SEQUENCE_TO_DISK; HookDataStruct UserHookData; /* Allocate defaults. */ MappAllocDefault(M_SETUP, &MilApplication, &MilSystem, &MilDisplay, &MilDigitizer, M_NULL); /* Allocate an image and display it. */ MbufAllocColor(MilSystem, (long) MdigInquire(MilDigitizer, M_SIZE_BAND, M_NULL), (long)(MdigInquire(MilDigitizer, M_SIZE_X, M_NULL)*GrabScale), (long)(MdigInquire(MilDigitizer, M_SIZE_Y, M_NULL)*GrabScale), 8L+M_UNSIGNED, M_IMAGE+M_GRAB+M_DISP+M_NON_PAGED, &MilImageDisp); MbufClear(MilImageDisp, 0x0); MdispSelect(MilDisplay, MilImageDisp); /* Grab continuously on display at the specified scale. */ MdigControl(MilDigitizer, M_GRAB_SCALE, GrabScale); MdigGrabContinuous(MilDigitizer, MilImageDisp); /* Print a message */ printf("\nSEQUENCE AQUISITION:\n"); printf("--------------------\n\n"); /* Inquire MIL licenses. */ MappInquire(M_LICENSE_MODULES, &LicenseModules); if (MsysInquire(MilSystem, M_SYSTEM_TYPE, M_NULL) == M_SYSTEM_ODYSSEY_TYPE) LicenseModules = (M_LICENSE_JPEGSTD | M_LICENSE_JPEG2000); /* If sequence is saved to disk, select between grabbing an uncompressed, JPEG or JPEG2000 sequence. */ if (SaveSequenceToDisk && (LicenseModules & (M_LICENSE_JPEGSTD | M_LICENSE_JPEG2000))) { printf("Choose the sequence format:\n"); printf("1) Uncompressed images.\n" ); if(LicenseModules & M_LICENSE_JPEGSTD) printf("2) Compressed images with a lossy JPEG algorithm.\n"); if(LicenseModules & M_LICENSE_JPEG2000) printf("3) Compressed images with a lossy JPEG 2000 algorithm.\n"); Selection = getch(); } else { printf("Press to record images.\n"); Selection = '1'; getch(); } /* Set the buffer attribute. */ switch(Selection) { case '1': case '\r': printf("\nRecording uncompressed images...\n\n"); CompressAttribute = M_NULL; break; case '2': printf("\nRecording JPEG images...\n\n"); CompressAttribute = M_COMPRESS + M_JPEG_LOSSY; /* If the system JPEG on-board compression use it. */ if (MsysInquire(MilSystem, M_BOARD_TYPE, M_NULL) & M_JPEG) OnBoardAttribute = M_ON_BOARD; break; case '3': printf("\nRecording JPEG 2000 images...\n\n"); CompressAttribute = M_COMPRESS + M_JPEG2000_LOSSY; /* If the system JPEG2000 on-board compression use it. */ if (MsysInquire(MilSystem, M_BOARD_TYPE, M_NULL) & M_J2K) OnBoardAttribute = M_ON_BOARD; break; default: printf("\nInvalid selection !.\n\nUsing uncompressed images.\n\n"); CompressAttribute = M_NULL; while (kbhit()) getch(); break; } /* Allocate 2 compressed buffers if required. */ if (CompressAttribute) { for (n=0; n<2; n++) { MbufAllocColor(MilSystem, (long)MdigInquire(MilDigitizer, M_SIZE_BAND, M_NULL), (long)(MdigInquire(MilDigitizer, M_SIZE_X, M_NULL)*GrabScale), (long)(MdigInquire(MilDigitizer, M_SIZE_Y, M_NULL)*GrabScale), 8L+M_UNSIGNED, M_IMAGE+CompressAttribute, &MilCompressedImage[n]); MbufControl(MilCompressedImage[n], M_Q_FACTOR, COMPRESSION_Q_FACTOR); } } /* Allocate the grab buffers to hold the sequence buffering. */ MappControl(M_ERROR, M_PRINT_DISABLE); for (NbFrames=0, n=0; n to continue.\n\n"); getch(); /* Stop the sequence acquisition. */ MdigProcess(MilDigitizer, MilGrabImages, NbFrames, M_STOP, M_DEFAULT, ArchiveFunction, &UserHookData); /* Read and print final statistics. */ MdigInquire(MilDigitizer, M_PROCESS_FRAME_COUNT, &FrameCount); MdigInquire(MilDigitizer, M_PROCESS_FRAME_RATE, &FrameRate); MdigInquire(MilDigitizer, M_PROCESS_FRAME_MISSED, &FrameMissed); printf("\n\n%ld frames archived (%ld missed), at %.1f frames/sec (%.1f ms/frame).\n", UserHookData.NbArchivedFrames, FrameMissed, FrameRate, 1000.0/FrameRate); /* Sequence file closing if required. */ if (SaveSequenceToDisk) MbufExportSequence(SEQUENCE_FILE, M_DEFAULT, M_NULL, M_NULL, FrameRate, M_CLOSE); /* Playback the sequence until a key is pressed. */ printf("Press to end the playback, any other key to playback again.\n\n"); if (UserHookData.NbArchivedFrames > 0) do { /* If sequence must be loaded. */ if (SaveSequenceToDisk) { /* Inquire information about the sequence. */ printf("Restoring the sequence from the AVI file...\n\n"); MbufDiskInquire(SEQUENCE_FILE, M_NUMBER_OF_IMAGES, &FrameCount); MbufDiskInquire(SEQUENCE_FILE, M_FRAME_RATE, &FrameRate); MbufDiskInquire(SEQUENCE_FILE, M_COMPRESSION_TYPE, &CompressAttribute); /* Open the sequence file. */ MbufImportSequence(SEQUENCE_FILE, M_DEFAULT, M_NULL, M_NULL, M_NULL, M_NULL, M_NULL, M_OPEN); } /* Activate asynchronous buffer copy and decompression on the system if supported. */ MappControl(M_ERROR, M_PRINT_DISABLE); MthrControl(MilSystem, M_BUS_MASTER_COPY_MODE, M_ASYNCHRONOUS); MappControl(M_ERROR, M_PRINT_ENABLE); /* Copy the images to the screen respecting the sequence frame rate. */ TotalReplay = 0.0; NbFramesReplayed = 0; for (n=0; n 0) { /* Make sure any previous asynchronous operation is completed. */ MthrWait(M_DEFAULT, M_THREAD_WAIT, M_NULL); /* Decompress a frame. */ MbufCopy(MilCompressedImage[1-(n&1)], MilImageDisp); NbFramesReplayed++; printf("Frame #%d \r", NbFramesReplayed); } else FrameCount++; if (n < (FrameCount-1)) { /* Load the next one. */ MbufImportSequence(SEQUENCE_FILE, M_DEFAULT, M_LOAD, M_NULL, &MilCompressedImage[n&1], n, 1, M_READ); } } else { /* Copy one of the grabbeds image directly. */ MbufCopy(MilGrabImages[n], MilImageDisp); NbFramesReplayed++; printf("Frame #%d \r", NbFramesReplayed); } } /* Check for a pressed key to exit. */ if (kbhit() && (n>=(NB_GRAB_IMAGE_MAX-1))) { getch(); break; } /* Wait to have a proper frame rate. */ MappTimer(M_TIMER_READ, &TimeWait); TotalReplay += TimeWait; TimeWait = (1/FrameRate) - TimeWait; MappTimer(M_TIMER_WAIT, &TimeWait); TotalReplay += (TimeWait > 0) ? TimeWait: 0.0; } /* Close the sequence file. */ if (SaveSequenceToDisk) MbufImportSequence(SEQUENCE_FILE, M_DEFAULT, M_NULL, M_NULL, M_NULL, M_NULL, M_NULL, M_CLOSE); /* Print statistics. */ printf("\n\n%ld frames replayed, at a frame rate of %.1f frames/sec (%.1f ms/frame).\n\n", NbFramesReplayed, n/TotalReplay, 1000.0*TotalReplay/n); } while(getch() != '\r'); /* Free all allocated buffers. */ MbufFree(MilImageDisp); for (n=0; nNbGrabbedFrames == 0) { MappControl(M_ERROR, M_PRINT_DISABLE); MthrControl(UserHookDataPtr->MilSystem, M_BUS_MASTER_COPY_MODE, M_ASYNCHRONOUS); MappControl(M_ERROR, M_PRINT_ENABLE); } /* Retrieve the MIL_ID of the grabbed buffer. */ MdigGetHookInfo(HookId, M_MODIFIED_BUFFER+M_BUFFER_ID, &ModifiedImage); /* Increment the frame count. */ UserHookDataPtr->NbGrabbedFrames++; /* Draw the frame count in the image if enabled and if the buffer is not on-board. */ if((FRAME_NUMBER_ANNOTATION == M_YES) && (!UserHookDataPtr->OnBoardAttribute)) { MOs_sprintf(Text, MIL_TEXT(" %ld "), UserHookDataPtr->NbGrabbedFrames); MgraText(M_DEFAULT, ModifiedImage, STRING_POS_X, STRING_POS_Y, Text); } /* Compress the new image if required while archiving the previous one. */ if (UserHookDataPtr->MilCompressedImage[0]) { /* Make sure any previous asynchronous operation is completed. */ MthrWait(M_DEFAULT, M_THREAD_WAIT, M_NULL); n = UserHookDataPtr->NbGrabbedFrames & 1; MbufCopy(ModifiedImage, UserHookDataPtr->MilCompressedImage[n]); if (UserHookDataPtr->NbGrabbedFrames > 1) { if (UserHookDataPtr->SaveSequenceToDisk && (UserHookDataPtr->NbGrabbedFrames > 1)) MbufExportSequence(SEQUENCE_FILE, M_DEFAULT, &UserHookDataPtr->MilCompressedImage[1-n], 1, M_DEFAULT, M_WRITE); UserHookDataPtr->NbArchivedFrames++; printf("Frame #%d \r", UserHookDataPtr->NbArchivedFrames); } } else /* Archive the new image directly if required. */ { if (UserHookDataPtr->SaveSequenceToDisk) { MbufExportSequence(SEQUENCE_FILE, M_DEFAULT, &ModifiedImage, 1, M_DEFAULT, M_WRITE); } UserHookDataPtr->NbArchivedFrames++; printf("Frame #%d \r", UserHookDataPtr->NbArchivedFrames); } /* Copy the new grabbed image to the display. */ MbufCopy(ModifiedImage, UserHookDataPtr->MilImageDisp); return 0; }