/// <summary> /// Remove all frames captured before the given capture time. They will not be encoded. /// </summary> public void WipeBufferUntil(double AbandonTime) { lock (this) { lock (WaitingCaptures) { while (WaitingCaptures.DataAvailable(this)) { var ti = WaitingCaptures.Peek(this); if (ti != null && ti.Seconds < AbandonTime) { WaitingCaptures.Dequeue(this); } else { break; } } } } lock (WaitingFrames) { while (WaitingFrames.Count > 0 && WaitingFrames[0].Seconds < AbandonTime) { WaitingFrames.RemoveAt(0); } } GC.Collect(); }
/// <summary> /// Load the buffer into a MediaFrame for the encoder. /// IMPORTANT: You must call UnloadFrame after this method is called. /// For efficiency, unload as soon as possible. /// </summary> public void LoadToFrame(ref MediaFrame Frame) { try { if (WaitingFrames.Count > 0) { TimedImage img = null; lock (WaitingFrames) { WaitingFrames.RemoveAll(a => a == null); WaitingFrames.Sort((a, b) => a.Seconds.CompareTo(b.Seconds)); img = WaitingFrames[0]; WaitingFrames.RemoveAt(0); } if (img.Luma == null || img.Cr == null || img.Cb == null) { return; // crap frame } Y = img.Luma; u = img.Cr; v = img.Cb; Frame.VideoSize = (ulong)Y.Length; Frame.VideoSampleTime = img.Seconds; pinY = GCHandle.Alloc(Y, GCHandleType.Pinned); Frame.Yplane = pinY.AddrOfPinnedObject(); pinU = GCHandle.Alloc(u, GCHandleType.Pinned); Frame.Uplane = pinU.AddrOfPinnedObject(); pinV = GCHandle.Alloc(v, GCHandleType.Pinned); Frame.Vplane = pinV.AddrOfPinnedObject(); } else { Frame.Yplane = IntPtr.Zero; Frame.Uplane = IntPtr.Zero; Frame.Vplane = IntPtr.Zero; Frame.VideoSize = 0; Console.WriteLine("Frame buffer was empty (in ImageToYUV_Buffer.LoadToFrame())"); } } catch { // Drop the bad frame data: UnloadFrame(ref Frame); // this can still be sent to the encoder, it should just mean a dropped frame Console.WriteLine("Lost a frame (no image)"); } }