blob: 9553dd72c523bc61dd7136ebfc7664611449680e [file] [log] [blame]
kjellander@webrtc.org35a17562011-10-06 06:44:54 +00001/*
pwestin@webrtc.orgce330352012-04-12 06:59:14 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +00003 *
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 */
kjellander@webrtc.org5b97b122011-12-08 07:42:18 +000010
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/video_coding/codecs/test/videoprocessor.h"
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <string.h>
14
ssilkin612f8582017-09-28 09:23:17 -070015#include <algorithm>
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000016#include <limits>
Erik Språng08127a92016-11-16 16:41:30 +010017#include <utility>
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000018
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/video/i420_buffer.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020020#include "common_types.h" // NOLINT(build/include)
ssilkin612f8582017-09-28 09:23:17 -070021#include "common_video/h264/h264_common.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "modules/video_coding/codecs/vp8/simulcast_rate_allocator.h"
23#include "modules/video_coding/include/video_codec_initializer.h"
24#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
25#include "rtc_base/checks.h"
26#include "rtc_base/logging.h"
27#include "rtc_base/timeutils.h"
28#include "system_wrappers/include/cpu_info.h"
29#include "test/gtest.h"
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000030
31namespace webrtc {
32namespace test {
33
brandtrb78bc752017-02-22 01:26:59 -080034namespace {
brandtr17b958c2017-03-07 01:41:43 -080035
brandtrbea36fd2017-08-07 03:36:54 -070036const int kRtpClockRateHz = 90000;
brandtr17b958c2017-03-07 01:41:43 -080037
brandtraebc61e2017-02-28 07:13:47 -080038std::unique_ptr<VideoBitrateAllocator> CreateBitrateAllocator(
brandtr07734a52017-08-08 08:35:53 -070039 TestConfig* config) {
brandtraebc61e2017-02-28 07:13:47 -080040 std::unique_ptr<TemporalLayersFactory> tl_factory;
brandtr07734a52017-08-08 08:35:53 -070041 if (config->codec_settings.codecType == VideoCodecType::kVideoCodecVP8) {
brandtraebc61e2017-02-28 07:13:47 -080042 tl_factory.reset(new TemporalLayersFactory());
brandtr07734a52017-08-08 08:35:53 -070043 config->codec_settings.VP8()->tl_factory = tl_factory.get();
brandtraebc61e2017-02-28 07:13:47 -080044 }
45 return std::unique_ptr<VideoBitrateAllocator>(
brandtr07734a52017-08-08 08:35:53 -070046 VideoCodecInitializer::CreateBitrateAllocator(config->codec_settings,
brandtraebc61e2017-02-28 07:13:47 -080047 std::move(tl_factory)));
48}
49
brandtr07734a52017-08-08 08:35:53 -070050void PrintCodecSettings(const VideoCodec& codec_settings) {
brandtrbea36fd2017-08-07 03:36:54 -070051 printf(" Codec settings:\n");
52 printf(" Codec type : %s\n",
kthelgason1cdddc92017-08-24 03:52:48 -070053 CodecTypeToPayloadString(codec_settings.codecType));
brandtr07734a52017-08-08 08:35:53 -070054 printf(" Start bitrate : %d kbps\n", codec_settings.startBitrate);
55 printf(" Max bitrate : %d kbps\n", codec_settings.maxBitrate);
56 printf(" Min bitrate : %d kbps\n", codec_settings.minBitrate);
57 printf(" Width : %d\n", codec_settings.width);
58 printf(" Height : %d\n", codec_settings.height);
59 printf(" Max frame rate : %d\n", codec_settings.maxFramerate);
60 printf(" QPmax : %d\n", codec_settings.qpMax);
61 if (codec_settings.codecType == kVideoCodecVP8) {
62 printf(" Complexity : %d\n", codec_settings.VP8().complexity);
brandtrbdd555c2017-08-21 01:34:04 -070063 printf(" Resilience : %d\n", codec_settings.VP8().resilience);
64 printf(" # temporal layers : %d\n",
65 codec_settings.VP8().numberOfTemporalLayers);
brandtr07734a52017-08-08 08:35:53 -070066 printf(" Denoising : %d\n", codec_settings.VP8().denoisingOn);
brandtrbea36fd2017-08-07 03:36:54 -070067 printf(" Error concealment : %d\n",
brandtr07734a52017-08-08 08:35:53 -070068 codec_settings.VP8().errorConcealmentOn);
brandtrbdd555c2017-08-21 01:34:04 -070069 printf(" Automatic resize : %d\n",
70 codec_settings.VP8().automaticResizeOn);
brandtr07734a52017-08-08 08:35:53 -070071 printf(" Frame dropping : %d\n", codec_settings.VP8().frameDroppingOn);
brandtr07734a52017-08-08 08:35:53 -070072 printf(" Key frame interval: %d\n", codec_settings.VP8().keyFrameInterval);
73 } else if (codec_settings.codecType == kVideoCodecVP9) {
74 printf(" Complexity : %d\n", codec_settings.VP9().complexity);
brandtrbdd555c2017-08-21 01:34:04 -070075 printf(" Resilience : %d\n", codec_settings.VP9().resilienceOn);
76 printf(" # temporal layers : %d\n",
77 codec_settings.VP9().numberOfTemporalLayers);
brandtr07734a52017-08-08 08:35:53 -070078 printf(" Denoising : %d\n", codec_settings.VP9().denoisingOn);
79 printf(" Frame dropping : %d\n", codec_settings.VP9().frameDroppingOn);
brandtr07734a52017-08-08 08:35:53 -070080 printf(" Key frame interval: %d\n", codec_settings.VP9().keyFrameInterval);
81 printf(" Adaptive QP mode : %d\n", codec_settings.VP9().adaptiveQpMode);
brandtrbdd555c2017-08-21 01:34:04 -070082 printf(" Automatic resize : %d\n",
83 codec_settings.VP9().automaticResizeOn);
84 printf(" # spatial layers : %d\n",
85 codec_settings.VP9().numberOfSpatialLayers);
86 printf(" Flexible mode : %d\n", codec_settings.VP9().flexibleMode);
brandtr07734a52017-08-08 08:35:53 -070087 } else if (codec_settings.codecType == kVideoCodecH264) {
88 printf(" Frame dropping : %d\n", codec_settings.H264().frameDroppingOn);
brandtrbea36fd2017-08-07 03:36:54 -070089 printf(" Key frame interval: %d\n",
brandtr07734a52017-08-08 08:35:53 -070090 codec_settings.H264().keyFrameInterval);
91 printf(" Profile : %d\n", codec_settings.H264().profile);
asaperssonae9ba042017-03-07 00:25:38 -080092 }
93}
94
asaperssona16c70b2017-08-29 05:39:36 -070095void VerifyQpParser(const EncodedImage& encoded_frame,
96 const TestConfig& config) {
brandtrd635e5b2017-09-06 04:48:22 -070097 if (config.hw_encoder)
asaperssona16c70b2017-08-29 05:39:36 -070098 return;
99
100 int qp;
101 if (config.codec_settings.codecType == kVideoCodecVP8) {
102 ASSERT_TRUE(vp8::GetQp(encoded_frame._buffer, encoded_frame._length, &qp));
103 } else if (config.codec_settings.codecType == kVideoCodecVP9) {
104 ASSERT_TRUE(vp9::GetQp(encoded_frame._buffer, encoded_frame._length, &qp));
105 } else {
106 return;
107 }
108 EXPECT_EQ(encoded_frame.qp_, qp) << "Encoder QP != parsed bitstream QP.";
109}
110
ssilkin612f8582017-09-28 09:23:17 -0700111rtc::Optional<size_t> GetMaxNaluLength(const EncodedImage& encoded_frame,
112 const TestConfig& config) {
113 if (config.codec_settings.codecType != kVideoCodecH264)
114 return rtc::Optional<size_t>();
115
116 std::vector<webrtc::H264::NaluIndex> nalu_indices =
117 webrtc::H264::FindNaluIndices(encoded_frame._buffer,
118 encoded_frame._length);
119
120 RTC_CHECK(!nalu_indices.empty());
121
122 size_t max_length = 0;
123 for (const webrtc::H264::NaluIndex& index : nalu_indices)
124 max_length = std::max(max_length, index.payload_size);
125
126 return rtc::Optional<size_t>(max_length);
127}
128
asaperssonae9ba042017-03-07 00:25:38 -0800129int GetElapsedTimeMicroseconds(int64_t start_ns, int64_t stop_ns) {
130 int64_t diff_us = (stop_ns - start_ns) / rtc::kNumNanosecsPerMicrosec;
131 RTC_DCHECK_GE(diff_us, std::numeric_limits<int>::min());
132 RTC_DCHECK_LE(diff_us, std::numeric_limits<int>::max());
133 return static_cast<int>(diff_us);
134}
135
brandtrb78bc752017-02-22 01:26:59 -0800136} // namespace
137
Åsa Persson7173cf22017-10-19 12:14:09 +0200138int TestConfig::NumberOfCores() const {
139 return use_single_core ? 1 : CpuInfo::DetectNumberOfCores();
brandtr8bc93852017-02-15 05:19:51 -0800140}
141
brandtrc4095522017-08-07 08:12:33 -0700142VideoProcessor::VideoProcessor(webrtc::VideoEncoder* encoder,
143 webrtc::VideoDecoder* decoder,
144 FrameReader* analysis_frame_reader,
145 FrameWriter* analysis_frame_writer,
146 PacketManipulator* packet_manipulator,
147 const TestConfig& config,
148 Stats* stats,
brandtrc4095522017-08-07 08:12:33 -0700149 IvfFileWriter* encoded_frame_writer,
150 FrameWriter* decoded_frame_writer)
brandtrc8c59052017-08-21 06:44:16 -0700151 : initialized_(false),
152 config_(config),
brandtr07734a52017-08-08 08:35:53 -0700153 encoder_(encoder),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000154 decoder_(decoder),
brandtr07734a52017-08-08 08:35:53 -0700155 bitrate_allocator_(CreateBitrateAllocator(&config_)),
brandtrbdd555c2017-08-21 01:34:04 -0700156 encode_callback_(this),
157 decode_callback_(this),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000158 packet_manipulator_(packet_manipulator),
brandtraebc61e2017-02-28 07:13:47 -0800159 analysis_frame_reader_(analysis_frame_reader),
160 analysis_frame_writer_(analysis_frame_writer),
brandtrb78bc752017-02-22 01:26:59 -0800161 encoded_frame_writer_(encoded_frame_writer),
162 decoded_frame_writer_(decoded_frame_writer),
brandtr8935d972017-09-06 01:53:22 -0700163 last_inputed_frame_num_(-1),
brandtr17b958c2017-03-07 01:41:43 -0800164 last_encoded_frame_num_(-1),
165 last_decoded_frame_num_(-1),
166 first_key_frame_has_been_excluded_(false),
brandtrbdd555c2017-08-21 01:34:04 -0700167 last_decoded_frame_buffer_(analysis_frame_reader->FrameLength()),
brandtraebc61e2017-02-28 07:13:47 -0800168 stats_(stats),
brandtrb57f4262017-08-30 06:29:51 -0700169 rate_update_index_(-1) {
Erik Språng08127a92016-11-16 16:41:30 +0100170 RTC_DCHECK(encoder);
171 RTC_DCHECK(decoder);
brandtraebc61e2017-02-28 07:13:47 -0800172 RTC_DCHECK(packet_manipulator);
brandtrb78bc752017-02-22 01:26:59 -0800173 RTC_DCHECK(analysis_frame_reader);
174 RTC_DCHECK(analysis_frame_writer);
Erik Språng08127a92016-11-16 16:41:30 +0100175 RTC_DCHECK(stats);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000176}
177
brandtr77920a42017-08-11 07:48:15 -0700178VideoProcessor::~VideoProcessor() = default;
brandtrbea36fd2017-08-07 03:36:54 -0700179
brandtrc4095522017-08-07 08:12:33 -0700180void VideoProcessor::Init() {
brandtrc8c59052017-08-21 06:44:16 -0700181 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700182 RTC_DCHECK(!initialized_) << "VideoProcessor already initialized.";
183 initialized_ = true;
brandtr17b958c2017-03-07 01:41:43 -0800184
brandtrbea36fd2017-08-07 03:36:54 -0700185 // Setup required callbacks for the encoder and decoder.
brandtrbdd555c2017-08-21 01:34:04 -0700186 RTC_CHECK_EQ(encoder_->RegisterEncodeCompleteCallback(&encode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800187 WEBRTC_VIDEO_CODEC_OK)
188 << "Failed to register encode complete callback";
brandtrbdd555c2017-08-21 01:34:04 -0700189 RTC_CHECK_EQ(decoder_->RegisterDecodeCompleteCallback(&decode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800190 WEBRTC_VIDEO_CODEC_OK)
191 << "Failed to register decode complete callback";
192
brandtraebc61e2017-02-28 07:13:47 -0800193 // Initialize the encoder and decoder.
Åsa Persson7173cf22017-10-19 12:14:09 +0200194 int num_cores = config_.NumberOfCores();
asapersson654d54c2017-02-10 00:16:07 -0800195 RTC_CHECK_EQ(
brandtr07734a52017-08-08 08:35:53 -0700196 encoder_->InitEncode(&config_.codec_settings, num_cores,
asapersson654d54c2017-02-10 00:16:07 -0800197 config_.networking_config.max_payload_size_in_bytes),
198 WEBRTC_VIDEO_CODEC_OK)
199 << "Failed to initialize VideoEncoder";
200
brandtr07734a52017-08-08 08:35:53 -0700201 RTC_CHECK_EQ(decoder_->InitDecode(&config_.codec_settings, num_cores),
asapersson654d54c2017-02-10 00:16:07 -0800202 WEBRTC_VIDEO_CODEC_OK)
203 << "Failed to initialize VideoDecoder";
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000204
kjellander@webrtc.org5b97b122011-12-08 07:42:18 +0000205 if (config_.verbose) {
206 printf("Video Processor:\n");
brandtrbea36fd2017-08-07 03:36:54 -0700207 printf(" Filename : %s\n", config_.filename.c_str());
208 printf(" Total # of frames: %d\n",
asapersson1d29c862017-06-22 02:18:50 -0700209 analysis_frame_reader_->NumberOfFrames());
brandtrbea36fd2017-08-07 03:36:54 -0700210 printf(" # CPU cores used : %d\n", num_cores);
211 const char* encoder_name = encoder_->ImplementationName();
212 printf(" Encoder implementation name: %s\n", encoder_name);
213 const char* decoder_name = decoder_->ImplementationName();
214 printf(" Decoder implementation name: %s\n", decoder_name);
215 if (strcmp(encoder_name, decoder_name) == 0) {
216 printf(" Codec implementation name : %s_%s\n",
kthelgason1cdddc92017-08-24 03:52:48 -0700217 CodecTypeToPayloadString(config_.codec_settings.codecType),
asapersson30df64f2017-05-19 04:07:38 -0700218 encoder_->ImplementationName());
219 }
asaperssonae9ba042017-03-07 00:25:38 -0800220 PrintCodecSettings(config_.codec_settings);
brandtrbea36fd2017-08-07 03:36:54 -0700221 printf("\n");
kjellander@webrtc.org5b97b122011-12-08 07:42:18 +0000222 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000223}
224
brandtr77920a42017-08-11 07:48:15 -0700225void VideoProcessor::Release() {
brandtrc8c59052017-08-21 06:44:16 -0700226 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
227
brandtr77920a42017-08-11 07:48:15 -0700228 RTC_CHECK_EQ(encoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
229 RTC_CHECK_EQ(decoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
230
brandtrbdd555c2017-08-21 01:34:04 -0700231 encoder_->RegisterEncodeCompleteCallback(nullptr);
232 decoder_->RegisterDecodeCompleteCallback(nullptr);
233
brandtr77920a42017-08-11 07:48:15 -0700234 initialized_ = false;
235}
236
brandtr8935d972017-09-06 01:53:22 -0700237void VideoProcessor::ProcessFrame() {
brandtrc8c59052017-08-21 06:44:16 -0700238 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700239 RTC_DCHECK(initialized_) << "VideoProcessor not initialized.";
brandtr8935d972017-09-06 01:53:22 -0700240 ++last_inputed_frame_num_;
asapersson654d54c2017-02-10 00:16:07 -0800241
brandtrbdd555c2017-08-21 01:34:04 -0700242 // Get frame from file.
magjed3f075492017-06-01 10:02:26 -0700243 rtc::scoped_refptr<I420BufferInterface> buffer(
brandtrb78bc752017-02-22 01:26:59 -0800244 analysis_frame_reader_->ReadFrame());
brandtrbdd555c2017-08-21 01:34:04 -0700245 RTC_CHECK(buffer) << "Tried to read too many frames from the file.";
brandtrb57f4262017-08-30 06:29:51 -0700246 // Use the frame number as the basis for timestamp to identify frames. Let the
247 // first timestamp be non-zero, to not make the IvfFileWriter believe that we
248 // want to use capture timestamps in the IVF files.
brandtr8935d972017-09-06 01:53:22 -0700249 const uint32_t rtp_timestamp = (last_inputed_frame_num_ + 1) *
250 kRtpClockRateHz /
brandtrb57f4262017-08-30 06:29:51 -0700251 config_.codec_settings.maxFramerate;
brandtr8935d972017-09-06 01:53:22 -0700252 rtp_timestamp_to_frame_num_[rtp_timestamp] = last_inputed_frame_num_;
brandtrbdd555c2017-08-21 01:34:04 -0700253 const int64_t kNoRenderTime = 0;
brandtrb57f4262017-08-30 06:29:51 -0700254 VideoFrame source_frame(buffer, rtp_timestamp, kNoRenderTime,
255 webrtc::kVideoRotation_0);
brandtr17b958c2017-03-07 01:41:43 -0800256
257 // Decide if we are going to force a keyframe.
258 std::vector<FrameType> frame_types(1, kVideoFrameDelta);
259 if (config_.keyframe_interval > 0 &&
brandtr8935d972017-09-06 01:53:22 -0700260 last_inputed_frame_num_ % config_.keyframe_interval == 0) {
brandtr17b958c2017-03-07 01:41:43 -0800261 frame_types[0] = kVideoFrameKey;
262 }
263
264 // Create frame statistics object used for aggregation at end of test run.
brandtr8935d972017-09-06 01:53:22 -0700265 FrameStatistic* frame_stat = stats_->AddFrame();
brandtr17b958c2017-03-07 01:41:43 -0800266
267 // For the highest measurement accuracy of the encode time, the start/stop
268 // time recordings should wrap the Encode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700269 frame_stat->encode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800270 frame_stat->encode_return_code =
271 encoder_->Encode(source_frame, nullptr, &frame_types);
272
273 if (frame_stat->encode_return_code != WEBRTC_VIDEO_CODEC_OK) {
brandtr8935d972017-09-06 01:53:22 -0700274 LOG(LS_WARNING) << "Failed to encode frame " << last_inputed_frame_num_
brandtrbea36fd2017-08-07 03:36:54 -0700275 << ", return code: " << frame_stat->encode_return_code
276 << ".";
brandtr17b958c2017-03-07 01:41:43 -0800277 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000278}
279
brandtrbdd555c2017-08-21 01:34:04 -0700280void VideoProcessor::SetRates(int bitrate_kbps, int framerate_fps) {
brandtrc8c59052017-08-21 06:44:16 -0700281 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbdd555c2017-08-21 01:34:04 -0700282 config_.codec_settings.maxFramerate = framerate_fps;
brandtrbea36fd2017-08-07 03:36:54 -0700283 int set_rates_result = encoder_->SetRateAllocation(
brandtrbdd555c2017-08-21 01:34:04 -0700284 bitrate_allocator_->GetAllocation(bitrate_kbps * 1000, framerate_fps),
285 framerate_fps);
brandtrbea36fd2017-08-07 03:36:54 -0700286 RTC_DCHECK_GE(set_rates_result, 0)
brandtrbdd555c2017-08-21 01:34:04 -0700287 << "Failed to update encoder with new rate " << bitrate_kbps << ".";
brandtrb57f4262017-08-30 06:29:51 -0700288 ++rate_update_index_;
289 num_dropped_frames_.push_back(0);
290 num_spatial_resizes_.push_back(0);
brandtrbea36fd2017-08-07 03:36:54 -0700291}
292
brandtrb57f4262017-08-30 06:29:51 -0700293std::vector<int> VideoProcessor::NumberDroppedFramesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700294 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700295 return num_dropped_frames_;
296}
297
brandtrb57f4262017-08-30 06:29:51 -0700298std::vector<int> VideoProcessor::NumberSpatialResizesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700299 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700300 return num_spatial_resizes_;
301}
302
brandtr45535622017-08-22 03:33:11 -0700303void VideoProcessor::FrameEncoded(webrtc::VideoCodecType codec,
304 const EncodedImage& encoded_image) {
brandtrc8c59052017-08-21 06:44:16 -0700305 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
306
brandtr32e0d262017-02-15 05:29:38 -0800307 // For the highest measurement accuracy of the encode time, the start/stop
308 // time recordings should wrap the Encode call as tightly as possible.
309 int64_t encode_stop_ns = rtc::TimeNanos();
310
brandtr8935d972017-09-06 01:53:22 -0700311 // Take the opportunity to verify the QP bitstream parser.
312 VerifyQpParser(encoded_image, config_);
brandtrb78bc752017-02-22 01:26:59 -0800313
brandtrb57f4262017-08-30 06:29:51 -0700314 // Check for dropped frames.
315 const int frame_number =
316 rtp_timestamp_to_frame_num_[encoded_image._timeStamp];
brandtr17b958c2017-03-07 01:41:43 -0800317 bool last_frame_missing = false;
318 if (frame_number > 0) {
319 RTC_DCHECK_GE(last_encoded_frame_num_, 0);
320 int num_dropped_from_last_encode =
321 frame_number - last_encoded_frame_num_ - 1;
322 RTC_DCHECK_GE(num_dropped_from_last_encode, 0);
brandtrb57f4262017-08-30 06:29:51 -0700323 RTC_CHECK_GE(rate_update_index_, 0);
324 num_dropped_frames_[rate_update_index_] += num_dropped_from_last_encode;
brandtr17b958c2017-03-07 01:41:43 -0800325 if (num_dropped_from_last_encode > 0) {
326 // For dropped frames, we write out the last decoded frame to avoid
327 // getting out of sync for the computation of PSNR and SSIM.
328 for (int i = 0; i < num_dropped_from_last_encode; i++) {
329 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
330 analysis_frame_writer_->FrameLength());
331 RTC_CHECK(analysis_frame_writer_->WriteFrame(
332 last_decoded_frame_buffer_.data()));
333 if (decoded_frame_writer_) {
334 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
335 decoded_frame_writer_->FrameLength());
336 RTC_CHECK(decoded_frame_writer_->WriteFrame(
337 last_decoded_frame_buffer_.data()));
338 }
brandtrb78bc752017-02-22 01:26:59 -0800339 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000340 }
brandtr8935d972017-09-06 01:53:22 -0700341 const FrameStatistic* last_encoded_frame_stat =
342 stats_->GetFrame(last_encoded_frame_num_);
343 last_frame_missing = (last_encoded_frame_stat->manipulated_length == 0);
brandtr17b958c2017-03-07 01:41:43 -0800344 }
345 // Ensure strict monotonicity.
346 RTC_CHECK_GT(frame_number, last_encoded_frame_num_);
347 last_encoded_frame_num_ = frame_number;
348
brandtr8935d972017-09-06 01:53:22 -0700349 // Update frame statistics.
350 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
351 frame_stat->encode_time_us =
352 GetElapsedTimeMicroseconds(frame_stat->encode_start_ns, encode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800353 frame_stat->encoding_successful = true;
brandtr8935d972017-09-06 01:53:22 -0700354 frame_stat->encoded_frame_size_bytes = encoded_image._length;
brandtr17b958c2017-03-07 01:41:43 -0800355 frame_stat->frame_type = encoded_image._frameType;
356 frame_stat->qp = encoded_image.qp_;
brandtr8935d972017-09-06 01:53:22 -0700357 frame_stat->bitrate_kbps = static_cast<int>(
brandtr07734a52017-08-08 08:35:53 -0700358 encoded_image._length * config_.codec_settings.maxFramerate * 8 / 1000);
brandtr17b958c2017-03-07 01:41:43 -0800359 frame_stat->total_packets =
philipelcce46fc2015-12-21 03:04:49 -0800360 encoded_image._length / config_.networking_config.packet_size_in_bytes +
361 1;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000362
ssilkin612f8582017-09-28 09:23:17 -0700363 frame_stat->max_nalu_length = GetMaxNaluLength(encoded_image, config_);
364
brandtr8bc93852017-02-15 05:19:51 -0800365 // Simulate packet loss.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000366 bool exclude_this_frame = false;
Peter Boström49e196a2015-10-23 15:58:18 +0200367 if (encoded_image._frameType == kVideoFrameKey) {
brandtraebc61e2017-02-28 07:13:47 -0800368 // Only keyframes can be excluded.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000369 switch (config_.exclude_frame_types) {
370 case kExcludeOnlyFirstKeyFrame:
371 if (!first_key_frame_has_been_excluded_) {
372 first_key_frame_has_been_excluded_ = true;
373 exclude_this_frame = true;
374 }
375 break;
376 case kExcludeAllKeyFrames:
377 exclude_this_frame = true;
378 break;
379 default:
Erik Språng08127a92016-11-16 16:41:30 +0100380 RTC_NOTREACHED();
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000381 }
382 }
hbosbab934b2016-01-27 01:36:03 -0800383
384 // Make a raw copy of the |encoded_image| buffer.
hbos3fe2c6a2016-01-22 00:07:12 -0800385 size_t copied_buffer_size = encoded_image._length +
386 EncodedImage::GetBufferPaddingBytes(codec);
kwiberg3f55dea2016-02-29 05:51:59 -0800387 std::unique_ptr<uint8_t[]> copied_buffer(new uint8_t[copied_buffer_size]);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000388 memcpy(copied_buffer.get(), encoded_image._buffer, encoded_image._length);
hbosbab934b2016-01-27 01:36:03 -0800389 // The image to feed to the decoder.
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000390 EncodedImage copied_image;
391 memcpy(&copied_image, &encoded_image, sizeof(copied_image));
hbos3fe2c6a2016-01-22 00:07:12 -0800392 copied_image._size = copied_buffer_size;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000393 copied_image._buffer = copied_buffer.get();
hbosbab934b2016-01-27 01:36:03 -0800394
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000395 if (!exclude_this_frame) {
brandtr17b958c2017-03-07 01:41:43 -0800396 frame_stat->packets_dropped =
philipelcce46fc2015-12-21 03:04:49 -0800397 packet_manipulator_->ManipulatePackets(&copied_image);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000398 }
brandtr8935d972017-09-06 01:53:22 -0700399 frame_stat->manipulated_length = copied_image._length;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000400
brandtr32e0d262017-02-15 05:29:38 -0800401 // For the highest measurement accuracy of the decode time, the start/stop
402 // time recordings should wrap the Decode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700403 frame_stat->decode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800404 frame_stat->decode_return_code =
405 decoder_->Decode(copied_image, last_frame_missing, nullptr);
brandtr8bc93852017-02-15 05:19:51 -0800406
brandtr17b958c2017-03-07 01:41:43 -0800407 if (frame_stat->decode_return_code != WEBRTC_VIDEO_CODEC_OK) {
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000408 // Write the last successful frame the output file to avoid getting it out
brandtr8bc93852017-02-15 05:19:51 -0800409 // of sync with the source file for SSIM and PSNR comparisons.
brandtr17b958c2017-03-07 01:41:43 -0800410 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
411 analysis_frame_writer_->FrameLength());
412 RTC_CHECK(
413 analysis_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800414 if (decoded_frame_writer_) {
brandtr17b958c2017-03-07 01:41:43 -0800415 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
416 decoded_frame_writer_->FrameLength());
417 RTC_CHECK(
418 decoded_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800419 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000420 }
brandtr8935d972017-09-06 01:53:22 -0700421
422 if (encoded_frame_writer_) {
423 RTC_CHECK(encoded_frame_writer_->WriteFrame(encoded_image, codec));
424 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000425}
426
brandtrc4095522017-08-07 08:12:33 -0700427void VideoProcessor::FrameDecoded(const VideoFrame& image) {
brandtrc8c59052017-08-21 06:44:16 -0700428 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
429
brandtr32e0d262017-02-15 05:29:38 -0800430 // For the highest measurement accuracy of the decode time, the start/stop
431 // time recordings should wrap the Decode call as tightly as possible.
Niels Möllerd28db7f2016-05-10 16:31:47 +0200432 int64_t decode_stop_ns = rtc::TimeNanos();
brandtr8bc93852017-02-15 05:19:51 -0800433
brandtr8935d972017-09-06 01:53:22 -0700434 // Update frame statistics.
brandtrb57f4262017-08-30 06:29:51 -0700435 const int frame_number = rtp_timestamp_to_frame_num_[image.timestamp()];
brandtr8935d972017-09-06 01:53:22 -0700436 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
437 frame_stat->decoded_width = image.width();
438 frame_stat->decoded_height = image.height();
439 frame_stat->decode_time_us =
440 GetElapsedTimeMicroseconds(frame_stat->decode_start_ns, decode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800441 frame_stat->decoding_successful = true;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000442
brandtr17b958c2017-03-07 01:41:43 -0800443 // Check if the codecs have resized the frame since previously decoded frame.
444 if (frame_number > 0) {
brandtrb57f4262017-08-30 06:29:51 -0700445 RTC_CHECK_GE(last_decoded_frame_num_, 0);
brandtr8935d972017-09-06 01:53:22 -0700446 const FrameStatistic* last_decoded_frame_stat =
447 stats_->GetFrame(last_decoded_frame_num_);
brandtr17b958c2017-03-07 01:41:43 -0800448 if (static_cast<int>(image.width()) !=
brandtr8935d972017-09-06 01:53:22 -0700449 last_decoded_frame_stat->decoded_width ||
brandtr17b958c2017-03-07 01:41:43 -0800450 static_cast<int>(image.height()) !=
brandtr8935d972017-09-06 01:53:22 -0700451 last_decoded_frame_stat->decoded_height) {
brandtrb57f4262017-08-30 06:29:51 -0700452 RTC_CHECK_GE(rate_update_index_, 0);
453 ++num_spatial_resizes_[rate_update_index_];
brandtr17b958c2017-03-07 01:41:43 -0800454 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000455 }
brandtr17b958c2017-03-07 01:41:43 -0800456 // Ensure strict monotonicity.
457 RTC_CHECK_GT(frame_number, last_decoded_frame_num_);
458 last_decoded_frame_num_ = frame_number;
459
brandtr8935d972017-09-06 01:53:22 -0700460 // Check if frame size is different from the original size, and if so,
brandtr17b958c2017-03-07 01:41:43 -0800461 // scale back to original size. This is needed for the PSNR and SSIM
brandtr8bc93852017-02-15 05:19:51 -0800462 // calculations.
brandtr17b958c2017-03-07 01:41:43 -0800463 size_t extracted_length;
464 rtc::Buffer extracted_buffer;
brandtr07734a52017-08-08 08:35:53 -0700465 if (image.width() != config_.codec_settings.width ||
466 image.height() != config_.codec_settings.height) {
brandtr17b958c2017-03-07 01:41:43 -0800467 rtc::scoped_refptr<I420Buffer> scaled_buffer(I420Buffer::Create(
brandtr07734a52017-08-08 08:35:53 -0700468 config_.codec_settings.width, config_.codec_settings.height));
Niels Möller718a7632016-06-13 13:06:01 +0200469 // Should be the same aspect ratio, no cropping needed.
magjed3f075492017-06-01 10:02:26 -0700470 scaled_buffer->ScaleFrom(*image.video_frame_buffer()->ToI420());
Niels Möller718a7632016-06-13 13:06:01 +0200471
nisseeb44b392017-04-28 07:18:05 -0700472 size_t length = CalcBufferSize(VideoType::kI420, scaled_buffer->width(),
473 scaled_buffer->height());
brandtr17b958c2017-03-07 01:41:43 -0800474 extracted_buffer.SetSize(length);
475 extracted_length =
476 ExtractBuffer(scaled_buffer, length, extracted_buffer.data());
477 } else {
478 // No resize.
nisseeb44b392017-04-28 07:18:05 -0700479 size_t length =
480 CalcBufferSize(VideoType::kI420, image.width(), image.height());
brandtr17b958c2017-03-07 01:41:43 -0800481 extracted_buffer.SetSize(length);
magjed3f075492017-06-01 10:02:26 -0700482 extracted_length = ExtractBuffer(image.video_frame_buffer()->ToI420(),
483 length, extracted_buffer.data());
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000484 }
brandtr17b958c2017-03-07 01:41:43 -0800485
486 RTC_DCHECK_EQ(extracted_length, analysis_frame_writer_->FrameLength());
487 RTC_CHECK(analysis_frame_writer_->WriteFrame(extracted_buffer.data()));
488 if (decoded_frame_writer_) {
489 RTC_DCHECK_EQ(extracted_length, decoded_frame_writer_->FrameLength());
490 RTC_CHECK(decoded_frame_writer_->WriteFrame(extracted_buffer.data()));
491 }
492
493 last_decoded_frame_buffer_ = std::move(extracted_buffer);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000494}
495
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000496} // namespace test
497} // namespace webrtc