Windows平台RTMP、RTSP播放器录像模块精细化控制

article/2025/11/6 19:15:03

技术背景

上篇文章,我们介绍了Unity平台RTMP、RTSP播放器录像功能,这里,我们详细的介绍下,做个RTSP或RTMP拉流端录像模块有哪些需要考虑的技术点?

在我们常规的考量,RTMP或RTSP流录制,无非就是拉取数据写文件而已,接口设计StartRecorder()/StopRecorder()足矣。

是的,一般场景下,两个接口足够了,但如果是做个更加通用的模块,以下几点是可以酌情考虑的:

  • 支持设置单个录像文件大小,比如单个录像文件最大设置到200M,到了200M,可自动切分到下个录像文件;
  • 支持设置录像路径;
  • 支持设置录像文件前缀:录像文件前缀,是为了更友好的做特定文件的分类;
  • 支持文件名增加日期;
  • 支持文件名增加时间;
  • 支持设置纯音频、纯视频、音视频录制模式;
  • 支持音频(PCMU/PCMA,Speex等)转AAC后再录像;
  • 支持录像事件回调,从开始录像,到录像结束均有event callback上来。

除了上述的设计,还需要确保和RTSP、RTMP播放在一个实例下,确保播放的过程中可以随时录像,录像的过程中,可以随时播放。

录像模块设计

无图无真相,先看录像设置:

开始录像、停止录像:

Windows平台,我们提供了C++和C#的接口,本文以C++接口设计为例:

先说录像设置:

设置录制纯音频或纯视频:

       /** 设置是否录视频,默认的话,如果视频源有视频就录,没有就没得录, 但有些场景下可能不想录制视频,只想录音频,所以增加个开关* is_record_video: 1 表示录制视频, 0 表示不录制视频, 默认是1*/NT_UINT32(NT_API *SetRecorderVideo)(NT_HANDLE handle, NT_INT32 is_record_video);/** 设置是否录音频,默认的话,如果视频源有音频就录,没有就没得录, 但有些场景下可能不想录制音频,只想录视频,所以增加个开关* is_record_audio: 1 表示录制音频, 0 表示不录制音频, 默认是1*/NT_UINT32(NT_API *SetRecorderAudio)(NT_HANDLE handle, NT_INT32 is_record_audio);

设置录像目录:

		/*设置本地录像目录, 必须是英文目录,否则会失败*/NT_UINT32(NT_API *SetRecorderDirectory)(NT_HANDLE handle, NT_PCSTR dir);

设置单个录像文件最大大小:

		/*设置单个录像文件最大大小, 当超过这个值的时候,将切割成第二个文件size: 单位是KB(1024Byte), 当前范围是 [5MB-800MB], 超出将被设置到范围内*/NT_UINT32(NT_API *SetRecorderFileMaxSize)(NT_HANDLE handle, NT_UINT32 size);

设置录像文件名生成规则:

		/*设置录像文件名生成规则*/NT_UINT32(NT_API *SetRecorderFileNameRuler)(NT_HANDLE handle, NT_SP_RecorderFileNameRuler* ruler);

对应的NT_SP_RecorderFileNameRuler设计:

// 如果三项都是0的话,将不能启动录像
typedef struct _NT_SP_RecorderFileNameRuler
{NT_UINT32	type_; // 这个值目前默认是0,将来扩展用NT_PCSTR	file_name_prefix_; // 设置一个录像文件名前缀, 例如:daniuliveNT_INT32	append_date_; // 如果是1的话,将在文件名上加日期, 例如:daniulive-2017-01-17NT_INT32	append_time_; //  如果是1的话,将增加时间,例如:daniulive-2017-01-17-17-10-36
} NT_SP_RecorderFileNameRuler;

设置录像回调接口:

		/*设置录像回调接口*/NT_UINT32(NT_API *SetRecorderCallBack)(NT_HANDLE handle,NT_PVOID call_back_data, SP_SDKRecorderCallBack call_back);

对应录像回调:

/*
录像回调
status: 1:表示开始写一个新录像文件. 2:表示已经写好一个录像文件
file_name: 实际录像文件名
*/
typedef NT_VOID(NT_CALLBACK* SP_SDKRecorderCallBack)(NT_HANDLE handle, NT_PVOID user_data, NT_UINT32 status,NT_PCSTR file_name);

设置音频转AAC开关:

		/*设置录像时音频转AAC编码的开关, aac比较通用,sdk增加其他音频编码(比如speex, pcmu, pcma等)转aac的功能.is_transcode: 设置为1的话,如果音频编码不是aac,则转成aac, 如果是aac,则不做转换. 设置为0的话,则不做任何转换. 默认是0.注意: 转码会增加性能消耗*/NT_UINT32(NT_API *SetRecorderAudioTranscodeAAC)(NT_HANDLE handle, NT_INT32 is_transcode);

