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