Esempio n. 1
0
        void ReleaseSenderObjects()
        {
            // Total synchronization: This may cause a frame hiccup, but it's
            // needed to dispose the readback buffers safely.
            AsyncGPUReadback.WaitAllRequests();

            // Game view capture method: Leave the sender instance without
            // disposing (we're not the owner) but synchronize it. It's needed to
            // dispose the readback buffers safely too.
            if (SharedInstance.IsGameViewSend(_send))
            {
                _send.SendVideoAsync(); // Sync by null-send
                _send = null;
            }

            // Private objet disposal
            _send?.Dispose();
            _send = null;

            _pool?.Dispose();
            _pool = null;

            _converter?.Dispose();
            _converter = null;

            // We don't dispose _onReadback because it's reusable.
        }
Esempio n. 2
0
        unsafe void OnReadback(AsyncGPUReadbackRequest request)
        {
            // Metadata retrieval
            using (var metadata = _metadataQueue.Dequeue())
            {
                // Ignore errors.
                if (request.hasError)
                {
                    return;
                }

                // Ignore it if the NDI object has been already disposed.
                if (_send == null || _send.IsInvalid || _send.IsClosed)
                {
                    return;
                }

                // Pixel format (depending on alpha mode)
                var fourcc = _enableAlpha ?
                             Interop.FourCC.UYVA : Interop.FourCC.UYVY;

                // Readback data retrieval
                var data  = request.GetData <byte>();
                var pdata = NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(data);

                // Data size verification
                if (data.Length / sizeof(uint) !=
                    Util.FrameDataCount(_width, _height, _enableAlpha))
                {
                    return;
                }

                // Frame data setup
                var frame = new Interop.VideoFrame
                {
                    Width  = _width, Height = _height, LineStride = _width * 2,
                    FourCC = _enableAlpha ?
                             Interop.FourCC.UYVA : Interop.FourCC.UYVY,
                    FrameFormat = Interop.FrameFormat.Progressive,
                    Data        = (System.IntPtr)pdata, Metadata = metadata
                };

                // Send via NDI
                _send.SendVideoAsync(frame);
            }
        }
Esempio n. 3
0
        unsafe void OnReadback(AsyncGPUReadbackRequest request)
        {
            // Metadata retrieval
            using (var metadata = _metadataQueue.Dequeue())
            {
                // Ignore errors.
                if (request.hasError)
                {
                    return;
                }

                // Ignore it if the NDI object has been already disposed.
                if (_send == null || _send.IsInvalid || _send.IsClosed || !_enableVideoFrames)
                {
                    return;
                }

                // Pixel format (depending on alpha mode)
                var fourcc = _enableAlpha ?
                             Interop.FourCC.UYVA : Interop.FourCC.UYVY;

                // Readback data retrieval
                var data = request.GetData <byte>();

                // NDI SDK Documentation p.21 re: send_video_v2_async
                //
                // If you call this and then free the pointer, your application will
                // most likely crash in an NDI thread because the SDK is still using the video frame
                // that was passed to the call.
                // One possible solution is to ping pong between two buffers on
                // alternating calls to NDIlib_send_send_video_v2_async

                if (data.Length <= 0)
                {
                    return;
                }

                if (videoFrameBuffer1 == null || videoFrameBuffer1.Length <= 0)
                {
                    videoFrameBuffer1 = new byte[data.Length];
                    bufferHandle1     = GCHandle.Alloc(videoFrameBuffer1, GCHandleType.Pinned);
                }

                if (videoFrameBuffer2 == null || videoFrameBuffer2.Length <= 0)
                {
                    videoFrameBuffer2 = new byte[data.Length];
                    bufferHandle2     = GCHandle.Alloc(videoFrameBuffer2, GCHandleType.Pinned);
                }

                // Handle frame size change
                if (videoFrameBuffer1.Length != data.Length)
                {
                    _send.SendVideoAsync(emptyVideoFrame);
                    bufferHandle1.Free();
                    videoFrameBuffer1 = new byte[data.Length];
                    bufferHandle1     = GCHandle.Alloc(videoFrameBuffer1, GCHandleType.Pinned);
                }
                if (videoFrameBuffer2.Length != data.Length)
                {
                    _send.SendVideoAsync(emptyVideoFrame);
                    bufferHandle2.Free();
                    videoFrameBuffer2 = new byte[data.Length];
                    bufferHandle2     = GCHandle.Alloc(videoFrameBuffer2, GCHandleType.Pinned);
                }

                // Ping pong handles
                var pdata = ping == 0 ? bufferHandle1.AddrOfPinnedObject() : bufferHandle2.AddrOfPinnedObject();
                data.CopyTo(ping == 0 ? videoFrameBuffer1 : videoFrameBuffer2);
                ping = ping == 0 ? 1 : 0;

                // Data size verification
                if (data.Length / sizeof(uint) !=
                    Util.FrameDataCount(_width, _height, _enableAlpha))
                {
                    return;
                }

                // Frame data setup
                var frame = new Interop.VideoFrame
                {
                    Width      = _width, Height = _height, LineStride = _width * 2,
                    FrameRateN = (int)frameRateND.x,
                    FrameRateD = (int)frameRateND.y,
                    FourCC     = _enableAlpha ?
                                 Interop.FourCC.UYVA : Interop.FourCC.UYVY,
                    FrameFormat = Interop.FrameFormat.Progressive,
                    Data        = (System.IntPtr)pdata, Metadata = metadata
                };

                // Send via NDI
                _send.SendVideoAsync(frame);

                if (metadata != IntPtr.Zero)
                {
                    _onVideoMetadataSent?.Invoke();
                }
            }
        }