启动录像、停止录像:

		/*启动录像*/NT_UINT32(NT_API *StartRecorder)(NT_HANDLE handle);/*停止录像*/NT_UINT32(NT_API *StopRecorder)(NT_HANDLE handle);

接口调用实例

/** Author: https://daniusdk.com*/
void CSmartPlayerDlg::OnBnClickedButtonRecord()
{if ( player_handle_ == NULL )return;CString btn_record_str;btn_record_.GetWindowTextW(btn_record_str);if ( btn_record_str == _T("录像") ){if ( !rec_conf_info_.is_record_video_ && !rec_conf_info_.is_record_audio_ ){AfxMessageBox(_T("音频录制选项和视频录制选项至少需要选择一个!"));return;}if ( !is_playing_ ){if ( !InitCommonSDKParam() ){AfxMessageBox(_T("设置参数错误!"));return;}}player_api_.SetRecorderVideo(player_handle_, rec_conf_info_.is_record_video_ ? 1 : 0);player_api_.SetRecorderAudio(player_handle_, rec_conf_info_.is_record_audio_ ? 1 : 0);auto ret = player_api_.SetRecorderDirectory(player_handle_, rec_conf_info_.dir_.c_str());if ( NT_ERC_OK != ret ){AfxMessageBox(_T("设置录像目录失败,请确保目录存在且是英文目录"));return;}player_api_.SetRecorderFileMaxSize(player_handle_, rec_conf_info_.file_max_size_);NT_SP_RecorderFileNameRuler rec_name_ruler = { 0 };rec_name_ruler.type_ = 0;rec_name_ruler.file_name_prefix_ = rec_conf_info_.file_name_prefix_.c_str();rec_name_ruler.append_date_		 = rec_conf_info_.is_append_date_ ? 1 : 0;rec_name_ruler.append_time_		 = rec_conf_info_.is_append_time_ ? 1 : 0;player_api_.SetRecorderFileNameRuler(player_handle_, &rec_name_ruler);player_api_.SetRecorderCallBack(player_handle_, GetSafeHwnd(), &SP_SDKRecorderHandle);player_api_.SetRecorderAudioTranscodeAAC(player_handle_, rec_conf_info_.is_audio_transcode_aac_ ? 1 : 0);if ( NT_ERC_OK != player_api_.StartRecorder(player_handle_) ){AfxMessageBox(_T("录像失败!"));return;}btn_record_.SetWindowTextW(_T("停止录像"));is_recording_ = true;}else{StopRecorder();}
}

停止录像:

void CSmartPlayerDlg::StopRecorder()
{if (player_handle_ == NULL)return;player_api_.StopRecorder(player_handle_);btn_record_.SetWindowTextW(_T("录像"));is_recording_ = false;if (!is_playing_){SetWindowText(base_title_);edit_duration_.SetWindowText(_T(""));btn_pause_.SetWindowText(_T("暂停"));}RefreshLogo(true);
}

总结

一个小小的录像功能,如果做的更加通用兼容性好的话,需要注意的点还很多,本文抛砖引玉,感兴趣的开发者可酌情参考。


http://chatgpt.dhexx.cn/article/D9CHNMV8.shtml

相关文章

RTMP视频播放器

感谢作者tcking、Bilibili,本项目借鉴了GiraffePlayer项目,项目一开始的灵感来源于GiraffePlayer项目,后期做纯粹做了视频播放器的界面的定制,基于ijkplayer项目进行的播放器界面UI封装。 简介 当前项目是基于ijkplayer项目进行…

从零开发一款Android RTMP播放器

1. 背景介绍 15年移动端直播应用火起来的时候,主要的直播协议是RTMP,多媒体服务以Adobe的AMS、wowza、Red5、crtmpserver、nginx rtmp module等,后面过长RTMP服务SRS开始流行。Android端播放器主要以开始以EXOPlayer播放HLS,但是…

rtsp+rtmp多路网页播放

一、前言 之前博主有写过 一篇博文,讲的是使用videojs在谷歌浏览器网页上播放rtmp流媒体,具体可参考我之前的博客:videojshlsrtmp网页播放 - 蛋片鸡 - 博客园 最近又开始研究了一下网页播放流媒体,在这里我主要补充一些播放rtmp、…

低延时极简RTMP播放器

RtmpPlaySdk简介 近期将项目上RTMP播放相关功能进行打包整理,实现了一款低延时的极简接口RTMP播放器(Windows版和Android版)。市面上的RTMP播放器较多,有开源的ijkplayer及其衍生品,也有收费的功能繁多的播放器&#…

rtmp 点播系统之播放器篇

rtmp (Real Time Media Protocal) ,是实时流媒体协议,由Adobe公司提出,属于半开放的协议。此协议基于flash平台的音视频点播协议。 音视的点播系统分为两部分,分别为客户端和服务端。在本文中我会先讲解如何实现一个简单的rtmp播放器。至于rtmp服务器的实现,会在下文中分析…

pgsql 使用技巧

