blob: 29f844c00d045efc8548850b0ddc4abce5911072 [file] [log] [blame]
stefan@webrtc.org360e3762013-08-22 09:29:561/*
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:0111#include "webrtc/test/fake_encoder.h"
stefan@webrtc.org360e3762013-08-22 09:29:5612
13#include "testing/gtest/include/gtest/gtest.h"
14
perkj26091b12016-09-01 08:17:4015#include "webrtc/base/checks.h"
Henrik Kjellander2557b862015-11-18 21:00:2116#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 17:17:4017#include "webrtc/system_wrappers/include/sleep.h"
pbos@webrtc.orgab990ae2014-09-17 09:02:2518
stefan@webrtc.org360e3762013-08-22 09:29:5619namespace webrtc {
pbos@webrtc.orgcb5118c2013-09-03 09:10:3720namespace test {
stefan@webrtc.org360e3762013-08-22 09:29:5621
22FakeEncoder::FakeEncoder(Clock* clock)
23 : clock_(clock),
24 callback_(NULL),
25 target_bitrate_kbps_(0),
pbos@webrtc.org3349ae02014-03-13 12:52:2726 max_target_bitrate_kbps_(-1),
stefan@webrtc.org360e3762013-08-22 09:29:5627 last_encode_time_ms_(0) {
sprang@webrtc.org40709352013-11-26 11:41:5928 // Generate some arbitrary not-all-zero data
29 for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) {
30 encoded_buffer_[i] = static_cast<uint8_t>(i);
31 }
stefan@webrtc.org360e3762013-08-22 09:29:5632}
33
34FakeEncoder::~FakeEncoder() {}
35
pbos@webrtc.org3349ae02014-03-13 12:52:2736void FakeEncoder::SetMaxBitrate(int max_kbps) {
perkj26091b12016-09-01 08:17:4037 RTC_DCHECK_GE(max_kbps, -1); // max_kbps == -1 disables it.
pbos@webrtc.org3349ae02014-03-13 12:52:2738 max_target_bitrate_kbps_ = max_kbps;
39}
40
stefan@webrtc.org360e3762013-08-22 09:29:5641int32_t FakeEncoder::InitEncode(const VideoCodec* config,
42 int32_t number_of_cores,
pkasting@chromium.org4591fbd2014-11-20 22:28:1443 size_t max_payload_size) {
stefan@webrtc.org360e3762013-08-22 09:29:5644 config_ = *config;
45 target_bitrate_kbps_ = config_.startBitrate;
46 return 0;
47}
48
Miguel Casas-Sanchez47650702015-05-30 00:21:4049int32_t FakeEncoder::Encode(const VideoFrame& input_image,
50 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 09:39:0651 const std::vector<FrameType>* frame_types) {
perkj26091b12016-09-01 08:17:4052 RTC_DCHECK_GT(config_.maxFramerate, 0);
pkasting@chromium.org4591fbd2014-11-20 22:28:1453 int64_t time_since_last_encode_ms = 1000 / config_.maxFramerate;
stefan@webrtc.org360e3762013-08-22 09:29:5654 int64_t time_now_ms = clock_->TimeInMilliseconds();
stefan@webrtc.org0bae1fa2014-11-05 14:05:2955 const bool first_encode = last_encode_time_ms_ == 0;
56 if (!first_encode) {
stefan@webrtc.org360e3762013-08-22 09:29:5657 // For all frames but the first we can estimate the display time by looking
58 // at the display time of the previous frame.
pbos@webrtc.org3349ae02014-03-13 12:52:2759 time_since_last_encode_ms = time_now_ms - last_encode_time_ms_;
stefan@webrtc.org360e3762013-08-22 09:29:5660 }
Erik Språngad113e52015-11-26 15:26:1261 if (time_since_last_encode_ms > 3 * 1000 / config_.maxFramerate) {
62 // Rudimentary check to make sure we don't widely overshoot bitrate target
63 // when resuming encoding after a suspension.
64 time_since_last_encode_ms = 3 * 1000 / config_.maxFramerate;
65 }
stefan@webrtc.org360e3762013-08-22 09:29:5666
pkasting@chromium.org4591fbd2014-11-20 22:28:1467 size_t bits_available =
68 static_cast<size_t>(target_bitrate_kbps_ * time_since_last_encode_ms);
69 size_t min_bits = static_cast<size_t>(
70 config_.simulcastStream[0].minBitrate * time_since_last_encode_ms);
pbos@webrtc.org0181b5f2013-09-09 08:26:3071 if (bits_available < min_bits)
72 bits_available = min_bits;
pkasting@chromium.org4591fbd2014-11-20 22:28:1473 size_t max_bits =
74 static_cast<size_t>(max_target_bitrate_kbps_ * time_since_last_encode_ms);
pbos@webrtc.org3349ae02014-03-13 12:52:2775 if (max_bits > 0 && max_bits < bits_available)
76 bits_available = max_bits;
stefan@webrtc.org360e3762013-08-22 09:29:5677 last_encode_time_ms_ = time_now_ms;
78
perkj26091b12016-09-01 08:17:4079 RTC_DCHECK_GT(config_.numberOfSimulcastStreams, 0);
pkasting@chromium.org4591fbd2014-11-20 22:28:1480 for (unsigned char i = 0; i < config_.numberOfSimulcastStreams; ++i) {
stefan@webrtc.org360e3762013-08-22 09:29:5681 CodecSpecificInfo specifics;
82 memset(&specifics, 0, sizeof(specifics));
pbos@webrtc.org0181b5f2013-09-09 08:26:3083 specifics.codecType = kVideoCodecGeneric;
84 specifics.codecSpecific.generic.simulcast_idx = i;
pkasting@chromium.org4591fbd2014-11-20 22:28:1485 size_t min_stream_bits = static_cast<size_t>(
86 config_.simulcastStream[i].minBitrate * time_since_last_encode_ms);
87 size_t max_stream_bits = static_cast<size_t>(
88 config_.simulcastStream[i].maxBitrate * time_since_last_encode_ms);
89 size_t stream_bits = (bits_available > max_stream_bits) ? max_stream_bits :
stefan@webrtc.org360e3762013-08-22 09:29:5690 bits_available;
pkasting@chromium.org4591fbd2014-11-20 22:28:1491 size_t stream_bytes = (stream_bits + 7) / 8;
stefan@webrtc.org0bae1fa2014-11-05 14:05:2992 if (first_encode) {
93 // The first frame is a key frame and should be larger.
94 // TODO(holmer): The FakeEncoder should store the bits_available between
95 // encodes so that it can compensate for oversized frames.
96 stream_bytes *= 10;
97 }
pkasting@chromium.org4591fbd2014-11-20 22:28:1498 if (stream_bytes > sizeof(encoded_buffer_))
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:5799 stream_bytes = sizeof(encoded_buffer_);
stefan@webrtc.org360e3762013-08-22 09:29:56100
perkj26091b12016-09-01 08:17:40101 // Always encode something on the first frame.
102 if (min_stream_bits > bits_available && i > 0)
103 continue;
pbos@webrtc.orgc095f512013-08-22 12:34:58104 EncodedImage encoded(
105 encoded_buffer_, stream_bytes, sizeof(encoded_buffer_));
stefan@webrtc.org360e3762013-08-22 09:29:56106 encoded._timeStamp = input_image.timestamp();
107 encoded.capture_time_ms_ = input_image.render_time_ms();
pbos@webrtc.org0181b5f2013-09-09 08:26:30108 encoded._frameType = (*frame_types)[i];
asaperssond89920b2015-07-22 13:52:00109 encoded._encodedWidth = config_.simulcastStream[i].width;
110 encoded._encodedHeight = config_.simulcastStream[i].height;
perkj26091b12016-09-01 08:17:40111 RTC_DCHECK(callback_ != NULL);
perkj275afc52016-09-01 07:21:16112 specifics.codec_name = ImplementationName();
stefan@webrtc.org360e3762013-08-22 09:29:56113 if (callback_->Encoded(encoded, &specifics, NULL) != 0)
114 return -1;
pkasting@chromium.org4591fbd2014-11-20 22:28:14115 bits_available -= std::min(encoded._length * 8, bits_available);
stefan@webrtc.org360e3762013-08-22 09:29:56116 }
117 return 0;
118}
119
120int32_t FakeEncoder::RegisterEncodeCompleteCallback(
121 EncodedImageCallback* callback) {
122 callback_ = callback;
123 return 0;
124}
125
126int32_t FakeEncoder::Release() { return 0; }
127
pkasting@chromium.org16825b12015-01-12 21:51:21128int32_t FakeEncoder::SetChannelParameters(uint32_t packet_loss, int64_t rtt) {
stefan@webrtc.org360e3762013-08-22 09:29:56129 return 0;
130}
131
132int32_t FakeEncoder::SetRates(uint32_t new_target_bitrate, uint32_t framerate) {
133 target_bitrate_kbps_ = new_target_bitrate;
134 return 0;
135}
pbos@webrtc.org3349ae02014-03-13 12:52:27136
Peter Boströmb7d9a972015-12-18 15:01:11137const char* FakeEncoder::kImplementationName = "fake_encoder";
138const char* FakeEncoder::ImplementationName() const {
139 return kImplementationName;
140}
141
stefan@webrtc.org79c33592014-08-06 09:24:53142FakeH264Encoder::FakeH264Encoder(Clock* clock)
143 : FakeEncoder(clock), callback_(NULL), idr_counter_(0) {
144 FakeEncoder::RegisterEncodeCompleteCallback(this);
145}
146
147int32_t FakeH264Encoder::RegisterEncodeCompleteCallback(
148 EncodedImageCallback* callback) {
149 callback_ = callback;
150 return 0;
151}
152
Sergey Ulanov525df3f2016-08-03 00:46:41153EncodedImageCallback::Result FakeH264Encoder::OnEncodedImage(
154 const EncodedImage& encoded_image,
155 const CodecSpecificInfo* codec_specific_info,
156 const RTPFragmentationHeader* fragments) {
stefan@webrtc.org79c33592014-08-06 09:24:53157 const size_t kSpsSize = 8;
158 const size_t kPpsSize = 11;
159 const int kIdrFrequency = 10;
160 RTPFragmentationHeader fragmentation;
161 if (idr_counter_++ % kIdrFrequency == 0 &&
162 encoded_image._length > kSpsSize + kPpsSize + 1) {
163 const size_t kNumSlices = 3;
164 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
165 fragmentation.fragmentationOffset[0] = 0;
166 fragmentation.fragmentationLength[0] = kSpsSize;
167 fragmentation.fragmentationOffset[1] = kSpsSize;
168 fragmentation.fragmentationLength[1] = kPpsSize;
169 fragmentation.fragmentationOffset[2] = kSpsSize + kPpsSize;
170 fragmentation.fragmentationLength[2] =
171 encoded_image._length - (kSpsSize + kPpsSize);
glaznev@webrtc.orge69220c2015-02-05 17:56:15172 const size_t kSpsNalHeader = 0x67;
173 const size_t kPpsNalHeader = 0x68;
174 const size_t kIdrNalHeader = 0x65;
stefan@webrtc.org79c33592014-08-06 09:24:53175 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kSpsNalHeader;
176 encoded_image._buffer[fragmentation.fragmentationOffset[1]] = kPpsNalHeader;
177 encoded_image._buffer[fragmentation.fragmentationOffset[2]] = kIdrNalHeader;
178 } else {
179 const size_t kNumSlices = 1;
180 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
181 fragmentation.fragmentationOffset[0] = 0;
182 fragmentation.fragmentationLength[0] = encoded_image._length;
glaznev@webrtc.orge69220c2015-02-05 17:56:15183 const size_t kNalHeader = 0x41;
stefan@webrtc.org79c33592014-08-06 09:24:53184 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kNalHeader;
185 }
186 uint8_t value = 0;
187 int fragment_counter = 0;
188 for (size_t i = 0; i < encoded_image._length; ++i) {
189 if (fragment_counter == fragmentation.fragmentationVectorSize ||
190 i != fragmentation.fragmentationOffset[fragment_counter]) {
191 encoded_image._buffer[i] = value++;
192 } else {
193 ++fragment_counter;
194 }
195 }
Sergey Ulanov525df3f2016-08-03 00:46:41196 return callback_->OnEncodedImage(encoded_image, NULL, &fragmentation);
stefan@webrtc.org79c33592014-08-06 09:24:53197}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46198
199DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms)
200 : test::FakeEncoder(clock),
201 delay_ms_(delay_ms) {}
202
Miguel Casas-Sanchez47650702015-05-30 00:21:40203int32_t DelayedEncoder::Encode(const VideoFrame& input_image,
asapersson@webrtc.org049e4ec2014-11-20 10:19:46204 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 09:39:06205 const std::vector<FrameType>* frame_types) {
asapersson@webrtc.org049e4ec2014-11-20 10:19:46206 SleepMs(delay_ms_);
207 return FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
208}
pbos@webrtc.orgcb5118c2013-09-03 09:10:37209} // namespace test
stefan@webrtc.org360e3762013-08-22 09:29:56210} // namespace webrtc