第五十章 视频编码后修改帧数据

基本概念

给视频添加滤镜的方法,是在视频帧被编码前对其进行处理。有时我们还需要在视频帧被编码后对其进行处理,插入一些自定义数据,比如插入 H.264 定义的 SEI(Supplemental Enhancement Information,补充增强信息)。

此时便可以使用 WebRTC Insertable Streams API,这组 API 在 WebRTC M83 (branch-heads/4103) 版本被引入,会分别在视频帧被编码后且发送前、或者被接收后且解码前被调用。由于笔者是 Native 开发,因此这里直接给出 C++ 代码;前端开发者则可以直接参照 W3C 对应文档

个人技术博客: fuqifacai.github.io

更多技术资讯下载: 2img.ai

相关配图由微信小程序【字形绘梦】免费生成

第五十章 视频编码后修改帧数据

源代码解析

首先我们需要继承并实现 webrtc::FrameTransformerInterface ,一个典型模版如下:

ExampleTransformer.cpp

namespace example {

// 在头文件中定义
// class ExampleTransformer : public webrtc::FrameTransformerInterface {
//  public:
//   virtual void RegisterTransformedFrameSinkCallback(
//       rtc::scoped_refptr<webrtc::TransformedFrameCallback>, uint32_t ssrc) override;
//   virtual void UnregisterTransformedFrameSinkCallback(uint32_t ssrc) override;
//   virtual void Transform(std::unique_ptr<webrtc::TransformableFrameInterface> frame) override;
//  private:
//   mutable webrtc::Mutex mutex_;
//   rtc::scoped_refptr<webrtc::TransformedFrameCallback> sink_callback_;
// }

  // WebRTC 只会在 webrtc::RTPSenderVideo 的构造方法中注册一个 callback,
  // 具体可以参见 rtp_sender_video.cc frame_transformer_delegate_->Init()
  void ExampleTransformer::RegisterTransformedFrameSinkCallback(
      rtc::scoped_refptr<webrtc::TransformedFrameCallback> callback, uint32_t ssrc) {
    webrtc::MutexLock lock(&mutex_);
    sink_callback_ = callback;
  }

  void ExampleTransformer::UnregisterTransformedFrameSinkCallback(uint32_t ssrc) {
    webrtc::MutexLock lock(&mutex_);
    sink_callback_ = nullptr;
  }

  void ExampleTransformer::Transform(std::unique_ptr<webrtc::TransformableFrameInterface> frame) {
    webrtc::MutexLock lock(&mutex_);
    if (sink_callback_ == nullptr) return;

    // 在这里处理 frame 的二进制数据...
    // 处理完毕后务必调用 sink_callback_ 将帧数据传递给上层
    sink_callback_->OnTransformedFrame(std::move(frame));
  }
}

如果你想要在视频帧被编码后且发送前被调用,可以通过 RtpSender 进行设置:

rtp_sender_interface.h

class RTC_EXPORT RtpSenderInterface : public rtc::RefCountInterface {
 public:
  // other definitions...

  // 设置的 frame_transformer 会在视频帧被编码后且发送前调用
  virtual void SetEncoderToPacketizerFrameTransformer(
      rtc::scoped_refptr<FrameTransformerInterface> frame_transformer);

  // other definitions...
}

如果你想要在视频帧被接收后且解码前被调用,可以通过 RtpReceiver 进行设置:

rtp_receiver_interface.h

class RTC_EXPORT RtpReceiverInterface : public rtc::RefCountInterface {
 public:
  // other definitions...

  // 设置的 frame_transformer 会在视频帧被接收后且解码前被调用
  virtual void SetDepacketizerToDecoderFrameTransformer(
      rtc::scoped_refptr<FrameTransformerInterface> frame_transformer);

  // other definitions...
}

最后,这组 API 也同样适用于音频,因此读者需要注意 transform 过程中 frame 的具体类型。如果是视频帧数据,实际类型为 webrtc::TransformableVideoFrameInterface ;如果是音频帧数据,则实际类型为 webrtc::TransformableAudioFrameInterface

在我们的流式中真实的源代码如下:

这是使用的入口,在Addtrack之后

//设置可插入流处理类
                                auto rtcSender = result_or_error.value();
                                if (rtcSender)
                                {
                                        rtc::scoped_refptr<StreamDataTransformer> myTransformer(new rtc::RefCountedObject<StreamDataTransformer>("TestName"));
                                        rtcSender->SetEncoderToPacketizerFrameTransformer(myTransformer);
                                }
                                else
                                {
                                        QL_ERROR("Invalid rtcSender");
                                }

真实处理逻辑的类封装中的头文件

剩余内容需解锁后查看

您需要付费解锁才能查看当前内容

VIP会员免费
已付费?登录刷新

Paragoger衍生者AI训练营。发布者:稻草人,转载请注明出处:https://www.shxcj.com/archives/6703

(0)
上一篇 2024-09-30 4:03 下午
下一篇 2024-09-30 4:05 下午

相关推荐

发表回复

登录后才能评论
本文授权以下站点有原版访问授权 https://www.shxcj.com https://www.2img.ai https://www.2video.cn