blob: 065b5299cd2b8a3012e006862b516b4541c26bd7 [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
palmkviste75f2042016-09-28 06:19:48 -070013#include <algorithm>
14
perkj26091b12016-09-01 01:17:40 -070015#include "webrtc/base/checks.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010016#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010017#include "webrtc/system_wrappers/include/sleep.h"
kwibergac9f8762016-09-30 22:29:43 -070018#include "webrtc/test/gtest.h"
pbos@webrtc.orgab990ae2014-09-17 09:02:25 +000019
stefan@webrtc.org360e3762013-08-22 09:29:56 +000020namespace webrtc {
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000021namespace test {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000022
23FakeEncoder::FakeEncoder(Clock* clock)
24 : clock_(clock),
25 callback_(NULL),
26 target_bitrate_kbps_(0),
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000027 max_target_bitrate_kbps_(-1),
stefan@webrtc.org360e3762013-08-22 09:29:56 +000028 last_encode_time_ms_(0) {
sprang@webrtc.org40709352013-11-26 11:41:59 +000029 // Generate some arbitrary not-all-zero data
30 for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) {
31 encoded_buffer_[i] = static_cast<uint8_t>(i);
32 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +000033}
34
35FakeEncoder::~FakeEncoder() {}
36
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000037void FakeEncoder::SetMaxBitrate(int max_kbps) {
perkj26091b12016-09-01 01:17:40 -070038 RTC_DCHECK_GE(max_kbps, -1); // max_kbps == -1 disables it.
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000039 max_target_bitrate_kbps_ = max_kbps;
40}
41
stefan@webrtc.org360e3762013-08-22 09:29:56 +000042int32_t FakeEncoder::InitEncode(const VideoCodec* config,
43 int32_t number_of_cores,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000044 size_t max_payload_size) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000045 config_ = *config;
46 target_bitrate_kbps_ = config_.startBitrate;
47 return 0;
48}
49
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070050int32_t FakeEncoder::Encode(const VideoFrame& input_image,
51 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -070052 const std::vector<FrameType>* frame_types) {
perkj26091b12016-09-01 01:17:40 -070053 RTC_DCHECK_GT(config_.maxFramerate, 0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000054 int64_t time_since_last_encode_ms = 1000 / config_.maxFramerate;
stefan@webrtc.org360e3762013-08-22 09:29:56 +000055 int64_t time_now_ms = clock_->TimeInMilliseconds();
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +000056 const bool first_encode = last_encode_time_ms_ == 0;
57 if (!first_encode) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000058 // For all frames but the first we can estimate the display time by looking
59 // at the display time of the previous frame.
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000060 time_since_last_encode_ms = time_now_ms - last_encode_time_ms_;
stefan@webrtc.org360e3762013-08-22 09:29:56 +000061 }
Erik Språngad113e52015-11-26 16:26:12 +010062 if (time_since_last_encode_ms > 3 * 1000 / config_.maxFramerate) {
63 // Rudimentary check to make sure we don't widely overshoot bitrate target
64 // when resuming encoding after a suspension.
65 time_since_last_encode_ms = 3 * 1000 / config_.maxFramerate;
66 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +000067
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000068 size_t bits_available =
69 static_cast<size_t>(target_bitrate_kbps_ * time_since_last_encode_ms);
70 size_t min_bits = static_cast<size_t>(
71 config_.simulcastStream[0].minBitrate * time_since_last_encode_ms);
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +000072 if (bits_available < min_bits)
73 bits_available = min_bits;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000074 size_t max_bits =
75 static_cast<size_t>(max_target_bitrate_kbps_ * time_since_last_encode_ms);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000076 if (max_bits > 0 && max_bits < bits_available)
77 bits_available = max_bits;
stefan@webrtc.org360e3762013-08-22 09:29:56 +000078 last_encode_time_ms_ = time_now_ms;
79
perkj26091b12016-09-01 01:17:40 -070080 RTC_DCHECK_GT(config_.numberOfSimulcastStreams, 0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000081 for (unsigned char i = 0; i < config_.numberOfSimulcastStreams; ++i) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000082 CodecSpecificInfo specifics;
83 memset(&specifics, 0, sizeof(specifics));
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +000084 specifics.codecType = kVideoCodecGeneric;
85 specifics.codecSpecific.generic.simulcast_idx = i;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000086 size_t min_stream_bits = static_cast<size_t>(
87 config_.simulcastStream[i].minBitrate * time_since_last_encode_ms);
88 size_t max_stream_bits = static_cast<size_t>(
89 config_.simulcastStream[i].maxBitrate * time_since_last_encode_ms);
90 size_t stream_bits = (bits_available > max_stream_bits) ? max_stream_bits :
stefan@webrtc.org360e3762013-08-22 09:29:56 +000091 bits_available;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000092 size_t stream_bytes = (stream_bits + 7) / 8;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +000093 if (first_encode) {
94 // The first frame is a key frame and should be larger.
95 // TODO(holmer): The FakeEncoder should store the bits_available between
96 // encodes so that it can compensate for oversized frames.
97 stream_bytes *= 10;
98 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000099 if (stream_bytes > sizeof(encoded_buffer_))
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000100 stream_bytes = sizeof(encoded_buffer_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000101
perkj26091b12016-09-01 01:17:40 -0700102 // Always encode something on the first frame.
103 if (min_stream_bits > bits_available && i > 0)
104 continue;
pbos@webrtc.orgc095f512013-08-22 12:34:58 +0000105 EncodedImage encoded(
106 encoded_buffer_, stream_bytes, sizeof(encoded_buffer_));
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000107 encoded._timeStamp = input_image.timestamp();
108 encoded.capture_time_ms_ = input_image.render_time_ms();
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000109 encoded._frameType = (*frame_types)[i];
asaperssond89920b2015-07-22 06:52:00 -0700110 encoded._encodedWidth = config_.simulcastStream[i].width;
111 encoded._encodedHeight = config_.simulcastStream[i].height;
perkj803d97f2016-11-01 11:45:46 -0700112 encoded.rotation_ = input_image.rotation();
perkj26091b12016-09-01 01:17:40 -0700113 RTC_DCHECK(callback_ != NULL);
perkj275afc52016-09-01 00:21:16 -0700114 specifics.codec_name = ImplementationName();
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000115 if (callback_->Encoded(encoded, &specifics, NULL) != 0)
116 return -1;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000117 bits_available -= std::min(encoded._length * 8, bits_available);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000118 }
119 return 0;
120}
121
122int32_t FakeEncoder::RegisterEncodeCompleteCallback(
123 EncodedImageCallback* callback) {
124 callback_ = callback;
125 return 0;
126}
127
128int32_t FakeEncoder::Release() { return 0; }
129
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000130int32_t FakeEncoder::SetChannelParameters(uint32_t packet_loss, int64_t rtt) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000131 return 0;
132}
133
134int32_t FakeEncoder::SetRates(uint32_t new_target_bitrate, uint32_t framerate) {
135 target_bitrate_kbps_ = new_target_bitrate;
136 return 0;
137}
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000138
Peter Boströmb7d9a972015-12-18 16:01:11 +0100139const char* FakeEncoder::kImplementationName = "fake_encoder";
140const char* FakeEncoder::ImplementationName() const {
141 return kImplementationName;
142}
143
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000144FakeH264Encoder::FakeH264Encoder(Clock* clock)
145 : FakeEncoder(clock), callback_(NULL), idr_counter_(0) {
146 FakeEncoder::RegisterEncodeCompleteCallback(this);
147}
148
149int32_t FakeH264Encoder::RegisterEncodeCompleteCallback(
150 EncodedImageCallback* callback) {
151 callback_ = callback;
152 return 0;
153}
154
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700155EncodedImageCallback::Result FakeH264Encoder::OnEncodedImage(
156 const EncodedImage& encoded_image,
157 const CodecSpecificInfo* codec_specific_info,
158 const RTPFragmentationHeader* fragments) {
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000159 const size_t kSpsSize = 8;
160 const size_t kPpsSize = 11;
161 const int kIdrFrequency = 10;
162 RTPFragmentationHeader fragmentation;
163 if (idr_counter_++ % kIdrFrequency == 0 &&
164 encoded_image._length > kSpsSize + kPpsSize + 1) {
165 const size_t kNumSlices = 3;
166 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
167 fragmentation.fragmentationOffset[0] = 0;
168 fragmentation.fragmentationLength[0] = kSpsSize;
169 fragmentation.fragmentationOffset[1] = kSpsSize;
170 fragmentation.fragmentationLength[1] = kPpsSize;
171 fragmentation.fragmentationOffset[2] = kSpsSize + kPpsSize;
172 fragmentation.fragmentationLength[2] =
173 encoded_image._length - (kSpsSize + kPpsSize);
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000174 const size_t kSpsNalHeader = 0x67;
175 const size_t kPpsNalHeader = 0x68;
176 const size_t kIdrNalHeader = 0x65;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000177 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kSpsNalHeader;
178 encoded_image._buffer[fragmentation.fragmentationOffset[1]] = kPpsNalHeader;
179 encoded_image._buffer[fragmentation.fragmentationOffset[2]] = kIdrNalHeader;
180 } else {
181 const size_t kNumSlices = 1;
182 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
183 fragmentation.fragmentationOffset[0] = 0;
184 fragmentation.fragmentationLength[0] = encoded_image._length;
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000185 const size_t kNalHeader = 0x41;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000186 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kNalHeader;
187 }
188 uint8_t value = 0;
189 int fragment_counter = 0;
190 for (size_t i = 0; i < encoded_image._length; ++i) {
191 if (fragment_counter == fragmentation.fragmentationVectorSize ||
192 i != fragmentation.fragmentationOffset[fragment_counter]) {
193 encoded_image._buffer[i] = value++;
194 } else {
195 ++fragment_counter;
196 }
197 }
palmkviste75f2042016-09-28 06:19:48 -0700198 CodecSpecificInfo specifics;
199 memset(&specifics, 0, sizeof(specifics));
200 specifics.codecType = kVideoCodecH264;
201 return callback_->OnEncodedImage(encoded_image, &specifics, &fragmentation);
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000202}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000203
204DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms)
205 : test::FakeEncoder(clock),
206 delay_ms_(delay_ms) {}
207
perkj803d97f2016-11-01 11:45:46 -0700208void DelayedEncoder::SetDelay(int delay_ms) {
209 rtc::CritScope lock(&lock_);
210 delay_ms_ = delay_ms;
211}
212
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700213int32_t DelayedEncoder::Encode(const VideoFrame& input_image,
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000214 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700215 const std::vector<FrameType>* frame_types) {
perkj803d97f2016-11-01 11:45:46 -0700216 int delay_ms = 0;
217 {
218 rtc::CritScope lock(&lock_);
219 delay_ms = delay_ms_;
220 }
221 SleepMs(delay_ms);
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000222 return FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
223}
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +0000224} // namespace test
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000225} // namespace webrtc