blob: 8b063d586117453719fdeaba5c6143efc329d10b [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
ssilkin612f8582017-09-28 09:23:17 -070013#include <algorithm>
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000014#include <limits>
Erik Språng08127a92016-11-16 16:41:30 +010015#include <utility>
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000016
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "api/video/i420_buffer.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020018#include "common_types.h" // NOLINT(build/include)
ssilkin612f8582017-09-28 09:23:17 -070019#include "common_video/h264/h264_common.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/video_coding/codecs/vp8/simulcast_rate_allocator.h"
21#include "modules/video_coding/include/video_codec_initializer.h"
22#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
23#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/timeutils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "test/gtest.h"
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000026
27namespace webrtc {
28namespace test {
29
brandtrb78bc752017-02-22 01:26:59 -080030namespace {
brandtr17b958c2017-03-07 01:41:43 -080031
brandtrbea36fd2017-08-07 03:36:54 -070032const int kRtpClockRateHz = 90000;
brandtr17b958c2017-03-07 01:41:43 -080033
brandtraebc61e2017-02-28 07:13:47 -080034std::unique_ptr<VideoBitrateAllocator> CreateBitrateAllocator(
brandtr07734a52017-08-08 08:35:53 -070035 TestConfig* config) {
brandtraebc61e2017-02-28 07:13:47 -080036 std::unique_ptr<TemporalLayersFactory> tl_factory;
brandtr07734a52017-08-08 08:35:53 -070037 if (config->codec_settings.codecType == VideoCodecType::kVideoCodecVP8) {
brandtraebc61e2017-02-28 07:13:47 -080038 tl_factory.reset(new TemporalLayersFactory());
brandtr07734a52017-08-08 08:35:53 -070039 config->codec_settings.VP8()->tl_factory = tl_factory.get();
brandtraebc61e2017-02-28 07:13:47 -080040 }
41 return std::unique_ptr<VideoBitrateAllocator>(
brandtr07734a52017-08-08 08:35:53 -070042 VideoCodecInitializer::CreateBitrateAllocator(config->codec_settings,
brandtraebc61e2017-02-28 07:13:47 -080043 std::move(tl_factory)));
44}
45
ssilkin612f8582017-09-28 09:23:17 -070046rtc::Optional<size_t> GetMaxNaluLength(const EncodedImage& encoded_frame,
47 const TestConfig& config) {
48 if (config.codec_settings.codecType != kVideoCodecH264)
49 return rtc::Optional<size_t>();
50
51 std::vector<webrtc::H264::NaluIndex> nalu_indices =
52 webrtc::H264::FindNaluIndices(encoded_frame._buffer,
53 encoded_frame._length);
54
55 RTC_CHECK(!nalu_indices.empty());
56
57 size_t max_length = 0;
58 for (const webrtc::H264::NaluIndex& index : nalu_indices)
59 max_length = std::max(max_length, index.payload_size);
60
61 return rtc::Optional<size_t>(max_length);
62}
63
asaperssonae9ba042017-03-07 00:25:38 -080064int GetElapsedTimeMicroseconds(int64_t start_ns, int64_t stop_ns) {
65 int64_t diff_us = (stop_ns - start_ns) / rtc::kNumNanosecsPerMicrosec;
66 RTC_DCHECK_GE(diff_us, std::numeric_limits<int>::min());
67 RTC_DCHECK_LE(diff_us, std::numeric_limits<int>::max());
68 return static_cast<int>(diff_us);
69}
70
brandtrb78bc752017-02-22 01:26:59 -080071} // namespace
72
brandtrc4095522017-08-07 08:12:33 -070073VideoProcessor::VideoProcessor(webrtc::VideoEncoder* encoder,
74 webrtc::VideoDecoder* decoder,
75 FrameReader* analysis_frame_reader,
76 FrameWriter* analysis_frame_writer,
77 PacketManipulator* packet_manipulator,
78 const TestConfig& config,
79 Stats* stats,
brandtrc4095522017-08-07 08:12:33 -070080 IvfFileWriter* encoded_frame_writer,
81 FrameWriter* decoded_frame_writer)
brandtrc8c59052017-08-21 06:44:16 -070082 : initialized_(false),
83 config_(config),
brandtr07734a52017-08-08 08:35:53 -070084 encoder_(encoder),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000085 decoder_(decoder),
brandtr07734a52017-08-08 08:35:53 -070086 bitrate_allocator_(CreateBitrateAllocator(&config_)),
brandtrbdd555c2017-08-21 01:34:04 -070087 encode_callback_(this),
88 decode_callback_(this),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000089 packet_manipulator_(packet_manipulator),
brandtraebc61e2017-02-28 07:13:47 -080090 analysis_frame_reader_(analysis_frame_reader),
91 analysis_frame_writer_(analysis_frame_writer),
brandtrb78bc752017-02-22 01:26:59 -080092 encoded_frame_writer_(encoded_frame_writer),
93 decoded_frame_writer_(decoded_frame_writer),
brandtr8935d972017-09-06 01:53:22 -070094 last_inputed_frame_num_(-1),
brandtr17b958c2017-03-07 01:41:43 -080095 last_encoded_frame_num_(-1),
96 last_decoded_frame_num_(-1),
97 first_key_frame_has_been_excluded_(false),
brandtrbdd555c2017-08-21 01:34:04 -070098 last_decoded_frame_buffer_(analysis_frame_reader->FrameLength()),
brandtraebc61e2017-02-28 07:13:47 -080099 stats_(stats),
brandtrb57f4262017-08-30 06:29:51 -0700100 rate_update_index_(-1) {
Erik Språng08127a92016-11-16 16:41:30 +0100101 RTC_DCHECK(encoder);
102 RTC_DCHECK(decoder);
brandtraebc61e2017-02-28 07:13:47 -0800103 RTC_DCHECK(packet_manipulator);
brandtrb78bc752017-02-22 01:26:59 -0800104 RTC_DCHECK(analysis_frame_reader);
105 RTC_DCHECK(analysis_frame_writer);
Erik Språng08127a92016-11-16 16:41:30 +0100106 RTC_DCHECK(stats);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000107}
108
brandtr77920a42017-08-11 07:48:15 -0700109VideoProcessor::~VideoProcessor() = default;
brandtrbea36fd2017-08-07 03:36:54 -0700110
brandtrc4095522017-08-07 08:12:33 -0700111void VideoProcessor::Init() {
brandtrc8c59052017-08-21 06:44:16 -0700112 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700113 RTC_DCHECK(!initialized_) << "VideoProcessor already initialized.";
114 initialized_ = true;
brandtr17b958c2017-03-07 01:41:43 -0800115
brandtrbea36fd2017-08-07 03:36:54 -0700116 // Setup required callbacks for the encoder and decoder.
brandtrbdd555c2017-08-21 01:34:04 -0700117 RTC_CHECK_EQ(encoder_->RegisterEncodeCompleteCallback(&encode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800118 WEBRTC_VIDEO_CODEC_OK)
119 << "Failed to register encode complete callback";
brandtrbdd555c2017-08-21 01:34:04 -0700120 RTC_CHECK_EQ(decoder_->RegisterDecodeCompleteCallback(&decode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800121 WEBRTC_VIDEO_CODEC_OK)
122 << "Failed to register decode complete callback";
123
brandtraebc61e2017-02-28 07:13:47 -0800124 // Initialize the encoder and decoder.
asapersson654d54c2017-02-10 00:16:07 -0800125 RTC_CHECK_EQ(
Åsa Persson2d27fb52017-10-19 14:05:50 +0200126 encoder_->InitEncode(&config_.codec_settings, config_.NumberOfCores(),
asapersson654d54c2017-02-10 00:16:07 -0800127 config_.networking_config.max_payload_size_in_bytes),
128 WEBRTC_VIDEO_CODEC_OK)
129 << "Failed to initialize VideoEncoder";
130
Åsa Persson2d27fb52017-10-19 14:05:50 +0200131 RTC_CHECK_EQ(
132 decoder_->InitDecode(&config_.codec_settings, config_.NumberOfCores()),
133 WEBRTC_VIDEO_CODEC_OK)
asapersson654d54c2017-02-10 00:16:07 -0800134 << "Failed to initialize VideoDecoder";
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000135}
136
brandtr77920a42017-08-11 07:48:15 -0700137void VideoProcessor::Release() {
brandtrc8c59052017-08-21 06:44:16 -0700138 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
139
brandtr77920a42017-08-11 07:48:15 -0700140 RTC_CHECK_EQ(encoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
141 RTC_CHECK_EQ(decoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
142
brandtrbdd555c2017-08-21 01:34:04 -0700143 encoder_->RegisterEncodeCompleteCallback(nullptr);
144 decoder_->RegisterDecodeCompleteCallback(nullptr);
145
brandtr77920a42017-08-11 07:48:15 -0700146 initialized_ = false;
147}
148
brandtr8935d972017-09-06 01:53:22 -0700149void VideoProcessor::ProcessFrame() {
brandtrc8c59052017-08-21 06:44:16 -0700150 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700151 RTC_DCHECK(initialized_) << "VideoProcessor not initialized.";
brandtr8935d972017-09-06 01:53:22 -0700152 ++last_inputed_frame_num_;
asapersson654d54c2017-02-10 00:16:07 -0800153
brandtrbdd555c2017-08-21 01:34:04 -0700154 // Get frame from file.
magjed3f075492017-06-01 10:02:26 -0700155 rtc::scoped_refptr<I420BufferInterface> buffer(
brandtrb78bc752017-02-22 01:26:59 -0800156 analysis_frame_reader_->ReadFrame());
brandtrbdd555c2017-08-21 01:34:04 -0700157 RTC_CHECK(buffer) << "Tried to read too many frames from the file.";
brandtrb57f4262017-08-30 06:29:51 -0700158 // Use the frame number as the basis for timestamp to identify frames. Let the
159 // first timestamp be non-zero, to not make the IvfFileWriter believe that we
160 // want to use capture timestamps in the IVF files.
brandtr8935d972017-09-06 01:53:22 -0700161 const uint32_t rtp_timestamp = (last_inputed_frame_num_ + 1) *
162 kRtpClockRateHz /
brandtrb57f4262017-08-30 06:29:51 -0700163 config_.codec_settings.maxFramerate;
brandtr8935d972017-09-06 01:53:22 -0700164 rtp_timestamp_to_frame_num_[rtp_timestamp] = last_inputed_frame_num_;
brandtrbdd555c2017-08-21 01:34:04 -0700165 const int64_t kNoRenderTime = 0;
brandtrb57f4262017-08-30 06:29:51 -0700166 VideoFrame source_frame(buffer, rtp_timestamp, kNoRenderTime,
167 webrtc::kVideoRotation_0);
brandtr17b958c2017-03-07 01:41:43 -0800168
169 // Decide if we are going to force a keyframe.
170 std::vector<FrameType> frame_types(1, kVideoFrameDelta);
171 if (config_.keyframe_interval > 0 &&
brandtr8935d972017-09-06 01:53:22 -0700172 last_inputed_frame_num_ % config_.keyframe_interval == 0) {
brandtr17b958c2017-03-07 01:41:43 -0800173 frame_types[0] = kVideoFrameKey;
174 }
175
176 // Create frame statistics object used for aggregation at end of test run.
brandtr8935d972017-09-06 01:53:22 -0700177 FrameStatistic* frame_stat = stats_->AddFrame();
brandtr17b958c2017-03-07 01:41:43 -0800178
179 // For the highest measurement accuracy of the encode time, the start/stop
180 // time recordings should wrap the Encode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700181 frame_stat->encode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800182 frame_stat->encode_return_code =
183 encoder_->Encode(source_frame, nullptr, &frame_types);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000184}
185
brandtrbdd555c2017-08-21 01:34:04 -0700186void VideoProcessor::SetRates(int bitrate_kbps, int framerate_fps) {
brandtrc8c59052017-08-21 06:44:16 -0700187 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbdd555c2017-08-21 01:34:04 -0700188 config_.codec_settings.maxFramerate = framerate_fps;
brandtrbea36fd2017-08-07 03:36:54 -0700189 int set_rates_result = encoder_->SetRateAllocation(
brandtrbdd555c2017-08-21 01:34:04 -0700190 bitrate_allocator_->GetAllocation(bitrate_kbps * 1000, framerate_fps),
191 framerate_fps);
brandtrbea36fd2017-08-07 03:36:54 -0700192 RTC_DCHECK_GE(set_rates_result, 0)
brandtrbdd555c2017-08-21 01:34:04 -0700193 << "Failed to update encoder with new rate " << bitrate_kbps << ".";
brandtrb57f4262017-08-30 06:29:51 -0700194 ++rate_update_index_;
195 num_dropped_frames_.push_back(0);
196 num_spatial_resizes_.push_back(0);
brandtrbea36fd2017-08-07 03:36:54 -0700197}
198
brandtrb57f4262017-08-30 06:29:51 -0700199std::vector<int> VideoProcessor::NumberDroppedFramesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700200 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700201 return num_dropped_frames_;
202}
203
brandtrb57f4262017-08-30 06:29:51 -0700204std::vector<int> VideoProcessor::NumberSpatialResizesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700205 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700206 return num_spatial_resizes_;
207}
208
brandtr45535622017-08-22 03:33:11 -0700209void VideoProcessor::FrameEncoded(webrtc::VideoCodecType codec,
210 const EncodedImage& encoded_image) {
brandtrc8c59052017-08-21 06:44:16 -0700211 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
212
brandtr32e0d262017-02-15 05:29:38 -0800213 // For the highest measurement accuracy of the encode time, the start/stop
214 // time recordings should wrap the Encode call as tightly as possible.
215 int64_t encode_stop_ns = rtc::TimeNanos();
216
Rasmus Brandtf7a35582017-10-24 10:16:33 +0200217 if (config_.encoded_frame_checker) {
218 config_.encoded_frame_checker->CheckEncodedFrame(codec, encoded_image);
219 }
brandtrb78bc752017-02-22 01:26:59 -0800220
brandtrb57f4262017-08-30 06:29:51 -0700221 // Check for dropped frames.
222 const int frame_number =
223 rtp_timestamp_to_frame_num_[encoded_image._timeStamp];
brandtr17b958c2017-03-07 01:41:43 -0800224 bool last_frame_missing = false;
225 if (frame_number > 0) {
226 RTC_DCHECK_GE(last_encoded_frame_num_, 0);
227 int num_dropped_from_last_encode =
228 frame_number - last_encoded_frame_num_ - 1;
229 RTC_DCHECK_GE(num_dropped_from_last_encode, 0);
brandtrb57f4262017-08-30 06:29:51 -0700230 RTC_CHECK_GE(rate_update_index_, 0);
231 num_dropped_frames_[rate_update_index_] += num_dropped_from_last_encode;
brandtr17b958c2017-03-07 01:41:43 -0800232 if (num_dropped_from_last_encode > 0) {
233 // For dropped frames, we write out the last decoded frame to avoid
234 // getting out of sync for the computation of PSNR and SSIM.
235 for (int i = 0; i < num_dropped_from_last_encode; i++) {
236 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
237 analysis_frame_writer_->FrameLength());
238 RTC_CHECK(analysis_frame_writer_->WriteFrame(
239 last_decoded_frame_buffer_.data()));
240 if (decoded_frame_writer_) {
241 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
242 decoded_frame_writer_->FrameLength());
243 RTC_CHECK(decoded_frame_writer_->WriteFrame(
244 last_decoded_frame_buffer_.data()));
245 }
brandtrb78bc752017-02-22 01:26:59 -0800246 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000247 }
brandtr8935d972017-09-06 01:53:22 -0700248 const FrameStatistic* last_encoded_frame_stat =
249 stats_->GetFrame(last_encoded_frame_num_);
250 last_frame_missing = (last_encoded_frame_stat->manipulated_length == 0);
brandtr17b958c2017-03-07 01:41:43 -0800251 }
252 // Ensure strict monotonicity.
253 RTC_CHECK_GT(frame_number, last_encoded_frame_num_);
254 last_encoded_frame_num_ = frame_number;
255
brandtr8935d972017-09-06 01:53:22 -0700256 // Update frame statistics.
257 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
258 frame_stat->encode_time_us =
259 GetElapsedTimeMicroseconds(frame_stat->encode_start_ns, encode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800260 frame_stat->encoding_successful = true;
brandtr8935d972017-09-06 01:53:22 -0700261 frame_stat->encoded_frame_size_bytes = encoded_image._length;
brandtr17b958c2017-03-07 01:41:43 -0800262 frame_stat->frame_type = encoded_image._frameType;
263 frame_stat->qp = encoded_image.qp_;
brandtr8935d972017-09-06 01:53:22 -0700264 frame_stat->bitrate_kbps = static_cast<int>(
brandtr07734a52017-08-08 08:35:53 -0700265 encoded_image._length * config_.codec_settings.maxFramerate * 8 / 1000);
brandtr17b958c2017-03-07 01:41:43 -0800266 frame_stat->total_packets =
philipelcce46fc2015-12-21 03:04:49 -0800267 encoded_image._length / config_.networking_config.packet_size_in_bytes +
268 1;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000269
ssilkin612f8582017-09-28 09:23:17 -0700270 frame_stat->max_nalu_length = GetMaxNaluLength(encoded_image, config_);
271
brandtr8bc93852017-02-15 05:19:51 -0800272 // Simulate packet loss.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000273 bool exclude_this_frame = false;
Peter Boström49e196a2015-10-23 15:58:18 +0200274 if (encoded_image._frameType == kVideoFrameKey) {
brandtraebc61e2017-02-28 07:13:47 -0800275 // Only keyframes can be excluded.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000276 switch (config_.exclude_frame_types) {
277 case kExcludeOnlyFirstKeyFrame:
278 if (!first_key_frame_has_been_excluded_) {
279 first_key_frame_has_been_excluded_ = true;
280 exclude_this_frame = true;
281 }
282 break;
283 case kExcludeAllKeyFrames:
284 exclude_this_frame = true;
285 break;
286 default:
Erik Språng08127a92016-11-16 16:41:30 +0100287 RTC_NOTREACHED();
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000288 }
289 }
hbosbab934b2016-01-27 01:36:03 -0800290
291 // Make a raw copy of the |encoded_image| buffer.
hbos3fe2c6a2016-01-22 00:07:12 -0800292 size_t copied_buffer_size = encoded_image._length +
293 EncodedImage::GetBufferPaddingBytes(codec);
kwiberg3f55dea2016-02-29 05:51:59 -0800294 std::unique_ptr<uint8_t[]> copied_buffer(new uint8_t[copied_buffer_size]);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000295 memcpy(copied_buffer.get(), encoded_image._buffer, encoded_image._length);
hbosbab934b2016-01-27 01:36:03 -0800296 // The image to feed to the decoder.
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000297 EncodedImage copied_image;
298 memcpy(&copied_image, &encoded_image, sizeof(copied_image));
hbos3fe2c6a2016-01-22 00:07:12 -0800299 copied_image._size = copied_buffer_size;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000300 copied_image._buffer = copied_buffer.get();
hbosbab934b2016-01-27 01:36:03 -0800301
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000302 if (!exclude_this_frame) {
brandtr17b958c2017-03-07 01:41:43 -0800303 frame_stat->packets_dropped =
philipelcce46fc2015-12-21 03:04:49 -0800304 packet_manipulator_->ManipulatePackets(&copied_image);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000305 }
brandtr8935d972017-09-06 01:53:22 -0700306 frame_stat->manipulated_length = copied_image._length;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000307
brandtr32e0d262017-02-15 05:29:38 -0800308 // For the highest measurement accuracy of the decode time, the start/stop
309 // time recordings should wrap the Decode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700310 frame_stat->decode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800311 frame_stat->decode_return_code =
312 decoder_->Decode(copied_image, last_frame_missing, nullptr);
brandtr8bc93852017-02-15 05:19:51 -0800313
brandtr17b958c2017-03-07 01:41:43 -0800314 if (frame_stat->decode_return_code != WEBRTC_VIDEO_CODEC_OK) {
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000315 // Write the last successful frame the output file to avoid getting it out
brandtr8bc93852017-02-15 05:19:51 -0800316 // of sync with the source file for SSIM and PSNR comparisons.
brandtr17b958c2017-03-07 01:41:43 -0800317 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
318 analysis_frame_writer_->FrameLength());
319 RTC_CHECK(
320 analysis_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800321 if (decoded_frame_writer_) {
brandtr17b958c2017-03-07 01:41:43 -0800322 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
323 decoded_frame_writer_->FrameLength());
324 RTC_CHECK(
325 decoded_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800326 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000327 }
brandtr8935d972017-09-06 01:53:22 -0700328
329 if (encoded_frame_writer_) {
330 RTC_CHECK(encoded_frame_writer_->WriteFrame(encoded_image, codec));
331 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000332}
333
brandtrc4095522017-08-07 08:12:33 -0700334void VideoProcessor::FrameDecoded(const VideoFrame& image) {
brandtrc8c59052017-08-21 06:44:16 -0700335 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
336
brandtr32e0d262017-02-15 05:29:38 -0800337 // For the highest measurement accuracy of the decode time, the start/stop
338 // time recordings should wrap the Decode call as tightly as possible.
Niels Möllerd28db7f2016-05-10 16:31:47 +0200339 int64_t decode_stop_ns = rtc::TimeNanos();
brandtr8bc93852017-02-15 05:19:51 -0800340
brandtr8935d972017-09-06 01:53:22 -0700341 // Update frame statistics.
brandtrb57f4262017-08-30 06:29:51 -0700342 const int frame_number = rtp_timestamp_to_frame_num_[image.timestamp()];
brandtr8935d972017-09-06 01:53:22 -0700343 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
344 frame_stat->decoded_width = image.width();
345 frame_stat->decoded_height = image.height();
346 frame_stat->decode_time_us =
347 GetElapsedTimeMicroseconds(frame_stat->decode_start_ns, decode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800348 frame_stat->decoding_successful = true;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000349
brandtr17b958c2017-03-07 01:41:43 -0800350 // Check if the codecs have resized the frame since previously decoded frame.
351 if (frame_number > 0) {
brandtrb57f4262017-08-30 06:29:51 -0700352 RTC_CHECK_GE(last_decoded_frame_num_, 0);
brandtr8935d972017-09-06 01:53:22 -0700353 const FrameStatistic* last_decoded_frame_stat =
354 stats_->GetFrame(last_decoded_frame_num_);
brandtr17b958c2017-03-07 01:41:43 -0800355 if (static_cast<int>(image.width()) !=
brandtr8935d972017-09-06 01:53:22 -0700356 last_decoded_frame_stat->decoded_width ||
brandtr17b958c2017-03-07 01:41:43 -0800357 static_cast<int>(image.height()) !=
brandtr8935d972017-09-06 01:53:22 -0700358 last_decoded_frame_stat->decoded_height) {
brandtrb57f4262017-08-30 06:29:51 -0700359 RTC_CHECK_GE(rate_update_index_, 0);
360 ++num_spatial_resizes_[rate_update_index_];
brandtr17b958c2017-03-07 01:41:43 -0800361 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000362 }
brandtr17b958c2017-03-07 01:41:43 -0800363 // Ensure strict monotonicity.
364 RTC_CHECK_GT(frame_number, last_decoded_frame_num_);
365 last_decoded_frame_num_ = frame_number;
366
Åsa Persson2d27fb52017-10-19 14:05:50 +0200367 // Check if frame size is different from the original size, and if so, scale
368 // back to original size. This is needed for the PSNR and SSIM calculations.
brandtr17b958c2017-03-07 01:41:43 -0800369 size_t extracted_length;
370 rtc::Buffer extracted_buffer;
brandtr07734a52017-08-08 08:35:53 -0700371 if (image.width() != config_.codec_settings.width ||
372 image.height() != config_.codec_settings.height) {
brandtr17b958c2017-03-07 01:41:43 -0800373 rtc::scoped_refptr<I420Buffer> scaled_buffer(I420Buffer::Create(
brandtr07734a52017-08-08 08:35:53 -0700374 config_.codec_settings.width, config_.codec_settings.height));
Niels Möller718a7632016-06-13 13:06:01 +0200375 // Should be the same aspect ratio, no cropping needed.
magjed3f075492017-06-01 10:02:26 -0700376 scaled_buffer->ScaleFrom(*image.video_frame_buffer()->ToI420());
Niels Möller718a7632016-06-13 13:06:01 +0200377
nisseeb44b392017-04-28 07:18:05 -0700378 size_t length = CalcBufferSize(VideoType::kI420, scaled_buffer->width(),
379 scaled_buffer->height());
brandtr17b958c2017-03-07 01:41:43 -0800380 extracted_buffer.SetSize(length);
381 extracted_length =
382 ExtractBuffer(scaled_buffer, length, extracted_buffer.data());
383 } else {
384 // No resize.
nisseeb44b392017-04-28 07:18:05 -0700385 size_t length =
386 CalcBufferSize(VideoType::kI420, image.width(), image.height());
brandtr17b958c2017-03-07 01:41:43 -0800387 extracted_buffer.SetSize(length);
magjed3f075492017-06-01 10:02:26 -0700388 extracted_length = ExtractBuffer(image.video_frame_buffer()->ToI420(),
389 length, extracted_buffer.data());
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000390 }
brandtr17b958c2017-03-07 01:41:43 -0800391
392 RTC_DCHECK_EQ(extracted_length, analysis_frame_writer_->FrameLength());
393 RTC_CHECK(analysis_frame_writer_->WriteFrame(extracted_buffer.data()));
394 if (decoded_frame_writer_) {
395 RTC_DCHECK_EQ(extracted_length, decoded_frame_writer_->FrameLength());
396 RTC_CHECK(decoded_frame_writer_->WriteFrame(extracted_buffer.data()));
397 }
398
399 last_decoded_frame_buffer_ = std::move(extracted_buffer);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000400}
401
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000402} // namespace test
403} // namespace webrtc