zoukankan      html  css  js  c++  java
  • 能用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模式绘制,感兴趣的开发者可以尝试看看。

  • 相关阅读:
    HDU 2236 无题Ⅱ
    Golden Tiger Claw(二分图)
    HDU 5969 最大的位或 (思维,贪心)
    HDU 3686 Traffic Real Time Query System (图论)
    SCOI 2016 萌萌哒
    Spring Boot支持控制台Banner定制
    构建第一个Spring Boot程序
    Spring Boot重要模块
    Java fastjson JSON和String互相转换
    BCompare 4 Windows激活方法【试用期30天重置】
  • 原文地址:https://www.cnblogs.com/daniulivesdk/p/13170102.html
Copyright © 2011-2022 走看看