summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/agnostic/VPXDecoder.h
blob: e5fe80128f17ca4177061a5ba12c8e5e2f7da513 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(VPXDecoder_h_)
#  define VPXDecoder_h_

#  include <stdint.h>

#  include "PlatformDecoderModule.h"
#  include "mozilla/Span.h"
#  include "mozilla/gfx/Types.h"
#  include "vpx/vp8dx.h"
#  include "vpx/vpx_codec.h"
#  include "vpx/vpx_decoder.h"

namespace mozilla {

DDLoggedTypeDeclNameAndBase(VPXDecoder, MediaDataDecoder);

class VPXDecoder final : public MediaDataDecoder,
                         public DecoderDoctorLifeLogger<VPXDecoder> {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VPXDecoder, final);

  explicit VPXDecoder(const CreateDecoderParams& aParams);

  RefPtr<InitPromise> Init() override;
  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
  RefPtr<DecodePromise> Drain() override;
  RefPtr<FlushPromise> Flush() override;
  RefPtr<ShutdownPromise> Shutdown() override;
  nsCString GetDescriptionName() const override {
    return "libvpx video decoder"_ns;
  }
  nsCString GetCodecName() const override;

  enum Codec : uint8_t {
    VP8 = 1 << 0,
    VP9 = 1 << 1,
    Unknown = 1 << 7,
  };

  // Return true if aMimeType is a one of the strings used by our demuxers to
  // identify VPX of the specified type. Does not parse general content type
  // strings, i.e. white space matters.
  static bool IsVPX(const nsACString& aMimeType,
                    uint8_t aCodecMask = VP8 | VP9);
  static bool IsVP8(const nsACString& aMimeType);
  static bool IsVP9(const nsACString& aMimeType);

  // Return true if a sample is a keyframe for the specified codec.
  static bool IsKeyframe(Span<const uint8_t> aBuffer, Codec aCodec);

  // Return the frame dimensions for a sample for the specified codec.
  static gfx::IntSize GetFrameSize(Span<const uint8_t> aBuffer, Codec aCodec);
  // Return the display dimensions for a sample for the specified codec.
  static gfx::IntSize GetDisplaySize(Span<const uint8_t> aBuffer, Codec aCodec);

  // Return the VP9 profile as per https://www.webmproject.org/vp9/profiles/
  // Return negative value if error.
  static int GetVP9Profile(Span<const uint8_t> aBuffer);

  struct VPXStreamInfo {
    gfx::IntSize mImage;
    bool mDisplayAndImageDifferent = false;
    gfx::IntSize mDisplay;
    bool mKeyFrame = false;

    uint8_t mProfile = 0;
    uint8_t mBitDepth = 8;
    /*
    0 CS_UNKNOWN Unknown (in this case the color space must be signaled outside
      the VP9 bitstream).
    1 CS_BT_601 Rec. ITU-R BT.601-7
    2 CS_BT_709 Rec. ITU-R BT.709-6
    3 CS_SMPTE_170 SMPTE-170
    4 CS_SMPTE_240 SMPTE-240
    5 CS_BT_2020 Rec. ITU-R BT.2020-2
    6 CS_RESERVED Reserved
    7 CS_RGB sRGB (IEC 61966-2-1)
    */
    int mColorSpace = 1;  // CS_BT_601

    gfx::YUVColorSpace ColorSpace() const {
      switch (mColorSpace) {
        case 1:
        case 3:
        case 4:
          return gfx::YUVColorSpace::BT601;
        case 2:
          return gfx::YUVColorSpace::BT709;
        case 5:
          return gfx::YUVColorSpace::BT2020;
        default:
          return gfx::YUVColorSpace::Default;
      }
    }

