This CL is a manual spin-off of [1], which tried to apply clang-tidy's performance-move-const-arg [1] to the WebRTC codebase. Since there were some wrong fixes to correct, this CL lands all the manual fixes where std::move was actually fine but the lambda was not mutable. [1] - https://webrtc-review.googlesource.com/c/src/+/120350 [2] - https://clang.llvm.org/extra/clang-tidy/checks/performance-move-const-arg.html Bug: webrtc:10252 Change-Id: I4602e3d4a63d2637dd389e775ffbf80fe95f40fc Reviewed-on: https://webrtc-review.googlesource.com/c/120927 Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26532}
180 lines
6.2 KiB
C++
180 lines
6.2 KiB
C++
/*
|
|
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
#include "test/scenario/quality_stats.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/event.h"
|
|
|
|
namespace webrtc {
|
|
namespace test {
|
|
|
|
VideoQualityAnalyzer::VideoQualityAnalyzer(
|
|
std::unique_ptr<RtcEventLogOutput> writer,
|
|
std::function<void(const VideoFrameQualityInfo&)> frame_info_handler)
|
|
: writer_(std::move(writer)), task_queue_("VideoAnalyzer") {
|
|
if (writer_) {
|
|
PrintHeaders();
|
|
frame_info_handlers_.push_back(
|
|
[this](const VideoFrameQualityInfo& info) { PrintFrameInfo(info); });
|
|
}
|
|
if (frame_info_handler)
|
|
frame_info_handlers_.push_back(frame_info_handler);
|
|
}
|
|
|
|
VideoQualityAnalyzer::~VideoQualityAnalyzer() {
|
|
rtc::Event event;
|
|
task_queue_.PostTask([&event] { event.Set(); });
|
|
event.Wait(rtc::Event::kForever);
|
|
}
|
|
|
|
void VideoQualityAnalyzer::OnCapturedFrame(const VideoFrame& frame) {
|
|
VideoFrame copy = frame;
|
|
task_queue_.PostTask([this, copy]() mutable {
|
|
if (!first_capture_ntp_time_ms_)
|
|
first_capture_ntp_time_ms_ = copy.ntp_time_ms();
|
|
captured_frames_.push_back(std::move(copy));
|
|
});
|
|
}
|
|
|
|
void VideoQualityAnalyzer::OnDecodedFrame(const VideoFrame& frame) {
|
|
VideoFrame decoded = frame;
|
|
RTC_CHECK(frame.ntp_time_ms());
|
|
RTC_CHECK(frame.timestamp());
|
|
task_queue_.PostTask([this, decoded] {
|
|
// If first frame never is received, this value will be wrong. However, that
|
|
// is something that is very unlikely to happen.
|
|
if (!first_decode_rtp_timestamp_)
|
|
first_decode_rtp_timestamp_ = decoded.timestamp();
|
|
RTC_CHECK(!captured_frames_.empty());
|
|
int64_t decoded_capture_time_ms = DecodedFrameCaptureTimeOffsetMs(decoded);
|
|
while (CapturedFrameCaptureTimeOffsetMs(captured_frames_.front()) <
|
|
decoded_capture_time_ms) {
|
|
VideoFrame lost = std::move(captured_frames_.front());
|
|
captured_frames_.pop_front();
|
|
VideoFrameQualityInfo lost_info =
|
|
VideoFrameQualityInfo{Timestamp::us(lost.timestamp_us()),
|
|
Timestamp::PlusInfinity(),
|
|
Timestamp::PlusInfinity(),
|
|
lost.width(),
|
|
lost.height(),
|
|
NAN};
|
|
for (auto& handler : frame_info_handlers_)
|
|
handler(lost_info);
|
|
RTC_CHECK(!captured_frames_.empty());
|
|
}
|
|
RTC_CHECK(!captured_frames_.empty());
|
|
RTC_CHECK(CapturedFrameCaptureTimeOffsetMs(captured_frames_.front()) ==
|
|
DecodedFrameCaptureTimeOffsetMs(decoded));
|
|
VideoFrame captured = std::move(captured_frames_.front());
|
|
captured_frames_.pop_front();
|
|
|
|
VideoFrameQualityInfo decoded_info =
|
|
VideoFrameQualityInfo{Timestamp::us(captured.timestamp_us()),
|
|
Timestamp::ms(decoded.timestamp() / 90.0),
|
|
Timestamp::ms(decoded.render_time_ms()),
|
|
decoded.width(),
|
|
decoded.height(),
|
|
I420PSNR(&captured, &decoded)};
|
|
for (auto& handler : frame_info_handlers_)
|
|
handler(decoded_info);
|
|
});
|
|
}
|
|
|
|
bool VideoQualityAnalyzer::Active() const {
|
|
return !frame_info_handlers_.empty();
|
|
}
|
|
|
|
int64_t VideoQualityAnalyzer::DecodedFrameCaptureTimeOffsetMs(
|
|
const VideoFrame& decoded) const {
|
|
// Assumes that the underlying resolution is ms.
|
|
// Note that we intentinally allow wraparound. The code is incorrect for
|
|
// durations of more than UINT32_MAX/90 ms.
|
|
RTC_DCHECK(first_decode_rtp_timestamp_);
|
|
return (decoded.timestamp() - *first_decode_rtp_timestamp_) / 90;
|
|
}
|
|
|
|
int64_t VideoQualityAnalyzer::CapturedFrameCaptureTimeOffsetMs(
|
|
const VideoFrame& captured) const {
|
|
RTC_DCHECK(first_capture_ntp_time_ms_);
|
|
return captured.ntp_time_ms() - *first_capture_ntp_time_ms_;
|
|
}
|
|
|
|
void VideoQualityAnalyzer::PrintHeaders() {
|
|
writer_->Write("capt recv_capt render width height psnr\n");
|
|
}
|
|
|
|
void VideoQualityAnalyzer::PrintFrameInfo(const VideoFrameQualityInfo& sample) {
|
|
LogWriteFormat(writer_.get(), "%.3f %.3f %.3f %i %i %.3f\n",
|
|
sample.capture_time.seconds<double>(),
|
|
sample.received_capture_time.seconds<double>(),
|
|
sample.render_time.seconds<double>(), sample.width,
|
|
sample.height, sample.psnr);
|
|
}
|
|
|
|
void VideoQualityStats::HandleFrameInfo(VideoFrameQualityInfo sample) {
|
|
total++;
|
|
if (sample.render_time.IsInfinite()) {
|
|
++lost;
|
|
} else {
|
|
++valid;
|
|
end_to_end_seconds.AddSample(
|
|
(sample.render_time - sample.capture_time).seconds<double>());
|
|
psnr.AddSample(sample.psnr);
|
|
}
|
|
}
|
|
|
|
ForwardingCapturedFrameTap::ForwardingCapturedFrameTap(
|
|
Clock* clock,
|
|
VideoQualityAnalyzer* analyzer,
|
|
rtc::VideoSourceInterface<VideoFrame>* source)
|
|
: clock_(clock), analyzer_(analyzer), source_(source) {}
|
|
|
|
ForwardingCapturedFrameTap::~ForwardingCapturedFrameTap() {}
|
|
|
|
void ForwardingCapturedFrameTap::OnFrame(const VideoFrame& frame) {
|
|
RTC_CHECK(sink_);
|
|
VideoFrame copy = frame;
|
|
if (frame.ntp_time_ms() == 0)
|
|
copy.set_ntp_time_ms(clock_->CurrentNtpInMilliseconds());
|
|
copy.set_timestamp(copy.ntp_time_ms() * 90);
|
|
analyzer_->OnCapturedFrame(copy);
|
|
sink_->OnFrame(copy);
|
|
}
|
|
void ForwardingCapturedFrameTap::OnDiscardedFrame() {
|
|
RTC_CHECK(sink_);
|
|
discarded_count_++;
|
|
sink_->OnDiscardedFrame();
|
|
}
|
|
|
|
void ForwardingCapturedFrameTap::AddOrUpdateSink(
|
|
VideoSinkInterface<VideoFrame>* sink,
|
|
const rtc::VideoSinkWants& wants) {
|
|
sink_ = sink;
|
|
source_->AddOrUpdateSink(this, wants);
|
|
}
|
|
void ForwardingCapturedFrameTap::RemoveSink(
|
|
VideoSinkInterface<VideoFrame>* sink) {
|
|
source_->RemoveSink(this);
|
|
sink_ = nullptr;
|
|
}
|
|
|
|
DecodedFrameTap::DecodedFrameTap(VideoQualityAnalyzer* analyzer)
|
|
: analyzer_(analyzer) {}
|
|
|
|
void DecodedFrameTap::OnFrame(const VideoFrame& frame) {
|
|
analyzer_->OnDecodedFrame(frame);
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace webrtc
|