Search code examples
c#webrtcdirect3d

How to change received Argb32VideoFrame(or I420AVideoFrame) from Webrtc to Texture2D?


I have a question during the webrtc test. (client to client) The screen capture frame obtained from Direct3D was transmitted in the webrtc method.

(Sender)
_screenShareSource = ExternalVideoTrackSource.CreateFromArgb32Callback(FrameCallback);

var videoTrackConfig = new LocalVideoTrackInitConfig { trackName = "screen_track" };            
_localVideoTrack = LocalVideoTrack.CreateFromSource(_screenShareSource, videoTrackConfig);

_videoTransceiver = _peerConnection.AddTransceiver(MediaKind.Video);
_videoTransceiver.LocalVideoTrack = _localVideoTrack;
_videoTransceiver.DesiredDirection = Transceiver.Direction.SendReceive;


(Receiver)
_peerConnection.VideoTrackAdded += (RemoteVideoTrack track) =>
{
    _remoteVideoTrack = track;
    **_remoteVideoTrack.Argb32VideoFrameReady += _remoteVideoTrack_Argb32VideoFrameReady;
    // or _remoteVideoTrack.I420AVideoFrameReady += _remoteVideoTrack_I420AVideoFrameReady;**
};

Receiving the frame was successful.

private void _remoteVideoTrack_Argb32VideoFrameReady(Argb32VideoFrame frame)
{    
    if (frame.width != lastWidthSize ||
        frame.height != lastHeigthSize)
    {
        //newSize = true;
        lastWidthSize = frame.width;
        lastHeigthSize = frame.height;
        swapChain.ResizeBuffers(
            2,
            (int)lastWidthSize,
            (int)lastHeigthSize,
            SharpDX.DXGI.Format.B8G8R8A8_UNorm,
            SharpDX.DXGI.SwapChainFlags.None);
    }

    using (var backBuffer = swapChain.GetBackBuffer<SharpDX.Direct3D11.Texture2D>(0))
        using (var bitmap = Direct3D11Helper.CreateSharpDXTexture2D(UpdateImage(frame)))
    {
        d3dDevice.ImmediateContext.CopyResource(bitmap, backBuffer);
    }
    swapChain.Present(0, SharpDX.DXGI.PresentFlags.None);
}

So, I want to display it on the screen with Direct3D, but I don't know how.

How to change Argb32VideoFrame (or I420AVideoFrame) to Texture2D?

Or... Is there a way to display Argb32VideoFrame (or I420AVideoFrame) on the screen in the current environment?

  • test environment: Win10, C#(.netframework/.netcore desktop)

Solution

  • This is one of the ways to change a bitmap to Texture2D.

        public SharpDX.Direct3D11.Texture2D CreateTexture2DFromBitmap(Argb32VideoFrame frame)
        {
            var width = (int)frame.width;
            var height = (int)frame.height;
            var stride = (int)frame.stride;
    
            SharpDX.Direct3D11.Texture2DDescription desc = new SharpDX.Direct3D11.Texture2DDescription
            {
                Width = width,
                Height = height,
                ArraySize = 1,
                BindFlags = SharpDX.Direct3D11.BindFlags.ShaderResource,
                Usage = SharpDX.Direct3D11.ResourceUsage.Default,
                CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.None,
                Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm,
                MipLevels = 1,
                OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None,
                SampleDescription = new SharpDX.DXGI.SampleDescription { Count = 1, Quality = 0 }
            };
    
            using (Bitmap bitmap = new Bitmap(width, height, stride, PixelFormat.Format32bppPArgb, frame.data))
            {
                BitmapData bmData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat);
                SharpDX.DataBox data = new SharpDX.DataBox(bmData.Scan0, bmData.Stride, 0);
                SharpDX.DataRectangle rect = new SharpDX.DataRectangle(data.DataPointer, data.RowPitch);
                SharpDX.Direct3D11.Texture2D _texture = new SharpDX.Direct3D11.Texture2D(d3dDevice, desc, new[] { rect });
                bitmap.UnlockBits(bmData);
                return _texture;
            }
        }