自定义编码器类简介
WebRTC内置了很多软编码器,我们可以直接使用外部的硬件编码器库,也可以自定义编码器,来实现我们的行为。
这里我们尝试自定义编码器类,封装Nvidia的NVEncoder H264编码能力。
核心思路和创建步骤
VideoEncoderFactory类在创建的时候,提供的编码器创建工厂函数中允许我们自定义的类,我们只需要对应的重载即可。
步骤 | 详细 |
创建VideoEncoderFactory的自定义实现 | 可以在WebRTC的源代码中下找到src\media\engine\fake_video_codec_factory.cc |
创建VideoEncoder的自定义实现 | 可以在WebRTC的源代码中下找到,test目录下 fake_video_codes工程。 |
创建CreatePeeroConnectionFactory的时候,第7个参数用第一步自定义的对象 | 一般建议参照官方的例子,用一个静态函数来创建该对象我尝试用一个局部变量来暂存却有编译失败的情况。貌似默认构造函数XX什么的问题。 |
第一步是VideoCapture,所以我们借用之前的AddTrack中的方法 |
部分源代码展示
//注意创建的时候globalSignalingThread和globalWorkerThread是必须的,否则信令不会收到
mPeerConnectionFactory = webrtc::CreatePeerConnectionFactory(
networkThread.get() /* network_thread */,
globalWorkerThread.get()/* worker_thread */,
globalSignalingThread.get() /* signaling_thread */,
myADM /* default_adm */,
std::move(myAudioEncoderFactory),
webrtc::CreateBuiltinAudioDecoderFactory(),
std::move(myVideoEncoderFactory),
webrtc::CreateBuiltinVideoDecoderFactory(),
nullptr /* audio_mixer */,
nullptr /* audio_processing */);
if (!mPeerConnectionFactory)
{
QL_ERROR("Create P2P Connection Factory error.");
DeletePeerConnection();
return false;
}
当我们采用自定义的编码器的时候,代码类似上述。
编码器工厂类重载
以下是我们创建自己的硬件编码器工厂类的实现。
//Important ,Use NVENC
if (QL::QLGlobalConfig::Get().IsUseNVENC())
{
//myVideoEncoderFactory = UniEncoderFactory::CreateUniEncoderFactory();
myVideoEncoderFactory = QL::CreateBuiltinExternalVideoEncoderFactory();
QL_LOG("Create My NVENC encoder");
}
只需要编码方是这样即可,如果另外一方是解码方,不需要这段代码。
自定义编码器时序图
采用设备捕获器的情况下的流程
完整实现源代码
这里给出这个自定义编码器类的完整代码
头文件部分
#ifndef EXTERNAL_BUILTIN_VIDEO_ENCODER_FACTORY_H_
#define EXTERNAL_BUILTIN_VIDEO_ENCODER_FACTORY_H_
#include <memory>
#include "rtc_base/system/rtc_export.h"
#include "api/video_codecs/video_encoder_factory.h"
namespace QL
{
// Creates a new factory that can create the built-in types of video decoders.
RTC_EXPORT std::unique_ptr<webrtc::VideoEncoderFactory> CreateBuiltinExternalVideoEncoderFactory();
} // namespace QL
#endif // EXTERNAL_BUILTIN_VIDEO_ENCODER_FACTORY_H_
Cpp部分
#include "QLH264EncoderFactory.h"
#include "absl/memory/memory.h"
#include "media/engine/internal_decoder_factory.h"
#include "rtc_base/logging.h"
#include "absl/strings/match.h"
#include "modules/video_coding/codecs/h264/include/h264.h"
#include "modules/video_coding/codecs/vp8/include/vp8.h"
#include "modules/video_coding/codecs/vp9/include/vp9.h"
#include "api/video_codecs/video_encoder_factory.h"
#include "api/video_codecs/sdp_video_format.h"
#include "QLGlobalConfig.h"
#include "QLH264Encoder.h"
#include "../SignalClient/MyEncoderCompleteCallback.h"
#include "QLLogSystem.h"
namespace QL
{
/// <summary>
///
/// </summary>
class QLH264EncoderFactory : public webrtc::VideoEncoderFactory
{
public:
/// <summary>
/// 在视频格式中增加对H264的支持。使得webrtc整个体系识别到本编码器
/// </summary>
/// <returns></returns>
std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override
{
std::vector<webrtc::SdpVideoFormat> video_formats;
for (const webrtc::SdpVideoFormat& h264_format : webrtc::SupportedH264Codecs())
{
video_formats.push_back(h264_format);
}
return video_formats;
}
//The format for previous m100
//VideoEncoderFactory::CodecInfo QueryVideoEncoder(
// const webrtc::SdpVideoFormat& format) const override {
// CodecInfo codec_info = { false, false };
// codec_info.is_hardware_accelerated = true;
// codec_info.has_internal_source = false;
// return codec_info;
//}
/// <summary>
/// 创建视频编码器。实现基类方法
/// 必须
/// </summary>
/// <param name="format"></param>
/// <returns></returns>
std::unique_ptr<webrtc::VideoEncoder> CreateVideoEncoder(const webrtc::SdpVideoFormat& format) override
{
#ifdef NO_CUDA
return nullptr;
#else
if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName))
{
if (webrtc::H264Encoder::IsSupported())
{
//启用NVENC就启用硬编码,否则使用webrtc内置的软编码
if (QL::QLGlobalConfig::Get().IsUseNVENC())
{
QL_LOG("Read sdp parameters\n");
webrtc::SdpVideoFormat::Parameters myFormat = format.parameters;
std::map<std::string, std::string>::iterator it;
for (it = myFormat.begin(); it != myFormat.end(); it++)
{
QL_LOG("SDP Parameter===>%s:%s", it->first.c_str(), it->second.c_str());
}
cricket::VideoCodec myCodec=cricket::VideoCodec(format);
std::unique_ptr<webrtc::VideoEncoder> myVideoEncoder=absl::make_unique<QL::QLH264Encoder>(myCodec);
QL_LOG("Start to create NVENC customized encoder and set callback.");
//Here we want our CUDA encoder to set a callback so that we can get a image after hardware encoded
MyEncoderCompleteCallback* myEncoderCallBackForImageEncoded = new MyEncoderCompleteCallback();
myVideoEncoder->RegisterEncodeCompleteCallback(myEncoderCallBackForImageEncoded);
QL_LOG("Succeed to create NVENC customized encoder and set callback.");
//rule
return myVideoEncoder;
}
else
{
return webrtc::H264Encoder::Create(cricket::VideoCodec(format));
}
}
}
return nullptr;
#endif
}
};
/// <summary>
///
/// </summary>
/// <returns></returns>
std::unique_ptr<webrtc::VideoEncoderFactory> CreateBuiltinExternalVideoEncoderFactory()
{
return absl::make_unique<QLH264EncoderFactory>();
}
}
总体来看
自定义编码器是一种允许开发者根据特定需求优化音视频编码和解码过程的技术。WebRTC 默认提供了几种标准编码器,但在某些情况下,可能需要实现自定义编码器以满足特殊需求,如更高的压缩效率、更低的延迟或特定的功能要求。下面是有关自定义编码器的详细信息及潜在风险问题:
自定义编码器的详细情况
- 自定义编码器的目标
- 优化性能:根据应用需求优化编码效率、解码速度或资源使用。
- 满足特殊需求:支持特定的编解码标准或自定义格式,满足业务需求。
- 实验和创新:尝试新的编码技术或算法,进行性能优化和创新。
- 实现自定义编码器
- WebRTC 的编码器接口:WebRTC 提供了
RTCRtpSender
和RTCRtpReceiver
接口,允许开发者定义编码和解码行为。 - 扩展编码器:可以基于现有的编码器进行扩展或修改,提供自定义的实现。
- 编解码器 API:WebRTC 的
RTCRtpCodecParameters
和RTCRtpCodecCapability
允许定义和使用自定义编解码器。
- 开发过程
- 定义编码器参数:设置自定义编码器的参数,包括比特率、分辨率、帧率等。
- 实现编码算法:编写和测试编码和解码算法,确保它们在不同条件下的稳定性和性能。
- 集成和测试:将自定义编码器集成到 WebRTC 应用中,进行全面的测试,确保与 WebRTC 其他部分的兼容性。
潜在风险和问题
- 性能问题
- 资源消耗:自定义编码器可能在性能上不如标准编码器,特别是如果编码算法没有经过优化,可能会消耗更多的 CPU 和内存资源。
- 延迟:自定义编码器可能引入额外的延迟,影响实时通信的体验。
- 兼容性问题
- 标准化:自定义编码器可能不完全符合现有的编码标准或协议,导致兼容性问题。
- 不同设备和浏览器支持:不同的设备和浏览器可能对自定义编码器的支持程度不同,可能导致无法正确解码。
- 维护和支持
- 复杂性:自定义编码器增加了系统的复杂性,需要额外的维护和支持。
- 更新和兼容性:随着 WebRTC 标准的更新,自定义编码器可能需要相应更新,以保持兼容性和性能。
- 安全问题
- 数据安全:自定义编码器可能会引入安全漏洞,特别是在处理敏感数据时。需要确保编码和解码过程中的数据安全。
- 恶意代码:如果自定义编码器实现不当,可能会引入恶意代码或漏洞,影响应用的安全性。
总结
自定义编码器在 WebRTC 中可以为特定应用提供性能和功能上的优势,但同时也带来了一些风险和挑战。在实施自定义编码器时,开发者需要仔细权衡其优缺点,进行充分的测试,确保其性能、兼容性和安全性符合要求。合理的设计和测试可以最大限度地减少这些风险,确保自定义编码器在实际应用中的稳定性和可靠性。
RA/SD 衍生者AI训练营。发布者:chris,转载请注明出处:https://www.shxcj.com/archives/6591