blob: 4736870d98ca1ea469d940774adef2d19b271aa7 [file] [log] [blame]
stefan@webrtc.org360e3762013-08-22 09:29:56 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "test/fake_encoder.h"
stefan@webrtc.org360e3762013-08-22 09:29:56 +000012
brandtre78d2662017-01-16 05:57:16 -080013#include <string.h>
14
palmkviste75f2042016-09-28 06:19:48 -070015#include <algorithm>
brandtre78d2662017-01-16 05:57:16 -080016#include <memory>
palmkviste75f2042016-09-28 06:19:48 -070017
Erik Språng4529fbc2018-10-12 10:30:31 +020018#include "api/video_codecs/vp8_temporal_layers.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020019#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/video_coding/include/video_codec_interface.h"
21#include "rtc_base/checks.h"
22#include "system_wrappers/include/sleep.h"
pbos@webrtc.orgab990ae2014-09-17 09:02:25 +000023
stefan@webrtc.org360e3762013-08-22 09:29:56 +000024namespace webrtc {
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000025namespace test {
Per Kjellander17fc7e22018-11-06 11:01:06 +010026namespace {
Ilya Nikolaevskiy6003e7a2018-10-15 10:47:23 +020027const int kKeyframeSizeFactor = 5;
28
29// Inverse of proportion of frames assigned to each temporal layer for all
30// possible temporal layers numbers.
31const int kTemporalLayerRateFactor[4][4] = {
32 {1, 0, 0, 0}, // 1/1
33 {2, 2, 0, 0}, // 1/2 + 1/2
34 {4, 4, 2, 0}, // 1/4 + 1/4 + 1/2
35 {8, 8, 4, 2}, // 1/8 + 1/8 + 1/4 + 1/2
36};
sprang4847ae62017-06-27 07:06:52 -070037
Per Kjellander17fc7e22018-11-06 11:01:06 +010038void WriteCounter(unsigned char* payload, uint32_t counter) {
39 payload[0] = (counter & 0x00FF);
40 payload[1] = (counter & 0xFF00) >> 8;
41 payload[2] = (counter & 0xFF0000) >> 16;
42 payload[3] = (counter & 0xFF000000) >> 24;
43}
44
45}; // namespace
46
stefan@webrtc.org360e3762013-08-22 09:29:56 +000047FakeEncoder::FakeEncoder(Clock* clock)
48 : clock_(clock),
brandtre78d2662017-01-16 05:57:16 -080049 callback_(nullptr),
sprang4847ae62017-06-27 07:06:52 -070050 configured_input_framerate_(-1),
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000051 max_target_bitrate_kbps_(-1),
sprang4847ae62017-06-27 07:06:52 -070052 pending_keyframe_(true),
Per Kjellander17fc7e22018-11-06 11:01:06 +010053 counter_(0),
sprang4847ae62017-06-27 07:06:52 -070054 debt_bytes_(0) {
sprang@webrtc.org40709352013-11-26 11:41:59 +000055 // Generate some arbitrary not-all-zero data
56 for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) {
57 encoded_buffer_[i] = static_cast<uint8_t>(i);
58 }
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020059 for (bool& used : used_layers_) {
60 used = false;
61 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +000062}
63
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000064void FakeEncoder::SetMaxBitrate(int max_kbps) {
perkj26091b12016-09-01 01:17:40 -070065 RTC_DCHECK_GE(max_kbps, -1); // max_kbps == -1 disables it.
brandtre78d2662017-01-16 05:57:16 -080066 rtc::CritScope cs(&crit_sect_);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000067 max_target_bitrate_kbps_ = max_kbps;
68}
69
stefan@webrtc.org360e3762013-08-22 09:29:56 +000070int32_t FakeEncoder::InitEncode(const VideoCodec* config,
71 int32_t number_of_cores,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000072 size_t max_payload_size) {
brandtre78d2662017-01-16 05:57:16 -080073 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +000074 config_ = *config;
Erik Språng08127a92016-11-16 16:41:30 +010075 target_bitrate_.SetBitrate(0, 0, config_.startBitrate * 1000);
sprang4847ae62017-06-27 07:06:52 -070076 configured_input_framerate_ = config_.maxFramerate;
77 pending_keyframe_ = true;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020078 last_frame_info_ = FrameInfo();
stefan@webrtc.org360e3762013-08-22 09:29:56 +000079 return 0;
80}
81
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070082int32_t FakeEncoder::Encode(const VideoFrame& input_image,
83 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -070084 const std::vector<FrameType>* frame_types) {
brandtre78d2662017-01-16 05:57:16 -080085 unsigned char max_framerate;
86 unsigned char num_simulcast_streams;
87 SimulcastStream simulcast_streams[kMaxSimulcastStreams];
88 EncodedImageCallback* callback;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020089 VideoBitrateAllocation target_bitrate;
sprang4847ae62017-06-27 07:06:52 -070090 int framerate;
ilnik00d802b2017-04-11 10:34:31 -070091 VideoCodecMode mode;
sprang4847ae62017-06-27 07:06:52 -070092 bool keyframe;
Per Kjellander17fc7e22018-11-06 11:01:06 +010093 uint32_t counter;
brandtre78d2662017-01-16 05:57:16 -080094 {
95 rtc::CritScope cs(&crit_sect_);
96 max_framerate = config_.maxFramerate;
97 num_simulcast_streams = config_.numberOfSimulcastStreams;
98 for (int i = 0; i < num_simulcast_streams; ++i) {
99 simulcast_streams[i] = config_.simulcastStream[i];
100 }
101 callback = callback_;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200102 target_bitrate = target_bitrate_;
ilnik00d802b2017-04-11 10:34:31 -0700103 mode = config_.mode;
sprang4847ae62017-06-27 07:06:52 -0700104 if (configured_input_framerate_ > 0) {
105 framerate = configured_input_framerate_;
106 } else {
107 framerate = max_framerate;
108 }
109 keyframe = pending_keyframe_;
110 pending_keyframe_ = false;
Per Kjellander17fc7e22018-11-06 11:01:06 +0100111 counter = counter_++;
brandtre78d2662017-01-16 05:57:16 -0800112 }
113
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200114 FrameInfo frame_info =
115 NextFrame(frame_types, keyframe, num_simulcast_streams, target_bitrate,
116 simulcast_streams, framerate);
117 for (uint8_t i = 0; i < frame_info.layers.size(); ++i) {
Per Kjellander17fc7e22018-11-06 11:01:06 +0100118 constexpr int kMinPayLoadLength = 14;
Per Kjellander841c9122018-10-04 18:40:28 +0200119 if (frame_info.layers[i].size < kMinPayLoadLength) {
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200120 // Drop this temporal layer.
121 continue;
sprang4847ae62017-06-27 07:06:52 -0700122 }
sprang4847ae62017-06-27 07:06:52 -0700123
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000124 CodecSpecificInfo specifics;
125 memset(&specifics, 0, sizeof(specifics));
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000126 specifics.codecType = kVideoCodecGeneric;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200127 std::unique_ptr<uint8_t[]> encoded_buffer(
128 new uint8_t[frame_info.layers[i].size]);
Per Kjellander17fc7e22018-11-06 11:01:06 +0100129 memcpy(encoded_buffer.get(), encoded_buffer_,
130 frame_info.layers[i].size - 4);
131 // Write a counter to the image to make each frame unique.
132 WriteCounter(encoded_buffer.get() + frame_info.layers[i].size - 4, counter);
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200133 EncodedImage encoded(encoded_buffer.get(), frame_info.layers[i].size,
134 sizeof(encoded_buffer_));
Niels Möller72bc8d62018-09-12 10:03:51 +0200135 encoded.SetTimestamp(input_image.timestamp());
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000136 encoded.capture_time_ms_ = input_image.render_time_ms();
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200137 encoded._frameType =
138 frame_info.keyframe ? kVideoFrameKey : kVideoFrameDelta;
brandtre78d2662017-01-16 05:57:16 -0800139 encoded._encodedWidth = simulcast_streams[i].width;
140 encoded._encodedHeight = simulcast_streams[i].height;
perkj803d97f2016-11-01 11:45:46 -0700141 encoded.rotation_ = input_image.rotation();
Niels Möllere3cf3d02018-06-13 11:52:16 +0200142 encoded.content_type_ = (mode == VideoCodecMode::kScreensharing)
ilnik00d802b2017-04-11 10:34:31 -0700143 ? VideoContentType::SCREENSHARE
144 : VideoContentType::UNSPECIFIED;
Niels Möllerd3b8c632018-08-27 15:33:42 +0200145 encoded.SetSpatialIndex(i);
brandtre78d2662017-01-16 05:57:16 -0800146 if (callback->OnEncodedImage(encoded, &specifics, nullptr).error !=
sergeyu2cb155a2016-11-04 11:39:29 -0700147 EncodedImageCallback::Result::OK) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000148 return -1;
sergeyu2cb155a2016-11-04 11:39:29 -0700149 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000150 }
151 return 0;
152}
153
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200154FakeEncoder::FrameInfo FakeEncoder::NextFrame(
155 const std::vector<FrameType>* frame_types,
156 bool keyframe,
157 uint8_t num_simulcast_streams,
158 const VideoBitrateAllocation& target_bitrate,
159 SimulcastStream simulcast_streams[kMaxSimulcastStreams],
160 int framerate) {
161 FrameInfo frame_info;
162 frame_info.keyframe = keyframe;
163
164 if (frame_types) {
165 for (FrameType frame_type : *frame_types) {
166 if (frame_type == kVideoFrameKey) {
167 frame_info.keyframe = true;
168 break;
169 }
170 }
171 }
172
Yves Gerey04140402018-10-08 11:39:18 +0200173 rtc::CritScope cs(&crit_sect_);
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200174 for (uint8_t i = 0; i < num_simulcast_streams; ++i) {
175 if (target_bitrate.GetBitrate(i, 0) > 0) {
176 int temporal_id = last_frame_info_.layers.size() > i
177 ? ++last_frame_info_.layers[i].temporal_id %
178 simulcast_streams[i].numberOfTemporalLayers
179 : 0;
180 frame_info.layers.emplace_back(0, temporal_id);
181 }
182 }
183
184 if (last_frame_info_.layers.size() < frame_info.layers.size()) {
185 // A new keyframe is needed since a new layer will be added.
186 frame_info.keyframe = true;
187 }
188
189 for (uint8_t i = 0; i < frame_info.layers.size(); ++i) {
190 FrameInfo::SpatialLayer& layer_info = frame_info.layers[i];
191 if (frame_info.keyframe) {
192 layer_info.temporal_id = 0;
193 size_t avg_frame_size =
Ilya Nikolaevskiy6003e7a2018-10-15 10:47:23 +0200194 (target_bitrate.GetBitrate(i, 0) + 7) *
195 kTemporalLayerRateFactor[frame_info.layers.size() - 1][i] /
196 (8 * framerate);
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200197
198 // The first frame is a key frame and should be larger.
199 // Store the overshoot bytes and distribute them over the coming frames,
200 // so that we on average meet the bitrate target.
201 debt_bytes_ += (kKeyframeSizeFactor - 1) * avg_frame_size;
202 layer_info.size = kKeyframeSizeFactor * avg_frame_size;
203 } else {
204 size_t avg_frame_size =
Ilya Nikolaevskiy6003e7a2018-10-15 10:47:23 +0200205 (target_bitrate.GetBitrate(i, layer_info.temporal_id) + 7) *
206 kTemporalLayerRateFactor[frame_info.layers.size() - 1][i] /
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200207 (8 * framerate);
208 layer_info.size = avg_frame_size;
209 if (debt_bytes_ > 0) {
210 // Pay at most half of the frame size for old debts.
211 size_t payment_size = std::min(avg_frame_size / 2, debt_bytes_);
212 debt_bytes_ -= payment_size;
213 layer_info.size -= payment_size;
214 }
215 }
216 }
217 last_frame_info_ = frame_info;
218 return frame_info;
219}
220
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000221int32_t FakeEncoder::RegisterEncodeCompleteCallback(
222 EncodedImageCallback* callback) {
brandtre78d2662017-01-16 05:57:16 -0800223 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000224 callback_ = callback;
225 return 0;
226}
227
Yves Gerey665174f2018-06-19 15:03:05 +0200228int32_t FakeEncoder::Release() {
229 return 0;
230}
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000231
Erik Språng566124a2018-04-23 12:32:22 +0200232int32_t FakeEncoder::SetRateAllocation(
233 const VideoBitrateAllocation& rate_allocation,
234 uint32_t framerate) {
brandtre78d2662017-01-16 05:57:16 -0800235 rtc::CritScope cs(&crit_sect_);
Erik Språng08127a92016-11-16 16:41:30 +0100236 target_bitrate_ = rate_allocation;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200237 int allocated_bitrate_kbps = target_bitrate_.get_sum_kbps();
238
239 // Scale bitrate allocation to not exceed the given max target bitrate.
240 if (max_target_bitrate_kbps_ > 0 &&
241 allocated_bitrate_kbps > max_target_bitrate_kbps_) {
242 for (uint8_t spatial_idx = 0; spatial_idx < kMaxSpatialLayers;
243 ++spatial_idx) {
244 for (uint8_t temporal_idx = 0; temporal_idx < kMaxTemporalStreams;
245 ++temporal_idx) {
246 if (target_bitrate_.HasBitrate(spatial_idx, temporal_idx)) {
247 uint32_t bitrate =
248 target_bitrate_.GetBitrate(spatial_idx, temporal_idx);
249 bitrate = static_cast<uint32_t>(
250 (bitrate * int64_t{max_target_bitrate_kbps_}) /
251 allocated_bitrate_kbps);
252 target_bitrate_.SetBitrate(spatial_idx, temporal_idx, bitrate);
253 }
254 }
255 }
256 }
257
sprang4847ae62017-06-27 07:06:52 -0700258 configured_input_framerate_ = framerate;
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000259 return 0;
260}
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000261
Peter Boströmb7d9a972015-12-18 16:01:11 +0100262const char* FakeEncoder::kImplementationName = "fake_encoder";
Erik Språngdf351f42018-11-06 11:33:15 +0100263VideoEncoder::EncoderInfo FakeEncoder::GetEncoderInfo() const {
264 EncoderInfo info;
265 info.implementation_name = kImplementationName;
266 return info;
Peter Boströmb7d9a972015-12-18 16:01:11 +0100267}
268
sprang4847ae62017-06-27 07:06:52 -0700269int FakeEncoder::GetConfiguredInputFramerate() const {
270 rtc::CritScope cs(&crit_sect_);
271 return configured_input_framerate_;
272}
273
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000274FakeH264Encoder::FakeH264Encoder(Clock* clock)
brandtre78d2662017-01-16 05:57:16 -0800275 : FakeEncoder(clock), callback_(nullptr), idr_counter_(0) {
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000276 FakeEncoder::RegisterEncodeCompleteCallback(this);
277}
278
279int32_t FakeH264Encoder::RegisterEncodeCompleteCallback(
280 EncodedImageCallback* callback) {
brandtre78d2662017-01-16 05:57:16 -0800281 rtc::CritScope cs(&local_crit_sect_);
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000282 callback_ = callback;
283 return 0;
284}
285
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700286EncodedImageCallback::Result FakeH264Encoder::OnEncodedImage(
287 const EncodedImage& encoded_image,
288 const CodecSpecificInfo* codec_specific_info,
289 const RTPFragmentationHeader* fragments) {
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000290 const size_t kSpsSize = 8;
291 const size_t kPpsSize = 11;
292 const int kIdrFrequency = 10;
brandtre78d2662017-01-16 05:57:16 -0800293 EncodedImageCallback* callback;
294 int current_idr_counter;
295 {
296 rtc::CritScope cs(&local_crit_sect_);
297 callback = callback_;
298 current_idr_counter = idr_counter_;
299 ++idr_counter_;
300 }
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000301 RTPFragmentationHeader fragmentation;
brandtre78d2662017-01-16 05:57:16 -0800302 if (current_idr_counter % kIdrFrequency == 0 &&
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000303 encoded_image._length > kSpsSize + kPpsSize + 1) {
304 const size_t kNumSlices = 3;
305 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
306 fragmentation.fragmentationOffset[0] = 0;
307 fragmentation.fragmentationLength[0] = kSpsSize;
308 fragmentation.fragmentationOffset[1] = kSpsSize;
309 fragmentation.fragmentationLength[1] = kPpsSize;
310 fragmentation.fragmentationOffset[2] = kSpsSize + kPpsSize;
311 fragmentation.fragmentationLength[2] =
312 encoded_image._length - (kSpsSize + kPpsSize);
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000313 const size_t kSpsNalHeader = 0x67;
314 const size_t kPpsNalHeader = 0x68;
315 const size_t kIdrNalHeader = 0x65;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000316 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kSpsNalHeader;
317 encoded_image._buffer[fragmentation.fragmentationOffset[1]] = kPpsNalHeader;
318 encoded_image._buffer[fragmentation.fragmentationOffset[2]] = kIdrNalHeader;
319 } else {
320 const size_t kNumSlices = 1;
321 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
322 fragmentation.fragmentationOffset[0] = 0;
323 fragmentation.fragmentationLength[0] = encoded_image._length;
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000324 const size_t kNalHeader = 0x41;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000325 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kNalHeader;
326 }
327 uint8_t value = 0;
328 int fragment_counter = 0;
329 for (size_t i = 0; i < encoded_image._length; ++i) {
330 if (fragment_counter == fragmentation.fragmentationVectorSize ||
331 i != fragmentation.fragmentationOffset[fragment_counter]) {
332 encoded_image._buffer[i] = value++;
333 } else {
334 ++fragment_counter;
335 }
336 }
palmkviste75f2042016-09-28 06:19:48 -0700337 CodecSpecificInfo specifics;
338 memset(&specifics, 0, sizeof(specifics));
339 specifics.codecType = kVideoCodecH264;
hta9aa96882016-12-06 05:36:03 -0800340 specifics.codecSpecific.H264.packetization_mode =
341 H264PacketizationMode::NonInterleaved;
brandtre78d2662017-01-16 05:57:16 -0800342 RTC_DCHECK(callback);
343 return callback->OnEncodedImage(encoded_image, &specifics, &fragmentation);
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000344}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000345
346DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms)
brandtr49ce67c2017-02-11 00:25:18 -0800347 : test::FakeEncoder(clock), delay_ms_(delay_ms) {
348 // The encoder could be created on a different thread than
349 // it is being used on.
350 sequence_checker_.Detach();
351}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000352
perkj803d97f2016-11-01 11:45:46 -0700353void DelayedEncoder::SetDelay(int delay_ms) {
brandtr49ce67c2017-02-11 00:25:18 -0800354 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
perkj803d97f2016-11-01 11:45:46 -0700355 delay_ms_ = delay_ms;
356}
357
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700358int32_t DelayedEncoder::Encode(const VideoFrame& input_image,
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000359 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700360 const std::vector<FrameType>* frame_types) {
brandtr49ce67c2017-02-11 00:25:18 -0800361 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
362
363 SleepMs(delay_ms_);
364
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000365 return FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
366}
brandtr696c9c62016-12-19 05:47:28 -0800367
brandtre78d2662017-01-16 05:57:16 -0800368MultithreadedFakeH264Encoder::MultithreadedFakeH264Encoder(Clock* clock)
brandtr696c9c62016-12-19 05:47:28 -0800369 : test::FakeH264Encoder(clock),
370 current_queue_(0),
brandtr49ce67c2017-02-11 00:25:18 -0800371 queue1_(nullptr),
372 queue2_(nullptr) {
373 // The encoder could be created on a different thread than
374 // it is being used on.
375 sequence_checker_.Detach();
376}
brandtr696c9c62016-12-19 05:47:28 -0800377
brandtr49ce67c2017-02-11 00:25:18 -0800378int32_t MultithreadedFakeH264Encoder::InitEncode(const VideoCodec* config,
379 int32_t number_of_cores,
380 size_t max_payload_size) {
381 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
382
383 queue1_.reset(new rtc::TaskQueue("Queue 1"));
384 queue2_.reset(new rtc::TaskQueue("Queue 2"));
385
386 return FakeH264Encoder::InitEncode(config, number_of_cores, max_payload_size);
387}
brandtr696c9c62016-12-19 05:47:28 -0800388
brandtre78d2662017-01-16 05:57:16 -0800389class MultithreadedFakeH264Encoder::EncodeTask : public rtc::QueuedTask {
brandtr696c9c62016-12-19 05:47:28 -0800390 public:
brandtre78d2662017-01-16 05:57:16 -0800391 EncodeTask(MultithreadedFakeH264Encoder* encoder,
brandtr696c9c62016-12-19 05:47:28 -0800392 const VideoFrame& input_image,
393 const CodecSpecificInfo* codec_specific_info,
394 const std::vector<FrameType>* frame_types)
395 : encoder_(encoder),
396 input_image_(input_image),
397 codec_specific_info_(),
398 frame_types_(*frame_types) {
399 if (codec_specific_info)
400 codec_specific_info_ = *codec_specific_info;
401 }
402
403 private:
404 bool Run() override {
405 encoder_->EncodeCallback(input_image_, &codec_specific_info_,
406 &frame_types_);
407 return true;
408 }
409
brandtre78d2662017-01-16 05:57:16 -0800410 MultithreadedFakeH264Encoder* const encoder_;
brandtr696c9c62016-12-19 05:47:28 -0800411 VideoFrame input_image_;
412 CodecSpecificInfo codec_specific_info_;
413 std::vector<FrameType> frame_types_;
414};
415
brandtre78d2662017-01-16 05:57:16 -0800416int32_t MultithreadedFakeH264Encoder::Encode(
brandtr696c9c62016-12-19 05:47:28 -0800417 const VideoFrame& input_image,
418 const CodecSpecificInfo* codec_specific_info,
419 const std::vector<FrameType>* frame_types) {
brandtr49ce67c2017-02-11 00:25:18 -0800420 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtr696c9c62016-12-19 05:47:28 -0800421
brandtr49ce67c2017-02-11 00:25:18 -0800422 std::unique_ptr<rtc::TaskQueue>& queue =
423 (current_queue_++ % 2 == 0) ? queue1_ : queue2_;
424
425 if (!queue) {
426 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
427 }
428
429 queue->PostTask(std::unique_ptr<rtc::QueuedTask>(
brandtr696c9c62016-12-19 05:47:28 -0800430 new EncodeTask(this, input_image, codec_specific_info, frame_types)));
431
brandtr49ce67c2017-02-11 00:25:18 -0800432 return WEBRTC_VIDEO_CODEC_OK;
brandtr696c9c62016-12-19 05:47:28 -0800433}
434
brandtre78d2662017-01-16 05:57:16 -0800435int32_t MultithreadedFakeH264Encoder::EncodeCallback(
brandtr696c9c62016-12-19 05:47:28 -0800436 const VideoFrame& input_image,
437 const CodecSpecificInfo* codec_specific_info,
438 const std::vector<FrameType>* frame_types) {
439 return FakeH264Encoder::Encode(input_image, codec_specific_info, frame_types);
440}
441
brandtr49ce67c2017-02-11 00:25:18 -0800442int32_t MultithreadedFakeH264Encoder::Release() {
443 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
444
445 queue1_.reset();
446 queue2_.reset();
447
448 return FakeH264Encoder::Release();
449}
450
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +0000451} // namespace test
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000452} // namespace webrtc