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