    uint8_t mColorPrimaries = gfx::CICP::ColourPrimaries::CP_UNSPECIFIED;
    gfx::ColorSpace2 ColorPrimaries() const {
      switch (mColorPrimaries) {
        case gfx::CICP::ColourPrimaries::CP_BT709:
          return gfx::ColorSpace2::BT709;
        case gfx::CICP::ColourPrimaries::CP_UNSPECIFIED:
          return gfx::ColorSpace2::BT709;
        case gfx::CICP::ColourPrimaries::CP_BT2020:
          return gfx::ColorSpace2::BT2020;
        default:
          return gfx::ColorSpace2::BT709;
      }
    }

    uint8_t mTransferFunction =
        gfx::CICP::TransferCharacteristics::TC_UNSPECIFIED;
    gfx::TransferFunction TransferFunction() const {
      switch (mTransferFunction) {
        case gfx::CICP::TransferCharacteristics::TC_BT709:
          return gfx::TransferFunction::BT709;
        case gfx::CICP::TransferCharacteristics::TC_SRGB:
          return gfx::TransferFunction::SRGB;
        case gfx::CICP::TransferCharacteristics::TC_SMPTE2084:
          return gfx::TransferFunction::PQ;
        case gfx::CICP::TransferCharacteristics::TC_HLG:
          return gfx::TransferFunction::HLG;
        default:
          return gfx::TransferFunction::BT709;
      }
    }

    /*
    mFullRange == false then:
      For BitDepth equals 8:
        Y is between 16 and 235 inclusive.
        U and V are between 16 and 240 inclusive.
      For BitDepth equals 10:
        Y is between 64 and 940 inclusive.
        U and V are between 64 and 960 inclusive.
      For BitDepth equals 12:
        Y is between 256 and 3760.
        U and V are between 256 and 3840 inclusive.
    mFullRange == true then:
      No restriction on Y, U, V values.
    */
    bool mFullRange = false;

    gfx::ColorRange ColorRange() const {
      return mFullRange ? gfx::ColorRange::FULL : gfx::ColorRange::LIMITED;
    }

    /*
      Sub-sampling, used only for non sRGB colorspace.
      subsampling_x subsampling_y Description
          0             0         YUV 4:4:4
          0             1         YUV 4:4:0
          1             0         YUV 4:2:2
          1             1         YUV 4:2:0
    */
    bool mSubSampling_x = true;
    bool mSubSampling_y = true;

    bool IsCompatible(const VPXStreamInfo& aOther) const {
      return mImage == aOther.mImage && mProfile == aOther.mProfile &&
             mBitDepth == aOther.mBitDepth &&
             mSubSampling_x == aOther.mSubSampling_x &&
             mSubSampling_y == aOther.mSubSampling_y &&
             mColorSpace == aOther.mColorSpace &&
             mFullRange == aOther.mFullRange;
    }
  };

  static bool GetStreamInfo(Span<const uint8_t> aBuffer, VPXStreamInfo& aInfo,
                            Codec aCodec);

  static void GetVPCCBox(MediaByteBuffer* aDestBox, const VPXStreamInfo& aInfo);
  // Set extradata for a VP8/VP9 track, returning false if the codec was
  // invalid.
  static bool SetVideoInfo(VideoInfo* aDestInfo, const nsAString& aCodec);

  static void SetChroma(VPXStreamInfo& aDestInfo, uint8_t chroma);
  static void ReadVPCCBox(VPXStreamInfo& aDestInfo, MediaByteBuffer* aBox);

 private:
  ~VPXDecoder();
  RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample);
  MediaResult DecodeAlpha(vpx_image_t** aImgAlpha, const MediaRawData* aSample);

  const RefPtr<layers::ImageContainer> mImageContainer;
  RefPtr<layers::KnowsCompositor> mImageAllocator;
  const RefPtr<TaskQueue> mTaskQueue;

  // VPx decoder state
  vpx_codec_ctx_t mVPX;

  // VPx alpha decoder state
  vpx_codec_ctx_t mVPXAlpha;

  const VideoInfo mInfo;

  const Codec mCodec;
  const bool mLowLatency;
  const Maybe<TrackingId> mTrackingId;
};

}  // namespace mozilla

#endif