blob: af5b4b35b5e75465823f89dbf0aaa5416568db21 [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
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000015#include <limits>
kwiberg3f55dea2016-02-29 05:51:59 -080016#include <memory>
Erik Språng08127a92016-11-16 16:41:30 +010017#include <utility>
kjellander@webrtc.org9c4e6622013-02-13 09:35:12 +000018#include <vector>
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000019
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "api/video/i420_buffer.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020021#include "common_types.h" // NOLINT(build/include)
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
asaperssonae9ba042017-03-07 00:25:38 -0800111int GetElapsedTimeMicroseconds(int64_t start_ns, int64_t stop_ns) {
112 int64_t diff_us = (stop_ns - start_ns) / rtc::kNumNanosecsPerMicrosec;
113 RTC_DCHECK_GE(diff_us, std::numeric_limits<int>::min());
114 RTC_DCHECK_LE(diff_us, std::numeric_limits<int>::max());
115 return static_cast<int>(diff_us);
116}
117
brandtrb78bc752017-02-22 01:26:59 -0800118} // namespace
119
brandtr8bc93852017-02-15 05:19:51 -0800120const char* ExcludeFrameTypesToStr(ExcludeFrameTypes e) {
121 switch (e) {
122 case kExcludeOnlyFirstKeyFrame:
123 return "ExcludeOnlyFirstKeyFrame";
124 case kExcludeAllKeyFrames:
125 return "ExcludeAllKeyFrames";
126 default:
127 RTC_NOTREACHED();
128 return "Unknown";
129 }
130}
131
brandtrc4095522017-08-07 08:12:33 -0700132VideoProcessor::VideoProcessor(webrtc::VideoEncoder* encoder,
133 webrtc::VideoDecoder* decoder,
134 FrameReader* analysis_frame_reader,
135 FrameWriter* analysis_frame_writer,
136 PacketManipulator* packet_manipulator,
137 const TestConfig& config,
138 Stats* stats,
brandtrc4095522017-08-07 08:12:33 -0700139 IvfFileWriter* encoded_frame_writer,
140 FrameWriter* decoded_frame_writer)
brandtrc8c59052017-08-21 06:44:16 -0700141 : initialized_(false),
142 config_(config),
brandtr07734a52017-08-08 08:35:53 -0700143 encoder_(encoder),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000144 decoder_(decoder),
brandtr07734a52017-08-08 08:35:53 -0700145 bitrate_allocator_(CreateBitrateAllocator(&config_)),
brandtrbdd555c2017-08-21 01:34:04 -0700146 encode_callback_(this),
147 decode_callback_(this),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000148 packet_manipulator_(packet_manipulator),
brandtraebc61e2017-02-28 07:13:47 -0800149 analysis_frame_reader_(analysis_frame_reader),
150 analysis_frame_writer_(analysis_frame_writer),
brandtrb78bc752017-02-22 01:26:59 -0800151 encoded_frame_writer_(encoded_frame_writer),
152 decoded_frame_writer_(decoded_frame_writer),
brandtr8935d972017-09-06 01:53:22 -0700153 last_inputed_frame_num_(-1),
brandtr17b958c2017-03-07 01:41:43 -0800154 last_encoded_frame_num_(-1),
155 last_decoded_frame_num_(-1),
156 first_key_frame_has_been_excluded_(false),
brandtrbdd555c2017-08-21 01:34:04 -0700157 last_decoded_frame_buffer_(analysis_frame_reader->FrameLength()),
brandtraebc61e2017-02-28 07:13:47 -0800158 stats_(stats),
brandtrb57f4262017-08-30 06:29:51 -0700159 rate_update_index_(-1) {
Erik Språng08127a92016-11-16 16:41:30 +0100160 RTC_DCHECK(encoder);
161 RTC_DCHECK(decoder);
brandtraebc61e2017-02-28 07:13:47 -0800162 RTC_DCHECK(packet_manipulator);
brandtrb78bc752017-02-22 01:26:59 -0800163 RTC_DCHECK(analysis_frame_reader);
164 RTC_DCHECK(analysis_frame_writer);
Erik Språng08127a92016-11-16 16:41:30 +0100165 RTC_DCHECK(stats);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000166}
167
brandtr77920a42017-08-11 07:48:15 -0700168VideoProcessor::~VideoProcessor() = default;
brandtrbea36fd2017-08-07 03:36:54 -0700169
brandtrc4095522017-08-07 08:12:33 -0700170void VideoProcessor::Init() {
brandtrc8c59052017-08-21 06:44:16 -0700171 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700172 RTC_DCHECK(!initialized_) << "VideoProcessor already initialized.";
173 initialized_ = true;
brandtr17b958c2017-03-07 01:41:43 -0800174
brandtrbea36fd2017-08-07 03:36:54 -0700175 // Setup required callbacks for the encoder and decoder.
brandtrbdd555c2017-08-21 01:34:04 -0700176 RTC_CHECK_EQ(encoder_->RegisterEncodeCompleteCallback(&encode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800177 WEBRTC_VIDEO_CODEC_OK)
178 << "Failed to register encode complete callback";
brandtrbdd555c2017-08-21 01:34:04 -0700179 RTC_CHECK_EQ(decoder_->RegisterDecodeCompleteCallback(&decode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800180 WEBRTC_VIDEO_CODEC_OK)
181 << "Failed to register decode complete callback";
182
brandtraebc61e2017-02-28 07:13:47 -0800183 // Initialize the encoder and decoder.
asapersson996103a2017-02-21 08:30:04 -0800184 uint32_t num_cores =
185 config_.use_single_core ? 1 : CpuInfo::DetectNumberOfCores();
asapersson654d54c2017-02-10 00:16:07 -0800186 RTC_CHECK_EQ(
brandtr07734a52017-08-08 08:35:53 -0700187 encoder_->InitEncode(&config_.codec_settings, num_cores,
asapersson654d54c2017-02-10 00:16:07 -0800188 config_.networking_config.max_payload_size_in_bytes),
189 WEBRTC_VIDEO_CODEC_OK)
190 << "Failed to initialize VideoEncoder";
191
brandtr07734a52017-08-08 08:35:53 -0700192 RTC_CHECK_EQ(decoder_->InitDecode(&config_.codec_settings, num_cores),
asapersson654d54c2017-02-10 00:16:07 -0800193 WEBRTC_VIDEO_CODEC_OK)
194 << "Failed to initialize VideoDecoder";
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000195
kjellander@webrtc.org5b97b122011-12-08 07:42:18 +0000196 if (config_.verbose) {
197 printf("Video Processor:\n");
brandtrbea36fd2017-08-07 03:36:54 -0700198 printf(" Filename : %s\n", config_.filename.c_str());
199 printf(" Total # of frames: %d\n",
asapersson1d29c862017-06-22 02:18:50 -0700200 analysis_frame_reader_->NumberOfFrames());
brandtrbea36fd2017-08-07 03:36:54 -0700201 printf(" # CPU cores used : %d\n", num_cores);
202 const char* encoder_name = encoder_->ImplementationName();
203 printf(" Encoder implementation name: %s\n", encoder_name);
204 const char* decoder_name = decoder_->ImplementationName();
205 printf(" Decoder implementation name: %s\n", decoder_name);
206 if (strcmp(encoder_name, decoder_name) == 0) {
207 printf(" Codec implementation name : %s_%s\n",
kthelgason1cdddc92017-08-24 03:52:48 -0700208 CodecTypeToPayloadString(config_.codec_settings.codecType),
asapersson30df64f2017-05-19 04:07:38 -0700209 encoder_->ImplementationName());
210 }
asaperssonae9ba042017-03-07 00:25:38 -0800211 PrintCodecSettings(config_.codec_settings);
brandtrbea36fd2017-08-07 03:36:54 -0700212 printf("\n");
kjellander@webrtc.org5b97b122011-12-08 07:42:18 +0000213 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000214}
215
brandtr77920a42017-08-11 07:48:15 -0700216void VideoProcessor::Release() {
brandtrc8c59052017-08-21 06:44:16 -0700217 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
218
brandtr77920a42017-08-11 07:48:15 -0700219 RTC_CHECK_EQ(encoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
220 RTC_CHECK_EQ(decoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
221
brandtrbdd555c2017-08-21 01:34:04 -0700222 encoder_->RegisterEncodeCompleteCallback(nullptr);
223 decoder_->RegisterDecodeCompleteCallback(nullptr);
224
brandtr77920a42017-08-11 07:48:15 -0700225 initialized_ = false;
226}
227
brandtr8935d972017-09-06 01:53:22 -0700228void VideoProcessor::ProcessFrame() {
brandtrc8c59052017-08-21 06:44:16 -0700229 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700230 RTC_DCHECK(initialized_) << "VideoProcessor not initialized.";
brandtr8935d972017-09-06 01:53:22 -0700231 ++last_inputed_frame_num_;
asapersson654d54c2017-02-10 00:16:07 -0800232
brandtrbdd555c2017-08-21 01:34:04 -0700233 // Get frame from file.
magjed3f075492017-06-01 10:02:26 -0700234 rtc::scoped_refptr<I420BufferInterface> buffer(
brandtrb78bc752017-02-22 01:26:59 -0800235 analysis_frame_reader_->ReadFrame());
brandtrbdd555c2017-08-21 01:34:04 -0700236 RTC_CHECK(buffer) << "Tried to read too many frames from the file.";
brandtrb57f4262017-08-30 06:29:51 -0700237 // Use the frame number as the basis for timestamp to identify frames. Let the
238 // first timestamp be non-zero, to not make the IvfFileWriter believe that we
239 // want to use capture timestamps in the IVF files.
brandtr8935d972017-09-06 01:53:22 -0700240 const uint32_t rtp_timestamp = (last_inputed_frame_num_ + 1) *
241 kRtpClockRateHz /
brandtrb57f4262017-08-30 06:29:51 -0700242 config_.codec_settings.maxFramerate;
brandtr8935d972017-09-06 01:53:22 -0700243 rtp_timestamp_to_frame_num_[rtp_timestamp] = last_inputed_frame_num_;
brandtrbdd555c2017-08-21 01:34:04 -0700244 const int64_t kNoRenderTime = 0;
brandtrb57f4262017-08-30 06:29:51 -0700245 VideoFrame source_frame(buffer, rtp_timestamp, kNoRenderTime,
246 webrtc::kVideoRotation_0);
brandtr17b958c2017-03-07 01:41:43 -0800247
248 // Decide if we are going to force a keyframe.
249 std::vector<FrameType> frame_types(1, kVideoFrameDelta);
250 if (config_.keyframe_interval > 0 &&
brandtr8935d972017-09-06 01:53:22 -0700251 last_inputed_frame_num_ % config_.keyframe_interval == 0) {
brandtr17b958c2017-03-07 01:41:43 -0800252 frame_types[0] = kVideoFrameKey;
253 }
254
255 // Create frame statistics object used for aggregation at end of test run.
brandtr8935d972017-09-06 01:53:22 -0700256 FrameStatistic* frame_stat = stats_->AddFrame();
brandtr17b958c2017-03-07 01:41:43 -0800257
258 // For the highest measurement accuracy of the encode time, the start/stop
259 // time recordings should wrap the Encode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700260 frame_stat->encode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800261 frame_stat->encode_return_code =
262 encoder_->Encode(source_frame, nullptr, &frame_types);
263
264 if (frame_stat->encode_return_code != WEBRTC_VIDEO_CODEC_OK) {
brandtr8935d972017-09-06 01:53:22 -0700265 LOG(LS_WARNING) << "Failed to encode frame " << last_inputed_frame_num_
brandtrbea36fd2017-08-07 03:36:54 -0700266 << ", return code: " << frame_stat->encode_return_code
267 << ".";
brandtr17b958c2017-03-07 01:41:43 -0800268 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000269}
270
brandtrbdd555c2017-08-21 01:34:04 -0700271void VideoProcessor::SetRates(int bitrate_kbps, int framerate_fps) {
brandtrc8c59052017-08-21 06:44:16 -0700272 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbdd555c2017-08-21 01:34:04 -0700273 config_.codec_settings.maxFramerate = framerate_fps;
brandtrbea36fd2017-08-07 03:36:54 -0700274 int set_rates_result = encoder_->SetRateAllocation(
brandtrbdd555c2017-08-21 01:34:04 -0700275 bitrate_allocator_->GetAllocation(bitrate_kbps * 1000, framerate_fps),
276 framerate_fps);
brandtrbea36fd2017-08-07 03:36:54 -0700277 RTC_DCHECK_GE(set_rates_result, 0)
brandtrbdd555c2017-08-21 01:34:04 -0700278 << "Failed to update encoder with new rate " << bitrate_kbps << ".";
brandtrb57f4262017-08-30 06:29:51 -0700279 ++rate_update_index_;
280 num_dropped_frames_.push_back(0);
281 num_spatial_resizes_.push_back(0);
brandtrbea36fd2017-08-07 03:36:54 -0700282}
283
brandtrb57f4262017-08-30 06:29:51 -0700284std::vector<int> VideoProcessor::NumberDroppedFramesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700285 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700286 return num_dropped_frames_;
287}
288
brandtrb57f4262017-08-30 06:29:51 -0700289std::vector<int> VideoProcessor::NumberSpatialResizesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700290 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700291 return num_spatial_resizes_;
292}
293
brandtr45535622017-08-22 03:33:11 -0700294void VideoProcessor::FrameEncoded(webrtc::VideoCodecType codec,
295 const EncodedImage& encoded_image) {
brandtrc8c59052017-08-21 06:44:16 -0700296 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
297
brandtr32e0d262017-02-15 05:29:38 -0800298 // For the highest measurement accuracy of the encode time, the start/stop
299 // time recordings should wrap the Encode call as tightly as possible.
300 int64_t encode_stop_ns = rtc::TimeNanos();
301
brandtr8935d972017-09-06 01:53:22 -0700302 // Take the opportunity to verify the QP bitstream parser.
303 VerifyQpParser(encoded_image, config_);
brandtrb78bc752017-02-22 01:26:59 -0800304
brandtrb57f4262017-08-30 06:29:51 -0700305 // Check for dropped frames.
306 const int frame_number =
307 rtp_timestamp_to_frame_num_[encoded_image._timeStamp];
brandtr17b958c2017-03-07 01:41:43 -0800308 bool last_frame_missing = false;
309 if (frame_number > 0) {
310 RTC_DCHECK_GE(last_encoded_frame_num_, 0);
311 int num_dropped_from_last_encode =
312 frame_number - last_encoded_frame_num_ - 1;
313 RTC_DCHECK_GE(num_dropped_from_last_encode, 0);
brandtrb57f4262017-08-30 06:29:51 -0700314 RTC_CHECK_GE(rate_update_index_, 0);
315 num_dropped_frames_[rate_update_index_] += num_dropped_from_last_encode;
brandtr17b958c2017-03-07 01:41:43 -0800316 if (num_dropped_from_last_encode > 0) {
317 // For dropped frames, we write out the last decoded frame to avoid
318 // getting out of sync for the computation of PSNR and SSIM.
319 for (int i = 0; i < num_dropped_from_last_encode; i++) {
320 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
321 analysis_frame_writer_->FrameLength());
322 RTC_CHECK(analysis_frame_writer_->WriteFrame(
323 last_decoded_frame_buffer_.data()));
324 if (decoded_frame_writer_) {
325 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
326 decoded_frame_writer_->FrameLength());
327 RTC_CHECK(decoded_frame_writer_->WriteFrame(
328 last_decoded_frame_buffer_.data()));
329 }
brandtrb78bc752017-02-22 01:26:59 -0800330 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000331 }
brandtr8935d972017-09-06 01:53:22 -0700332 const FrameStatistic* last_encoded_frame_stat =
333 stats_->GetFrame(last_encoded_frame_num_);
334 last_frame_missing = (last_encoded_frame_stat->manipulated_length == 0);
brandtr17b958c2017-03-07 01:41:43 -0800335 }
336 // Ensure strict monotonicity.
337 RTC_CHECK_GT(frame_number, last_encoded_frame_num_);
338 last_encoded_frame_num_ = frame_number;
339
brandtr8935d972017-09-06 01:53:22 -0700340 // Update frame statistics.
341 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
342 frame_stat->encode_time_us =
343 GetElapsedTimeMicroseconds(frame_stat->encode_start_ns, encode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800344 frame_stat->encoding_successful = true;
brandtr8935d972017-09-06 01:53:22 -0700345 frame_stat->encoded_frame_size_bytes = encoded_image._length;
brandtr17b958c2017-03-07 01:41:43 -0800346 frame_stat->frame_type = encoded_image._frameType;
347 frame_stat->qp = encoded_image.qp_;
brandtr8935d972017-09-06 01:53:22 -0700348 frame_stat->bitrate_kbps = static_cast<int>(
brandtr07734a52017-08-08 08:35:53 -0700349 encoded_image._length * config_.codec_settings.maxFramerate * 8 / 1000);
brandtr17b958c2017-03-07 01:41:43 -0800350 frame_stat->total_packets =
philipelcce46fc2015-12-21 03:04:49 -0800351 encoded_image._length / config_.networking_config.packet_size_in_bytes +
352 1;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000353
brandtr8bc93852017-02-15 05:19:51 -0800354 // Simulate packet loss.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000355 bool exclude_this_frame = false;
Peter Boström49e196a2015-10-23 15:58:18 +0200356 if (encoded_image._frameType == kVideoFrameKey) {
brandtraebc61e2017-02-28 07:13:47 -0800357 // Only keyframes can be excluded.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000358 switch (config_.exclude_frame_types) {
359 case kExcludeOnlyFirstKeyFrame:
360 if (!first_key_frame_has_been_excluded_) {
361 first_key_frame_has_been_excluded_ = true;
362 exclude_this_frame = true;
363 }
364 break;
365 case kExcludeAllKeyFrames:
366 exclude_this_frame = true;
367 break;
368 default:
Erik Språng08127a92016-11-16 16:41:30 +0100369 RTC_NOTREACHED();
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000370 }
371 }
hbosbab934b2016-01-27 01:36:03 -0800372
373 // Make a raw copy of the |encoded_image| buffer.
hbos3fe2c6a2016-01-22 00:07:12 -0800374 size_t copied_buffer_size = encoded_image._length +
375 EncodedImage::GetBufferPaddingBytes(codec);
kwiberg3f55dea2016-02-29 05:51:59 -0800376 std::unique_ptr<uint8_t[]> copied_buffer(new uint8_t[copied_buffer_size]);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000377 memcpy(copied_buffer.get(), encoded_image._buffer, encoded_image._length);
hbosbab934b2016-01-27 01:36:03 -0800378 // The image to feed to the decoder.
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000379 EncodedImage copied_image;
380 memcpy(&copied_image, &encoded_image, sizeof(copied_image));
hbos3fe2c6a2016-01-22 00:07:12 -0800381 copied_image._size = copied_buffer_size;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000382 copied_image._buffer = copied_buffer.get();
hbosbab934b2016-01-27 01:36:03 -0800383
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000384 if (!exclude_this_frame) {
brandtr17b958c2017-03-07 01:41:43 -0800385 frame_stat->packets_dropped =
philipelcce46fc2015-12-21 03:04:49 -0800386 packet_manipulator_->ManipulatePackets(&copied_image);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000387 }
brandtr8935d972017-09-06 01:53:22 -0700388 frame_stat->manipulated_length = copied_image._length;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000389
brandtr32e0d262017-02-15 05:29:38 -0800390 // For the highest measurement accuracy of the decode time, the start/stop
391 // time recordings should wrap the Decode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700392 frame_stat->decode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800393 frame_stat->decode_return_code =
394 decoder_->Decode(copied_image, last_frame_missing, nullptr);
brandtr8bc93852017-02-15 05:19:51 -0800395
brandtr17b958c2017-03-07 01:41:43 -0800396 if (frame_stat->decode_return_code != WEBRTC_VIDEO_CODEC_OK) {
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000397 // Write the last successful frame the output file to avoid getting it out
brandtr8bc93852017-02-15 05:19:51 -0800398 // of sync with the source file for SSIM and PSNR comparisons.
brandtr17b958c2017-03-07 01:41:43 -0800399 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
400 analysis_frame_writer_->FrameLength());
401 RTC_CHECK(
402 analysis_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800403 if (decoded_frame_writer_) {
brandtr17b958c2017-03-07 01:41:43 -0800404 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
405 decoded_frame_writer_->FrameLength());
406 RTC_CHECK(
407 decoded_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800408 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000409 }
brandtr8935d972017-09-06 01:53:22 -0700410
411 if (encoded_frame_writer_) {
412 RTC_CHECK(encoded_frame_writer_->WriteFrame(encoded_image, codec));
413 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000414}
415
brandtrc4095522017-08-07 08:12:33 -0700416void VideoProcessor::FrameDecoded(const VideoFrame& image) {
brandtrc8c59052017-08-21 06:44:16 -0700417 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
418
brandtr32e0d262017-02-15 05:29:38 -0800419 // For the highest measurement accuracy of the decode time, the start/stop
420 // time recordings should wrap the Decode call as tightly as possible.
Niels Möllerd28db7f2016-05-10 16:31:47 +0200421 int64_t decode_stop_ns = rtc::TimeNanos();
brandtr8bc93852017-02-15 05:19:51 -0800422
brandtr8935d972017-09-06 01:53:22 -0700423 // Update frame statistics.
brandtrb57f4262017-08-30 06:29:51 -0700424 const int frame_number = rtp_timestamp_to_frame_num_[image.timestamp()];
brandtr8935d972017-09-06 01:53:22 -0700425 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
426 frame_stat->decoded_width = image.width();
427 frame_stat->decoded_height = image.height();
428 frame_stat->decode_time_us =
429 GetElapsedTimeMicroseconds(frame_stat->decode_start_ns, decode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800430 frame_stat->decoding_successful = true;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000431
brandtr17b958c2017-03-07 01:41:43 -0800432 // Check if the codecs have resized the frame since previously decoded frame.
433 if (frame_number > 0) {
brandtrb57f4262017-08-30 06:29:51 -0700434 RTC_CHECK_GE(last_decoded_frame_num_, 0);
brandtr8935d972017-09-06 01:53:22 -0700435 const FrameStatistic* last_decoded_frame_stat =
436 stats_->GetFrame(last_decoded_frame_num_);
brandtr17b958c2017-03-07 01:41:43 -0800437 if (static_cast<int>(image.width()) !=
brandtr8935d972017-09-06 01:53:22 -0700438 last_decoded_frame_stat->decoded_width ||
brandtr17b958c2017-03-07 01:41:43 -0800439 static_cast<int>(image.height()) !=
brandtr8935d972017-09-06 01:53:22 -0700440 last_decoded_frame_stat->decoded_height) {
brandtrb57f4262017-08-30 06:29:51 -0700441 RTC_CHECK_GE(rate_update_index_, 0);
442 ++num_spatial_resizes_[rate_update_index_];
brandtr17b958c2017-03-07 01:41:43 -0800443 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000444 }
brandtr17b958c2017-03-07 01:41:43 -0800445 // Ensure strict monotonicity.
446 RTC_CHECK_GT(frame_number, last_decoded_frame_num_);
447 last_decoded_frame_num_ = frame_number;
448
brandtr8935d972017-09-06 01:53:22 -0700449 // Check if frame size is different from the original size, and if so,
brandtr17b958c2017-03-07 01:41:43 -0800450 // scale back to original size. This is needed for the PSNR and SSIM
brandtr8bc93852017-02-15 05:19:51 -0800451 // calculations.
brandtr17b958c2017-03-07 01:41:43 -0800452 size_t extracted_length;
453 rtc::Buffer extracted_buffer;
brandtr07734a52017-08-08 08:35:53 -0700454 if (image.width() != config_.codec_settings.width ||
455 image.height() != config_.codec_settings.height) {
brandtr17b958c2017-03-07 01:41:43 -0800456 rtc::scoped_refptr<I420Buffer> scaled_buffer(I420Buffer::Create(
brandtr07734a52017-08-08 08:35:53 -0700457 config_.codec_settings.width, config_.codec_settings.height));
Niels Möller718a7632016-06-13 13:06:01 +0200458 // Should be the same aspect ratio, no cropping needed.
magjed3f075492017-06-01 10:02:26 -0700459 scaled_buffer->ScaleFrom(*image.video_frame_buffer()->ToI420());
Niels Möller718a7632016-06-13 13:06:01 +0200460
nisseeb44b392017-04-28 07:18:05 -0700461 size_t length = CalcBufferSize(VideoType::kI420, scaled_buffer->width(),
462 scaled_buffer->height());
brandtr17b958c2017-03-07 01:41:43 -0800463 extracted_buffer.SetSize(length);
464 extracted_length =
465 ExtractBuffer(scaled_buffer, length, extracted_buffer.data());
466 } else {
467 // No resize.
nisseeb44b392017-04-28 07:18:05 -0700468 size_t length =
469 CalcBufferSize(VideoType::kI420, image.width(), image.height());
brandtr17b958c2017-03-07 01:41:43 -0800470 extracted_buffer.SetSize(length);
magjed3f075492017-06-01 10:02:26 -0700471 extracted_length = ExtractBuffer(image.video_frame_buffer()->ToI420(),
472 length, extracted_buffer.data());
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000473 }
brandtr17b958c2017-03-07 01:41:43 -0800474
475 RTC_DCHECK_EQ(extracted_length, analysis_frame_writer_->FrameLength());
476 RTC_CHECK(analysis_frame_writer_->WriteFrame(extracted_buffer.data()));
477 if (decoded_frame_writer_) {
478 RTC_DCHECK_EQ(extracted_length, decoded_frame_writer_->FrameLength());
479 RTC_CHECK(decoded_frame_writer_->WriteFrame(extracted_buffer.data()));
480 }
481
482 last_decoded_frame_buffer_ = std::move(extracted_buffer);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000483}
484
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000485} // namespace test
486} // namespace webrtc