视频裸流传输
更新时间: 2024/09/18 16:26:13
在一些需要与硬件配合的应用场景中,比如使用教室硬件设备进行线上教学,在利用硬件自身能力进行视频采集、编码的基础上,还需要良好的抗弱网传输能力。若您拥有第三方视频编解码模块或有能力自研编解码,为了实现实时视频码流传输互通,NERTC SDK 为您提供抗弱网、抗丢包的纯传输通道。
功能介绍
依托网易云信底层实时传输网络 WE-CAN(Communication Acceleration Network),NERTC 运用全球节点及抗弱网算法,提供低延时、高稳定性的音视频码流传输通道,大大减少延时、丢包等网络问题对音视频传输质量和体验的影响。
NERTC SDK 支持视频裸流传输,您可以向 NERTC SDK 提供自定义的 H.264 等格式的视频编码数据,并由 NERTC SDK 进行推流。
注意事项
使用 NERTC SDK 提供的裸流传输通道时,您需要自行管理视频流的采集、编解码、渲染和其他处理。
发送视频裸流
实现方法
- 调用
setDevice
方法指定特定外部视频采集设备;调用此方法时,您需要设置device_id
参数为视频采集设备 IDnertc-video-external-device
(主流)或nertc-subvideo-external-device
(辅流),并设置type
为kNERTCVideoStreamMain
(主流) 或kNERtcVideoStreamSub
(辅流)。 - 调用
setExternalVideoSource
方法开启外部视频源数据输入;调用此方法时,您需要设置enable
参数为true
,并设置type
为kNERTCVideoStreamMain
(主流) 或kNERtcVideoStreamSub
(辅流)。自定义外部视频采集接口支持在通话过程中动态调用,接口设置在通话结束后仍然有效;若您需要关闭该功能,请在下次通话前再次调用此方法关闭自定义视频采集。
- 调用
setExternalVideoSource
方法开启外部视频源数据输入;调用此方法时,您需要设置enable
参数为true
,并设置type
为kNERTCVideoStreamMain
(主流) 或kNERtcVideoStreamSub
(辅流)。若您开启的是外部视频主流输入,请开启对应的媒体主流传输通道,辅流同理。
- 您需要自行处理视频数据的采集与编码。
- 调用
pushExternalVideoEncodedFrame
方法推送外部视频主流或辅流编码帧,并通过NERtcVideoEncodedFrame
设置编码后的视频数据,包括视频编码器类型、NAL 帧数据类型、NAL 帧数据长度、视频帧宽高等。- 建议在推送外部视频编码帧时,不要同时调用
pushExternalVideoFrame
方法。 - 若您开启的是外部视频主流输入,请使用对应的媒体主流传输通道推送编码帧,辅流同理。
- 所有 NAL 帧数据长度之和不能超过 nalData 参数对应的数据总长度。
- 建议在推送外部视频编码帧时,不要同时调用
- 推送视频编码帧成功后,您可以通过
setVideoEncoderQosObserver
接口注册视频编码 QoS 信息监听器,通过返回的相关视频编码数据调整视频编码策略。相关回调如下:onRequestSendKeyFrame
:I 帧请求事件回调。onVideoCodecUpdated
:视频编码器类型信息回调。onBitrateUpdated
:视频码率信息回调。
示例代码
以实现视频主流编码帧传输为例,示例代码如下:
// 设置外部视频设备
IVideoDeviceManager *vdmPtr = nullptr;
auto ret = nrtc_engine->queryInterface(nertc::kNERtcIIDVideoDeviceManager, (void **)&vdmPtr);
if (ret != nertc::kNERtcNoError) {
/// error handling
}
if (vdmPtr) {
ret = vdmPtr->setDevice(kNERtcExternalVideoDeviceID, nertc::kNERTCVideoStreamMain);
if (ret != nertc::kNERtcNoError) {
/// error handling
}
}
// 开启外部视频源
ret = nrtc_engine->setExternalVideoSource(nertc::kNERTCVideoStreamMain, true);
if (ret != nertc::kNERtcNoError) {
/// error handling
}
//设置本地画布
nertc::NERtcVideoCanvas local_canvas;
local_canvas.cb = onLocalFrameDataCallback;//回调和窗口2选1,全部不填代表移除
local_canvas.user_data = nullptr;
//canvas.window = window;
ret = nrtc_engine->setupLocalVideoCanvas(&local_canvas);
if (ret != nertc::kNERtcNoError) {
/// error handling
}
//打开视频发送
ret = nrtc_engine->enableLocalVideo(true);
if (ret != nertc::kNERtcNoError) {
/// error handling
}
// 设置视频编码Qos信息观测器
class NERtcVideoEncoderQosObserver : public nertc::INERtcVideoEncoderQosObserver
{
public:
void onRequestSendKeyFrame(NERtcVideoStreamType video_stream_type) override {
/*视频I帧请求回调*/
}
void onBitrateUpdated(uint32_t bitrate_bps, NERtcVideoStreamType video_stream_type) override {
/*视频码率信息回调*/
}
void onVideoCodecUpdated(NERtcVideoCodecType video_codec_type, NERtcVideoStreamType video_stream_type) override {
/*视频编码器信息回调*/
}
};
NERtcVideoEncoderQosObserver observer;
ret = nrtc_engine->setVideoEncoderQosObserver(&observer);
if (ret != nertc::kNERtcNoError) {
/// error handling
}
// 推送外部视频编码帧
int timediff = 1000000 / fps; //us
steady_clock::time_point last = steady_clock::now();
steady_clock::time_point now = steady_clock::now();
while (true) {
now = steady_clock::now();
long gap = duration_cast<microseconds>((now - last)).count();
if ( gap >= timediff) {
last = now - microseconds(gap - timediff);
nertc::NERtcVideoEncodedFrame frame;
memset(&frame, 0, sizeof(frame));
frame.codec_type = nertc::kNERtcVideoCodecTypeH264;
frame.frame_type = nertc::kNERtcNalFrameTypeIDR;
frame.nal_count = nalCnt;
frame.nal_length = nalLen;
frame.nal_data = data;
frame.timestamp_us = TimeMicros(); // 机器时间,us
frame.width = width;
frame.height = height;
nrtc_engine->pushExternalVideoEncodedFrame(&frame)
}
std::this_thread::sleep_for(milliseconds(1)); //1ms
}
接收视频裸流
实现方法
-
在初始化前,调用
setParameters
方法关闭 NERTC SDK 的视频解码功能,SDK 将不会自动解码并渲染远端视频。 -
在初始化后,调用
setPreDecodeObserver
注册解码前媒体数据观测器。 -
远端发送音频流后,SDK 触发
onFrame
回调,通过preDecodeFrame
参数返回相关解码前媒体数据,包括用户的 UID、媒体数据类型、数据长度、视频帧宽高等。 -
您需要自行处理视频数据的解码与渲染。
示例代码
// 关闭解码器
auto ret = nrtc_engine->setParameters(R"({"disable_video_decoder": true})")
if (ret != nertc::kNERtcNoError) {
/// error handling
}
// 初始化引擎
ret = nrtc_engine->initialize(contex);
if (ret != nertc::kNERtcNoError) {
/// error handling
}
// 设置解码前数据回调观测器
class NERtcPreDecodeObserver:public nertc::INERtcPreDecodeObserver {
public:
void onFrame(NERtcPreDecodeFrameInfo* pre_decode_frame) override {
/*解码前媒体数据回调*/
}
};
NERtcPreDecodeObserver observer;
ret = nrtc_engine->setPreDecodeObserver(&observer);
if (ret != nertc::kNERtcNoError) {
/// error handling
}
API 参考
方法 | 功能描述 |
---|---|
setDevice |
指定特定外部视频采集设备 |
setExternalVideoSource |
开启外部视频源数据输入 |
pushExternalVideoEncodedFrame |
推送外部视频主流或辅流编码帧 |
setVideoEncoderQosObserver |
注册视频编码 QoS 信息监听器 |
setPreDecodeObserver |
注册解码前媒体数据观测器 |
事件 | 事件描述 |
---|---|
onRequestSendKeyFrame |
I 帧请求事件回调 |
onVideoCodecUpdated |
视频编码器类型信息回调 |
onBitrateUpdated |
视频码率信息回调 |
onFrame |
解码前媒体数据回调 |