blob: d0b6402004e74305066a01a45ccec148d7cd43d5 [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
13#include "testing/gtest/include/gtest/gtest.h"
14
pbos@webrtc.orgab990ae2014-09-17 09:02:25 +000015#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +000016#include "webrtc/system_wrappers/interface/sleep.h"
pbos@webrtc.orgab990ae2014-09-17 09:02:25 +000017
stefan@webrtc.org360e3762013-08-22 09:29:56 +000018namespace webrtc {
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000019namespace test {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000020
21FakeEncoder::FakeEncoder(Clock* clock)
22 : clock_(clock),
23 callback_(NULL),
24 target_bitrate_kbps_(0),
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000025 max_target_bitrate_kbps_(-1),
stefan@webrtc.org360e3762013-08-22 09:29:56 +000026 last_encode_time_ms_(0) {
sprang@webrtc.org40709352013-11-26 11:41:59 +000027 // Generate some arbitrary not-all-zero data
28 for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) {
29 encoded_buffer_[i] = static_cast<uint8_t>(i);
30 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +000031}
32
33FakeEncoder::~FakeEncoder() {}
34
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000035void FakeEncoder::SetMaxBitrate(int max_kbps) {
36 assert(max_kbps >= -1); // max_kbps == -1 disables it.
37 max_target_bitrate_kbps_ = max_kbps;
38}
39
stefan@webrtc.org360e3762013-08-22 09:29:56 +000040int32_t FakeEncoder::InitEncode(const VideoCodec* config,
41 int32_t number_of_cores,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000042 size_t max_payload_size) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000043 config_ = *config;
44 target_bitrate_kbps_ = config_.startBitrate;
45 return 0;
46}
47
48int32_t FakeEncoder::Encode(
49 const I420VideoFrame& input_image,
50 const CodecSpecificInfo* codec_specific_info,
51 const std::vector<VideoFrameType>* frame_types) {
52 assert(config_.maxFramerate > 0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000053 int64_t time_since_last_encode_ms = 1000 / config_.maxFramerate;
stefan@webrtc.org360e3762013-08-22 09:29:56 +000054 int64_t time_now_ms = clock_->TimeInMilliseconds();
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +000055 const bool first_encode = last_encode_time_ms_ == 0;
56 if (!first_encode) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000057 // 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:27 +000059 time_since_last_encode_ms = time_now_ms - last_encode_time_ms_;
stefan@webrtc.org360e3762013-08-22 09:29:56 +000060 }
61
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000062 size_t bits_available =
63 static_cast<size_t>(target_bitrate_kbps_ * time_since_last_encode_ms);
64 size_t min_bits = static_cast<size_t>(
65 config_.simulcastStream[0].minBitrate * time_since_last_encode_ms);
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +000066 if (bits_available < min_bits)
67 bits_available = min_bits;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000068 size_t max_bits =
69 static_cast<size_t>(max_target_bitrate_kbps_ * time_since_last_encode_ms);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000070 if (max_bits > 0 && max_bits < bits_available)
71 bits_available = max_bits;
stefan@webrtc.org360e3762013-08-22 09:29:56 +000072 last_encode_time_ms_ = time_now_ms;
73
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +000074 assert(config_.numberOfSimulcastStreams > 0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000075 for (unsigned char i = 0; i < config_.numberOfSimulcastStreams; ++i) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000076 CodecSpecificInfo specifics;
77 memset(&specifics, 0, sizeof(specifics));
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +000078 specifics.codecType = kVideoCodecGeneric;
79 specifics.codecSpecific.generic.simulcast_idx = i;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000080 size_t min_stream_bits = static_cast<size_t>(
81 config_.simulcastStream[i].minBitrate * time_since_last_encode_ms);
82 size_t max_stream_bits = static_cast<size_t>(
83 config_.simulcastStream[i].maxBitrate * time_since_last_encode_ms);
84 size_t stream_bits = (bits_available > max_stream_bits) ? max_stream_bits :
stefan@webrtc.org360e3762013-08-22 09:29:56 +000085 bits_available;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000086 size_t stream_bytes = (stream_bits + 7) / 8;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +000087 if (first_encode) {
88 // The first frame is a key frame and should be larger.
89 // TODO(holmer): The FakeEncoder should store the bits_available between
90 // encodes so that it can compensate for oversized frames.
91 stream_bytes *= 10;
92 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000093 if (stream_bytes > sizeof(encoded_buffer_))
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +000094 stream_bytes = sizeof(encoded_buffer_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +000095
pbos@webrtc.orgc095f512013-08-22 12:34:58 +000096 EncodedImage encoded(
97 encoded_buffer_, stream_bytes, sizeof(encoded_buffer_));
stefan@webrtc.org360e3762013-08-22 09:29:56 +000098 encoded._timeStamp = input_image.timestamp();
99 encoded.capture_time_ms_ = input_image.render_time_ms();
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000100 encoded._frameType = (*frame_types)[i];
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000101 // Always encode something on the first frame.
102 if (min_stream_bits > bits_available && i > 0) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000103 encoded._length = 0;
104 encoded._frameType = kSkipFrame;
105 }
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000106 assert(callback_ != NULL);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000107 if (callback_->Encoded(encoded, &specifics, NULL) != 0)
108 return -1;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000109 bits_available -= std::min(encoded._length * 8, bits_available);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000110 }
111 return 0;
112}
113
114int32_t FakeEncoder::RegisterEncodeCompleteCallback(
115 EncodedImageCallback* callback) {
116 callback_ = callback;
117 return 0;
118}
119
120int32_t FakeEncoder::Release() { return 0; }
121
122int32_t FakeEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
123 return 0;
124}
125
126int32_t FakeEncoder::SetRates(uint32_t new_target_bitrate, uint32_t framerate) {
127 target_bitrate_kbps_ = new_target_bitrate;
128 return 0;
129}
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000130
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000131FakeH264Encoder::FakeH264Encoder(Clock* clock)
132 : FakeEncoder(clock), callback_(NULL), idr_counter_(0) {
133 FakeEncoder::RegisterEncodeCompleteCallback(this);
134}
135
136int32_t FakeH264Encoder::RegisterEncodeCompleteCallback(
137 EncodedImageCallback* callback) {
138 callback_ = callback;
139 return 0;
140}
141
142int32_t FakeH264Encoder::Encoded(EncodedImage& encoded_image,
143 const CodecSpecificInfo* codec_specific_info,
144 const RTPFragmentationHeader* fragments) {
145 const size_t kSpsSize = 8;
146 const size_t kPpsSize = 11;
147 const int kIdrFrequency = 10;
148 RTPFragmentationHeader fragmentation;
149 if (idr_counter_++ % kIdrFrequency == 0 &&
150 encoded_image._length > kSpsSize + kPpsSize + 1) {
151 const size_t kNumSlices = 3;
152 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
153 fragmentation.fragmentationOffset[0] = 0;
154 fragmentation.fragmentationLength[0] = kSpsSize;
155 fragmentation.fragmentationOffset[1] = kSpsSize;
156 fragmentation.fragmentationLength[1] = kPpsSize;
157 fragmentation.fragmentationOffset[2] = kSpsSize + kPpsSize;
158 fragmentation.fragmentationLength[2] =
159 encoded_image._length - (kSpsSize + kPpsSize);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000160 const size_t kSpsNalHeader = 0x37;
161 const size_t kPpsNalHeader = 0x38;
162 const size_t kIdrNalHeader = 0x15;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000163 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kSpsNalHeader;
164 encoded_image._buffer[fragmentation.fragmentationOffset[1]] = kPpsNalHeader;
165 encoded_image._buffer[fragmentation.fragmentationOffset[2]] = kIdrNalHeader;
166 } else {
167 const size_t kNumSlices = 1;
168 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
169 fragmentation.fragmentationOffset[0] = 0;
170 fragmentation.fragmentationLength[0] = encoded_image._length;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000171 const size_t kNalHeader = 0x11;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000172 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kNalHeader;
173 }
174 uint8_t value = 0;
175 int fragment_counter = 0;
176 for (size_t i = 0; i < encoded_image._length; ++i) {
177 if (fragment_counter == fragmentation.fragmentationVectorSize ||
178 i != fragmentation.fragmentationOffset[fragment_counter]) {
179 encoded_image._buffer[i] = value++;
180 } else {
181 ++fragment_counter;
182 }
183 }
184 return callback_->Encoded(encoded_image, NULL, &fragmentation);
185}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000186
187DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms)
188 : test::FakeEncoder(clock),
189 delay_ms_(delay_ms) {}
190
191int32_t DelayedEncoder::Encode(const I420VideoFrame& input_image,
192 const CodecSpecificInfo* codec_specific_info,
193 const std::vector<VideoFrameType>* frame_types) {
194 SleepMs(delay_ms_);
195 return FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
196}
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +0000197} // namespace test
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000198} // namespace webrtc