1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h"
6
7 #include <stdint.h>
8
9 #include <cstring>
10 #include <memory>
11
12 #include "base/bits.h"
13 #include "base/containers/adapters.h"
14 #include "base/feature_list.h"
15 #include "base/logging.h"
16 #include "base/memory/scoped_refptr.h"
17 #include "base/numerics/safe_conversions.h"
18 #include "base/optional.h"
19 #include "base/timer/elapsed_timer.h"
20 #include "build/build_config.h"
21 #include "cc/base/math_util.h"
22 #include "media/base/video_color_space.h"
23 #include "media/base/video_frame.h"
24 #include "media/renderers/paint_canvas_video_renderer.h"
25 #include "media/video/half_float_maker.h"
26 #include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
27 #include "third_party/blink/renderer/platform/image-decoders/image_animation.h"
28 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
29 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
30 #include "third_party/libavif/src/include/avif/avif.h"
31 #include "third_party/libyuv/include/libyuv.h"
32 #include "third_party/skia/include/core/SkData.h"
33 #include "ui/gfx/color_space.h"
34 #include "ui/gfx/color_transform.h"
35 #include "ui/gfx/half_float.h"
36 #include "ui/gfx/icc_profile.h"
37
38 #if defined(ARCH_CPU_BIG_ENDIAN)
39 #error Blink assumes a little-endian target.
40 #endif
41
42 namespace {
43
44 // Builds a gfx::ColorSpace from the ITU-T H.273 (CICP) color description in the
45 // image. This color space is used to create the gfx::ColorTransform for the
46 // YUV-to-RGB conversion. If the image does not have an ICC profile, this color
47 // space is also used to create the embedded color profile.
GetColorSpace(const avifImage * image)48 gfx::ColorSpace GetColorSpace(const avifImage* image) {
49 // (As of ISO/IEC 23000-22:2019 Amendment 2) MIAF Section 7.3.6.4 says:
50 // If a coded image has no associated colour property, the default property
51 // is defined as having colour_type equal to 'nclx' with properties as
52 // follows:
53 // – colour_primaries equal to 1,
54 // - transfer_characteristics equal to 13,
55 // - matrix_coefficients equal to 5 or 6 (which are functionally identical),
56 // and
57 // - full_range_flag equal to 1.
58 // ...
59 // These values correspond to AVIF_COLOR_PRIMARIES_BT709,
60 // AVIF_TRANSFER_CHARACTERISTICS_SRGB, and AVIF_MATRIX_COEFFICIENTS_BT601,
61 // respectively.
62 //
63 // Note that this only specifies the default color property when the color
64 // property is absent. It does not really specify the default values for
65 // colour_primaries, transfer_characteristics, and matrix_coefficients when
66 // they are equal to 2 (unspecified). But we will interpret it as specifying
67 // the default values for these variables because we must choose some defaults
68 // and these are the most reasonable defaults to choose. We also advocate that
69 // all AVIF decoders choose these defaults:
70 // https://github.com/AOMediaCodec/av1-avif/issues/84
71 const auto primaries =
72 image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED
73 ? AVIF_COLOR_PRIMARIES_BT709
74 : image->colorPrimaries;
75 const auto transfer = image->transferCharacteristics ==
76 AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED
77 ? AVIF_TRANSFER_CHARACTERISTICS_SRGB
78 : image->transferCharacteristics;
79 const auto matrix =
80 image->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED
81 ? AVIF_MATRIX_COEFFICIENTS_BT601
82 : image->matrixCoefficients;
83 const auto range = image->yuvRange == AVIF_RANGE_FULL
84 ? gfx::ColorSpace::RangeID::FULL
85 : gfx::ColorSpace::RangeID::LIMITED;
86 media::VideoColorSpace color_space(primaries, transfer, matrix, range);
87 if (color_space.IsSpecified())
88 return color_space.ToGfxColorSpace();
89 // media::VideoColorSpace and gfx::ColorSpace do not support CICP
90 // MatrixCoefficients 12, 13, 14.
91 DCHECK_GE(matrix, 12);
92 DCHECK_LE(matrix, 14);
93 if (image->yuvRange == AVIF_RANGE_FULL)
94 return gfx::ColorSpace::CreateJpeg();
95 return gfx::ColorSpace::CreateREC709();
96 }
97
98 // Returns whether media::PaintCanvasVideoRenderer (PCVR) can convert the YUV
99 // color space of |image| to RGB.
100 // media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels() uses libyuv
101 // for the YUV-to-RGB conversion.
102 //
103 // NOTE: Ideally, this function should be a static method of
104 // media::PaintCanvasVideoRenderer. We did not do that because
105 // media::PaintCanvasVideoRenderer uses the JPEG matrix coefficients for all
106 // full-range YUV color spaces, but we want to use the JPEG matrix coefficients
107 // only for full-range BT.601 YUV.
IsColorSpaceSupportedByPCVR(const avifImage * image)108 bool IsColorSpaceSupportedByPCVR(const avifImage* image) {
109 SkYUVColorSpace yuv_color_space;
110 if (!GetColorSpace(image).ToSkYUVColorSpace(image->depth, &yuv_color_space))
111 return false;
112 const bool color_space_is_supported =
113 yuv_color_space == kJPEG_Full_SkYUVColorSpace ||
114 yuv_color_space == kRec601_Limited_SkYUVColorSpace ||
115 yuv_color_space == kRec709_Limited_SkYUVColorSpace ||
116 yuv_color_space == kBT2020_8bit_Limited_SkYUVColorSpace;
117 // libyuv supports the alpha channel only with the I420 pixel format, which is
118 // 8-bit YUV 4:2:0.
119 return color_space_is_supported &&
120 (!image->alphaPlane ||
121 (image->depth == 8 && image->yuvFormat == AVIF_PIXEL_FORMAT_YUV420 &&
122 image->alphaRange == AVIF_RANGE_FULL));
123 }
124
AvifToVideoPixelFormat(avifPixelFormat fmt,int depth)125 media::VideoPixelFormat AvifToVideoPixelFormat(avifPixelFormat fmt, int depth) {
126 if (depth != 8 && depth != 10 && depth != 12) {
127 // Unsupported bit depth.
128 NOTREACHED();
129 return media::PIXEL_FORMAT_UNKNOWN;
130 }
131 int index = (depth - 8) / 2;
132 static constexpr media::VideoPixelFormat kYUV420Formats[] = {
133 media::PIXEL_FORMAT_I420, media::PIXEL_FORMAT_YUV420P10,
134 media::PIXEL_FORMAT_YUV420P12};
135 static constexpr media::VideoPixelFormat kYUV422Formats[] = {
136 media::PIXEL_FORMAT_I422, media::PIXEL_FORMAT_YUV422P10,
137 media::PIXEL_FORMAT_YUV422P12};
138 static constexpr media::VideoPixelFormat kYUV444Formats[] = {
139 media::PIXEL_FORMAT_I444, media::PIXEL_FORMAT_YUV444P10,
140 media::PIXEL_FORMAT_YUV444P12};
141 switch (fmt) {
142 case AVIF_PIXEL_FORMAT_YUV420:
143 case AVIF_PIXEL_FORMAT_YUV400:
144 return kYUV420Formats[index];
145 case AVIF_PIXEL_FORMAT_YUV422:
146 return kYUV422Formats[index];
147 case AVIF_PIXEL_FORMAT_YUV444:
148 return kYUV444Formats[index];
149 case AVIF_PIXEL_FORMAT_NONE:
150 NOTREACHED();
151 return media::PIXEL_FORMAT_UNKNOWN;
152 }
153 }
154
155 // |y_size| is the width or height of the Y plane. Returns the width or height
156 // of the U and V planes. |chroma_shift| represents the subsampling of the
157 // chroma (U and V) planes in the x (for width) or y (for height) direction.
UVSize(int y_size,int chroma_shift)158 int UVSize(int y_size, int chroma_shift) {
159 DCHECK(chroma_shift == 0 || chroma_shift == 1);
160 return (y_size + chroma_shift) >> chroma_shift;
161 }
162
WritePixel(float max_channel,const gfx::Point3F & pixel,float alpha,bool premultiply_alpha,uint32_t * rgba_dest)163 inline void WritePixel(float max_channel,
164 const gfx::Point3F& pixel,
165 float alpha,
166 bool premultiply_alpha,
167 uint32_t* rgba_dest) {
168 uint8_t r = base::ClampRound<uint8_t>(pixel.x() * 255.0f);
169 uint8_t g = base::ClampRound<uint8_t>(pixel.y() * 255.0f);
170 uint8_t b = base::ClampRound<uint8_t>(pixel.z() * 255.0f);
171 uint8_t a = base::ClampRound<uint8_t>(alpha * 255.0f);
172 if (premultiply_alpha)
173 blink::ImageFrame::SetRGBAPremultiply(rgba_dest, r, g, b, a);
174 else
175 *rgba_dest = SkPackARGB32NoCheck(a, r, g, b);
176 }
177
WritePixel(float max_channel,const gfx::Point3F & pixel,float alpha,bool premultiply_alpha,uint64_t * rgba_dest)178 inline void WritePixel(float max_channel,
179 const gfx::Point3F& pixel,
180 float alpha,
181 bool premultiply_alpha,
182 uint64_t* rgba_dest) {
183 float rgba_pixels[4];
184 rgba_pixels[0] = pixel.x();
185 rgba_pixels[1] = pixel.y();
186 rgba_pixels[2] = pixel.z();
187 rgba_pixels[3] = alpha;
188 if (premultiply_alpha && alpha != 1.0f) {
189 rgba_pixels[0] *= alpha;
190 rgba_pixels[1] *= alpha;
191 rgba_pixels[2] *= alpha;
192 }
193
194 gfx::FloatToHalfFloat(rgba_pixels, reinterpret_cast<uint16_t*>(rgba_dest),
195 base::size(rgba_pixels));
196 }
197
198 enum class ColorType { kMono, kColor };
199
200 template <ColorType color_type, typename InputType, typename OutputType>
YUVAToRGBA(const avifImage * image,const gfx::ColorTransform * transform,bool premultiply_alpha,OutputType * rgba_dest)201 void YUVAToRGBA(const avifImage* image,
202 const gfx::ColorTransform* transform,
203 bool premultiply_alpha,
204 OutputType* rgba_dest) {
205 avifPixelFormatInfo format_info;
206 avifGetPixelFormatInfo(image->yuvFormat, &format_info);
207 gfx::Point3F pixel;
208 const int max_channel_i = (1 << image->depth) - 1;
209 const float max_channel = float{max_channel_i};
210 for (uint32_t j = 0; j < image->height; ++j) {
211 const int uv_j = j >> format_info.chromaShiftY;
212
213 const InputType* y_ptr = reinterpret_cast<InputType*>(
214 &image->yuvPlanes[AVIF_CHAN_Y][j * image->yuvRowBytes[AVIF_CHAN_Y]]);
215 const InputType* u_ptr = reinterpret_cast<InputType*>(
216 &image->yuvPlanes[AVIF_CHAN_U][uv_j * image->yuvRowBytes[AVIF_CHAN_U]]);
217 const InputType* v_ptr = reinterpret_cast<InputType*>(
218 &image->yuvPlanes[AVIF_CHAN_V][uv_j * image->yuvRowBytes[AVIF_CHAN_V]]);
219 const InputType* a_ptr = nullptr;
220 if (image->alphaPlane) {
221 a_ptr = reinterpret_cast<InputType*>(
222 &image->alphaPlane[j * image->alphaRowBytes]);
223 }
224
225 for (uint32_t i = 0; i < image->width; ++i) {
226 const int uv_i = i >> format_info.chromaShiftX;
227 pixel.set_x(y_ptr[i] / max_channel);
228 if (color_type == ColorType::kColor) {
229 pixel.set_y(u_ptr[uv_i] / max_channel);
230 pixel.set_z(v_ptr[uv_i] / max_channel);
231 } else {
232 pixel.set_y(0.5f);
233 pixel.set_z(0.5f);
234 }
235
236 transform->Transform(&pixel, 1);
237
238 int alpha = max_channel_i;
239 // TODO(wtc): Use templates or other ways to avoid checking whether the
240 // image supports alpha and whether alpha is limited range in the inner
241 // loop.
242 if (a_ptr) {
243 alpha = a_ptr[i];
244 if (image->alphaRange == AVIF_RANGE_LIMITED)
245 alpha = avifLimitedToFullY(image->depth, alpha);
246 }
247
248 WritePixel(max_channel, pixel, alpha / max_channel, premultiply_alpha,
249 rgba_dest);
250 rgba_dest++;
251 }
252 }
253 }
254
255 } // namespace
256
257 namespace blink {
258
AVIFImageDecoder(AlphaOption alpha_option,HighBitDepthDecodingOption hbd_option,const ColorBehavior & color_behavior,size_t max_decoded_bytes,AnimationOption animation_option)259 AVIFImageDecoder::AVIFImageDecoder(AlphaOption alpha_option,
260 HighBitDepthDecodingOption hbd_option,
261 const ColorBehavior& color_behavior,
262 size_t max_decoded_bytes,
263 AnimationOption animation_option)
264 : ImageDecoder(alpha_option, hbd_option, color_behavior, max_decoded_bytes),
265 animation_option_(animation_option) {}
266
267 AVIFImageDecoder::~AVIFImageDecoder() = default;
268
ImageIsHighBitDepth()269 bool AVIFImageDecoder::ImageIsHighBitDepth() {
270 return bit_depth_ > 8;
271 }
272
OnSetData(SegmentReader * data)273 void AVIFImageDecoder::OnSetData(SegmentReader* data) {
274 // avifDecoder requires all the data be available before reading and cannot
275 // read incrementally as data comes in. See
276 // https://github.com/AOMediaCodec/libavif/issues/11.
277 if (IsAllDataReceived() && !MaybeCreateDemuxer())
278 SetFailed();
279 }
280
GetYUVSubsampling() const281 cc::YUVSubsampling AVIFImageDecoder::GetYUVSubsampling() const {
282 switch (decoder_->image->yuvFormat) {
283 case AVIF_PIXEL_FORMAT_YUV420:
284 return cc::YUVSubsampling::k420;
285 case AVIF_PIXEL_FORMAT_YUV422:
286 return cc::YUVSubsampling::k422;
287 case AVIF_PIXEL_FORMAT_YUV444:
288 return cc::YUVSubsampling::k444;
289 case AVIF_PIXEL_FORMAT_YUV400:
290 return cc::YUVSubsampling::kUnknown;
291 case AVIF_PIXEL_FORMAT_NONE:
292 NOTREACHED();
293 return cc::YUVSubsampling::kUnknown;
294 }
295 }
296
DecodedYUVSize(cc::YUVIndex index) const297 IntSize AVIFImageDecoder::DecodedYUVSize(cc::YUVIndex index) const {
298 DCHECK(IsDecodedSizeAvailable());
299 if (index == cc::YUVIndex::kU || index == cc::YUVIndex::kV) {
300 return IntSize(UVSize(Size().Width(), chroma_shift_x_),
301 UVSize(Size().Height(), chroma_shift_y_));
302 }
303 return Size();
304 }
305
DecodedYUVWidthBytes(cc::YUVIndex index) const306 size_t AVIFImageDecoder::DecodedYUVWidthBytes(cc::YUVIndex index) const {
307 DCHECK(IsDecodedSizeAvailable());
308 // Try to return the same width bytes as used by the dav1d library. This will
309 // allow DecodeToYUV() to copy each plane with a single memcpy() call.
310 //
311 // The comments for Dav1dPicAllocator in dav1d/picture.h require the pixel
312 // width be padded to a multiple of 128 pixels.
313 int aligned_width = base::bits::Align(Size().Width(), 128);
314 if (index == cc::YUVIndex::kU || index == cc::YUVIndex::kV) {
315 aligned_width >>= chroma_shift_x_;
316 }
317 // When the stride is a multiple of 1024, dav1d_default_picture_alloc()
318 // slightly pads the stride to avoid a reduction in cache hit rate in most
319 // L1/L2 cache implementations. Match that trick here. (Note that this padding
320 // is not documented in dav1d/picture.h.)
321 if ((aligned_width & 1023) == 0)
322 aligned_width += 64;
323
324 // High bit depth YUV is stored as a uint16_t, double the number of bytes.
325 if (bit_depth_ > 8) {
326 DCHECK_LE(bit_depth_, 16);
327 aligned_width *= 2;
328 }
329
330 return aligned_width;
331 }
332
GetYUVColorSpace() const333 SkYUVColorSpace AVIFImageDecoder::GetYUVColorSpace() const {
334 DCHECK(CanDecodeToYUV());
335 DCHECK_NE(yuv_color_space_, SkYUVColorSpace::kIdentity_SkYUVColorSpace);
336 return yuv_color_space_;
337 }
338
GetYUVBitDepth() const339 uint8_t AVIFImageDecoder::GetYUVBitDepth() const {
340 DCHECK(CanDecodeToYUV());
341 return bit_depth_;
342 }
343
DecodeToYUV()344 void AVIFImageDecoder::DecodeToYUV() {
345 DCHECK(image_planes_);
346 DCHECK(CanDecodeToYUV());
347 DCHECK(IsAllDataReceived());
348
349 if (Failed())
350 return;
351
352 DCHECK(decoder_);
353 DCHECK_EQ(decoded_frame_count_, 1u); // Not animation.
354
355 // libavif cannot decode to an external buffer. So we need to copy from
356 // libavif's internal buffer to |image_planes_|.
357 // TODO(crbug.com/1099825): Enhance libavif to decode to an external buffer.
358 if (!DecodeImage(0)) {
359 SetFailed();
360 return;
361 }
362
363 const auto* image = decoder_->image;
364 // Frame size must be equal to container size.
365 if (Size() != IntSize(image->width, image->height)) {
366 DVLOG(1) << "Frame size " << IntSize(image->width, image->height)
367 << " differs from container size " << Size();
368 SetFailed();
369 return;
370 }
371 // Frame bit depth must be equal to container bit depth.
372 if (image->depth != bit_depth_) {
373 DVLOG(1) << "Frame bit depth must be equal to container bit depth";
374 SetFailed();
375 return;
376 }
377 // Frame YUV format must be equal to container YUV format.
378 if (image->yuvFormat != avif_yuv_format_) {
379 DVLOG(1) << "Frame YUV format must be equal to container YUV format";
380 SetFailed();
381 return;
382 }
383 DCHECK(!image->alphaPlane);
384 static_assert(cc::YUVIndex::kY == static_cast<cc::YUVIndex>(AVIF_CHAN_Y), "");
385 static_assert(cc::YUVIndex::kU == static_cast<cc::YUVIndex>(AVIF_CHAN_U), "");
386 static_assert(cc::YUVIndex::kV == static_cast<cc::YUVIndex>(AVIF_CHAN_V), "");
387
388 // Disable subnormal floats which can occur when converting to half float.
389 std::unique_ptr<cc::ScopedSubnormalFloatDisabler> disable_subnormals;
390 const bool is_f16 = image_planes_->color_type() == kA16_float_SkColorType;
391 if (is_f16)
392 disable_subnormals = std::make_unique<cc::ScopedSubnormalFloatDisabler>();
393 const float kHighBitDepthMultiplier =
394 (is_f16 ? 1.0f : 65535.0f) / ((1 << bit_depth_) - 1);
395
396 // Initialize |width| and |height| to the width and height of the luma plane.
397 uint32_t width = image->width;
398 uint32_t height = image->height;
399
400 // |height| comes from the AV1 sequence header or frame header, which encodes
401 // max_frame_height_minus_1 and frame_height_minus_1, respectively, as n-bit
402 // unsigned integers for some n.
403 DCHECK_GT(height, 0u);
404 for (size_t plane_index = 0; plane_index < cc::kNumYUVPlanes; ++plane_index) {
405 const cc::YUVIndex plane = static_cast<cc::YUVIndex>(plane_index);
406 const size_t src_row_bytes =
407 base::strict_cast<size_t>(image->yuvRowBytes[plane_index]);
408 const size_t dst_row_bytes = image_planes_->RowBytes(plane);
409
410 if (bit_depth_ == 8) {
411 DCHECK_EQ(image_planes_->color_type(), kGray_8_SkColorType);
412 const uint8_t* src = image->yuvPlanes[plane_index];
413 uint8_t* dst = static_cast<uint8_t*>(image_planes_->Plane(plane));
414 libyuv::CopyPlane(src, src_row_bytes, dst, dst_row_bytes, width, height);
415 } else {
416 DCHECK_GT(bit_depth_, 8u);
417 DCHECK_LE(bit_depth_, 16u);
418 const uint16_t* src =
419 reinterpret_cast<uint16_t*>(image->yuvPlanes[plane_index]);
420 uint16_t* dst = static_cast<uint16_t*>(image_planes_->Plane(plane));
421 if (image_planes_->color_type() == kA16_unorm_SkColorType) {
422 const size_t src_stride = src_row_bytes / 2;
423 const size_t dst_stride = dst_row_bytes / 2;
424 for (uint32_t j = 0; j < height; ++j) {
425 for (uint32_t i = 0; i < width; ++i) {
426 dst[j * dst_stride + i] =
427 src[j * src_stride + i] * kHighBitDepthMultiplier + 0.5f;
428 }
429 }
430 } else if (image_planes_->color_type() == kA16_float_SkColorType) {
431 // Note: Unlike CopyPlane_16, HalfFloatPlane wants the stride in bytes.
432 libyuv::HalfFloatPlane(src, src_row_bytes, dst, dst_row_bytes,
433 kHighBitDepthMultiplier, width, height);
434 } else {
435 NOTREACHED() << "Unsupported color type: "
436 << static_cast<int>(image_planes_->color_type());
437 }
438 }
439 if (plane == cc::YUVIndex::kY) {
440 // Having processed the luma plane, change |width| and |height| to the
441 // width and height of the chroma planes.
442 width = UVSize(width, chroma_shift_x_);
443 height = UVSize(height, chroma_shift_y_);
444 }
445 }
446 }
447
RepetitionCount() const448 int AVIFImageDecoder::RepetitionCount() const {
449 return decoded_frame_count_ > 1 ? kAnimationLoopInfinite : kAnimationNone;
450 }
451
FrameDurationAtIndex(size_t index) const452 base::TimeDelta AVIFImageDecoder::FrameDurationAtIndex(size_t index) const {
453 return index < frame_buffer_cache_.size()
454 ? frame_buffer_cache_[index].Duration()
455 : base::TimeDelta();
456 }
457
ImageHasBothStillAndAnimatedSubImages() const458 bool AVIFImageDecoder::ImageHasBothStillAndAnimatedSubImages() const {
459 // Per MIAF, all animated AVIF files must have a still image, even if it's
460 // just a pointer to the first frame of the animation.
461 if (decoded_frame_count_ > 1)
462 return true;
463
464 // TODO(wtc): We should rely on libavif to tell us if the file has both an
465 // image and an animation track instead of just checking the major brand.
466 //
467 // An AVIF image begins with a file‐type box 'ftyp':
468 // unsigned int(32) size;
469 // unsigned int(32) type = boxtype; // boxtype is 'ftyp'
470 // unsigned int(32) major_brand;
471 // ...
472 FastSharedBufferReader fast_reader(data_);
473 char buf[4];
474 const char* major_brand = fast_reader.GetConsecutiveData(8, 4, buf);
475 // The brand 'avis' is an AVIF image sequence (animation) brand.
476 return memcmp(major_brand, "avis", 4) == 0;
477 }
478
479 // static
MatchesAVIFSignature(const FastSharedBufferReader & fast_reader)480 bool AVIFImageDecoder::MatchesAVIFSignature(
481 const FastSharedBufferReader& fast_reader) {
482 // avifPeekCompatibleFileType() clamps compatible brands at 32 when reading in
483 // the ftyp box in ISO BMFF for the 'avif' or 'avis' brand. So the maximum
484 // number of bytes read is 144 bytes (size 4 bytes, type 4 bytes, major brand
485 // 4 bytes, minor version 4 bytes, and 4 bytes * 32 compatible brands).
486 char buffer[144];
487 avifROData input;
488 input.size = std::min(sizeof(buffer), fast_reader.size());
489 input.data = reinterpret_cast<const uint8_t*>(
490 fast_reader.GetConsecutiveData(0, input.size, buffer));
491 return avifPeekCompatibleFileType(&input);
492 }
493
GetColorTransformForTesting()494 gfx::ColorTransform* AVIFImageDecoder::GetColorTransformForTesting() {
495 UpdateColorTransform(GetColorSpace(decoder_->image), decoder_->image->depth);
496 return color_transform_.get();
497 }
498
DecodeSize()499 void AVIFImageDecoder::DecodeSize() {
500 // Because avifDecoder cannot read incrementally as data comes in, we cannot
501 // decode the size until all data is received. When all data is received,
502 // OnSetData() decodes the size right away. So DecodeSize() doesn't need to do
503 // anything.
504 }
505
DecodeFrameCount()506 size_t AVIFImageDecoder::DecodeFrameCount() {
507 return Failed() ? frame_buffer_cache_.size() : decoded_frame_count_;
508 }
509
InitializeNewFrame(size_t index)510 void AVIFImageDecoder::InitializeNewFrame(size_t index) {
511 auto& buffer = frame_buffer_cache_[index];
512 if (decode_to_half_float_)
513 buffer.SetPixelFormat(ImageFrame::PixelFormat::kRGBA_F16);
514
515 // For AVIFs, the frame always fills the entire image.
516 buffer.SetOriginalFrameRect(IntRect(IntPoint(), Size()));
517
518 avifImageTiming timing;
519 auto ret = avifDecoderNthImageTiming(decoder_.get(), index, &timing);
520 DCHECK_EQ(ret, AVIF_RESULT_OK);
521 buffer.SetDuration(base::TimeDelta::FromSecondsD(timing.duration));
522 }
523
Decode(size_t index)524 void AVIFImageDecoder::Decode(size_t index) {
525 // TODO(dalecurtis): For fragmented AVIF image sequence files we probably want
526 // to allow partial decoding. Depends on if we see frequent use of multi-track
527 // images where there's lots to ignore.
528 if (Failed() || !IsAllDataReceived())
529 return;
530
531 UpdateAggressivePurging(index);
532
533 if (!DecodeImage(index)) {
534 SetFailed();
535 return;
536 }
537
538 const auto* image = decoder_->image;
539 // Frame size must be equal to container size.
540 if (Size() != IntSize(image->width, image->height)) {
541 DVLOG(1) << "Frame size " << IntSize(image->width, image->height)
542 << " differs from container size " << Size();
543 SetFailed();
544 return;
545 }
546 // Frame bit depth must be equal to container bit depth.
547 if (image->depth != bit_depth_) {
548 DVLOG(1) << "Frame bit depth must be equal to container bit depth";
549 SetFailed();
550 return;
551 }
552 // Frame YUV format must be equal to container YUV format.
553 if (image->yuvFormat != avif_yuv_format_) {
554 DVLOG(1) << "Frame YUV format must be equal to container YUV format";
555 SetFailed();
556 return;
557 }
558
559 ImageFrame& buffer = frame_buffer_cache_[index];
560 DCHECK_EQ(buffer.GetStatus(), ImageFrame::kFrameEmpty);
561
562 if (!InitFrameBuffer(index)) {
563 DVLOG(1) << "Failed to create frame buffer...";
564 SetFailed();
565 return;
566 }
567
568 if (!RenderImage(image, &buffer)) {
569 SetFailed();
570 return;
571 }
572
573 ColorCorrectImage(&buffer);
574
575 buffer.SetPixelsChanged(true);
576 buffer.SetHasAlpha(!!image->alphaPlane);
577 buffer.SetStatus(ImageFrame::kFrameComplete);
578 }
579
CanReusePreviousFrameBuffer(size_t index) const580 bool AVIFImageDecoder::CanReusePreviousFrameBuffer(size_t index) const {
581 // (a) Technically we can reuse the bitmap of the previous frame because the
582 // AVIF decoder handles frame dependence internally and we never need to
583 // preserve previous frames to decode later ones, and (b) since this function
584 // will not currently be called, this is really more for the reader than any
585 // functional purpose.
586 return true;
587 }
588
MaybeCreateDemuxer()589 bool AVIFImageDecoder::MaybeCreateDemuxer() {
590 if (decoder_)
591 return true;
592
593 decoder_ = std::unique_ptr<avifDecoder, void (*)(avifDecoder*)>(
594 avifDecoderCreate(), avifDecoderDestroy);
595 if (!decoder_)
596 return false;
597
598 // TODO(dalecurtis): This may create a second copy of the media data in
599 // memory, which is not great. libavif should provide a read() based API:
600 // https://github.com/AOMediaCodec/libavif/issues/11
601 image_data_ = data_->GetAsSkData();
602 if (!image_data_)
603 return false;
604
605 // TODO(wtc): Currently libavif always prioritizes the animation, but that's
606 // not correct. It should instead select animation or still image based on the
607 // preferred and major brands listed in the file.
608 if (animation_option_ != AnimationOption::kUnspecified &&
609 avifDecoderSetSource(
610 decoder_.get(), animation_option_ == AnimationOption::kPreferAnimation
611 ? AVIF_DECODER_SOURCE_TRACKS
612 : AVIF_DECODER_SOURCE_PRIMARY_ITEM) !=
613 AVIF_RESULT_OK) {
614 return false;
615 }
616
617 // Chrome doesn't use XMP and Exif metadata. Ignoring XMP and Exif will ensure
618 // avifDecoderParse() isn't waiting for some tiny Exif payload hiding at the
619 // end of a file.
620 decoder_->ignoreXMP = AVIF_TRUE;
621 decoder_->ignoreExif = AVIF_TRUE;
622 auto ret = avifDecoderSetIOMemory(decoder_.get(), image_data_->bytes(),
623 image_data_->size());
624 if (ret != AVIF_RESULT_OK) {
625 DVLOG(1) << "avifDecoderSetIOMemory failed: " << avifResultToString(ret);
626 return false;
627 }
628 ret = avifDecoderParse(decoder_.get());
629 if (ret != AVIF_RESULT_OK) {
630 DVLOG(1) << "avifDecoderParse failed: " << avifResultToString(ret);
631 return false;
632 }
633
634 // Image metadata is available in decoder_->image after avifDecoderParse()
635 // even though decoder_->imageIndex is invalid (-1).
636 DCHECK_EQ(decoder_->imageIndex, -1);
637 // This variable is named |container| to emphasize the fact that the current
638 // contents of decoder_->image come from the container, not any frame.
639 const auto* container = decoder_->image;
640
641 // The container width and container height are read from either the tkhd
642 // (track header) box of a track or the ispe (image spatial extents) property
643 // of an image item, both of which are mandatory in the spec.
644 if (container->width == 0 || container->height == 0) {
645 DVLOG(1) << "Container width and height must be present";
646 return false;
647 }
648
649 // The container depth is read from either the av1C box of a track or the av1C
650 // property of an image item, both of which are mandatory in the spec.
651 if (container->depth == 0) {
652 DVLOG(1) << "Container depth must be present";
653 return false;
654 }
655
656 DCHECK_GT(decoder_->imageCount, 0);
657 decoded_frame_count_ = decoder_->imageCount;
658 bit_depth_ = container->depth;
659 decode_to_half_float_ =
660 ImageIsHighBitDepth() &&
661 high_bit_depth_decoding_option_ == kHighBitDepthToHalfFloat;
662
663 avif_yuv_format_ = container->yuvFormat;
664 avifPixelFormatInfo format_info;
665 avifGetPixelFormatInfo(container->yuvFormat, &format_info);
666 chroma_shift_x_ = format_info.chromaShiftX;
667 chroma_shift_y_ = format_info.chromaShiftY;
668
669 // SetEmbeddedColorProfile() must be called before IsSizeAvailable() becomes
670 // true. So call SetEmbeddedColorProfile() before calling SetSize(). The color
671 // profile is either an ICC profile or the CICP color description.
672
673 if (!IgnoresColorSpace()) {
674 // The CICP color description is always present because we can always get it
675 // from the AV1 sequence header for the frames. If an ICC profile is
676 // present, use it instead of the CICP color description.
677 if (container->icc.size) {
678 std::unique_ptr<ColorProfile> profile =
679 ColorProfile::Create(container->icc.data, container->icc.size);
680 if (!profile) {
681 DVLOG(1) << "Failed to parse image ICC profile";
682 return false;
683 }
684 uint32_t data_color_space = profile->GetProfile()->data_color_space;
685 const bool is_mono = container->yuvFormat == AVIF_PIXEL_FORMAT_YUV400;
686 if (is_mono) {
687 if (data_color_space != skcms_Signature_Gray &&
688 data_color_space != skcms_Signature_RGB)
689 profile = nullptr;
690 } else {
691 if (data_color_space != skcms_Signature_RGB)
692 profile = nullptr;
693 }
694 if (!profile) {
695 DVLOG(1)
696 << "Image contains ICC profile that does not match its color space";
697 return false;
698 }
699 SetEmbeddedColorProfile(std::move(profile));
700 } else if (container->colorPrimaries != AVIF_COLOR_PRIMARIES_UNSPECIFIED ||
701 container->transferCharacteristics !=
702 AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED) {
703 gfx::ColorSpace frame_cs = GetColorSpace(container);
704 sk_sp<SkColorSpace> sk_color_space =
705 frame_cs.GetAsFullRangeRGB().ToSkColorSpace();
706 skcms_ICCProfile profile;
707 sk_color_space->toProfile(&profile);
708 SetEmbeddedColorProfile(std::make_unique<ColorProfile>(profile));
709 }
710 }
711
712 // Determine whether the image can be decoded to YUV.
713 // * Alpha channel is not supported.
714 // * Multi-frame images (animations) are not supported. (The DecodeToYUV()
715 // method does not have an 'index' parameter.)
716 // * If ColorTransform() returns a non-null pointer, the decoder has to do a
717 // color space conversion, so we don't decode to YUV.
718 allow_decode_to_yuv_ = avif_yuv_format_ != AVIF_PIXEL_FORMAT_YUV400 &&
719 !decoder_->alphaPresent && decoded_frame_count_ == 1 &&
720 GetColorSpace(container).ToSkYUVColorSpace(
721 container->depth, &yuv_color_space_) &&
722 !ColorTransform();
723 return SetSize(container->width, container->height);
724 }
725
DecodeImage(size_t index)726 bool AVIFImageDecoder::DecodeImage(size_t index) {
727 const auto ret = avifDecoderNthImage(decoder_.get(), index);
728 // |index| should be less than what DecodeFrameCount() returns, so we should
729 // not get the AVIF_RESULT_NO_IMAGES_REMAINING error.
730 DCHECK_NE(ret, AVIF_RESULT_NO_IMAGES_REMAINING);
731 return ret == AVIF_RESULT_OK;
732 }
733
UpdateColorTransform(const gfx::ColorSpace & frame_cs,int bit_depth)734 void AVIFImageDecoder::UpdateColorTransform(const gfx::ColorSpace& frame_cs,
735 int bit_depth) {
736 if (color_transform_ && color_transform_->GetSrcColorSpace() == frame_cs)
737 return;
738
739 // For YUV-to-RGB color conversion we can pass an invalid dst color space to
740 // skip the code for full color conversion.
741 color_transform_ = gfx::ColorTransform::NewColorTransform(
742 frame_cs, bit_depth, gfx::ColorSpace(), bit_depth,
743 gfx::ColorTransform::Intent::INTENT_PERCEPTUAL);
744 }
745
RenderImage(const avifImage * image,ImageFrame * buffer)746 bool AVIFImageDecoder::RenderImage(const avifImage* image, ImageFrame* buffer) {
747 const gfx::ColorSpace frame_cs = GetColorSpace(image);
748 const bool is_mono = image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400;
749 const bool premultiply_alpha = buffer->PremultiplyAlpha();
750
751 if (decode_to_half_float_) {
752 UpdateColorTransform(frame_cs, image->depth);
753
754 uint64_t* rgba_hhhh = buffer->GetAddrF16(0, 0);
755
756 // Color and format convert from YUV HBD -> RGBA half float.
757 if (is_mono) {
758 YUVAToRGBA<ColorType::kMono, uint16_t>(image, color_transform_.get(),
759 premultiply_alpha, rgba_hhhh);
760 } else {
761 // TODO(crbug.com/1099820): Add fast path for 10bit 4:2:0 using libyuv.
762 YUVAToRGBA<ColorType::kColor, uint16_t>(image, color_transform_.get(),
763 premultiply_alpha, rgba_hhhh);
764 }
765 return true;
766 }
767
768 uint32_t* rgba_8888 = buffer->GetAddr(0, 0);
769 // Call media::PaintCanvasVideoRenderer (PCVR) if the color space is
770 // supported.
771 if (IsColorSpaceSupportedByPCVR(image)) {
772 // Create temporary frame wrapping the YUVA planes.
773 scoped_refptr<media::VideoFrame> frame;
774 auto pixel_format = AvifToVideoPixelFormat(image->yuvFormat, image->depth);
775 if (pixel_format == media::PIXEL_FORMAT_UNKNOWN)
776 return false;
777 auto size = gfx::Size(image->width, image->height);
778 if (image->alphaPlane) {
779 DCHECK_EQ(pixel_format, media::PIXEL_FORMAT_I420);
780 pixel_format = media::PIXEL_FORMAT_I420A;
781 frame = media::VideoFrame::WrapExternalYuvaData(
782 pixel_format, size, gfx::Rect(size), size, image->yuvRowBytes[0],
783 image->yuvRowBytes[1], image->yuvRowBytes[2], image->alphaRowBytes,
784 image->yuvPlanes[0], image->yuvPlanes[1], image->yuvPlanes[2],
785 image->alphaPlane, base::TimeDelta());
786 } else {
787 frame = media::VideoFrame::WrapExternalYuvData(
788 pixel_format, size, gfx::Rect(size), size, image->yuvRowBytes[0],
789 image->yuvRowBytes[1], image->yuvRowBytes[2], image->yuvPlanes[0],
790 image->yuvPlanes[1], image->yuvPlanes[2], base::TimeDelta());
791 }
792 frame->set_color_space(frame_cs);
793
794 // Really only handles 709, 601, 2020, JPEG 8-bit conversions and uses
795 // libyuv under the hood, so is much faster than our manual path.
796 //
797 // Technically has support for 10-bit 4:2:0 and 4:2:2, but not to
798 // half-float and only has support for 4:4:4 and 12-bit by down-shifted
799 // copies.
800 //
801 // https://bugs.chromium.org/p/libyuv/issues/detail?id=845
802 media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
803 frame.get(), rgba_8888, frame->visible_rect().width() * 4,
804 premultiply_alpha);
805 return true;
806 }
807
808 UpdateColorTransform(frame_cs, image->depth);
809 if (ImageIsHighBitDepth()) {
810 if (is_mono) {
811 YUVAToRGBA<ColorType::kMono, uint16_t>(image, color_transform_.get(),
812 premultiply_alpha, rgba_8888);
813 } else {
814 YUVAToRGBA<ColorType::kColor, uint16_t>(image, color_transform_.get(),
815 premultiply_alpha, rgba_8888);
816 }
817 } else {
818 if (is_mono) {
819 YUVAToRGBA<ColorType::kMono, uint8_t>(image, color_transform_.get(),
820 premultiply_alpha, rgba_8888);
821 } else {
822 YUVAToRGBA<ColorType::kColor, uint8_t>(image, color_transform_.get(),
823 premultiply_alpha, rgba_8888);
824 }
825 }
826 return true;
827 }
828
ColorCorrectImage(ImageFrame * buffer)829 void AVIFImageDecoder::ColorCorrectImage(ImageFrame* buffer) {
830 // Postprocess the image data according to the profile.
831 const ColorProfileTransform* const transform = ColorTransform();
832 if (!transform)
833 return;
834 const auto alpha_format = (buffer->HasAlpha() && buffer->PremultiplyAlpha())
835 ? skcms_AlphaFormat_PremulAsEncoded
836 : skcms_AlphaFormat_Unpremul;
837 if (decode_to_half_float_) {
838 const skcms_PixelFormat color_format = skcms_PixelFormat_RGBA_hhhh;
839 for (int y = 0; y < Size().Height(); ++y) {
840 ImageFrame::PixelDataF16* const row = buffer->GetAddrF16(0, y);
841 const bool success = skcms_Transform(
842 row, color_format, alpha_format, transform->SrcProfile(), row,
843 color_format, alpha_format, transform->DstProfile(), Size().Width());
844 DCHECK(success);
845 }
846 } else {
847 const skcms_PixelFormat color_format = XformColorFormat();
848 for (int y = 0; y < Size().Height(); ++y) {
849 ImageFrame::PixelData* const row = buffer->GetAddr(0, y);
850 const bool success = skcms_Transform(
851 row, color_format, alpha_format, transform->SrcProfile(), row,
852 color_format, alpha_format, transform->DstProfile(), Size().Width());
853 DCHECK(success);
854 }
855 }
856 }
857
858 } // namespace blink
859