wpf下如何实现超低延迟的RTMP或RTSP播放

​技术背景

我们在做Windows平台RTMP和RTSP播放模块对接的时候,有开发者需要在wpf下调用,如果要在wpf下使用,只需要参考C#的对接demo即可,唯一不同的是,视频流数据显示的话,要么通过控件模式,要么可以让RTMP、RTSP播放模块回调rgb数据上来,在wpf直接绘制即可。

技术实现

本文以大牛直播SDK的Windows平台SmartPlayer为例,回调数据的模式,其他不再说明,只要处理好上来的数据就好:

播放之前,设置回调,选择NT_SP_E_VIDEO_FRAME_FORMAT_RGB32:

ini 复制代码
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_);

处理rgb数据回调:

ini 复制代码
       /*
        * nt_player_wrapper.cs
        * Author: daniusdk.com
        */
        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));

            if (video_frame.format_ != (Int32)NT.NTSmartPlayerDefine.NT_SP_E_VIDEO_FRAME_FORMAT.NT_SP_E_VIDEO_FRAME_FORMAT_RGB32)
                return;

            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);
        }

另外一种,可以用picturebox,在MainWindow.xaml 做以下设置:

ini 复制代码
        <WindowsFormsHost HorizontalAlignment="Left" Height="338" Margin="10,10,0,0" VerticalAlignment="Top" Width="480" Background="Black">
            <wf:PictureBox x:Name="RealPlayWnd"></wf:PictureBox>
        </WindowsFormsHost>

为了便于多实例集成参考,以播放2路为例(一路2560*1440,一路1920*1080):

具体实现如下:

