public override unsafe Task RenderFrameAsync(VideoFrameRenderer renderer, VideoFrameData frame, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(TaskHelper.CanceledTask); fixed(void *p = _screenBuffer) { renderer.RenderVideoFrame32(frame, (IntPtr)p, 160 * 4); } if (cancellationToken.IsCancellationRequested) return(TaskHelper.CanceledTask); } // Setting up a task completion source may not be needed here, but I don't know if there's something to gain by not doing so. if (SynchronizationContext != null) { var tcs = new TaskCompletionSource <bool>(); SynchronizationContext.Post(UpdateScreenAndPresent, tcs); return(tcs.Task); } else { UpdateScreenAndPresent(null); return(TaskHelper.TrueTask); } }
public override Task RenderFrameAsync(VideoFrameRenderer renderer, VideoFrameData frame, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(TaskHelper.CanceledTask); } var bitmap = _screenBitmapTripleBufferingSystem.GetCurrentProducerBuffer(); // Calls to GDI+ should be thread-safe for the most part, so we only have to take a little bit of care for ensuring correctness. bitmap.LockBits(_screenRectangle, ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb, _lockedScreenBitmapData); renderer.RenderVideoFrame32(frame, _lockedScreenBitmapData.Scan0, _lockedScreenBitmapData.Stride); bitmap.UnlockBits(_lockedScreenBitmapData); _screenBitmapTripleBufferingSystem.GetNextProducerBuffer(); if (cancellationToken.IsCancellationRequested) { return(TaskHelper.CanceledTask); } // Setting up a task completion source may not be needed here, but I don't know if there's something to gain by not doing so. if (SynchronizationContext != null) { var tcs = new TaskCompletionSource <bool>(); SynchronizationContext.Post(Render, tcs); return(tcs.Task); } else { Render(null); return(CompletedTask); } }