blob: 60e7c4a0865588b98a9783d4036e61104116697e [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
asaperssona16c70b2017-08-29 05:39:36 -070046void VerifyQpParser(const EncodedImage& encoded_frame,
47 const TestConfig& config) {
brandtrd635e5b2017-09-06 04:48:22 -070048 if (config.hw_encoder)
asaperssona16c70b2017-08-29 05:39:36 -070049 return;
50
51 int qp;
52 if (config.codec_settings.codecType == kVideoCodecVP8) {
53 ASSERT_TRUE(vp8::GetQp(encoded_frame._buffer, encoded_frame._length, &qp));
54 } else if (config.codec_settings.codecType == kVideoCodecVP9) {
55 ASSERT_TRUE(vp9::GetQp(encoded_frame._buffer, encoded_frame._length, &qp));
56 } else {
57 return;
58 }
59 EXPECT_EQ(encoded_frame.qp_, qp) << "Encoder QP != parsed bitstream QP.";
60}
61
ssilkin612f8582017-09-28 09:23:17 -070062rtc::Optional<size_t> GetMaxNaluLength(const EncodedImage& encoded_frame,
63 const TestConfig& config) {
64 if (config.codec_settings.codecType != kVideoCodecH264)
65 return rtc::Optional<size_t>();
66
67 std::vector<webrtc::H264::NaluIndex> nalu_indices =
68 webrtc::H264::FindNaluIndices(encoded_frame._buffer,
69 encoded_frame._length);
70
71 RTC_CHECK(!nalu_indices.empty());
72
73 size_t max_length = 0;
74 for (const webrtc::H264::NaluIndex& index : nalu_indices)
75 max_length = std::max(max_length, index.payload_size);
76
77 return rtc::Optional<size_t>(max_length);
78}
79
asaperssonae9ba042017-03-07 00:25:38 -080080int GetElapsedTimeMicroseconds(int64_t start_ns, int64_t stop_ns) {
81 int64_t diff_us = (stop_ns - start_ns) / rtc::kNumNanosecsPerMicrosec;
82 RTC_DCHECK_GE(diff_us, std::numeric_limits<int>::min());
83 RTC_DCHECK_LE(diff_us, std::numeric_limits<int>::max());
84 return static_cast<int>(diff_us);
85}
86
brandtrb78bc752017-02-22 01:26:59 -080087} // namespace
88
brandtrc4095522017-08-07 08:12:33 -070089VideoProcessor::VideoProcessor(webrtc::VideoEncoder* encoder,
90 webrtc::VideoDecoder* decoder,
91 FrameReader* analysis_frame_reader,
92 FrameWriter* analysis_frame_writer,
93 PacketManipulator* packet_manipulator,
94 const TestConfig& config,
95 Stats* stats,
brandtrc4095522017-08-07 08:12:33 -070096 IvfFileWriter* encoded_frame_writer,
97 FrameWriter* decoded_frame_writer)
brandtrc8c59052017-08-21 06:44:16 -070098 : initialized_(false),
99 config_(config),
brandtr07734a52017-08-08 08:35:53 -0700100 encoder_(encoder),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000101 decoder_(decoder),
brandtr07734a52017-08-08 08:35:53 -0700102 bitrate_allocator_(CreateBitrateAllocator(&config_)),
brandtrbdd555c2017-08-21 01:34:04 -0700103 encode_callback_(this),
104 decode_callback_(this),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000105 packet_manipulator_(packet_manipulator),
brandtraebc61e2017-02-28 07:13:47 -0800106 analysis_frame_reader_(analysis_frame_reader),
107 analysis_frame_writer_(analysis_frame_writer),
brandtrb78bc752017-02-22 01:26:59 -0800108 encoded_frame_writer_(encoded_frame_writer),
109 decoded_frame_writer_(decoded_frame_writer),
brandtr8935d972017-09-06 01:53:22 -0700110 last_inputed_frame_num_(-1),
brandtr17b958c2017-03-07 01:41:43 -0800111 last_encoded_frame_num_(-1),
112 last_decoded_frame_num_(-1),
113 first_key_frame_has_been_excluded_(false),
brandtrbdd555c2017-08-21 01:34:04 -0700114 last_decoded_frame_buffer_(analysis_frame_reader->FrameLength()),
brandtraebc61e2017-02-28 07:13:47 -0800115 stats_(stats),
brandtrb57f4262017-08-30 06:29:51 -0700116 rate_update_index_(-1) {
Erik Språng08127a92016-11-16 16:41:30 +0100117 RTC_DCHECK(encoder);
118 RTC_DCHECK(decoder);
brandtraebc61e2017-02-28 07:13:47 -0800119 RTC_DCHECK(packet_manipulator);
brandtrb78bc752017-02-22 01:26:59 -0800120 RTC_DCHECK(analysis_frame_reader);
121 RTC_DCHECK(analysis_frame_writer);
Erik Språng08127a92016-11-16 16:41:30 +0100122 RTC_DCHECK(stats);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000123}
124
brandtr77920a42017-08-11 07:48:15 -0700125VideoProcessor::~VideoProcessor() = default;
brandtrbea36fd2017-08-07 03:36:54 -0700126
brandtrc4095522017-08-07 08:12:33 -0700127void VideoProcessor::Init() {
brandtrc8c59052017-08-21 06:44:16 -0700128 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700129 RTC_DCHECK(!initialized_) << "VideoProcessor already initialized.";
130 initialized_ = true;
brandtr17b958c2017-03-07 01:41:43 -0800131
brandtrbea36fd2017-08-07 03:36:54 -0700132 // Setup required callbacks for the encoder and decoder.
brandtrbdd555c2017-08-21 01:34:04 -0700133 RTC_CHECK_EQ(encoder_->RegisterEncodeCompleteCallback(&encode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800134 WEBRTC_VIDEO_CODEC_OK)
135 << "Failed to register encode complete callback";
brandtrbdd555c2017-08-21 01:34:04 -0700136 RTC_CHECK_EQ(decoder_->RegisterDecodeCompleteCallback(&decode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800137 WEBRTC_VIDEO_CODEC_OK)
138 << "Failed to register decode complete callback";
139
brandtraebc61e2017-02-28 07:13:47 -0800140 // Initialize the encoder and decoder.
asapersson654d54c2017-02-10 00:16:07 -0800141 RTC_CHECK_EQ(
Åsa Persson2d27fb52017-10-19 14:05:50 +0200142 encoder_->InitEncode(&config_.codec_settings, config_.NumberOfCores(),
asapersson654d54c2017-02-10 00:16:07 -0800143 config_.networking_config.max_payload_size_in_bytes),
144 WEBRTC_VIDEO_CODEC_OK)
145 << "Failed to initialize VideoEncoder";
146
Åsa Persson2d27fb52017-10-19 14:05:50 +0200147 RTC_CHECK_EQ(
148 decoder_->InitDecode(&config_.codec_settings, config_.NumberOfCores()),
149 WEBRTC_VIDEO_CODEC_OK)
asapersson654d54c2017-02-10 00:16:07 -0800150 << "Failed to initialize VideoDecoder";
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000151}
152
brandtr77920a42017-08-11 07:48:15 -0700153void VideoProcessor::Release() {
brandtrc8c59052017-08-21 06:44:16 -0700154 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
155
brandtr77920a42017-08-11 07:48:15 -0700156 RTC_CHECK_EQ(encoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
157 RTC_CHECK_EQ(decoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
158
brandtrbdd555c2017-08-21 01:34:04 -0700159 encoder_->RegisterEncodeCompleteCallback(nullptr);
160 decoder_->RegisterDecodeCompleteCallback(nullptr);
161
brandtr77920a42017-08-11 07:48:15 -0700162 initialized_ = false;
163}
164
brandtr8935d972017-09-06 01:53:22 -0700165void VideoProcessor::ProcessFrame() {
brandtrc8c59052017-08-21 06:44:16 -0700166 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700167 RTC_DCHECK(initialized_) << "VideoProcessor not initialized.";
brandtr8935d972017-09-06 01:53:22 -0700168 ++last_inputed_frame_num_;
asapersson654d54c2017-02-10 00:16:07 -0800169
brandtrbdd555c2017-08-21 01:34:04 -0700170 // Get frame from file.
magjed3f075492017-06-01 10:02:26 -0700171 rtc::scoped_refptr<I420BufferInterface> buffer(
brandtrb78bc752017-02-22 01:26:59 -0800172 analysis_frame_reader_->ReadFrame());
brandtrbdd555c2017-08-21 01:34:04 -0700173 RTC_CHECK(buffer) << "Tried to read too many frames from the file.";
brandtrb57f4262017-08-30 06:29:51 -0700174 // Use the frame number as the basis for timestamp to identify frames. Let the
175 // first timestamp be non-zero, to not make the IvfFileWriter believe that we
176 // want to use capture timestamps in the IVF files.
brandtr8935d972017-09-06 01:53:22 -0700177 const uint32_t rtp_timestamp = (last_inputed_frame_num_ + 1) *
178 kRtpClockRateHz /
brandtrb57f4262017-08-30 06:29:51 -0700179 config_.codec_settings.maxFramerate;
brandtr8935d972017-09-06 01:53:22 -0700180 rtp_timestamp_to_frame_num_[rtp_timestamp] = last_inputed_frame_num_;
brandtrbdd555c2017-08-21 01:34:04 -0700181 const int64_t kNoRenderTime = 0;
brandtrb57f4262017-08-30 06:29:51 -0700182 VideoFrame source_frame(buffer, rtp_timestamp, kNoRenderTime,
183 webrtc::kVideoRotation_0);
brandtr17b958c2017-03-07 01:41:43 -0800184
185 // Decide if we are going to force a keyframe.
186 std::vector<FrameType> frame_types(1, kVideoFrameDelta);
187 if (config_.keyframe_interval > 0 &&
brandtr8935d972017-09-06 01:53:22 -0700188 last_inputed_frame_num_ % config_.keyframe_interval == 0) {
brandtr17b958c2017-03-07 01:41:43 -0800189 frame_types[0] = kVideoFrameKey;
190 }
191
192 // Create frame statistics object used for aggregation at end of test run.
brandtr8935d972017-09-06 01:53:22 -0700193 FrameStatistic* frame_stat = stats_->AddFrame();
brandtr17b958c2017-03-07 01:41:43 -0800194
195 // For the highest measurement accuracy of the encode time, the start/stop
196 // time recordings should wrap the Encode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700197 frame_stat->encode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800198 frame_stat->encode_return_code =
199 encoder_->Encode(source_frame, nullptr, &frame_types);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000200}
201
brandtrbdd555c2017-08-21 01:34:04 -0700202void VideoProcessor::SetRates(int bitrate_kbps, int framerate_fps) {
brandtrc8c59052017-08-21 06:44:16 -0700203 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbdd555c2017-08-21 01:34:04 -0700204 config_.codec_settings.maxFramerate = framerate_fps;
brandtrbea36fd2017-08-07 03:36:54 -0700205 int set_rates_result = encoder_->SetRateAllocation(
brandtrbdd555c2017-08-21 01:34:04 -0700206 bitrate_allocator_->GetAllocation(bitrate_kbps * 1000, framerate_fps),
207 framerate_fps);
brandtrbea36fd2017-08-07 03:36:54 -0700208 RTC_DCHECK_GE(set_rates_result, 0)
brandtrbdd555c2017-08-21 01:34:04 -0700209 << "Failed to update encoder with new rate " << bitrate_kbps << ".";
brandtrb57f4262017-08-30 06:29:51 -0700210 ++rate_update_index_;
211 num_dropped_frames_.push_back(0);
212 num_spatial_resizes_.push_back(0);
brandtrbea36fd2017-08-07 03:36:54 -0700213}
214
brandtrb57f4262017-08-30 06:29:51 -0700215std::vector<int> VideoProcessor::NumberDroppedFramesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700216 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700217 return num_dropped_frames_;
218}
219
brandtrb57f4262017-08-30 06:29:51 -0700220std::vector<int> VideoProcessor::NumberSpatialResizesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700221 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700222 return num_spatial_resizes_;
223}
224
brandtr45535622017-08-22 03:33:11 -0700225void VideoProcessor::FrameEncoded(webrtc::VideoCodecType codec,
226 const EncodedImage& encoded_image) {
brandtrc8c59052017-08-21 06:44:16 -0700227 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
228
brandtr32e0d262017-02-15 05:29:38 -0800229 // For the highest measurement accuracy of the encode time, the start/stop
230 // time recordings should wrap the Encode call as tightly as possible.
231 int64_t encode_stop_ns = rtc::TimeNanos();
232
brandtr8935d972017-09-06 01:53:22 -0700233 // Take the opportunity to verify the QP bitstream parser.
234 VerifyQpParser(encoded_image, config_);
brandtrb78bc752017-02-22 01:26:59 -0800235
brandtrb57f4262017-08-30 06:29:51 -0700236 // Check for dropped frames.
237 const int frame_number =
238 rtp_timestamp_to_frame_num_[encoded_image._timeStamp];
brandtr17b958c2017-03-07 01:41:43 -0800239 bool last_frame_missing = false;
240 if (frame_number > 0) {
241 RTC_DCHECK_GE(last_encoded_frame_num_, 0);
242 int num_dropped_from_last_encode =
243 frame_number - last_encoded_frame_num_ - 1;
244 RTC_DCHECK_GE(num_dropped_from_last_encode, 0);
brandtrb57f4262017-08-30 06:29:51 -0700245 RTC_CHECK_GE(rate_update_index_, 0);
246 num_dropped_frames_[rate_update_index_] += num_dropped_from_last_encode;
brandtr17b958c2017-03-07 01:41:43 -0800247 if (num_dropped_from_last_encode > 0) {
248 // For dropped frames, we write out the last decoded frame to avoid
249 // getting out of sync for the computation of PSNR and SSIM.
250 for (int i = 0; i < num_dropped_from_last_encode; i++) {
251 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
252 analysis_frame_writer_->FrameLength());
253 RTC_CHECK(analysis_frame_writer_->WriteFrame(
254 last_decoded_frame_buffer_.data()));
255 if (decoded_frame_writer_) {
256 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
257 decoded_frame_writer_->FrameLength());
258 RTC_CHECK(decoded_frame_writer_->WriteFrame(
259 last_decoded_frame_buffer_.data()));
260 }
brandtrb78bc752017-02-22 01:26:59 -0800261 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000262 }
brandtr8935d972017-09-06 01:53:22 -0700263 const FrameStatistic* last_encoded_frame_stat =
264 stats_->GetFrame(last_encoded_frame_num_);
265 last_frame_missing = (last_encoded_frame_stat->manipulated_length == 0);
brandtr17b958c2017-03-07 01:41:43 -0800266 }
267 // Ensure strict monotonicity.
268 RTC_CHECK_GT(frame_number, last_encoded_frame_num_);
269 last_encoded_frame_num_ = frame_number;
270
brandtr8935d972017-09-06 01:53:22 -0700271 // Update frame statistics.
272 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
273 frame_stat->encode_time_us =
274 GetElapsedTimeMicroseconds(frame_stat->encode_start_ns, encode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800275 frame_stat->encoding_successful = true;
brandtr8935d972017-09-06 01:53:22 -0700276 frame_stat->encoded_frame_size_bytes = encoded_image._length;
brandtr17b958c2017-03-07 01:41:43 -0800277 frame_stat->frame_type = encoded_image._frameType;
278 frame_stat->qp = encoded_image.qp_;
brandtr8935d972017-09-06 01:53:22 -0700279 frame_stat->bitrate_kbps = static_cast<int>(
brandtr07734a52017-08-08 08:35:53 -0700280 encoded_image._length * config_.codec_settings.maxFramerate * 8 / 1000);
brandtr17b958c2017-03-07 01:41:43 -0800281 frame_stat->total_packets =
philipelcce46fc2015-12-21 03:04:49 -0800282 encoded_image._length / config_.networking_config.packet_size_in_bytes +
283 1;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000284
ssilkin612f8582017-09-28 09:23:17 -0700285 frame_stat->max_nalu_length = GetMaxNaluLength(encoded_image, config_);
286
brandtr8bc93852017-02-15 05:19:51 -0800287 // Simulate packet loss.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000288 bool exclude_this_frame = false;
Peter Boström49e196a2015-10-23 15:58:18 +0200289 if (encoded_image._frameType == kVideoFrameKey) {
brandtraebc61e2017-02-28 07:13:47 -0800290 // Only keyframes can be excluded.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000291 switch (config_.exclude_frame_types) {
292 case kExcludeOnlyFirstKeyFrame:
293 if (!first_key_frame_has_been_excluded_) {
294 first_key_frame_has_been_excluded_ = true;
295 exclude_this_frame = true;
296 }
297 break;
298 case kExcludeAllKeyFrames:
299 exclude_this_frame = true;
300 break;
301 default:
Erik Språng08127a92016-11-16 16:41:30 +0100302 RTC_NOTREACHED();
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000303 }
304 }
hbosbab934b2016-01-27 01:36:03 -0800305
306 // Make a raw copy of the |encoded_image| buffer.
hbos3fe2c6a2016-01-22 00:07:12 -0800307 size_t copied_buffer_size = encoded_image._length +
308 EncodedImage::GetBufferPaddingBytes(codec);
kwiberg3f55dea2016-02-29 05:51:59 -0800309 std::unique_ptr<uint8_t[]> copied_buffer(new uint8_t[copied_buffer_size]);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000310 memcpy(copied_buffer.get(), encoded_image._buffer, encoded_image._length);
hbosbab934b2016-01-27 01:36:03 -0800311 // The image to feed to the decoder.
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000312 EncodedImage copied_image;
313 memcpy(&copied_image, &encoded_image, sizeof(copied_image));
hbos3fe2c6a2016-01-22 00:07:12 -0800314 copied_image._size = copied_buffer_size;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000315 copied_image._buffer = copied_buffer.get();
hbosbab934b2016-01-27 01:36:03 -0800316
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000317 if (!exclude_this_frame) {
brandtr17b958c2017-03-07 01:41:43 -0800318 frame_stat->packets_dropped =
philipelcce46fc2015-12-21 03:04:49 -0800319 packet_manipulator_->ManipulatePackets(&copied_image);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000320 }
brandtr8935d972017-09-06 01:53:22 -0700321 frame_stat->manipulated_length = copied_image._length;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000322
brandtr32e0d262017-02-15 05:29:38 -0800323 // For the highest measurement accuracy of the decode time, the start/stop
324 // time recordings should wrap the Decode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700325 frame_stat->decode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800326 frame_stat->decode_return_code =
327 decoder_->Decode(copied_image, last_frame_missing, nullptr);
brandtr8bc93852017-02-15 05:19:51 -0800328
brandtr17b958c2017-03-07 01:41:43 -0800329 if (frame_stat->decode_return_code != WEBRTC_VIDEO_CODEC_OK) {
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000330 // Write the last successful frame the output file to avoid getting it out
brandtr8bc93852017-02-15 05:19:51 -0800331 // of sync with the source file for SSIM and PSNR comparisons.
brandtr17b958c2017-03-07 01:41:43 -0800332 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
333 analysis_frame_writer_->FrameLength());
334 RTC_CHECK(
335 analysis_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800336 if (decoded_frame_writer_) {
brandtr17b958c2017-03-07 01:41:43 -0800337 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
338 decoded_frame_writer_->FrameLength());
339 RTC_CHECK(
340 decoded_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800341 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000342 }
brandtr8935d972017-09-06 01:53:22 -0700343
344 if (encoded_frame_writer_) {
345 RTC_CHECK(encoded_frame_writer_->WriteFrame(encoded_image, codec));
346 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000347}
348
brandtrc4095522017-08-07 08:12:33 -0700349void VideoProcessor::FrameDecoded(const VideoFrame& image) {
brandtrc8c59052017-08-21 06:44:16 -0700350 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
351
brandtr32e0d262017-02-15 05:29:38 -0800352 // For the highest measurement accuracy of the decode time, the start/stop
353 // time recordings should wrap the Decode call as tightly as possible.
Niels Möllerd28db7f2016-05-10 16:31:47 +0200354 int64_t decode_stop_ns = rtc::TimeNanos();
brandtr8bc93852017-02-15 05:19:51 -0800355
brandtr8935d972017-09-06 01:53:22 -0700356 // Update frame statistics.
brandtrb57f4262017-08-30 06:29:51 -0700357 const int frame_number = rtp_timestamp_to_frame_num_[image.timestamp()];
brandtr8935d972017-09-06 01:53:22 -0700358 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
359 frame_stat->decoded_width = image.width();
360 frame_stat->decoded_height = image.height();
361 frame_stat->decode_time_us =
362 GetElapsedTimeMicroseconds(frame_stat->decode_start_ns, decode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800363 frame_stat->decoding_successful = true;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000364
brandtr17b958c2017-03-07 01:41:43 -0800365 // Check if the codecs have resized the frame since previously decoded frame.
366 if (frame_number > 0) {
brandtrb57f4262017-08-30 06:29:51 -0700367 RTC_CHECK_GE(last_decoded_frame_num_, 0);
brandtr8935d972017-09-06 01:53:22 -0700368 const FrameStatistic* last_decoded_frame_stat =
369 stats_->GetFrame(last_decoded_frame_num_);
brandtr17b958c2017-03-07 01:41:43 -0800370 if (static_cast<int>(image.width()) !=
brandtr8935d972017-09-06 01:53:22 -0700371 last_decoded_frame_stat->decoded_width ||
brandtr17b958c2017-03-07 01:41:43 -0800372 static_cast<int>(image.height()) !=
brandtr8935d972017-09-06 01:53:22 -0700373 last_decoded_frame_stat->decoded_height) {
brandtrb57f4262017-08-30 06:29:51 -0700374 RTC_CHECK_GE(rate_update_index_, 0);
375 ++num_spatial_resizes_[rate_update_index_];
brandtr17b958c2017-03-07 01:41:43 -0800376 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000377 }
brandtr17b958c2017-03-07 01:41:43 -0800378 // Ensure strict monotonicity.
379 RTC_CHECK_GT(frame_number, last_decoded_frame_num_);
380 last_decoded_frame_num_ = frame_number;
381
Åsa Persson2d27fb52017-10-19 14:05:50 +0200382 // Check if frame size is different from the original size, and if so, scale
383 // back to original size. This is needed for the PSNR and SSIM calculations.
brandtr17b958c2017-03-07 01:41:43 -0800384 size_t extracted_length;
385 rtc::Buffer extracted_buffer;
brandtr07734a52017-08-08 08:35:53 -0700386 if (image.width() != config_.codec_settings.width ||
387 image.height() != config_.codec_settings.height) {
brandtr17b958c2017-03-07 01:41:43 -0800388 rtc::scoped_refptr<I420Buffer> scaled_buffer(I420Buffer::Create(
brandtr07734a52017-08-08 08:35:53 -0700389 config_.codec_settings.width, config_.codec_settings.height));
Niels Möller718a7632016-06-13 13:06:01 +0200390 // Should be the same aspect ratio, no cropping needed.
magjed3f075492017-06-01 10:02:26 -0700391 scaled_buffer->ScaleFrom(*image.video_frame_buffer()->ToI420());
Niels Möller718a7632016-06-13 13:06:01 +0200392
nisseeb44b392017-04-28 07:18:05 -0700393 size_t length = CalcBufferSize(VideoType::kI420, scaled_buffer->width(),
394 scaled_buffer->height());
brandtr17b958c2017-03-07 01:41:43 -0800395 extracted_buffer.SetSize(length);
396 extracted_length =
397 ExtractBuffer(scaled_buffer, length, extracted_buffer.data());
398 } else {
399 // No resize.
nisseeb44b392017-04-28 07:18:05 -0700400 size_t length =
401 CalcBufferSize(VideoType::kI420, image.width(), image.height());
brandtr17b958c2017-03-07 01:41:43 -0800402 extracted_buffer.SetSize(length);
magjed3f075492017-06-01 10:02:26 -0700403 extracted_length = ExtractBuffer(image.video_frame_buffer()->ToI420(),
404 length, extracted_buffer.data());
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000405 }
brandtr17b958c2017-03-07 01:41:43 -0800406
407 RTC_DCHECK_EQ(extracted_length, analysis_frame_writer_->FrameLength());
408 RTC_CHECK(analysis_frame_writer_->WriteFrame(extracted_buffer.data()));
409 if (decoded_frame_writer_) {
410 RTC_DCHECK_EQ(extracted_length, decoded_frame_writer_->FrameLength());
411 RTC_CHECK(decoded_frame_writer_->WriteFrame(extracted_buffer.data()));
412 }
413
414 last_decoded_frame_buffer_ = std::move(extracted_buffer);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000415}
416
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000417} // namespace test
418} // namespace webrtc