blob: 5fb66875b855533609bc1f0565eec550ccd58cec [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
#include <memory>
#include <utility>
#include "SkData.h"
#include "base/macros.h"
#include "third_party/blink/renderer/platform/graphics/image_decoder_wrapper.h"
#include "third_party/blink/renderer/platform/graphics/image_decoding_store.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/skia/include/core/SkYUVASizeInfo.h"
namespace blink {
static bool UpdateYUVComponentSizes(ImageDecoder* decoder,
SkISize component_sizes[4],
size_t component_width_bytes[4]) {
DCHECK(decoder->CanDecodeToYUV());
for (int yuv_index = 0; yuv_index < 3; ++yuv_index) {
IntSize size = decoder->DecodedYUVSize(yuv_index);
component_sizes[yuv_index].set(size.Width(), size.Height());
component_width_bytes[yuv_index] = decoder->DecodedYUVWidthBytes(yuv_index);
}
component_sizes[3] = SkISize::MakeEmpty();
component_width_bytes[3] = 0;
return true;
}
ImageFrameGenerator::ImageFrameGenerator(const SkISize& full_size,
bool is_multi_frame,
const ColorBehavior& color_behavior,
std::vector<SkISize> supported_sizes)
: full_size_(full_size),
decoder_color_behavior_(color_behavior),
is_multi_frame_(is_multi_frame),
supported_sizes_(std::move(supported_sizes)) {
#if DCHECK_IS_ON()
// Verify that sizes are in an increasing order, since
// GetSupportedDecodeSize() depends on it.
SkISize last_size = SkISize::MakeEmpty();
for (auto& size : supported_sizes_) {
DCHECK_GE(size.width(), last_size.width());
DCHECK_GE(size.height(), last_size.height());
}
#endif
}
ImageFrameGenerator::~ImageFrameGenerator() {
ImageDecodingStore::Instance().RemoveCacheIndexedByGenerator(this);
}
bool ImageFrameGenerator::DecodeAndScale(
SegmentReader* data,
bool all_data_received,
size_t index,
const SkImageInfo& info,
void* pixels,
size_t row_bytes,
ImageDecoder::AlphaOption alpha_option,
cc::PaintImage::GeneratorClientId client_id) {
{
MutexLocker lock(generator_mutex_);
if (decode_failed_)
return false;
}
TRACE_EVENT1("blink", "ImageFrameGenerator::decodeAndScale", "generator",
this);
// This implementation does not support arbitrary scaling so check the
// requested size.
SkISize scaled_size = SkISize::Make(info.width(), info.height());
CHECK(GetSupportedDecodeSize(scaled_size) == scaled_size);
ImageDecoder::HighBitDepthDecodingOption high_bit_depth_decoding_option =
ImageDecoder::kDefaultBitDepth;
if (info.colorType() == kRGBA_F16_SkColorType) {
high_bit_depth_decoding_option = ImageDecoder::kHighBitDepthToHalfFloat;
}
size_t frame_count = 0u;
bool has_alpha = true;
// |decode_failed| indicates a failure due to a corrupt image.
bool decode_failed = false;
// |current_decode_succeeded| indicates a failure to decode the current frame.
// Its possible to have a valid but fail to decode a frame in the case where
// we don't have enough data to decode this particular frame yet.
bool current_decode_succeeded = false;
{
// Lock the mutex, so only one thread can use the decoder at once.
ClientMutexLocker lock(this, client_id);
ImageDecoderWrapper decoder_wrapper(
this, data, scaled_size, alpha_option, decoder_color_behavior_,
high_bit_depth_decoding_option, index, info, pixels, row_bytes,
all_data_received, client_id);
current_decode_succeeded = decoder_wrapper.Decode(
image_decoder_factory_.get(), &frame_count, &has_alpha);
decode_failed = decoder_wrapper.decode_failed();
}
MutexLocker lock(generator_mutex_);
decode_failed_ = decode_failed;
if (decode_failed_) {
DCHECK(!current_decode_succeeded);
return false;
}
if (!current_decode_succeeded)
return false;
SetHasAlpha(index, has_alpha);
if (frame_count != 0u)
frame_count_ = frame_count;
return true;
}
bool ImageFrameGenerator::DecodeToYUV(SegmentReader* data,
size_t index,
const SkISize component_sizes[3],
void* planes[3],
const size_t row_bytes[3]) {
MutexLocker lock(generator_mutex_);
DCHECK_EQ(index, 0u);
// TODO (scroggo): The only interesting thing this uses from the
// ImageFrameGenerator is m_decodeFailed. Move this into
// DecodingImageGenerator, which is the only class that calls it.
if (decode_failed_)
return false;
TRACE_EVENT1("blink", "ImageFrameGenerator::decodeToYUV", "frame index",
static_cast<int>(index));
if (!planes || !planes[0] || !planes[1] || !planes[2] || !row_bytes ||
!row_bytes[0] || !row_bytes[1] || !row_bytes[2]) {
return false;
}
const bool data_complete = true;
std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
data, data_complete, ImageDecoder::kAlphaPremultiplied,
ImageDecoder::kDefaultBitDepth, decoder_color_behavior_);
// getYUVComponentSizes was already called and was successful, so
// ImageDecoder::create must succeed.
DCHECK(decoder);
std::unique_ptr<ImagePlanes> image_planes =
std::make_unique<ImagePlanes>(planes, row_bytes);
decoder->SetImagePlanes(std::move(image_planes));
DCHECK(decoder->CanDecodeToYUV());
if (decoder->DecodeToYUV()) {
SetHasAlpha(0, false); // YUV is always opaque
return true;
}
DCHECK(decoder->Failed());
yuv_decoding_failed_ = true;
return false;
}
void ImageFrameGenerator::SetHasAlpha(size_t index, bool has_alpha) {
generator_mutex_.AssertAcquired();
if (index >= has_alpha_.size()) {
const size_t old_size = has_alpha_.size();
has_alpha_.resize(index + 1);
for (size_t i = old_size; i < has_alpha_.size(); ++i)
has_alpha_[i] = true;
}
has_alpha_[index] = has_alpha;
}
bool ImageFrameGenerator::HasAlpha(size_t index) {
MutexLocker lock(generator_mutex_);
if (index < has_alpha_.size())
return has_alpha_[index];
return true;
}
bool ImageFrameGenerator::GetYUVComponentSizes(SegmentReader* data,
SkYUVASizeInfo* size_info) {
TRACE_EVENT2("blink", "ImageFrameGenerator::getYUVComponentSizes", "width",
full_size_.width(), "height", full_size_.height());
MutexLocker lock(generator_mutex_);
if (yuv_decoding_failed_)
return false;
const bool data_complete = true;
std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
data, data_complete, ImageDecoder::kAlphaPremultiplied,
ImageDecoder::kDefaultBitDepth, decoder_color_behavior_);
if (!decoder)
return false;
// Setting a dummy ImagePlanes object signals to the decoder that we want to
// do YUV decoding.
std::unique_ptr<ImagePlanes> dummy_image_planes =
std::make_unique<ImagePlanes>();
decoder->SetImagePlanes(std::move(dummy_image_planes));
return UpdateYUVComponentSizes(decoder.get(), size_info->fSizes,
size_info->fWidthBytes);
}
SkISize ImageFrameGenerator::GetSupportedDecodeSize(
const SkISize& requested_size) const {
for (auto& size : supported_sizes_) {
if (size.width() >= requested_size.width() &&
size.height() >= requested_size.height()) {
return size;
}
}
return full_size_;
}
ImageFrameGenerator::ClientMutexLocker::ClientMutexLocker(
ImageFrameGenerator* generator,
cc::PaintImage::GeneratorClientId client_id)
: generator_(generator), client_id_(client_id) {
{
MutexLocker lock(generator_->generator_mutex_);
ClientMutex* client_mutex = nullptr;
auto it = generator_->mutex_map_.find(client_id_);
if (it == generator_->mutex_map_.end())
client_mutex = &generator_->mutex_map_[client_id];
else
client_mutex = &it->second;
client_mutex->ref_count++;
mutex_ = &client_mutex->mutex;
}
mutex_->lock();
}
ImageFrameGenerator::ClientMutexLocker::~ClientMutexLocker() {
mutex_->unlock();
MutexLocker lock(generator_->generator_mutex_);
auto it = generator_->mutex_map_.find(client_id_);
DCHECK(it != generator_->mutex_map_.end());
it->second.ref_count--;
if (it->second.ref_count == 0)
generator_->mutex_map_.erase(it);
}
} // namespace blink