WebRTC中的视频编码及编码参数体系

本篇文章介绍了webrtc中视频编码器的创建流程及编码器参数体系。

在webrtc中视频编码功能是一列功能类相互协作实现的,因为编码功能不只涉及到将raw video数据编码,还至少有如下几个功能:

  1. 根据配置或视频协商的结果初始化编码参数。
  2. 根据带宽或配置,动态改变编码参数,比如动态改变编码码率,分辨率,帧率等。
  3. 同时产生多条码流。

整个视频编码功能包括下面几个功能类:

  • 视频编码接口类及相关工厂类

VideoEncoder视频编码接口类,是一个抽象接口类。

VideoEncoderFactory工厂类,用于创建 VideoEncoder的具体实例。

  • 具体的编码类

H264Encoder h264编码接口类,有个 Create方法用于创建h264的编码类实例。

 H264EncoderImp h264编码的具体实现, H264Encoder的实例。

  • 编码器参数配置相关类

包括 VideoStreamVideoCodeViCodecInitializer 。

创建编码器

VideoEncoderFactory

创建编码器的工厂类,它是个抽象类,定义了创建编码器的方法

std::unique_ptr<VideoEncoder> CreateVideoEncoder(      const SdpVideoFormat& format);

BuiltinVideoEncoderFactoryInternalEncoderFactoryVideoEncoderFactory的实现子类

WebRTC中的视频编码及编码参数体系

BuiltinVideoEncoderFactory类中有一个 InternalEncoderFactory的成员变量,具体的创建编码器的工作在 InternalEncoderFactory中完成,如下代码:

std::unique_ptr<VideoEncoder> InternalEncoderFactory::CreateVideoEncoder(    const SdpVideoFormat& format) {  if (absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName))    return VP8Encoder::Create();  if (absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName))    return VP9Encoder::Create(cricket::VideoCodec(format));  if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName))    return H264Encoder::Create(cricket::VideoCodec(format));  if (kIsLibaomAv1EncoderSupported &&      absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName))    return CreateLibaomAv1Encoder();  RTC_LOG(LS_ERROR) << "Trying to created encoder of unsupported format "                    << format.name;  return nullptr;}

VideoEncoderFactory的接口是面向业务,通过转调到 InternalEncoderFactoryCreateVideoEncoder方法来创建具体的编码器。

创建编码器的调用堆栈

如下堆栈,创建编码器

