blob: cc453fab17cf539d5b5bf2dcea081a860a0d09af [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>
kwiberg3f55dea2016-02-29 05:51:59 -080017#include <memory>
Erik Språng08127a92016-11-16 16:41:30 +010018#include <utility>
kjellander@webrtc.org9c4e6622013-02-13 09:35:12 +000019#include <vector>
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000020
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "api/video/i420_buffer.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020022#include "common_types.h" // NOLINT(build/include)
ssilkin612f8582017-09-28 09:23:17 -070023#include "common_video/h264/h264_common.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "modules/video_coding/codecs/vp8/simulcast_rate_allocator.h"
25#include "modules/video_coding/include/video_codec_initializer.h"
26#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
27#include "rtc_base/checks.h"
28#include "rtc_base/logging.h"
29#include "rtc_base/timeutils.h"
30#include "system_wrappers/include/cpu_info.h"
31#include "test/gtest.h"
kjellander@webrtc.org35a17562011-10-06 06:44:54 +000032
33namespace webrtc {
34namespace test {
35
brandtrb78bc752017-02-22 01:26:59 -080036namespace {
brandtr17b958c2017-03-07 01:41:43 -080037
brandtrbea36fd2017-08-07 03:36:54 -070038const int kRtpClockRateHz = 90000;
brandtr17b958c2017-03-07 01:41:43 -080039
brandtraebc61e2017-02-28 07:13:47 -080040std::unique_ptr<VideoBitrateAllocator> CreateBitrateAllocator(
brandtr07734a52017-08-08 08:35:53 -070041 TestConfig* config) {
brandtraebc61e2017-02-28 07:13:47 -080042 std::unique_ptr<TemporalLayersFactory> tl_factory;
brandtr07734a52017-08-08 08:35:53 -070043 if (config->codec_settings.codecType == VideoCodecType::kVideoCodecVP8) {
brandtraebc61e2017-02-28 07:13:47 -080044 tl_factory.reset(new TemporalLayersFactory());
brandtr07734a52017-08-08 08:35:53 -070045 config->codec_settings.VP8()->tl_factory = tl_factory.get();
brandtraebc61e2017-02-28 07:13:47 -080046 }
47 return std::unique_ptr<VideoBitrateAllocator>(
brandtr07734a52017-08-08 08:35:53 -070048 VideoCodecInitializer::CreateBitrateAllocator(config->codec_settings,
brandtraebc61e2017-02-28 07:13:47 -080049 std::move(tl_factory)));
50}
51
brandtr07734a52017-08-08 08:35:53 -070052void PrintCodecSettings(const VideoCodec& codec_settings) {
brandtrbea36fd2017-08-07 03:36:54 -070053 printf(" Codec settings:\n");
54 printf(" Codec type : %s\n",
kthelgason1cdddc92017-08-24 03:52:48 -070055 CodecTypeToPayloadString(codec_settings.codecType));
brandtr07734a52017-08-08 08:35:53 -070056 printf(" Start bitrate : %d kbps\n", codec_settings.startBitrate);
57 printf(" Max bitrate : %d kbps\n", codec_settings.maxBitrate);
58 printf(" Min bitrate : %d kbps\n", codec_settings.minBitrate);
59 printf(" Width : %d\n", codec_settings.width);
60 printf(" Height : %d\n", codec_settings.height);
61 printf(" Max frame rate : %d\n", codec_settings.maxFramerate);
62 printf(" QPmax : %d\n", codec_settings.qpMax);
63 if (codec_settings.codecType == kVideoCodecVP8) {
64 printf(" Complexity : %d\n", codec_settings.VP8().complexity);
brandtrbdd555c2017-08-21 01:34:04 -070065 printf(" Resilience : %d\n", codec_settings.VP8().resilience);
66 printf(" # temporal layers : %d\n",
67 codec_settings.VP8().numberOfTemporalLayers);
brandtr07734a52017-08-08 08:35:53 -070068 printf(" Denoising : %d\n", codec_settings.VP8().denoisingOn);
brandtrbea36fd2017-08-07 03:36:54 -070069 printf(" Error concealment : %d\n",
brandtr07734a52017-08-08 08:35:53 -070070 codec_settings.VP8().errorConcealmentOn);
brandtrbdd555c2017-08-21 01:34:04 -070071 printf(" Automatic resize : %d\n",
72 codec_settings.VP8().automaticResizeOn);
brandtr07734a52017-08-08 08:35:53 -070073 printf(" Frame dropping : %d\n", codec_settings.VP8().frameDroppingOn);
brandtr07734a52017-08-08 08:35:53 -070074 printf(" Key frame interval: %d\n", codec_settings.VP8().keyFrameInterval);
75 } else if (codec_settings.codecType == kVideoCodecVP9) {
76 printf(" Complexity : %d\n", codec_settings.VP9().complexity);
brandtrbdd555c2017-08-21 01:34:04 -070077 printf(" Resilience : %d\n", codec_settings.VP9().resilienceOn);
78 printf(" # temporal layers : %d\n",
79 codec_settings.VP9().numberOfTemporalLayers);
brandtr07734a52017-08-08 08:35:53 -070080 printf(" Denoising : %d\n", codec_settings.VP9().denoisingOn);
81 printf(" Frame dropping : %d\n", codec_settings.VP9().frameDroppingOn);
brandtr07734a52017-08-08 08:35:53 -070082 printf(" Key frame interval: %d\n", codec_settings.VP9().keyFrameInterval);
83 printf(" Adaptive QP mode : %d\n", codec_settings.VP9().adaptiveQpMode);
brandtrbdd555c2017-08-21 01:34:04 -070084 printf(" Automatic resize : %d\n",
85 codec_settings.VP9().automaticResizeOn);
86 printf(" # spatial layers : %d\n",
87 codec_settings.VP9().numberOfSpatialLayers);
88 printf(" Flexible mode : %d\n", codec_settings.VP9().flexibleMode);
brandtr07734a52017-08-08 08:35:53 -070089 } else if (codec_settings.codecType == kVideoCodecH264) {
90 printf(" Frame dropping : %d\n", codec_settings.H264().frameDroppingOn);
brandtrbea36fd2017-08-07 03:36:54 -070091 printf(" Key frame interval: %d\n",
brandtr07734a52017-08-08 08:35:53 -070092 codec_settings.H264().keyFrameInterval);
93 printf(" Profile : %d\n", codec_settings.H264().profile);
asaperssonae9ba042017-03-07 00:25:38 -080094 }
95}
96
asaperssona16c70b2017-08-29 05:39:36 -070097void VerifyQpParser(const EncodedImage& encoded_frame,
98 const TestConfig& config) {
brandtrd635e5b2017-09-06 04:48:22 -070099 if (config.hw_encoder)
asaperssona16c70b2017-08-29 05:39:36 -0700100 return;
101
102 int qp;
103 if (config.codec_settings.codecType == kVideoCodecVP8) {
104 ASSERT_TRUE(vp8::GetQp(encoded_frame._buffer, encoded_frame._length, &qp));
105 } else if (config.codec_settings.codecType == kVideoCodecVP9) {
106 ASSERT_TRUE(vp9::GetQp(encoded_frame._buffer, encoded_frame._length, &qp));
107 } else {
108 return;
109 }
110 EXPECT_EQ(encoded_frame.qp_, qp) << "Encoder QP != parsed bitstream QP.";
111}
112
ssilkin612f8582017-09-28 09:23:17 -0700113rtc::Optional<size_t> GetMaxNaluLength(const EncodedImage& encoded_frame,
114 const TestConfig& config) {
115 if (config.codec_settings.codecType != kVideoCodecH264)
116 return rtc::Optional<size_t>();
117
118 std::vector<webrtc::H264::NaluIndex> nalu_indices =
119 webrtc::H264::FindNaluIndices(encoded_frame._buffer,
120 encoded_frame._length);
121
122 RTC_CHECK(!nalu_indices.empty());
123
124 size_t max_length = 0;
125 for (const webrtc::H264::NaluIndex& index : nalu_indices)
126 max_length = std::max(max_length, index.payload_size);
127
128 return rtc::Optional<size_t>(max_length);
129}
130
asaperssonae9ba042017-03-07 00:25:38 -0800131int GetElapsedTimeMicroseconds(int64_t start_ns, int64_t stop_ns) {
132 int64_t diff_us = (stop_ns - start_ns) / rtc::kNumNanosecsPerMicrosec;
133 RTC_DCHECK_GE(diff_us, std::numeric_limits<int>::min());
134 RTC_DCHECK_LE(diff_us, std::numeric_limits<int>::max());
135 return static_cast<int>(diff_us);
136}
137
brandtrb78bc752017-02-22 01:26:59 -0800138} // namespace
139
brandtr8bc93852017-02-15 05:19:51 -0800140const char* ExcludeFrameTypesToStr(ExcludeFrameTypes e) {
141 switch (e) {
142 case kExcludeOnlyFirstKeyFrame:
143 return "ExcludeOnlyFirstKeyFrame";
144 case kExcludeAllKeyFrames:
145 return "ExcludeAllKeyFrames";
146 default:
147 RTC_NOTREACHED();
148 return "Unknown";
149 }
150}
151
brandtrc4095522017-08-07 08:12:33 -0700152VideoProcessor::VideoProcessor(webrtc::VideoEncoder* encoder,
153 webrtc::VideoDecoder* decoder,
154 FrameReader* analysis_frame_reader,
155 FrameWriter* analysis_frame_writer,
156 PacketManipulator* packet_manipulator,
157 const TestConfig& config,
158 Stats* stats,
brandtrc4095522017-08-07 08:12:33 -0700159 IvfFileWriter* encoded_frame_writer,
160 FrameWriter* decoded_frame_writer)
brandtrc8c59052017-08-21 06:44:16 -0700161 : initialized_(false),
162 config_(config),
brandtr07734a52017-08-08 08:35:53 -0700163 encoder_(encoder),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000164 decoder_(decoder),
brandtr07734a52017-08-08 08:35:53 -0700165 bitrate_allocator_(CreateBitrateAllocator(&config_)),
brandtrbdd555c2017-08-21 01:34:04 -0700166 encode_callback_(this),
167 decode_callback_(this),
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000168 packet_manipulator_(packet_manipulator),
brandtraebc61e2017-02-28 07:13:47 -0800169 analysis_frame_reader_(analysis_frame_reader),
170 analysis_frame_writer_(analysis_frame_writer),
brandtrb78bc752017-02-22 01:26:59 -0800171 encoded_frame_writer_(encoded_frame_writer),
172 decoded_frame_writer_(decoded_frame_writer),
brandtr8935d972017-09-06 01:53:22 -0700173 last_inputed_frame_num_(-1),
brandtr17b958c2017-03-07 01:41:43 -0800174 last_encoded_frame_num_(-1),
175 last_decoded_frame_num_(-1),
176 first_key_frame_has_been_excluded_(false),
brandtrbdd555c2017-08-21 01:34:04 -0700177 last_decoded_frame_buffer_(analysis_frame_reader->FrameLength()),
brandtraebc61e2017-02-28 07:13:47 -0800178 stats_(stats),
brandtrb57f4262017-08-30 06:29:51 -0700179 rate_update_index_(-1) {
Erik Språng08127a92016-11-16 16:41:30 +0100180 RTC_DCHECK(encoder);
181 RTC_DCHECK(decoder);
brandtraebc61e2017-02-28 07:13:47 -0800182 RTC_DCHECK(packet_manipulator);
brandtrb78bc752017-02-22 01:26:59 -0800183 RTC_DCHECK(analysis_frame_reader);
184 RTC_DCHECK(analysis_frame_writer);
Erik Språng08127a92016-11-16 16:41:30 +0100185 RTC_DCHECK(stats);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000186}
187
brandtr77920a42017-08-11 07:48:15 -0700188VideoProcessor::~VideoProcessor() = default;
brandtrbea36fd2017-08-07 03:36:54 -0700189
brandtrc4095522017-08-07 08:12:33 -0700190void VideoProcessor::Init() {
brandtrc8c59052017-08-21 06:44:16 -0700191 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700192 RTC_DCHECK(!initialized_) << "VideoProcessor already initialized.";
193 initialized_ = true;
brandtr17b958c2017-03-07 01:41:43 -0800194
brandtrbea36fd2017-08-07 03:36:54 -0700195 // Setup required callbacks for the encoder and decoder.
brandtrbdd555c2017-08-21 01:34:04 -0700196 RTC_CHECK_EQ(encoder_->RegisterEncodeCompleteCallback(&encode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800197 WEBRTC_VIDEO_CODEC_OK)
198 << "Failed to register encode complete callback";
brandtrbdd555c2017-08-21 01:34:04 -0700199 RTC_CHECK_EQ(decoder_->RegisterDecodeCompleteCallback(&decode_callback_),
asapersson654d54c2017-02-10 00:16:07 -0800200 WEBRTC_VIDEO_CODEC_OK)
201 << "Failed to register decode complete callback";
202
brandtraebc61e2017-02-28 07:13:47 -0800203 // Initialize the encoder and decoder.
asapersson996103a2017-02-21 08:30:04 -0800204 uint32_t num_cores =
205 config_.use_single_core ? 1 : CpuInfo::DetectNumberOfCores();
asapersson654d54c2017-02-10 00:16:07 -0800206 RTC_CHECK_EQ(
brandtr07734a52017-08-08 08:35:53 -0700207 encoder_->InitEncode(&config_.codec_settings, num_cores,
asapersson654d54c2017-02-10 00:16:07 -0800208 config_.networking_config.max_payload_size_in_bytes),
209 WEBRTC_VIDEO_CODEC_OK)
210 << "Failed to initialize VideoEncoder";
211
brandtr07734a52017-08-08 08:35:53 -0700212 RTC_CHECK_EQ(decoder_->InitDecode(&config_.codec_settings, num_cores),
asapersson654d54c2017-02-10 00:16:07 -0800213 WEBRTC_VIDEO_CODEC_OK)
214 << "Failed to initialize VideoDecoder";
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000215
kjellander@webrtc.org5b97b122011-12-08 07:42:18 +0000216 if (config_.verbose) {
217 printf("Video Processor:\n");
brandtrbea36fd2017-08-07 03:36:54 -0700218 printf(" Filename : %s\n", config_.filename.c_str());
219 printf(" Total # of frames: %d\n",
asapersson1d29c862017-06-22 02:18:50 -0700220 analysis_frame_reader_->NumberOfFrames());
brandtrbea36fd2017-08-07 03:36:54 -0700221 printf(" # CPU cores used : %d\n", num_cores);
222 const char* encoder_name = encoder_->ImplementationName();
223 printf(" Encoder implementation name: %s\n", encoder_name);
224 const char* decoder_name = decoder_->ImplementationName();
225 printf(" Decoder implementation name: %s\n", decoder_name);
226 if (strcmp(encoder_name, decoder_name) == 0) {
227 printf(" Codec implementation name : %s_%s\n",
kthelgason1cdddc92017-08-24 03:52:48 -0700228 CodecTypeToPayloadString(config_.codec_settings.codecType),
asapersson30df64f2017-05-19 04:07:38 -0700229 encoder_->ImplementationName());
230 }
asaperssonae9ba042017-03-07 00:25:38 -0800231 PrintCodecSettings(config_.codec_settings);
brandtrbea36fd2017-08-07 03:36:54 -0700232 printf("\n");
kjellander@webrtc.org5b97b122011-12-08 07:42:18 +0000233 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000234}
235
brandtr77920a42017-08-11 07:48:15 -0700236void VideoProcessor::Release() {
brandtrc8c59052017-08-21 06:44:16 -0700237 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
238
brandtr77920a42017-08-11 07:48:15 -0700239 RTC_CHECK_EQ(encoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
240 RTC_CHECK_EQ(decoder_->Release(), WEBRTC_VIDEO_CODEC_OK);
241
brandtrbdd555c2017-08-21 01:34:04 -0700242 encoder_->RegisterEncodeCompleteCallback(nullptr);
243 decoder_->RegisterDecodeCompleteCallback(nullptr);
244
brandtr77920a42017-08-11 07:48:15 -0700245 initialized_ = false;
246}
247
brandtr8935d972017-09-06 01:53:22 -0700248void VideoProcessor::ProcessFrame() {
brandtrc8c59052017-08-21 06:44:16 -0700249 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
asapersson1d29c862017-06-22 02:18:50 -0700250 RTC_DCHECK(initialized_) << "VideoProcessor not initialized.";
brandtr8935d972017-09-06 01:53:22 -0700251 ++last_inputed_frame_num_;
asapersson654d54c2017-02-10 00:16:07 -0800252
brandtrbdd555c2017-08-21 01:34:04 -0700253 // Get frame from file.
magjed3f075492017-06-01 10:02:26 -0700254 rtc::scoped_refptr<I420BufferInterface> buffer(
brandtrb78bc752017-02-22 01:26:59 -0800255 analysis_frame_reader_->ReadFrame());
brandtrbdd555c2017-08-21 01:34:04 -0700256 RTC_CHECK(buffer) << "Tried to read too many frames from the file.";
brandtrb57f4262017-08-30 06:29:51 -0700257 // Use the frame number as the basis for timestamp to identify frames. Let the
258 // first timestamp be non-zero, to not make the IvfFileWriter believe that we
259 // want to use capture timestamps in the IVF files.
brandtr8935d972017-09-06 01:53:22 -0700260 const uint32_t rtp_timestamp = (last_inputed_frame_num_ + 1) *
261 kRtpClockRateHz /
brandtrb57f4262017-08-30 06:29:51 -0700262 config_.codec_settings.maxFramerate;
brandtr8935d972017-09-06 01:53:22 -0700263 rtp_timestamp_to_frame_num_[rtp_timestamp] = last_inputed_frame_num_;
brandtrbdd555c2017-08-21 01:34:04 -0700264 const int64_t kNoRenderTime = 0;
brandtrb57f4262017-08-30 06:29:51 -0700265 VideoFrame source_frame(buffer, rtp_timestamp, kNoRenderTime,
266 webrtc::kVideoRotation_0);
brandtr17b958c2017-03-07 01:41:43 -0800267
268 // Decide if we are going to force a keyframe.
269 std::vector<FrameType> frame_types(1, kVideoFrameDelta);
270 if (config_.keyframe_interval > 0 &&
brandtr8935d972017-09-06 01:53:22 -0700271 last_inputed_frame_num_ % config_.keyframe_interval == 0) {
brandtr17b958c2017-03-07 01:41:43 -0800272 frame_types[0] = kVideoFrameKey;
273 }
274
275 // Create frame statistics object used for aggregation at end of test run.
brandtr8935d972017-09-06 01:53:22 -0700276 FrameStatistic* frame_stat = stats_->AddFrame();
brandtr17b958c2017-03-07 01:41:43 -0800277
278 // For the highest measurement accuracy of the encode time, the start/stop
279 // time recordings should wrap the Encode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700280 frame_stat->encode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800281 frame_stat->encode_return_code =
282 encoder_->Encode(source_frame, nullptr, &frame_types);
283
284 if (frame_stat->encode_return_code != WEBRTC_VIDEO_CODEC_OK) {
brandtr8935d972017-09-06 01:53:22 -0700285 LOG(LS_WARNING) << "Failed to encode frame " << last_inputed_frame_num_
brandtrbea36fd2017-08-07 03:36:54 -0700286 << ", return code: " << frame_stat->encode_return_code
287 << ".";
brandtr17b958c2017-03-07 01:41:43 -0800288 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000289}
290
brandtrbdd555c2017-08-21 01:34:04 -0700291void VideoProcessor::SetRates(int bitrate_kbps, int framerate_fps) {
brandtrc8c59052017-08-21 06:44:16 -0700292 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbdd555c2017-08-21 01:34:04 -0700293 config_.codec_settings.maxFramerate = framerate_fps;
brandtrbea36fd2017-08-07 03:36:54 -0700294 int set_rates_result = encoder_->SetRateAllocation(
brandtrbdd555c2017-08-21 01:34:04 -0700295 bitrate_allocator_->GetAllocation(bitrate_kbps * 1000, framerate_fps),
296 framerate_fps);
brandtrbea36fd2017-08-07 03:36:54 -0700297 RTC_DCHECK_GE(set_rates_result, 0)
brandtrbdd555c2017-08-21 01:34:04 -0700298 << "Failed to update encoder with new rate " << bitrate_kbps << ".";
brandtrb57f4262017-08-30 06:29:51 -0700299 ++rate_update_index_;
300 num_dropped_frames_.push_back(0);
301 num_spatial_resizes_.push_back(0);
brandtrbea36fd2017-08-07 03:36:54 -0700302}
303
brandtrb57f4262017-08-30 06:29:51 -0700304std::vector<int> VideoProcessor::NumberDroppedFramesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700305 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700306 return num_dropped_frames_;
307}
308
brandtrb57f4262017-08-30 06:29:51 -0700309std::vector<int> VideoProcessor::NumberSpatialResizesPerRateUpdate() const {
brandtrc8c59052017-08-21 06:44:16 -0700310 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtrbea36fd2017-08-07 03:36:54 -0700311 return num_spatial_resizes_;
312}
313
brandtr45535622017-08-22 03:33:11 -0700314void VideoProcessor::FrameEncoded(webrtc::VideoCodecType codec,
315 const EncodedImage& encoded_image) {
brandtrc8c59052017-08-21 06:44:16 -0700316 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
317
brandtr32e0d262017-02-15 05:29:38 -0800318 // For the highest measurement accuracy of the encode time, the start/stop
319 // time recordings should wrap the Encode call as tightly as possible.
320 int64_t encode_stop_ns = rtc::TimeNanos();
321
brandtr8935d972017-09-06 01:53:22 -0700322 // Take the opportunity to verify the QP bitstream parser.
323 VerifyQpParser(encoded_image, config_);
brandtrb78bc752017-02-22 01:26:59 -0800324
brandtrb57f4262017-08-30 06:29:51 -0700325 // Check for dropped frames.
326 const int frame_number =
327 rtp_timestamp_to_frame_num_[encoded_image._timeStamp];
brandtr17b958c2017-03-07 01:41:43 -0800328 bool last_frame_missing = false;
329 if (frame_number > 0) {
330 RTC_DCHECK_GE(last_encoded_frame_num_, 0);
331 int num_dropped_from_last_encode =
332 frame_number - last_encoded_frame_num_ - 1;
333 RTC_DCHECK_GE(num_dropped_from_last_encode, 0);
brandtrb57f4262017-08-30 06:29:51 -0700334 RTC_CHECK_GE(rate_update_index_, 0);
335 num_dropped_frames_[rate_update_index_] += num_dropped_from_last_encode;
brandtr17b958c2017-03-07 01:41:43 -0800336 if (num_dropped_from_last_encode > 0) {
337 // For dropped frames, we write out the last decoded frame to avoid
338 // getting out of sync for the computation of PSNR and SSIM.
339 for (int i = 0; i < num_dropped_from_last_encode; i++) {
340 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
341 analysis_frame_writer_->FrameLength());
342 RTC_CHECK(analysis_frame_writer_->WriteFrame(
343 last_decoded_frame_buffer_.data()));
344 if (decoded_frame_writer_) {
345 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
346 decoded_frame_writer_->FrameLength());
347 RTC_CHECK(decoded_frame_writer_->WriteFrame(
348 last_decoded_frame_buffer_.data()));
349 }
brandtrb78bc752017-02-22 01:26:59 -0800350 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000351 }
brandtr8935d972017-09-06 01:53:22 -0700352 const FrameStatistic* last_encoded_frame_stat =
353 stats_->GetFrame(last_encoded_frame_num_);
354 last_frame_missing = (last_encoded_frame_stat->manipulated_length == 0);
brandtr17b958c2017-03-07 01:41:43 -0800355 }
356 // Ensure strict monotonicity.
357 RTC_CHECK_GT(frame_number, last_encoded_frame_num_);
358 last_encoded_frame_num_ = frame_number;
359
brandtr8935d972017-09-06 01:53:22 -0700360 // Update frame statistics.
361 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
362 frame_stat->encode_time_us =
363 GetElapsedTimeMicroseconds(frame_stat->encode_start_ns, encode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800364 frame_stat->encoding_successful = true;
brandtr8935d972017-09-06 01:53:22 -0700365 frame_stat->encoded_frame_size_bytes = encoded_image._length;
brandtr17b958c2017-03-07 01:41:43 -0800366 frame_stat->frame_type = encoded_image._frameType;
367 frame_stat->qp = encoded_image.qp_;
brandtr8935d972017-09-06 01:53:22 -0700368 frame_stat->bitrate_kbps = static_cast<int>(
brandtr07734a52017-08-08 08:35:53 -0700369 encoded_image._length * config_.codec_settings.maxFramerate * 8 / 1000);
brandtr17b958c2017-03-07 01:41:43 -0800370 frame_stat->total_packets =
philipelcce46fc2015-12-21 03:04:49 -0800371 encoded_image._length / config_.networking_config.packet_size_in_bytes +
372 1;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000373
ssilkin612f8582017-09-28 09:23:17 -0700374 frame_stat->max_nalu_length = GetMaxNaluLength(encoded_image, config_);
375
brandtr8bc93852017-02-15 05:19:51 -0800376 // Simulate packet loss.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000377 bool exclude_this_frame = false;
Peter Boström49e196a2015-10-23 15:58:18 +0200378 if (encoded_image._frameType == kVideoFrameKey) {
brandtraebc61e2017-02-28 07:13:47 -0800379 // Only keyframes can be excluded.
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000380 switch (config_.exclude_frame_types) {
381 case kExcludeOnlyFirstKeyFrame:
382 if (!first_key_frame_has_been_excluded_) {
383 first_key_frame_has_been_excluded_ = true;
384 exclude_this_frame = true;
385 }
386 break;
387 case kExcludeAllKeyFrames:
388 exclude_this_frame = true;
389 break;
390 default:
Erik Språng08127a92016-11-16 16:41:30 +0100391 RTC_NOTREACHED();
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000392 }
393 }
hbosbab934b2016-01-27 01:36:03 -0800394
395 // Make a raw copy of the |encoded_image| buffer.
hbos3fe2c6a2016-01-22 00:07:12 -0800396 size_t copied_buffer_size = encoded_image._length +
397 EncodedImage::GetBufferPaddingBytes(codec);
kwiberg3f55dea2016-02-29 05:51:59 -0800398 std::unique_ptr<uint8_t[]> copied_buffer(new uint8_t[copied_buffer_size]);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000399 memcpy(copied_buffer.get(), encoded_image._buffer, encoded_image._length);
hbosbab934b2016-01-27 01:36:03 -0800400 // The image to feed to the decoder.
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000401 EncodedImage copied_image;
402 memcpy(&copied_image, &encoded_image, sizeof(copied_image));
hbos3fe2c6a2016-01-22 00:07:12 -0800403 copied_image._size = copied_buffer_size;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000404 copied_image._buffer = copied_buffer.get();
hbosbab934b2016-01-27 01:36:03 -0800405
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000406 if (!exclude_this_frame) {
brandtr17b958c2017-03-07 01:41:43 -0800407 frame_stat->packets_dropped =
philipelcce46fc2015-12-21 03:04:49 -0800408 packet_manipulator_->ManipulatePackets(&copied_image);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000409 }
brandtr8935d972017-09-06 01:53:22 -0700410 frame_stat->manipulated_length = copied_image._length;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000411
brandtr32e0d262017-02-15 05:29:38 -0800412 // For the highest measurement accuracy of the decode time, the start/stop
413 // time recordings should wrap the Decode call as tightly as possible.
brandtr8935d972017-09-06 01:53:22 -0700414 frame_stat->decode_start_ns = rtc::TimeNanos();
brandtr17b958c2017-03-07 01:41:43 -0800415 frame_stat->decode_return_code =
416 decoder_->Decode(copied_image, last_frame_missing, nullptr);
brandtr8bc93852017-02-15 05:19:51 -0800417
brandtr17b958c2017-03-07 01:41:43 -0800418 if (frame_stat->decode_return_code != WEBRTC_VIDEO_CODEC_OK) {
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000419 // Write the last successful frame the output file to avoid getting it out
brandtr8bc93852017-02-15 05:19:51 -0800420 // of sync with the source file for SSIM and PSNR comparisons.
brandtr17b958c2017-03-07 01:41:43 -0800421 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
422 analysis_frame_writer_->FrameLength());
423 RTC_CHECK(
424 analysis_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800425 if (decoded_frame_writer_) {
brandtr17b958c2017-03-07 01:41:43 -0800426 RTC_DCHECK_EQ(last_decoded_frame_buffer_.size(),
427 decoded_frame_writer_->FrameLength());
428 RTC_CHECK(
429 decoded_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data()));
brandtrb78bc752017-02-22 01:26:59 -0800430 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000431 }
brandtr8935d972017-09-06 01:53:22 -0700432
433 if (encoded_frame_writer_) {
434 RTC_CHECK(encoded_frame_writer_->WriteFrame(encoded_image, codec));
435 }
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000436}
437
brandtrc4095522017-08-07 08:12:33 -0700438void VideoProcessor::FrameDecoded(const VideoFrame& image) {
brandtrc8c59052017-08-21 06:44:16 -0700439 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
440
brandtr32e0d262017-02-15 05:29:38 -0800441 // For the highest measurement accuracy of the decode time, the start/stop
442 // time recordings should wrap the Decode call as tightly as possible.
Niels Möllerd28db7f2016-05-10 16:31:47 +0200443 int64_t decode_stop_ns = rtc::TimeNanos();
brandtr8bc93852017-02-15 05:19:51 -0800444
brandtr8935d972017-09-06 01:53:22 -0700445 // Update frame statistics.
brandtrb57f4262017-08-30 06:29:51 -0700446 const int frame_number = rtp_timestamp_to_frame_num_[image.timestamp()];
brandtr8935d972017-09-06 01:53:22 -0700447 FrameStatistic* frame_stat = stats_->GetFrame(frame_number);
448 frame_stat->decoded_width = image.width();
449 frame_stat->decoded_height = image.height();
450 frame_stat->decode_time_us =
451 GetElapsedTimeMicroseconds(frame_stat->decode_start_ns, decode_stop_ns);
brandtr17b958c2017-03-07 01:41:43 -0800452 frame_stat->decoding_successful = true;
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000453
brandtr17b958c2017-03-07 01:41:43 -0800454 // Check if the codecs have resized the frame since previously decoded frame.
455 if (frame_number > 0) {
brandtrb57f4262017-08-30 06:29:51 -0700456 RTC_CHECK_GE(last_decoded_frame_num_, 0);
brandtr8935d972017-09-06 01:53:22 -0700457 const FrameStatistic* last_decoded_frame_stat =
458 stats_->GetFrame(last_decoded_frame_num_);
brandtr17b958c2017-03-07 01:41:43 -0800459 if (static_cast<int>(image.width()) !=
brandtr8935d972017-09-06 01:53:22 -0700460 last_decoded_frame_stat->decoded_width ||
brandtr17b958c2017-03-07 01:41:43 -0800461 static_cast<int>(image.height()) !=
brandtr8935d972017-09-06 01:53:22 -0700462 last_decoded_frame_stat->decoded_height) {
brandtrb57f4262017-08-30 06:29:51 -0700463 RTC_CHECK_GE(rate_update_index_, 0);
464 ++num_spatial_resizes_[rate_update_index_];
brandtr17b958c2017-03-07 01:41:43 -0800465 }
marpan@webrtc.orgf4c2de92012-06-05 21:07:28 +0000466 }
brandtr17b958c2017-03-07 01:41:43 -0800467 // Ensure strict monotonicity.
468 RTC_CHECK_GT(frame_number, last_decoded_frame_num_);
469 last_decoded_frame_num_ = frame_number;
470
brandtr8935d972017-09-06 01:53:22 -0700471 // Check if frame size is different from the original size, and if so,
brandtr17b958c2017-03-07 01:41:43 -0800472 // scale back to original size. This is needed for the PSNR and SSIM
brandtr8bc93852017-02-15 05:19:51 -0800473 // calculations.
brandtr17b958c2017-03-07 01:41:43 -0800474 size_t extracted_length;
475 rtc::Buffer extracted_buffer;
brandtr07734a52017-08-08 08:35:53 -0700476 if (image.width() != config_.codec_settings.width ||
477 image.height() != config_.codec_settings.height) {
brandtr17b958c2017-03-07 01:41:43 -0800478 rtc::scoped_refptr<I420Buffer> scaled_buffer(I420Buffer::Create(
brandtr07734a52017-08-08 08:35:53 -0700479 config_.codec_settings.width, config_.codec_settings.height));
Niels Möller718a7632016-06-13 13:06:01 +0200480 // Should be the same aspect ratio, no cropping needed.
magjed3f075492017-06-01 10:02:26 -0700481 scaled_buffer->ScaleFrom(*image.video_frame_buffer()->ToI420());
Niels Möller718a7632016-06-13 13:06:01 +0200482
nisseeb44b392017-04-28 07:18:05 -0700483 size_t length = CalcBufferSize(VideoType::kI420, scaled_buffer->width(),
484 scaled_buffer->height());
brandtr17b958c2017-03-07 01:41:43 -0800485 extracted_buffer.SetSize(length);
486 extracted_length =
487 ExtractBuffer(scaled_buffer, length, extracted_buffer.data());
488 } else {
489 // No resize.
nisseeb44b392017-04-28 07:18:05 -0700490 size_t length =
491 CalcBufferSize(VideoType::kI420, image.width(), image.height());
brandtr17b958c2017-03-07 01:41:43 -0800492 extracted_buffer.SetSize(length);
magjed3f075492017-06-01 10:02:26 -0700493 extracted_length = ExtractBuffer(image.video_frame_buffer()->ToI420(),
494 length, extracted_buffer.data());
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000495 }
brandtr17b958c2017-03-07 01:41:43 -0800496
497 RTC_DCHECK_EQ(extracted_length, analysis_frame_writer_->FrameLength());
498 RTC_CHECK(analysis_frame_writer_->WriteFrame(extracted_buffer.data()));
499 if (decoded_frame_writer_) {
500 RTC_DCHECK_EQ(extracted_length, decoded_frame_writer_->FrameLength());
501 RTC_CHECK(decoded_frame_writer_->WriteFrame(extracted_buffer.data()));
502 }
503
504 last_decoded_frame_buffer_ = std::move(extracted_buffer);
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000505}
506
kjellander@webrtc.org35a17562011-10-06 06:44:54 +0000507} // namespace test
508} // namespace webrtc