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,感兴趣的开发者,可以尝试看看,有问题可以单独跟我沟通。

相关推荐
dvlinker1 天前
【音视频开发】使用支持硬件加速的D3D11绘图遇到的绘图失败与绘图崩溃问题的记录与总结
音视频开发·c/c++·视频播放·d3d11·d3d11绘图模式
aqi004 天前
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
ffmpeg·音视频·直播·流媒体
音视频牛哥6 天前
Android平台GB28181实时回传流程和技术实现
音视频开发·视频编码·直播
音视频牛哥8 天前
RTMP、RTSP直播播放器的低延迟设计探讨
音视频开发·视频编码·直播
音视频牛哥12 天前
电脑共享同屏的几种方法分享
音视频开发·视频编码·直播
aqi0014 天前
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
android·ffmpeg·音视频·直播·流媒体
aqi0015 天前
FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher
android·ffmpeg·音视频·直播·流媒体
加油吧x青年16 天前
Web端开启直播技术方案分享
前端·webrtc·直播
aqi001 个月前
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
android·ffmpeg·音视频·直播·流媒体