peerconnectionclient.exe!webrtc:: anonymousnamespace'::BuiltinVideoEncoderFactory::CreateVideoEncoder() 行 59 C++
peerconnection_client.exe!webrtc::VideoStreamEncoder::ReconfigureEncoder() 行 633 C++
peerconnection_client.exe!webrtc::VideoStreamEncoder::MaybeEncodeVideoFrame() 行 1264 C++
peerconnection_client.exe!webrtc::VideoStreamEncoder::OnFrame(const webrtc::VideoFrame &)::(anonymous class)::operator()() 行 1046 C++
peerconnection_client.exe!webrtc::webrtc_new_closure_impl::ClosureTask<lambda at ../../video/videostreamencoder.cc:1032:7'>::Run() 行 33 C++
peerconnectionclient.exe!webrtc:: anonymousnamespace'::TaskQueueWin::RunPendingTasks() 行 272 C++
peerconnection_client.exe!webrtc::anonymous namespace'::TaskQueueWin::RunThreadMain() 行 285 C++
peerconnectionclient.exe!webrtc::`anonymous namespace'::TaskQueueWin::ThreadMain() 行 280 C++
peerconnectionclient.exe!rtc::PlatformThread::Run() 行 130 C++
peerconnection_client.exe!rtc::PlatformThread::StartThread() 行 62 C++

VideoStreamEncoderReconfigureEncoder方法中创建编码器(这里的 VideoStreamEncoder类在video目录下videostreamencoder.h文件中)

VideoEncoder

\api\vidoecodecs\videoencoder.h
\video_coding\codecs\h264.h

webrtc中包括多种编码器,比如 h264vp8等,各个编码器的功能都类似,所以抽象出一个 VideoEncoder的基类,各个不同格式的编码器是它的具体子类。如下类图(这里只列出了 H264Encoder子类)

WebRTC中的视频编码及编码参数体系

上面类图中只列出了最通用的5个接口,适用于所有编码器。

编码器的配置体系

前面提到过,编码器会有编码参数,这些参数信息可能是业务配置产生,也可能是媒体能力协商时产生,最终都需要设置到编码器中,所以通常会有一套配置功能类,来管理这些参数。

VideoEncoderConfig

\api\videocodecs\videoencoder_config.h

与业务直接打交道的配置类 VideoEncoderConfig

WebRTC中的视频编码及编码参数体系

VideoStream

\api\videocodecs\videoencoder_config.h

The |VideoStream| struct describes a simulcast layer, or “stream”

按照它的注释描述,代表了一条码流(的配置)。它包含了码流的一些基本参数,是 VideoEncoderConfig中的配置信息的进一步细化。

simulcast 是指同时产生多条不同分辨率,帧率,码率的码流,一个 VideoStream代表了其中一条码流的配置,如下定义:

struct VideoStream {  VideoStream();  ~VideoStream();  VideoStream(const VideoStream& other);  std::string ToString() const;  // Width in pixels.  size_t width;  // Height in pixels.  size_t height;  // Frame rate in fps.  int max_framerate;  // Bitrate, in bps, for the stream.  int min_bitrate_bps;  int target_bitrate_bps;  int max_bitrate_bps;  double scale_resolution_down_by;  // Maximum Quantization Parameter to use when encoding the stream.  int max_qp;  absl::optional<size_t> num_temporal_layers;  absl::optional<double> bitrate_priority;  // If this stream is enabled by the user, or not.  bool active;};

包含分辨率,最大/小码率,qp值等。num_temporal_layers代表时间域的层数,就是帧率,在支持 temporal layer的编码器中(比如vp8/9),就是一条码流包含不同的帧率。

VideoCodec

\api\videocodecs\videocodec.h

Common video codec properties

VideoCodec是编码器的配置信息,如下类图:

WebRTC中的视频编码及编码参数体系

包括codec,分辨率,帧率,码率(起始,最大,最小),qp值,simulcast stream信息。在 InitEncode方法中需要 VideoCodec类型的形参。将 VideoStreamVideoEncoderConfig中配置信息转换成 VideoCodec后,再去设置到编码器中。

VideoStream只是 VideoCodec的子集。如果是*simulcast *模式, VideoCodec中包含多个 VideoStream的配置信息。

//这就是对应的videoStream的配置SpatialLayer simulcastStream[kMaxSimulcastStreams];

VideoCodecInitializer

\modules\videocoding\include\videocodec_initializer.h

VideoEncoderConfigVideoStream转换为 VideoCodec

WebRTC中的视频编码及编码参数体系

关系

这几个编码器参数配置相关的类,关系如下:

WebRTC中的视频编码及编码参数体系

业务层根据配置或媒体协商的结果生成编码器参数 VideoEncoderConfig,再将 VideoEncoderConfig中的 simulcast信息取出生成 VideoStreamsimulcast每条码流对应一个 VideoSteramVideoCodeceInitalizerVideoEncoderConfigVideoStream参数配置信息转换成 VideoCodec中配置信息, VideoCodec会用于初始化 VideoEncoder。具体的参数转换策略可以看看, VideoStreamFactoryInterface类中的 CreateEncoderStreams方法

std::vector<VideoStream> CreateEncoderStreams(        
int width,        
int height,        
const VideoEncoderConfig& encoder_config)

VideoCodecInitializer类中 SetupCodec方法

bool SetupCodec(const VideoEncoderConfig& config,                         
const std::vector<VideoStream>& streams, VideoCodec* codec)

VideoStreamEncoder类中的 ReconfigureEncoder方法中,有从创建编码器到转换编码器配置的整个流程,可以看看具体调用方法。

总结

  • 不同编码格式的编码器功能基本一致,通常是会抽象出一个基类,比如 VideoEncoder
  • 编码器支持的特性不同,所以编码器的参数配置往往是分层的,从抽象到具体,从粗到细。比如 VideoEncoderConfig到 VideoStream到 VideoCodec,就是这种层次递进的情况。
  • webrtc中的编码器配置体系比较复杂,繁琐,这是因为它的功能特性决定的,它要支持不同编码器,支持simulcastTemporalLayer,并且对simulcast中每条码流的帧率,码率,分辨率是根据带宽,cpu性能来动态适用,所以肯定需要额外的参数配置。如果我们自己实现视频编码功能,不需要这些特性,可以简化这种配置体系。

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论