blob: b8d04e67b0e12156ace333aa8629f4948ac154db [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
Mirko Bonadei71207422017-09-15 13:58:09 +020018#include "common_types.h" // NOLINT(build/include)
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020019#include "modules/video_coding/codecs/vp8/temporal_layers.h"
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 {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000026
sprang4847ae62017-06-27 07:06:52 -070027const int kKeyframeSizeFactor = 10;
28
stefan@webrtc.org360e3762013-08-22 09:29:56 +000029FakeEncoder::FakeEncoder(Clock* clock)
30 : clock_(clock),
brandtre78d2662017-01-16 05:57:16 -080031 callback_(nullptr),
sprang4847ae62017-06-27 07:06:52 -070032 configured_input_framerate_(-1),
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000033 max_target_bitrate_kbps_(-1),
sprang4847ae62017-06-27 07:06:52 -070034 pending_keyframe_(true),
35 debt_bytes_(0) {
sprang@webrtc.org40709352013-11-26 11:41:59 +000036 // Generate some arbitrary not-all-zero data
37 for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) {
38 encoded_buffer_[i] = static_cast<uint8_t>(i);
39 }
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020040 for (bool& used : used_layers_) {
41 used = false;
42 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +000043}
44
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000045void FakeEncoder::SetMaxBitrate(int max_kbps) {
perkj26091b12016-09-01 01:17:40 -070046 RTC_DCHECK_GE(max_kbps, -1); // max_kbps == -1 disables it.
brandtre78d2662017-01-16 05:57:16 -080047 rtc::CritScope cs(&crit_sect_);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000048 max_target_bitrate_kbps_ = max_kbps;
49}
50
stefan@webrtc.org360e3762013-08-22 09:29:56 +000051int32_t FakeEncoder::InitEncode(const VideoCodec* config,
52 int32_t number_of_cores,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000053 size_t max_payload_size) {
brandtre78d2662017-01-16 05:57:16 -080054 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +000055 config_ = *config;
Erik Språng08127a92016-11-16 16:41:30 +010056 target_bitrate_.SetBitrate(0, 0, config_.startBitrate * 1000);
sprang4847ae62017-06-27 07:06:52 -070057 configured_input_framerate_ = config_.maxFramerate;
58 pending_keyframe_ = true;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020059 last_frame_info_ = FrameInfo();
stefan@webrtc.org360e3762013-08-22 09:29:56 +000060 return 0;
61}
62
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070063int32_t FakeEncoder::Encode(const VideoFrame& input_image,
64 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -070065 const std::vector<FrameType>* frame_types) {
brandtre78d2662017-01-16 05:57:16 -080066 unsigned char max_framerate;
67 unsigned char num_simulcast_streams;
68 SimulcastStream simulcast_streams[kMaxSimulcastStreams];
69 EncodedImageCallback* callback;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020070 VideoBitrateAllocation target_bitrate;
sprang4847ae62017-06-27 07:06:52 -070071 int framerate;
ilnik00d802b2017-04-11 10:34:31 -070072 VideoCodecMode mode;
sprang4847ae62017-06-27 07:06:52 -070073 bool keyframe;
brandtre78d2662017-01-16 05:57:16 -080074 {
75 rtc::CritScope cs(&crit_sect_);
76 max_framerate = config_.maxFramerate;
77 num_simulcast_streams = config_.numberOfSimulcastStreams;
78 for (int i = 0; i < num_simulcast_streams; ++i) {
79 simulcast_streams[i] = config_.simulcastStream[i];
80 }
81 callback = callback_;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020082 target_bitrate = target_bitrate_;
ilnik00d802b2017-04-11 10:34:31 -070083 mode = config_.mode;
sprang4847ae62017-06-27 07:06:52 -070084 if (configured_input_framerate_ > 0) {
85 framerate = configured_input_framerate_;
86 } else {
87 framerate = max_framerate;
88 }
89 keyframe = pending_keyframe_;
90 pending_keyframe_ = false;
brandtre78d2662017-01-16 05:57:16 -080091 }
92
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020093 FrameInfo frame_info =
94 NextFrame(frame_types, keyframe, num_simulcast_streams, target_bitrate,
95 simulcast_streams, framerate);
96 for (uint8_t i = 0; i < frame_info.layers.size(); ++i) {
97 if (frame_info.layers[i].size == 0) {
98 // Drop this temporal layer.
99 continue;
sprang4847ae62017-06-27 07:06:52 -0700100 }
sprang4847ae62017-06-27 07:06:52 -0700101
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000102 CodecSpecificInfo specifics;
103 memset(&specifics, 0, sizeof(specifics));
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000104 specifics.codecType = kVideoCodecGeneric;
105 specifics.codecSpecific.generic.simulcast_idx = i;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200106 std::unique_ptr<uint8_t[]> encoded_buffer(
107 new uint8_t[frame_info.layers[i].size]);
108 memcpy(encoded_buffer.get(), encoded_buffer_, frame_info.layers[i].size);
109 EncodedImage encoded(encoded_buffer.get(), frame_info.layers[i].size,
110 sizeof(encoded_buffer_));
111 encoded._timeStamp = input_image.timestamp();
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000112 encoded.capture_time_ms_ = input_image.render_time_ms();
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200113 encoded._frameType =
114 frame_info.keyframe ? kVideoFrameKey : kVideoFrameDelta;
brandtre78d2662017-01-16 05:57:16 -0800115 encoded._encodedWidth = simulcast_streams[i].width;
116 encoded._encodedHeight = simulcast_streams[i].height;
perkj803d97f2016-11-01 11:45:46 -0700117 encoded.rotation_ = input_image.rotation();
Niels Möllere3cf3d02018-06-13 11:52:16 +0200118 encoded.content_type_ = (mode == VideoCodecMode::kScreensharing)
ilnik00d802b2017-04-11 10:34:31 -0700119 ? VideoContentType::SCREENSHARE
120 : VideoContentType::UNSPECIFIED;
perkj275afc52016-09-01 00:21:16 -0700121 specifics.codec_name = ImplementationName();
brandtre78d2662017-01-16 05:57:16 -0800122 if (callback->OnEncodedImage(encoded, &specifics, nullptr).error !=
sergeyu2cb155a2016-11-04 11:39:29 -0700123 EncodedImageCallback::Result::OK) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000124 return -1;
sergeyu2cb155a2016-11-04 11:39:29 -0700125 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000126 }
127 return 0;
128}
129
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200130FakeEncoder::FrameInfo FakeEncoder::NextFrame(
131 const std::vector<FrameType>* frame_types,
132 bool keyframe,
133 uint8_t num_simulcast_streams,
134 const VideoBitrateAllocation& target_bitrate,
135 SimulcastStream simulcast_streams[kMaxSimulcastStreams],
136 int framerate) {
137 FrameInfo frame_info;
138 frame_info.keyframe = keyframe;
139
140 if (frame_types) {
141 for (FrameType frame_type : *frame_types) {
142 if (frame_type == kVideoFrameKey) {
143 frame_info.keyframe = true;
144 break;
145 }
146 }
147 }
148
149 for (uint8_t i = 0; i < num_simulcast_streams; ++i) {
150 if (target_bitrate.GetBitrate(i, 0) > 0) {
151 int temporal_id = last_frame_info_.layers.size() > i
152 ? ++last_frame_info_.layers[i].temporal_id %
153 simulcast_streams[i].numberOfTemporalLayers
154 : 0;
155 frame_info.layers.emplace_back(0, temporal_id);
156 }
157 }
158
159 if (last_frame_info_.layers.size() < frame_info.layers.size()) {
160 // A new keyframe is needed since a new layer will be added.
161 frame_info.keyframe = true;
162 }
163
164 for (uint8_t i = 0; i < frame_info.layers.size(); ++i) {
165 FrameInfo::SpatialLayer& layer_info = frame_info.layers[i];
166 if (frame_info.keyframe) {
167 layer_info.temporal_id = 0;
168 size_t avg_frame_size =
169 (target_bitrate.GetBitrate(i, 0) + 7) / (8 * framerate);
170
171 // The first frame is a key frame and should be larger.
172 // Store the overshoot bytes and distribute them over the coming frames,
173 // so that we on average meet the bitrate target.
174 debt_bytes_ += (kKeyframeSizeFactor - 1) * avg_frame_size;
175 layer_info.size = kKeyframeSizeFactor * avg_frame_size;
176 } else {
177 size_t avg_frame_size =
178 (target_bitrate.GetBitrate(i, layer_info.temporal_id) + 7) /
179 (8 * framerate);
180 layer_info.size = avg_frame_size;
181 if (debt_bytes_ > 0) {
182 // Pay at most half of the frame size for old debts.
183 size_t payment_size = std::min(avg_frame_size / 2, debt_bytes_);
184 debt_bytes_ -= payment_size;
185 layer_info.size -= payment_size;
186 }
187 }
188 }
189 last_frame_info_ = frame_info;
190 return frame_info;
191}
192
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000193int32_t FakeEncoder::RegisterEncodeCompleteCallback(
194 EncodedImageCallback* callback) {
brandtre78d2662017-01-16 05:57:16 -0800195 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000196 callback_ = callback;
197 return 0;
198}
199
Yves Gerey665174f2018-06-19 15:03:05 +0200200int32_t FakeEncoder::Release() {
201 return 0;
202}
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000203
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000204int32_t FakeEncoder::SetChannelParameters(uint32_t packet_loss, int64_t rtt) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000205 return 0;
206}
207
Erik Språng566124a2018-04-23 12:32:22 +0200208int32_t FakeEncoder::SetRateAllocation(
209 const VideoBitrateAllocation& rate_allocation,
210 uint32_t framerate) {
brandtre78d2662017-01-16 05:57:16 -0800211 rtc::CritScope cs(&crit_sect_);
Erik Språng08127a92016-11-16 16:41:30 +0100212 target_bitrate_ = rate_allocation;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200213 int allocated_bitrate_kbps = target_bitrate_.get_sum_kbps();
214
215 // Scale bitrate allocation to not exceed the given max target bitrate.
216 if (max_target_bitrate_kbps_ > 0 &&
217 allocated_bitrate_kbps > max_target_bitrate_kbps_) {
218 for (uint8_t spatial_idx = 0; spatial_idx < kMaxSpatialLayers;
219 ++spatial_idx) {
220 for (uint8_t temporal_idx = 0; temporal_idx < kMaxTemporalStreams;
221 ++temporal_idx) {
222 if (target_bitrate_.HasBitrate(spatial_idx, temporal_idx)) {
223 uint32_t bitrate =
224 target_bitrate_.GetBitrate(spatial_idx, temporal_idx);
225 bitrate = static_cast<uint32_t>(
226 (bitrate * int64_t{max_target_bitrate_kbps_}) /
227 allocated_bitrate_kbps);
228 target_bitrate_.SetBitrate(spatial_idx, temporal_idx, bitrate);
229 }
230 }
231 }
232 }
233
sprang4847ae62017-06-27 07:06:52 -0700234 configured_input_framerate_ = framerate;
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000235 return 0;
236}
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000237
Peter Boströmb7d9a972015-12-18 16:01:11 +0100238const char* FakeEncoder::kImplementationName = "fake_encoder";
239const char* FakeEncoder::ImplementationName() const {
240 return kImplementationName;
241}
242
sprang4847ae62017-06-27 07:06:52 -0700243int FakeEncoder::GetConfiguredInputFramerate() const {
244 rtc::CritScope cs(&crit_sect_);
245 return configured_input_framerate_;
246}
247
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000248FakeH264Encoder::FakeH264Encoder(Clock* clock)
brandtre78d2662017-01-16 05:57:16 -0800249 : FakeEncoder(clock), callback_(nullptr), idr_counter_(0) {
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000250 FakeEncoder::RegisterEncodeCompleteCallback(this);
251}
252
253int32_t FakeH264Encoder::RegisterEncodeCompleteCallback(
254 EncodedImageCallback* callback) {
brandtre78d2662017-01-16 05:57:16 -0800255 rtc::CritScope cs(&local_crit_sect_);
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000256 callback_ = callback;
257 return 0;
258}
259
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700260EncodedImageCallback::Result FakeH264Encoder::OnEncodedImage(
261 const EncodedImage& encoded_image,
262 const CodecSpecificInfo* codec_specific_info,
263 const RTPFragmentationHeader* fragments) {
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000264 const size_t kSpsSize = 8;
265 const size_t kPpsSize = 11;
266 const int kIdrFrequency = 10;
brandtre78d2662017-01-16 05:57:16 -0800267 EncodedImageCallback* callback;
268 int current_idr_counter;
269 {
270 rtc::CritScope cs(&local_crit_sect_);
271 callback = callback_;
272 current_idr_counter = idr_counter_;
273 ++idr_counter_;
274 }
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000275 RTPFragmentationHeader fragmentation;
brandtre78d2662017-01-16 05:57:16 -0800276 if (current_idr_counter % kIdrFrequency == 0 &&
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000277 encoded_image._length > kSpsSize + kPpsSize + 1) {
278 const size_t kNumSlices = 3;
279 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
280 fragmentation.fragmentationOffset[0] = 0;
281 fragmentation.fragmentationLength[0] = kSpsSize;
282 fragmentation.fragmentationOffset[1] = kSpsSize;
283 fragmentation.fragmentationLength[1] = kPpsSize;
284 fragmentation.fragmentationOffset[2] = kSpsSize + kPpsSize;
285 fragmentation.fragmentationLength[2] =
286 encoded_image._length - (kSpsSize + kPpsSize);
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000287 const size_t kSpsNalHeader = 0x67;
288 const size_t kPpsNalHeader = 0x68;
289 const size_t kIdrNalHeader = 0x65;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000290 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kSpsNalHeader;
291 encoded_image._buffer[fragmentation.fragmentationOffset[1]] = kPpsNalHeader;
292 encoded_image._buffer[fragmentation.fragmentationOffset[2]] = kIdrNalHeader;
293 } else {
294 const size_t kNumSlices = 1;
295 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
296 fragmentation.fragmentationOffset[0] = 0;
297 fragmentation.fragmentationLength[0] = encoded_image._length;
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000298 const size_t kNalHeader = 0x41;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000299 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kNalHeader;
300 }
301 uint8_t value = 0;
302 int fragment_counter = 0;
303 for (size_t i = 0; i < encoded_image._length; ++i) {
304 if (fragment_counter == fragmentation.fragmentationVectorSize ||
305 i != fragmentation.fragmentationOffset[fragment_counter]) {
306 encoded_image._buffer[i] = value++;
307 } else {
308 ++fragment_counter;
309 }
310 }
palmkviste75f2042016-09-28 06:19:48 -0700311 CodecSpecificInfo specifics;
312 memset(&specifics, 0, sizeof(specifics));
313 specifics.codecType = kVideoCodecH264;
hta9aa96882016-12-06 05:36:03 -0800314 specifics.codecSpecific.H264.packetization_mode =
315 H264PacketizationMode::NonInterleaved;
brandtre78d2662017-01-16 05:57:16 -0800316 RTC_DCHECK(callback);
317 return callback->OnEncodedImage(encoded_image, &specifics, &fragmentation);
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000318}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000319
320DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms)
brandtr49ce67c2017-02-11 00:25:18 -0800321 : test::FakeEncoder(clock), delay_ms_(delay_ms) {
322 // The encoder could be created on a different thread than
323 // it is being used on.
324 sequence_checker_.Detach();
325}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000326
perkj803d97f2016-11-01 11:45:46 -0700327void DelayedEncoder::SetDelay(int delay_ms) {
brandtr49ce67c2017-02-11 00:25:18 -0800328 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
perkj803d97f2016-11-01 11:45:46 -0700329 delay_ms_ = delay_ms;
330}
331
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700332int32_t DelayedEncoder::Encode(const VideoFrame& input_image,
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000333 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700334 const std::vector<FrameType>* frame_types) {
brandtr49ce67c2017-02-11 00:25:18 -0800335 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
336
337 SleepMs(delay_ms_);
338
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000339 return FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
340}
brandtr696c9c62016-12-19 05:47:28 -0800341
brandtre78d2662017-01-16 05:57:16 -0800342MultithreadedFakeH264Encoder::MultithreadedFakeH264Encoder(Clock* clock)
brandtr696c9c62016-12-19 05:47:28 -0800343 : test::FakeH264Encoder(clock),
344 current_queue_(0),
brandtr49ce67c2017-02-11 00:25:18 -0800345 queue1_(nullptr),
346 queue2_(nullptr) {
347 // The encoder could be created on a different thread than
348 // it is being used on.
349 sequence_checker_.Detach();
350}
brandtr696c9c62016-12-19 05:47:28 -0800351
brandtr49ce67c2017-02-11 00:25:18 -0800352int32_t MultithreadedFakeH264Encoder::InitEncode(const VideoCodec* config,
353 int32_t number_of_cores,
354 size_t max_payload_size) {
355 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
356
357 queue1_.reset(new rtc::TaskQueue("Queue 1"));
358 queue2_.reset(new rtc::TaskQueue("Queue 2"));
359
360 return FakeH264Encoder::InitEncode(config, number_of_cores, max_payload_size);
361}
brandtr696c9c62016-12-19 05:47:28 -0800362
brandtre78d2662017-01-16 05:57:16 -0800363class MultithreadedFakeH264Encoder::EncodeTask : public rtc::QueuedTask {
brandtr696c9c62016-12-19 05:47:28 -0800364 public:
brandtre78d2662017-01-16 05:57:16 -0800365 EncodeTask(MultithreadedFakeH264Encoder* encoder,
brandtr696c9c62016-12-19 05:47:28 -0800366 const VideoFrame& input_image,
367 const CodecSpecificInfo* codec_specific_info,
368 const std::vector<FrameType>* frame_types)
369 : encoder_(encoder),
370 input_image_(input_image),
371 codec_specific_info_(),
372 frame_types_(*frame_types) {
373 if (codec_specific_info)
374 codec_specific_info_ = *codec_specific_info;
375 }
376
377 private:
378 bool Run() override {
379 encoder_->EncodeCallback(input_image_, &codec_specific_info_,
380 &frame_types_);
381 return true;
382 }
383
brandtre78d2662017-01-16 05:57:16 -0800384 MultithreadedFakeH264Encoder* const encoder_;
brandtr696c9c62016-12-19 05:47:28 -0800385 VideoFrame input_image_;
386 CodecSpecificInfo codec_specific_info_;
387 std::vector<FrameType> frame_types_;
388};
389
brandtre78d2662017-01-16 05:57:16 -0800390int32_t MultithreadedFakeH264Encoder::Encode(
brandtr696c9c62016-12-19 05:47:28 -0800391 const VideoFrame& input_image,
392 const CodecSpecificInfo* codec_specific_info,
393 const std::vector<FrameType>* frame_types) {
brandtr49ce67c2017-02-11 00:25:18 -0800394 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtr696c9c62016-12-19 05:47:28 -0800395
brandtr49ce67c2017-02-11 00:25:18 -0800396 std::unique_ptr<rtc::TaskQueue>& queue =
397 (current_queue_++ % 2 == 0) ? queue1_ : queue2_;
398
399 if (!queue) {
400 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
401 }
402
403 queue->PostTask(std::unique_ptr<rtc::QueuedTask>(
brandtr696c9c62016-12-19 05:47:28 -0800404 new EncodeTask(this, input_image, codec_specific_info, frame_types)));
405
brandtr49ce67c2017-02-11 00:25:18 -0800406 return WEBRTC_VIDEO_CODEC_OK;
brandtr696c9c62016-12-19 05:47:28 -0800407}
408
brandtre78d2662017-01-16 05:57:16 -0800409int32_t MultithreadedFakeH264Encoder::EncodeCallback(
brandtr696c9c62016-12-19 05:47:28 -0800410 const VideoFrame& input_image,
411 const CodecSpecificInfo* codec_specific_info,
412 const std::vector<FrameType>* frame_types) {
413 return FakeH264Encoder::Encode(input_image, codec_specific_info, frame_types);
414}
415
brandtr49ce67c2017-02-11 00:25:18 -0800416int32_t MultithreadedFakeH264Encoder::Release() {
417 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
418
419 queue1_.reset();
420 queue2_.reset();
421
422 return FakeH264Encoder::Release();
423}
424
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +0000425} // namespace test
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000426} // namespace webrtc