blob: c7a3e73cefb5b113914577c88dd85887de283577 [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/loader/image/animated_image_tracker.h"
#include <algorithm>
#include <utility>
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "cobalt/base/polymorphic_downcast.h"
namespace cobalt {
namespace loader {
namespace image {
AnimatedImageTracker::AnimatedImageTracker(
const char* name,
base::ThreadPriority animated_image_decode_thread_priority)
: animated_image_decode_thread_("AnimatedImage"),
name_(name),
count_animated_images_active(
base::StringPrintf("Count.%s.AnimatedImage.Active", name), 0,
"Total number of active animated image decoders."),
count_animated_frames_decoded(
base::StringPrintf("Count.%s.AnimatedImage.DecodedFrames", name), 0,
"Total number of decoded animated image frames."),
count_animated_frames_decoding_underrun(
base::StringPrintf("Count.%s.AnimatedImage.DecodingUnderruns", name),
0, "Number of underruns from decoding animated images"),
count_animated_frames_decoding_overrun(
base::StringPrintf("Count.%s.AnimatedImage.DecodingOverruns", name),
0, "Number of overruns from decoding animated images") {
TRACE_EVENT0("cobalt::loader::image", "AnimatedImageTracker::RecordImage()");
base::Thread::Options options(base::MessageLoop::TYPE_DEFAULT,
0 /* default stack size */);
options.priority = animated_image_decode_thread_priority;
animated_image_decode_thread_.StartWithOptions(options);
}
AnimatedImageTracker::~AnimatedImageTracker() {
TRACE_EVENT0("cobalt::loader::image", "AnimatedImageTracker::RecordImage()");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
void AnimatedImageTracker::IncreaseURLCount(const GURL& url) {
TRACE_EVENT0("cobalt::loader::image",
"AnimatedImageTracker::IncreaseURLCount()");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
current_url_counts_[url]++;
}
void AnimatedImageTracker::DecreaseURLCount(const GURL& url) {
TRACE_EVENT0("cobalt::loader::image",
"AnimatedImageTracker::DecreaseURLCount()");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_GT(current_url_counts_[url], 0);
current_url_counts_[url]--;
}
void AnimatedImageTracker::RecordImage(
const GURL& url, loader::image::AnimatedImage* animated_image) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(animated_image);
TRACE_EVENT0("cobalt::loader::image", "AnimatedImageTracker::RecordImage()");
image_map_[url] = animated_image;
}
void AnimatedImageTracker::ProcessRecordedImages() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
TRACE_EVENT0("cobalt::loader::image",
"AnimatedImageTracker::ProcessRecordedImages()");
for (URLToIntMap::iterator it = current_url_counts_.begin();
it != current_url_counts_.end();) {
const GURL& url = it->first;
URLSet::iterator playing_url = playing_urls_.find(url);
if (it->second == 0) {
// Remove the images that are no longer displayed, and stop the
// animations.
if (playing_url != playing_urls_.end()) {
playing_urls_.erase(playing_url);
OnDisplayEnd(image_map_[url].get());
}
image_map_.erase(url);
previous_url_counts_.erase(url);
current_url_counts_.erase(it++);
} else {
// Record the images that start to be displayed, and start the
// animations.
if (playing_url == playing_urls_.end()) {
URLToImageMap::iterator playing_image = image_map_.find(url);
if (playing_image != image_map_.end()) {
playing_urls_.insert(std::make_pair(url, base::Unused()));
OnDisplayStart(playing_image->second.get());
}
}
previous_url_counts_[url] = it->second;
++it;
}
}
}
void AnimatedImageTracker::OnDisplayStart(
loader::image::AnimatedImage* animated_image) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(animated_image);
TRACE_EVENT0("cobalt::loader::image",
"AnimatedImageTracker::OnDisplayStart()");
animated_image->Play(animated_image_decode_thread_.task_runner());
}
void AnimatedImageTracker::OnDisplayEnd(
loader::image::AnimatedImage* animated_image) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(animated_image);
TRACE_EVENT0("cobalt::loader::image", "AnimatedImageTracker::OnDisplayEnd()");
animated_image->Stop();
}
void AnimatedImageTracker::Reset() {
for (const auto& playing_url : playing_urls_) {
OnDisplayEnd(image_map_[playing_url.first].get());
}
image_map_.clear();
current_url_counts_.clear();
previous_url_counts_.clear();
playing_urls_.clear();
}
void AnimatedImageTracker::OnRenderTreeRasterized() {
count_animated_images_active = playing_urls_.size();
for (const auto& playing_url : playing_urls_) {
auto image = image_map_[playing_url.first].get();
auto stats = image->GetFrameDeltaStats();
count_animated_frames_decoded += stats.frames_decoded;
count_animated_frames_decoding_underrun += stats.frames_underrun;
count_animated_frames_decoding_overrun += stats.frames_overrun;
}
}
} // namespace image
} // namespace loader
} // namespace cobalt