• 能用D3D要啥自行车?Windows平台播放RTSP或RTMP渲染模式比较


    废话不多说,先说结论,Windows平台播放渲染这块,支持D3D的前提下,优先D3D,如果检测到不支持D3D,数据回调上来,GDI模式绘制。

    相比GDI模式,D3D绘制更细腻,绘制效率更高,CPU占用低,只要是系统检测支持,一般建议D3D模式。

    无图无真相:

    本文以1920*1080分辨率、30帧、固定码率(采集屏幕左侧区域)为例,通过大牛直播SDK ( github) 的Windows平台SmartPublisherDemo.exe工具推送到内网nginx服务器,然后分别以D3D模式和GDI模式拉流(播放端缓冲设置为0)。

    可以看到:

    D3D模式,CPU占用只有2.7%,延迟:249-156 = 93ms;

    GDI模式,CPU占用19.5%,延迟249-73 = 176ms。

    无论是从延迟和CPU占用上看,D3D模式都占优。

    实现思路:

    以C#的demo为例:

    1. 先检测系统是否支持D3D模式:

                    if (NT.NTBaseCodeDefine.NT_ERC_OK == NTSmartPlayerSDK.NT_SP_IsSupportD3DRender(player_handle_, playWnd.Handle, ref in_support_d3d_render))
                    {
                        if (1 == in_support_d3d_render)
                        {
                            is_support_d3d_render = true;
                        }
                    }

    2. 如不支持D3D,数据回到上层,做绘制:

                    if (is_support_d3d_render)
                    {
                        is_gdi_render_ = false;
    
                        // 支持d3d绘制的话,就用D3D绘制
                        NTSmartPlayerSDK.NT_SP_SetRenderWindow(player_handle_, playWnd.Handle);
    
                        if (btn_check_render_scale_mode.Checked)
                        {
                            NTSmartPlayerSDK.NT_SP_SetRenderScaleMode(player_handle_, 1);
                        }
                        else
                        {
                            NTSmartPlayerSDK.NT_SP_SetRenderScaleMode(player_handle_, 0);
                        }
                        
                    }
                    else
                    {
                        is_gdi_render_ = true;
    
                        playWnd.Visible = false;
    
                        // 不支持D3D就让播放器吐出数据来,用GDI绘制
    
                        //video frame callback (YUV/RGB)
                        //format请参见 NT_SP_E_VIDEO_FRAME_FORMAT,如需回调YUV,请设置为 NT_SP_E_VIDEO_FRAME_FROMAT_I420
                        video_frame_call_back_ = new SP_SDKVideoFrameCallBack(SetVideoFrameCallBack);
                        NTSmartPlayerSDK.NT_SP_SetVideoFrameCallBack(player_handle_, (Int32)NT.NTSmartPlayerDefine.NT_SP_E_VIDEO_FRAME_FORMAT.NT_SP_E_VIDEO_FRAME_FORMAT_RGB32, IntPtr.Zero, video_frame_call_back_);
                    }
            public void SetVideoFrameCallBack(IntPtr handle, IntPtr userData, UInt32 status, IntPtr frame)
            {
                if (frame == IntPtr.Zero)
                {
                    return;
                }
    
                //如需直接处理RGB数据,请参考以下流程
                NT_SP_VideoFrame video_frame = (NT_SP_VideoFrame)Marshal.PtrToStructure(frame, typeof(NT_SP_VideoFrame));
    
                NT_SP_VideoFrame pVideoFrame = new NT_SP_VideoFrame();
    
                pVideoFrame.format_ = video_frame.format_;
                pVideoFrame.width_ = video_frame.width_;
                pVideoFrame.height_ = video_frame.height_;
    
                pVideoFrame.timestamp_ = video_frame.timestamp_;
                pVideoFrame.stride0_ = video_frame.stride0_;
                pVideoFrame.stride1_ = video_frame.stride1_;
                pVideoFrame.stride2_ = video_frame.stride2_;
                pVideoFrame.stride3_ = video_frame.stride3_;
    
                Int32 argb_size = video_frame.stride0_ * video_frame.height_;
    
                pVideoFrame.plane0_ = Marshal.AllocHGlobal(argb_size);
                CopyMemory(pVideoFrame.plane0_, video_frame.plane0_, (UInt32)argb_size);
    
    
                if (playWnd.InvokeRequired)
                {
                    BeginInvoke(set_video_frame_call_back_, status, pVideoFrame);
                }
                else
                {
                    set_video_frame_call_back_(status, pVideoFrame);
                }
            }

    具体绘制代码:

            private void SmartPlayerForm_Paint(object sender, PaintEventArgs e)
            {
                if (player_handle_ == IntPtr.Zero || !is_gdi_render_ || !is_playing_)
                {
                    return;
                }
    
                if (cur_video_frame_.plane0_ == IntPtr.Zero)
                {
                    return;
                }
    
                Bitmap bitmap = new Bitmap(cur_video_frame_.width_, cur_video_frame_.height_, cur_video_frame_.stride0_,
                     System.Drawing.Imaging.PixelFormat.Format32bppRgb, cur_video_frame_.plane0_);
    
                int image_width = cur_video_frame_.width_;
                int image_height = cur_video_frame_.height_;
    
                Graphics g = e.Graphics;    //获取窗体画布
                g.SmoothingMode = SmoothingMode.HighSpeed;
    
                int limit_w = this.Width - 60;
                int limit_h = this.Height - playWnd.Top - 60;
    
                if (btn_check_render_scale_mode.Checked)
                {
                    int d_w = 0, d_h = 0;
                    int left_offset = 0;
                    int top_offset = 0;
    
                    Brush brush = new SolidBrush(Color.Black);
                    g.FillRectangle(brush, playWnd.Left, playWnd.Top, limit_w, limit_h);
    
                    GetRenderRect(limit_w, limit_h, image_width, image_height, ref left_offset, ref top_offset, ref d_w, ref d_h);
                    g.DrawImage(bitmap, playWnd.Left + left_offset, playWnd.Top + top_offset, d_w, d_h);   //在窗体的画布中绘画出内存中的图像
                }
                else
                {
                    g.DrawImage(bitmap, playWnd.Left, playWnd.Top, limit_w, limit_h);   //在窗体的画布中绘画出内存中的图像
                }
            }

    目前来看,不支持D3D的机器少之又少,在环境具备的情况下,优先建议考虑D3D模式绘制,感兴趣的开发者可以尝试看看。

  • 相关阅读:
    Typescript和React结合项目初始化
    React 和 TypeScript 如何一起使用
    Cesium取代leaflet,和Vue等前端框架结合
    cesium之3dtiles的制作问题
    Cesium-3dTiles格式详解
    TIN和等高线的关系
    CAD如何生成等高线
    Cesium风场
    cesium加载等高线
    DEM坡度和坡向分析
  • 原文地址:https://www.cnblogs.com/daniulivesdk/p/13170102.html
Copyright © 2020-2023  润新知