Commit 62fe0b34 authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Stop posting video stats for every Render(); optimize storage.

There's really no reason for us to be posting this for every single
Render() call. They can be updated nearly as quickly during each
FrameReady() call. There's also no reason for us to create a new
PipelineStatistics structure every time either. Instead replace
a multitude of member variables with a PipelineStatistics member.

This is an optimization of PipelineStatistics usage so that we
can add a Decoder enum value later.

BUG=793151
TEST=existing tests pass.

Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I5375acf74a625e1095e6631e177b4a04a4a0e54d
Reviewed-on: https://chromium-review.googlesource.com/816019Reviewed-by: default avatarChrome Cunningham <chcunningham@chromium.org>
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#523171}
parent e410b0bb
......@@ -49,9 +49,8 @@ DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderStreamTraits(
void DecoderStreamTraits<DemuxerStream::AUDIO>::ReportStatistics(
const StatisticsCB& statistics_cb,
int bytes_decoded) {
PipelineStatistics statistics;
statistics.audio_bytes_decoded = bytes_decoded;
statistics_cb.Run(statistics);
stats_.audio_bytes_decoded = bytes_decoded;
statistics_cb.Run(stats_);
}
void DecoderStreamTraits<DemuxerStream::AUDIO>::InitializeDecoder(
......@@ -126,19 +125,18 @@ DecoderStreamTraits<DemuxerStream::VIDEO>::DecoderStreamTraits(
void DecoderStreamTraits<DemuxerStream::VIDEO>::ReportStatistics(
const StatisticsCB& statistics_cb,
int bytes_decoded) {
PipelineStatistics statistics;
statistics.video_bytes_decoded = bytes_decoded;
stats_.video_bytes_decoded = bytes_decoded;
if (keyframe_distance_average_.count()) {
statistics.video_keyframe_distance_average =
stats_.video_keyframe_distance_average =
keyframe_distance_average_.Average();
} else {
// Before we have enough keyframes to calculate the average distance, we
// will assume the average keyframe distance is infinitely large.
statistics.video_keyframe_distance_average = base::TimeDelta::Max();
stats_.video_keyframe_distance_average = base::TimeDelta::Max();
}
statistics_cb.Run(statistics);
statistics_cb.Run(stats_);
}
void DecoderStreamTraits<DemuxerStream::VIDEO>::InitializeDecoder(
......
......@@ -66,8 +66,8 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::AUDIO> {
// if timestamp gaps are detected. Sufficiently large gaps can lead to AV sync
// drift.
std::unique_ptr<AudioTimestampValidator> audio_ts_validator_;
MediaLog* media_log_;
PipelineStatistics stats_;
};
template <>
......@@ -104,6 +104,7 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::VIDEO> {
base::TimeDelta last_keyframe_timestamp_;
MovingAverage keyframe_distance_average_;
base::flat_set<base::TimeDelta> frames_to_drop_;
PipelineStatistics stats_;
};
} // namespace media
......
......@@ -130,13 +130,9 @@ VideoRendererImpl::VideoRendererImpl(
pending_read_(false),
drop_frames_(drop_frames),
buffering_state_(BUFFERING_HAVE_NOTHING),
frames_decoded_(0),
frames_dropped_(0),
frames_decoded_power_efficient_(0),
tick_clock_(base::DefaultTickClock::GetInstance()),
was_background_rendering_(false),
time_progressing_(false),
last_video_memory_usage_(0),
have_renderered_frames_(false),
last_frame_opaque_(false),
painted_first_frame_(false),
......@@ -217,6 +213,7 @@ void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) {
start_timestamp_ = timestamp;
painted_first_frame_ = false;
has_playback_met_watch_time_duration_requirement_ = false;
last_render_time_ = last_frame_ready_time_ = base::TimeTicks();
AttemptRead_Locked();
}
......@@ -285,6 +282,7 @@ scoped_refptr<VideoFrame> VideoRendererImpl::Render(
TRACE_EVENT1("media", "VideoRendererImpl::Render", "id", media_log_->id());
base::AutoLock auto_lock(lock_);
DCHECK_EQ(state_, kPlaying);
last_render_time_ = tick_clock_->NowTicks();
size_t frames_dropped = 0;
scoped_refptr<VideoFrame> result =
......@@ -316,8 +314,7 @@ scoped_refptr<VideoFrame> VideoRendererImpl::Render(
// Just after resuming from background rendering, we also don't count the
// dropped frames since they are likely just dropped due to being too old.
if (!background_rendering && !was_background_rendering_)
frames_dropped_ += frames_dropped;
UpdateStats_Locked();
stats_.video_frames_dropped += frames_dropped;
was_background_rendering_ = background_rendering;
// Always post this task, it will acquire new frames if necessary and since it
......@@ -512,7 +509,8 @@ void VideoRendererImpl::FrameReady(base::TimeTicks read_time,
return;
}
read_durations_.AddSample(tick_clock_->NowTicks() - read_time);
last_frame_ready_time_ = tick_clock_->NowTicks();
read_durations_.AddSample(last_frame_ready_time_ - read_time);
UMA_HISTOGRAM_ENUMERATION("Media.VideoFrame.ColorSpace",
ColorSpaceUMAHelper(frame->ColorSpace()),
......@@ -566,9 +564,8 @@ void VideoRendererImpl::FrameReady(base::TimeTicks read_time,
// We may have removed all frames above and have reached end of stream.
MaybeFireEndedCallback_Locked(time_progressing_);
// Update statistics here instead of during Render() when the sink is stopped.
if (!sink_started_)
UpdateStats_Locked();
// Update any statistics since the last call.
UpdateStats_Locked();
// Paint the first frame if possible and necessary. Paint ahead of
// HAVE_ENOUGH_DATA to ensure the user sees the frame as early as possible.
......@@ -611,7 +608,9 @@ bool VideoRendererImpl::HaveEnoughData_Locked() const {
return true;
}
if (was_background_rendering_ && frames_decoded_)
// If we've decoded any frames since the last render, signal have enough to
// avoid underflowing when video is not visible unless we run out of frames.
if (was_background_rendering_ && last_frame_ready_time_ >= last_render_time_)
return true;
if (!low_delay_ && video_frame_stream_->CanReadWithoutStalling())
......@@ -663,13 +662,13 @@ void VideoRendererImpl::AddReadyFrame_Locked(
lock_.AssertAcquired();
DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
frames_decoded_++;
++stats_.video_frames_decoded;
bool power_efficient = false;
if (frame->metadata()->GetBoolean(VideoFrameMetadata::POWER_EFFICIENT,
&power_efficient) &&
power_efficient) {
++frames_decoded_power_efficient_;
++stats_.video_frames_decoded_power_efficient;
}
algorithm_->EnqueueFrame(frame);
......@@ -723,37 +722,29 @@ void VideoRendererImpl::OnVideoFrameStreamResetDone() {
}
void VideoRendererImpl::UpdateStats_Locked() {
DCHECK(task_runner_->BelongsToCurrentThread());
lock_.AssertAcquired();
DCHECK_GE(frames_decoded_, 0);
DCHECK_GE(frames_dropped_, 0);
// No need to check for `frames_decoded_power_efficient_` because if it is
// greater than 0, `frames_decoded_` will too.
if (frames_decoded_ || frames_dropped_) {
if (frames_dropped_)
TRACE_EVENT_INSTANT2("media", "VideoFramesDropped",
TRACE_EVENT_SCOPE_THREAD, "count", frames_dropped_,
"id", media_log_->id());
PipelineStatistics statistics;
statistics.video_frames_decoded = frames_decoded_;
statistics.video_frames_dropped = frames_dropped_;
statistics.video_frames_decoded_power_efficient =
frames_decoded_power_efficient_;
const size_t memory_usage = algorithm_->GetMemoryUsage();
statistics.video_memory_usage = memory_usage - last_video_memory_usage_;
statistics.video_frame_duration_average =
algorithm_->average_frame_duration();
task_runner_->PostTask(FROM_HERE,
base::Bind(&VideoRendererImpl::OnStatisticsUpdate,
weak_factory_.GetWeakPtr(), statistics));
frames_decoded_ = 0;
frames_dropped_ = 0;
frames_decoded_power_efficient_ = 0;
last_video_memory_usage_ = memory_usage;
// No need to check for `stats_.video_frames_decoded_power_efficient` because
// if it is greater than 0, `stats_.video_frames_decoded` will too.
if (!stats_.video_frames_decoded && !stats_.video_frames_dropped)
return;
if (stats_.video_frames_dropped) {
TRACE_EVENT_INSTANT2("media", "VideoFramesDropped",
TRACE_EVENT_SCOPE_THREAD, "count",
stats_.video_frames_dropped, "id", media_log_->id());
}
const size_t memory_usage = algorithm_->GetMemoryUsage();
stats_.video_memory_usage = memory_usage - stats_.video_memory_usage;
stats_.video_frame_duration_average = algorithm_->average_frame_duration();
OnStatisticsUpdate(stats_);
stats_.video_frames_decoded = 0;
stats_.video_frames_dropped = 0;
stats_.video_frames_decoded_power_efficient = 0;
stats_.video_memory_usage = memory_usage;
}
bool VideoRendererImpl::HaveReachedBufferingCap() const {
......@@ -856,7 +847,7 @@ void VideoRendererImpl::RemoveFramesForUnderflowOrBackgroundRendering() {
// the entire queue. Note: this may cause slight inaccuracies in the number
// of dropped frames since the frame may have been rendered before.
if (!sink_started_ && !algorithm_->effective_frames_queued()) {
frames_dropped_ += algorithm_->frames_queued();
stats_.video_frames_dropped += algorithm_->frames_queued();
algorithm_->Reset(
VideoRendererAlgorithm::ResetFlag::kPreserveNextFrameEstimates);
painted_first_frame_ = false;
......@@ -874,7 +865,7 @@ void VideoRendererImpl::RemoveFramesForUnderflowOrBackgroundRendering() {
// subtract from the given value). It's important to always call this so
// that frame statistics are updated correctly.
if (buffering_state_ == BUFFERING_HAVE_NOTHING) {
frames_dropped_ += algorithm_->RemoveExpiredFrames(
stats_.video_frames_dropped += algorithm_->RemoveExpiredFrames(
current_time + algorithm_->average_frame_duration());
return;
}
......
......@@ -293,11 +293,7 @@ class MEDIA_EXPORT VideoRendererImpl
// Keeps track of the number of frames decoded and dropped since the
// last call to |statistics_cb_|. These must be accessed under lock.
int frames_decoded_;
int frames_dropped_;
// Keeps track of the number of power efficient decoded frames.
int frames_decoded_power_efficient_;
PipelineStatistics stats_;
base::TickClock* tick_clock_;
......@@ -316,10 +312,6 @@ class MEDIA_EXPORT VideoRendererImpl
// only be accessed from |task_runner_|.
bool time_progressing_;
// Memory usage of |algorithm_| recorded during the last UpdateStats_Locked()
// call.
int64_t last_video_memory_usage_;
// Indicates if a frame has been processed by CheckForMetadataChanges().
bool have_renderered_frames_;
......@@ -345,6 +337,11 @@ class MEDIA_EXPORT VideoRendererImpl
size_t max_buffered_frames_;
MovingAverage read_durations_;
// Last Render() and last FrameReady() times respectively. Used to avoid
// triggering underflow when background rendering.
base::TimeTicks last_render_time_;
base::TimeTicks last_frame_ready_time_;
// Indicates that the playback has been ongoing for at least
// limits::kMinimumElapsedWatchTimeSecs.
bool has_playback_met_watch_time_duration_requirement_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment