Windows平台如何实现RTSP|RTMP流录像?

ops/2024/10/9 14:18:21/

好多开发者使用场景,除了实现基础的低延迟RTSP、RTMP播放外,还需要实现RTSP、RTMP流数据的本地录像功能。本文以大牛直播SDK的Windows平台播放模块为例,介绍下如何实现RTSP、RTMP流录像

功能设计

  •  [拉流]支持拉取RTSP流录像
  •  [拉流]支持拉取RTMP流录像
  •  [逻辑分离]和播放、转发功能完全分离,支持随时录像;
  •  [参数设置]支持设置单个录像文件大小、录像路径等,并支持纯音频、纯视频、音视频录制模式;
  •  [音频转码]支持音频(PCMU/PCMA,Speex等)转AAC后再录像;
  •  [265支持]支持RTSP/RTMP H.265录制到MP4文件;
  •  [事件回调]从开始录像,到录像结束均有event callback上来。

引入相关头文件和库

C#头文件:

  • [base code定义]nt_base_code_define.cs
  • [player接口]smart_player_define.cs
  • [player参数定义]smart_player_sdk.cs

相关Lib:

  • SmartLog.dll
  • SmartLog.lib
  • SmartPlayerSDK.dll
  • SmartPlayerSDK.lib
  • avcodec-56.dll
  • avdevice-56.dll
  • avfilter-5.dll
  • avformat-56.dll
  • avutil-54.dll
  • postproc-53.dll
  • swresample-1.dll
  • swscale-3.dll

 设置日志存放路径

需要在player_api_.Init之前添加下面的代码:

// 设置日志路径(请确保目录存在)
String log_path = "D:\\playerlog";
NTSmartLog.NT_SL_SetPath(log_path);

如目录存在,并具备文件写入权限,关闭应用程序后,相关文件夹下会有smart_sdk.log生成。

初始化SDK

NT_SP_Init:SDK初始化,多实例播放,此接口仅需调用一次即可。

 创建播放实例

NT_SP_Open:每调用一次Open接口,对应一个播放实例,如需播放多实例,对应多个player handler。

if (player_handle_ == IntPtr.Zero)
{player_handle_ = new IntPtr();UInt32 ret_open = NTSmartPlayerSDK.NT_SP_Open(out player_handle_, IntPtr.Zero, 0, IntPtr.Zero);if (ret_open != 0){player_handle_ = IntPtr.Zero;MessageBox.Show("调用NT_SP_Open失败..");return;}
}

设置回调事件

NT_SP_SetEventCallBack:用于回调网络链接状态、buffer状态(开始、buffer比例、结束)、实时带宽等,对应EventID如下:

/*事件ID*/
public enum NT_SP_E_EVENT_ID : uint
{NT_SP_E_EVENT_ID_BASE = NTBaseCodeDefine.NT_EVENT_ID_SMART_PLAYER_SDK,NT_SP_E_EVENT_ID_CONNECTING          = NT_SP_E_EVENT_ID_BASE | 0x2, /*连接中*/NT_SP_E_EVENT_ID_CONNECTION_FAILED = NT_SP_E_EVENT_ID_BASE | 0x3, /*连接失败*/NT_SP_E_EVENT_ID_CONNECTED       = NT_SP_E_EVENT_ID_BASE | 0x4, /*已连接*/NT_SP_E_EVENT_ID_DISCONNECTED     = NT_SP_E_EVENT_ID_BASE | 0x5, /*断开连接*/NT_SP_E_EVENT_ID_NO_MEDIADATA_RECEIVED = NT_SP_E_EVENT_ID_BASE | 0x8,  /*收不到RTMP数据*/NT_SP_E_EVENT_ID_RTSP_STATUS_CODE   = NT_SP_E_EVENT_ID_BASE | 0xB,  /*rtsp status code上报, 目前只上报401, param1表示status code*//* 接下来请从0x81开始*/NT_SP_E_EVENT_ID_START_BUFFERING = NT_SP_E_EVENT_ID_BASE | 0x81, /*开始缓冲*/NT_SP_E_EVENT_ID_BUFFERING     = NT_SP_E_EVENT_ID_BASE | 0x82, /*缓冲中, param1 表示百分比进度*/NT_SP_E_EVENT_ID_STOP_BUFFERING  = NT_SP_E_EVENT_ID_BASE | 0x83, /*停止缓冲*/NT_SP_E_EVENT_ID_DOWNLOAD_SPEED  = NT_SP_E_EVENT_ID_BASE | 0x91, /*下载速度, param1表示下载速度,单位是(Byte/s)*/NT_SP_E_EVENT_ID_PLAYBACK_REACH_EOS = NT_SP_E_EVENT_ID_BASE | 0xa1,     /*播放结束, 直播流没有这个事件,点播流才有*/NT_SP_E_EVENT_ID_RECORDER_REACH_EOS = NT_SP_E_EVENT_ID_BASE | 0xa2,     /*录像结束, 直播流没有这个事件, 点播流才有*/NT_SP_E_EVENT_ID_PULLSTREAM_REACH_EOS = NT_SP_E_EVENT_ID_BASE | 0xa3,   /*拉流结束, 直播流没有这个事件,点播流才有*/NT_SP_E_EVENT_ID_DURATION = NT_SP_E_EVENT_ID_BASE | 0xa8, /*视频时长,如果是直播,则不上报,如果是点播的话, 若能从视频源获取视频时长的话,则上报, param1表示视频时长,单位是毫秒(ms)*/
}

