Commit 47dc4a53 authored by sergeyu's avatar sergeyu Committed by Commit bot

More cleanups in FrameStats

1. Separated HostFrameStats and ClientFrameStats. This will allow to
   track host and client stats separately.
2. Added FrameStatsConsumer interface to allow verify that FrameStats
   are generated correctly.
3. Added VideoRenderer::GetFrameStatsConsumer() and changed
   WebrtcVideoRendererAdapter to get VideoRenderer instead of
   FrameConsumer, so now the adapter can report FrameStats.

BUG=621691

Review-Url: https://codereview.chromium.org/2113523007
Cr-Commit-Position: refs/heads/master@{#403953}
parent f68e2a5d
......@@ -13,13 +13,13 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "remoting/protocol/client_authentication_config.h"
#include "remoting/protocol/client_stub.h"
#include "remoting/protocol/clipboard_stub.h"
#include "remoting/protocol/connection_to_host.h"
#include "remoting/protocol/input_stub.h"
#include "remoting/protocol/mouse_input_filter.h"
#include "remoting/protocol/performance_tracker.h"
#include "remoting/protocol/session_config.h"
#include "remoting/protocol/video_stub.h"
#include "remoting/signaling/signal_strategy.h"
......@@ -144,9 +144,6 @@ class ChromotingClient : public SignalStrategy::Listener,
// True if |protocol::Capabilities| message has been received.
bool host_capabilities_received_ = false;
// Record the statistics of the connection.
protocol::PerformanceTracker perf_tracker_;
DISALLOW_COPY_AND_ASSIGN(ChromotingClient);
};
......
......@@ -132,6 +132,12 @@ protocol::FrameConsumer::PixelFormat JniVideoRenderer::GetPixelFormat() {
return FORMAT_RGBA;
}
bool JniVideoRenderer::Initialize(
const ClientContext& context,
protocol::FrameStatsConsumer* stats_consumer) {
return software_video_renderer_.Initialize(context, stats_consumer);
}
void JniVideoRenderer::OnSessionConfig(const protocol::SessionConfig& config) {
return software_video_renderer_.OnSessionConfig(config);
}
......@@ -144,9 +150,8 @@ protocol::FrameConsumer* JniVideoRenderer::GetFrameConsumer() {
return software_video_renderer_.GetFrameConsumer();
}
bool JniVideoRenderer::Initialize(const ClientContext& context,
protocol::PerformanceTracker* perf_tracker) {
return software_video_renderer_.Initialize(context, perf_tracker);
protocol::FrameStatsConsumer* JniVideoRenderer::GetFrameStatsConsumer() {
return software_video_renderer_.GetFrameStatsConsumer();
}
} // namespace remoting
......@@ -41,12 +41,13 @@ class JniVideoRenderer : public protocol::FrameConsumer,
const base::Closure& done) override;
PixelFormat GetPixelFormat() override;
// JniVideoRenderer implementation.
// VideoRenderer implementation.
bool Initialize(const ClientContext& client_context,
protocol::FrameStatsConsumer* stats_consumer) override;
void OnSessionConfig(const protocol::SessionConfig& config) override;
protocol::VideoStub* GetVideoStub() override;
protocol::FrameConsumer* GetFrameConsumer() override;
bool Initialize(const ClientContext& client_context,
protocol::PerformanceTracker* perf_tracker) override;
protocol::FrameStatsConsumer* GetFrameStatsConsumer() override;
private:
class Renderer;
......
......@@ -23,7 +23,7 @@ namespace remoting {
class ClientContext;
namespace protocol {
class PerformanceTracker;
class FrameStatsConsumer;
} // namespace protocol
// Interface for video renderers that render video in pepper plugin.
......
......@@ -98,10 +98,10 @@ void PepperVideoRenderer2D::EnableDebugDirtyRegion(bool enable) {
bool PepperVideoRenderer2D::Initialize(
const ClientContext& client_context,
protocol::PerformanceTracker* perf_tracker) {
protocol::FrameStatsConsumer* stats_consumer) {
DCHECK(thread_checker_.CalledOnValidThread());
return software_video_renderer_.Initialize(client_context, perf_tracker);
return software_video_renderer_.Initialize(client_context, stats_consumer);
}
void PepperVideoRenderer2D::OnSessionConfig(
......@@ -123,6 +123,12 @@ protocol::FrameConsumer* PepperVideoRenderer2D::GetFrameConsumer() {
return software_video_renderer_.GetFrameConsumer();
}
protocol::FrameStatsConsumer* PepperVideoRenderer2D::GetFrameStatsConsumer() {
DCHECK(thread_checker_.CalledOnValidThread());
return software_video_renderer_.GetFrameStatsConsumer();
}
std::unique_ptr<webrtc::DesktopFrame> PepperVideoRenderer2D::AllocateFrame(
const webrtc::DesktopSize& size) {
DCHECK(thread_checker_.CalledOnValidThread());
......
......@@ -52,10 +52,11 @@ class PepperVideoRenderer2D : public PepperVideoRenderer,
// VideoRenderer interface.
bool Initialize(const ClientContext& client_context,
protocol::PerformanceTracker* perf_tracker) override;
protocol::FrameStatsConsumer* stats_consumer) override;
void OnSessionConfig(const protocol::SessionConfig& config) override;
protocol::VideoStub* GetVideoStub() override;
protocol::FrameConsumer* GetFrameConsumer() override;
protocol::FrameStatsConsumer* GetFrameStatsConsumer() override;
private:
// protocol::FrameConsumer implementation.
......
......@@ -33,27 +33,34 @@ const uint32_t kMinimumPictureCount = 3;
class PepperVideoRenderer3D::FrameTracker {
public:
FrameTracker(std::unique_ptr<VideoPacket> packet,
protocol::PerformanceTracker* perf_tracker,
protocol::FrameStatsConsumer* stats_consumer,
const base::Closure& done)
: packet_(std::move(packet)), perf_tracker_(perf_tracker), done_(done) {
stats_ = protocol::FrameStats::GetForVideoPacket(*packet_);
: packet_(std::move(packet)),
stats_consumer_(stats_consumer),
done_(done) {
stats_.host_stats = protocol::HostFrameStats::GetForVideoPacket(*packet_);
stats_.client_stats.time_received = base::TimeTicks::Now();
}
~FrameTracker() {
if (perf_tracker_)
perf_tracker_->RecordVideoFrameStats(stats_);
if (stats_consumer_)
stats_consumer_->OnVideoFrameStats(stats_);
if (!done_.is_null())
done_.Run();
}
void OnDecoded() { stats_.time_decoded = base::TimeTicks::Now(); }
void OnRendered() { stats_.time_rendered = base::TimeTicks::Now(); }
void OnDecoded() {
stats_.client_stats.time_decoded = base::TimeTicks::Now();
}
void OnRendered() {
stats_.client_stats.time_rendered = base::TimeTicks::Now();
}
VideoPacket* packet() { return packet_.get(); }
private:
std::unique_ptr<VideoPacket> packet_;
protocol::PerformanceTracker* perf_tracker_;
protocol::FrameStatsConsumer* stats_consumer_;
protocol::FrameStats stats_;
base::Closure done_;
};
......@@ -104,8 +111,8 @@ void PepperVideoRenderer3D::EnableDebugDirtyRegion(bool enable) {
bool PepperVideoRenderer3D::Initialize(
const ClientContext& context,
protocol::PerformanceTracker* perf_tracker) {
perf_tracker_ = perf_tracker;
protocol::FrameStatsConsumer* stats_consumer) {
stats_consumer_ = stats_consumer;
const int32_t context_attributes[] = {
PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
......@@ -198,12 +205,16 @@ protocol::FrameConsumer* PepperVideoRenderer3D::GetFrameConsumer() {
return nullptr;
}
protocol::FrameStatsConsumer* PepperVideoRenderer3D::GetFrameStatsConsumer() {
return stats_consumer_;
}
void PepperVideoRenderer3D::ProcessVideoPacket(
std::unique_ptr<VideoPacket> packet,
const base::Closure& done) {
VideoPacket* packet_ptr = packet.get();
std::unique_ptr<FrameTracker> frame_tracker(
new FrameTracker(std::move(packet), perf_tracker_, done));
new FrameTracker(std::move(packet), stats_consumer_, done));
// Don't need to do anything if the packet is empty. Host sends empty video
// packets when the screen is not changing.
......
......@@ -25,6 +25,10 @@ struct PPB_OpenGLES2;
namespace remoting {
namespace protocol {
class FrameStatsConsumer;
} // namespace protocol
// PepperVideoRenderer that uses the PPB_VideoDecoder interface for video
// decoding and Graphics3D for rendering.
class PepperVideoRenderer3D : public PepperVideoRenderer,
......@@ -41,10 +45,11 @@ class PepperVideoRenderer3D : public PepperVideoRenderer,
// VideoRenderer interface.
bool Initialize(const ClientContext& client_context,
protocol::PerformanceTracker* perf_tracker) override;
protocol::FrameStatsConsumer* stats_consumer) override;
void OnSessionConfig(const protocol::SessionConfig& config) override;
protocol::VideoStub* GetVideoStub() override;
protocol::FrameConsumer* GetFrameConsumer() override;
protocol::FrameStatsConsumer* GetFrameStatsConsumer() override;
// protocol::VideoStub interface.
void ProcessVideoPacket(std::unique_ptr<VideoPacket> packet,
......@@ -93,7 +98,7 @@ class PepperVideoRenderer3D : public PepperVideoRenderer,
pp::Instance* pp_instance_ = nullptr;
EventHandler* event_handler_ = nullptr;
protocol::PerformanceTracker* perf_tracker_ = nullptr;
protocol::FrameStatsConsumer* stats_consumer_ = nullptr;
pp::Graphics3D graphics_;
const PPB_OpenGLES2* gles2_if_;
......
......@@ -46,18 +46,17 @@ std::unique_ptr<webrtc::DesktopFrame> DoDecodeFrame(
} // namespace
SoftwareVideoRenderer::SoftwareVideoRenderer(protocol::FrameConsumer* consumer)
: consumer_(consumer),
weak_factory_(this) {
: consumer_(consumer), weak_factory_(this) {
thread_checker_.DetachFromThread();
}
SoftwareVideoRenderer::SoftwareVideoRenderer(
scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner,
protocol::FrameConsumer* consumer,
protocol::PerformanceTracker* perf_tracker)
protocol::FrameStatsConsumer* stats_consumer)
: decode_task_runner_(decode_task_runner),
consumer_(consumer),
perf_tracker_(perf_tracker),
stats_consumer_(stats_consumer),
weak_factory_(this) {}
SoftwareVideoRenderer::~SoftwareVideoRenderer() {
......@@ -67,10 +66,10 @@ SoftwareVideoRenderer::~SoftwareVideoRenderer() {
bool SoftwareVideoRenderer::Initialize(
const ClientContext& client_context,
protocol::PerformanceTracker* perf_tracker) {
protocol::FrameStatsConsumer* stats_consumer) {
DCHECK(thread_checker_.CalledOnValidThread());
decode_task_runner_ = client_context.decode_task_runner();
perf_tracker_ = perf_tracker;
stats_consumer_ = stats_consumer;
return true;
}
......@@ -105,6 +104,10 @@ protocol::FrameConsumer* SoftwareVideoRenderer::GetFrameConsumer() {
return consumer_;
}
protocol::FrameStatsConsumer* SoftwareVideoRenderer::GetFrameStatsConsumer() {
return stats_consumer_;
}
void SoftwareVideoRenderer::ProcessVideoPacket(
std::unique_ptr<VideoPacket> packet,
const base::Closure& done) {
......@@ -112,15 +115,17 @@ void SoftwareVideoRenderer::ProcessVideoPacket(
base::ScopedClosureRunner done_runner(done);
std::unique_ptr<protocol::FrameStats> frame_stats(new protocol::FrameStats(
protocol::FrameStats::GetForVideoPacket(*packet)));
std::unique_ptr<protocol::FrameStats> frame_stats(new protocol::FrameStats());
frame_stats->host_stats =
protocol::HostFrameStats::GetForVideoPacket(*packet);
frame_stats->client_stats.time_received = base::TimeTicks::Now();
// If the video packet is empty then there is nothing to decode. Empty packets
// are used to maintain activity on the network. Stats for such packets still
// need to be reported.
if (!packet->has_data() || packet->data().size() == 0) {
if (perf_tracker_)
perf_tracker_->RecordVideoFrameStats(*frame_stats);
if (stats_consumer_)
stats_consumer_->OnVideoFrameStats(*frame_stats);
return;
}
......@@ -162,8 +167,7 @@ void SoftwareVideoRenderer::RenderFrame(
std::unique_ptr<webrtc::DesktopFrame> frame) {
DCHECK(thread_checker_.CalledOnValidThread());
stats->time_decoded = base::TimeTicks::Now();
stats->client_stats.time_decoded = base::TimeTicks::Now();
if (!frame) {
if (!done.is_null())
done.Run();
......@@ -181,9 +185,9 @@ void SoftwareVideoRenderer::OnFrameRendered(
const base::Closure& done) {
DCHECK(thread_checker_.CalledOnValidThread());
stats->time_rendered = base::TimeTicks::Now();
if (perf_tracker_)
perf_tracker_->RecordVideoFrameStats(*stats);
stats->client_stats.time_rendered = base::TimeTicks::Now();
if (stats_consumer_)
stats_consumer_->OnVideoFrameStats(*stats);
if (!done.is_null())
done.Run();
......
......@@ -32,7 +32,7 @@ class VideoDecoder;
namespace protocol {
class FrameConsumer;
struct FrameStats;
class PerformanceTracker;
class FrameStatsConsumer;
} // namespace protocol
// Implementation of VideoRenderer interface that decodes frame on CPU (on a
......@@ -42,27 +42,28 @@ class SoftwareVideoRenderer : public protocol::VideoRenderer,
public:
// The renderer can be created on any thread but afterwards all methods must
// be called on the same thread.
SoftwareVideoRenderer(protocol::FrameConsumer* consumer);
explicit SoftwareVideoRenderer(protocol::FrameConsumer* consumer);
// Deprecated constructor. TODO(yuweih): remove.
// Constructs the renderer and initializes it immediately. Caller should not
// call Initialize() after using this constructor.
// All methods must be called on the same thread the renderer is created. The
// |decode_task_runner_| is used to decode the video packets. |perf_tracker|
// must outlive the renderer. |perf_tracker| may be nullptr, performance
// tracking is disabled in that case.
// |decode_task_runner_| is used to decode the video packets. |consumer| and
// |stats_consumer| must outlive the renderer. |stats_consumer| may be
// nullptr, performance tracking is disabled in that case.
SoftwareVideoRenderer(
scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner,
protocol::FrameConsumer* consumer,
protocol::PerformanceTracker* perf_tracker);
protocol::FrameStatsConsumer* stats_consumer);
~SoftwareVideoRenderer() override;
// VideoRenderer interface.
bool Initialize(const ClientContext& client_context,
protocol::PerformanceTracker* perf_tracker) override;
protocol::FrameStatsConsumer* stats_consumer) override;
void OnSessionConfig(const protocol::SessionConfig& config) override;
protocol::VideoStub* GetVideoStub() override;
protocol::FrameConsumer* GetFrameConsumer() override;
protocol::FrameStatsConsumer* GetFrameStatsConsumer() override;
// protocol::VideoStub interface.
void ProcessVideoPacket(std::unique_ptr<VideoPacket> packet,
......@@ -76,8 +77,8 @@ class SoftwareVideoRenderer : public protocol::VideoRenderer,
const base::Closure& done);
scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_;
protocol::FrameConsumer* consumer_;
protocol::PerformanceTracker* perf_tracker_ = nullptr;
protocol::FrameConsumer* const consumer_;
protocol::FrameStatsConsumer* stats_consumer_ = nullptr;
std::unique_ptr<VideoDecoder> decoder_;
......
......@@ -63,11 +63,27 @@ FrameConsumer::PixelFormat FakeFrameConsumer::GetPixelFormat() {
return FORMAT_BGRA;
}
FakeFrameStatsConsumer::FakeFrameStatsConsumer() {}
FakeFrameStatsConsumer::~FakeFrameStatsConsumer() {}
void FakeFrameStatsConsumer::set_on_stats_callback(
base::Closure on_stats_callback) {
on_stats_callback_ = on_stats_callback;
}
void FakeFrameStatsConsumer::OnVideoFrameStats(const FrameStats& stats) {
CHECK(thread_checker_.CalledOnValidThread());
received_stats_.push_back(stats);
if (!on_stats_callback_.is_null())
on_stats_callback_.Run();
}
FakeVideoRenderer::FakeVideoRenderer() {}
FakeVideoRenderer::~FakeVideoRenderer() {}
bool FakeVideoRenderer::Initialize(const ClientContext& client_context,
protocol::PerformanceTracker* perf_tracker) {
bool FakeVideoRenderer::Initialize(
const ClientContext& client_context,
protocol::FrameStatsConsumer* stats_consumer) {
return true;
}
......@@ -83,5 +99,10 @@ FakeFrameConsumer* FakeVideoRenderer::GetFrameConsumer() {
return &frame_consumer_;
}
FakeFrameStatsConsumer* FakeVideoRenderer::GetFrameStatsConsumer() {
CHECK(thread_checker_.CalledOnValidThread());
return &frame_stats_consumer_;
}
} // namespace protocol
} // namespace remoting
......@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/threading/thread_checker.h"
#include "remoting/protocol/frame_consumer.h"
#include "remoting/protocol/frame_stats.h"
#include "remoting/protocol/video_renderer.h"
#include "remoting/protocol/video_stub.h"
......@@ -64,6 +65,25 @@ class FakeFrameConsumer : public FrameConsumer {
base::Closure on_frame_callback_;
};
class FakeFrameStatsConsumer : public FrameStatsConsumer {
public:
FakeFrameStatsConsumer();
~FakeFrameStatsConsumer() override;
const std::list<FrameStats>& received_stats() { return received_stats_; }
void set_on_stats_callback(base::Closure on_stats_callback);
// FrameStatsConsumer interface.
void OnVideoFrameStats(const FrameStats& stats) override;
private:
base::ThreadChecker thread_checker_;
std::list<FrameStats> received_stats_;
base::Closure on_stats_callback_;
};
class FakeVideoRenderer : public VideoRenderer {
public:
FakeVideoRenderer();
......@@ -71,16 +91,18 @@ class FakeVideoRenderer : public VideoRenderer {
// VideoRenderer interface.
bool Initialize(const ClientContext& client_context,
protocol::PerformanceTracker* perf_tracker) override;
protocol::FrameStatsConsumer* stats_consumer) override;
void OnSessionConfig(const SessionConfig& config) override;
FakeVideoStub* GetVideoStub() override;
FakeFrameConsumer* GetFrameConsumer() override;
FakeFrameStatsConsumer* GetFrameStatsConsumer() override;
private:
base::ThreadChecker thread_checker_;
FakeVideoStub video_stub_;
FakeFrameConsumer frame_consumer_;
FakeFrameStatsConsumer frame_stats_consumer_;
};
} // namespace protocol
......
......@@ -9,15 +9,20 @@
namespace remoting {
namespace protocol {
FrameStats::FrameStats() = default;
FrameStats::FrameStats(const FrameStats&) = default;
FrameStats::~FrameStats() = default;
ClientFrameStats::ClientFrameStats() = default;
ClientFrameStats::ClientFrameStats(const ClientFrameStats&) = default;
ClientFrameStats::~ClientFrameStats() = default;
ClientFrameStats& ClientFrameStats::operator=(const ClientFrameStats&) =
default;
HostFrameStats::HostFrameStats() = default;
HostFrameStats::HostFrameStats(const HostFrameStats&) = default;
HostFrameStats::~HostFrameStats() = default;
// static
FrameStats FrameStats::GetForVideoPacket(const VideoPacket& packet) {
FrameStats result;
HostFrameStats HostFrameStats::GetForVideoPacket(const VideoPacket& packet) {
HostFrameStats result;
result.frame_size = packet.data().size();
result.time_received = base::TimeTicks::Now();
if (packet.has_latest_event_timestamp()) {
result.latest_event_timestamp =
base::TimeTicks::FromInternalValue(packet.latest_event_timestamp());
......@@ -49,5 +54,9 @@ FrameStats FrameStats::GetForVideoPacket(const VideoPacket& packet) {
return result;
}
FrameStats::FrameStats() = default;
FrameStats::FrameStats(const FrameStats&) = default;
FrameStats::~FrameStats() = default;
} // namespace protocol
} // namespace remoting
......@@ -10,20 +10,20 @@
namespace remoting {
class VideoPacket;
class FrameStatsMessage;
namespace protocol {
// Struct used to track timestamp for various events in the video pipeline for a
// single video frame
struct FrameStats {
FrameStats();
FrameStats(const FrameStats&);
~FrameStats();
struct HostFrameStats {
HostFrameStats();
HostFrameStats(const HostFrameStats&);
~HostFrameStats();
// Copies timing fields from the |packet|.
static FrameStats GetForVideoPacket(const VideoPacket& packet);
// Extracts timing fields from the |packet|.
static HostFrameStats GetForVideoPacket(const VideoPacket& packet);
int frame_size = 0;
// Frame Size.
int frame_size {};
// Set to null for frames that were not sent after a fresh input event.
base::TimeTicks latest_event_timestamp;
......@@ -35,12 +35,35 @@ struct FrameStats {
base::TimeDelta capture_overhead_delay = base::TimeDelta::Max();
base::TimeDelta encode_pending_delay = base::TimeDelta::Max();
base::TimeDelta send_pending_delay = base::TimeDelta::Max();
};
struct ClientFrameStats {
ClientFrameStats();
ClientFrameStats(const ClientFrameStats&);
~ClientFrameStats();
ClientFrameStats& operator=(const ClientFrameStats&);
base::TimeTicks time_received;
base::TimeTicks time_decoded;
base::TimeTicks time_rendered;
};
struct FrameStats {
FrameStats();
FrameStats(const FrameStats&);
~FrameStats();
HostFrameStats host_stats;
ClientFrameStats client_stats;
};
class FrameStatsConsumer {
public:
virtual void OnVideoFrameStats(const FrameStats& stats) = 0;
protected:
virtual ~FrameStatsConsumer() {}
};
} // namespace protocol
} // namespace remoting
......
......@@ -107,7 +107,7 @@ void PerformanceTracker::SetUpdateUmaCallbacks(
uma_enum_histogram_updater_ = update_uma_enum_histogram_callback;
}
void PerformanceTracker::RecordVideoFrameStats(const FrameStats& stats) {
void PerformanceTracker::OnVideoFrameStats(const FrameStats& stats) {
if (!is_paused_ && !upload_uma_stats_timer_.IsRunning()) {
upload_uma_stats_timer_.Start(
FROM_HERE, base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds),
......@@ -119,72 +119,77 @@ void PerformanceTracker::RecordVideoFrameStats(const FrameStats& stats) {
video_packet_rate_.Record(1);
// Use only non-empty frames to estimate frame rate.
if (stats.frame_size)
if (stats.host_stats.frame_size)
video_frame_rate_.Record(1);
video_bandwidth_.Record(stats.frame_size);
video_bandwidth_.Record(stats.host_stats.frame_size);
if (stats.capture_delay != base::TimeDelta::Max()) {
video_capture_ms_.Record(stats.capture_delay.InMilliseconds());
if (stats.host_stats.capture_delay != base::TimeDelta::Max()) {
video_capture_ms_.Record(stats.host_stats.capture_delay.InMilliseconds());
uma_custom_times_updater_.Run(
kVideoCaptureLatencyHistogram, stats.capture_delay.InMilliseconds(),
kVideoCaptureLatencyHistogram,
stats.host_stats.capture_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
}
if (stats.encode_delay != base::TimeDelta::Max()) {
video_encode_ms_.Record(stats.encode_delay.InMilliseconds());
if (stats.host_stats.encode_delay != base::TimeDelta::Max()) {
video_encode_ms_.Record(stats.host_stats.encode_delay.InMilliseconds());
uma_custom_times_updater_.Run(
kVideoEncodeLatencyHistogram, stats.encode_delay.InMilliseconds(),
kVideoEncodeLatencyHistogram,
stats.host_stats.encode_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
}
if (stats.capture_pending_delay != base::TimeDelta::Max()) {
uma_custom_times_updater_.Run(kCapturePendingLatencyHistogram,
stats.capture_pending_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs,
kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
if (stats.host_stats.capture_pending_delay != base::TimeDelta::Max()) {
uma_custom_times_updater_.Run(
kCapturePendingLatencyHistogram,
stats.host_stats.capture_pending_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
}
if (stats.capture_overhead_delay != base::TimeDelta::Max()) {
uma_custom_times_updater_.Run(kCaptureOverheadHistogram,
stats.capture_overhead_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs,
kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
if (stats.host_stats.capture_overhead_delay != base::TimeDelta::Max()) {
uma_custom_times_updater_.Run(
kCaptureOverheadHistogram,
stats.host_stats.capture_overhead_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
}
if (stats.encode_pending_delay != base::TimeDelta::Max()) {
uma_custom_times_updater_.Run(kEncodePendingLatencyHistogram,
stats.encode_pending_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs,
kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
if (stats.host_stats.encode_pending_delay != base::TimeDelta::Max()) {
uma_custom_times_updater_.Run(
kEncodePendingLatencyHistogram,
stats.host_stats.encode_pending_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
}
if (stats.send_pending_delay != base::TimeDelta::Max()) {
if (stats.host_stats.send_pending_delay != base::TimeDelta::Max()) {
uma_custom_times_updater_.Run(
kSendPendingLatencyHistogram, stats.send_pending_delay.InMilliseconds(),
kSendPendingLatencyHistogram,
stats.host_stats.send_pending_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
}
DCHECK(!stats.time_received.is_null());
DCHECK(!stats.client_stats.time_received.is_null());
// Report decode and render delay only for non-empty frames.
if (stats.frame_size > 0) {
DCHECK(!stats.time_rendered.is_null());
DCHECK(!stats.time_decoded.is_null());
base::TimeDelta decode_delay = stats.time_decoded - stats.time_received;
if (stats.host_stats.frame_size > 0) {
DCHECK(!stats.client_stats.time_rendered.is_null());
DCHECK(!stats.client_stats.time_decoded.is_null());
base::TimeDelta decode_delay =
stats.client_stats.time_decoded - stats.client_stats.time_received;
video_decode_ms_.Record(decode_delay.InMilliseconds());
uma_custom_times_updater_.Run(
kVideoDecodeLatencyHistogram, decode_delay.InMilliseconds(),
kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
kVideoActionsHistogramsBuckets);
base::TimeDelta render_delay = stats.time_rendered - stats.time_decoded;
base::TimeDelta render_delay =
stats.client_stats.time_rendered - stats.client_stats.time_decoded;
video_paint_ms_.Record(render_delay.InMilliseconds());
uma_custom_times_updater_.Run(
kVideoPaintLatencyHistogram, render_delay.InMilliseconds(),
......@@ -194,31 +199,35 @@ void PerformanceTracker::RecordVideoFrameStats(const FrameStats& stats) {
// |latest_event_timestamp| is set only for the first frame after an input
// event.
if (stats.latest_event_timestamp.is_null())
if (stats.host_stats.latest_event_timestamp.is_null())
return;
// For empty frames use time_received as time_rendered.
base::TimeTicks time_rendered =
(stats.frame_size > 0) ? stats.time_rendered : stats.time_received;
base::TimeTicks time_rendered = (stats.host_stats.frame_size > 0)
? stats.client_stats.time_rendered
: stats.client_stats.time_received;
base::TimeDelta round_trip_latency =
time_rendered - stats.latest_event_timestamp;
time_rendered - stats.host_stats.latest_event_timestamp;
round_trip_ms_.Record(round_trip_latency.InMilliseconds());
uma_custom_times_updater_.Run(
kRoundTripLatencyHistogram, round_trip_latency.InMilliseconds(),
kLatencyHistogramMinMs, kLatencyHistogramMaxMs, kLatencyHistogramBuckets);
// Report estimated network latency.
if (stats.capture_delay != base::TimeDelta::Max() &&
stats.encode_delay != base::TimeDelta::Max() &&
stats.capture_pending_delay != base::TimeDelta::Max() &&