wpf下RTSP|RTMP播放器两种渲染模式实现

这篇具有很好参考价值的文章主要介绍了wpf下RTSP|RTMP播放器两种渲染模式实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

技术背景

在这篇blog之前,我提到了wpf下播放RTMP和RTSP渲染的两种方式,一种是通过控件模式,另外一种是直接原生RTSP、RTMP播放模块,回调rgb,然后在wpf下渲染,本文就两种方式做个说明。

技术实现

以大牛直播SDK的Windows平台SmartPlayer为例,我们先说第一种通过控件模式,控件模式,非常简单:可以用picturebox,在MainWindow.xaml 做以下设置:

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

StartPlayer的时候,调NT_SP_SetRenderWindow,把handler设置下去即可,如果需要硬解码,可以先做硬解码检测,检测支持的话,设置硬解码模式。

       /*
        * nt_player_wrapper.cs
        * Author: daniusdk.com
        */
        public bool StartPlay(String url, bool is_rtsp_tcp_mode, bool is_mute, bool is_hardware_decorder)
        {
	        if ( is_playing_ )
		        return false;

            if (!OpenPlayerHandle(url, is_rtsp_tcp_mode, is_mute, is_hardware_decorder))
		        return false;

            //video resolution callback
            video_size_call_back_ = new SP_SDKVideoSizeCallBack(SP_SDKVideoSizeHandle);
            NTSmartPlayerSDK.NT_SP_SetVideoSizeCallBack(player_handle_, IntPtr.Zero, video_size_call_back_);

            if (render_wnd_ != null)
            {
                NTSmartPlayerSDK.NT_SP_SetRenderWindow(player_handle_, render_wnd_.Handle);
                NTSmartPlayerSDK.NT_SP_SetRenderScaleMode(player_handle_, 1);
            }
            else if(image_wnd_ != null)
            {
                //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_);
            }

	        uint ret = NTSmartPlayerSDK.NT_SP_StartPlay(player_handle_);
	        if ( NTBaseCodeDefine.NT_ERC_OK != ret )
	        {
                NTSmartPlayerSDK.NT_SP_Close(player_handle_);
			    player_handle_ = IntPtr.Zero;

		        return false;
	        }

	        is_playing_ = true;

	        return true;
        }

另外一种模式,是通过回调rgb,然后在image上渲染,回调rgb,在StartPlay()已有说明。=,设置回调,选择NT_SP_E_VIDEO_FRAME_FORMAT_RGB32格式,然后处理回调数据即可。

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数据回调的地方,拿到bitmap_source数据,设给image.Source即可:

        public void SDKVideoFrameCallBack(IntPtr handle, UInt32 status, BitmapSource bitmap_source)
        {
            if (image_wnd_ == null)
                return;

            if (player_handle_ == IntPtr.Zero || !is_playing_ || bitmap_source == null)
                return;
        
            image_wnd_.Source = bitmap_source;
        }

为了便于比较,我们做了个四窗口的demo展示(一路2560*1440,一路1920*1080),上面是通过picturebox控件直接设置handle到原生模块播放,第三第四个窗口知通过image自己绘制:

wpf下RTSP|RTMP播放器两种渲染模式实现,大牛直播SDK,wpf rtmp播放器,wpf rtsp播放器,wpf rtsp player,wpf rtmp player,wpf播放rtmp,wpf播放rtsp,大牛直播sdk

具体实现如下:

       /*
        * MainWindow.xaml.cs
        * Author: daniusdk.com
        */
        public MainWindow()
        {
            InitializeComponent();

            if (!InitSDK())
                return;

            UIDispatcher = Dispatcher.CurrentDispatcher;

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

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

            player3_ = new nt_player_wrapper(null, image_render, UIDispatcher);
            player3_.EventGetPlayerEventMsg += new DelGetPlayerEventMsg(GetPlayerEventMsgInfo);
            player3_.EventGetVideoSize += new DelGetVideoSize(GetVideoSize);

            player4_ = new nt_player_wrapper(null, image_render1, UIDispatcher);
            player4_.EventGetPlayerEventMsg += new DelGetPlayerEventMsg(GetPlayerEventMsgInfo);
            player4_.EventGetVideoSize += new DelGetVideoSize(GetVideoSize);
        }

        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;
                bool is_hardware_decoder = true;

                if (!player1_.StartPlay("rtsp://admin:daniulive12345@192.168.0.120:554/h264/ch1/main/av_stream", false, is_mute, is_hardware_decoder))
                    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;
                bool is_hardware_decoder = true;

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

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

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

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

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

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

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

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


关闭窗口的时候,记得调用停止播放逻辑,所有实例关闭后,调用NT_SP_UnInit():

        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 (player3_.IsPlaying())
            {
                player3_.StopPlay();
            }

            player3_.Dispose();

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

            player4_.Dispose();

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

            base.OnClosing(e);
        }

总结

