webrtc 发送自定义视频之自定义编码器

上篇文章分析过发送自定义视频的可能实现方式,  看上去可行的是自定义编码器的方法. 现在具体讲讲如何实现.

webrtc默认的视频发送流程:

视频捕获--> 视频编码-->视频发送. 

我们要做的是停止捕获,  伪造编码,准备自定义视频数据, 发送视频. 

流程还是webrtc的流程, 只是替换了流程中的一部分.

如何替换编码器呢?  我们需要一个假的编码器, 它有编码器类的所有接口, 但是不做实际编码动作.  这样的类webrtc自带一个FakeVP8Encoder(也可以用修改vp8的类, 然后注释掉其中的encode函数).

webrtc留给用户的接口类有PeerConnection/ PeerConnectionFactory等, 这两个类是核心, 所以其它操作的源头.  自定义实现自然要从这入口开始. 

准备替换:

基于webrtc的应用基本都要创建PeerConnection/ PeerConnectionFactory两个类的实例. 创建factory的时候可以传入VideoEncoderFactory,  这是自定义encoder的开始. 

this->peerConnectionFactory = webrtc::CreatePeerConnectionFactory(

  this->networkThread.get(),

  this->workerThread.get(),

  this->signalingThread.get(),

  nullptr /*default_adm*/,

  webrtc::CreateBuiltinAudioEncoderFactory(),

  webrtc::CreateBuiltinAudioDecoderFactory(),

  //webrtc::CreateBuiltinVideoEncoderFactory(),

  webrtc::test::CreateFakeVideoEncoderFactory(),  // 自定义encoder的开始.

  webrtc::CreateBuiltinVideoDecoderFactory(),

  nullptr /*audio_mixer*/,

  nullptr /*audio_processing*/);

然后来看  webrtc::test::CreateFakeVideoEncoderFactory()的实现:

std::unique_ptr CreateFakeVideoEncoderFactory() {

  return std::make_unique();

}

然后看FakeVideoEncoderFactory类的实现:

class RTC_EXPORT FakeVideoEncoderFactory : public VideoEncoderFactory {

public:

  FakeVideoEncoderFactory();

  // VideoEncoderFactory implementation

  std::vector GetSupportedFormats() const override;

  VideoEncoderFactory::CodecInfo QueryVideoEncoder(

      const SdpVideoFormat& format) const override;

  std::unique_ptr CreateVideoEncoder(

      const SdpVideoFormat& format) override;

// add by yyq

const std::unique_ptr task_queue_factory_;  // 是因为要创建一个task用于连续发送自定义视频数据. 

};

看看CreateVideoEncoder的实现:

std::unique_ptr FakeVideoEncoderFactory::CreateVideoEncoder(

    const SdpVideoFormat& format) {

  return std::make_unique(Clock::GetRealTimeClock(), *task_queue_factory_);

}

这里我们就实现了用FakeVP8Encoder替换系统默认的Encoder.  这样我们可以在我们自定义的Encoder里边实现想要的操作. 



下边简单看下具体实现:

主要是创建了一个FakeVP8Encoder.  简单看下该类的声明:

class FakeVP8Encoder : public FakeEncoder {

public:

//  explicit FakeVP8Encoder(Clock* clock);

  explicit FakeVP8Encoder(Clock* clock, TaskQueueFactory& task_queue_factory);

....

}

该类继承自FakeEncoder:

class FakeEncoder : public VideoEncoder {

public:

//  explicit FakeEncoder(Clock* clock); 

  explicit FakeEncoder(Clock* clock, TaskQueueFactory& task_queue_factory);

  int32_t Encode(const VideoFrame& input_image,

                const std::vector* frame_types) override;

  int32_t RegisterEncodeCompleteCallback(

      EncodedImageCallback* callback) override;

  // add by yyq

  int32_t ForwardFrame();

...

  // add by yyq

private:

  RepeatingTaskHandle frame_encoder_task_;

  rtc::TaskQueue task_queue_;

//  const std::unique_ptr tq_factory_;

}

来看看FakeEncoder里边的关键函数 Encode 和 RegisterEncodeCompleteCallback:

Encode函数负责编码, 边把编码后的数据通过RegisterEncodeCompleteCallback函数投递给后续处理者, 就是要调用后续模块进行发送.

我们要修改的点就在这里了. 

1. 我们的Encode函数由于是fake encode, 实现自然是没有去实际编码, 我们完全可以随意修改, 自定义视频数据, 然后发送出去.  

2. 创建一个定时任务, 用于解析来自文件的视频码流并通过RegisterEncodeCompleteCallback函数注册的处理对象, 投递给后续处理逻辑即可.  这样就完美替换掉了编码数据以及使用了webrtc原始的发送流程. 

你可能感兴趣的:(webrtc 发送自定义视频之自定义编码器)