blob: a76ac131d1b77fa1d53640d9f36c9177566ec2e6 [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
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000011#include "webrtc/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
perkj26091b12016-09-01 01:17:40 -070018#include "webrtc/base/checks.h"
brandtre78d2662017-01-16 05:57:16 -080019#include "webrtc/common_types.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010020#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/system_wrappers/include/sleep.h"
kwibergac9f8762016-09-30 22:29:43 -070022#include "webrtc/test/gtest.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
27FakeEncoder::FakeEncoder(Clock* clock)
28 : clock_(clock),
brandtre78d2662017-01-16 05:57:16 -080029 callback_(nullptr),
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000030 max_target_bitrate_kbps_(-1),
sprang317005a2017-06-08 07:12:17 -070031 last_encode_time_ms_(0) {
sprang@webrtc.org40709352013-11-26 11:41:59 +000032 // Generate some arbitrary not-all-zero data
33 for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) {
34 encoded_buffer_[i] = static_cast<uint8_t>(i);
35 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +000036}
37
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000038void FakeEncoder::SetMaxBitrate(int max_kbps) {
perkj26091b12016-09-01 01:17:40 -070039 RTC_DCHECK_GE(max_kbps, -1); // max_kbps == -1 disables it.
brandtre78d2662017-01-16 05:57:16 -080040 rtc::CritScope cs(&crit_sect_);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000041 max_target_bitrate_kbps_ = max_kbps;
42}
43
stefan@webrtc.org360e3762013-08-22 09:29:56 +000044int32_t FakeEncoder::InitEncode(const VideoCodec* config,
45 int32_t number_of_cores,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000046 size_t max_payload_size) {
brandtre78d2662017-01-16 05:57:16 -080047 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +000048 config_ = *config;
Erik Språng08127a92016-11-16 16:41:30 +010049 target_bitrate_.SetBitrate(0, 0, config_.startBitrate * 1000);
stefan@webrtc.org360e3762013-08-22 09:29:56 +000050 return 0;
51}
52
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070053int32_t FakeEncoder::Encode(const VideoFrame& input_image,
54 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -070055 const std::vector<FrameType>* frame_types) {
brandtre78d2662017-01-16 05:57:16 -080056 unsigned char max_framerate;
57 unsigned char num_simulcast_streams;
58 SimulcastStream simulcast_streams[kMaxSimulcastStreams];
59 EncodedImageCallback* callback;
60 uint32_t target_bitrate_sum_kbps;
61 int max_target_bitrate_kbps;
sprang317005a2017-06-08 07:12:17 -070062 int64_t last_encode_time_ms;
brandtre78d2662017-01-16 05:57:16 -080063 size_t num_encoded_bytes;
ilnik00d802b2017-04-11 10:34:31 -070064 VideoCodecMode mode;
brandtre78d2662017-01-16 05:57:16 -080065 {
66 rtc::CritScope cs(&crit_sect_);
67 max_framerate = config_.maxFramerate;
68 num_simulcast_streams = config_.numberOfSimulcastStreams;
69 for (int i = 0; i < num_simulcast_streams; ++i) {
70 simulcast_streams[i] = config_.simulcastStream[i];
71 }
72 callback = callback_;
73 target_bitrate_sum_kbps = target_bitrate_.get_sum_kbps();
74 max_target_bitrate_kbps = max_target_bitrate_kbps_;
sprang317005a2017-06-08 07:12:17 -070075 last_encode_time_ms = last_encode_time_ms_;
brandtre78d2662017-01-16 05:57:16 -080076 num_encoded_bytes = sizeof(encoded_buffer_);
ilnik00d802b2017-04-11 10:34:31 -070077 mode = config_.mode;
brandtre78d2662017-01-16 05:57:16 -080078 }
79
sprang317005a2017-06-08 07:12:17 -070080 int64_t time_now_ms = clock_->TimeInMilliseconds();
81 const bool first_encode = (last_encode_time_ms == 0);
brandtre78d2662017-01-16 05:57:16 -080082 RTC_DCHECK_GT(max_framerate, 0);
sprang317005a2017-06-08 07:12:17 -070083 int64_t time_since_last_encode_ms = 1000 / max_framerate;
84 if (!first_encode) {
85 // For all frames but the first we can estimate the display time by looking
86 // at the display time of the previous frame.
87 time_since_last_encode_ms = time_now_ms - last_encode_time_ms;
88 }
89 if (time_since_last_encode_ms > 3 * 1000 / max_framerate) {
90 // Rudimentary check to make sure we don't widely overshoot bitrate target
91 // when resuming encoding after a suspension.
92 time_since_last_encode_ms = 3 * 1000 / max_framerate;
93 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +000094
sprang317005a2017-06-08 07:12:17 -070095 size_t bits_available =
96 static_cast<size_t>(target_bitrate_sum_kbps * time_since_last_encode_ms);
97 size_t min_bits = static_cast<size_t>(simulcast_streams[0].minBitrate *
98 time_since_last_encode_ms);
brandtre78d2662017-01-16 05:57:16 -080099
sprang317005a2017-06-08 07:12:17 -0700100 if (bits_available < min_bits)
101 bits_available = min_bits;
102 size_t max_bits =
103 static_cast<size_t>(max_target_bitrate_kbps * time_since_last_encode_ms);
104 if (max_bits > 0 && max_bits < bits_available)
105 bits_available = max_bits;
106
107 {
108 rtc::CritScope cs(&crit_sect_);
109 last_encode_time_ms_ = time_now_ms;
110 }
brandtre78d2662017-01-16 05:57:16 -0800111
112 RTC_DCHECK_GT(num_simulcast_streams, 0);
113 for (unsigned char i = 0; i < num_simulcast_streams; ++i) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000114 CodecSpecificInfo specifics;
115 memset(&specifics, 0, sizeof(specifics));
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000116 specifics.codecType = kVideoCodecGeneric;
117 specifics.codecSpecific.generic.simulcast_idx = i;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000118 size_t min_stream_bits = static_cast<size_t>(
sprang317005a2017-06-08 07:12:17 -0700119 simulcast_streams[i].minBitrate * time_since_last_encode_ms);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000120 size_t max_stream_bits = static_cast<size_t>(
sprang317005a2017-06-08 07:12:17 -0700121 simulcast_streams[i].maxBitrate * time_since_last_encode_ms);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000122 size_t stream_bits = (bits_available > max_stream_bits) ? max_stream_bits :
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000123 bits_available;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000124 size_t stream_bytes = (stream_bits + 7) / 8;
sprang317005a2017-06-08 07:12:17 -0700125 if (first_encode) {
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000126 // The first frame is a key frame and should be larger.
sprang317005a2017-06-08 07:12:17 -0700127 // TODO(holmer): The FakeEncoder should store the bits_available between
128 // encodes so that it can compensate for oversized frames.
129 stream_bytes *= 10;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000130 }
brandtre78d2662017-01-16 05:57:16 -0800131 if (stream_bytes > num_encoded_bytes)
132 stream_bytes = num_encoded_bytes;
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000133
perkj26091b12016-09-01 01:17:40 -0700134 // Always encode something on the first frame.
135 if (min_stream_bits > bits_available && i > 0)
136 continue;
brandtre78d2662017-01-16 05:57:16 -0800137
138 std::unique_ptr<uint8_t[]> encoded_buffer(new uint8_t[num_encoded_bytes]);
139 memcpy(encoded_buffer.get(), encoded_buffer_, num_encoded_bytes);
140 EncodedImage encoded(encoded_buffer.get(), stream_bytes, num_encoded_bytes);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000141 encoded._timeStamp = input_image.timestamp();
142 encoded.capture_time_ms_ = input_image.render_time_ms();
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000143 encoded._frameType = (*frame_types)[i];
brandtre78d2662017-01-16 05:57:16 -0800144 encoded._encodedWidth = simulcast_streams[i].width;
145 encoded._encodedHeight = simulcast_streams[i].height;
perkj803d97f2016-11-01 11:45:46 -0700146 encoded.rotation_ = input_image.rotation();
ilnik00d802b2017-04-11 10:34:31 -0700147 encoded.content_type_ = (mode == kScreensharing)
148 ? VideoContentType::SCREENSHARE
149 : VideoContentType::UNSPECIFIED;
perkj275afc52016-09-01 00:21:16 -0700150 specifics.codec_name = ImplementationName();
ilnik04f4d122017-06-19 07:18:55 -0700151 specifics.codecSpecific.generic.simulcast_idx = i;
brandtre78d2662017-01-16 05:57:16 -0800152 RTC_DCHECK(callback);
153 if (callback->OnEncodedImage(encoded, &specifics, nullptr).error !=
sergeyu2cb155a2016-11-04 11:39:29 -0700154 EncodedImageCallback::Result::OK) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000155 return -1;
sergeyu2cb155a2016-11-04 11:39:29 -0700156 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000157 bits_available -= std::min(encoded._length * 8, bits_available);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000158 }
159 return 0;
160}
161
162int32_t FakeEncoder::RegisterEncodeCompleteCallback(
163 EncodedImageCallback* callback) {
brandtre78d2662017-01-16 05:57:16 -0800164 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000165 callback_ = callback;
166 return 0;
167}
168
169int32_t FakeEncoder::Release() { return 0; }
170
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000171int32_t FakeEncoder::SetChannelParameters(uint32_t packet_loss, int64_t rtt) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000172 return 0;
173}
174
Erik Språng08127a92016-11-16 16:41:30 +0100175int32_t FakeEncoder::SetRateAllocation(const BitrateAllocation& rate_allocation,
176 uint32_t framerate) {
brandtre78d2662017-01-16 05:57:16 -0800177 rtc::CritScope cs(&crit_sect_);
Erik Språng08127a92016-11-16 16:41:30 +0100178 target_bitrate_ = rate_allocation;
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000179 return 0;
180}
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000181
Peter Boströmb7d9a972015-12-18 16:01:11 +0100182const char* FakeEncoder::kImplementationName = "fake_encoder";
183const char* FakeEncoder::ImplementationName() const {
184 return kImplementationName;
185}
186
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000187FakeH264Encoder::FakeH264Encoder(Clock* clock)
brandtre78d2662017-01-16 05:57:16 -0800188 : FakeEncoder(clock), callback_(nullptr), idr_counter_(0) {
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000189 FakeEncoder::RegisterEncodeCompleteCallback(this);
190}
191
192int32_t FakeH264Encoder::RegisterEncodeCompleteCallback(
193 EncodedImageCallback* callback) {
brandtre78d2662017-01-16 05:57:16 -0800194 rtc::CritScope cs(&local_crit_sect_);
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000195 callback_ = callback;
196 return 0;
197}
198
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700199EncodedImageCallback::Result FakeH264Encoder::OnEncodedImage(
200 const EncodedImage& encoded_image,
201 const CodecSpecificInfo* codec_specific_info,
202 const RTPFragmentationHeader* fragments) {
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000203 const size_t kSpsSize = 8;
204 const size_t kPpsSize = 11;
205 const int kIdrFrequency = 10;
brandtre78d2662017-01-16 05:57:16 -0800206 EncodedImageCallback* callback;
207 int current_idr_counter;
208 {
209 rtc::CritScope cs(&local_crit_sect_);
210 callback = callback_;
211 current_idr_counter = idr_counter_;
212 ++idr_counter_;
213 }
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000214 RTPFragmentationHeader fragmentation;
brandtre78d2662017-01-16 05:57:16 -0800215 if (current_idr_counter % kIdrFrequency == 0 &&
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000216 encoded_image._length > kSpsSize + kPpsSize + 1) {
217 const size_t kNumSlices = 3;
218 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
219 fragmentation.fragmentationOffset[0] = 0;
220 fragmentation.fragmentationLength[0] = kSpsSize;
221 fragmentation.fragmentationOffset[1] = kSpsSize;
222 fragmentation.fragmentationLength[1] = kPpsSize;
223 fragmentation.fragmentationOffset[2] = kSpsSize + kPpsSize;
224 fragmentation.fragmentationLength[2] =
225 encoded_image._length - (kSpsSize + kPpsSize);
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000226 const size_t kSpsNalHeader = 0x67;
227 const size_t kPpsNalHeader = 0x68;
228 const size_t kIdrNalHeader = 0x65;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000229 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kSpsNalHeader;
230 encoded_image._buffer[fragmentation.fragmentationOffset[1]] = kPpsNalHeader;
231 encoded_image._buffer[fragmentation.fragmentationOffset[2]] = kIdrNalHeader;
232 } else {
233 const size_t kNumSlices = 1;
234 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
235 fragmentation.fragmentationOffset[0] = 0;
236 fragmentation.fragmentationLength[0] = encoded_image._length;
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000237 const size_t kNalHeader = 0x41;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000238 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kNalHeader;
239 }
240 uint8_t value = 0;
241 int fragment_counter = 0;
242 for (size_t i = 0; i < encoded_image._length; ++i) {
243 if (fragment_counter == fragmentation.fragmentationVectorSize ||
244 i != fragmentation.fragmentationOffset[fragment_counter]) {
245 encoded_image._buffer[i] = value++;
246 } else {
247 ++fragment_counter;
248 }
249 }
palmkviste75f2042016-09-28 06:19:48 -0700250 CodecSpecificInfo specifics;
251 memset(&specifics, 0, sizeof(specifics));
252 specifics.codecType = kVideoCodecH264;
hta9aa96882016-12-06 05:36:03 -0800253 specifics.codecSpecific.H264.packetization_mode =
254 H264PacketizationMode::NonInterleaved;
brandtre78d2662017-01-16 05:57:16 -0800255 RTC_DCHECK(callback);
256 return callback->OnEncodedImage(encoded_image, &specifics, &fragmentation);
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000257}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000258
259DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms)
brandtr49ce67c2017-02-11 00:25:18 -0800260 : test::FakeEncoder(clock), delay_ms_(delay_ms) {
261 // The encoder could be created on a different thread than
262 // it is being used on.
263 sequence_checker_.Detach();
264}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000265
perkj803d97f2016-11-01 11:45:46 -0700266void DelayedEncoder::SetDelay(int delay_ms) {
brandtr49ce67c2017-02-11 00:25:18 -0800267 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
perkj803d97f2016-11-01 11:45:46 -0700268 delay_ms_ = delay_ms;
269}
270
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700271int32_t DelayedEncoder::Encode(const VideoFrame& input_image,
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000272 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700273 const std::vector<FrameType>* frame_types) {
brandtr49ce67c2017-02-11 00:25:18 -0800274 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
275
276 SleepMs(delay_ms_);
277
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000278 return FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
279}
brandtr696c9c62016-12-19 05:47:28 -0800280
brandtre78d2662017-01-16 05:57:16 -0800281MultithreadedFakeH264Encoder::MultithreadedFakeH264Encoder(Clock* clock)
brandtr696c9c62016-12-19 05:47:28 -0800282 : test::FakeH264Encoder(clock),
283 current_queue_(0),
brandtr49ce67c2017-02-11 00:25:18 -0800284 queue1_(nullptr),
285 queue2_(nullptr) {
286 // The encoder could be created on a different thread than
287 // it is being used on.
288 sequence_checker_.Detach();
289}
brandtr696c9c62016-12-19 05:47:28 -0800290
brandtr49ce67c2017-02-11 00:25:18 -0800291int32_t MultithreadedFakeH264Encoder::InitEncode(const VideoCodec* config,
292 int32_t number_of_cores,
293 size_t max_payload_size) {
294 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
295
296 queue1_.reset(new rtc::TaskQueue("Queue 1"));
297 queue2_.reset(new rtc::TaskQueue("Queue 2"));
298
299 return FakeH264Encoder::InitEncode(config, number_of_cores, max_payload_size);
300}
brandtr696c9c62016-12-19 05:47:28 -0800301
brandtre78d2662017-01-16 05:57:16 -0800302class MultithreadedFakeH264Encoder::EncodeTask : public rtc::QueuedTask {
brandtr696c9c62016-12-19 05:47:28 -0800303 public:
brandtre78d2662017-01-16 05:57:16 -0800304 EncodeTask(MultithreadedFakeH264Encoder* encoder,
brandtr696c9c62016-12-19 05:47:28 -0800305 const VideoFrame& input_image,
306 const CodecSpecificInfo* codec_specific_info,
307 const std::vector<FrameType>* frame_types)
308 : encoder_(encoder),
309 input_image_(input_image),
310 codec_specific_info_(),
311 frame_types_(*frame_types) {
312 if (codec_specific_info)
313 codec_specific_info_ = *codec_specific_info;
314 }
315
316 private:
317 bool Run() override {
318 encoder_->EncodeCallback(input_image_, &codec_specific_info_,
319 &frame_types_);
320 return true;
321 }
322
brandtre78d2662017-01-16 05:57:16 -0800323 MultithreadedFakeH264Encoder* const encoder_;
brandtr696c9c62016-12-19 05:47:28 -0800324 VideoFrame input_image_;
325 CodecSpecificInfo codec_specific_info_;
326 std::vector<FrameType> frame_types_;
327};
328
brandtre78d2662017-01-16 05:57:16 -0800329int32_t MultithreadedFakeH264Encoder::Encode(
brandtr696c9c62016-12-19 05:47:28 -0800330 const VideoFrame& input_image,
331 const CodecSpecificInfo* codec_specific_info,
332 const std::vector<FrameType>* frame_types) {
brandtr49ce67c2017-02-11 00:25:18 -0800333 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtr696c9c62016-12-19 05:47:28 -0800334
brandtr49ce67c2017-02-11 00:25:18 -0800335 std::unique_ptr<rtc::TaskQueue>& queue =
336 (current_queue_++ % 2 == 0) ? queue1_ : queue2_;
337
338 if (!queue) {
339 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
340 }
341
342 queue->PostTask(std::unique_ptr<rtc::QueuedTask>(
brandtr696c9c62016-12-19 05:47:28 -0800343 new EncodeTask(this, input_image, codec_specific_info, frame_types)));
344
brandtr49ce67c2017-02-11 00:25:18 -0800345 return WEBRTC_VIDEO_CODEC_OK;
brandtr696c9c62016-12-19 05:47:28 -0800346}
347
brandtre78d2662017-01-16 05:57:16 -0800348int32_t MultithreadedFakeH264Encoder::EncodeCallback(
brandtr696c9c62016-12-19 05:47:28 -0800349 const VideoFrame& input_image,
350 const CodecSpecificInfo* codec_specific_info,
351 const std::vector<FrameType>* frame_types) {
352 return FakeH264Encoder::Encode(input_image, codec_specific_info, frame_types);
353}
354
brandtr49ce67c2017-02-11 00:25:18 -0800355int32_t MultithreadedFakeH264Encoder::Release() {
356 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
357
358 queue1_.reset();
359 queue2_.reset();
360
361 return FakeH264Encoder::Release();
362}
363
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +0000364} // namespace test
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000365} // namespace webrtc