video_frame_observer.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #include "pch.h"
  2. #include "../common/comm.h"
  3. #include "video_frame_observer.h"
  4. constexpr int kBufferAlignment = 64;
  5. ArgbBuffer::ArgbBuffer(int width, int height, int stride)
  6. : width_(width),
  7. height_(height),
  8. stride_(stride),
  9. data_(static_cast<uint8_t*>(
  10. webrtc::AlignedMalloc(ArgbDataSize(height, stride),
  11. kBufferAlignment))) {
  12. RTC_DCHECK_GT(width, 0);
  13. RTC_DCHECK_GT(height, 0);
  14. RTC_DCHECK_GE(stride, 4 * width);
  15. }
  16. rtc::scoped_refptr<webrtc::I420BufferInterface> ArgbBuffer::ToI420()
  17. {
  18. //创建了一个 webrtc::I420Buffer实例i420_buffer,并调用其静态方法 Create初始化一个I420格式的缓冲区
  19. rtc::scoped_refptr<webrtc::I420Buffer> i420_buffer =
  20. webrtc::I420Buffer::Create(width_, height_, stride_, stride_ / 2,
  21. stride_ / 2);
  22. //libyuv库中的函数,用于将ARGB格式的数据转换为I420格式
  23. libyuv::ARGBToI420(Data(), Stride(), i420_buffer->MutableDataY(),
  24. i420_buffer->StrideY(), i420_buffer->MutableDataU(),
  25. i420_buffer->StrideU(), i420_buffer->MutableDataV(),
  26. i420_buffer->StrideV(), width_, height_);
  27. return i420_buffer;
  28. }
  29. void VideoFrameObserver::SetCallback(I420FrameReadyCallback callback) {
  30. std::lock_guard<std::mutex> lock{ mutex_ };
  31. i420_callback_ = std::move(callback);
  32. }
  33. void VideoFrameObserver::SetCallback(ARGBFrameReadyCallback callback)
  34. {
  35. std::lock_guard<std::mutex> lock{ mutex_ };
  36. argb_callback_ = std::move(callback);
  37. }
  38. ArgbBuffer* VideoFrameObserver::GetArgbScratchBuffer(int width, int height)
  39. {
  40. //计算了所需的图像大小,并将结果保存在 needed_size 变量中
  41. const size_t needed_size = ArgbDataSize(width, height);
  42. //尝试从 argb_scratch_buffer_ 中获取已有的缓冲区,并将其存储在 buffer 变量中
  43. if (auto* buffer = argb_scratch_buffer_.get())
  44. {
  45. //检查已有的缓冲区是否足够大以容纳所需的图像数据
  46. if (buffer->Size() >= needed_size)
  47. {
  48. return buffer;
  49. }
  50. }
  51. //创建一个新的足够大的ArgbBuffer对象,并将其存储在argb_scratch_buffer_中
  52. argb_scratch_buffer_ = ArgbBuffer::Create(width, height);
  53. return argb_scratch_buffer_.get();
  54. }
  55. void VideoFrameObserver::OnFrame(const webrtc::VideoFrame& frame) {
  56. std::lock_guard<std::mutex> lock{ mutex_ };
  57. if (!i420_callback_ && !argb_callback_)
  58. return;
  59. //从 frame(一个 webrtc::VideoFrame 对象)中调用 video_frame_buffer() 方法获取视频帧缓冲区
  60. //将该缓冲区存储在一个 rtc::scoped_refptr<webrtc::VideoFrameBuffer> 类型的变量 buffer 中,以便自动管理其生命周期
  61. rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
  62. frame.video_frame_buffer());
  63. //获取当前视频帧的宽度和高度
  64. const int width = frame.width();
  65. const int height = frame.height();
  66. //检查缓冲区的类型是否为 kI420A(即带有 alpha 通道的 I420 格式)
  67. if (buffer->type() != webrtc::VideoFrameBuffer::Type::kI420A)
  68. {
  69. // The buffer is not encoded in I420 with alpha channel; use I420 without
  70. // alpha channel as interchange format for the callback, and convert the
  71. // buffer to that (or do nothing if already in I420).
  72. //如果不是,将缓冲区转换为 I420 格式,获取 Y、U、V 平面的数据指针,由于没有 alpha 通道,aptr 被设为 nullptr
  73. rtc::scoped_refptr<webrtc::I420BufferInterface> i420_buffer =
  74. buffer->ToI420();
  75. const uint8_t* yptr = i420_buffer->DataY();
  76. const uint8_t* uptr = i420_buffer->DataU();
  77. const uint8_t* vptr = i420_buffer->DataV();
  78. const uint8_t* aptr = nullptr;
  79. // if (i420_callback_) {
  80. // i420_callback_(yptr, uptr, vptr, aptr, i420_buffer->StrideY(),
  81. // i420_buffer->StrideU(), i420_buffer->StrideV(), 0, width,
  82. // height);
  83. // }
  84. //如果存在 argb_callback_ 回调函数,调用该函数
  85. if (argb_callback_)
  86. {
  87. // ArgbBuffer* const argb_buffer = GetArgbScratchBuffer(width, height);
  88. // libyuv::I420ToARGB(yptr, i420_buffer->StrideY(), uptr,
  89. // i420_buffer->StrideU(), vptr, i420_buffer->StrideV(),
  90. // argb_buffer->Data(), argb_buffer->Stride(), width,
  91. // height);
  92. argb_callback_(yptr,i420_buffer->StrideY(),uptr,i420_buffer->StrideU(),vptr,i420_buffer->StrideV(), width*4, width, height);
  93. }
  94. }
  95. //如果缓冲区类型是 kI420A,则直接处理带有 alpha 通道的 I420 缓冲区
  96. else
  97. {
  98. // The buffer is encoded in I420 with alpha channel, use it directly.
  99. const webrtc::I420ABufferInterface* i420a_buffer = buffer->GetI420A();
  100. const uint8_t* yptr = i420a_buffer->DataY();
  101. const uint8_t* uptr = i420a_buffer->DataU();
  102. const uint8_t* vptr = i420a_buffer->DataV();
  103. const uint8_t* aptr = i420a_buffer->DataA();
  104. // if (i420_callback_) {
  105. // i420_callback_(yptr, uptr, vptr, aptr, i420a_buffer->StrideY(),
  106. // i420a_buffer->StrideU(), i420a_buffer->StrideV(),
  107. // i420a_buffer->StrideA(), width, height);
  108. // }
  109. if (argb_callback_)
  110. {
  111. // ArgbBuffer* const argb_buffer = GetArgbScratchBuffer(width, height);
  112. // libyuv::I420AlphaToARGB(
  113. // yptr, i420a_buffer->StrideY(), uptr, i420a_buffer->StrideU(), vptr,
  114. // i420a_buffer->StrideV(), aptr, i420a_buffer->StrideA(),
  115. // argb_buffer->Data(), argb_buffer->Stride(), width, height, 0);
  116. argb_callback_(yptr, i420a_buffer->StrideY(), uptr, i420a_buffer->StrideU(), vptr, i420a_buffer->StrideV(), width * 4, width, height);
  117. }
  118. }
  119. }