private void RenderWebRTCFrameYUV(MLWebRTC.VideoSink.Frame frame)
        {
            for (int i = 0; i < rawVideoTexturesYUV.Length; ++i)
            {
                MLWebRTC.VideoSink.Frame.ImagePlane imagePlane = frame.ImagePlanes[i];
                if (imagePlane.Data == System.IntPtr.Zero)
                {
                    return;
                }

                UpdateYUVTextureChannel(ref rawVideoTexturesYUV[i], imagePlane, remoteDisplayYUV, samplerNamesYUV[i]);
            }
        }
        private void RenderWebRTCFrameRGB(MLWebRTC.VideoSink.Frame frame)
        {
            for (int i = 0; i < rawVideoTexturesRGB.Length; ++i)
            {
                MLWebRTC.VideoSink.Frame.ImagePlane imagePlane = frame.ImagePlanes[i];
                Texture2D rawVideoTextureRGB = rawVideoTexturesRGB[i];

                int width = (int)(imagePlane.Stride / imagePlane.BytesPerPixel);
                if (rawVideoTextureRGB == null || rawVideoTextureRGB.width != width || rawVideoTextureRGB.height != imagePlane.Height)
                {
                    rawVideoTextureRGB                         = new Texture2D(width, (int)imagePlane.Height, TextureFormat.RGBA32, false);
                    rawVideoTextureRGB.filterMode              = FilterMode.Bilinear;
                    remoteDisplayRGB.material.mainTexture      = rawVideoTextureRGB;
                    remoteDisplayRGB.material.mainTextureScale = new Vector2(1.0f, -1.0f);
                }

                rawVideoTexturesRGB[i] = rawVideoTextureRGB;
                rawVideoTextureRGB.LoadRawTextureData(imagePlane.Data, (int)imagePlane.Size);
                rawVideoTextureRGB.Apply();
            }
        }
        private void RenderWebRTCFrame(MLWebRTC.VideoSink.Frame frame)
        {
            if (frame.ImagePlanes == null)
            {
                return;
            }

#if PLATFORM_LUMIN
            float fps = 1.0f / fpsTimer.Elapsed();

            if (fpsText != null)
            {
                fpsText.text = string.Format("{0:0.00}", fps);
                if (fps >= 24f)
                {
                    fpsText.color = Color.green;
                }
                else if (fps >= 16f)
                {
                    fpsText.color = Color.yellow;
                }
                else
                {
                    fpsText.color = Color.red;
                }
            }
#endif
            if (frame.ImagePlanes.Length > 1)
            {
                float aspectRatio = frame.ImagePlanes[0].Width / (float)frame.ImagePlanes[0].Height;
                float scaleWidth  = transform.lossyScale.y * aspectRatio;

                // sets the plane to the aspect ratio of the frame
                if (transform.lossyScale.x != scaleWidth)
                {
                    Transform parent = transform.parent;
                    transform.parent     = null;
                    transform.localScale = new Vector3(scaleWidth, transform.localScale.y, transform.localScale.z);
                    transform.parent     = parent;
                }
            }

            switch (frame.Format)
            {
            case MLWebRTC.VideoSink.Frame.OutputFormat.YUV_420_888:
            {
                if (!this.remoteDisplayYUV.enabled || this.remoteDisplayRGB.enabled)
                {
                    this.remoteDisplayRGB.enabled = false;
                    this.remoteDisplayYUV.enabled = true;
                }
                RenderWebRTCFrameYUV(frame);
                break;
            }

            case MLWebRTC.VideoSink.Frame.OutputFormat.RGBA_8888:
            {
                if (!this.remoteDisplayRGB.enabled || this.remoteDisplayYUV.enabled)
                {
                    this.remoteDisplayYUV.enabled = false;
                    this.remoteDisplayRGB.enabled = true;
                }
                RenderWebRTCFrameRGB(frame);
                break;
            }
            }

#if PLATFORM_LUMIN
            fpsTimer.Reset();
#endif
        }