xref: /aosp_15_r20/external/webrtc/modules/video_coding/codecs/multiplex/multiplex_encoder_adapter.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/video_coding/codecs/multiplex/include/multiplex_encoder_adapter.h"
12 
13 #include <cstring>
14 
15 #include "api/video/encoded_image.h"
16 #include "api/video_codecs/video_encoder.h"
17 #include "common_video/include/video_frame_buffer.h"
18 #include "common_video/libyuv/include/webrtc_libyuv.h"
19 #include "media/base/video_common.h"
20 #include "modules/video_coding/codecs/multiplex/include/augmented_video_frame_buffer.h"
21 #include "rtc_base/logging.h"
22 
23 namespace webrtc {
24 
25 // Callback wrapper that helps distinguish returned results from `encoders_`
26 // instances.
27 class MultiplexEncoderAdapter::AdapterEncodedImageCallback
28     : public webrtc::EncodedImageCallback {
29  public:
AdapterEncodedImageCallback(webrtc::MultiplexEncoderAdapter * adapter,AlphaCodecStream stream_idx)30   AdapterEncodedImageCallback(webrtc::MultiplexEncoderAdapter* adapter,
31                               AlphaCodecStream stream_idx)
32       : adapter_(adapter), stream_idx_(stream_idx) {}
33 
OnEncodedImage(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info)34   EncodedImageCallback::Result OnEncodedImage(
35       const EncodedImage& encoded_image,
36       const CodecSpecificInfo* codec_specific_info) override {
37     if (!adapter_)
38       return Result(Result::OK);
39     return adapter_->OnEncodedImage(stream_idx_, encoded_image,
40                                     codec_specific_info);
41   }
42 
43  private:
44   MultiplexEncoderAdapter* adapter_;
45   const AlphaCodecStream stream_idx_;
46 };
47 
MultiplexEncoderAdapter(VideoEncoderFactory * factory,const SdpVideoFormat & associated_format,bool supports_augmented_data)48 MultiplexEncoderAdapter::MultiplexEncoderAdapter(
49     VideoEncoderFactory* factory,
50     const SdpVideoFormat& associated_format,
51     bool supports_augmented_data)
52     : factory_(factory),
53       associated_format_(associated_format),
54       encoded_complete_callback_(nullptr),
55       key_frame_interval_(0),
56       supports_augmented_data_(supports_augmented_data) {}
57 
~MultiplexEncoderAdapter()58 MultiplexEncoderAdapter::~MultiplexEncoderAdapter() {
59   Release();
60 }
61 
SetFecControllerOverride(FecControllerOverride * fec_controller_override)62 void MultiplexEncoderAdapter::SetFecControllerOverride(
63     FecControllerOverride* fec_controller_override) {
64   // Ignored.
65 }
66 
InitEncode(const VideoCodec * inst,const VideoEncoder::Settings & settings)67 int MultiplexEncoderAdapter::InitEncode(
68     const VideoCodec* inst,
69     const VideoEncoder::Settings& settings) {
70   const size_t buffer_size =
71       CalcBufferSize(VideoType::kI420, inst->width, inst->height);
72   multiplex_dummy_planes_.resize(buffer_size);
73   // It is more expensive to encode 0x00, so use 0x80 instead.
74   std::fill(multiplex_dummy_planes_.begin(), multiplex_dummy_planes_.end(),
75             0x80);
76 
77   RTC_DCHECK_EQ(kVideoCodecMultiplex, inst->codecType);
78   VideoCodec video_codec = *inst;
79   video_codec.codecType = PayloadStringToCodecType(associated_format_.name);
80 
81   // Take over the key frame interval at adapter level, because we have to
82   // sync the key frames for both sub-encoders.
83   switch (video_codec.codecType) {
84     case kVideoCodecVP8:
85       key_frame_interval_ = video_codec.VP8()->keyFrameInterval;
86       video_codec.VP8()->keyFrameInterval = 0;
87       break;
88     case kVideoCodecVP9:
89       key_frame_interval_ = video_codec.VP9()->keyFrameInterval;
90       video_codec.VP9()->keyFrameInterval = 0;
91       break;
92     case kVideoCodecH264:
93       key_frame_interval_ = video_codec.H264()->keyFrameInterval;
94       video_codec.H264()->keyFrameInterval = 0;
95       break;
96     default:
97       break;
98   }
99 
100   encoder_info_ = EncoderInfo();
101   encoder_info_.implementation_name = "MultiplexEncoderAdapter (";
102   encoder_info_.requested_resolution_alignment = 1;
103   encoder_info_.apply_alignment_to_all_simulcast_layers = false;
104   // This needs to be false so that we can do the split in Encode().
105   encoder_info_.supports_native_handle = false;
106 
107   for (size_t i = 0; i < kAlphaCodecStreams; ++i) {
108     std::unique_ptr<VideoEncoder> encoder =
109         factory_->CreateVideoEncoder(associated_format_);
110     const int rv = encoder->InitEncode(&video_codec, settings);
111     if (rv) {
112       RTC_LOG(LS_ERROR) << "Failed to create multiplex codec index " << i;
113       return rv;
114     }
115     adapter_callbacks_.emplace_back(new AdapterEncodedImageCallback(
116         this, static_cast<AlphaCodecStream>(i)));
117     encoder->RegisterEncodeCompleteCallback(adapter_callbacks_.back().get());
118 
119     const EncoderInfo& encoder_impl_info = encoder->GetEncoderInfo();
120     encoder_info_.implementation_name += encoder_impl_info.implementation_name;
121     if (i != kAlphaCodecStreams - 1) {
122       encoder_info_.implementation_name += ", ";
123     }
124     // Uses hardware support if any of the encoders uses it.
125     // For example, if we are having issues with down-scaling due to
126     // pipelining delay in HW encoders we need higher encoder usage
127     // thresholds in CPU adaptation.
128     if (i == 0) {
129       encoder_info_.is_hardware_accelerated =
130           encoder_impl_info.is_hardware_accelerated;
131     } else {
132       encoder_info_.is_hardware_accelerated |=
133           encoder_impl_info.is_hardware_accelerated;
134     }
135 
136     encoder_info_.requested_resolution_alignment = cricket::LeastCommonMultiple(
137         encoder_info_.requested_resolution_alignment,
138         encoder_impl_info.requested_resolution_alignment);
139 
140     if (encoder_impl_info.apply_alignment_to_all_simulcast_layers) {
141       encoder_info_.apply_alignment_to_all_simulcast_layers = true;
142     }
143 
144     encoders_.emplace_back(std::move(encoder));
145   }
146   encoder_info_.implementation_name += ")";
147 
148   return WEBRTC_VIDEO_CODEC_OK;
149 }
150 
Encode(const VideoFrame & input_image,const std::vector<VideoFrameType> * frame_types)151 int MultiplexEncoderAdapter::Encode(
152     const VideoFrame& input_image,
153     const std::vector<VideoFrameType>* frame_types) {
154   if (!encoded_complete_callback_) {
155     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
156   }
157 
158   // The input image is forwarded as-is, unless it is a native buffer and
159   // `supports_augmented_data_` is true in which case we need to map it in order
160   // to access the underlying AugmentedVideoFrameBuffer.
161   VideoFrame forwarded_image = input_image;
162   if (supports_augmented_data_ &&
163       forwarded_image.video_frame_buffer()->type() ==
164           VideoFrameBuffer::Type::kNative) {
165     auto info = GetEncoderInfo();
166     rtc::scoped_refptr<VideoFrameBuffer> mapped_buffer =
167         forwarded_image.video_frame_buffer()->GetMappedFrameBuffer(
168             info.preferred_pixel_formats);
169     if (!mapped_buffer) {
170       // Unable to map the buffer.
171       return WEBRTC_VIDEO_CODEC_ERROR;
172     }
173     forwarded_image.set_video_frame_buffer(std::move(mapped_buffer));
174   }
175 
176   std::vector<VideoFrameType> adjusted_frame_types;
177   if (key_frame_interval_ > 0 && picture_index_ % key_frame_interval_ == 0) {
178     adjusted_frame_types.push_back(VideoFrameType::kVideoFrameKey);
179   } else {
180     adjusted_frame_types.push_back(VideoFrameType::kVideoFrameDelta);
181   }
182   const bool has_alpha = forwarded_image.video_frame_buffer()->type() ==
183                          VideoFrameBuffer::Type::kI420A;
184   std::unique_ptr<uint8_t[]> augmenting_data = nullptr;
185   uint16_t augmenting_data_length = 0;
186   AugmentedVideoFrameBuffer* augmented_video_frame_buffer = nullptr;
187   if (supports_augmented_data_) {
188     augmented_video_frame_buffer = static_cast<AugmentedVideoFrameBuffer*>(
189         forwarded_image.video_frame_buffer().get());
190     augmenting_data_length =
191         augmented_video_frame_buffer->GetAugmentingDataSize();
192     augmenting_data =
193         std::unique_ptr<uint8_t[]>(new uint8_t[augmenting_data_length]);
194     memcpy(augmenting_data.get(),
195            augmented_video_frame_buffer->GetAugmentingData(),
196            augmenting_data_length);
197     augmenting_data_size_ = augmenting_data_length;
198   }
199 
200   {
201     MutexLock lock(&mutex_);
202     stashed_images_.emplace(
203         std::piecewise_construct,
204         std::forward_as_tuple(forwarded_image.timestamp()),
205         std::forward_as_tuple(
206             picture_index_, has_alpha ? kAlphaCodecStreams : 1,
207             std::move(augmenting_data), augmenting_data_length));
208   }
209 
210   ++picture_index_;
211 
212   // Encode YUV
213   int rv =
214       encoders_[kYUVStream]->Encode(forwarded_image, &adjusted_frame_types);
215 
216   // If we do not receive an alpha frame, we send a single frame for this
217   // `picture_index_`. The receiver will receive `frame_count` as 1 which
218   // specifies this case.
219   if (rv || !has_alpha)
220     return rv;
221 
222   // Encode AXX
223   rtc::scoped_refptr<VideoFrameBuffer> frame_buffer =
224       supports_augmented_data_
225           ? augmented_video_frame_buffer->GetVideoFrameBuffer()
226           : forwarded_image.video_frame_buffer();
227   const I420ABufferInterface* yuva_buffer = frame_buffer->GetI420A();
228   rtc::scoped_refptr<I420BufferInterface> alpha_buffer =
229       WrapI420Buffer(forwarded_image.width(), forwarded_image.height(),
230                      yuva_buffer->DataA(), yuva_buffer->StrideA(),
231                      multiplex_dummy_planes_.data(), yuva_buffer->StrideU(),
232                      multiplex_dummy_planes_.data(), yuva_buffer->StrideV(),
233                      // To keep reference alive.
234                      [frame_buffer] {});
235   VideoFrame alpha_image =
236       VideoFrame::Builder()
237           .set_video_frame_buffer(alpha_buffer)
238           .set_timestamp_rtp(forwarded_image.timestamp())
239           .set_timestamp_ms(forwarded_image.render_time_ms())
240           .set_rotation(forwarded_image.rotation())
241           .set_id(forwarded_image.id())
242           .set_packet_infos(forwarded_image.packet_infos())
243           .build();
244   rv = encoders_[kAXXStream]->Encode(alpha_image, &adjusted_frame_types);
245   return rv;
246 }
247 
RegisterEncodeCompleteCallback(EncodedImageCallback * callback)248 int MultiplexEncoderAdapter::RegisterEncodeCompleteCallback(
249     EncodedImageCallback* callback) {
250   encoded_complete_callback_ = callback;
251   return WEBRTC_VIDEO_CODEC_OK;
252 }
253 
SetRates(const RateControlParameters & parameters)254 void MultiplexEncoderAdapter::SetRates(
255     const RateControlParameters& parameters) {
256   VideoBitrateAllocation bitrate_allocation(parameters.bitrate);
257   bitrate_allocation.SetBitrate(
258       0, 0, parameters.bitrate.GetBitrate(0, 0) - augmenting_data_size_);
259   for (auto& encoder : encoders_) {
260     // TODO(emircan): `framerate` is used to calculate duration in encoder
261     // instances. We report the total frame rate to keep real time for now.
262     // Remove this after refactoring duration logic.
263     encoder->SetRates(RateControlParameters(
264         bitrate_allocation,
265         static_cast<uint32_t>(encoders_.size() * parameters.framerate_fps),
266         parameters.bandwidth_allocation -
267             DataRate::BitsPerSec(augmenting_data_size_)));
268   }
269 }
270 
OnPacketLossRateUpdate(float packet_loss_rate)271 void MultiplexEncoderAdapter::OnPacketLossRateUpdate(float packet_loss_rate) {
272   for (auto& encoder : encoders_) {
273     encoder->OnPacketLossRateUpdate(packet_loss_rate);
274   }
275 }
276 
OnRttUpdate(int64_t rtt_ms)277 void MultiplexEncoderAdapter::OnRttUpdate(int64_t rtt_ms) {
278   for (auto& encoder : encoders_) {
279     encoder->OnRttUpdate(rtt_ms);
280   }
281 }
282 
OnLossNotification(const LossNotification & loss_notification)283 void MultiplexEncoderAdapter::OnLossNotification(
284     const LossNotification& loss_notification) {
285   for (auto& encoder : encoders_) {
286     encoder->OnLossNotification(loss_notification);
287   }
288 }
289 
Release()290 int MultiplexEncoderAdapter::Release() {
291   for (auto& encoder : encoders_) {
292     const int rv = encoder->Release();
293     if (rv)
294       return rv;
295   }
296   encoders_.clear();
297   adapter_callbacks_.clear();
298   MutexLock lock(&mutex_);
299   stashed_images_.clear();
300 
301   return WEBRTC_VIDEO_CODEC_OK;
302 }
303 
GetEncoderInfo() const304 VideoEncoder::EncoderInfo MultiplexEncoderAdapter::GetEncoderInfo() const {
305   return encoder_info_;
306 }
307 
OnEncodedImage(AlphaCodecStream stream_idx,const EncodedImage & encodedImage,const CodecSpecificInfo * codecSpecificInfo)308 EncodedImageCallback::Result MultiplexEncoderAdapter::OnEncodedImage(
309     AlphaCodecStream stream_idx,
310     const EncodedImage& encodedImage,
311     const CodecSpecificInfo* codecSpecificInfo) {
312   // Save the image
313   MultiplexImageComponent image_component;
314   image_component.component_index = stream_idx;
315   image_component.codec_type =
316       PayloadStringToCodecType(associated_format_.name);
317   image_component.encoded_image = encodedImage;
318 
319   MutexLock lock(&mutex_);
320   const auto& stashed_image_itr =
321       stashed_images_.find(encodedImage.Timestamp());
322   const auto& stashed_image_next_itr = std::next(stashed_image_itr, 1);
323   RTC_DCHECK(stashed_image_itr != stashed_images_.end());
324   MultiplexImage& stashed_image = stashed_image_itr->second;
325   const uint8_t frame_count = stashed_image.component_count;
326 
327   stashed_image.image_components.push_back(image_component);
328 
329   if (stashed_image.image_components.size() == frame_count) {
330     // Complete case
331     for (auto iter = stashed_images_.begin();
332          iter != stashed_images_.end() && iter != stashed_image_next_itr;
333          iter++) {
334       // No image at all, skip.
335       if (iter->second.image_components.size() == 0)
336         continue;
337 
338       // We have to send out those stashed frames, otherwise the delta frame
339       // dependency chain is broken.
340       combined_image_ =
341           MultiplexEncodedImagePacker::PackAndRelease(iter->second);
342 
343       CodecSpecificInfo codec_info = *codecSpecificInfo;
344       codec_info.codecType = kVideoCodecMultiplex;
345       encoded_complete_callback_->OnEncodedImage(combined_image_, &codec_info);
346     }
347 
348     stashed_images_.erase(stashed_images_.begin(), stashed_image_next_itr);
349   }
350   return EncodedImageCallback::Result(EncodedImageCallback::Result::OK);
351 }
352 
353 }  // namespace webrtc
354