WebrtcGmpVideoCodec.h (17324B)
1 /* 2 * Copyright (c) 2012, The WebRTC project authors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * * Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * * Neither the name of Google nor the names of its contributors may 17 * be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #ifndef WEBRTCGMPVIDEOCODEC_H_ 34 #define WEBRTCGMPVIDEOCODEC_H_ 35 36 #include <string> 37 38 #include "GMPVideoDecoderProxy.h" 39 #include "GMPVideoEncoderProxy.h" 40 #include "MediaConduitInterface.h" 41 #include "PerformanceRecorder.h" 42 #include "VideoConduit.h" 43 #include "api/video/video_frame_type.h" 44 #include "common_video/h264/h264_bitstream_parser.h" 45 #include "gmp-video-host.h" 46 #include "jsapi/PeerConnectionImpl.h" 47 #include "modules/video_coding/include/video_error_codes.h" 48 #include "modules/video_coding/svc/scalable_video_controller.h" 49 #include "mozIGeckoMediaPluginService.h" 50 #include "mozilla/EventTargetCapability.h" 51 #include "mozilla/Mutex.h" 52 #include "mozilla/glean/DomMediaWebrtcMetrics.h" 53 #include "nsTArray.h" 54 #include "nsThreadUtils.h" 55 56 namespace mozilla::detail { 57 struct InputImageData { 58 uint64_t gmp_timestamp_us = 0; 59 int64_t ntp_timestamp_ms = 0; 60 int64_t timestamp_us = 0; 61 uint32_t rtp_timestamp = 0; 62 webrtc::ScalableVideoController::LayerFrameConfig frame_config; 63 }; 64 } // namespace mozilla::detail 65 66 // webrtc::CodecSpecificInfo has members that are not always memmovable, which 67 // is required by nsTArray/AutoTArray by default. Use move constructors where 68 // necessary. 69 template <> 70 struct nsTArray_RelocationStrategy<mozilla::detail::InputImageData> { 71 using IID = mozilla::detail::InputImageData; 72 // This logic follows MemMoveAnnotation.h. 73 using Type = 74 std::conditional_t<(std::is_trivially_move_constructible_v<IID> || 75 (!std::is_move_constructible_v<IID> && 76 std::is_trivially_copy_constructible_v<IID>)) && 77 std::is_trivially_destructible_v<IID>, 78 nsTArray_RelocateUsingMemutils, 79 nsTArray_RelocateUsingMoveConstructor<IID>>; 80 }; 81 82 namespace mozilla { 83 84 static void NotifyGmpInitDone(const std::string& aPCHandle, int32_t aResult, 85 const std::string& aError = "") { 86 if (!NS_IsMainThread()) { 87 MOZ_ALWAYS_SUCCEEDS(GetMainThreadSerialEventTarget()->Dispatch( 88 NS_NewRunnableFunction(__func__, [aPCHandle, aResult, aError] { 89 NotifyGmpInitDone(aPCHandle, aResult, aError); 90 }))); 91 return; 92 } 93 94 glean::webrtc::gmp_init_success 95 .EnumGet(static_cast<glean::webrtc::GmpInitSuccessLabel>( 96 aResult == WEBRTC_VIDEO_CODEC_OK)) 97 .Add(); 98 if (aResult == WEBRTC_VIDEO_CODEC_OK) { 99 // Might be useful to notify the PeerConnection about successful init 100 // someday. 101 return; 102 } 103 104 PeerConnectionWrapper wrapper(aPCHandle); 105 if (wrapper.impl()) { 106 wrapper.impl()->OnMediaError(aError); 107 } 108 } 109 110 // Hold a frame for later decode 111 class GMPDecodeData { 112 public: 113 GMPDecodeData(const webrtc::EncodedImage& aInputImage, bool aMissingFrames, 114 int64_t aRenderTimeMs) 115 : mImage(aInputImage), 116 mMissingFrames(aMissingFrames), 117 mRenderTimeMs(aRenderTimeMs) { 118 // We want to use this for queuing, and the calling code recycles the 119 // buffer on return from Decode() 120 MOZ_RELEASE_ASSERT(aInputImage.size() < 121 (std::numeric_limits<size_t>::max() >> 1)); 122 } 123 124 ~GMPDecodeData() = default; 125 126 const webrtc::EncodedImage mImage; 127 const bool mMissingFrames; 128 const int64_t mRenderTimeMs; 129 }; 130 131 class RefCountedWebrtcVideoEncoder { 132 public: 133 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING 134 135 // Implement sort of WebrtcVideoEncoder interface and support refcounting. 136 // (We cannot use |Release|, since that's needed for nsRefPtr) 137 virtual int32_t InitEncode( 138 const webrtc::VideoCodec* aCodecSettings, 139 const webrtc::VideoEncoder::Settings& aSettings) = 0; 140 141 virtual int32_t Encode( 142 const webrtc::VideoFrame& aInputImage, 143 const std::vector<webrtc::VideoFrameType>* aFrameTypes) = 0; 144 145 virtual int32_t RegisterEncodeCompleteCallback( 146 webrtc::EncodedImageCallback* aCallback) = 0; 147 148 virtual int32_t Shutdown() = 0; 149 150 virtual int32_t SetRates( 151 const webrtc::VideoEncoder::RateControlParameters& aParameters) = 0; 152 153 virtual MediaEventSource<uint64_t>* InitPluginEvent() = 0; 154 155 virtual MediaEventSource<uint64_t>* ReleasePluginEvent() = 0; 156 157 virtual WebrtcVideoEncoder::EncoderInfo GetEncoderInfo() const = 0; 158 159 protected: 160 virtual ~RefCountedWebrtcVideoEncoder() = default; 161 }; 162 163 class WebrtcGmpVideoEncoder final : public GMPVideoEncoderCallbackProxy, 164 public RefCountedWebrtcVideoEncoder { 165 public: 166 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcGmpVideoEncoder, final); 167 168 WebrtcGmpVideoEncoder(const webrtc::SdpVideoFormat& aFormat, 169 std::string aPCHandle); 170 171 // Implement VideoEncoder interface, sort of. 172 // (We cannot use |Release|, since that's needed for nsRefPtr) 173 int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings, 174 const webrtc::VideoEncoder::Settings& aSettings) override; 175 176 int32_t Encode( 177 const webrtc::VideoFrame& aInputImage, 178 const std::vector<webrtc::VideoFrameType>* aFrameTypes) override; 179 180 int32_t RegisterEncodeCompleteCallback( 181 webrtc::EncodedImageCallback* aCallback) override; 182 183 int32_t Shutdown() override; 184 185 int32_t SetRates( 186 const webrtc::VideoEncoder::RateControlParameters& aParameters) override; 187 188 WebrtcVideoEncoder::EncoderInfo GetEncoderInfo() const override; 189 190 MediaEventSource<uint64_t>* InitPluginEvent() override { 191 return &mInitPluginEvent; 192 } 193 194 MediaEventSource<uint64_t>* ReleasePluginEvent() override { 195 return &mReleasePluginEvent; 196 } 197 198 // GMPVideoEncoderCallback virtual functions. 199 void Terminated() override; 200 201 void Encoded(GMPVideoEncodedFrame* aEncodedFrame, 202 const nsTArray<uint8_t>& aCodecSpecificInfo) override; 203 204 void Dropped(uint64_t aTimestamp) override; 205 206 void Error(GMPErr aError) override {} 207 208 private: 209 virtual ~WebrtcGmpVideoEncoder(); 210 211 void InitEncode_g(const GMPVideoCodec& aCodecParams, int32_t aNumberOfCores, 212 uint32_t aMaxPayloadSize); 213 int32_t GmpInitDone_g(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost, 214 const GMPVideoCodec& aCodecParams, 215 std::string* aErrorOut); 216 int32_t GmpInitDone_g(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost, 217 std::string* aErrorOut); 218 int32_t InitEncoderForSize(unsigned short aWidth, unsigned short aHeight, 219 std::string* aErrorOut); 220 void Close_g(); 221 222 class InitDoneCallback final : public GetGMPVideoEncoderCallback { 223 public: 224 InitDoneCallback(const RefPtr<WebrtcGmpVideoEncoder>& aEncoder, 225 const GMPVideoCodec& aCodecParams) 226 : mEncoder(aEncoder), mCodecParams(aCodecParams) {} 227 228 void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override { 229 std::string errorOut; 230 int32_t result = 231 mEncoder->GmpInitDone_g(aGMP, aHost, mCodecParams, &errorOut); 232 NotifyGmpInitDone(mEncoder->mPCHandle, result, errorOut); 233 } 234 235 private: 236 const RefPtr<WebrtcGmpVideoEncoder> mEncoder; 237 const GMPVideoCodec mCodecParams; 238 }; 239 240 void Encode_g(const webrtc::VideoFrame& aInputImage, 241 std::vector<webrtc::VideoFrameType> aFrameTypes); 242 void RegetEncoderForResolutionChange(uint32_t aWidth, uint32_t aHeight); 243 244 class InitDoneForResolutionChangeCallback final 245 : public GetGMPVideoEncoderCallback { 246 public: 247 InitDoneForResolutionChangeCallback( 248 const RefPtr<WebrtcGmpVideoEncoder>& aEncoder, uint32_t aWidth, 249 uint32_t aHeight) 250 : mEncoder(aEncoder), mWidth(aWidth), mHeight(aHeight) {} 251 252 void Done(GMPVideoEncoderProxy* aGMP, GMPVideoHost* aHost) override { 253 std::string errorOut; 254 int32_t result = mEncoder->GmpInitDone_g(aGMP, aHost, &errorOut); 255 if (result != WEBRTC_VIDEO_CODEC_OK) { 256 NotifyGmpInitDone(mEncoder->mPCHandle, result, errorOut); 257 return; 258 } 259 260 result = mEncoder->InitEncoderForSize(mWidth, mHeight, &errorOut); 261 NotifyGmpInitDone(mEncoder->mPCHandle, result, errorOut); 262 } 263 264 private: 265 const RefPtr<WebrtcGmpVideoEncoder> mEncoder; 266 const uint32_t mWidth; 267 const uint32_t mHeight; 268 }; 269 270 int32_t SetRates_g(uint32_t aOldBitRateKbps, uint32_t aNewBitRateKbps, 271 Maybe<double> aFrameRate); 272 273 nsCOMPtr<mozIGeckoMediaPluginService> mMPS; 274 nsCOMPtr<nsIThread> mGMPThread; 275 GMPVideoEncoderProxy* mGMP; 276 Maybe<EventTargetCapability<nsISerialEventTarget>> mEncodeQueue; 277 // Used to handle a race where Release() is called while init is in progress 278 bool mInitting; 279 uint32_t mConfiguredBitrateKbps MOZ_GUARDED_BY(mEncodeQueue); 280 GMPVideoHost* mHost; 281 GMPVideoCodec mCodecParams{}; 282 uint32_t mMaxPayloadSize; 283 bool mNeedKeyframe; 284 int mSyncLayerCap; 285 const webrtc::CodecParameterMap mFormatParams; 286 webrtc::H264BitstreamParser mH264BitstreamParser; 287 std::unique_ptr<webrtc::ScalableVideoController> mSvcController; 288 Mutex mCallbackMutex; 289 webrtc::EncodedImageCallback* mCallback MOZ_GUARDED_BY(mCallbackMutex); 290 Maybe<uint64_t> mCachedPluginId; 291 const std::string mPCHandle; 292 293 static constexpr size_t kMaxImagesInFlight = 1; 294 // Map rtp time -> input image data 295 AutoTArray<detail::InputImageData, kMaxImagesInFlight> mInputImageMap; 296 297 MediaEventProducer<uint64_t> mInitPluginEvent; 298 MediaEventProducer<uint64_t> mReleasePluginEvent; 299 }; 300 301 // Basically a strong ref to a RefCountedWebrtcVideoEncoder, that also 302 // translates from Release() to RefCountedWebrtcVideoEncoder::Shutdown(), 303 // since we need RefCountedWebrtcVideoEncoder::Release() for managing the 304 // refcount. The webrtc.org code gets one of these, so it doesn't unilaterally 305 // delete the "real" encoder. 306 class WebrtcVideoEncoderProxy final : public WebrtcVideoEncoder { 307 public: 308 explicit WebrtcVideoEncoderProxy( 309 RefPtr<RefCountedWebrtcVideoEncoder> aEncoder) 310 : mEncoderImpl(std::move(aEncoder)) {} 311 312 virtual ~WebrtcVideoEncoderProxy() { 313 RegisterEncodeCompleteCallback(nullptr); 314 } 315 316 MediaEventSource<uint64_t>* InitPluginEvent() override { 317 return mEncoderImpl->InitPluginEvent(); 318 } 319 320 MediaEventSource<uint64_t>* ReleasePluginEvent() override { 321 return mEncoderImpl->ReleasePluginEvent(); 322 } 323 324 int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings, 325 const WebrtcVideoEncoder::Settings& aSettings) override { 326 return mEncoderImpl->InitEncode(aCodecSettings, aSettings); 327 } 328 329 int32_t Encode( 330 const webrtc::VideoFrame& aInputImage, 331 const std::vector<webrtc::VideoFrameType>* aFrameTypes) override { 332 return mEncoderImpl->Encode(aInputImage, aFrameTypes); 333 } 334 335 int32_t RegisterEncodeCompleteCallback( 336 webrtc::EncodedImageCallback* aCallback) override { 337 return mEncoderImpl->RegisterEncodeCompleteCallback(aCallback); 338 } 339 340 int32_t Release() override { return mEncoderImpl->Shutdown(); } 341 342 void SetRates(const RateControlParameters& aParameters) override { 343 mEncoderImpl->SetRates(aParameters); 344 } 345 346 EncoderInfo GetEncoderInfo() const override { 347 return mEncoderImpl->GetEncoderInfo(); 348 } 349 350 private: 351 const RefPtr<RefCountedWebrtcVideoEncoder> mEncoderImpl; 352 }; 353 354 class WebrtcGmpVideoDecoder final : public GMPVideoDecoderCallbackProxy { 355 public: 356 WebrtcGmpVideoDecoder(std::string aPCHandle, TrackingId aTrackingId); 357 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcGmpVideoDecoder, final); 358 359 // Implement VideoEncoder interface, sort of. 360 // (We cannot use |Release|, since that's needed for nsRefPtr) 361 virtual bool Configure(const webrtc::VideoDecoder::Settings& settings); 362 virtual int32_t Decode(const webrtc::EncodedImage& aInputImage, 363 bool aMissingFrames, int64_t aRenderTimeMs); 364 virtual int32_t RegisterDecodeCompleteCallback( 365 webrtc::DecodedImageCallback* aCallback); 366 367 virtual int32_t ReleaseGmp(); 368 369 MediaEventSource<uint64_t>* InitPluginEvent() { return &mInitPluginEvent; } 370 371 MediaEventSource<uint64_t>* ReleasePluginEvent() { 372 return &mReleasePluginEvent; 373 } 374 375 // GMPVideoDecoderCallbackProxy 376 void Terminated() override; 377 378 void Decoded(GMPVideoi420Frame* aDecodedFrame) override; 379 380 void ReceivedDecodedReferenceFrame(const uint64_t aPictureId) override { 381 MOZ_CRASH(); 382 } 383 384 void ReceivedDecodedFrame(const uint64_t aPictureId) override { MOZ_CRASH(); } 385 386 void InputDataExhausted() override {} 387 388 void DrainComplete() override {} 389 390 void ResetComplete() override {} 391 392 void Error(GMPErr aError) override { mDecoderStatus = aError; } 393 394 private: 395 virtual ~WebrtcGmpVideoDecoder(); 396 397 void Configure_g(const webrtc::VideoDecoder::Settings& settings); 398 int32_t GmpInitDone_g(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost, 399 std::string* aErrorOut); 400 void Close_g(); 401 402 class InitDoneCallback final : public GetGMPVideoDecoderCallback { 403 public: 404 explicit InitDoneCallback(const RefPtr<WebrtcGmpVideoDecoder>& aDecoder) 405 : mDecoder(aDecoder) {} 406 407 void Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost) override { 408 std::string errorOut; 409 int32_t result = mDecoder->GmpInitDone_g(aGMP, aHost, &errorOut); 410 NotifyGmpInitDone(mDecoder->mPCHandle, result, errorOut); 411 } 412 413 private: 414 const RefPtr<WebrtcGmpVideoDecoder> mDecoder; 415 }; 416 417 void Decode_g(UniquePtr<GMPDecodeData>&& aDecodeData); 418 419 nsCOMPtr<mozIGeckoMediaPluginService> mMPS; 420 nsCOMPtr<nsIThread> mGMPThread; 421 GMPVideoDecoderProxy* mGMP; // Addref is held for us 422 // Used to handle a race where Release() is called while init is in progress 423 bool mInitting; 424 // Frames queued for decode while mInitting is true 425 nsTArray<UniquePtr<GMPDecodeData>> mQueuedFrames; 426 GMPVideoHost* mHost; 427 // Protects mCallback 428 Mutex mCallbackMutex; 429 webrtc::DecodedImageCallback* mCallback MOZ_GUARDED_BY(mCallbackMutex); 430 Maybe<uint64_t> mCachedPluginId; 431 Atomic<GMPErr, ReleaseAcquire> mDecoderStatus; 432 const std::string mPCHandle; 433 const TrackingId mTrackingId; 434 PerformanceRecorderMulti<DecodeStage> mPerformanceRecorder; 435 436 MediaEventProducer<uint64_t> mInitPluginEvent; 437 MediaEventProducer<uint64_t> mReleasePluginEvent; 438 }; 439 440 // Basically a strong ref to a WebrtcGmpVideoDecoder, that also translates 441 // from Release() to WebrtcGmpVideoDecoder::ReleaseGmp(), since we need 442 // WebrtcGmpVideoDecoder::Release() for managing the refcount. 443 // The webrtc.org code gets one of these, so it doesn't unilaterally delete 444 // the "real" encoder. 445 class WebrtcVideoDecoderProxy final : public WebrtcVideoDecoder { 446 public: 447 explicit WebrtcVideoDecoderProxy(std::string aPCHandle, 448 TrackingId aTrackingId) 449 : mDecoderImpl(new WebrtcGmpVideoDecoder(std::move(aPCHandle), 450 std::move(aTrackingId))) {} 451 452 virtual ~WebrtcVideoDecoderProxy() { 453 RegisterDecodeCompleteCallback(nullptr); 454 } 455 456 MediaEventSource<uint64_t>* InitPluginEvent() override { 457 return mDecoderImpl->InitPluginEvent(); 458 } 459 460 MediaEventSource<uint64_t>* ReleasePluginEvent() override { 461 return mDecoderImpl->ReleasePluginEvent(); 462 } 463 464 bool Configure(const Settings& settings) override { 465 return mDecoderImpl->Configure(settings); 466 } 467 468 int32_t Decode(const webrtc::EncodedImage& aInputImage, bool aMissingFrames, 469 int64_t aRenderTimeMs) override { 470 return mDecoderImpl->Decode(aInputImage, aMissingFrames, aRenderTimeMs); 471 } 472 473 int32_t RegisterDecodeCompleteCallback( 474 webrtc::DecodedImageCallback* aCallback) override { 475 return mDecoderImpl->RegisterDecodeCompleteCallback(aCallback); 476 } 477 478 int32_t Release() override { return mDecoderImpl->ReleaseGmp(); } 479 480 private: 481 const RefPtr<WebrtcGmpVideoDecoder> mDecoderImpl; 482 }; 483 484 } // namespace mozilla 485 486 #endif