火山RTC 7 获得远端裸数据
一、获得远端裸数据
1、获得h264数据
1)、远端编码后视频数据监测器
/*** @locale zh* @type callback* @region 视频管理* @brief 远端编码后视频数据监测器<br>* 注意:回调函数是在 SDK 内部线程(非 UI 线程)同步抛出来的,请不要做耗时操作或直接操作 UI,否则可能导致 app 崩溃。*/
/*** @locale en* @type callback* @region video management* @brief Remote encoded video data monitor<br>* Note: Callback functions are thrown synchronously in a non-UI thread within the SDK. Therefore, you must not perform any time-consuming operations or direct UI operations within the callback function, as this may cause the app to crash.*/
class IRemoteEncodedVideoFrameObserver {
public:/*** @locale zh* @hidden constructor/destructor* @brief 析构函数*//*** @locale en* @hidden constructor/destructor* @brief Destructor*/virtual ~IRemoteEncodedVideoFrameObserver() {}/*** @locale zh* @type callback* @region 视频数据回调* @brief 调用 registerRemoteEncodedVideoFrameObserver{@link #IRTCVideo#registerRemoteEncodedVideoFrameObserver} 后,SDK 监测到远端编码后视频数据时,触发该回调* @param stream_info 收到的远端流信息,参看 RemoteStreamKey{@link #RemoteStreamKey}* @param video_stream 收到的远端视频帧信息,参看 IEncodedVideoFrame{@link #IEncodedVideoFrame}*//*** @locale en* @type callback* @region video data callback* @brief Call registerRemoteEncodedVideoFrameObserver{@link #IRTCVideo#registerRemoteEncodedVideoFrameObserver}, the callback is triggered when the SDK detects the remote encoded video data* @param stream_info The received remote stream information. See RemoteStreamKey{@link #RemoteStreamKey}* @param video_stream The received remote video frame information. See IEncodedVideoFrame{@link #IEncodedVideoFrame}*/virtual void onRemoteEncodedVideoFrame(const RemoteStreamKey& stream_info, const IEncodedVideoFrame& video_stream) = 0;
};
2)、IRemoteEncodedVideoFrameObserver 派生
class ByteRTCEventHandler : public QObject,public bytertc::IRTCVideoEventHandler,public bytertc::IAudioEffectPlayerEventHandler,public bytertc::IMixedStreamObserver,public bytertc::IMediaPlayerEventHandler,public bytertc::IRemoteEncodedVideoFrameObserver,public bytertc::IVideoSink
virtual void onRemoteEncodedVideoFrame(const bytertc::RemoteStreamKey& stream_info, const bytertc::IEncodedVideoFrame& video_stream) override;
void ByteRTCEventHandler::onRemoteEncodedVideoFrame(const bytertc::RemoteStreamKey& stream_info, const bytertc::IEncodedVideoFrame& video_stream) {}
std::unique_ptr<ByteRTCEventHandler> m_handler;
3)、registerRemoteEncodedVideoFrameObserver
/*** @locale zh* @type api* @region 视频管理* @brief 注册远端编码后视频数据回调。 <br>* 完成注册后,当 SDK 监测到远端编码后视频帧时,会触发 onRemoteEncodedVideoFrame{@link #IRemoteEncodedVideoFrameObserver#onRemoteEncodedVideoFrame} 回调* @param observer 远端编码后视频数据监测器,参看 IRemoteEncodedVideoFrameObserver{@link #IRemoteEncodedVideoFrameObserver}* @return * + 0: 调用成功。<br>* + < 0 : 调用失败。查看 ReturnStatus{@link #ReturnStatus} 获得更多错误说明* @note * + 更多自定义解码功能说明参看 [自定义视频编解码](https://www.volcengine.com/docs/6348/82921#%E8%87%AA%E5%AE%9A%E4%B9%89%E8%A7%86%E9%A2%91%E8%A7%A3%E7%A0%81)。<br>* + 该方法适用于手动订阅,并且进房前后均可调用,建议在进房前调用。 <br>* + 引擎销毁前需取消注册,调用该方法将参数设置为 nullptr 即可。*//*** @locale en* @type api* @region video management* @brief Video data callback after registering remote encoding. <br>* After registration, when the SDK detects a remote encoded video frame, it will trigger the onRemoteEncodedVideoFrame{@link #IRemoteEncodedVideoFrameObserver#onRemoteEncodedVideoFrame} callback* @param observer Remote encoded video data monitor. See IRemoteEncodedVideoFrameObserver{@link #IRemoteEncodedVideoFrameObserver}* @return * + 0: Success.<br>* + < 0 : Fail. See ReturnStatus{@link #ReturnStatus} for more details* @note * + See [Custom Video Encoding and Decoding](https://docs.byteplus.com/byteplus-rtc/docs/82921#custom-video-decoding) for more details about custom video decoding. <br>* + This method applys to manual subscription mode and can be called either before or after entering the Room. It is recommended to call it before entering the room. <br>* + The engine needs to be unregistered before it is destroyed. Call this method to set the parameter to nullptr.*/virtual int registerRemoteEncodedVideoFrameObserver(IRemoteEncodedVideoFrameObserver* observer) = 0;
m_video->registerRemoteEncodedVideoFrameObserver(m_handler.get());
2、自定义视频渲染器
0)、IVideoSink
/*** @locale zh* @type keytype* @brief 自定义视频渲染器*/
/*** @locale en* @type keytype* @brief Custom video renderer*/
class IVideoSink {
public:/*** @locale zh* @type keytype* @brief 视频帧编码格式*//*** @locale en* @type keytype* @brief Video frame encoding format*/enum PixelFormat {/*** @locale zh* @brief YUV I420 格式*//*** @locale en* @brief YUV I420 format*/kI420 = VideoPixelFormat::kVideoPixelFormatI420,/*** @locale zh* @brief RGBA 格式, 字节序为 R8 G8 B8 A8*//*** @locale en* @brief RGBA format*/kRGBA = VideoPixelFormat::kVideoPixelFormatRGBA,/*** @locale zh* @brief 原始视频帧格式*//*** @locale en* @brief Original format*/kOriginal = VideoPixelFormat::kVideoPixelFormatUnknown,};/*** @locale zh* @type callback* @brief 视频帧回调* @param [out] video_frame 视频帧结构类,参看 IVideoFrame{@link #IVideoFrame}* @return 返回值暂未使用*//*** @locale en* @type callback* @brief Video frame callback* @param [out] video_frame Video frame structure. See IVideoFrame{@link #IVideoFrame}.* @return Temporarily unavailable*/virtual bool onFrame(IVideoFrame* video_frame) = 0;/*** @locale zh* @type callback* @region 房间管理* @brief 获取外部渲染耗时。* @note 获取外部渲染耗时进行上报。开发者需要自己计算平均渲染耗时。*//*** @locale en* @type callback* @region Room Management* @brief Gets the time taken in custom rendering.* @note Gets the time taken in custom rendering and report. You need to calculate the average rendering time by yourself.*/virtual int getRenderElapse() = 0;/*** @locale zh* @type callback* @brief 释放渲染器。* @note 通知开发者渲染器即将被废弃。收到该返回通知后即可释放资源。*//*** @locale en* @type callback* @brief Releases the renderer.* @note Used to notify the user that the renderer is about to be deprecated. Resources can be released upon receipt of this notification.*/virtual void release() {}/*** @locale zh* @hidden constructor/destructor* @brief 析构函数*//*** @locale en* @hidden constructor/destructor* @brief Destructor*/virtual ~IVideoSink() = default;/*** @locale zh* @hidden sink id* @brief sink id*//*** @locale en* @hidden sink id* @brief sink id*/virtual void* uniqueId() const { return (void *)this; }
};
1)、setRemoteVideoSink
/*** @locale zh* @type api* @deprecated since 3.57, use setRemoteVideoRender{@link #IRTCVideo#setRemoteVideoRender} instead.* @region 自定义视频采集渲染* @brief 将远端视频流与自定义渲染器绑定。* @param stream_key 远端流信息,用于指定需要渲染的视频流来源及属性,参看 RemoteStreamKey{@link #RemoteStreamKey}。* @param video_sink 自定义视频渲染器,参看 IVideoSink{@link #IVideoSink}。* @param required_format video_sink 适用的视频帧编码格式,参看 PixelFormat{@link #PixelFormat}。* @return * + 0: 调用成功。<br>* + < 0 : 调用失败。查看 ReturnStatus{@link #ReturnStatus} 获得更多错误说明* @note * + RTC SDK 默认使用 RTC SDK 自带的渲染器(内部渲染器)进行视频渲染。<br>* + 该方法进房前后均可以调用。若想在进房前调用,你需要在加入房间前获取远端流信息;若无法预先获取远端流信息,你可以在加入房间并通过 onUserPublishStream{@link #IRTCRoomEventHandler#onUserPublishStream} 回调获取到远端流信息之后,再调用该方法。<br>* + 如果需要解除绑定,必须将 video_sink 设置为 null。退房时将清除绑定状态。<br>* + 本方法获取的是后处理后的视频帧,如需获取其他位置的视频帧(如解码后的视频帧),请调用 setRemoteVideoRender{@link #IRTCVideo#setRemoteVideoRender}。*//*** @locale en* @type api* @region Custom Video Capturing & Rendering* @brief Binds the remote video stream to a custom renderer.* @param stream_key Remote stream information which specifys the source and type of the video stream to be rendered. See RemoteStreamKey{@link #RemoteStreamKey}.* @param video_sink Custom video renderer. See IVideoSink{@link #IVideoSink}.* @param required_format Encoding format which applys to the custom renderer. See PixelFormat{@link #PixelFormat}.* @return * + 0: Success.<br>* + < 0 : Fail. See ReturnStatus{@link #ReturnStatus} for more details* @note * + RTC SDK uses its own renderer (internal renderer) for video rendering by default. <br>* + Joining or leaving the room will not affect the binding state. <br>* + This API can be called before and after entering the room. To call before entering the room, you need to get the remote stream information before joining the room; if you cannot get the remote stream information in advance, you can call the API after joining the room and getting the remote stream information via onUserPublishStream{@link #IRTCRoomEventHandler#onUserPublishStream}.<br>* + If you need to unbind, you must set videoSink to null.*/virtual int setRemoteVideoSink(RemoteStreamKey stream_key, IVideoSink* video_sink, IVideoSink::PixelFormat required_format) = 0;
2)、远端用户发布流时,设置渲染方式
注意:设置registerRemoteEncodedVideoFrameObserver 后,setRemoteVideoSink 不再起作用了
//远端用户发流
void QuickStartWidget::onSigUserPublishStream(std::string roomid, std::string uid, bytertc::MediaStreamType type)
{QString log_str = QString("onUserPublishStream,roomid:")+ QString::fromStdString(roomid)+ ",uid:" + QString::fromStdString(uid)+ ",type:" + QString::number(type);appendCallback(log_str);if (!m_remote_rendered) {if (0) {bytertc::VideoCanvas cas;bytertc::RemoteStreamKey key;key.room_id = roomid.c_str();key.user_id = uid.c_str();key.stream_index = bytertc::kStreamIndexMain;cas.background_color = 0;cas.render_mode = bytertc::kRenderModeHidden;cas.view = nullptr;m_video->setRemoteVideoCanvas(key, cas);cas.view = (void*)ui->widget_remote->getWinId();m_video->setRemoteVideoCanvas(key, cas);ui->widget_remote->setUserInfo(roomid, uid);m_remote_rendered = true;}else {bytertc::RemoteStreamKey key;key.room_id = roomid.c_str();key.user_id = uid.c_str();key.stream_index = bytertc::kStreamIndexMain;// m_video->setRemoteVideoSink(key, m_handler.get(), bytertc::IVideoSink::PixelFormat::kRGBA);m_video->setRemoteVideoSink(key, m_handler.get(), bytertc::IVideoSink::PixelFormat::kRGBA);m_remote_rendered = true;}}
}
3)、获得远端裸数据
bool ByteRTCEventHandler::onFrame(bytertc::IVideoFrame* video_frame) {bytertc::VideoFrameType type= video_frame->frameType();bytertc::VideoPixelFormat format=video_frame->pixelFormat();bytertc::VideoContentType contentType= video_frame->videoContentType();int width = video_frame->width();int height= video_frame->height();bytertc::VideoRotation rotation = video_frame->rotation();bytertc::ColorSpace space = video_frame->colorSpace();int numPlans = video_frame->numberOfPlanes();uint8_t* data = video_frame->getPlaneData(numPlans-1);SaveRGBAToPNG(data, width, height, "output.png");return true;
}
测试
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"void SaveRGBAToPNG(uint8_t* rgbaData, int width, int height, const std::string& filePath) {// 第4个参数是每像素通道数,这里RGBA是4// 每行像素的跨度是 width * 4 字节stbi_write_png(filePath.c_str(), width, height, 4, rgbaData, width * 4);
}
相关文章:
火山RTC 7 获得远端裸数据
一、获得远端裸数据 1、获得h264数据 1)、远端编码后视频数据监测器 /*** locale zh* type callback* region 视频管理* brief 远端编码后视频数据监测器<br>* 注意:回调函数是在 SDK 内部线程(非 UI 线程)同步抛出来的&a…...

通过SMTP协议实现Linux邮件发送配置指南
一、环境准备与基础配置 1. SMTP服务开通(以qq邮箱为例) 登录qq邮箱网页端,进入「设置」-「POP3/SMTP/IMAP」 开启「SMTP服务」并获取16位授权码(替代邮箱密码使用) 记录关键参数: SMTP服务器地址&#…...

若依框架页面
1.页面地址 若依管理系统 2.账号和密码 管理员 账号admin 密码admin123 运维 账号yuwei 密码123456 自己搭建的地址方便大家学习,不要攻击哦,谢谢啊...

44、私有程序集与共享程序集有什么区别?
私有程序集(Private Assembly)与共享程序集(Shared Assembly)是.NET框架中程序集部署的两种不同方式,它们在部署位置、版本控制、访问权限等方面存在显著差异,以下是对二者的详细比较: 1. 部署…...

【Java面试题】——this 和 super 的区别
🎁个人主页:User_芊芊君子 🎉欢迎大家点赞👍评论📝收藏⭐文章 🔍系列专栏:【Java】内容概括 【前言】 在Java的世界里,this和 super是两个非常重要且容易混淆的关键字。无论是在日常…...
记录 QT 在liunx 下 QFileDialog 类调用问题 ()Linux下QFileDialog没反应)
1. 2025.05.14 踩坑记录 因为QT 在 liunx 文件系统不同导致的 Windows : QString filePath QFileDialog::getOpenFileName(nullptr, "选择文件", ".", "文本文件 (*.txt);所有文件 (*.*)"); 没问题 liunx 下 打不开ÿ…...

CentOS 7 内核升级指南:解决兼容性问题并提升性能
点击上方“程序猿技术大咖”,关注并选择“设为星标” 回复“加群”获取入群讨论资格! CentOS 7 默认搭载的 3.10.x 版本内核虽然稳定,但随着硬件和软件技术的快速发展,可能面临以下问题: 硬件兼容性不足:新…...
【前端】:单 HTML 去除 Word 批注
在现代办公中,.docx 文件常用于文档编辑,但其中的批注(注释)有时需要在分享或归档前被去除。本文将从原理出发,深入剖析如何在纯前端环境下实现对 .docx 文件注释的移除,并提供完整的实现源码。最后&#x…...

解决 PicGo 上传 GitHub图床及Marp中Github图片编译常见难题指南
[目录] 0.行文概述 1.PicGo图片上传失败 2.*关于在Vscode中Marp图片的编译问题* 3.总结与启示行文概述 写作本文的动机是本人看到了Awesome Marp,发现使用 Markdown \texttt{Markdown} Markdown做PPT若加持一些 CSS , JavaScript \texttt{CSS},\texttt{JavaScript} …...

软考 系统架构设计师系列知识点之杂项集萃(59)
接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(58) 第96题 假设关系模式R(U, F),属性集U{A, B, C},函数依赖集F{A->B, B->C}。若将其分解为p{R1(U1, F1), R2(U2, F2),其中U1{A, B}, U2{A, …...

python使用matplotlib画图
【README】 plot画图有两种方法:包括 plt.plot(), ax.plot()-画多个子图 ,其中ax表示某个坐标轴; 【1】画单个图 import matplotlib # 避免兼容性问题:明确指定 matplotlib 使用兼容的后端,TkAgg 或 Agg matplotlib.use(TkAgg) …...
鸿蒙OSUniApp 开发实时聊天页面的最佳实践与实现#三方框架 #Uniapp
使用 UniApp 开发实时聊天页面的最佳实践与实现 在移动应用开发领域,实时聊天功能已经成为许多应用不可或缺的组成部分。本文将深入探讨如何使用 UniApp 框架开发一个功能完善的实时聊天页面,从布局设计到核心逻辑实现,带领大家一步步打造专…...

upload-labs通关笔记-第5关 文件上传之.ini绕过
目录 一、ini文件绕过原理 二、源码审计 三、渗透实战 1、查看提示 2、制作.user.ini文件 (1)首先创建一个文本文件 (2)保存文件名为.user.ini 2、制作jpg后缀脚本 (1)创建一个文本文件 …...

ssti模板注入学习
ssti模板注入原理 ssti模板注入是一种基于服务器的模板引擎的特性和漏洞产生的一种漏洞,通过将而已代码注入模板中实现的服务器的攻击 模板引擎 为什么要有模板引擎 在web开发中,为了使用户界面与业务数据(内容)分离而产生的&…...

填涂颜色(bfs)
归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言📝 含泪播种的人一定能含笑收获! 题目描述 由数字 0 0 0 组成的方阵中,有一任意形状的由数字 1 1 1 构成的闭合圈。现…...

ros1+docker环境快速搭建
快速使用python 解析ros1的bag消息ros这个东西可以说安装起来非常麻烦的,费时费力,很可能还安装不成功,特别是我的环境是ubuntu22.04 ,官方都不支持安装ros1。因此一个可行且快速的方法是使用别人配置好的ros的docker环境 一、下…...
vscode extention踩坑记
# npx vsce package --allow-missing-repository --no-dependencies #耗时且不稳定 npx vsce package --allow-missing-repository #用这行 code --install-extension $vsixFileName --force我问ai:为什么我的.vsix文件大了那么多 ai答:因为你没有用 --n…...

GpuGeek全栈AI开发实战:从零构建企业级大模型生产管线(附完整案例)
目录 背景一、算力困境:AI开发者的「三重诅咒」1.1 硬件成本黑洞1.2 资源调度失衡1.3 环境部署陷阱 二、三大核心技术突破GpuGeek的破局方案2.1 分时切片调度引擎(Time-Slicing Scheduler)2.2 异构计算融合架构2.3 AI资产自动化…...
【TroubleShoot】禁用Unity Render Graph API 兼容模式
使用Unity 6时新建了项目,有一个警告提示: The project currently uses the compatibility mode where the Render Graph API is disabled. Support for this mode will be removed in future Unity versions. Migrate existing ScriptableRenderPasses…...
数据库字段唯一性修复指南:从设计缺陷到规范实现
数据库字段唯一性修复指南:从设计缺陷到规范实现 一、问题背景 表结构设计缺陷: sys_user 表未对 dingtalk_user_id(钉钉用户ID)字段设置唯一性约束,导致数据重复,引发以下问题: 系统稳定性风…...

DataX从Mysql导数据到Hive分区表案例
0、下载DataX并解压到对应目录 DataX安装包,开箱即用,无需配置。 https://datax-opensource.oss-cn-hangzhou.aliyuncs.com/202308/datax.tar.gz 相关参考文档 https://github.com/alibaba/DataX/blob/master/hdfswriter/doc/hdfswriter.md 1、Hive分区…...
高性能编程相关
常见高性能编程技巧: 一,系统级性能优化:从系统架构设计考虑,例如消息队列,模块分成分级,IO读写带宽等 二,算法级性能优化:时间和空间优化 三,代码级性能优…...

vulnhub靶场——secarmy
靶机:secarmy靶机,IP地址为192.168.230.18 攻击:kali,IP地址为192.168.230.134 靶机和攻击机都采用VMware虚拟机,都采用NAT模式 端口扫描: nmap 192.168.230.18 -O -A -p- --reason -sV 21/tcp (ftp): 开…...

labview硬件采集
(1)硬件的描述 (2)实验步骤1: (3)实验步骤2 库名/路径的选择要使用32位的开发资料 (4)实验步骤3 (5)实验步骤4 找到DoSetV12() 设置返回类型 设置chan 设置state labv…...

openfeign与dubbo调用下载excel实践
一、前言 openfeign和dubbo均是rpc框架 RPC(Remote Procedure Call,远程过程调用)框架 是一种允许程序像调用本地方法一样调用远程服务器上函数的技术。它隐藏了底层网络通信的复杂性,让开发者可以专注于业务逻辑,实现…...

ISP有感自发
一、黑电平 由于传感器,即便在无光的情况下,依然会产生微小的暗电流,这些暗电流可能是噪点会影响后期的调试。因此,我们便将这些电流处理为0,成为纯黑的颜色。可以在源头消除这些误差。 如何矫正黑电平: …...

web 自动化之 PO 设计模式详解
文章目录 一、什么是 POM二、如何基于 POM 进行自动化框架架构?1、base 层封装2、pageobjects 层封装3、TestCases 层封装 三、元素和方法分离&数据分离1、哪些部分可以进行分离2、示例代码 四、总结 一、什么是 POM POM page object model 页面对象模型 WEB 自…...

NVMe简介1
它分为两部分,这里是第一部分。 NVM Express(NVMe)是一种高性能、可扩展的接口协议,用于通过PCI express(PCIe)总线,实现主机软件与NVM设备之间的通信。目前,由于NVMe SSD相比于SATA…...

【python机器学习】Day 25 异常处理
知识点: 异常处理机制debug过程中的各类报错try-except机制try-except-else-finally机制 在即将进入深度学习专题学习前,我们最后差缺补漏,把一些常见且重要的知识点给他们补上,加深对代码和流程的理解。 借助ai写代码的时候&…...

数学建模初等模型应用
一、目的 掌握初等模型的建模方法,对简单的初等模型能借助Matlab工具软件进行辅助建模、求解和检验。 二、实验内容与设计思想(设计思路、主要代码分析) 1、预测鱼的质量 (1)设计思路:使用线性回归模型预测鱼的质量…...