视频裸流传输

更新时间: 2024/03/15 17:14:52

在一些需要与硬件配合的应用场景中,比如使用教室硬件设备进行线上教学,在利用硬件自身能力进行视频采集、编码的基础上,还需要良好的抗弱网传输能力。若您拥有第三方视频编解码模块或有能力自研编解码,为了实现实时视频码流传输互通,NERTC SDK 为您提供抗弱网、抗丢包的纯传输通道。

功能介绍

依托网易云信底层实时传输网络 WE-CAN(Communication Acceleration Network),NERTC 运用全球节点及抗弱网算法,提供低延时、高稳定性的音视频码流传输通道,大大减少延时、丢包等网络问题对音视频传输质量和体验的影响。

NERTC SDK 支持视频裸流传输,您可以向 NERTC SDK 提供自定义的 H.264 等格式的视频编码数据,并由 NERTC SDK 进行推流。

注意事项

使用 NERTC SDK 提供的裸流传输通道时,您需要自行管理视频流的采集、编解码、渲染和其他处理。

发送视频裸流

实现方法

  1. 调用 setDevice 方法指定特定外部视频采集设备;调用此方法时,您需要设置 device_id 参数为视频采集设备 ID nertc-video-external-device(主流)或 nertc-subvideo-external-device(辅流),并设置 typekNERTCVideoStreamMain(主流) 或 kNERtcVideoStreamSub(辅流)。
  2. 调用 setExternalVideoSource 方法开启外部视频源数据输入;调用此方法时,您需要设置 enable 参数为 true,并设置 typekNERTCVideoStreamMain(主流) 或 kNERtcVideoStreamSub(辅流)。

    自定义外部视频采集接口支持在通话过程中动态调用,接口设置在通话结束后仍然有效;若您需要关闭该功能,请在下次通话前再次调用此方法关闭自定义视频采集。

  3. 调用 setExternalVideoSource 方法开启外部视频源数据输入;调用此方法时,您需要设置 enable 参数为 true,并设置 typekNERTCVideoStreamMain(主流) 或 kNERtcVideoStreamSub(辅流)。

    若您开启的是外部视频主流输入,请开启对应的媒体主流传输通道,辅流同理。

  4. 您需要自行处理视频数据的采集与编码。
  5. 调用 pushExternalVideoEncodedFrame 方法推送外部视频主流或辅流编码帧,并通过 NERtcVideoEncodedFrame 设置编码后的视频数据,包括视频编码器类型、NAL 帧数据类型、NAL 帧数据长度、视频帧宽高等。
    • 建议在推送外部视频编码帧时,不要同时调用 pushExternalVideoFrame 方法。
    • 若您开启的是外部视频主流输入,请使用对应的媒体主流传输通道推送编码帧,辅流同理。
    • 所有 NAL 帧数据长度之和不能超过 nalData 参数对应的数据总长度。
  6. 推送视频编码帧成功后,您可以通过 setVideoEncoderQosObserver 接口注册视频编码 QoS 信息监听器,通过返回的相关视频编码数据调整视频编码策略。相关回调如下:

示例代码

以实现视频主流编码帧传输为例,示例代码如下:

// 设置外部视频设备
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
}

接收视频裸流

实现方法

  1. 在初始化前,调用 setParameters 方法关闭 NERTC SDK 的视频解码功能,SDK 将不会自动解码并渲染远端视频。

  2. 在初始化后,调用 setPreDecodeObserver 注册解码前媒体数据观测器。

  3. 远端发送音频流后,SDK 触发 onFrame 回调,通过 preDecodeFrame 参数返回相关解码前媒体数据,包括用户的 UID、媒体数据类型、数据长度、视频帧宽高等。

  4. 您需要自行处理视频数据的解码与渲染。

示例代码

// 关闭解码器
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 解码前媒体数据回调
此文档是否对你有帮助?
有帮助
去反馈
  • 功能介绍
  • 注意事项
  • 发送视频裸流
  • 实现方法
  • 示例代码
  • 接收视频裸流
  • 实现方法
  • 示例代码
  • API 参考