设置拉流的URL

NT_SP_SetURL:支持rtsp/rtmp/本地FLV文件(全路径)。

设置录像规则

  1. NT_SP_SetRecorderDirectory:设置录像目录
  2. NT_SP_SetRecorderFileMaxSize:设置单个文件最大大小
  3. NT_SP_SetRecorderFileNameRuler:设置录像文件名生成规则
  4. NT_SP_SetRecorderCallBack:设置录像回调接口
  5. NT_SP_SetRecorderAudioTranscodeAAC:设置录像时音频转AAC编码的开关, aac比较通用,sdk增加其他音频编码(比如speex, pcmu, pcma等)转aac的功能
  6. NT_SP_SetRecorderVideo:设置是否录视频,默认的话,如果视频源有视频就录,没有就没得录, 但有些场景下可能不想录制视频,只想录音频,所以增加个开关
  7. NT_SP_SetRecorderAudio:设置是否录音频,默认的话,如果视频源有音频就录,没有就没得录, 但有些场景下可能不想录制音频,只想录视频,所以增加个开关

实现录像逻辑

  1. NT_SP_StartRecorder:启动录像
  2. NT_SP_StopRecorder:停止录像

代码调用示例:

/** SmartPlayerForm.cs* Author: daniusdk.com* WeChat: xinsheng120*/
private void btn_record_Click(object sender, EventArgs e)
{if (player_handle_ == IntPtr.Zero)return;if (btn_record.Text == "录像"){if (!is_rec_video_ && !is_rec_audio_){MessageBox.Show("音频录制选项和视频录制选项至少需要选择一个!");return;}if (!is_playing_){if (!InitCommonSDKParam()){MessageBox.Show("设置参数错误!");return;}}NTSmartPlayerSDK.NT_SP_SetRecorderVideo(player_handle_, is_rec_video_ ? 1 : 0);NTSmartPlayerSDK.NT_SP_SetRecorderAudio(player_handle_, is_rec_audio_ ? 1 : 0);UInt32 ret = NTSmartPlayerSDK.NT_SP_SetRecorderDirectoryW(player_handle_, rec_dir_);if (NT.NTBaseCodeDefine.NT_ERC_OK != ret){MessageBox.Show("设置录像目录失败");return;}NTSmartPlayerSDK.NT_SP_SetRecorderFileMaxSize(player_handle_, max_file_size_);NT_SP_RecorderFileNameRuler rec_name_ruler = new NT_SP_RecorderFileNameRuler();rec_name_ruler.type_ = 0;rec_name_ruler.file_name_prefix_ = rec_name_file_prefix_;rec_name_ruler.append_date_ = is_append_date_ ? 1 : 0;rec_name_ruler.append_time_ = is_append_time_ ? 1 : 0;NTSmartPlayerSDK.NT_SP_SetRecorderFileNameRuler(player_handle_, ref rec_name_ruler);record_call_back_ = new SP_SDKRecorderCallBack(SDKRecorderCallBack);NTSmartPlayerSDK.NT_SP_SetRecorderCallBack(player_handle_, IntPtr.Zero, record_call_back_);NTSmartPlayerSDK.NT_SP_SetRecorderAudioTranscodeAAC(player_handle_, is_audio_transcode_aac_ ? 1 : 0);if (NT.NTBaseCodeDefine.NT_ERC_OK != NTSmartPlayerSDK.NT_SP_StartRecorder(player_handle_)){MessageBox.Show("录像失败!");return;}btn_record.Text = "停止录像";is_recording_ = true;}else{StopRecorder();}
}

