Click here to show toolbars of the Web Online Help System: show toolbars |
//************************************************************************************* // // File name: MseqProcess.cs // Location: See Matrox Example Launcher in the MIL Control Center // // // Synopsis: This program shows the use of the MseqProcess() and MseqFeed() functions // to perform real-time encoding of a sequence of captured images. // // The user's preprocessing and compression code is written in a hook // function that will be called by MdigProcess() for each frame grabbed // (see ProcessingFunction()). The queueing for encoding of the next // frame is also made in that hook function to allow fully parallel // execution of the capture and the encoding. // // Note: The average encoding time must be shorter than the grab time or // some frames will be missed. Missed frames are very frequent when // the encoding is done by software. Also, if the captured images // are not displayed and the frame count is not drawn or printed // in the hook function, the CPU usage is reduced significantly. // // When encoding a 1080p source it is recommended to have your // MIL Non-Paged Memory set to at least 64MB. // // Copyright (C) Matrox Electronic Systems Ltd., 1992-2016. // All Rights Reserved using System; using System.Runtime.InteropServices; using System.Text; using Matrox.MatroxImagingLibrary; namespace MseqProcess { // User's processing function hook data object. class ProcessingHookDataStruct { public MIL_ID MilDigitizer; public MIL_ID MilImageDisp; public MIL_ID MilSeqContext; public MIL_INT ProcessedImageCount; public ProcessingHookOperation ProcessingOperation; } // Optional encoding end function hook data object. class EncodingFrameEndHookDataStruct { public MIL_INT EncodedImageCount; } // Optional decoding end function hook data object. class DecodingFrameEndHookDataStruct { public MIL_INT DecodedImageCount; public MIL_ID MilImageDisp; } enum ProcessingHookOperation { DISPLAY, ENCODE } class Program { // Number of images in the buffering grab queue. // Generally, increasing this number gives better real-time grab. private const int BUFFERING_SIZE_MAX = 20; // Target sequence file name and location. // The temporary directory location can be reached with %temp% under Windows. private static readonly string SEQUENCE_FILE = MIL.M_TEMP_DIR + "SeqProcess.mp4"; // Remote target sequence file name and location if Distributed MIL is used. private static readonly string REMOTE_SEQUENCE_FILE = "remote:///" + SEQUENCE_FILE; // Main function. // // ---------------// static int Main(string[] args) { MIL_ID MilApplication = MIL.M_NULL; MIL_ID MilRemoteApplication = MIL.M_NULL; MIL_ID MilSystem = MIL.M_NULL; MIL_ID MilDigitizer = MIL.M_NULL; MIL_ID MilDisplay = MIL.M_NULL; MIL_ID MilImageDisp = MIL.M_NULL; MIL_ID[] MilGrabBufferList = new MIL_ID[BUFFERING_SIZE_MAX]; MIL_ID MilCompressContext = MIL.M_NULL; MIL_ID MilDecompressContext = MIL.M_NULL; MIL_INT LicenseModules = 0; MIL_INT MilSystemLocation = MIL.M_NULL; MIL_INT MilGrabBufferListSize; MIL_INT ProcessFrameCount = 0; MIL_INT NbFrames = 0; MIL_INT n = 0; double EncodingDesiredFrameRate = 0.0; double ProcessFrameRate = 0.0; MIL_INT SeqProcessFilePathSize = 0; StringBuilder SeqProcessFilePath = null; ProcessingHookDataStruct ProcessingUserHookData = new ProcessingHookDataStruct(); EncodingFrameEndHookDataStruct EncodingFrameEndUserHookData = new EncodingFrameEndHookDataStruct(); DecodingFrameEndHookDataStruct DecodingFrameEndUserHookData = new DecodingFrameEndHookDataStruct(); MIL_INT SeqSystemType = MIL.M_NULL; // Allocate defaults. MIL.MappAllocDefault(MIL.M_DEFAULT, ref MilApplication, ref MilSystem, ref MilDisplay, ref MilDigitizer, ref MilImageDisp); MIL.MsysInquire(MilSystem, MIL.M_OWNER_APPLICATION, ref MilRemoteApplication); MilSystemLocation = MIL.MsysInquire(MilSystem, MIL.M_LOCATION, MIL.M_NULL); // Check if the system is running under Windows. if (MIL.MappInquire(MilRemoteApplication, MIL.M_PLATFORM_OS_TYPE, MIL.M_NULL) != MIL.M_OS_WINDOWS) { if (MilSystemLocation == MIL.M_REMOTE) Console.WriteLine("The Distributed MIL server must run on a Windows system."); else Console.WriteLine("This example only works with a Windows system."); Console.WriteLine("Press <Enter> to end."); Console.ReadKey(); MIL.MappFreeDefault(MilApplication, MilSystem, MilDisplay, MilDigitizer, MilImageDisp); return 0; } // Inquire MIL licenses. MIL.MappInquire(MilRemoteApplication, MIL.M_LICENSE_MODULES, ref LicenseModules); if ((LicenseModules & MIL.M_LICENSE_JPEGSTD) != MIL.M_LICENSE_JPEGSTD) { Console.WriteLine("Need a Compression/Decompression license to run this example."); Console.WriteLine("Press <Enter> to end."); Console.ReadKey(); MIL.MappFreeDefault(MilApplication, MilSystem, MilDisplay, MilDigitizer, MilImageDisp); return 0; } // Allocate the grab buffers and clear them. MIL.MappControl(MIL.M_DEFAULT, MIL.M_ERROR, MIL.M_PRINT_DISABLE); for (MilGrabBufferListSize = 0; MilGrabBufferListSize < BUFFERING_SIZE_MAX; MilGrabBufferListSize++) { MIL.MbufAllocColor(MilSystem, MIL.MdigInquire(MilDigitizer, MIL.M_SIZE_BAND, MIL.M_NULL), MIL.MdigInquire(MilDigitizer, MIL.M_SIZE_X, MIL.M_NULL), MIL.MdigInquire(MilDigitizer, MIL.M_SIZE_Y, MIL.M_NULL), 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_GRAB + MIL.M_PROC, ref MilGrabBufferList[MilGrabBufferListSize]); if (MilGrabBufferList[MilGrabBufferListSize] != MIL.M_NULL) { MIL.MbufClear(MilGrabBufferList[MilGrabBufferListSize], 0xFF); } else { break; } } MIL.MappControl(MIL.M_DEFAULT, MIL.M_ERROR, MIL.M_PRINT_ENABLE); // Free buffers to leave space for possible temporary buffers. for (n = 0; n < 2 && MilGrabBufferListSize > 0; n++) { MilGrabBufferListSize--; MIL.MbufFree(MilGrabBufferList[MilGrabBufferListSize]); } if (MilGrabBufferListSize == 0) { Console.WriteLine("!!! No grab buffers have been allocated. Need to set more Non-Paged Memory. !!!"); MIL.MappFreeDefault(MilApplication, MilSystem, MilDisplay, MilDigitizer, MilImageDisp); Console.WriteLine("Press <Enter> to end."); Console.ReadKey(); return 1; } // Initialize the User's processing function data structure only for Display. ProcessingUserHookData.MilDigitizer = MilDigitizer; ProcessingUserHookData.MilSeqContext = MIL.M_NULL; ProcessingUserHookData.MilImageDisp = MilImageDisp; ProcessingUserHookData.ProcessedImageCount = 0; ProcessingUserHookData.ProcessingOperation = ProcessingHookOperation.DISPLAY; // get a handle to the HookDataStruct object in the managed heap, we will use this // handle to get the object back in the callback function GCHandle hUserData = GCHandle.Alloc(ProcessingUserHookData); // Start the sequence acquisition. The preprocessing and encoding hook function // is called for every frame grabbed. MIL_DIG_HOOK_FUNCTION_PTR ProcessingFunctionDelegate = new MIL_DIG_HOOK_FUNCTION_PTR(ProcessingFunction); // Start MdigProcess() to show the live camera output. MIL.MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize, MIL.M_START, MIL.M_DEFAULT, ProcessingFunctionDelegate, GCHandle.ToIntPtr(hUserData)); // Print a message. Console.Write("\nH.264 IMAGE SEQUENCE COMPRESSION.\n"); Console.Write("---------------------------------\n\n"); Console.Write("Press <Enter> to start compression.\r"); Console.ReadKey(); // Stop MdigProcess(). MIL.MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize, MIL.M_STOP, MIL.M_DEFAULT, ProcessingFunctionDelegate, GCHandle.ToIntPtr(hUserData)); // Inquire the rate at which the frames were grabbed using MdigProcess() MIL.MdigInquire(MilDigitizer, MIL.M_PROCESS_FRAME_RATE, ref EncodingDesiredFrameRate); Console.Write("Grabbing frames at {0:0.00} frames/sec.\n", EncodingDesiredFrameRate); // Creates a context for the H.264 compression engine. Compression will be done // using hardware or software depending on the system hardware configuration. MIL.MseqAlloc(MilSystem, MIL.M_DEFAULT, MIL.M_SEQ_COMPRESS, MIL.M_DEFAULT, MIL.M_DEFAULT, ref MilCompressContext); // Specify the destination of the compressed file and the target container type. // The last argument specifies to generate an MP4 file. MIL.MseqDefine(MilCompressContext, MIL.M_SEQ_OUTPUT(0) + MIL.M_SEQ_DEST(0), MIL.M_FILE, (MilSystemLocation != MIL.M_REMOTE ? SEQUENCE_FILE : REMOTE_SEQUENCE_FILE), MIL.M_FILE_FORMAT_MP4); // Set the compression context's settings. // Sets the compression context's settings to compress frames at any resolution under // 1920 x 1080. Any resolution higher than that will generate a warning that can be disabled // using MseqControl with M_SETTING_AUTO_ADJUSTMENT. See documentation for more details. // MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_STREAM_BIT_RATE_MODE, MIL.M_VARIABLE); // MIL.M_VARIABLE or MIL.M_CONSTANT MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_STREAM_BIT_RATE, 5000); // 5 Mbps bit rate MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_STREAM_BIT_RATE_MAX, 5000); // 5 Mbps bit rate if (EncodingDesiredFrameRate != 0) MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_STREAM_FRAME_RATE, EncodingDesiredFrameRate); // 60Hz frame rate. MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_STREAM_FRAME_RATE_MODE, MIL.M_VARIABLE); // Attempts to update the file header with the encoding frame rate // if lower than the specified frame rate. MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_STREAM_QUALITY, 100); // 1=best speed, 100=best quality MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_STREAM_PROFILE, MIL.M_PROFILE_HIGH); // MIL.M_PROFILE_BASELINE, MIL.M_PROFILE_MAIN, MIL.M_PROFILE_HIGH MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_STREAM_LEVEL, MIL.M_LEVEL_4_2); // MIL.M_LEVEL_1, MIL.M_LEVEL_1B, MIL.M_LEVEL_1_1, MIL.M_LEVEL_1_2, MIL.M_LEVEL_1_3, // MIL.M_LEVEL_2, MIL.M_LEVEL_2_1, MIL.M_LEVEL_2_2, // MIL.M_LEVEL_3, MIL.M_LEVEL_3_1, MIL.M_LEVEL_3_2, // MIL.M_LEVEL_4, MIL.M_LEVEL_4_1, MIL.M_LEVEL_4_2, // MIL.M_LEVEL_5, MIL.M_LEVEL_5_1 MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_STREAM_GROUP_OF_PICTURE_SIZE, 30); // Interval between I-Frame // Initialize the optional encoding end function data structure. EncodingFrameEndUserHookData.EncodedImageCount = 0; // get a handle to the HookDataStruct object in the managed heap, we will use this // handle to get the object back in the callback function GCHandle EncodingFrameEndUserHookDataHandle = GCHandle.Alloc(EncodingFrameEndUserHookData); // Register the encoding end function to the sequence context. MIL_SEQ_HOOK_FUNCTION_PTR FrameEncodingEndFunctionDelegate = new MIL_SEQ_HOOK_FUNCTION_PTR(FrameEncodingEndFunction); MIL.MseqHookFunction(MilCompressContext, MIL.M_FRAME_END, FrameEncodingEndFunctionDelegate, GCHandle.ToIntPtr(EncodingFrameEndUserHookDataHandle)); // Provide a sample image to initialize the encoding engine accordingly. MIL.MseqControl(MilCompressContext, MIL.M_CONTEXT, MIL.M_BUFFER_SAMPLE, MilGrabBufferList[0]); // Disable error prints because MseqProcess() might not support the current input source. MIL.MappControl(MIL.M_ERROR, MIL.M_PRINT_DISABLE); // Start the encoding process, waits for buffer to be fed for encoding. MIL.MseqProcess(MilCompressContext, MIL.M_START, MIL.M_ASYNCHRONOUS); // Checks if an error has been logged by MseqProcess(). If so, stop the example. if (CheckMseqProcessError(MilApplication, MilCompressContext)) { // An error happened during MseqProcess() and we need to free the allocated resources. MIL.MseqProcess(MilCompressContext, MIL.M_STOP, MIL.M_NULL); MIL_INT SourceSizeX = 0; MIL_INT SourceSizeY = 0; double SourceFPS = 0; MIL.MdigInquire(MilDigitizer, MIL.M_SIZE_X, ref SourceSizeX); MIL.MdigInquire(MilDigitizer, MIL.M_SIZE_Y, ref SourceSizeY); MIL.MdigInquire(MilDigitizer, MIL.M_PROCESS_FRAME_RATE, ref SourceFPS); Console.WriteLine("Unable to perform H.264 encoding with the current input source of"); Console.WriteLine("{0} X {1} @ {2:0.00} fps.", SourceSizeX, SourceSizeY, SourceFPS); Console.WriteLine(); Console.WriteLine("Example parameters are optimized for sources of"); Console.WriteLine("1920 x 1080 @ 60 fps."); Console.WriteLine(); Console.WriteLine("You can try changing encoding parameters to better match your source."); Console.WriteLine(); Console.WriteLine("Press <Enter> to end."); Console.ReadKey(); while (MilGrabBufferListSize > 0) { MIL.MbufFree(MilGrabBufferList[--MilGrabBufferListSize]); MilGrabBufferList[MilGrabBufferListSize] = MIL.M_NULL; } MIL.MseqFree(MilCompressContext); MIL.MappFreeDefault(MilApplication, MilSystem, MilDisplay, MilDigitizer, MilImageDisp); return 0; } // MseqProcess() is running without error, so re-enable the error print. MIL.MappControl(MIL.M_ERROR, MIL.M_PRINT_ENABLE); // Display the type of compression used. Console.Write("Live image capture and compression to file using "); MIL.MseqInquire(MilCompressContext, MIL.M_CONTEXT, MIL.M_CODEC_TYPE, ref SeqSystemType); if (SeqSystemType == MIL.M_HARDWARE + MIL.M_QSV) { Console.WriteLine("Hardware acceleration."); } else // MIL.M_SOFTWARE + MIL.M_QSV { Console.WriteLine("Software implementation."); } // Set the sequence context id in the user hook data structure to start // feeding buffers for encoding in ProcessingFunction. // ProcessingUserHookData.MilSeqContext = MilCompressContext; ProcessingUserHookData.ProcessedImageCount = 0; ProcessingUserHookData.ProcessingOperation = ProcessingHookOperation.ENCODE; MIL.MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize, MIL.M_START, MIL.M_DEFAULT, ProcessingFunctionDelegate, GCHandle.ToIntPtr(hUserData)); // NOTE: Now the main() is free to perform other tasks while the compression is executing. // --------------------------------------------------------------------------------------- // Print a message and wait for a key press after a minimum number of frames. Console.WriteLine("Press <Enter> to stop.\n"); Console.ReadKey(); // Stop the processing. MIL.MdigProcess(MilDigitizer, MilGrabBufferList, MilGrabBufferListSize, MIL.M_STOP + MIL.M_WAIT, MIL.M_DEFAULT, ProcessingFunctionDelegate, GCHandle.ToIntPtr(hUserData)); // Free the processing user data handle. hUserData.Free(); // Stop the encoding process MIL.MseqProcess(MilCompressContext, MIL.M_STOP, MIL.M_WAIT); // Make sure the hook handler function delegate is not prematurely garbage collected since // only MIL has a reference to it. GC.KeepAlive(FrameEncodingEndFunctionDelegate); // Free the encoding user data handle. EncodingFrameEndUserHookDataHandle.Free(); // Print statistics. MIL.MdigInquire(MilDigitizer, MIL.M_PROCESS_FRAME_COUNT, ref ProcessFrameCount); MIL.MdigInquire(MilDigitizer, MIL.M_PROCESS_FRAME_RATE, ref ProcessFrameRate); Console.WriteLine("{0} frames encoded at {1:0.00} frames/sec ({2:0.0} ms/frame).", ProcessFrameCount, ProcessFrameRate, 1000.0 / ProcessFrameRate); Console.WriteLine(); MIL.MseqInquire(MilCompressContext, MIL.M_SEQ_OUTPUT(0) + MIL.M_SEQ_DEST(0), MIL.M_STREAM_FILE_NAME_SIZE, ref SeqProcessFilePathSize); SeqProcessFilePath = new StringBuilder((int)SeqProcessFilePathSize); MIL.MseqInquire(MilCompressContext, MIL.M_SEQ_OUTPUT(0) + MIL.M_SEQ_DEST(0), MIL.M_STREAM_FILE_NAME, SeqProcessFilePath); Console.WriteLine("The video sequence file was written to:"); Console.WriteLine("{0}.", SeqProcessFilePath.ToString()); Console.WriteLine(); Console.WriteLine("It can be played back using any compatible video player."); // Free the grab buffers and sequence context. while (MilGrabBufferListSize > 0) { MIL.MbufFree(MilGrabBufferList[--MilGrabBufferListSize]); MilGrabBufferList[MilGrabBufferListSize] = MIL.M_NULL; } MIL.MseqFree(MilCompressContext); // Wait for a key to start the replay. Console.WriteLine("Press <Enter> to replay encoded sequence."); Console.ReadKey(); MIL.MseqAlloc(MilSystem, MIL.M_DEFAULT, MIL.M_SEQ_DECOMPRESS, MIL.M_DEFAULT, MIL.M_DEFAULT, ref MilDecompressContext); // Specify the destination of the compressed file and the target container type. // The last argument specifies to generate an MP4 file. MIL.MseqDefine(MilDecompressContext, MIL.M_SEQ_INPUT(0), MIL.M_FILE, (MilSystemLocation != MIL.M_REMOTE ? SEQUENCE_FILE : REMOTE_SEQUENCE_FILE), MIL.M_FILE_FORMAT_MP4); double outputFrameRate = 0.0; MIL.MseqInquire(MilDecompressContext, MIL.M_SEQ_INPUT(0), MIL.M_STREAM_FRAME_RATE, ref outputFrameRate); Console.WriteLine(); Console.WriteLine("Replaying file at {0:0.00} frames/second.", outputFrameRate); // Initialize the optional decoding end function data structure. DecodingFrameEndUserHookData.DecodedImageCount = 0; DecodingFrameEndUserHookData.MilImageDisp = MilImageDisp; // get a handle to the HookDataStruct object in the managed heap, we will use this // handle to get the object back in the callback function GCHandle DecodingFrameEndUserHookDataHandle = GCHandle.Alloc(DecodingFrameEndUserHookData); // Register the decoding end function to the sequence context. MIL_SEQ_HOOK_FUNCTION_PTR FrameDecodingEndFunctionDelegate = new MIL_SEQ_HOOK_FUNCTION_PTR(FrameDecodingEndFunction); MIL.MseqHookFunction(MilDecompressContext, MIL.M_FRAME_END, FrameDecodingEndFunctionDelegate, GCHandle.ToIntPtr(DecodingFrameEndUserHookDataHandle)); // Start the decoding process, waits for buffer to be fed for encoding. MIL.MseqProcess(MilDecompressContext, MIL.M_START, MIL.M_ASYNCHRONOUS); // Print a message and wait for a key press after a minimum number of frames. Console.WriteLine("Press <Enter> to stop.\n"); Console.ReadKey(); // Stop the play back. MIL.MseqProcess(MilDecompressContext, MIL.M_STOP, MIL.M_NULL); // Make sure the hook handler function delegate is not prematurely garbage collected since // only MIL has a reference to it. GC.KeepAlive(FrameDecodingEndFunctionDelegate); // Free the decoding user data handle. DecodingFrameEndUserHookDataHandle.Free(); MIL.MseqFree(MilDecompressContext); // Wait for a key to end. Console.WriteLine("Press <Enter> to end."); Console.ReadKey(); // Release defaults. MIL.MappFreeDefault(MilApplication, MilSystem, MilDisplay, MilDigitizer, MilImageDisp); return 0; } // Local defines. private const int STRING_LENGTH_MAX = 20; private const int STRING_POS_X = 20; private const int STRING_POS_Y = 20; // User's processing function called every time a grab buffer is modified. // ------------------------------------------------------------------------ static MIL_INT ProcessingFunction(MIL_INT HookType, MIL_ID HookId, IntPtr HookDataPtr) { // this is how to check if the user data is null, the IntPtr class // contains a member, Zero, which exists solely for this purpose if (!IntPtr.Zero.Equals(HookDataPtr)) { // get the handle to the ProcessingHookDataStruct object back from the IntPtr GCHandle hUserData = GCHandle.FromIntPtr(HookDataPtr); // get a reference to the ProcessingHookDataStruct object ProcessingHookDataStruct UserHookDataPtr = hUserData.Target as ProcessingHookDataStruct; MIL_ID ModifiedBufferId = MIL.M_NULL; string Text; // Retrieve the MIL_ID of the grabbed buffer. MIL.MdigGetHookInfo(HookId, MIL.M_MODIFIED_BUFFER + MIL.M_BUFFER_ID, ref ModifiedBufferId); switch (UserHookDataPtr.ProcessingOperation) { case ProcessingHookOperation.DISPLAY: // Update the display with the last captured image. MIL.MbufCopy(ModifiedBufferId, UserHookDataPtr.MilImageDisp); break; case ProcessingHookOperation.ENCODE: // Increase the compressed images count. UserHookDataPtr.ProcessedImageCount++; // Print and draw the frame count (comment this block to reduce CPU usage). Console.Write("Processing frame #{0}.\r", UserHookDataPtr.ProcessedImageCount); Text = string.Format("{0}", UserHookDataPtr.ProcessedImageCount); MIL.MgraText(MIL.M_DEFAULT, ModifiedBufferId, STRING_POS_X, STRING_POS_Y, Text); // Enqueue the grabbed buffer for parallel encoding. MIL.MseqFeed(UserHookDataPtr.MilSeqContext, ModifiedBufferId, MIL.M_DEFAULT); // Update the display with the last captured image. MIL.MbufCopy(ModifiedBufferId, UserHookDataPtr.MilImageDisp); break; } } return 0; } // Optional encoding end function called every time a buffer is finished being compressed. // ---------------------------------------------------------------------------------------- static MIL_INT FrameEncodingEndFunction(MIL_INT HookType, MIL_ID HookId, IntPtr HookDataPtr) { // this is how to check if the user data is null, the IntPtr class // contains a member, Zero, which exists solely for this purpose if (!IntPtr.Zero.Equals(HookDataPtr)) { // get the handle to the FrameEndHookDataStruct object back from the IntPtr GCHandle hUserData = GCHandle.FromIntPtr(HookDataPtr); // get a reference to the FrameEndHookDataStruct object EncodingFrameEndHookDataStruct UserHookDataPtr = hUserData.Target as EncodingFrameEndHookDataStruct; // Frame end hook post processing. if (HookType == MIL.M_FRAME_END) { MIL_ID CompressedBufferId = MIL.M_NULL; MIL_INT CompressedDataPtr = MIL.M_NULL; MIL_INT CompressedDataSize = 0; // Increment a encoded frame counter UserHookDataPtr.EncodedImageCount++; // Retrieve the MIL_ID of the encoded buffer. MIL.MseqGetHookInfo(HookId, MIL.M_MODIFIED_BUFFER + MIL.M_BUFFER_ID, ref CompressedBufferId); // Retrieves the address of the encoded data. MIL.MbufInquire(CompressedBufferId, MIL.M_HOST_ADDRESS, ref CompressedDataPtr); // Retrieves the size in bytes of the encoded data. MIL.MbufInquire(CompressedBufferId, MIL.M_SIZE_BYTE, ref CompressedDataSize); // ----------------------------------------------------------------------------------------------- // Here you can do any action with the encoded data, such as send the buffer through a network // stream. If the processing done on the compressed data is long, it is recommended to copy the // buffer and to process it in a separate thread to avoid blocking the compression's flow. // ----------------------------------------------------------------------------------------------- } } return 0; } // Optional decoding end function called every time a buffer is finished being decompressed. // ------------------------------------------------------------------------------------------ static MIL_INT FrameDecodingEndFunction(MIL_INT HookType, MIL_ID HookId, IntPtr HookDataPtr) { // this is how to check if the user data is null, the IntPtr class // contains a member, Zero, which exists solely for this purpose if (!IntPtr.Zero.Equals(HookDataPtr)) { // get the handle to the FrameEndHookDataStruct object back from the IntPtr GCHandle hUserData = GCHandle.FromIntPtr(HookDataPtr); // get a reference to the FrameEndHookDataStruct object DecodingFrameEndHookDataStruct UserHookDataPtr = hUserData.Target as DecodingFrameEndHookDataStruct; // Frame end hook post processing. if (HookType == MIL.M_FRAME_END) { MIL_ID DecompressedBufferId = MIL.M_NULL; // Increment a encoded frame counter. UserHookDataPtr.DecodedImageCount++; // Retrieve the MIL_ID of the encoded buffer. MIL.MseqGetHookInfo(HookId, MIL.M_MODIFIED_BUFFER + MIL.M_BUFFER_ID, ref DecompressedBufferId); // ----------------------------------------------------------------------------------------------- // Here you can do any action with the decoded buffer. // ----------------------------------------------------------------------------------------------- MIL.MbufCopy(DecompressedBufferId, UserHookDataPtr.MilImageDisp); } } return 0; } private struct MSEQ_PARAM { public MSEQ_PARAM(string controlName, MIL_INT controlType, MIL_INT originalValue, MIL_INT effectiveValue) { ControlName = controlName; ControlType = controlType; OriginalValue = originalValue; EffectiveValue = effectiveValue; } public string ControlName; public MIL_INT ControlType; public MIL_INT OriginalValue; public MIL_INT EffectiveValue; } // Checks if MseqProcess generated an error or a warning. // This function prints out the MIL error message, if any. // If a sequence context parameter has been modified, it means that only a warning has been generated. // If it is a warning, it displays the control that has been modified. // If it is an error, it return M_YES to indicate that the example needs to be stopped. // ---------------------------------------------------------------------------------------------------- private static bool CheckMseqProcessError(MIL_ID MilApplication, MIL_ID MilCompressContext) { bool IsError = false; bool IsWarning = false; MIL_INT MilErrorCode = PrintMilErrorMessage(MilApplication); // MseqProcess generated an error, check in details if it is a warning or an error. if (MilErrorCode != MIL.M_NULL_ERROR) { MSEQ_PARAM[] MseqParamList = new MSEQ_PARAM[] { new MSEQ_PARAM("M_STREAM_BIT_RATE_MODE", MIL.M_STREAM_BIT_RATE_MODE, 0, 0), new MSEQ_PARAM( "M_STREAM_BIT_RATE", MIL.M_STREAM_BIT_RATE, 0, 0 ), new MSEQ_PARAM( "M_STREAM_BIT_RATE_MAX", MIL.M_STREAM_BIT_RATE_MAX, 0, 0 ), new MSEQ_PARAM( "M_STREAM_FRAME_RATE_MODE", MIL.M_STREAM_FRAME_RATE_MODE, 0, 0 ), new MSEQ_PARAM( "M_STREAM_QUALITY", MIL.M_STREAM_QUALITY, 0, 0 ), new MSEQ_PARAM( "M_STREAM_PROFILE", MIL.M_STREAM_PROFILE, 0, 0 ), new MSEQ_PARAM( "M_STREAM_LEVEL", MIL.M_STREAM_LEVEL, 0, 0 ), new MSEQ_PARAM( "M_STREAM_GROUP_OF_PICTURE_SIZE", MIL.M_STREAM_GROUP_OF_PICTURE_SIZE, 0, 0 )}; MIL_INT NumberOfModifiedParams = 0; // Loop though the param list to find which one has been internally modified. for (MIL_INT ParamIndex = 0; ParamIndex < MseqParamList.Length; ParamIndex++) { // Query the original control values. MIL.MseqInquire(MilCompressContext, MIL.M_CONTEXT, MseqParamList[ParamIndex].ControlType, ref MseqParamList[ParamIndex].OriginalValue); // Query the effective control values. MIL.MseqInquire(MilCompressContext, MIL.M_CONTEXT, MseqParamList[ParamIndex].ControlType | MIL.M_EFFECTIVE_VALUE, ref MseqParamList[ParamIndex].EffectiveValue); // If the original value is different than the effective value, // the error received is only a warning and processing can continue. // if (MseqParamList[ParamIndex].OriginalValue != MseqParamList[ParamIndex].EffectiveValue) { if (NumberOfModifiedParams == 0) Console.Write("\nParameter(s) that have been internally modified:\n"); // Prints the Control type internally modified. Console.WriteLine("- {0}", MseqParamList[ParamIndex].ControlName); NumberOfModifiedParams++; IsWarning = true; } } Console.WriteLine(); // If the error logged is not a warning, you cannot encode the current input source. // The example needs to be stopped. // if (!IsWarning) IsError = true; } return IsError; } // Print the current error code in the console private static MIL_INT PrintMilErrorMessage(MIL_ID MilApplication) { MIL_INT MilErrorCode; StringBuilder MilErrorMsg = new StringBuilder(MIL.M_ERROR_MESSAGE_SIZE); MIL_INT[] MilErrorSubCode = new MIL_INT[3]; StringBuilder[] MilErrorSubMsg = new StringBuilder[3]; // Initialize MilErrorSubMsg array. for (int i = 0; i < 3; i++) MilErrorSubMsg[i] = new StringBuilder(MIL.M_ERROR_MESSAGE_SIZE); MilErrorCode = MIL.MappGetError(MilApplication, MIL.M_CURRENT + MIL.M_MESSAGE, MilErrorMsg); if (MilErrorCode != MIL.M_NULL_ERROR) { /* Collects Mil error messages and sub-messages */ MIL_INT subCount = 3; MIL.MappGetError(MilApplication, MIL.M_CURRENT_SUB_NB, ref subCount); MilErrorSubCode[0] = MIL.MappGetError(MilApplication, MIL.M_CURRENT_SUB_1 + MIL.M_MESSAGE, MilErrorSubMsg[0]); MilErrorSubCode[1] = MIL.MappGetError(MilApplication, MIL.M_CURRENT_SUB_2 + MIL.M_MESSAGE, MilErrorSubMsg[1]); MilErrorSubCode[2] = MIL.MappGetError(MilApplication, MIL.M_CURRENT_SUB_3 + MIL.M_MESSAGE, MilErrorSubMsg[2]); Console.WriteLine("\nMseqProcess generated a warning or an error:"); Console.WriteLine(" {0}", MilErrorMsg.ToString()); for (int i = 0; i < subCount; i++) { if (MilErrorSubCode[i] != 0) Console.WriteLine(" {0}", MilErrorSubMsg[i]); } } return MilErrorCode; } } }