public VTStatus DecodeFrame(CMSampleBuffer sampleBuffer, VTDecodeFrameFlags decodeFlags, out VTDecodeInfoFlags infoFlags, VTDecompressionOutputHandler outputHandler) { if (Handle == IntPtr.Zero) { throw new ObjectDisposedException("DecompressionSession"); } if (sampleBuffer == null) { throw new ArgumentNullException("sampleBuffer"); } if (outputHandler == null) { throw new ArgumentNullException("outputHandler"); } unsafe { var block = new BlockLiteral(); var blockPtr = █ block.SetupBlockUnsafe(decompressionOutputHandlerTrampoline, outputHandler); try { return(VTDecompressionSessionDecodeFrameWithOutputHandler(Handle, sampleBuffer.Handle, decodeFlags, out infoFlags, blockPtr)); } finally { blockPtr->CleanupBlock(); } } }
static unsafe void VTDecompressionOutputHandlerTrampoline(BlockLiteral *block, VTStatus status, VTDecodeInfoFlags infoFlags, IntPtr imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration) { var del = (VTDecompressionOutputHandler)(block->Target); if (del != null) { del(status, infoFlags, new CVImageBuffer(imageBuffer), presentationTimeStamp, presentationDuration); } }
void DidDecompress(IntPtr sourceFrame, VTStatus status, VTDecodeInfoFlags flags, CVImageBuffer buffer, CMTime presentationTimeStamp, CMTime presentationDuration) { if (status != VTStatus.Ok) { Console.WriteLine("Error decompresssing frame at time: {0:#.###} error: {1} infoFlags: {2}", (float)presentationTimeStamp.Value / presentationTimeStamp.TimeScale, (int)status, flags); return; } if (buffer == null) { return; } // Find the correct position for this frame in the output frames array if (presentationTimeStamp.IsInvalid) { Console.WriteLine("Not a valid time for image buffer"); return; } var framePTS = presentationTimeStamp.Seconds; lock (thisLock) { // since we want to keep the managed `pixelBuffer` alive outside the execution // of the callback we need to create our own (managed) instance from the handle var pixelBuffer = Runtime.GetINativeObject <CVPixelBuffer> (buffer.Handle, false); int insertionIndex = presentationTimes.Count - 1; while (insertionIndex >= 0) { var aNumber = presentationTimes [insertionIndex]; if (aNumber <= framePTS) { break; } insertionIndex--; } if (insertionIndex + 1 == presentationTimes.Count) { presentationTimes.Add(framePTS); outputFrames.Add(pixelBuffer); } else { presentationTimes.Insert(insertionIndex + 1, framePTS); outputFrames.Insert(insertionIndex + 1, pixelBuffer); } } }
static void DecompressionCallback(IntPtr outputCallbackClosure, IntPtr sourceFrame, VTStatus status, VTDecodeInfoFlags infoFlags, IntPtr imageBufferPtr, CMTime presentationTimeStamp, CMTime presentationDuration) { var gch = GCHandle.FromIntPtr(outputCallbackClosure); var func = (VTDecompressionOutputCallback)gch.Target; // Apple headers states that the callback should get a CVImageBuffer but it turned out that not all of them are a // CVImageBuffer, some can be instances of CVImageBuffer and others can be instances of CVPixelBuffer. So we go one // step further in the inheritance hierarchy and supply the callback a CVPixelBuffer and the callback supplies // to the developer a CVImageBuffer, so the developer can choose when to use one or the other and we mimic // what Apple provides on its headers. using (var sampleBuffer = new CVPixelBuffer(imageBufferPtr)) { func(sourceFrame, status, infoFlags, sampleBuffer, presentationTimeStamp, presentationDuration); } }
static void DecompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceFrame, VTStatus status, VTDecodeInfoFlags infoFlags, IntPtr imageBufferPtr, CMTime presentationTimeStamp, CMTime presentationDuration) { var gch = GCHandle.FromIntPtr (outputCallbackClosure); var func = (VTDecompressionOutputCallback) gch.Target; // Apple headers states that the callback should get a CVImageBuffer but it turned out that not all of them are a // CVImageBuffer, some can be instances of CVImageBuffer and others can be instances of CVPixelBuffer. So we go one // step further in the inheritance hierarchy and supply the callback a CVPixelBuffer and the callback supplies // to the developer a CVImageBuffer, so the developer can choose when to use one or the other and we mimic // what Apple provides on its headers. using (var sampleBuffer = new CVPixelBuffer (imageBufferPtr)) { func (sourceFrame, status, infoFlags, sampleBuffer, presentationTimeStamp, presentationDuration); } }
extern static unsafe VTStatus VTDecompressionSessionDecodeFrameWithOutputHandler( /* VTDecompressionSessionRef */ IntPtr session, /* CMSampleBufferRef */ IntPtr sampleBuffer, /* VTDecodeFrameFlags */ VTDecodeFrameFlags decodeFlags, /* VTDecodeInfoFlags */ out VTDecodeInfoFlags infoFlagsOut, /* VTDecompressionOutputHandler */ BlockLiteral *outputHandler);
public VTStatus DecodeFrame(CMSampleBuffer sampleBuffer, VTDecodeFrameFlags decodeFlags, IntPtr sourceFrame, out VTDecodeInfoFlags infoFlags) { if (Handle == IntPtr.Zero) { throw new ObjectDisposedException("DecompressionSession"); } if (sampleBuffer == null) { throw new ArgumentNullException("sampleBuffer"); } return(VTDecompressionSessionDecodeFrame(Handle, sampleBuffer.Handle, decodeFlags, sourceFrame, out infoFlags)); }
extern static VTStatus VTDecompressionSessionDecodeFrame( /* VTDecompressionSessionRef */ IntPtr session, /* CMSampleBufferRef */ IntPtr sampleBuffer, /* VTDecodeFrameFlags */ VTDecodeFrameFlags decodeFlags, /* void* */ IntPtr sourceFrame, /* VTDecodeInfoFlags */ out VTDecodeInfoFlags infoFlagsOut);
public VTStatus DecodeFrame (CMSampleBuffer sampleBuffer, VTDecodeFrameFlags decodeFlags, out VTDecodeInfoFlags infoFlags, VTDecompressionOutputHandler outputHandler) { if (Handle == IntPtr.Zero) throw new ObjectDisposedException ("DecompressionSession"); if (sampleBuffer == null) throw new ArgumentNullException ("sampleBuffer"); if (outputHandler == null) throw new ArgumentNullException ("outputHandler"); unsafe { var block = new BlockLiteral (); var blockPtr = █ block.SetupBlock (decompressionOutputHandlerTrampoline, outputHandler); try { return VTDecompressionSessionDecodeFrameWithOutputHandler (Handle, sampleBuffer.Handle, decodeFlags, out infoFlags, blockPtr); } finally { blockPtr->CleanupBlock (); } } }
static unsafe void VTDecompressionOutputHandlerTrampoline (BlockLiteral *block, VTStatus status, VTDecodeInfoFlags infoFlags, IntPtr imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration) { var del = (VTDecompressionOutputHandler)(block->Target); if (del != null) del (status, infoFlags, new CVImageBuffer (imageBuffer), presentationTimeStamp, presentationDuration); }
extern static unsafe VTStatus VTDecompressionSessionDecodeFrameWithOutputHandler ( /* VTDecompressionSessionRef */ IntPtr session, /* CMSampleBufferRef */ IntPtr sampleBuffer, /* VTDecodeFrameFlags */ VTDecodeFrameFlags decodeFlags, /* VTDecodeInfoFlags */ out VTDecodeInfoFlags infoFlagsOut, /* VTDecompressionOutputHandler */ BlockLiteral *outputHandler);
public VTStatus DecodeFrame (CMSampleBuffer sampleBuffer, VTDecodeFrameFlags decodeFlags, IntPtr sourceFrame, out VTDecodeInfoFlags infoFlags) { if (Handle == IntPtr.Zero) throw new ObjectDisposedException ("DecompressionSession"); if (sampleBuffer == null) throw new ArgumentNullException ("sampleBuffer"); return VTDecompressionSessionDecodeFrame (Handle, sampleBuffer.Handle, decodeFlags, sourceFrame, out infoFlags); }
extern static VTStatus VTDecompressionSessionDecodeFrame ( /* VTDecompressionSessionRef */ IntPtr session, /* CMSampleBufferRef */ IntPtr sampleBuffer, /* VTDecodeFrameFlags */ VTDecodeFrameFlags decodeFlags, /* void* */ IntPtr sourceFrame, /* VTDecodeInfoFlags */ out VTDecodeInfoFlags infoFlagsOut);
void DidDecompress(IntPtr sourceFrame, VTStatus status, VTDecodeInfoFlags flags, CVImageBuffer buffer, CMTime presentationTimeStamp, CMTime presentationDuration) { if (status != VTStatus.Ok) { Console.WriteLine ("Error decompresssing frame at time: {0:#.###} error: {1} infoFlags: {2}", (float)presentationTimeStamp.Value / presentationTimeStamp.TimeScale, (int)status, flags); return; } if (buffer == null) return; // Find the correct position for this frame in the output frames array if (presentationTimeStamp.IsInvalid) { Console.WriteLine ("Not a valid time for image buffer"); return; } var framePTS = presentationTimeStamp.Seconds; lock (thisLock) { // since we want to keep the managed `pixelBuffer` alive outside the execution // of the callback we need to create our own (managed) instance from the handle var pixelBuffer = Runtime.GetINativeObject<CVPixelBuffer> (buffer.Handle, false); int insertionIndex = presentationTimes.Count - 1; while (insertionIndex >= 0) { var aNumber = presentationTimes [insertionIndex]; if (aNumber <= framePTS) break; insertionIndex--; } if (insertionIndex + 1 == presentationTimes.Count) { presentationTimes.Add (framePTS); outputFrames.Add (pixelBuffer); } else { presentationTimes.Insert (insertionIndex + 1, framePTS); outputFrames.Insert (insertionIndex + 1, pixelBuffer); } } }