diff --git a/dom/media/gmp/GMPLog.h b/dom/media/gmp/GMPLog.h index 6aa197642771..94e797e82762 100644 --- a/dom/media/gmp/GMPLog.h +++ b/dom/media/gmp/GMPLog.h @@ -7,11 +7,14 @@ #define DOM_MEDIA_GMPLOG_H_ #include "content_decryption_module.h" +#include "gmp-video-codec.h" #include "mozilla/Logging.h" namespace mozilla { extern LogModule* GetGMPLog(); +extern LogModule* GetGMPLibraryLog(); +extern GMPLogLevel GetGMPLibraryLogLevel(); #define GMP_LOG_ERROR(msg, ...) \ MOZ_LOG(GetGMPLog(), LogLevel::Error, (msg, ##__VA_ARGS__)) diff --git a/dom/media/gmp/GMPMessageUtils.h b/dom/media/gmp/GMPMessageUtils.h index 33a18f7ad82d..b4f16072d891 100644 --- a/dom/media/gmp/GMPMessageUtils.h +++ b/dom/media/gmp/GMPMessageUtils.h @@ -44,6 +44,11 @@ struct ParamTraits : public ContiguousEnumSerializer {}; +template <> +struct ParamTraits + : public ContiguousEnumSerializerInclusive {}; + template <> struct ParamTraits : public ContiguousEnumSerializer { WriteParam(aWriter, aParam.mSimulcastStream[i]); } WriteParam(aWriter, aParam.mMode); + WriteParam(aWriter, aParam.mUseThreadedDecode); + WriteParam(aWriter, aParam.mLogLevel); } static bool Read(MessageReader* aReader, paramType* aResult) { // NOTE: make sure this matches any versions supported if (!ReadParam(aReader, &(aResult->mGMPApiVersion)) || - aResult->mGMPApiVersion != kGMPVersion33) { + (aResult->mGMPApiVersion != kGMPVersion33 && + aResult->mGMPApiVersion != kGMPVersion34)) { return false; } if (!ReadParam(aReader, &(aResult->mCodecType))) { @@ -161,7 +169,9 @@ struct ParamTraits { } } - if (!ReadParam(aReader, &(aResult->mMode))) { + if (!ReadParam(aReader, &(aResult->mMode)) || + !ReadParam(aReader, &(aResult->mUseThreadedDecode)) || + !ReadParam(aReader, &(aResult->mLogLevel))) { return false; } diff --git a/dom/media/gmp/GMPService.cpp b/dom/media/gmp/GMPService.cpp index 82e38405a52c..08facb8aa086 100644 --- a/dom/media/gmp/GMPService.cpp +++ b/dom/media/gmp/GMPService.cpp @@ -44,6 +44,29 @@ LogModule* GetGMPLog() { return sLog; } +LogModule* GetGMPLibraryLog() { + static LazyLogModule sLog("GMPLibrary"); + return sLog; +} + +GMPLogLevel GetGMPLibraryLogLevel() { + switch (GetGMPLibraryLog()->Level()) { + case LogLevel::Disabled: + return kGMPLogQuiet; + case LogLevel::Error: + return kGMPLogError; + case LogLevel::Warning: + return kGMPLogWarning; + case LogLevel::Info: + return kGMPLogInfo; + case LogLevel::Debug: + return kGMPLogDebug; + case LogLevel::Verbose: + return kGMPLogDetail; + } + return kGMPLogInvalid; +} + #ifdef __CLASS__ # undef __CLASS__ #endif diff --git a/dom/media/gmp/GMPService.h b/dom/media/gmp/GMPService.h index 4633677c6daf..8f4271812eb4 100644 --- a/dom/media/gmp/GMPService.h +++ b/dom/media/gmp/GMPService.h @@ -8,6 +8,7 @@ #include "GMPContentParent.h" #include "GMPCrashHelper.h" +#include "gmp-video-codec.h" #include "mozIGeckoMediaPluginService.h" #include "mozilla/Atomics.h" #include "mozilla/gmp/GMPTypes.h" @@ -32,6 +33,8 @@ class GMPCrashHelper; class MediaResult; extern LogModule* GetGMPLog(); +extern LogModule* GetGMPLibraryLog(); +extern GMPLogLevel GetGMPLibraryLogLevel(); namespace gmp { diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp index 5229fe8f7141..b6ba9f3c8f74 100644 --- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -662,8 +662,8 @@ void GeckoMediaPluginServiceParent::SendFlushFOGData( ipc::RejectCallback&&>( "GMPParent::SendFlushFOGData", gmp, static_cast && aResolve, - mozilla::ipc::RejectCallback && aReject)>( + mozilla::ipc::ResolveCallback&& aResolve, + mozilla::ipc::RejectCallback&& aReject)>( &GMPParent::SendFlushFOGData), [promise](ipc::ByteBuf&& aValue) { @@ -700,8 +700,8 @@ GeckoMediaPluginServiceParent::TestTriggerMetrics() { ipc::RejectCallback&&>( "GMPParent::SendTestTriggerMetrics", gmp, static_cast && aResolve, - mozilla::ipc::RejectCallback && aReject)>( + mozilla::ipc::ResolveCallback&& aResolve, + mozilla::ipc::RejectCallback&& aReject)>( &PGMPParent::SendTestTriggerMetrics), [promise](bool aValue) { diff --git a/dom/media/gmp/GMPTypes.ipdlh b/dom/media/gmp/GMPTypes.ipdlh index d0449a80d9ed..6cb37b60688b 100644 --- a/dom/media/gmp/GMPTypes.ipdlh +++ b/dom/media/gmp/GMPTypes.ipdlh @@ -63,6 +63,7 @@ struct GMPVideoi420FrameData { int32_t mWidth; int32_t mHeight; uint64_t mTimestamp; // microseconds + uint64_t? mUpdatedTimestamp; // microseconds uint64_t mDuration; // microseconds }; diff --git a/dom/media/gmp/GMPVideoDecoderParent.cpp b/dom/media/gmp/GMPVideoDecoderParent.cpp index 4732a99930cf..09230251f46f 100644 --- a/dom/media/gmp/GMPVideoDecoderParent.cpp +++ b/dom/media/gmp/GMPVideoDecoderParent.cpp @@ -283,9 +283,19 @@ void GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy) { mozilla::ipc::IPCResult GMPVideoDecoderParent::RecvDecoded( const GMPVideoi420FrameData& aDecodedFrame) { --mFrameCount; - GMP_LOG_VERBOSE("GMPVideoDecoderParent[%p]::RecvDecoded() timestamp=%" PRId64 - " frameCount=%d", - this, aDecodedFrame.mTimestamp(), mFrameCount); + if (aDecodedFrame.mUpdatedTimestamp() && + aDecodedFrame.mUpdatedTimestamp().value() != aDecodedFrame.mTimestamp()) { + GMP_LOG_VERBOSE( + "GMPVideoDecoderParent[%p]::RecvDecoded() timestamp=[%" PRId64 + " -> %" PRId64 "] frameCount=%d", + this, aDecodedFrame.mTimestamp(), + aDecodedFrame.mUpdatedTimestamp().value(), mFrameCount); + } else { + GMP_LOG_VERBOSE( + "GMPVideoDecoderParent[%p]::RecvDecoded() timestamp=%" PRId64 + " frameCount=%d", + this, aDecodedFrame.mTimestamp(), mFrameCount); + } if (mCallback) { if (GMPVideoi420FrameImpl::CheckFrameData(aDecodedFrame)) { diff --git a/dom/media/gmp/GMPVideoi420FrameImpl.cpp b/dom/media/gmp/GMPVideoi420FrameImpl.cpp index 051838b985c3..1ca3e8123fc7 100644 --- a/dom/media/gmp/GMPVideoi420FrameImpl.cpp +++ b/dom/media/gmp/GMPVideoi420FrameImpl.cpp @@ -28,6 +28,7 @@ GMPVideoi420FrameImpl::GMPVideoi420FrameImpl( mWidth(aFrameData.mWidth()), mHeight(aFrameData.mHeight()), mTimestamp(aFrameData.mTimestamp()), + mUpdatedTimestamp(aFrameData.mUpdatedTimestamp()), mDuration(aFrameData.mDuration()) { MOZ_ASSERT(aHost); } @@ -41,6 +42,7 @@ bool GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData) { aFrameData.mWidth() = mWidth; aFrameData.mHeight() = mHeight; aFrameData.mTimestamp() = mTimestamp; + aFrameData.mUpdatedTimestamp() = mUpdatedTimestamp; aFrameData.mDuration() = mDuration; return true; } @@ -158,6 +160,7 @@ GMPErr GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight, mWidth = aWidth; mHeight = aHeight; mTimestamp = 0ll; + mUpdatedTimestamp.reset(); mDuration = 0ll; return GMPNoErr; @@ -220,6 +223,7 @@ GMPErr GMPVideoi420FrameImpl::CopyFrame(const GMPVideoi420Frame& aFrame) { mWidth = f.mWidth; mHeight = f.mHeight; mTimestamp = f.mTimestamp; + mUpdatedTimestamp = f.mUpdatedTimestamp; mDuration = f.mDuration; return GMPNoErr; @@ -233,6 +237,7 @@ void GMPVideoi420FrameImpl::SwapFrame(GMPVideoi420Frame* aFrame) { std::swap(mWidth, f->mWidth); std::swap(mHeight, f->mHeight); std::swap(mTimestamp, f->mTimestamp); + std::swap(mUpdatedTimestamp, f->mUpdatedTimestamp); std::swap(mDuration, f->mDuration); } @@ -296,6 +301,14 @@ void GMPVideoi420FrameImpl::SetTimestamp(uint64_t aTimestamp) { uint64_t GMPVideoi420FrameImpl::Timestamp() const { return mTimestamp; } +void GMPVideoi420FrameImpl::SetUpdatedTimestamp(uint64_t aTimestamp) { + mUpdatedTimestamp = Some(aTimestamp); +} + +uint64_t GMPVideoi420FrameImpl::UpdatedTimestamp() const { + return mUpdatedTimestamp ? *mUpdatedTimestamp : mTimestamp; +} + void GMPVideoi420FrameImpl::SetDuration(uint64_t aDuration) { mDuration = aDuration; } diff --git a/dom/media/gmp/GMPVideoi420FrameImpl.h b/dom/media/gmp/GMPVideoi420FrameImpl.h index 3c78a246911f..53377beb8d44 100644 --- a/dom/media/gmp/GMPVideoi420FrameImpl.h +++ b/dom/media/gmp/GMPVideoi420FrameImpl.h @@ -9,6 +9,7 @@ #include "gmp-video-frame-i420.h" #include "mozilla/ipc/Shmem.h" #include "GMPVideoPlaneImpl.h" +#include "mozilla/Maybe.h" namespace mozilla::gmp { @@ -53,6 +54,8 @@ class GMPVideoi420FrameImpl : public GMPVideoi420Frame { int32_t Height() const override; void SetTimestamp(uint64_t aTimestamp) override; uint64_t Timestamp() const override; + void SetUpdatedTimestamp(uint64_t aTimestamp) override; + uint64_t UpdatedTimestamp() const override; void SetDuration(uint64_t aDuration) override; uint64_t Duration() const override; bool IsZeroSize() const override; @@ -68,6 +71,7 @@ class GMPVideoi420FrameImpl : public GMPVideoi420Frame { int32_t mWidth; int32_t mHeight; uint64_t mTimestamp; + Maybe mUpdatedTimestamp; uint64_t mDuration; }; diff --git a/dom/media/gmp/gmp-api/gmp-video-codec.h b/dom/media/gmp/gmp-api/gmp-video-codec.h index 81c32e63721a..c426fc994a9f 100644 --- a/dom/media/gmp/gmp-api/gmp-video-codec.h +++ b/dom/media/gmp/gmp-api/gmp-video-codec.h @@ -134,10 +134,24 @@ enum GMPVideoCodecMode { kGMPCodecModeInvalid // Should always be last. }; +enum GMPLogLevel { + kGMPLogDefault, + kGMPLogQuiet, + kGMPLogError, + kGMPLogWarning, + kGMPLogInfo, + kGMPLogDebug, + kGMPLogDetail, + kGMPLogInvalid // Should always be last. +}; + enum GMPApiVersion { kGMPVersion32 = 1, // leveraging that V32 had mCodecType first, and only supported H264 kGMPVersion33 = 33, + + // Adds GMPVideoi420Frame::SetUpdatedTimestamp/UpdatedTimestamp + kGMPVersion34 = 34, }; struct GMPVideoCodec { @@ -163,6 +177,9 @@ struct GMPVideoCodec { GMPSimulcastStream mSimulcastStream[kGMPMaxSimulcastStreams]; GMPVideoCodecMode mMode; + + bool mUseThreadedDecode; + GMPLogLevel mLogLevel; }; // Either single encoded unit, or multiple units separated by 8/16/24/32 diff --git a/dom/media/gmp/gmp-api/gmp-video-frame-i420.h b/dom/media/gmp/gmp-api/gmp-video-frame-i420.h index 6899d9c19cb9..bf64b9090327 100644 --- a/dom/media/gmp/gmp-api/gmp-video-frame-i420.h +++ b/dom/media/gmp/gmp-api/gmp-video-frame-i420.h @@ -129,6 +129,14 @@ class GMPVideoi420Frame : public GMPVideoFrame { // Reset underlying plane buffers sizes to 0. This function doesn't clear // memory. virtual void ResetSize() = 0; + + // -- These methods have been added in kGMPVersion34 -- + + // Set an updated frame timestamp (microseconds) from decoder + virtual void SetUpdatedTimestamp(uint64_t aTimestamp) = 0; + + // Get an updated frame timestamp (microseconds) from decoder + virtual uint64_t UpdatedTimestamp() const = 0; }; #endif // GMP_VIDEO_FRAME_I420_h_ diff --git a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp index 8087f3d060fc..218366ef7bf3 100644 --- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp +++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp @@ -10,8 +10,10 @@ #include "GMPLog.h" #include "MediaData.h" #include "mozilla/EndianUtils.h" +#include "mozilla/StaticPrefs_media.h" #include "nsServiceManagerUtils.h" #include "AnnexB.h" +#include "H264.h" #include "MP4Decoder.h" #include "prsystem.h" #include "VPXDecoder.h" @@ -74,19 +76,33 @@ void GMPVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame) { b.mYUVColorSpace = DefaultColorSpace({decodedFrame->Width(), decodedFrame->Height()}); - Maybe streamOffset = - mStreamOffsets.Extract(decodedFrame->Timestamp()); - if (NS_WARN_IF(!streamOffset)) { - streamOffset.emplace(mLastStreamOffset); + UniquePtr sampleData; + if (auto entryHandle = mSamples.Lookup(decodedFrame->Timestamp())) { + sampleData = std::move(entryHandle.Data()); + entryHandle.Remove(); + } else { + GMP_LOG_DEBUG( + "GMPVideoDecoder::Decoded(this=%p) missing sample metadata for " + "time %" PRIu64, + this, decodedFrame->Timestamp()); + if (mSamples.IsEmpty()) { + // If we have no remaining samples in the table, then we have processed + // all outstanding decode requests. + ProcessReorderQueue(mDecodePromise, __func__); + } + return; } + MOZ_ASSERT(sampleData); + gfx::IntRect pictureRegion(0, 0, decodedFrame->Width(), decodedFrame->Height()); RefPtr v = VideoData::CreateAndCopyData( - mConfig, mImageContainer, *streamOffset, - media::TimeUnit::FromMicroseconds(decodedFrame->Timestamp()), - media::TimeUnit::FromMicroseconds(decodedFrame->Duration()), b, false, - media::TimeUnit::FromMicroseconds(-1), pictureRegion, mKnowsCompositor); + mConfig, mImageContainer, sampleData->mOffset, + media::TimeUnit::FromMicroseconds(decodedFrame->UpdatedTimestamp()), + media::TimeUnit::FromMicroseconds(decodedFrame->Duration()), b, + sampleData->mKeyframe, media::TimeUnit::FromMicroseconds(-1), + pictureRegion, mKnowsCompositor); RefPtr self = this; if (v) { mPerformanceRecorder.Record(static_cast(decodedFrame->Timestamp()), @@ -99,15 +115,16 @@ void GMPVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame) { aStage.SetColorRange(b.mColorRange); }); - mDecodedData.AppendElement(std::move(v)); + mReorderQueue.Push(std::move(v)); - if (mStreamOffsets.IsEmpty()) { - // If we have no remaining offsets in the table, then we have processed + if (mSamples.IsEmpty()) { + // If we have no remaining samples in the table, then we have processed // all outstanding decode requests. - mDecodePromise.ResolveIfExists(std::move(mDecodedData), __func__); + ProcessReorderQueue(mDecodePromise, __func__); } } else { - mDecodedData.Clear(); + mReorderQueue.Clear(); + mSamples.Clear(); mDecodePromise.RejectIfExists( MediaResult(NS_ERROR_OUT_OF_MEMORY, RESULT_DETAIL("CallBack::CreateAndCopyData")), @@ -128,17 +145,15 @@ void GMPVideoDecoder::ReceivedDecodedFrame(const uint64_t aPictureId) { void GMPVideoDecoder::InputDataExhausted() { GMP_LOG_DEBUG("GMPVideoDecoder::InputDataExhausted"); MOZ_ASSERT(IsOnGMPThread()); - mStreamOffsets.Clear(); - mDecodePromise.ResolveIfExists(std::move(mDecodedData), __func__); - mDecodedData = DecodedData(); + mSamples.Clear(); + ProcessReorderQueue(mDecodePromise, __func__); } void GMPVideoDecoder::DrainComplete() { GMP_LOG_DEBUG("GMPVideoDecoder::DrainComplete"); MOZ_ASSERT(IsOnGMPThread()); - mStreamOffsets.Clear(); - mDrainPromise.ResolveIfExists(std::move(mDecodedData), __func__); - mDecodedData = DecodedData(); + mSamples.Clear(); + ProcessReorderQueue(mDrainPromise, __func__); } void GMPVideoDecoder::ResetComplete() { @@ -165,6 +180,25 @@ void GMPVideoDecoder::Terminated() { Error(GMPErr::GMPAbortedErr); } +void GMPVideoDecoder::ProcessReorderQueue( + MozPromiseHolder& aPromise, const char* aMethodName) { + if (aPromise.IsEmpty()) { + return; + } + + DecodedData results; + size_t availableFrames = mReorderQueue.Length(); + if (availableFrames > mMaxRefFrames) { + size_t resolvedFrames = availableFrames - mMaxRefFrames; + results.SetCapacity(resolvedFrames); + do { + results.AppendElement(mReorderQueue.Pop()); + } while (--resolvedFrames > 0); + } + + aPromise.ResolveIfExists(std::move(results), aMethodName); +} + GMPVideoDecoder::GMPVideoDecoder(const GMPVideoDecoderParams& aParams) : mConfig(aParams.mConfig), mGMP(nullptr), @@ -173,7 +207,8 @@ GMPVideoDecoder::GMPVideoDecoder(const GMPVideoDecoderParams& aParams) mCrashHelper(aParams.mCrashHelper), mImageContainer(aParams.mImageContainer), mKnowsCompositor(aParams.mKnowsCompositor), - mTrackingId(aParams.mTrackingId) {} + mTrackingId(aParams.mTrackingId), + mCanDecodeBatch(StaticPrefs::media_gmp_decoder_decode_batch()) {} void GMPVideoDecoder::InitTags(nsTArray& aTags) { if (MP4Decoder::IsH264(mConfig.mMimeType)) { @@ -252,7 +287,7 @@ void GMPVideoDecoder::GMPInitDone(GMPVideoDecoderProxy* aGMP, GMPVideoCodec codec; memset(&codec, 0, sizeof(codec)); - codec.mGMPApiVersion = kGMPVersion33; + codec.mGMPApiVersion = kGMPVersion34; nsTArray codecSpecific; if (MP4Decoder::IsH264(mConfig.mMimeType)) { codec.mCodecType = kGMPVideoCodecH264; @@ -262,6 +297,7 @@ void GMPVideoDecoder::GMPInitDone(GMPVideoDecoderProxy* aGMP, // OpenH264 expects pseudo-AVCC, but others must be passed // AnnexB for H264. mConvertToAnnexB = !isOpenH264; + mMaxRefFrames = H264::ComputeMaxRefFrames(mConfig.mExtraData); } else if (VPXDecoder::IsVP8(mConfig.mMimeType)) { codec.mCodecType = kGMPVideoCodecVP8; } else if (VPXDecoder::IsVP9(mConfig.mMimeType)) { @@ -274,6 +310,8 @@ void GMPVideoDecoder::GMPInitDone(GMPVideoDecoderProxy* aGMP, } codec.mWidth = mConfig.mImage.width; codec.mHeight = mConfig.mImage.height; + codec.mUseThreadedDecode = StaticPrefs::media_gmp_decoder_multithreaded(); + codec.mLogLevel = GetGMPLibraryLogLevel(); nsresult rv = aGMP->InitDecode(codec, codecSpecific, this, PR_GetNumberOfProcessors()); @@ -368,11 +406,12 @@ RefPtr GMPVideoDecoder::Decode( } // If we have multiple outstanding frames, we need to track which offset - // belongs to which frame. - mLastStreamOffset = sample->mOffset; - mStreamOffsets.WithEntryHandle(frameTimestamp, [&](auto entryHandle) { - MOZ_ASSERT(!entryHandle, "Duplicate sample with matching timestamp!"); - entryHandle.InsertOrUpdate(sample->mOffset); + // belongs to which frame. During seek, it is possible to get the same frame + // requested twice, if the old frame is still outstanding. We will simply drop + // the extra decoded frame and request more input if the last outstanding. + mSamples.WithEntryHandle(frameTimestamp, [&](auto entryHandle) { + auto sampleData = MakeUnique(sample); + entryHandle.InsertOrUpdate(std::move(sampleData)); }); return p; diff --git a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h index fd40f13f15c2..50d001c6d1b1 100644 --- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h +++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h @@ -14,8 +14,9 @@ # include "MediaInfo.h" # include "PerformanceRecorder.h" # include "PlatformDecoderModule.h" +# include "ReorderQueue.h" # include "mozIGeckoMediaPluginService.h" -# include "nsHashtablesFwd.h" +# include "nsClassHashtable.h" namespace mozilla { @@ -31,9 +32,9 @@ struct MOZ_STACK_CLASS GMPVideoDecoderParams { DDLoggedTypeDeclNameAndBase(GMPVideoDecoder, MediaDataDecoder); -class GMPVideoDecoder : public MediaDataDecoder, - public GMPVideoDecoderCallbackProxy, - public DecoderDoctorLifeLogger { +class GMPVideoDecoder final : public MediaDataDecoder, + public GMPVideoDecoderCallbackProxy, + public DecoderDoctorLifeLogger { public: explicit GMPVideoDecoder(const GMPVideoDecoderParams& aParams); @@ -50,6 +51,7 @@ class GMPVideoDecoder : public MediaDataDecoder, return mConvertToAnnexB ? ConversionRequired::kNeedAnnexB : ConversionRequired::kNeedAVCC; } + bool CanDecodeBatch() const override { return mCanDecodeBatch; } // GMPVideoDecoderCallbackProxy // All those methods are called on the GMP thread. @@ -67,6 +69,8 @@ class GMPVideoDecoder : public MediaDataDecoder, virtual nsCString GetNodeId(); virtual GMPUniquePtr CreateFrame(MediaRawData* aSample); virtual const VideoInfo& GetConfig() const; + void ProcessReorderQueue(MozPromiseHolder& aPromise, + const char* aMethodName); private: class GMPInitDoneCallback : public GetGMPVideoDecoderCallback { @@ -91,18 +95,28 @@ class GMPVideoDecoder : public MediaDataDecoder, MozPromiseHolder mInitPromise; RefPtr mCrashHelper; - int64_t mLastStreamOffset = 0; - nsTHashMap mStreamOffsets; + struct SampleMetadata { + explicit SampleMetadata(MediaRawData* aSample) + : mOffset(aSample->mOffset), mKeyframe(aSample->mKeyframe) {} + int64_t mOffset; + bool mKeyframe; + }; + + nsClassHashtable mSamples; RefPtr mImageContainer; RefPtr mKnowsCompositor; PerformanceRecorderMulti mPerformanceRecorder; const Maybe mTrackingId; + uint32_t mMaxRefFrames = 0; + ReorderQueue mReorderQueue; + MozPromiseHolder mDecodePromise; MozPromiseHolder mDrainPromise; MozPromiseHolder mFlushPromise; DecodedData mDecodedData; bool mConvertToAnnexB = false; + bool mCanDecodeBatch = false; }; } // namespace mozilla diff --git a/dom/media/webrtc/libwebrtcglue/WebrtcGmpVideoCodec.cpp b/dom/media/webrtc/libwebrtcglue/WebrtcGmpVideoCodec.cpp index 800e887d4a0d..f894fda2b289 100644 --- a/dom/media/webrtc/libwebrtcglue/WebrtcGmpVideoCodec.cpp +++ b/dom/media/webrtc/libwebrtcglue/WebrtcGmpVideoCodec.cpp @@ -141,7 +141,7 @@ int32_t WebrtcGmpVideoEncoder::InitEncode( GMPVideoCodec codecParams; memset(&codecParams, 0, sizeof(codecParams)); - codecParams.mGMPApiVersion = 33; + codecParams.mGMPApiVersion = kGMPVersion34; codecParams.mStartBitrate = aCodecSettings->startBitrate; codecParams.mMinBitrate = aCodecSettings->minBitrate; codecParams.mMaxBitrate = aCodecSettings->maxBitrate; @@ -730,7 +730,7 @@ int32_t WebrtcGmpVideoDecoder::GmpInitDone(GMPVideoDecoderProxy* aGMP, // Bug XXXXXX: transfer settings from codecSettings to codec. GMPVideoCodec codec; memset(&codec, 0, sizeof(codec)); - codec.mGMPApiVersion = 33; + codec.mGMPApiVersion = kGMPVersion34; // XXX this is currently a hack // GMPVideoCodecUnion codecSpecific; @@ -1009,7 +1009,7 @@ void WebrtcGmpVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame) { .set_video_frame_buffer(video_frame_buffer) .set_timestamp_rtp( // round up - (aDecodedFrame->Timestamp() * 90ll + 999) / 1000) + (aDecodedFrame->UpdatedTimestamp() * 90ll + 999) / 1000) .build(); mPerformanceRecorder.Record( static_cast(aDecodedFrame->Timestamp()), diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 0a7e1de51154..6df2309fa784 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -10337,12 +10337,24 @@ value: 2500 mirror: always +# True if we want to decode in batches. +- name: media.gmp.decoder.decode_batch + type: RelaxedAtomicBool + value: false + mirror: always + # True if we allow use of any decoders found in GMP plugins. - name: media.gmp.decoder.enabled type: RelaxedAtomicBool value: false mirror: always +# True if we want to request the multithreaded GMP decoder. +- name: media.gmp.decoder.multithreaded + type: RelaxedAtomicBool + value: false + mirror: always + # True if we want to try using the GMP plugin decoders first. - name: media.gmp.decoder.preferred type: RelaxedAtomicBool