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