tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsAVIFDecoder.h (9926B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 *
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_image_decoders_nsAVIFDecoder_h
      8 #define mozilla_image_decoders_nsAVIFDecoder_h
      9 
     10 #include "Decoder.h"
     11 #include "mozilla/gfx/Types.h"
     12 #include "MP4Metadata.h"
     13 #include "mp4parse.h"
     14 #include "SampleIterator.h"
     15 #include "SurfacePipe.h"
     16 
     17 #include <aom/aom_decoder.h>
     18 #include "dav1d/dav1d.h"
     19 
     20 namespace mozilla {
     21 namespace image {
     22 class RasterImage;
     23 class AVIFDecoderStream;
     24 class AVIFParser;
     25 class AVIFDecoderInterface;
     26 
     27 class nsAVIFDecoder final : public Decoder {
     28 public:
     29  virtual ~nsAVIFDecoder();
     30 
     31  DecoderType GetType() const override { return DecoderType::AVIF; }
     32 
     33 protected:
     34  LexerResult DoDecode(SourceBufferIterator& aIterator,
     35                       IResumable* aOnResume) override;
     36  Maybe<glean::impl::MemoryDistributionMetric> SpeedMetric() const override;
     37 
     38 private:
     39  friend class DecoderFactory;
     40  friend class AVIFDecoderInterface;
     41  friend class AVIFParser;
     42 
     43  // Decoders should only be instantiated via DecoderFactory.
     44  explicit nsAVIFDecoder(RasterImage* aImage);
     45 
     46  static intptr_t ReadSource(uint8_t* aDestBuf, uintptr_t aDestBufSize,
     47                             void* aUserData);
     48 
     49  typedef int Dav1dResult;
     50  enum class NonAOMCodecError { NoFrame, SizeOverflow };
     51  typedef Variant<aom_codec_err_t, NonAOMCodecError> AOMResult;
     52  enum class NonDecoderResult {
     53    NeedMoreData,
     54    OutputAvailable,
     55    Complete,
     56    SizeOverflow,
     57    OutOfMemory,
     58    PipeInitError,
     59    WriteBufferError,
     60    AlphaYSizeMismatch,
     61    AlphaYColorDepthMismatch,
     62    MetadataImageSizeMismatch,
     63    RenderSizeMismatch,
     64    FrameSizeChanged,
     65    InvalidCICP,
     66    NoSamples,
     67    ConvertYCbCrFailure,
     68  };
     69  using DecodeResult =
     70      Variant<Mp4parseStatus, NonDecoderResult, Dav1dResult, AOMResult>;
     71  Mp4parseStatus CreateParser();
     72  DecodeResult CreateDecoder();
     73  DecodeResult DoDecodeInternal(SourceBufferIterator& aIterator,
     74                                IResumable* aOnResume);
     75 
     76  static bool IsDecodeSuccess(const DecodeResult& aResult);
     77 
     78  void RecordDecodeResultTelemetry(const DecodeResult& aResult);
     79 
     80  Vector<uint8_t> mBufferedData;
     81  RefPtr<AVIFDecoderStream> mBufferStream;
     82 
     83  /// Pointer to the next place to read from mBufferedData
     84  const uint8_t* mReadCursor = nullptr;
     85 
     86  UniquePtr<AVIFParser> mParser = nullptr;
     87  UniquePtr<AVIFDecoderInterface> mDecoder = nullptr;
     88 
     89  bool mIsAnimated = false;
     90  bool mHasAlpha = false;
     91  bool mUsePipeTransform = true;
     92 };
     93 
     94 class AVIFDecoderStream : public ByteStream {
     95 public:
     96  explicit AVIFDecoderStream(Vector<uint8_t>* aBuffer) { mBuffer = aBuffer; }
     97 
     98  virtual nsresult ReadAt(int64_t offset, void* data, size_t size,
     99                          size_t* bytes_read) override;
    100  virtual nsresult CachedReadAt(int64_t offset, void* data, size_t size,
    101                                size_t* bytes_read) override {
    102    return ReadAt(offset, data, size, bytes_read);
    103  };
    104  virtual bool Length(int64_t* size) override;
    105  virtual const uint8_t* GetContiguousAccess(int64_t aOffset,
    106                                             size_t aSize) override;
    107 
    108 private:
    109  Vector<uint8_t>* mBuffer;
    110 };
    111 
    112 struct AVIFImage {
    113  uint32_t mFrameNum = 0;
    114  FrameTimeout mDuration = FrameTimeout::Zero();
    115  RefPtr<MediaRawData> mColorImage = nullptr;
    116  RefPtr<MediaRawData> mAlphaImage = nullptr;
    117 };
    118 
    119 class AVIFParser {
    120 public:
    121  static Mp4parseStatus Create(const Mp4parseIo* aIo, ByteStream* aBuffer,
    122                               UniquePtr<AVIFParser>& aParserOut,
    123                               bool aAllowSequences, bool aAnimateAVIFMajor);
    124 
    125  ~AVIFParser();
    126 
    127  const Mp4parseAvifInfo& GetInfo() const { return mInfo; }
    128 
    129  uint32_t GetFrameCount();
    130 
    131  nsAVIFDecoder::DecodeResult GetImage(AVIFImage& aImage);
    132 
    133  bool IsAnimated() const;
    134 
    135 private:
    136  explicit AVIFParser(const Mp4parseIo* aIo);
    137 
    138  Mp4parseStatus Init(ByteStream* aBuffer, bool aAllowSequences,
    139                      bool aAnimateAVIFMajor);
    140 
    141  struct FreeAvifParser {
    142    void operator()(Mp4parseAvifParser* aPtr) { mp4parse_avif_free(aPtr); }
    143  };
    144 
    145  const Mp4parseIo* mIo;
    146  UniquePtr<Mp4parseAvifParser, FreeAvifParser> mParser = nullptr;
    147  Mp4parseAvifInfo mInfo = {};
    148 
    149  UniquePtr<SampleIterator> mColorSampleIter = nullptr;
    150  UniquePtr<SampleIterator> mAlphaSampleIter = nullptr;
    151  uint32_t mFrameNum = 0;
    152 };
    153 
    154 struct Dav1dPictureUnref {
    155  void operator()(Dav1dPicture* aPtr) {
    156    dav1d_picture_unref(aPtr);
    157    delete aPtr;
    158  }
    159 };
    160 
    161 using OwnedDav1dPicture = UniquePtr<Dav1dPicture, Dav1dPictureUnref>;
    162 
    163 class OwnedAOMImage {
    164 public:
    165  ~OwnedAOMImage();
    166 
    167  static OwnedAOMImage* CopyFrom(aom_image_t* aImage, bool aIsAlpha);
    168 
    169  aom_image_t* GetImage() { return mImage.isSome() ? mImage.ptr() : nullptr; }
    170 
    171 private:
    172  OwnedAOMImage();
    173 
    174  bool CloneFrom(aom_image_t* aImage, bool aIsAlpha);
    175 
    176  // The mImage's planes are referenced to mBuffer
    177  Maybe<aom_image_t> mImage;
    178  UniquePtr<uint8_t[]> mBuffer;
    179 };
    180 
    181 struct AVIFDecodedData : layers::PlanarYCbCrData {
    182 public:
    183  Maybe<OrientedIntSize> mRenderSize = Nothing();
    184  gfx::CICP::ColourPrimaries mColourPrimaries = gfx::CICP::CP_UNSPECIFIED;
    185  gfx::CICP::TransferCharacteristics mTransferCharacteristics =
    186      gfx::CICP::TC_UNSPECIFIED;
    187  gfx::CICP::MatrixCoefficients mMatrixCoefficients = gfx::CICP::MC_UNSPECIFIED;
    188 
    189  OwnedDav1dPicture mColorDav1d;
    190  OwnedDav1dPicture mAlphaDav1d;
    191  UniquePtr<OwnedAOMImage> mColorAOM;
    192  UniquePtr<OwnedAOMImage> mAlphaAOM;
    193 
    194  // CICP values (either from the BMFF container or the AV1 sequence header) are
    195  // used to create the colorspace transform. CICP::MatrixCoefficients is only
    196  // stored for the sake of telemetry, since the relevant information for YUV ->
    197  // RGB conversion is stored in mYUVColorSpace.
    198  //
    199  // There are three potential sources of color information for an AVIF:
    200  // 1. ICC profile via a ColourInformationBox (colr) defined in [ISOBMFF]
    201  //    § 12.1.5 "Colour information" and [MIAF] § 7.3.6.4 "Colour information
    202  //    property"
    203  // 2. NCLX (AKA CICP see [ITU-T H.273]) values in the same
    204  // ColourInformationBox
    205  //    which can have an ICC profile or NCLX values, not both).
    206  // 3. NCLX values in the AV1 bitstream
    207  //
    208  // The 'colr' box is optional, but there are always CICP values in the AV1
    209  // bitstream, so it is possible to have both. Per ISOBMFF § 12.1.5.1
    210  // > If colour information is supplied in both this box, and also in the
    211  // > video bitstream, this box takes precedence, and over-rides the
    212  // > information in the bitstream.
    213  //
    214  // If present, the ICC profile takes precedence over CICP values, but only
    215  // specifies the color space, not the matrix coefficients necessary to convert
    216  // YCbCr data (as most AVIF are encoded) to RGB. The matrix coefficients are
    217  // always derived from the CICP values for matrix_coefficients (and
    218  // potentially colour_primaries, but in that case only the CICP values for
    219  // colour_primaries will be used, not anything harvested from the ICC
    220  // profile).
    221  //
    222  // If there is no ICC profile, the color space transform will be based on the
    223  // CICP values either from the 'colr' box, or if absent/unspecified, the
    224  // decoded AV1 sequence header.
    225  //
    226  // For values that are 2 (meaning unspecified) after trying both, the
    227  // fallback values are:
    228  // - CP:  1 (BT.709/sRGB)
    229  // - TC: 13 (sRGB)
    230  // - MC:  6 (BT.601)
    231  // - Range: Full
    232  //
    233  // Additional details here:
    234  // <https://github.com/AOMediaCodec/libavif/wiki/CICP#unspecified>. Note
    235  // that this contradicts the current version of [MIAF] § 7.3.6.4 which
    236  // specifies MC=1 (BT.709). This is revised in [MIAF DAMD2] and confirmed by
    237  // <https://github.com/AOMediaCodec/av1-avif/issues/77#issuecomment-676526097>
    238  //
    239  // The precedence for applying the various values and defaults in the event
    240  // no valid values are found are managed by the following functions.
    241  //
    242  // References:
    243  // [ISOBMFF]: ISO/IEC 14496-12:2020 <https://www.iso.org/standard/74428.html>
    244  // [MIAF]: ISO/IEC 23000-22:2019 <https://www.iso.org/standard/74417.html>
    245  // [MIAF DAMD2]: ISO/IEC 23000-22:2019/FDAmd 2
    246  // <https://www.iso.org/standard/81634.html>
    247  // [ITU-T H.273]: Rec. ITU-T H.273 (12/2016)
    248  //     <https://www.itu.int/rec/T-REC-H.273-201612-I/en>
    249  void SetCicpValues(
    250      const Mp4parseNclxColourInformation* aNclx,
    251      const gfx::CICP::ColourPrimaries aAv1ColourPrimaries,
    252      const gfx::CICP::TransferCharacteristics aAv1TransferCharacteristics,
    253      const gfx::CICP::MatrixCoefficients aAv1MatrixCoefficients);
    254 };
    255 
    256 // An interface to do decode and get the decoded data
    257 class AVIFDecoderInterface {
    258 public:
    259  using Dav1dResult = nsAVIFDecoder::Dav1dResult;
    260  using NonAOMCodecError = nsAVIFDecoder::NonAOMCodecError;
    261  using AOMResult = nsAVIFDecoder::AOMResult;
    262  using NonDecoderResult = nsAVIFDecoder::NonDecoderResult;
    263  using DecodeResult = nsAVIFDecoder::DecodeResult;
    264 
    265  virtual ~AVIFDecoderInterface() = default;
    266 
    267  // Set the mDecodedData if Decode() succeeds
    268  virtual DecodeResult Decode(bool aShouldSendTelemetry,
    269                              const Mp4parseAvifInfo& aAVIFInfo,
    270                              const AVIFImage& aSamples) = 0;
    271  // Must be called only once after Decode() succeeds
    272  UniquePtr<AVIFDecodedData> GetDecodedData() {
    273    MOZ_ASSERT(mDecodedData);
    274    return std::move(mDecodedData);
    275  }
    276 
    277 protected:
    278  explicit AVIFDecoderInterface() = default;
    279 
    280  inline static bool IsDecodeSuccess(const DecodeResult& aResult) {
    281    return nsAVIFDecoder::IsDecodeSuccess(aResult);
    282  }
    283 
    284  // The mDecodedData is valid after Decode() succeeds
    285  UniquePtr<AVIFDecodedData> mDecodedData;
    286 };
    287 
    288 }  // namespace image
    289 }  // namespace mozilla
    290 
    291 #endif  // mozilla_image_decoders_nsAVIFDecoder_h