1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
27
28 #include <memory>
29 #include <utility>
30
31 #include "base/macros.h"
32 #include "third_party/blink/renderer/platform/graphics/image_decoder_wrapper.h"
33 #include "third_party/blink/renderer/platform/graphics/image_decoding_store.h"
34 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
35 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
36 #include "third_party/skia/include/core/SkData.h"
37 #include "third_party/skia/include/core/SkYUVASizeInfo.h"
38
39 namespace blink {
40
UpdateYUVAInfoPlanarConfigAndWidthBytes(ImageDecoder * decoder,SkYUVAInfo::PlanarConfig * config,size_t component_width_bytes[SkYUVAInfo::kMaxPlanes])41 static bool UpdateYUVAInfoPlanarConfigAndWidthBytes(
42 ImageDecoder* decoder,
43 SkYUVAInfo::PlanarConfig* config,
44 size_t component_width_bytes[SkYUVAInfo::kMaxPlanes]) {
45 switch (decoder->GetYUVSubsampling()) {
46 case cc::YUVSubsampling::k410:
47 *config = SkYUVAInfo::PlanarConfig::kY_U_V_410;
48 break;
49 case cc::YUVSubsampling::k411:
50 *config = SkYUVAInfo::PlanarConfig::kY_U_V_411;
51 break;
52 case cc::YUVSubsampling::k420:
53 *config = SkYUVAInfo::PlanarConfig::kY_U_V_420;
54 break;
55 case cc::YUVSubsampling::k422:
56 *config = SkYUVAInfo::PlanarConfig::kY_U_V_422;
57 break;
58 case cc::YUVSubsampling::k440:
59 *config = SkYUVAInfo::PlanarConfig::kY_U_V_440;
60 break;
61 case cc::YUVSubsampling::k444:
62 *config = SkYUVAInfo::PlanarConfig::kY_U_V_444;
63 break;
64 default:
65 return false;
66 }
67 component_width_bytes[0] = decoder->DecodedYUVWidthBytes(cc::YUVIndex::kY);
68 component_width_bytes[1] = decoder->DecodedYUVWidthBytes(cc::YUVIndex::kU);
69 component_width_bytes[2] = decoder->DecodedYUVWidthBytes(cc::YUVIndex::kV);
70 // TODO(crbug/910276): Alpha plane is currently unsupported.
71 component_width_bytes[3] = 0;
72 return true;
73 }
74
ImageFrameGenerator(const SkISize & full_size,bool is_multi_frame,const ColorBehavior & color_behavior,Vector<SkISize> supported_sizes)75 ImageFrameGenerator::ImageFrameGenerator(const SkISize& full_size,
76 bool is_multi_frame,
77 const ColorBehavior& color_behavior,
78 Vector<SkISize> supported_sizes)
79 : full_size_(full_size),
80 decoder_color_behavior_(color_behavior),
81 is_multi_frame_(is_multi_frame),
82 supported_sizes_(std::move(supported_sizes)) {
83 #if DCHECK_IS_ON()
84 // Verify that sizes are in an increasing order, since
85 // GetSupportedDecodeSize() depends on it.
86 SkISize last_size = SkISize::MakeEmpty();
87 for (auto& size : supported_sizes_) {
88 DCHECK_GE(size.width(), last_size.width());
89 DCHECK_GE(size.height(), last_size.height());
90 }
91 #endif
92 }
93
~ImageFrameGenerator()94 ImageFrameGenerator::~ImageFrameGenerator() {
95 // We expect all image decoders to be unlocked and catch with DCHECKs if not.
96 ImageDecodingStore::Instance().RemoveCacheIndexedByGenerator(this);
97 }
98
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)99 bool ImageFrameGenerator::DecodeAndScale(
100 SegmentReader* data,
101 bool all_data_received,
102 size_t index,
103 const SkImageInfo& info,
104 void* pixels,
105 size_t row_bytes,
106 ImageDecoder::AlphaOption alpha_option,
107 cc::PaintImage::GeneratorClientId client_id) {
108 {
109 MutexLocker lock(generator_mutex_);
110 if (decode_failed_)
111 return false;
112 }
113
114 TRACE_EVENT1("blink", "ImageFrameGenerator::decodeAndScale", "generator",
115 this);
116
117 // This implementation does not support arbitrary scaling so check the
118 // requested size.
119 SkISize scaled_size = SkISize::Make(info.width(), info.height());
120 CHECK(GetSupportedDecodeSize(scaled_size) == scaled_size);
121
122 ImageDecoder::HighBitDepthDecodingOption high_bit_depth_decoding_option =
123 ImageDecoder::kDefaultBitDepth;
124 if (info.colorType() == kRGBA_F16_SkColorType) {
125 high_bit_depth_decoding_option = ImageDecoder::kHighBitDepthToHalfFloat;
126 }
127
128 size_t frame_count = 0u;
129 bool has_alpha = true;
130
131 // |decode_failed| indicates a failure due to a corrupt image.
132 bool decode_failed = false;
133 // |current_decode_succeeded| indicates a failure to decode the current frame.
134 // Its possible to have a valid but fail to decode a frame in the case where
135 // we don't have enough data to decode this particular frame yet.
136 bool current_decode_succeeded = false;
137 {
138 // Lock the mutex, so only one thread can use the decoder at once.
139 ClientMutexLocker lock(this, client_id);
140 ImageDecoderWrapper decoder_wrapper(
141 this, data, scaled_size, alpha_option, decoder_color_behavior_,
142 high_bit_depth_decoding_option, index, info, pixels, row_bytes,
143 all_data_received, client_id);
144 current_decode_succeeded = decoder_wrapper.Decode(
145 image_decoder_factory_.get(), &frame_count, &has_alpha);
146 decode_failed = decoder_wrapper.decode_failed();
147 }
148
149 MutexLocker lock(generator_mutex_);
150 decode_failed_ = decode_failed;
151 if (decode_failed_) {
152 DCHECK(!current_decode_succeeded);
153 return false;
154 }
155
156 if (!current_decode_succeeded)
157 return false;
158
159 SetHasAlpha(index, has_alpha);
160 if (frame_count != 0u)
161 frame_count_ = frame_count;
162
163 return true;
164 }
165
DecodeToYUV(SegmentReader * data,size_t index,SkColorType color_type,const SkISize component_sizes[cc::kNumYUVPlanes],void * planes[cc::kNumYUVPlanes],const size_t row_bytes[cc::kNumYUVPlanes])166 bool ImageFrameGenerator::DecodeToYUV(
167 SegmentReader* data,
168 size_t index,
169 SkColorType color_type,
170 const SkISize component_sizes[cc::kNumYUVPlanes],
171 void* planes[cc::kNumYUVPlanes],
172 const size_t row_bytes[cc::kNumYUVPlanes]) {
173 MutexLocker lock(generator_mutex_);
174 DCHECK_EQ(index, 0u);
175
176 // TODO (scroggo): The only interesting thing this uses from the
177 // ImageFrameGenerator is m_decodeFailed. Move this into
178 // DecodingImageGenerator, which is the only class that calls it.
179 if (decode_failed_ || yuv_decoding_failed_)
180 return false;
181
182 if (!planes || !planes[0] || !planes[1] || !planes[2] || !row_bytes ||
183 !row_bytes[0] || !row_bytes[1] || !row_bytes[2]) {
184 return false;
185 }
186 const bool all_data_received = true;
187 std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
188 data, all_data_received, ImageDecoder::kAlphaPremultiplied,
189 ImageDecoder::kDefaultBitDepth, decoder_color_behavior_);
190 // getYUVComponentSizes was already called and was successful, so
191 // ImageDecoder::create must succeed.
192 DCHECK(decoder);
193
194 std::unique_ptr<ImagePlanes> image_planes =
195 std::make_unique<ImagePlanes>(planes, row_bytes, color_type);
196 // TODO(crbug.com/943519): Don't forget to initialize planes to black or
197 // transparent for incremental decoding.
198 decoder->SetImagePlanes(std::move(image_planes));
199
200 DCHECK(decoder->CanDecodeToYUV());
201
202 {
203 // This is the YUV analog of ImageFrameGenerator::decode.
204 TRACE_EVENT0("blink,benchmark", "ImageFrameGenerator::decodeToYUV");
205 decoder->DecodeToYUV();
206 }
207
208 if (!decoder->Failed()) {
209 // TODO(crbug.com/910276): Set this properly for alpha support.
210 SetHasAlpha(index, false);
211 return true;
212 }
213
214 DCHECK(decoder->Failed());
215 yuv_decoding_failed_ = true;
216 return false;
217 }
218
SetHasAlpha(size_t index,bool has_alpha)219 void ImageFrameGenerator::SetHasAlpha(size_t index, bool has_alpha) {
220 generator_mutex_.AssertAcquired();
221
222 if (index >= has_alpha_.size()) {
223 const size_t old_size = has_alpha_.size();
224 has_alpha_.resize(index + 1);
225 for (size_t i = old_size; i < has_alpha_.size(); ++i)
226 has_alpha_[i] = true;
227 }
228 has_alpha_[index] = has_alpha;
229 }
230
HasAlpha(size_t index)231 bool ImageFrameGenerator::HasAlpha(size_t index) {
232 MutexLocker lock(generator_mutex_);
233
234 if (index < has_alpha_.size())
235 return has_alpha_[index];
236 return true;
237 }
238
GetYUVAInfo(SegmentReader * data,const SkYUVAPixmapInfo::SupportedDataTypes & supported_data_types,SkYUVAPixmapInfo * info)239 bool ImageFrameGenerator::GetYUVAInfo(
240 SegmentReader* data,
241 const SkYUVAPixmapInfo::SupportedDataTypes& supported_data_types,
242 SkYUVAPixmapInfo* info) {
243 TRACE_EVENT2("blink", "ImageFrameGenerator::GetYUVAInfo", "width",
244 full_size_.width(), "height", full_size_.height());
245
246 MutexLocker lock(generator_mutex_);
247
248 if (yuv_decoding_failed_)
249 return false;
250 std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
251 data, true /* data_complete */, ImageDecoder::kAlphaPremultiplied,
252 ImageDecoder::kDefaultBitDepth, decoder_color_behavior_);
253 DCHECK(decoder);
254
255 DCHECK(decoder->CanDecodeToYUV());
256 SkYUVAInfo::PlanarConfig config;
257 size_t width_bytes[SkYUVAInfo::kMaxPlanes];
258 if (!UpdateYUVAInfoPlanarConfigAndWidthBytes(decoder.get(), &config,
259 width_bytes)) {
260 return false;
261 }
262 SkYUVAInfo yuva_info(full_size_, config, decoder->GetYUVColorSpace());
263 SkYUVAPixmapInfo::DataType dataType;
264 if (decoder->GetYUVBitDepth() > 8) {
265 if (supported_data_types.supported(config,
266 SkYUVAPixmapInfo::DataType::kUnorm16)) {
267 dataType = SkYUVAPixmapInfo::DataType::kUnorm16;
268 } else if (supported_data_types.supported(
269 config, SkYUVAPixmapInfo::DataType::kFloat16)) {
270 dataType = SkYUVAPixmapInfo::DataType::kFloat16;
271 } else {
272 return false;
273 }
274 } else if (supported_data_types.supported(
275 config, SkYUVAPixmapInfo::DataType::kUnorm8)) {
276 dataType = SkYUVAPixmapInfo::DataType::kUnorm8;
277 } else {
278 return false;
279 }
280 *info = SkYUVAPixmapInfo(yuva_info, dataType, width_bytes);
281 DCHECK(info->isSupported(supported_data_types));
282
283 return true;
284 }
285
GetSupportedDecodeSize(const SkISize & requested_size) const286 SkISize ImageFrameGenerator::GetSupportedDecodeSize(
287 const SkISize& requested_size) const {
288 for (auto& size : supported_sizes_) {
289 if (size.width() >= requested_size.width() &&
290 size.height() >= requested_size.height()) {
291 return size;
292 }
293 }
294 return full_size_;
295 }
296
ClientMutexLocker(ImageFrameGenerator * generator,cc::PaintImage::GeneratorClientId client_id)297 ImageFrameGenerator::ClientMutexLocker::ClientMutexLocker(
298 ImageFrameGenerator* generator,
299 cc::PaintImage::GeneratorClientId client_id)
300 : generator_(generator), client_id_(client_id) {
301 {
302 MutexLocker lock(generator_->generator_mutex_);
303 auto it = generator_->mutex_map_.find(client_id_);
304 ClientMutex* client_mutex;
305 if (it == generator_->mutex_map_.end()) {
306 auto result = generator_->mutex_map_.insert(
307 client_id_, std::make_unique<ClientMutex>());
308 client_mutex = result.stored_value->value.get();
309 } else {
310 client_mutex = it->value.get();
311 }
312 client_mutex->ref_count++;
313 mutex_ = &client_mutex->mutex;
314 }
315
316 mutex_->lock();
317 }
318
~ClientMutexLocker()319 ImageFrameGenerator::ClientMutexLocker::~ClientMutexLocker() {
320 mutex_->unlock();
321
322 MutexLocker lock(generator_->generator_mutex_);
323 auto it = generator_->mutex_map_.find(client_id_);
324 DCHECK(it != generator_->mutex_map_.end());
325 it->value->ref_count--;
326
327 if (it->value->ref_count == 0)
328 generator_->mutex_map_.erase(it);
329 }
330
331 } // namespace blink
332