wpf下实现低延迟的RTSP或RTMP播放,以上两种模式都可以尝试看,都不麻烦,如果想更灵活,可以采用回调rgb然后自己绘制的模式,如果想更省事,那么直接picturebox控件handle设置下去,底层自己绘制,以上是大概的实现逻辑,感兴趣的开发者,或有这方面技术诉求的,有问题可以单独跟我沟通。文章来源地址https://www.toymoban.com/news/detail-852490.html

到了这里,关于wpf下RTSP|RTMP播放器两种渲染模式实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 播放器开发(五):视频帧处理并用SDL渲染播放

    VideoOutPut 模块 1、初始化【分配缓存、读取信息】 2、开始线程工作【从队列读帧-缩放-发送渲染信号到窗口】 VideoWidget 自定义Widget类 1、定义内部变量 2、如果使用SDL,需要进行初始化 3、接收到信号后需要执行槽函数进行渲染 分配缓存 执行缩放 创建SDL窗口纹理渲染器 SDL渲

    2024年01月22日
    浏览(34)
  • 一个WPF开发的、界面简洁漂亮的音频播放器

    今天推荐一个界面简洁、美观的、支持国际化开源音频播放器。 这是一个基于C# + WPF开发的,界面外观简洁大方,操作体验良好的音频播放器。 支持各种音频格式,包括:MP4、WMA、OGG、FLAC、M4A、AAC、WAV、APE 和 OPUS;支持标记、实时显示歌词等功能;支持换肤、中英文等主流

    2024年02月01日
    浏览(37)
  • VS+C#+WPF多线程视频摄像头播放器监控

    程序示例精选 C#+WPF多线程视频摄像头播放器监控 如需安装运行环境或远程调试,见文章底部个人 QQ 名片,由专业技术人员远程协助! 这篇博客针对C#+WPF多线程视频摄像头播放器监控编写代码,代码整洁,规则,易读。 学习与应用推荐首选。 为什么需要用多线程,多线程是

    2024年02月09日
    浏览(30)
  • 用VLC开发视频播放器/组件(两种方式:libVLC / VLC-Qt)

    MSVC-2015 Qt 5.14.2 QCreator 参考:心流剑 libVLC 各版本 下载链接 我的下载版本为:3.0.11 sdk/lib文件夹目录 qmake vlc 部分的配置(路径根据自己的修改) 只需要 : libvlc.lib、libvlccore.lib 把 plugins 文件夹、libvlc.dll、libvlccore.dll 复制到 bin_Debug / bin_Release VLC-Qt 下载地址 参考链接1:链接

    2024年02月12日
    浏览(80)
  • Qt推流程序(视频文件/视频流/摄像头/桌面转成流媒体rtmp+hls+webrtc)可在网页和播放器远程观看

    推流直播就是把采集阶段封包好的内容传输到服务器的过程。其实就是将现场的视频信号从手机端,电脑端,摄影机端打包传到服务器的过程。“推流”对网络要求比较高,如果网络不稳定,直播效果就会很差,观众观看直播时就会发生卡顿等现象,观看体验比较糟糕。主流

    2024年02月04日
    浏览(50)
  • 【设计模式】腾讯二面:自动贩卖机/音频播放器使用了什么设计模式?

    状态模式是什么? 状态模式,也被称作状态对象模式,是一种行为设计模式。 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类。 它让对象在其内部状态改变时改变自己的行为。外部调用者无需了解对象内部状态的具体实现,仅需通过简单的

    2024年01月20日
    浏览(34)
  • Artplayer视频JSON解析播放器源码|支持弹幕|json数据模式

    全开源Artplayer播放器视频解析源码,支持两种返回模式:网页播放模式、json数据模式,json数据模式支持限制ip每分钟访问次数+UA限制+key密钥,也可理解为防盗链 ,本播放器带弹幕库。 运行环境 推荐使用PHP8.0+ redis扩展插件 使用说明 1、本播放器不支持直链,需要一个正确的

    2024年04月26日
    浏览(21)
  • 腾讯二面:自动贩卖机/音频播放器使用了什么设计模式?

    状态模式是什么? 状态模式,也被称作状态对象模式,是一种行为设计模式。 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类。 它让对象在其内部状态改变时改变自己的行为。外部调用者无需了解对象内部状态的具体实现,仅需通过简单的

    2024年01月20日
    浏览(32)
  • csf格式手机播放器(安卓csf格式播放器)

    手机播放视频文件的方法: 1.使用手机自带的安卓播放器播放即可。 2.如果您的手机不支持所播放的视频文件格式,请下载第三方视频播放器播放。播放这种格式,需要下载一个CSF转化器的CSF编译软件,软件名字叫ScenicEditor。 另外也可以直接用格式工厂转换,将CSF直接转换成

    2024年02月10日
    浏览(42)
  • Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器

    Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器实例的示例: 上述代码中,使用 getInstance() 方法获取 AudioPlayer 的单例对象,参数传入 Context 对象。 在 getInstance() 方法中判断单例对象是否为空,如果为空则创建新的 AudioPlayer 对象,否则返回已有的单例对象。 这样

    2024年02月12日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包