1.CASCADE 级联删除,如果表或模式或数据库有序列、分区相关 依赖时,需要修改表或模式或数据库,则使用它 DROP SCHEMA viid_facestatic CASCADE 2.pgsql隐藏字段ctid,一般用于去重 3. pg 表自连接使用场景 3.1 有一张卡口表 求…

pgsql

这里写目录标题 pgpool安装pgsql流复制备份与恢复客户端验证服务器设置及操作服务器配置监控数据活动 PostgreSQL是以加州大学伯克利分校计算机系开发的 POSTGRES, Version 4.2为基础的对象关系型数据库管理系统(ORDBMS)。 PostgreSQL是最初伯克利代码的一个开放源码的继承者。…

pgsql基本操作

pgsql基本操作 1. 修改postgresql.conf postgresql.conf存放位置在/etc/postgresql/9.x/main下,这里的x取决于你安装PostgreSQL的版本号,编辑或添加下面一行,使PostgreSQL可以接受来自任意IP的连接请求。 listen_addresses *2. 修改pg_hb…

pgsql常用sql和函数

常用pgsql -- 列出所有schema select * from information_schema.schemata; -- Schema下所有表 select * from pg_tables where schemaname query_db and tablename in(port,device,res_carry_business,hardware,shelf,device_hardware_relation); -- Schema下所有索引 select…

PGSQL大小写敏感总结

PGSQL大小写敏感总结 由于PGSQL使用会出现大小写敏感的问题,所以在设置字段名字的时候,如果字段名需要大写需要加上""号来表示,该字段需要大写 公司业务需要我使用PGSQL创建自增主键,我在使用 nextval() 绑定创建的序列…

PGSQL常用操作

0. 启动pgsl数据库 pg_ctl -D /xx/pgdata start 回到顶部 1. 查看pgsl版本 pg_ctl --version 回到顶部 1. 命令行登录数据库 1 psql -U username -d dbname -h hostip -p port 回到顶部 2. 列出所有数据库 \l 回到顶部 3. 切换数据库 1 \c dbname 回到顶部 …

PL/pgSQL

1.简介 L/pgSQL是一种用于PostgreSQL数据库系统的可载入的过程语言。 可以被用来创建函数和触发器过程对SQL语言增加控制结构可以执行复杂计算继承所有用户定义类型、函数和操作符可以被定义为受服务器信任便于使用 [1]使用PL/pgSQL的优点 SQL 是一种查询语言,可…

Windows 10 安装配置连接PostgreSQL教程

Windows 10 安装配置连接PostgreSQL教程 1.1 PostgreSQL 下载1.2 配置环境变量1.3 PostgreSQL 初始化1.4 创建postgres用户1.5 启动postgresql1.6 客户端连接测试1.6.1 SQL Shell (psql)命令行连接测试1.6.2 客户端 pdAdmin 4 连接测试1.6.3 客户端Navicat Permium 连接测试 1.…

Spring原理-IOC控制反转

spring相关文章 Spring原理-IOC控制反转 Spring框架七大核心模块 Spring Beans原理–bean生命周期 一、Spring概述 1、 定义 Spring是一个轻量级Java开发框架,最早有Rod Johnson创建,目的是为了解决企业级应用开发复杂性。它是一个分层的JavaSE/Java…

依赖倒置和控制反转

依赖倒置 定义 依赖反转原则(Dependency inversion principle,DIP)是指一种特定的解耦形式,使得高层次的类不依赖于低层次的类的实现细节,依赖关系被颠倒(反转),从而使得低层次类依…

Inversion of Control (IOC)控制反转 有什么好处

要了解控制反转( Inversion of Control ), 我觉得有必要先了解软件设计的一个重要思想:依赖倒置原则(Dependency Inversion Principle )。 什么是依赖倒置原则?假设我们设计一辆汽车:先设计轮子,然后根据…

Spring学习:IOC控制反转

一、Spring概述: Spring是一个开源框架,其存在的根本使命就是简化JAVA开发。为了降低JAVA开发的复杂性,Spring采取了以下四种关键策略: 基于POJO的最轻量级和最小侵入性编程;通过依赖注入和面向接口实现松耦合&#x…

控制反转(IOC)简介

IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”,还有些书籍翻译成为“控制反向”或者“控制倒置”。 1996年,Michael Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IOC 这个概念。对于面向对象设计及编程…

IoC 控制反转理解

控制反转——Inversion of Control,缩写为IoC ,是一个重要的面向对象编程的法则,说到底它是一种设计思想,其可以降低程序中的耦合度,在以前,我们通过new进行创建对象,这是程序主动去创建依赖对象…

IOC控制反转理解

1. IOC基础 IOC:全称Inversion Of Control,中文翻译是控制反转的意思。初学Spring绕不过去的一个弯,需要好好理解IOC的思想。网上看了很多博客,也看了很多网课,但是还是云里云雾。终于看到一个容易理解的例子&#xf…