VideoFrame.h (10389B)
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 7 #ifndef mozilla_dom_VideoFrame_h 8 #define mozilla_dom_VideoFrame_h 9 10 #include "js/TypeDecls.h" 11 #include "mozilla/ErrorResult.h" 12 #include "mozilla/Span.h" 13 #include "mozilla/WeakPtr.h" 14 #include "mozilla/dom/BindingDeclarations.h" 15 #include "mozilla/dom/BufferSourceBindingFwd.h" 16 #include "mozilla/dom/TypedArray.h" 17 #include "mozilla/dom/VideoColorSpaceBinding.h" 18 #include "mozilla/dom/WebCodecsUtils.h" 19 #include "mozilla/gfx/Point.h" 20 #include "mozilla/gfx/Rect.h" 21 #include "mozilla/media/MediaUtils.h" 22 #include "nsCycleCollectionParticipant.h" 23 #include "nsTArrayForwardDeclare.h" 24 #include "nsWrapperCache.h" 25 26 class nsIGlobalObject; 27 class nsIURI; 28 29 namespace mozilla { 30 31 namespace layers { 32 class Image; 33 } // namespace layers 34 35 namespace dom { 36 37 class DOMRectReadOnly; 38 class HTMLCanvasElement; 39 class HTMLImageElement; 40 class HTMLVideoElement; 41 class ImageBitmap; 42 class OffscreenCanvas; 43 class Promise; 44 class SVGImageElement; 45 class StructuredCloneHolder; 46 class VideoColorSpace; 47 class VideoFrame; 48 enum class PredefinedColorSpace : uint8_t; 49 enum class VideoPixelFormat : uint8_t; 50 struct VideoFrameBufferInit; 51 struct VideoFrameCopyToOptions; 52 struct VideoFrameInit; 53 54 } // namespace dom 55 56 namespace webgpu { 57 class ExternalTexture; 58 } // namespace webgpu 59 60 } // namespace mozilla 61 62 namespace mozilla::dom { 63 64 struct VideoFrameData { 65 VideoFrameData(layers::Image* aImage, const Maybe<VideoPixelFormat>& aFormat, 66 gfx::IntRect aVisibleRect, gfx::IntSize aDisplaySize, 67 Maybe<uint64_t> aDuration, int64_t aTimestamp, 68 const VideoColorSpaceInternal& aColorSpace); 69 VideoFrameData(const VideoFrameData& aData) = default; 70 71 const RefPtr<layers::Image> mImage; 72 const Maybe<VideoPixelFormat> mFormat; 73 const gfx::IntRect mVisibleRect; 74 const gfx::IntSize mDisplaySize; 75 const Maybe<uint64_t> mDuration; 76 const int64_t mTimestamp; 77 const VideoColorSpaceInternal mColorSpace; 78 }; 79 80 struct VideoFrameSerializedData : VideoFrameData { 81 VideoFrameSerializedData(const VideoFrameData& aData, 82 gfx::IntSize aCodedSize); 83 84 const gfx::IntSize mCodedSize; 85 }; 86 87 class VideoFrame final : public nsISupports, 88 public nsWrapperCache, 89 public media::ShutdownConsumer { 90 public: 91 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 92 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(VideoFrame) 93 94 public: 95 VideoFrame(nsIGlobalObject* aParent, const RefPtr<layers::Image>& aImage, 96 const Maybe<VideoPixelFormat>& aFormat, gfx::IntSize aCodedSize, 97 gfx::IntRect aVisibleRect, gfx::IntSize aDisplaySize, 98 const Maybe<uint64_t>& aDuration, int64_t aTimestamp, 99 const VideoColorSpaceInternal& aColorSpace); 100 VideoFrame(nsIGlobalObject* aParent, const VideoFrameSerializedData& aData); 101 VideoFrame(const VideoFrame& aOther); 102 103 protected: 104 ~VideoFrame(); 105 106 public: 107 nsIGlobalObject* GetParentObject() const; 108 109 JSObject* WrapObject(JSContext* aCx, 110 JS::Handle<JSObject*> aGivenProto) override; 111 112 static bool PrefEnabled(JSContext* aCx, JSObject* aObj = nullptr); 113 114 static already_AddRefed<VideoFrame> Constructor( 115 const GlobalObject& aGlobal, HTMLImageElement& aImageElement, 116 const VideoFrameInit& aInit, ErrorResult& aRv); 117 static already_AddRefed<VideoFrame> Constructor( 118 const GlobalObject& aGlobal, SVGImageElement& aSVGImageElement, 119 const VideoFrameInit& aInit, ErrorResult& aRv); 120 static already_AddRefed<VideoFrame> Constructor( 121 const GlobalObject& aGlobal, HTMLCanvasElement& aCanvasElement, 122 const VideoFrameInit& aInit, ErrorResult& aRv); 123 static already_AddRefed<VideoFrame> Constructor( 124 const GlobalObject& aGlobal, HTMLVideoElement& aVideoElement, 125 const VideoFrameInit& aInit, ErrorResult& aRv); 126 static already_AddRefed<VideoFrame> Constructor( 127 const GlobalObject& aGlobal, OffscreenCanvas& aOffscreenCanvas, 128 const VideoFrameInit& aInit, ErrorResult& aRv); 129 static already_AddRefed<VideoFrame> Constructor(const GlobalObject& aGlobal, 130 ImageBitmap& aImageBitmap, 131 const VideoFrameInit& aInit, 132 ErrorResult& aRv); 133 static already_AddRefed<VideoFrame> Constructor(const GlobalObject& aGlobal, 134 VideoFrame& aVideoFrame, 135 const VideoFrameInit& aInit, 136 ErrorResult& aRv); 137 static already_AddRefed<VideoFrame> Constructor( 138 const GlobalObject& aGlobal, const ArrayBufferView& aBufferView, 139 const VideoFrameBufferInit& aInit, ErrorResult& aRv); 140 static already_AddRefed<VideoFrame> Constructor( 141 const GlobalObject& aGlobal, const ArrayBuffer& aBuffer, 142 const VideoFrameBufferInit& aInit, ErrorResult& aRv); 143 144 Nullable<VideoPixelFormat> GetFormat() const; 145 146 uint32_t CodedWidth() const; 147 148 uint32_t CodedHeight() const; 149 150 already_AddRefed<DOMRectReadOnly> GetCodedRect() const; 151 152 already_AddRefed<DOMRectReadOnly> GetVisibleRect() const; 153 154 uint32_t DisplayWidth() const; 155 156 uint32_t DisplayHeight() const; 157 158 Nullable<uint64_t> GetDuration() const; 159 160 int64_t Timestamp() const; 161 162 already_AddRefed<VideoColorSpace> ColorSpace() const; 163 164 uint32_t AllocationSize(const VideoFrameCopyToOptions& aOptions, 165 ErrorResult& aRv); 166 167 already_AddRefed<Promise> CopyTo(const AllowSharedBufferSource& aDestination, 168 const VideoFrameCopyToOptions& aOptions, 169 ErrorResult& aRv); 170 171 already_AddRefed<VideoFrame> Clone(ErrorResult& aRv) const; 172 173 void Close(); 174 bool IsClosed() const; 175 void OnShutdown() override; 176 177 // [Serializable] implementations: {Read, Write}StructuredClone 178 static JSObject* ReadStructuredClone(JSContext* aCx, nsIGlobalObject* aGlobal, 179 JSStructuredCloneReader* aReader, 180 const VideoFrameSerializedData& aData); 181 182 bool WriteStructuredClone(JSStructuredCloneWriter* aWriter, 183 StructuredCloneHolder* aHolder) const; 184 185 // [Transferable] implementations: Transfer, FromTransferred 186 using TransferredData = VideoFrameSerializedData; 187 188 UniquePtr<TransferredData> Transfer(); 189 190 static already_AddRefed<VideoFrame> FromTransferred(nsIGlobalObject* aGlobal, 191 TransferredData* aData); 192 193 // Native only methods. 194 const gfx::IntSize& NativeCodedSize() const { return mCodedSize; } 195 const gfx::IntSize& NativeDisplaySize() const { return mDisplaySize; } 196 const gfx::IntRect& NativeVisibleRect() const { return mVisibleRect; } 197 already_AddRefed<layers::Image> GetImage() const; 198 199 // Track a WebGPU ExternalTexture as being imported from this video frame. 200 // This ensures it will be correctly expired when the video frame is closed. 201 void TrackWebGPUExternalTexture( 202 WeakPtr<webgpu::ExternalTexture> aExternalTexture); 203 204 nsCString ToString() const; 205 206 public: 207 // A VideoPixelFormat wrapper providing utilities for VideoFrame. 208 class Format final { 209 public: 210 explicit Format(const VideoPixelFormat& aFormat); 211 ~Format() = default; 212 const VideoPixelFormat& PixelFormat() const; 213 gfx::SurfaceFormat ToSurfaceFormat() const; 214 void MakeOpaque(); 215 216 // TODO: Assign unique value for each plane? 217 // The value indicates the order of the plane in format. 218 enum class Plane : uint8_t { Y = 0, RGBA = Y, U = 1, UV = U, V = 2, A = 3 }; 219 nsTArray<Plane> Planes() const; 220 const char* PlaneName(const Plane& aPlane) const; 221 uint32_t SampleBytes(const Plane& aPlane) const; 222 gfx::IntSize SampleSize(const Plane& aPlane) const; 223 bool IsValidSize(const gfx::IntSize& aSize) const; 224 size_t ByteCount(const gfx::IntSize& aSize) const; 225 226 private: 227 bool IsYUV() const; 228 VideoPixelFormat mFormat; 229 }; 230 231 private: 232 // VideoFrame can run on either main thread or worker thread. 233 void AssertIsOnOwningThread() const { NS_ASSERT_OWNINGTHREAD(VideoFrame); } 234 235 already_AddRefed<VideoFrame> ConvertToRGBFrame( 236 const VideoPixelFormat& aFormat, const PredefinedColorSpace& aColorSpace); 237 238 VideoFrameData GetVideoFrameData() const; 239 240 // Below helpers are used to automatically release the holding Resource if 241 // VideoFrame is never Close()d by the users. 242 void StartAutoClose(); 243 void StopAutoClose(); 244 void CloseIfNeeded(); 245 246 // A class representing the VideoFrame's data. 247 class Resource final { 248 public: 249 Resource(const RefPtr<layers::Image>& aImage, Maybe<Format>&& aFormat); 250 Resource(const Resource& aOther); 251 ~Resource() = default; 252 Maybe<VideoPixelFormat> TryPixelFormat() const; 253 uint32_t Stride(const Format::Plane& aPlane) const; 254 bool CopyTo(const Format::Plane& aPlane, const gfx::IntRect& aRect, 255 Span<uint8_t>&& aPlaneDest, size_t aDestinationStride) const; 256 257 const RefPtr<layers::Image> mImage; 258 // Nothing() if mImage is not in VideoPixelFormat 259 const Maybe<Format> mFormat; 260 }; 261 262 nsCOMPtr<nsIGlobalObject> mParent; 263 264 // Use Maybe instead of UniquePtr to allow copy ctor. 265 // The mResource's existence is used as the [[Detached]] for [Transferable]. 266 Maybe<const Resource> mResource; // Nothing() after `Close()`d 267 268 // TODO: Replace this by mResource->mImage->GetSize()? 269 gfx::IntSize mCodedSize; 270 gfx::IntRect mVisibleRect; 271 gfx::IntSize mDisplaySize; 272 273 Maybe<uint64_t> mDuration; 274 int64_t mTimestamp; 275 VideoColorSpaceInternal mColorSpace; 276 277 // The following are used to help monitoring mResource release. 278 RefPtr<media::ShutdownWatcher> mShutdownWatcher = nullptr; 279 280 // WebGPU external textures that were imported from this video frame. We must 281 // call `Expire()` on them when the video frame is closed. 282 nsTArray<WeakPtr<webgpu::ExternalTexture>> mWebGPUExternalTextures; 283 }; 284 285 } // namespace mozilla::dom 286 287 #endif // mozilla_dom_VideoFrame_h