xref: /aosp_15_r20/external/webrtc/test/fake_encoder.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2013 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 "test/fake_encoder.h"
12 
13 #include <string.h>
14 
15 #include <algorithm>
16 #include <cstdint>
17 #include <memory>
18 #include <string>
19 
20 #include "api/video/video_content_type.h"
21 #include "modules/video_coding/codecs/h264/include/h264_globals.h"
22 #include "modules/video_coding/include/video_codec_interface.h"
23 #include "modules/video_coding/include/video_error_codes.h"
24 #include "rtc_base/checks.h"
25 #include "system_wrappers/include/sleep.h"
26 
27 namespace webrtc {
28 namespace test {
29 namespace {
30 const int kKeyframeSizeFactor = 5;
31 
32 // Inverse of proportion of frames assigned to each temporal layer for all
33 // possible temporal layers numbers.
34 const int kTemporalLayerRateFactor[4][4] = {
35     {1, 0, 0, 0},  // 1/1
36     {2, 2, 0, 0},  // 1/2 + 1/2
37     {4, 4, 2, 0},  // 1/4 + 1/4 + 1/2
38     {8, 8, 4, 2},  // 1/8 + 1/8 + 1/4 + 1/2
39 };
40 
WriteCounter(unsigned char * payload,uint32_t counter)41 void WriteCounter(unsigned char* payload, uint32_t counter) {
42   payload[0] = (counter & 0x00FF);
43   payload[1] = (counter & 0xFF00) >> 8;
44   payload[2] = (counter & 0xFF0000) >> 16;
45   payload[3] = (counter & 0xFF000000) >> 24;
46 }
47 
48 }  // namespace
49 
FakeEncoder(Clock * clock)50 FakeEncoder::FakeEncoder(Clock* clock)
51     : clock_(clock),
52       num_initializations_(0),
53       callback_(nullptr),
54       max_target_bitrate_kbps_(-1),
55       pending_keyframe_(true),
56       counter_(0),
57       debt_bytes_(0) {
58   for (bool& used : used_layers_) {
59     used = false;
60   }
61 }
62 
SetFecControllerOverride(FecControllerOverride * fec_controller_override)63 void FakeEncoder::SetFecControllerOverride(
64     FecControllerOverride* fec_controller_override) {
65   // Ignored.
66 }
67 
SetMaxBitrate(int max_kbps)68 void FakeEncoder::SetMaxBitrate(int max_kbps) {
69   RTC_DCHECK_GE(max_kbps, -1);  // max_kbps == -1 disables it.
70   MutexLock lock(&mutex_);
71   max_target_bitrate_kbps_ = max_kbps;
72   SetRatesLocked(current_rate_settings_);
73 }
74 
SetQp(int qp)75 void FakeEncoder::SetQp(int qp) {
76   MutexLock lock(&mutex_);
77   qp_ = qp;
78 }
79 
InitEncode(const VideoCodec * config,const Settings & settings)80 int32_t FakeEncoder::InitEncode(const VideoCodec* config,
81                                 const Settings& settings) {
82   MutexLock lock(&mutex_);
83   config_ = *config;
84   ++num_initializations_;
85   current_rate_settings_.bitrate.SetBitrate(0, 0, config_.startBitrate * 1000);
86   current_rate_settings_.framerate_fps = config_.maxFramerate;
87   pending_keyframe_ = true;
88   last_frame_info_ = FrameInfo();
89   return 0;
90 }
91 
Encode(const VideoFrame & input_image,const std::vector<VideoFrameType> * frame_types)92 int32_t FakeEncoder::Encode(const VideoFrame& input_image,
93                             const std::vector<VideoFrameType>* frame_types) {
94   unsigned char max_framerate;
95   unsigned char num_simulcast_streams;
96   SimulcastStream simulcast_streams[kMaxSimulcastStreams];
97   EncodedImageCallback* callback;
98   RateControlParameters rates;
99   bool keyframe;
100   uint32_t counter;
101   absl::optional<int> qp;
102   {
103     MutexLock lock(&mutex_);
104     max_framerate = config_.maxFramerate;
105     num_simulcast_streams = config_.numberOfSimulcastStreams;
106     for (int i = 0; i < num_simulcast_streams; ++i) {
107       simulcast_streams[i] = config_.simulcastStream[i];
108     }
109     callback = callback_;
110     rates = current_rate_settings_;
111     if (rates.framerate_fps <= 0.0) {
112       rates.framerate_fps = max_framerate;
113     }
114     keyframe = pending_keyframe_;
115     pending_keyframe_ = false;
116     counter = counter_++;
117     qp = qp_;
118   }
119 
120   FrameInfo frame_info =
121       NextFrame(frame_types, keyframe, num_simulcast_streams, rates.bitrate,
122                 simulcast_streams, static_cast<int>(rates.framerate_fps + 0.5));
123   for (uint8_t i = 0; i < frame_info.layers.size(); ++i) {
124     constexpr int kMinPayLoadLength = 14;
125     if (frame_info.layers[i].size < kMinPayLoadLength) {
126       // Drop this temporal layer.
127       continue;
128     }
129 
130     auto buffer = EncodedImageBuffer::Create(frame_info.layers[i].size);
131     // Fill the buffer with arbitrary data. Write someting to make Asan happy.
132     memset(buffer->data(), 9, frame_info.layers[i].size);
133     // Write a counter to the image to make each frame unique.
134     WriteCounter(buffer->data() + frame_info.layers[i].size - 4, counter);
135 
136     EncodedImage encoded;
137     encoded.SetEncodedData(buffer);
138 
139     encoded.SetTimestamp(input_image.timestamp());
140     encoded._frameType = frame_info.keyframe ? VideoFrameType::kVideoFrameKey
141                                              : VideoFrameType::kVideoFrameDelta;
142     encoded._encodedWidth = simulcast_streams[i].width;
143     encoded._encodedHeight = simulcast_streams[i].height;
144     if (qp)
145       encoded.qp_ = *qp;
146     encoded.SetSpatialIndex(i);
147     CodecSpecificInfo codec_specific = EncodeHook(encoded, buffer);
148 
149     if (callback->OnEncodedImage(encoded, &codec_specific).error !=
150         EncodedImageCallback::Result::OK) {
151       return -1;
152     }
153   }
154   return 0;
155 }
156 
EncodeHook(EncodedImage & encoded_image,rtc::scoped_refptr<EncodedImageBuffer> buffer)157 CodecSpecificInfo FakeEncoder::EncodeHook(
158     EncodedImage& encoded_image,
159     rtc::scoped_refptr<EncodedImageBuffer> buffer) {
160   CodecSpecificInfo codec_specific;
161   codec_specific.codecType = kVideoCodecGeneric;
162   return codec_specific;
163 }
164 
NextFrame(const std::vector<VideoFrameType> * frame_types,bool keyframe,uint8_t num_simulcast_streams,const VideoBitrateAllocation & target_bitrate,SimulcastStream simulcast_streams[kMaxSimulcastStreams],int framerate)165 FakeEncoder::FrameInfo FakeEncoder::NextFrame(
166     const std::vector<VideoFrameType>* frame_types,
167     bool keyframe,
168     uint8_t num_simulcast_streams,
169     const VideoBitrateAllocation& target_bitrate,
170     SimulcastStream simulcast_streams[kMaxSimulcastStreams],
171     int framerate) {
172   FrameInfo frame_info;
173   frame_info.keyframe = keyframe;
174 
175   if (frame_types) {
176     for (VideoFrameType frame_type : *frame_types) {
177       if (frame_type == VideoFrameType::kVideoFrameKey) {
178         frame_info.keyframe = true;
179         break;
180       }
181     }
182   }
183 
184   MutexLock lock(&mutex_);
185   for (uint8_t i = 0; i < num_simulcast_streams; ++i) {
186     if (target_bitrate.GetBitrate(i, 0) > 0) {
187       int temporal_id = last_frame_info_.layers.size() > i
188                             ? ++last_frame_info_.layers[i].temporal_id %
189                                   simulcast_streams[i].numberOfTemporalLayers
190                             : 0;
191       frame_info.layers.emplace_back(0, temporal_id);
192     }
193   }
194 
195   if (last_frame_info_.layers.size() < frame_info.layers.size()) {
196     // A new keyframe is needed since a new layer will be added.
197     frame_info.keyframe = true;
198   }
199 
200   for (uint8_t i = 0; i < frame_info.layers.size(); ++i) {
201     FrameInfo::SpatialLayer& layer_info = frame_info.layers[i];
202     if (frame_info.keyframe) {
203       layer_info.temporal_id = 0;
204       size_t avg_frame_size =
205           (target_bitrate.GetBitrate(i, 0) + 7) *
206           kTemporalLayerRateFactor[frame_info.layers.size() - 1][i] /
207           (8 * framerate);
208 
209       // The first frame is a key frame and should be larger.
210       // Store the overshoot bytes and distribute them over the coming frames,
211       // so that we on average meet the bitrate target.
212       debt_bytes_ += (kKeyframeSizeFactor - 1) * avg_frame_size;
213       layer_info.size = kKeyframeSizeFactor * avg_frame_size;
214     } else {
215       size_t avg_frame_size =
216           (target_bitrate.GetBitrate(i, layer_info.temporal_id) + 7) *
217           kTemporalLayerRateFactor[frame_info.layers.size() - 1][i] /
218           (8 * framerate);
219       layer_info.size = avg_frame_size;
220       if (debt_bytes_ > 0) {
221         // Pay at most half of the frame size for old debts.
222         size_t payment_size = std::min(avg_frame_size / 2, debt_bytes_);
223         debt_bytes_ -= payment_size;
224         layer_info.size -= payment_size;
225       }
226     }
227   }
228   last_frame_info_ = frame_info;
229   return frame_info;
230 }
231 
RegisterEncodeCompleteCallback(EncodedImageCallback * callback)232 int32_t FakeEncoder::RegisterEncodeCompleteCallback(
233     EncodedImageCallback* callback) {
234   MutexLock lock(&mutex_);
235   callback_ = callback;
236   return 0;
237 }
238 
Release()239 int32_t FakeEncoder::Release() {
240   return 0;
241 }
242 
SetRates(const RateControlParameters & parameters)243 void FakeEncoder::SetRates(const RateControlParameters& parameters) {
244   MutexLock lock(&mutex_);
245   SetRatesLocked(parameters);
246 }
247 
SetRatesLocked(const RateControlParameters & parameters)248 void FakeEncoder::SetRatesLocked(const RateControlParameters& parameters) {
249   current_rate_settings_ = parameters;
250   int allocated_bitrate_kbps = parameters.bitrate.get_sum_kbps();
251 
252   // Scale bitrate allocation to not exceed the given max target bitrate.
253   if (max_target_bitrate_kbps_ > 0 &&
254       allocated_bitrate_kbps > max_target_bitrate_kbps_) {
255     for (uint8_t spatial_idx = 0; spatial_idx < kMaxSpatialLayers;
256          ++spatial_idx) {
257       for (uint8_t temporal_idx = 0; temporal_idx < kMaxTemporalStreams;
258            ++temporal_idx) {
259         if (current_rate_settings_.bitrate.HasBitrate(spatial_idx,
260                                                       temporal_idx)) {
261           uint32_t bitrate = current_rate_settings_.bitrate.GetBitrate(
262               spatial_idx, temporal_idx);
263           bitrate = static_cast<uint32_t>(
264               (bitrate * int64_t{max_target_bitrate_kbps_}) /
265               allocated_bitrate_kbps);
266           current_rate_settings_.bitrate.SetBitrate(spatial_idx, temporal_idx,
267                                                     bitrate);
268         }
269       }
270     }
271   }
272 }
273 
274 const char* FakeEncoder::kImplementationName = "fake_encoder";
GetEncoderInfo() const275 VideoEncoder::EncoderInfo FakeEncoder::GetEncoderInfo() const {
276   EncoderInfo info;
277   info.implementation_name = kImplementationName;
278   info.is_hardware_accelerated = true;
279   MutexLock lock(&mutex_);
280   for (int sid = 0; sid < config_.numberOfSimulcastStreams; ++sid) {
281     int number_of_temporal_layers =
282         config_.simulcastStream[sid].numberOfTemporalLayers;
283     info.fps_allocation[sid].clear();
284     for (int tid = 0; tid < number_of_temporal_layers; ++tid) {
285       // {1/4, 1/2, 1} allocation for num layers = 3.
286       info.fps_allocation[sid].push_back(255 /
287                                          (number_of_temporal_layers - tid));
288     }
289   }
290   return info;
291 }
292 
GetConfiguredInputFramerate() const293 int FakeEncoder::GetConfiguredInputFramerate() const {
294   MutexLock lock(&mutex_);
295   return static_cast<int>(current_rate_settings_.framerate_fps + 0.5);
296 }
297 
GetNumInitializations() const298 int FakeEncoder::GetNumInitializations() const {
299   MutexLock lock(&mutex_);
300   return num_initializations_;
301 }
302 
config() const303 const VideoCodec& FakeEncoder::config() const {
304   MutexLock lock(&mutex_);
305   return config_;
306 }
307 
FakeH264Encoder(Clock * clock)308 FakeH264Encoder::FakeH264Encoder(Clock* clock)
309     : FakeEncoder(clock), idr_counter_(0) {}
310 
EncodeHook(EncodedImage & encoded_image,rtc::scoped_refptr<EncodedImageBuffer> buffer)311 CodecSpecificInfo FakeH264Encoder::EncodeHook(
312     EncodedImage& encoded_image,
313     rtc::scoped_refptr<EncodedImageBuffer> buffer) {
314   static constexpr std::array<uint8_t, 3> kStartCode = {0, 0, 1};
315   const size_t kSpsSize = 8;
316   const size_t kPpsSize = 11;
317   const int kIdrFrequency = 10;
318   int current_idr_counter;
319   {
320     MutexLock lock(&local_mutex_);
321     current_idr_counter = idr_counter_;
322     ++idr_counter_;
323   }
324   for (size_t i = 0; i < encoded_image.size(); ++i) {
325     buffer->data()[i] = static_cast<uint8_t>(i);
326   }
327 
328   if (current_idr_counter % kIdrFrequency == 0 &&
329       encoded_image.size() > kSpsSize + kPpsSize + 1 + 3 * kStartCode.size()) {
330     const size_t kSpsNalHeader = 0x67;
331     const size_t kPpsNalHeader = 0x68;
332     const size_t kIdrNalHeader = 0x65;
333     uint8_t* data = buffer->data();
334     memcpy(data, kStartCode.data(), kStartCode.size());
335     data += kStartCode.size();
336     data[0] = kSpsNalHeader;
337     data += kSpsSize;
338 
339     memcpy(data, kStartCode.data(), kStartCode.size());
340     data += kStartCode.size();
341     data[0] = kPpsNalHeader;
342     data += kPpsSize;
343 
344     memcpy(data, kStartCode.data(), kStartCode.size());
345     data += kStartCode.size();
346     data[0] = kIdrNalHeader;
347   } else {
348     memcpy(buffer->data(), kStartCode.data(), kStartCode.size());
349     const size_t kNalHeader = 0x41;
350     buffer->data()[kStartCode.size()] = kNalHeader;
351   }
352 
353   CodecSpecificInfo codec_specific;
354   codec_specific.codecType = kVideoCodecH264;
355   codec_specific.codecSpecific.H264.packetization_mode =
356       H264PacketizationMode::NonInterleaved;
357   return codec_specific;
358 }
359 
DelayedEncoder(Clock * clock,int delay_ms)360 DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms)
361     : test::FakeEncoder(clock), delay_ms_(delay_ms) {
362   // The encoder could be created on a different thread than
363   // it is being used on.
364   sequence_checker_.Detach();
365 }
366 
SetDelay(int delay_ms)367 void DelayedEncoder::SetDelay(int delay_ms) {
368   RTC_DCHECK_RUN_ON(&sequence_checker_);
369   delay_ms_ = delay_ms;
370 }
371 
Encode(const VideoFrame & input_image,const std::vector<VideoFrameType> * frame_types)372 int32_t DelayedEncoder::Encode(const VideoFrame& input_image,
373                                const std::vector<VideoFrameType>* frame_types) {
374   RTC_DCHECK_RUN_ON(&sequence_checker_);
375 
376   SleepMs(delay_ms_);
377 
378   return FakeEncoder::Encode(input_image, frame_types);
379 }
380 
MultithreadedFakeH264Encoder(Clock * clock,TaskQueueFactory * task_queue_factory)381 MultithreadedFakeH264Encoder::MultithreadedFakeH264Encoder(
382     Clock* clock,
383     TaskQueueFactory* task_queue_factory)
384     : test::FakeH264Encoder(clock),
385       task_queue_factory_(task_queue_factory),
386       current_queue_(0),
387       queue1_(nullptr),
388       queue2_(nullptr) {
389   // The encoder could be created on a different thread than
390   // it is being used on.
391   sequence_checker_.Detach();
392 }
393 
InitEncode(const VideoCodec * config,const Settings & settings)394 int32_t MultithreadedFakeH264Encoder::InitEncode(const VideoCodec* config,
395                                                  const Settings& settings) {
396   RTC_DCHECK_RUN_ON(&sequence_checker_);
397 
398   queue1_ = task_queue_factory_->CreateTaskQueue(
399       "Queue 1", TaskQueueFactory::Priority::NORMAL);
400   queue2_ = task_queue_factory_->CreateTaskQueue(
401       "Queue 2", TaskQueueFactory::Priority::NORMAL);
402 
403   return FakeH264Encoder::InitEncode(config, settings);
404 }
405 
Encode(const VideoFrame & input_image,const std::vector<VideoFrameType> * frame_types)406 int32_t MultithreadedFakeH264Encoder::Encode(
407     const VideoFrame& input_image,
408     const std::vector<VideoFrameType>* frame_types) {
409   RTC_DCHECK_RUN_ON(&sequence_checker_);
410 
411   TaskQueueBase* queue =
412       (current_queue_++ % 2 == 0) ? queue1_.get() : queue2_.get();
413 
414   if (!queue) {
415     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
416   }
417 
418   queue->PostTask([this, input_image, frame_types = *frame_types] {
419     EncodeCallback(input_image, &frame_types);
420   });
421 
422   return WEBRTC_VIDEO_CODEC_OK;
423 }
424 
EncodeCallback(const VideoFrame & input_image,const std::vector<VideoFrameType> * frame_types)425 int32_t MultithreadedFakeH264Encoder::EncodeCallback(
426     const VideoFrame& input_image,
427     const std::vector<VideoFrameType>* frame_types) {
428   return FakeH264Encoder::Encode(input_image, frame_types);
429 }
430 
Release()431 int32_t MultithreadedFakeH264Encoder::Release() {
432   RTC_DCHECK_RUN_ON(&sequence_checker_);
433 
434   queue1_.reset();
435   queue2_.reset();
436 
437   return FakeH264Encoder::Release();
438 }
439 
440 }  // namespace test
441 }  // namespace webrtc
442