csharp 复制代码
       /*
        * MainWindow.xaml.cs
        * Author: daniusdk.com
        */
        public MainWindow()
        {
            InitializeComponent();

            if (!InitSDK())
                return;

            UIDispatcher = Dispatcher.CurrentDispatcher;

            player1_ = new nt_player_wrapper(RealPlayWnd, UIDispatcher);
            player1_.EventGetPlayerEventMsg += new DelGetPlayerEventMsg(GetPlayerEventMsgInfo);
            player1_.EventGetVideoSize += new DelGetVideoSize(GetVideoSize);

            player2_ = new nt_player_wrapper(RealPlayWnd1, UIDispatcher);
            player2_.EventGetPlayerEventMsg += new DelGetPlayerEventMsg(GetPlayerEventMsgInfo);
            player2_.EventGetVideoSize += new DelGetVideoSize(GetVideoSize);
        }

        private void GetPlayerEventMsgInfo(IntPtr handle, String msg)
        {
            this.Dispatcher.Invoke((Action)delegate()
            {
                event_label.Content = msg;
            });
        }

        private void GetVideoSize(IntPtr handle, String size)
        {
            this.Dispatcher.Invoke((Action)delegate()
            {
                video_size.Content = size;
            });
        }

        private bool InitSDK()
        {
            if (!is_player_sdk_init_)
            {
                UInt32 isPlayerInited = NT.NTSmartPlayerSDK.NT_SP_Init(0, IntPtr.Zero);
                if (isPlayerInited != 0)
                {
                    MessageBox.Show("调用NT_SP_Init失败..");
                    return false;
                }

                is_player_sdk_init_ = true;
            }

            return true;
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (!player1_.IsPlaying())
            {
                player1_.SetBuffer(0);
                bool is_mute = true;

                if (!player1_.StartPlay("rtsp://admin:daniulive12345@192.168.0.120:554/h264/ch1/main/av_stream", false, is_mute))
                    return;

                btn_playback1.Content = "停止播放";
            }
            else
            {
                player1_.StopPlay();
                btn_playback1.Content = "开始播放";
            }
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            if (!player2_.IsPlaying())
            {
                player2_.SetBuffer(0);
                bool is_mute = true;

                if (!player2_.StartPlay("rtsp://admin:admin123456@192.168.0.121:554/cam/realmonitor?channel=1&subtype=0", false, is_mute))
                    return;

                btn_playback2.Content = "停止播放";
            }
            else
            {
                player2_.StopPlay();
                btn_playback2.Content = "开始播放";
            }
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            if (MessageBox.Show("确定要关闭窗口吗?", "确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
            {
                // 如果用户选择"否",取消关闭
                e.Cancel = true;
            }

            if (player1_.IsPlaying())
            {
                player1_.StopPlay();
            }

            player1_.Dispose();

            if (player2_.IsPlaying())
            {
                player2_.StopPlay();
            }

            player2_.Dispose();

            if (is_player_sdk_init_)
            {
                NTSmartPlayerSDK.NT_SP_UnInit();
                is_player_sdk_init_ = false;
            }    

            base.OnClosing(e);
        }

延迟依旧毫秒级,CPU占用如下,如果用硬解码,体验会更好:

SmartPlayer以跨平台的RTSP播放器为例,我们实现的功能如下,如不单独说明,系Windows、Linux、Android、iOS全平台支持:

  • 支持播放协议高稳定、超低延迟、业内首屈一指的RTSP直播播放器SDK;
  • 多实例播放支持多实例播放;
  • 事件回调支持网络状态、buffer状态等回调;
  • 视频格式支持H.265、H.264,此外,还支持RTSP MJPEG播放;
  • 音频格式支持AAC/PCMA/PCMU;
  • H.264/H.265软解码支持H.264/H.265软解;
  • H.264硬解码Windows/Android/iOS支持特定机型H.264硬解;
  • H.265硬解Windows/Android/iOS支持特定机型H.265硬解;
  • H.264/H.265硬解码Android支持设置Surface模式硬解和普通模式硬解码;
  • RTSP模式设置支持RTSP TCP/UDP模式设置;
  • RTSP TCP/UDP自动切换支持RTSP TCP、UDP模式自动切换;
  • RTSP超时设置支持RTSP超时时间设置,单位:秒;
  • RTSP 401认证处理支持上报RTSP 401事件,如URL携带鉴权信息,会自动处理;
  • 缓冲时间设置支持buffer time设置;
  • 首屏秒开支持首屏秒开模式;
  • 复杂网络处理支持断网重连等各种网络环境自动适配;
  • 快速切换URL支持播放过程中,快速切换其他URL,内容切换更快;
  • 音视频多种render机制Android平台,视频:surfaceview/OpenGL ES,音频:AudioTrack/OpenSL ES;
  • 实时静音支持播放过程中,实时静音/取消静音;
  • 实时音量调节支持播放过程中实时调节音量;
  • 实时快照支持播放过程中截取当前播放画面;
  • 只播关键帧Windows平台支持实时设置是否只播放关键帧;
  • 渲染角度支持0°,90°,180°和270°四个视频画面渲染角度设置;
  • 渲染镜像支持水平反转、垂直反转模式设置;
  • 等比例缩放支持图像等比例缩放绘制(Android设置surface模式硬解模式不支持);
  • 实时下载速度更新支持当前下载速度实时回调(支持设置回调时间间隔);
  • 解码前视频数据回调支持H.264/H.265数据回调;
  • 解码后视频数据回调支持解码后YUV/RGB数据回调;
  • 解码前音频数据回调支持AAC/PCMA/PCMU数据回调;
  • 音视频自适应支持播放过程中,音视频信息改变后自适应;
  • 扩展录像功能完美支持和录像模块组合使用。

总结

Windows平台下如果需要wpf播放,如果需要更灵活,可以采用回调rgb数据的模式,上层直接绘制,只是低延迟的播放出来画面,采用上述控件模式亦可,除了wpf外,我们提供了C++和C#的接口和demo,感兴趣的开发者,可以尝试看看,有问题可以单独跟我沟通。

相关推荐
音视频牛哥7 天前
不只是等待 IDR:SmartMediaKit 播放器对 H.264 GDR 码流的完整适配实践
音视频开发·视频编码·直播
三木彤14 天前
语音转文本python
音视频开发
鹧鸪晏18 天前
Android GLSurfaceView 完全指南
android·音视频开发
ltlovezh21 天前
AAC 元数据:ADTS 与 ASC 的区别、转换和常见坑
后端·ffmpeg·音视频开发
深念Y21 天前
我明白为什么B站没法在浏览器开直播了——Windows Chrome推流踩坑全记录
前端·chrome·webrtc·浏览器·srs·直播·flv
深念Y22 天前
仿B站直播功能技术选型:为什么必须用SRS而不是WebRTC P2P?
webrtc·srs·直播·推流·b站·多媒体·obs
MonkeyKing23 天前
iOS 音频实战:边播边缓存、预加载与断点续播完整实现
音视频开发
11年老程序猿在线搬砖23 天前
2026年语聊APP开发费用深度拆解:从MVP到百万并发的预算清单
音视频开发·创业·技术选型·社交app开发·语聊app·开发费用
深念Y1 个月前
网络多播与广播:到底能不能节省带宽和流量?
网络·直播·p2p·点对点·多播·流量·单播
sno_guo1 个月前
直播抠图技术100谈之25---调色中曲线是最优解
人工智能·算法·机器学习·直播·内容运营·obs抠图·直播技术