tor-browser

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

AOMDecoder.h (10273B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      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 #if !defined(AOMDecoder_h_)
      7 #  define AOMDecoder_h_
      8 
      9 #  include <aom/aom_decoder.h>
     10 #  include <stdint.h>
     11 
     12 #  include "PerformanceRecorder.h"
     13 #  include "PlatformDecoderModule.h"
     14 #  include "VideoUtils.h"
     15 #  include "mozilla/Span.h"
     16 
     17 namespace mozilla {
     18 
     19 DDLoggedTypeDeclNameAndBase(AOMDecoder, MediaDataDecoder);
     20 
     21 class AOMDecoder final : public MediaDataDecoder,
     22                         public DecoderDoctorLifeLogger<AOMDecoder> {
     23 public:
     24  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AOMDecoder, final);
     25 
     26  explicit AOMDecoder(const CreateDecoderParams& aParams);
     27 
     28  RefPtr<InitPromise> Init() override;
     29  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
     30  RefPtr<DecodePromise> Drain() override;
     31  RefPtr<FlushPromise> Flush() override;
     32  RefPtr<ShutdownPromise> Shutdown() override;
     33  nsCString GetDescriptionName() const override {
     34    return "av1 libaom video decoder"_ns;
     35  }
     36  nsCString GetCodecName() const override { return "av1"_ns; }
     37 
     38  // Return true if aMimeType is a one of the strings used
     39  // by our demuxers to identify AV1 streams.
     40  static bool IsAV1(const nsACString& aMimeType);
     41 
     42  // Return true if uses AV1 main profile.
     43  static bool IsMainProfile(const MediaByteBuffer* aBox);
     44 
     45  // Return true if a sample is a keyframe.
     46  static bool IsKeyframe(Span<const uint8_t> aBuffer);
     47 
     48  // Return the frame dimensions for a sample.
     49  static gfx::IntSize GetFrameSize(Span<const uint8_t> aBuffer);
     50 
     51  // obu_type defined at:
     52  // https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=123
     53  enum class OBUType : uint8_t {
     54    Reserved = 0,
     55    SequenceHeader = 1,
     56    TemporalDelimiter = 2,
     57    FrameHeader = 3,
     58    TileGroup = 4,
     59    Metadata = 5,
     60    Frame = 6,
     61    RedundantFrameHeader = 7,
     62    TileList = 8,
     63    Padding = 15
     64  };
     65 
     66  struct OBUInfo {
     67    OBUType mType = OBUType::Reserved;
     68    bool mExtensionFlag = false;
     69    Span<const uint8_t> mContents;
     70 
     71    bool IsValid() const {
     72      switch (mType) {
     73        case OBUType::SequenceHeader:
     74        case OBUType::TemporalDelimiter:
     75        case OBUType::FrameHeader:
     76        case OBUType::TileGroup:
     77        case OBUType::Metadata:
     78        case OBUType::Frame:
     79        case OBUType::RedundantFrameHeader:
     80        case OBUType::TileList:
     81        case OBUType::Padding:
     82          return true;
     83        default:
     84          return false;
     85      }
     86    }
     87  };
     88 
     89  struct OBUIterator {
     90   public:
     91    explicit OBUIterator(const Span<const uint8_t>& aData)
     92        : mData(aData), mPosition(0), mGoNext(true), mResult(NS_OK) {}
     93    bool HasNext() {
     94      UpdateNext();
     95      return !mGoNext;
     96    }
     97    OBUInfo Next() {
     98      UpdateNext();
     99      mGoNext = true;
    100      return mCurrent;
    101    }
    102    MediaResult GetResult() const { return mResult; }
    103 
    104   private:
    105    const Span<const uint8_t>& mData;
    106    size_t mPosition;
    107    OBUInfo mCurrent;
    108    bool mGoNext;
    109    MediaResult mResult;
    110 
    111    // Used to fill mCurrent with the next OBU in the iterator.
    112    // mGoNext must be set to false if the next OBU is retrieved,
    113    // otherwise it will be true so that HasNext() returns false.
    114    // When an invalid OBU is read, the iterator will finish and
    115    // mCurrent will be reset to default OBUInfo().
    116    void UpdateNext();
    117  };
    118 
    119  // Create an iterator to parse Open Bitstream Units from a buffer.
    120  static OBUIterator ReadOBUs(const Span<const uint8_t>& aData);
    121  // Writes an Open Bitstream Unit header type and the contained subheader.
    122  // Extension flag is set to 0 and size field is always present.
    123  static already_AddRefed<MediaByteBuffer> CreateOBU(
    124      const OBUType aType, const Span<const uint8_t>& aContents);
    125 
    126  // chroma_sample_position defined at:
    127  // https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=131
    128  enum class ChromaSamplePosition : uint8_t {
    129    Unknown = 0,
    130    Vertical = 1,
    131    Colocated = 2,
    132    Reserved = 3
    133  };
    134 
    135  struct OperatingPoint {
    136    // https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=125
    137    // operating_point_idc[ i ]: A set of bitwise flags determining
    138    // the temporal and spatial layers to decode.
    139    // A value of 0 indicates that scalability is not being used.
    140    uint16_t mLayers = 0;
    141    // https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=650
    142    // See A.3: Levels for a definition of the available levels.
    143    uint8_t mLevel = 0;
    144    // https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=126
    145    // seq_tier[ i ]: The tier for the selected operating point.
    146    uint8_t mTier = 0;
    147 
    148    bool operator==(const OperatingPoint& aOther) const {
    149      return mLayers == aOther.mLayers && mLevel == aOther.mLevel &&
    150             mTier == aOther.mTier;
    151    }
    152    bool operator!=(const OperatingPoint& aOther) const {
    153      return !(*this == aOther);
    154    }
    155  };
    156 
    157  struct AV1SequenceInfo {
    158    AV1SequenceInfo() = default;
    159 
    160    AV1SequenceInfo(const AV1SequenceInfo& aOther) { *this = aOther; }
    161 
    162    // Profiles, levels and tiers defined at:
    163    // https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=650
    164    uint8_t mProfile = 0;
    165 
    166    // choose_operating_point( ) defines that the operating points are
    167    // specified in order of preference by the encoder. Higher operating
    168    // points indices in the header will allow a tradeoff of quality for
    169    // performance, dropping some data from the decoding process.
    170    // Normally we are only interested in the first operating point.
    171    // See: https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=126
    172    nsTArray<OperatingPoint> mOperatingPoints = nsTArray<OperatingPoint>(1);
    173 
    174    gfx::IntSize mImage = {0, 0};
    175 
    176    // Color configs explained at:
    177    // https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=129
    178    uint8_t mBitDepth = 8;
    179    bool mMonochrome = false;
    180    bool mSubsamplingX = true;
    181    bool mSubsamplingY = true;
    182    ChromaSamplePosition mChromaSamplePosition = ChromaSamplePosition::Unknown;
    183 
    184    VideoColorSpace mColorSpace;
    185 
    186    gfx::ColorDepth ColorDepth() const {
    187      return gfx::ColorDepthForBitDepth(mBitDepth);
    188    }
    189 
    190    bool operator==(const AV1SequenceInfo& aOther) const {
    191      if (mProfile != aOther.mProfile || mImage != aOther.mImage ||
    192          mBitDepth != aOther.mBitDepth || mMonochrome != aOther.mMonochrome ||
    193          mSubsamplingX != aOther.mSubsamplingX ||
    194          mSubsamplingY != aOther.mSubsamplingY ||
    195          mChromaSamplePosition != aOther.mChromaSamplePosition ||
    196          mColorSpace != aOther.mColorSpace) {
    197        return false;
    198      }
    199 
    200      size_t opCount = mOperatingPoints.Length();
    201      if (opCount != aOther.mOperatingPoints.Length()) {
    202        return false;
    203      }
    204      for (size_t i = 0; i < opCount; i++) {
    205        if (mOperatingPoints[i] != aOther.mOperatingPoints[i]) {
    206          return false;
    207        }
    208      }
    209 
    210      return true;
    211    }
    212    bool operator!=(const AV1SequenceInfo& aOther) const {
    213      return !(*this == aOther);
    214    }
    215    AV1SequenceInfo& operator=(const AV1SequenceInfo& aOther) {
    216      mProfile = aOther.mProfile;
    217 
    218      size_t opCount = aOther.mOperatingPoints.Length();
    219      mOperatingPoints.ClearAndRetainStorage();
    220      mOperatingPoints.SetCapacity(opCount);
    221      for (size_t i = 0; i < opCount; i++) {
    222        mOperatingPoints.AppendElement(aOther.mOperatingPoints[i]);
    223      }
    224 
    225      mImage = aOther.mImage;
    226      mBitDepth = aOther.mBitDepth;
    227      mMonochrome = aOther.mMonochrome;
    228      mSubsamplingX = aOther.mSubsamplingX;
    229      mSubsamplingY = aOther.mSubsamplingY;
    230      mChromaSamplePosition = aOther.mChromaSamplePosition;
    231      mColorSpace = aOther.mColorSpace;
    232      return *this;
    233    }
    234  };
    235 
    236  // Get a sequence header's info from a sample.
    237  // Returns a MediaResult with codes:
    238  //    NS_OK: Sequence header was successfully found and read.
    239  //    NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA: Sequence header was not present.
    240  //    Other errors will indicate that the data was corrupt.
    241  static MediaResult ReadSequenceHeaderInfo(const Span<const uint8_t>& aSample,
    242                                            AV1SequenceInfo& aDestInfo);
    243  // Writes a sequence header OBU to the buffer.
    244  static already_AddRefed<MediaByteBuffer> CreateSequenceHeader(
    245      const AV1SequenceInfo& aInfo, nsresult& aResult);
    246 
    247  // Reads the raw data of an ISOBMFF-compatible av1 configuration box (av1C),
    248  // including any included sequence header.
    249  static void TryReadAV1CBox(const MediaByteBuffer* aBox,
    250                             AV1SequenceInfo& aDestInfo,
    251                             MediaResult& aSeqHdrResult);
    252  // Reads the raw data of an ISOBMFF-compatible av1 configuration box (av1C),
    253  // including any included sequence header.
    254  // This function should only be called for av1C boxes made by WriteAV1CBox, as
    255  // it will assert that the box and its contained OBUs are not corrupted.
    256  static void ReadAV1CBox(const MediaByteBuffer* aBox,
    257                          AV1SequenceInfo& aDestInfo, bool& aHadSeqHdr) {
    258    MediaResult seqHdrResult;
    259    TryReadAV1CBox(aBox, aDestInfo, seqHdrResult);
    260    nsresult code = seqHdrResult.Code();
    261    MOZ_ASSERT(code == NS_OK || code == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
    262    aHadSeqHdr = code == NS_OK;
    263  }
    264  // Writes an ISOBMFF-compatible av1 configuration box (av1C) to the buffer.
    265  static void WriteAV1CBox(const AV1SequenceInfo& aInfo,
    266                           MediaByteBuffer* aDestBox, bool& aHasSeqHdr);
    267 
    268  // Create sequence info from a MIME codecs string.
    269  static Maybe<AV1SequenceInfo> CreateSequenceInfoFromCodecs(
    270      const nsAString& aCodec);
    271  static bool SetVideoInfo(VideoInfo* aDestInfo, const nsAString& aCodec);
    272 
    273 private:
    274  ~AOMDecoder();
    275  RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample);
    276 
    277  const RefPtr<layers::ImageContainer> mImageContainer;
    278  const RefPtr<TaskQueue> mTaskQueue;
    279 
    280  // AOM decoder state
    281  aom_codec_ctx_t mCodec;
    282 
    283  const VideoInfo mInfo;
    284  const Maybe<TrackingId> mTrackingId;
    285  PerformanceRecorderMulti<DecodeStage> mPerformanceRecorder;
    286 };
    287 
    288 }  // namespace mozilla
    289 
    290 #endif  // AOMDecoder_h_