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 callbackvideo_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_I420video_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自己绘制:

具体实现如下:

       /** 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设置下去,底层自己绘制,以上是大概的实现逻辑,感兴趣的开发者,或有这方面技术诉求的,有问题可以单独跟我沟通。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/619224.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

双向链表的实现(详解)

目录 前言初始化双向链表的结构为双向链表的节点开辟空间头插尾插打印链表尾删头删查找指定位置之后的插入删除pos节点销毁双向链表 前言 链表的分类&#xff1a; 带头 不带头 单向 双向 循环 不循环 一共有 (2 * 2 * 2) 种链表 带头指的是&#xff1a;带有哨兵位节点 哨兵位&a…

webrtc中的Track,MediaChannel,MediaStream

文章目录 Track,MediaChannel,MediaStream的关系MediaStream的创建流程创建VideoChannel的堆栈创建VideoStream的堆栈 sdp中媒体参数信息的映射sdp中媒体信息参数设置体系参数设置流程参数映射体系 Track,MediaChannel,MediaStream的关系 Audio/Video track&#xff0c;MediaC…

Servlet实现常用功能及其他方法

getParameter 获取body或url中指定的key/value值 String classIdreq.getParameter("classId"); getQueryString 获取请求的所有查询参数key,values1 String queryStringreq.getQueryString(); from表单提交 前端通过from表单提交用户名和密码 <!DOCTYPE htm…

Java record类用法简介

参考资料 Java 16 新特性&#xff1a;record类新特性Record最全用法总结—动力节点总结Javaのレコードクラス从头学Java17-Stream API&#xff08;二&#xff09;结合Record、Optional 目录 一. 介绍二. 基本语法三. 各种特性示例3.1 准备3.2 创建&#xff0c;属性&#xff0c…

MySQL 社区版 安装总结

很早就安装过MySQL&#xff0c;没有遇到过什么问题&#xff0c;直接next就行了&#xff0c;这次在新电脑上安装却遇到了一些问题&#xff0c;记录一下。 安装的是MySQL社区版&#xff0c;下载地址是www.mysql.com&#xff0c;进入后选择DOWNLOAD页面&#xff0c;选择MySQL Com…

对常见FTP客户端/服务器的调查与分析

前言 主要是想看看常见的服务器和客户端是如何实现协议中要求的功能的&#xff0c;。 比如RF959要求的记录结构&#xff08;Record Structure&#xff09;、页结构&#xff08;Page Structure&#xff09;、Block Mode、Compress Mode&#xff0c;看起来就很抽象。 实测发现…

快速入门深度学习9.1(用时20min)——GRU

速通《动手学深度学习》9.1 写在最前面九、现代循环神经网络9.1 门控循环单元&#xff08;GRU&#xff09;9.1.1. 门控隐状态9.1.1.1. 重置门和更新门9.1.1.2. 候选隐状态9.1.1.3. 隐状态 9.1.3 API简洁实现小结 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 20…

【状态压缩 容斥原理 组合数学】100267. 单面值组合的第 K 小金额

本文涉及知识点 状态压缩 容斥原理 组合数学 二分查找算法合集 LeetCode100267. 单面值组合的第 K 小金额 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给你一个整数 k 。 你有无限量的每种面额的硬币。但是&#xff0c;你 不能 组合使用不同面额的硬币。 返回…

适合刚入门同学做的小程序项目

今天用uniapp做了一个酒桌数字筛子的小程序&#xff0c;因为平时玩的骰子小程序都是骰子的动画效果展示&#xff0c;喝多的时候非常容易看错&#x1f621;&#x1f601;&#xff0c;所以就想着看能不能做一个纯数字显示类型的骰盅&#xff0c;一目了然干净利落。&#x1f44f;&…

数据结构之排序了如指掌(三)

目录 题外话 正题 快速排序 Hoare法 Hoare法思路 Hoare法代码详解 挖坑法 挖坑法思路 挖坑法代码 前后指针法 前后指针法思路 前后指针法代码 小结 题外话 我们接着把没有写完的排序内容完成,快速排序其实大同小异,大家好好把思路整理一下 正题 快速排序 快速排序一…

BTS441RGATMA1 N沟道 43V 17A高侧电源开关芯片 英飞凌

BTS441RGATMA1是一款由Infineon Technologies制造的高侧开关电源芯片。 BTS441RGATMA1具有以下功能&#xff1a; 高端电源开关&#xff1a;BTS441RGATMA1是一种N通道功率场效应晶体管&#xff08;FET&#xff09;&#xff0c;用于高端电源开关应用。 高侧开关&#xff1a;该器件…

数据结构-堆详解

堆 图片&#xff1a; 二叉堆的父节点为这个子树的最值。 如何维护它。 我们发现它是一棵二叉树&#xff0c;那就自然满足若父节点为 x x x 则左儿子节点为 x 2 x\times2 x2 右儿子为 x 2 1 x\times 2 1 x21 这是显然的&#xff0c;但如果写成指针或结构体就太麻烦了&…