录像事件回调

/** 录像回调* status: 1:表示开始写一个新录像文件. 2:表示已经写好一个录像文件* file_name: 实际录像文件名*/
[UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]public delegate void SP_SDKRecorderCallBack(IntPtr handle, IntPtr user_data, UInt32 status, [MarshalAs(UnmanagedType.LPStr)] String file_name);

调用示例:

private void RecordCallBack(UInt32 status, [MarshalAs(UnmanagedType.LPStr)] String file_name)
{byte[] utf8_bytes = Encoding.Default.GetBytes(file_name);byte[] default_bytes = Encoding.Convert(Encoding.UTF8, Encoding.Default, utf8_bytes);String recorder_file_name = Encoding.Default.GetString(default_bytes);StringBuilder sb = new StringBuilder();sb.Append("录像状态:");if (status == 1){sb.Append("new file: ");}else if(status == 2){sb.Append("finished file: ");}sb.Append(recorder_file_name);MessageBox.Show(sb.ToString());
}

销毁播放实例

NT_SP_Close

调用Close接口后,player handler置空。

if ( player_handle_ != IntPtr.Zero)
{NTSmartPlayerSDK.NT_SP_Close(player_handle_);player_handle_ = IntPtr.Zero;
}

释放资源

NT_SP_UnInit

UnInit() 是SDK最后一个调用的接口,多实例环境下,只需要调用一次即可。


http://www.ppmy.cn/ops/119741.html

相关文章

UniApp基于xe-upload实现文件上传组件

xe-upload地址:文件选择、文件上传组件(图片,视频,文件等) - DCloud 插件市场 致敬开发者!!! 感觉好用的话,给xe-upload的作者一个好评 背景:开发中经常会有…

数学建模研赛总结

目录 前言进度问题四分析问题五分析数模论文经验分享总结 前言 本文为博主数学建模比赛第五天的内容记录,希望所写的一些内容能够对大家有所帮助,不足之处欢迎大家批评指正🤝🤝🤝 进度 今天已经是最后一天了&#xf…

react是一种语言?

React 不是一种编程语言,而是一种用于构建用户界面的 JavaScript 库。它由 Facebook 开发,并广泛用于开发单页应用程序(SPA)。React 允许你将 UI 拆分成独立的、可复用的组件,这些组件可以接收输入(称为“p…

DBeaver显示PostgreSQL数据库的信息模式

DBeaver连接PostgreSQL数据库后,默认情况下是不加载信息模式的,如果有需要,我们可以通过设置显示信息模式。 具体步骤:点击数据库连接–>右键打开设置–>连接设置–>常规–>导航视图–>自定义–>勾选显示系统对…

【信创,国产化】信息化系统信创改造,国产化改造方案,云建设

信创,即“信息技术应用创新”。我国自主信息产业聚焦信息技术应用创新,旨在通过对IT硬件、软件等各个环节的重构,基于我国自有IT底层架构和标准,形成自有开放生态,从根本上解决本质安全问题,实现信息技术可…

WITS核心价值观【创新】篇|系统进化论 解锁新纪元

「客尊」、「诚信」、「创新」 与「卓越」 是纬创软件的核心价值观。我们秉持诚信态度,致力于成为客户长期且值得信赖的合作伙伴。持续提升服务厚度,透过数字创新实践多市场的跨境交付,助客户保持市场领先地位。以追求卓越的不懈精神&#xf…

OpenCV视频I/O(3)视频采集类VideoCapture之获取当前使用的视频捕获 API 后端的名称函数getBackendName()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 getBackendName 函数是 OpenCV 中 VideoCapture 类的一个方法,用于获取当前使用的视频捕获 API 后端的名称。这可以帮助开发者了解当…

避免学术欺诈!在ChatGPT帮助下实现严格引用并避免抄袭

学境思源,一键生成论文初稿: AcademicIdeas - 学境思源AI论文写作 当今的学术环境中,保持学术诚信至关重要。随着ChatGPT等技术的发展,写作变得更加高效,但也增加了不当使用的风险。严格的引用和避免抄袭不仅是学术道…