diff --git a/webrtc/modules/video_coding/codecs/test/stats.cc b/webrtc/modules/video_coding/codecs/test/stats.cc index 649c0d549a..b2950ae35d 100644 --- a/webrtc/modules/video_coding/codecs/test/stats.cc +++ b/webrtc/modules/video_coding/codecs/test/stats.cc @@ -12,88 +12,93 @@ #include -#include // min_element, max_element +#include #include "webrtc/rtc_base/checks.h" #include "webrtc/rtc_base/format_macros.h" namespace webrtc { namespace test { + namespace { + bool LessForEncodeTime(const FrameStatistic& s1, const FrameStatistic& s2) { - return s1.encode_time_in_us < s2.encode_time_in_us; + RTC_DCHECK_NE(s1.frame_number, s2.frame_number); + return s1.encode_time_us < s2.encode_time_us; } bool LessForDecodeTime(const FrameStatistic& s1, const FrameStatistic& s2) { - return s1.decode_time_in_us < s2.decode_time_in_us; + RTC_DCHECK_NE(s1.frame_number, s2.frame_number); + return s1.decode_time_us < s2.decode_time_us; } bool LessForEncodedSize(const FrameStatistic& s1, const FrameStatistic& s2) { - return s1.encoded_frame_length_in_bytes < s2.encoded_frame_length_in_bytes; + RTC_DCHECK_NE(s1.frame_number, s2.frame_number); + return s1.encoded_frame_size_bytes < s2.encoded_frame_size_bytes; } bool LessForBitRate(const FrameStatistic& s1, const FrameStatistic& s2) { - return s1.bit_rate_in_kbps < s2.bit_rate_in_kbps; + RTC_DCHECK_NE(s1.frame_number, s2.frame_number); + return s1.bitrate_kbps < s2.bitrate_kbps; } + } // namespace -Stats::Stats() {} - -Stats::~Stats() {} - -FrameStatistic& Stats::NewFrame(int frame_number) { - RTC_DCHECK_GE(frame_number, 0); - FrameStatistic stat; - stat.frame_number = frame_number; - stats_.push_back(stat); - return stats_[frame_number]; +FrameStatistic* Stats::AddFrame() { + // We don't expect more frames than what can be stored in an int. + stats_.emplace_back(static_cast(stats_.size())); + return &stats_.back(); } -void Stats::PrintSummary() { +FrameStatistic* Stats::GetFrame(int frame_number) { + RTC_CHECK_GE(frame_number, 0); + RTC_CHECK_LT(frame_number, stats_.size()); + return &stats_[frame_number]; +} + +size_t Stats::size() const { + return stats_.size(); +} + +void Stats::PrintSummary() const { if (stats_.empty()) { printf("No frame statistics have been logged yet.\n"); return; } // Calculate min, max, average and total encoding time. - int total_encoding_time_in_us = 0; - int total_decoding_time_in_us = 0; - int total_qp = 0; - int total_qp_count = 0; - size_t total_encoded_frames_lengths = 0; - size_t total_encoded_key_frames_lengths = 0; - size_t total_encoded_nonkey_frames_lengths = 0; - size_t num_keyframes = 0; - size_t num_nonkeyframes = 0; + int total_encoding_time_us = 0; + int total_decoding_time_us = 0; + size_t total_encoded_frame_size_bytes = 0; + size_t total_encoded_key_frame_size_bytes = 0; + size_t total_encoded_delta_frame_size_bytes = 0; + size_t num_key_frames = 0; + size_t num_delta_frames = 0; for (const FrameStatistic& stat : stats_) { - total_encoding_time_in_us += stat.encode_time_in_us; - total_decoding_time_in_us += stat.decode_time_in_us; - total_encoded_frames_lengths += stat.encoded_frame_length_in_bytes; + total_encoding_time_us += stat.encode_time_us; + total_decoding_time_us += stat.decode_time_us; + total_encoded_frame_size_bytes += stat.encoded_frame_size_bytes; if (stat.frame_type == webrtc::kVideoFrameKey) { - total_encoded_key_frames_lengths += stat.encoded_frame_length_in_bytes; - ++num_keyframes; + total_encoded_key_frame_size_bytes += stat.encoded_frame_size_bytes; + ++num_key_frames; } else { - total_encoded_nonkey_frames_lengths += stat.encoded_frame_length_in_bytes; - ++num_nonkeyframes; - } - if (stat.qp >= 0) { - total_qp += stat.qp; - ++total_qp_count; + total_encoded_delta_frame_size_bytes += stat.encoded_frame_size_bytes; + ++num_delta_frames; } } // Encoding stats. printf("Encoding time:\n"); - FrameStatisticsIterator frame; - frame = std::min_element(stats_.begin(), stats_.end(), LessForEncodeTime); - printf(" Min : %7d us (frame %d)\n", frame->encode_time_in_us, - frame->frame_number); - frame = std::max_element(stats_.begin(), stats_.end(), LessForEncodeTime); - printf(" Max : %7d us (frame %d)\n", frame->encode_time_in_us, - frame->frame_number); + auto frame_it = + std::min_element(stats_.begin(), stats_.end(), LessForEncodeTime); + printf(" Min : %7d us (frame %d)\n", frame_it->encode_time_us, + frame_it->frame_number); + frame_it = std::max_element(stats_.begin(), stats_.end(), LessForEncodeTime); + printf(" Max : %7d us (frame %d)\n", frame_it->encode_time_us, + frame_it->frame_number); printf(" Average : %7d us\n", - static_cast(total_encoding_time_in_us / stats_.size())); + static_cast(total_encoding_time_us / stats_.size())); // Decoding stats. printf("Decoding time:\n"); @@ -107,57 +112,66 @@ void Stats::PrintSummary() { if (decoded_frames.empty()) { printf("No successfully decoded frames exist in this statistics.\n"); } else { - frame = std::min_element(decoded_frames.begin(), decoded_frames.end(), - LessForDecodeTime); - printf(" Min : %7d us (frame %d)\n", frame->decode_time_in_us, - frame->frame_number); - frame = std::max_element(decoded_frames.begin(), decoded_frames.end(), - LessForDecodeTime); - printf(" Max : %7d us (frame %d)\n", frame->decode_time_in_us, - frame->frame_number); + frame_it = std::min_element(decoded_frames.begin(), decoded_frames.end(), + LessForDecodeTime); + printf(" Min : %7d us (frame %d)\n", frame_it->decode_time_us, + frame_it->frame_number); + frame_it = std::max_element(decoded_frames.begin(), decoded_frames.end(), + LessForDecodeTime); + printf(" Max : %7d us (frame %d)\n", frame_it->decode_time_us, + frame_it->frame_number); printf(" Average : %7d us\n", - static_cast(total_decoding_time_in_us / decoded_frames.size())); + static_cast(total_decoding_time_us / decoded_frames.size())); printf(" Failures: %d frames failed to decode.\n", static_cast(stats_.size() - decoded_frames.size())); } // Frame size stats. printf("Frame sizes:\n"); - frame = std::min_element(stats_.begin(), stats_.end(), LessForEncodedSize); + frame_it = std::min_element(stats_.begin(), stats_.end(), LessForEncodedSize); printf(" Min : %7" PRIuS " bytes (frame %d)\n", - frame->encoded_frame_length_in_bytes, frame->frame_number); - frame = std::max_element(stats_.begin(), stats_.end(), LessForEncodedSize); + frame_it->encoded_frame_size_bytes, frame_it->frame_number); + frame_it = std::max_element(stats_.begin(), stats_.end(), LessForEncodedSize); printf(" Max : %7" PRIuS " bytes (frame %d)\n", - frame->encoded_frame_length_in_bytes, frame->frame_number); + frame_it->encoded_frame_size_bytes, frame_it->frame_number); printf(" Average : %7" PRIuS " bytes\n", - total_encoded_frames_lengths / stats_.size()); - if (num_keyframes > 0) { + total_encoded_frame_size_bytes / stats_.size()); + if (num_key_frames > 0) { printf(" Average key frame size : %7" PRIuS " bytes (%" PRIuS " keyframes)\n", - total_encoded_key_frames_lengths / num_keyframes, num_keyframes); + total_encoded_key_frame_size_bytes / num_key_frames, num_key_frames); } - if (num_nonkeyframes > 0) { + if (num_delta_frames > 0) { printf(" Average non-key frame size: %7" PRIuS " bytes (%" PRIuS " frames)\n", - total_encoded_nonkey_frames_lengths / num_nonkeyframes, - num_nonkeyframes); + total_encoded_delta_frame_size_bytes / num_delta_frames, + num_delta_frames); } // Bitrate stats. printf("Bitrates:\n"); - frame = std::min_element(stats_.begin(), stats_.end(), LessForBitRate); - printf(" Min bitrate: %7d kbps (frame %d)\n", frame->bit_rate_in_kbps, - frame->frame_number); - frame = std::max_element(stats_.begin(), stats_.end(), LessForBitRate); - printf(" Max bitrate: %7d kbps (frame %d)\n", frame->bit_rate_in_kbps, - frame->frame_number); + frame_it = std::min_element(stats_.begin(), stats_.end(), LessForBitRate); + printf(" Min bitrate: %7d kbps (frame %d)\n", frame_it->bitrate_kbps, + frame_it->frame_number); + frame_it = std::max_element(stats_.begin(), stats_.end(), LessForBitRate); + printf(" Max bitrate: %7d kbps (frame %d)\n", frame_it->bitrate_kbps, + frame_it->frame_number); printf("\n"); - printf("Total encoding time : %7d ms.\n", total_encoding_time_in_us / 1000); - printf("Total decoding time : %7d ms.\n", total_decoding_time_in_us / 1000); + printf("Total encoding time : %7d ms.\n", total_encoding_time_us / 1000); + printf("Total decoding time : %7d ms.\n", total_decoding_time_us / 1000); printf("Total processing time: %7d ms.\n", - (total_encoding_time_in_us + total_decoding_time_in_us) / 1000); + (total_encoding_time_us + total_decoding_time_us) / 1000); + // QP stats. + int total_qp = 0; + int total_qp_count = 0; + for (const FrameStatistic& stat : stats_) { + if (stat.qp >= 0) { + total_qp += stat.qp; + ++total_qp_count; + } + } int avg_qp = (total_qp_count > 0) ? (total_qp / total_qp_count) : -1; printf("Average QP: %d\n", avg_qp); } diff --git a/webrtc/modules/video_coding/codecs/test/stats.h b/webrtc/modules/video_coding/codecs/test/stats.h index 1a9b18767f..a0bd112980 100644 --- a/webrtc/modules/video_coding/codecs/test/stats.h +++ b/webrtc/modules/video_coding/codecs/test/stats.h @@ -18,48 +18,55 @@ namespace webrtc { namespace test { -// Contains statistics of a single processed frame. +// Statistics for one processed frame. struct FrameStatistic { - bool encoding_successful = false; - bool decoding_successful = false; + explicit FrameStatistic(int frame_number) : frame_number(frame_number) {} + const int frame_number = 0; + + // Encoding. + int64_t encode_start_ns = 0; int encode_return_code = 0; + bool encoding_successful = false; + int encode_time_us = 0; + int bitrate_kbps = 0; + size_t encoded_frame_size_bytes = 0; + webrtc::FrameType frame_type = kVideoFrameDelta; + + // Decoding. + int64_t decode_start_ns = 0; int decode_return_code = 0; - int encode_time_in_us = 0; - int decode_time_in_us = 0; + bool decoding_successful = false; + int decode_time_us = 0; + int decoded_width = 0; + int decoded_height = 0; + + // Quantization. int qp = -1; - int frame_number = 0; + // How many packets were discarded of the encoded frame data (if any). int packets_dropped = 0; size_t total_packets = 0; - - // Current bit rate. Calculated out of the size divided with the time - // interval per frame. - int bit_rate_in_kbps = 0; - - // Copied from EncodedImage. - size_t encoded_frame_length_in_bytes = 0; - webrtc::FrameType frame_type = kVideoFrameDelta; + size_t manipulated_length = 0; }; -// Handles statistics from a single video processing run. -// Contains calculation methods for interesting metrics from these stats. +// Statistics for a sequence of processed frames. This class is not thread safe. class Stats { public: - typedef std::vector::iterator FrameStatisticsIterator; + Stats() = default; + ~Stats() = default; - Stats(); - virtual ~Stats(); + // Creates a FrameStatistic for the next frame to be processed. + FrameStatistic* AddFrame(); - // Add a new statistic data object. - // The |frame_number| must be incrementing and start at zero in order to use - // it as an index for the FrameStatistic vector. - // Returns the newly created statistic object. - FrameStatistic& NewFrame(int frame_number); + // Returns the FrameStatistic corresponding to |frame_number|. + FrameStatistic* GetFrame(int frame_number); - // Prints a summary of all the statistics that have been gathered during the - // processing. - void PrintSummary(); + size_t size() const; + // TODO(brandtr): Add output as CSV. + void PrintSummary() const; + + private: std::vector stats_; }; diff --git a/webrtc/modules/video_coding/codecs/test/stats_unittest.cc b/webrtc/modules/video_coding/codecs/test/stats_unittest.cc index 55bdfaff91..24fe265407 100644 --- a/webrtc/modules/video_coding/codecs/test/stats_unittest.cc +++ b/webrtc/modules/video_coding/codecs/test/stats_unittest.cc @@ -11,36 +11,32 @@ #include "webrtc/modules/video_coding/codecs/test/stats.h" #include "webrtc/test/gtest.h" -#include "webrtc/typedefs.h" namespace webrtc { namespace test { TEST(StatsTest, TestEmptyObject) { Stats stats; - EXPECT_EQ(0u, stats.stats_.size()); - stats.PrintSummary(); // should not crash + stats.PrintSummary(); // Should not crash. } TEST(StatsTest, AddSingleFrame) { - const int kFrameNumber = 0; Stats stats; - stats.NewFrame(kFrameNumber); - EXPECT_EQ(1u, stats.stats_.size()); - FrameStatistic* frame_stat = &stats.stats_[0]; - EXPECT_EQ(kFrameNumber, frame_stat->frame_number); + FrameStatistic* frame_stat = stats.AddFrame(); + EXPECT_EQ(0, frame_stat->frame_number); + EXPECT_EQ(1u, stats.size()); } TEST(StatsTest, AddMultipleFrames) { Stats stats; const int kNumFrames = 1000; for (int i = 0; i < kNumFrames; ++i) { - FrameStatistic& frame_stat = stats.NewFrame(i); - EXPECT_EQ(i, frame_stat.frame_number); + FrameStatistic* frame_stat = stats.AddFrame(); + EXPECT_EQ(i, frame_stat->frame_number); } - EXPECT_EQ(kNumFrames, static_cast(stats.stats_.size())); + EXPECT_EQ(kNumFrames, static_cast(stats.size())); - stats.PrintSummary(); // should not crash + stats.PrintSummary(); // Should not crash. } } // namespace test diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc index fab707fe82..ed19ae63f0 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc @@ -150,6 +150,7 @@ VideoProcessor::VideoProcessor(webrtc::VideoEncoder* encoder, analysis_frame_writer_(analysis_frame_writer), encoded_frame_writer_(encoded_frame_writer), decoded_frame_writer_(decoded_frame_writer), + last_inputed_frame_num_(-1), last_encoded_frame_num_(-1), last_decoded_frame_num_(-1), first_key_frame_has_been_excluded_(false), @@ -162,7 +163,6 @@ VideoProcessor::VideoProcessor(webrtc::VideoEncoder* encoder, RTC_DCHECK(analysis_frame_reader); RTC_DCHECK(analysis_frame_writer); RTC_DCHECK(stats); - frame_infos_.reserve(analysis_frame_reader->NumberOfFrames()); } VideoProcessor::~VideoProcessor() = default; @@ -225,11 +225,10 @@ void VideoProcessor::Release() { initialized_ = false; } -void VideoProcessor::ProcessFrame(int frame_number) { +void VideoProcessor::ProcessFrame() { RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); - RTC_DCHECK_EQ(frame_number, frame_infos_.size()) - << "Must process frames in sequence."; RTC_DCHECK(initialized_) << "VideoProcessor not initialized."; + ++last_inputed_frame_num_; // Get frame from file. rtc::scoped_refptr buffer( @@ -238,9 +237,10 @@ void VideoProcessor::ProcessFrame(int frame_number) { // Use the frame number as the basis for timestamp to identify frames. Let the // first timestamp be non-zero, to not make the IvfFileWriter believe that we // want to use capture timestamps in the IVF files. - const uint32_t rtp_timestamp = (frame_number + 1) * kRtpClockRateHz / + const uint32_t rtp_timestamp = (last_inputed_frame_num_ + 1) * + kRtpClockRateHz / config_.codec_settings.maxFramerate; - rtp_timestamp_to_frame_num_[rtp_timestamp] = frame_number; + rtp_timestamp_to_frame_num_[rtp_timestamp] = last_inputed_frame_num_; const int64_t kNoRenderTime = 0; VideoFrame source_frame(buffer, rtp_timestamp, kNoRenderTime, webrtc::kVideoRotation_0); @@ -248,25 +248,21 @@ void VideoProcessor::ProcessFrame(int frame_number) { // Decide if we are going to force a keyframe. std::vector frame_types(1, kVideoFrameDelta); if (config_.keyframe_interval > 0 && - frame_number % config_.keyframe_interval == 0) { + last_inputed_frame_num_ % config_.keyframe_interval == 0) { frame_types[0] = kVideoFrameKey; } - // Store frame information during the different stages of encode and decode. - frame_infos_.emplace_back(); - FrameInfo* frame_info = &frame_infos_.back(); - // Create frame statistics object used for aggregation at end of test run. - FrameStatistic* frame_stat = &stats_->NewFrame(frame_number); + FrameStatistic* frame_stat = stats_->AddFrame(); // For the highest measurement accuracy of the encode time, the start/stop // time recordings should wrap the Encode call as tightly as possible. - frame_info->encode_start_ns = rtc::TimeNanos(); + frame_stat->encode_start_ns = rtc::TimeNanos(); frame_stat->encode_return_code = encoder_->Encode(source_frame, nullptr, &frame_types); if (frame_stat->encode_return_code != WEBRTC_VIDEO_CODEC_OK) { - LOG(LS_WARNING) << "Failed to encode frame " << frame_number + LOG(LS_WARNING) << "Failed to encode frame " << last_inputed_frame_num_ << ", return code: " << frame_stat->encode_return_code << "."; } @@ -303,9 +299,8 @@ void VideoProcessor::FrameEncoded(webrtc::VideoCodecType codec, // time recordings should wrap the Encode call as tightly as possible. int64_t encode_stop_ns = rtc::TimeNanos(); - if (encoded_frame_writer_) { - RTC_CHECK(encoded_frame_writer_->WriteFrame(encoded_image, codec)); - } + // Take the opportunity to verify the QP bitstream parser. + VerifyQpParser(encoded_image, config_); // Check for dropped frames. const int frame_number = @@ -334,26 +329,23 @@ void VideoProcessor::FrameEncoded(webrtc::VideoCodecType codec, } } } - last_frame_missing = - (frame_infos_[last_encoded_frame_num_].manipulated_length == 0); + const FrameStatistic* last_encoded_frame_stat = + stats_->GetFrame(last_encoded_frame_num_); + last_frame_missing = (last_encoded_frame_stat->manipulated_length == 0); } // Ensure strict monotonicity. RTC_CHECK_GT(frame_number, last_encoded_frame_num_); last_encoded_frame_num_ = frame_number; - // Update frame information and statistics. - VerifyQpParser(encoded_image, config_); - RTC_CHECK_LT(frame_number, frame_infos_.size()); - FrameInfo* frame_info = &frame_infos_[frame_number]; - FrameStatistic* frame_stat = &stats_->stats_[frame_number]; - frame_stat->encode_time_in_us = - GetElapsedTimeMicroseconds(frame_info->encode_start_ns, encode_stop_ns); + // Update frame statistics. + FrameStatistic* frame_stat = stats_->GetFrame(frame_number); + frame_stat->encode_time_us = + GetElapsedTimeMicroseconds(frame_stat->encode_start_ns, encode_stop_ns); frame_stat->encoding_successful = true; - frame_stat->encoded_frame_length_in_bytes = encoded_image._length; - frame_stat->frame_number = frame_number; + frame_stat->encoded_frame_size_bytes = encoded_image._length; frame_stat->frame_type = encoded_image._frameType; frame_stat->qp = encoded_image.qp_; - frame_stat->bit_rate_in_kbps = static_cast( + frame_stat->bitrate_kbps = static_cast( encoded_image._length * config_.codec_settings.maxFramerate * 8 / 1000); frame_stat->total_packets = encoded_image._length / config_.networking_config.packet_size_in_bytes + @@ -393,11 +385,11 @@ void VideoProcessor::FrameEncoded(webrtc::VideoCodecType codec, frame_stat->packets_dropped = packet_manipulator_->ManipulatePackets(&copied_image); } - frame_info->manipulated_length = copied_image._length; + frame_stat->manipulated_length = copied_image._length; // For the highest measurement accuracy of the decode time, the start/stop // time recordings should wrap the Decode call as tightly as possible. - frame_info->decode_start_ns = rtc::TimeNanos(); + frame_stat->decode_start_ns = rtc::TimeNanos(); frame_stat->decode_return_code = decoder_->Decode(copied_image, last_frame_missing, nullptr); @@ -415,6 +407,10 @@ void VideoProcessor::FrameEncoded(webrtc::VideoCodecType codec, decoded_frame_writer_->WriteFrame(last_decoded_frame_buffer_.data())); } } + + if (encoded_frame_writer_) { + RTC_CHECK(encoded_frame_writer_->WriteFrame(encoded_image, codec)); + } } void VideoProcessor::FrameDecoded(const VideoFrame& image) { @@ -424,26 +420,24 @@ void VideoProcessor::FrameDecoded(const VideoFrame& image) { // time recordings should wrap the Decode call as tightly as possible. int64_t decode_stop_ns = rtc::TimeNanos(); - // Update frame information and statistics. + // Update frame statistics. const int frame_number = rtp_timestamp_to_frame_num_[image.timestamp()]; - RTC_CHECK_LT(frame_number, frame_infos_.size()); - FrameInfo* frame_info = &frame_infos_[frame_number]; - frame_info->decoded_width = image.width(); - frame_info->decoded_height = image.height(); - FrameStatistic* frame_stat = &stats_->stats_[frame_number]; - frame_stat->decode_time_in_us = - GetElapsedTimeMicroseconds(frame_info->decode_start_ns, decode_stop_ns); + FrameStatistic* frame_stat = stats_->GetFrame(frame_number); + frame_stat->decoded_width = image.width(); + frame_stat->decoded_height = image.height(); + frame_stat->decode_time_us = + GetElapsedTimeMicroseconds(frame_stat->decode_start_ns, decode_stop_ns); frame_stat->decoding_successful = true; // Check if the codecs have resized the frame since previously decoded frame. if (frame_number > 0) { RTC_CHECK_GE(last_decoded_frame_num_, 0); - const FrameInfo& last_decoded_frame_info = - frame_infos_[last_decoded_frame_num_]; + const FrameStatistic* last_decoded_frame_stat = + stats_->GetFrame(last_decoded_frame_num_); if (static_cast(image.width()) != - last_decoded_frame_info.decoded_width || + last_decoded_frame_stat->decoded_width || static_cast(image.height()) != - last_decoded_frame_info.decoded_height) { + last_decoded_frame_stat->decoded_height) { RTC_CHECK_GE(rate_update_index_, 0); ++num_spatial_resizes_[rate_update_index_]; } @@ -452,7 +446,7 @@ void VideoProcessor::FrameDecoded(const VideoFrame& image) { RTC_CHECK_GT(frame_number, last_decoded_frame_num_); last_decoded_frame_num_ = frame_number; - // Check if codec size is different from the original size, and if so, + // Check if frame size is different from the original size, and if so, // scale back to original size. This is needed for the PSNR and SSIM // calculations. size_t extracted_length; diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor.h b/webrtc/modules/video_coding/codecs/test/videoprocessor.h index e50f0d9018..3ae3dc5c0e 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor.h +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.h @@ -134,9 +134,11 @@ class VideoProcessor { // Tears down callbacks and releases the encoder and decoder. void Release(); - // Processes a single frame. The frames must be processed in order, and the - // VideoProcessor must be initialized first. - void ProcessFrame(int frame_number); + // Reads a frame from the analysis frame reader and sends it to the encoder. + // When the encode callback is received, the encoded frame is sent to the + // decoder. The decoded frame is written to disk by the analysis frame writer. + // Objective video quality metrics can thus be calculated after the fact. + void ProcessFrame(); // Updates the encoder with target rates. Must be called at least once. void SetRates(int bitrate_kbps, int framerate_fps); @@ -148,18 +150,6 @@ class VideoProcessor { std::vector NumberSpatialResizesPerRateUpdate() const; private: - // Container that holds per-frame information that needs to be stored between - // calls to Encode and Decode, as well as the corresponding callbacks. It is - // not directly used for statistics -- for that, test::FrameStatistic is used. - // TODO(brandtr): Get rid of this struct and use the Stats class instead. - struct FrameInfo { - int64_t encode_start_ns = 0; - int64_t decode_start_ns = 0; - int decoded_width = 0; - int decoded_height = 0; - size_t manipulated_length = 0; - }; - class VideoProcessorEncodeCompleteCallback : public webrtc::EncodedImageCallback { public: @@ -283,10 +273,8 @@ class VideoProcessor { IvfFileWriter* const encoded_frame_writer_; FrameWriter* const decoded_frame_writer_; - // Frame metadata for all frames that have been added through a call to - // ProcessFrames(). We need to store this metadata over the course of the - // test run, to support pipelining HW codecs. - std::vector frame_infos_ GUARDED_BY(sequence_checker_); + // Keep track of inputed/encoded/decoded frames, so we can detect frame drops. + int last_inputed_frame_num_ GUARDED_BY(sequence_checker_); int last_encoded_frame_num_ GUARDED_BY(sequence_checker_); int last_decoded_frame_num_ GUARDED_BY(sequence_checker_); diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc index 7fd5dc2de7..68c2a683b8 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc @@ -191,8 +191,7 @@ void VideoProcessorIntegrationTest::ProcessFramesAndMaybeVerify( rate_profile.input_frame_rate[rate_update_index]); } - task_queue.PostTask( - [this, frame_number] { processor_->ProcessFrame(frame_number); }); + task_queue.PostTask([this] { processor_->ProcessFrame(); }); ++frame_number; if (frame_number == @@ -245,7 +244,7 @@ void VideoProcessorIntegrationTest::ProcessFramesAndMaybeVerify( num_dropped_frames, num_resize_actions); // Calculate and print other statistics. - EXPECT_EQ(num_frames, static_cast(stats_.stats_.size())); + EXPECT_EQ(num_frames, static_cast(stats_.size())); stats_.PrintSummary(); // Calculate and print image quality statistics. @@ -414,10 +413,10 @@ void VideoProcessorIntegrationTest::UpdateRateControlMetrics(int frame_number) { ++num_frames_per_update_[tl_idx]; ++num_frames_total_; - FrameType frame_type = stats_.stats_[frame_number].frame_type; + const FrameStatistic* frame_stat = stats_.GetFrame(frame_number); + FrameType frame_type = frame_stat->frame_type; float encoded_size_kbits = - stats_.stats_[frame_number].encoded_frame_length_in_bytes * 8.0f / - 1000.0f; + frame_stat->encoded_frame_size_bytes * 8.0f / 1000.0f; // Update layer data. // Update rate mismatch relative to per-frame bandwidth for delta frames. diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc index 5f71a68cb2..9474760299 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc @@ -109,13 +109,13 @@ TEST_F(VideoProcessorTest, ProcessFrames_FixedFramerate) { encoder_mock_, Encode(Property(&VideoFrame::timestamp, 1 * 90000 / kFramerateFps), _, _)) .Times(1); - video_processor_->ProcessFrame(0); + video_processor_->ProcessFrame(); EXPECT_CALL( encoder_mock_, Encode(Property(&VideoFrame::timestamp, 2 * 90000 / kFramerateFps), _, _)) .Times(1); - video_processor_->ProcessFrame(1); + video_processor_->ProcessFrame(); ExpectRelease(); video_processor_->Release(); @@ -135,7 +135,7 @@ TEST_F(VideoProcessorTest, ProcessFrames_VariableFramerate) { 1 * 90000 / kStartFramerateFps), _, _)) .Times(1); - video_processor_->ProcessFrame(0); + video_processor_->ProcessFrame(); const int kNewFramerateFps = 13; video_processor_->SetRates(kBitrateKbps, kNewFramerateFps); @@ -144,7 +144,7 @@ TEST_F(VideoProcessorTest, ProcessFrames_VariableFramerate) { 2 * 90000 / kNewFramerateFps), _, _)) .Times(1); - video_processor_->ProcessFrame(1); + video_processor_->ProcessFrame(); ExpectRelease(); video_processor_->Release();