前面分析到,video数据由VideoCaptureInput,通过DeliverFrame函数传递到ViEEncoder来进行处理.
这里详细分析ViEEncoder对Video数据的处理过程:
ViEEncoder对象初始化
在End_to_End_tests中的RunTest()中创建的VideoSendStream::Config send_config,并定义pre_encode_callback_,用于对送入Encoder的frame进行预处理
Call::CreateVideoSendStream(send_config, ..)
new VideoSendStream(.., config,..)
new ViEEncoder(.., config.pre_encode_callback, ..)
例如自定义类A,其对象a要使用这一功能,需要按以下方式进行实现:
- A要继承I420FrameCallback类
- override FrameCallback方法,实现需要做的预处理,可以自己实现,也可以很容易的就集成现有的图像处理库(opencv .etc)
- 创建VideoSendStream::Config send_config, 并初始化pre_encode_callback_
- 根据send_config创建VideoSendStream对象
ViEEncoder::DeliverFrame
将video数据送入编码器
// Pass frame via preprocessor.
const int ret = vpm_->PreprocessFrame(video_frame, &decimated_frame);
VideoProcessingModuleImpl::PreprocessFrame
VPMFramePreprocessor::PreprocessFrame
- resize if needed (VPMSimpleSpatialResampler::ResampleFrame(frame,
&resampled_frame_)) - content analysis ( VPMContentAnalysis::ComputeContentMetrics)
对送入编码器的数据进行预处理,在现有的代码中没有相应的实现
if (pre_encode_callback_) {
....
pre_encode_callback_->FrameCallback(decimated_frame);
}
将准备好的数据送入编码器:
vcm_->AddVideoFrame(*output_frame);
调用关系:
VideoCodingModule::AddVideoFrame
VideoCodingModuleImpl::AddVideoFrame
VideoSender::AddVideoFrame
VideoSender::AddVideoFrame
编码器以及编码参数配置
编码器初始化流程及参数配置:
创建Config信息:
所有的编码器选择,编码器参数,编码输出数据的callback函数都是在这里进行配置的
VideoSendStream::Config send_config
- EncoderSettings(payload_name,payload_type, VideoEncoder对象(选择对应的encode类型(H264)))
- Rtp(max_packet_size, RtpExtension, NackConfig, FecConfig, Rtx())
- send_transport //Transport for outgoing packets.
- LoadObserver* overuse_callback, 当前系统的负载情况,根据incoming capture frame的jitter计算
- I420FrameCallback*
- EncodedFrameObserver* post_encode_callback,编码输出帧的处理
- VideoRenderer* local_renderer,Renderer for local preview
- VideoCaptureInput* Input(),video数据输入
VideoEncoderConfig encoder_config
- vector< VideoStream > streams 视频流的常规参数配置(width, height, framerate, bitrate(min/max/target), qp )
创建Encoder,参考EndToEndTest中的实现
rtc::scoped_ptr< VideoEncoder > encoder(
VideoEncoder::Create(VideoEncoder::kVp8));
//根据需要传入不同的参数,初始化不同的encoder
//VP8Encoder::Create();
send_config_.encoder_settings.encoder = encoder.get();
创建一个VideoEncoder对象,保存在VideoSendStream::Config中通话下面的调用顺序,进行设置:
CreateVideoSendStream(send_config_, ...);
VideoSendStream::VideoSendStream(..., config, ...);
VideoEncoder::RegisterExternalEncoder(
config.encoder_settings.encoder, ...);
ViEEncoder::RegisterExternalEncoder(encoder, ...);
VideoCodingModuleImpl::RegisterExternalEncoder(externalEncoder, ...);
VideoSender::RegisterExternalEncoder(externalEncoder, ...);
VCMCodecDataBase::RegisterExternalEncoder(external_encoder, ...);
最终保存在VCMCodecDataBase的成员变量external_encoder_中。
初始化VideoSendStream对象
这个对象很重要,所有上行数据的操作都是从这里开始的:
- ViEEncoder初始化
- ViEChannel初始化
- VideoCaptureInput初始化
- EncodedFrameObserver 编码输出码流问题
构造函数的具体实现:
VideoSendStream::VideoSendStream(
int num_cpu_cores,
ProcessThread* module_process_thread,
CallStats* call_stats,
CongestionController* congestion_controller,
const VideoSendStream::Config& config,
const VideoEncoderConfig& encoder_config,
const std::map<uint32_t, RtpState>& suspended_ssrcs)
: stats_proxy_(Clock::GetRealTimeClock(), config),
transport_adapter_(config.send_transport),
encoded_frame_proxy_(config.post_encode_callback),
config_(config),
suspended_ssrcs_(suspended_ssrcs),
m