diff --git a/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp b/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp index f6c509cf09..01abfd84e4 100644 --- a/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp +++ b/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp @@ -15,7 +15,7 @@ #include "mozilla/dom/BluetoothMapParametersBinding.h" #include "mozilla/dom/ipc/BlobParent.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/dom/File.h" #include "mozilla/RefPtr.h" diff --git a/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp b/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp index 4ea53ae1b5..1c80a3bf22 100644 --- a/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp +++ b/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp @@ -13,7 +13,7 @@ #include "BluetoothUuidHelper.h" #include "mozilla/dom/BluetoothPbapParametersBinding.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/dom/File.h" #include "mozilla/dom/ipc/BlobParent.h" #include "mozilla/RefPtr.h" diff --git a/dom/bluetooth/bluedroid/BluetoothSocketMessageWatcher.cpp b/dom/bluetooth/bluedroid/BluetoothSocketMessageWatcher.cpp index 22a8f19e3d..03f744bbf1 100644 --- a/dom/bluetooth/bluedroid/BluetoothSocketMessageWatcher.cpp +++ b/dom/bluetooth/bluedroid/BluetoothSocketMessageWatcher.cpp @@ -9,7 +9,7 @@ #include #include #include "BluetoothInterface.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "nsClassHashtable.h" BEGIN_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/common/BluetoothCommon.h b/dom/bluetooth/common/BluetoothCommon.h index 0d1b5ba776..56533dacb0 100644 --- a/dom/bluetooth/common/BluetoothCommon.h +++ b/dom/bluetooth/common/BluetoothCommon.h @@ -9,7 +9,7 @@ #include #include "mozilla/Compiler.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Observer.h" #include "mozilla/UniquePtr.h" #include "nsPrintfCString.h" diff --git a/dom/bluetooth/common/ObexBase.h b/dom/bluetooth/common/ObexBase.h index e3f4ee85a5..239030bdbd 100644 --- a/dom/bluetooth/common/ObexBase.h +++ b/dom/bluetooth/common/ObexBase.h @@ -8,7 +8,7 @@ #define mozilla_dom_bluetooth_ObexBase_h #include "BluetoothCommon.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/UniquePtr.h" #include "nsTArray.h" diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 5bf906e4d1..367b916bde 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -84,7 +84,7 @@ #include "mozilla/dom/PBrowserParent.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/dom/TypedArray.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Helpers.h" #include "mozilla/gfx/PathHelpers.h" diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 1087f61de1..50b23e5c83 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -50,7 +50,7 @@ #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ImageData.h" #include "mozilla/dom/ToJSValue.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/RefPtr.h" #include "mozilla/UniquePtrExtensions.h" diff --git a/dom/canvas/WebGLContextTextures.cpp b/dom/canvas/WebGLContextTextures.cpp index 9f0115955d..882fe304e7 100644 --- a/dom/canvas/WebGLContextTextures.cpp +++ b/dom/canvas/WebGLContextTextures.cpp @@ -47,7 +47,7 @@ #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ImageData.h" #include "mozilla/dom/ToJSValue.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" namespace mozilla { diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index d59451ecf7..eadfbffa95 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -21,7 +21,7 @@ #include "mozilla/Attributes.h" #include "mozilla/AppProcessChecker.h" #include "mozilla/AutoRestore.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Hal.h" #include "mozilla/LazyIdleThread.h" #include "mozilla/Maybe.h" diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 2e7e1a5ab1..4259751099 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -23,7 +23,7 @@ #include "js/Date.h" #include "js/StructuredClone.h" #include "KeyPath.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/ErrorResult.h" #include "mozilla/Move.h" #include "mozilla/dom/BindingUtils.h" diff --git a/dom/indexedDB/Key.cpp b/dom/indexedDB/Key.cpp index c7fd28048c..6b168710bb 100644 --- a/dom/indexedDB/Key.cpp +++ b/dom/indexedDB/Key.cpp @@ -12,7 +12,7 @@ #include "js/Date.h" #include "js/Value.h" #include "jsfriendapi.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/FloatingPoint.h" #include "mozIStorageStatement.h" #include "mozIStorageValueArray.h" diff --git a/dom/media/ADTSDecoder.cpp b/dom/media/ADTSDecoder.cpp index 02c5d51ec0..2217fec7e9 100644 --- a/dom/media/ADTSDecoder.cpp +++ b/dom/media/ADTSDecoder.cpp @@ -32,7 +32,6 @@ ADTSDecoder::CreateStateMachine() /* static */ bool ADTSDecoder::IsEnabled() { - PDMFactory::Init(); RefPtr platform = new PDMFactory(); return (platform && platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"), /* DecoderDoctorDiagnostics* */ nullptr)); diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index 8d82d4b122..b71111e796 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -31,7 +31,6 @@ MP3Decoder::CreateStateMachine() { /* static */ bool MP3Decoder::IsEnabled() { - PDMFactory::Init(); RefPtr platform = new PDMFactory(); return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mpeg"), /* DecoderDoctorDiagnostics* */ nullptr); diff --git a/dom/media/MP3Demuxer.cpp b/dom/media/MP3Demuxer.cpp index a96808ba28..b7b87634da 100644 --- a/dom/media/MP3Demuxer.cpp +++ b/dom/media/MP3Demuxer.cpp @@ -10,7 +10,7 @@ #include #include "mozilla/Assertions.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "VideoUtils.h" #include "TimeUnits.h" #include "prenv.h" diff --git a/dom/media/MediaDecoderReaderWrapper.cpp b/dom/media/MediaDecoderReaderWrapper.cpp index ae3b8d6186..0d5ca7187b 100644 --- a/dom/media/MediaDecoderReaderWrapper.cpp +++ b/dom/media/MediaDecoderReaderWrapper.cpp @@ -279,7 +279,7 @@ MediaDecoderReaderWrapper::IsRequestingAudioData() const } bool -MediaDecoderReaderWrapper::IsRequestingVidoeData() const +MediaDecoderReaderWrapper::IsRequestingVideoData() const { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); return mVideoDataRequest.Exists(); diff --git a/dom/media/MediaDecoderReaderWrapper.h b/dom/media/MediaDecoderReaderWrapper.h index 34c2c64b1d..6703262312 100644 --- a/dom/media/MediaDecoderReaderWrapper.h +++ b/dom/media/MediaDecoderReaderWrapper.h @@ -247,7 +247,7 @@ public: void RequestVideoData(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold); bool IsRequestingAudioData() const; - bool IsRequestingVidoeData() const; + bool IsRequestingVideoData() const; RefPtr Seek(SeekTarget aTarget, media::TimeUnit aEndTime); RefPtr WaitForData(MediaData::Type aType); diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 5202e9b040..0ef5f3e482 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -1764,7 +1764,7 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued() return NS_OK; } - if (!IsVideoDecoding() || mReader->IsRequestingVidoeData() || + if (!IsVideoDecoding() || mReader->IsRequestingVideoData() || mVideoWaitRequest.Exists()) { return NS_OK; } @@ -2277,7 +2277,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine() "Don't yet have a strategy for non-heuristic + non-WaitForData"); DispatchDecodeTasksIfNeeded(); MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mReader->IsRequestingAudioData() || mAudioWaitRequest.Exists()); - MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVidoeData() || mVideoWaitRequest.Exists()); + MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVideoData() || mVideoWaitRequest.Exists()); DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, " "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s", OutOfDecodedAudio(), AudioRequestStatus(), @@ -2860,7 +2860,7 @@ const char* MediaDecoderStateMachine::VideoRequestStatus() const { MOZ_ASSERT(OnTaskQueue()); - if (mReader->IsRequestingVidoeData()) { + if (mReader->IsRequestingVideoData()) { MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists()); return "pending"; } else if (mVideoWaitRequest.Exists()) { diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index a6a79b8857..b5a8acdeda 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -60,8 +60,10 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder, VideoFrameContainer* aVideoFrameContainer, layers::LayersBackend aLayersBackend) : MediaDecoderReader(aDecoder) - , mAudio(this, MediaData::AUDIO_DATA, Preferences::GetUint("media.audio-decode-ahead", 2)) - , mVideo(this, MediaData::VIDEO_DATA, Preferences::GetUint("media.video-decode-ahead", 2)) + , mAudio(this, MediaData::AUDIO_DATA, Preferences::GetUint("media.audio-decode-ahead", 2), + Preferences::GetUint("media.audio-max-decode-error", 3)) + , mVideo(this, MediaData::VIDEO_DATA, Preferences::GetUint("media.video-decode-ahead", 2), + Preferences::GetUint("media.video-max-decode-error", 2)) , mDemuxer(aDemuxer) , mDemuxerInitDone(false) , mLastReportedNumDecodedFrames(0) @@ -87,10 +89,6 @@ MediaFormatReader::Shutdown() { MOZ_ASSERT(OnTaskQueue()); - if (HasVideo()) { - ReportDroppedFramesTelemetry(); - } - mDemuxerInitRequest.DisconnectIfExists(); mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__); mSeekPromise.RejectIfExists(NS_ERROR_FAILURE, __func__); @@ -172,7 +170,6 @@ nsresult MediaFormatReader::Init() { MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - PDMFactory::Init(); InitLayersBackendType(); @@ -483,8 +480,8 @@ MediaFormatReader::ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThr } return (nextKeyframe < aTimeThreshold || (mVideo.mTimeThreshold && - mVideo.mTimeThreshold.ref().mTime < aTimeThreshold)) && - nextKeyframe.ToMicroseconds() >= 0; + mVideo.mTimeThreshold.ref().EndTime() < aTimeThreshold)) && + nextKeyframe.ToMicroseconds() >= 0 && !nextKeyframe.IsInfinite(); } RefPtr @@ -496,7 +493,6 @@ MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe, MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests"); MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists() || mVideo.mTimeThreshold.isSome()); - MOZ_DIAGNOSTIC_ASSERT(!mSkipRequest.Exists(), "called mid-skipping"); MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek"); LOGV("RequestVideoData(%d, %lld)", aSkipToNextKeyframe, aTimeThreshold); @@ -541,6 +537,9 @@ MediaFormatReader::OnDemuxFailed(TrackType aTrack, DemuxerFailureReason aFailure decoder.mDemuxRequest.Complete(); switch (aFailure) { case DemuxerFailureReason::END_OF_STREAM: + if (!decoder.mWaitingForData) { + decoder.mNeedDraining = true; + } NotifyEndOfStream(aTrack); break; case DemuxerFailureReason::DEMUXER_ERROR: @@ -552,7 +551,7 @@ MediaFormatReader::OnDemuxFailed(TrackType aTrack, DemuxerFailureReason aFailure } NotifyWaitingForData(aTrack); break; - case DemuxerFailureReason::CANCELED: + case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH; case DemuxerFailureReason::SHUTDOWN: if (decoder.HasPromise()) { decoder.RejectPromise(CANCELED, __func__); @@ -589,11 +588,13 @@ RefPtr MediaFormatReader::RequestAudioData() { MOZ_ASSERT(OnTaskQueue()); - MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking"); - MOZ_DIAGNOSTIC_ASSERT(!mAudio.mSeekRequest.Exists() || - mAudio.mTimeThreshold.isSome()); MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests"); - MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek"); + MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || mSeekPromise.IsEmpty(), + "No sample requests allowed while seeking"); + MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || + !mAudio.mSeekRequest.Exists() || + mAudio.mTimeThreshold.isSome()); + MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || !IsSeeking(), "called mid-seek"); LOGV(""); if (!HasAudio()) { @@ -651,8 +652,7 @@ MediaFormatReader::NotifyNewOutput(TrackType aTrack, MediaData* aSample) } decoder.mOutput.AppendElement(aSample); decoder.mNumSamplesOutput++; - decoder.mNumSamplesOutputTotal++; - decoder.mNumSamplesOutputTotalSinceTelemetry++; + decoder.mNumOfConsecutiveError = 0; ScheduleUpdate(aTrack); } @@ -681,12 +681,12 @@ MediaFormatReader::NotifyDrainComplete(TrackType aTrack) } void -MediaFormatReader::NotifyError(TrackType aTrack) +MediaFormatReader::NotifyError(TrackType aTrack, MediaDataDecoderError aError) { MOZ_ASSERT(OnTaskQueue()); LOGV("%s Decoding error", TrackTypeToStr(aTrack)); auto& decoder = GetDecoderData(aTrack); - decoder.mError = true; + decoder.mError = decoder.HasFatalError() ? decoder.mError : Some(aError); ScheduleUpdate(aTrack); } @@ -708,7 +708,6 @@ MediaFormatReader::NotifyEndOfStream(TrackType aTrack) MOZ_ASSERT(OnTaskQueue()); auto& decoder = GetDecoderData(aTrack); decoder.mDemuxEOS = true; - decoder.mNeedDraining = true; ScheduleUpdate(aTrack); } @@ -730,8 +729,8 @@ MediaFormatReader::NeedInput(DecoderData& aDecoder) // run of input than we input, decoders fire an "input exhausted" callback, // which overrides our "few more samples" threshold. return - !aDecoder.mDraining && - !aDecoder.mError && + !aDecoder.HasPendingDrain() && + !aDecoder.HasFatalError() && aDecoder.mDecodingRequested && !aDecoder.mDemuxRequest.Exists() && !aDecoder.HasInternalSeekPending() && @@ -781,13 +780,19 @@ MediaFormatReader::UpdateReceivedNewData(TrackType aTrack) // Nothing more to do until this operation complete. return true; } + + if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) { + LOGV("Skipping in progress, nothing more to do"); + return true; + } + if (decoder.mDemuxRequest.Exists()) { // We may have pending operations to process, so we want to continue // after UpdateReceivedNewData returns. return false; } - if (decoder.mDrainComplete || decoder.mDraining) { + if (decoder.HasPendingDrain()) { // We do not want to clear mWaitingForData or mDemuxEOS while // a drain is in progress in order to properly complete the operation. return false; @@ -809,17 +814,21 @@ MediaFormatReader::UpdateReceivedNewData(TrackType aTrack) } decoder.mWaitingForData = false; - if (decoder.mError) { + if (decoder.HasFatalError()) { return false; } - if (!mSeekPromise.IsEmpty()) { + if (!mSeekPromise.IsEmpty() && + (!IsVideoSeeking() || aTrack == TrackInfo::kVideoTrack)) { MOZ_ASSERT(!decoder.HasPromise()); - MOZ_DIAGNOSTIC_ASSERT(!mAudio.mTimeThreshold && !mVideo.mTimeThreshold, + MOZ_DIAGNOSTIC_ASSERT((IsVideoSeeking() || !mAudio.mTimeThreshold) && + !mVideo.mTimeThreshold, "InternalSeek must have been aborted when Seek was first called"); - MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasWaitingPromise() && !mVideo.HasWaitingPromise(), + MOZ_DIAGNOSTIC_ASSERT((IsVideoSeeking() || !mAudio.HasWaitingPromise()) && + !mVideo.HasWaitingPromise(), "Waiting promises must have been rejected when Seek was first called"); - if (mVideo.mSeekRequest.Exists() || mAudio.mSeekRequest.Exists()) { + if (mVideo.mSeekRequest.Exists() || + (!IsVideoSeeking() && mAudio.mSeekRequest.Exists())) { // Already waiting for a seek to complete. Nothing more to do. return true; } @@ -922,9 +931,6 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack, LOG("%s stream id has changed from:%d to:%d, draining decoder.", TrackTypeToStr(aTrack), decoder.mLastStreamSourceID, info->GetID()); - if (aTrack == TrackType::kVideoTrack) { - ReportDroppedFramesTelemetry(); - } decoder.mNeedDraining = true; decoder.mNextStreamSourceID = Some(info->GetID()); ScheduleUpdate(aTrack); @@ -945,10 +951,13 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack, decoder.mQueuedSamples.AppendElements(Move(samples)); NotifyDecodingRequested(aTrack); } else { + TimeInterval time = + TimeInterval(TimeUnit::FromMicroseconds(sample->mTime), + TimeUnit::FromMicroseconds(sample->GetEndTime())); InternalSeekTarget seekTarget = - decoder.mTimeThreshold.refOr(InternalSeekTarget(TimeUnit::FromMicroseconds(sample->mTime), false)); + decoder.mTimeThreshold.refOr(InternalSeekTarget(time, false)); LOG("Stream change occurred on a non-keyframe. Seeking to:%lld", - seekTarget.mTime.ToMicroseconds()); + sample->mTime); InternalSeek(aTrack, seekTarget); } return; @@ -988,14 +997,14 @@ MediaFormatReader::InternalSeek(TrackType aTrack, const InternalSeekTarget& aTar { MOZ_ASSERT(OnTaskQueue()); LOG("%s internal seek to %f", - TrackTypeToStr(aTrack), aTarget.mTime.ToSeconds()); + TrackTypeToStr(aTrack), aTarget.Time().ToSeconds()); auto& decoder = GetDecoderData(aTrack); decoder.Flush(); decoder.ResetDemuxer(); decoder.mTimeThreshold = Some(aTarget); RefPtr self = this; - decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().mTime) + decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time()) ->Then(OwnerThread(), __func__, [self, aTrack] (media::TimeUnit aTime) { auto& decoder = self->GetDecoderData(aTrack); @@ -1016,7 +1025,7 @@ MediaFormatReader::InternalSeek(TrackType aTrack, const InternalSeekTarget& aTar decoder.mTimeThreshold.reset(); self->NotifyEndOfStream(aTrack); break; - case DemuxerFailureReason::CANCELED: + case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH; case DemuxerFailureReason::SHUTDOWN: decoder.mTimeThreshold.reset(); break; @@ -1071,6 +1080,11 @@ MediaFormatReader::Update(TrackType aTrack) return; } + if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) { + LOGV("Skipping in progress, nothing more to do"); + return; + } + if (UpdateReceivedNewData(aTrack)) { LOGV("Nothing more to do"); return; @@ -1095,23 +1109,32 @@ MediaFormatReader::Update(TrackType aTrack) RefPtr& output = decoder.mOutput[0]; InternalSeekTarget target = decoder.mTimeThreshold.ref(); media::TimeUnit time = media::TimeUnit::FromMicroseconds(output->mTime); - if (time >= target.mTime) { + if (time >= target.Time()) { // We have reached our internal seek target. decoder.mTimeThreshold.reset(); } - if (time < target.mTime || (target.mDropTarget && time == target.mTime)) { + if (time < target.Time() || (target.mDropTarget && target.Contains(time))) { LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)", TrackTypeToStr(aTrack), media::TimeUnit::FromMicroseconds(output->mTime).ToSeconds(), - target.mTime.ToSeconds(), + target.Time().ToSeconds(), output->mKeyframe); decoder.mOutput.RemoveElementAt(0); + decoder.mSizeOfQueue -= 1; } } if (decoder.HasPromise()) { needOutput = true; if (decoder.mOutput.Length()) { + RefPtr output = decoder.mOutput[0]; + decoder.mOutput.RemoveElementAt(0); + decoder.mSizeOfQueue -= 1; + decoder.mLastSampleTime = + Some(TimeInterval(TimeUnit::FromMicroseconds(output->mTime), + TimeUnit::FromMicroseconds(output->GetEndTime()))); + decoder.mNumSamplesOutputTotal++; + ReturnOutput(output, aTrack); // We have a decoded sample ready to be returned. if (aTrack == TrackType::kVideoTrack) { uint64_t delta = @@ -1122,13 +1145,7 @@ MediaFormatReader::Update(TrackType aTrack) mVideo.mIsHardwareAccelerated = mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error); } - RefPtr output = decoder.mOutput[0]; - decoder.mOutput.RemoveElementAt(0); - decoder.mSizeOfQueue -= 1; - decoder.mLastSampleTime = - Some(media::TimeUnit::FromMicroseconds(output->mTime)); - ReturnOutput(output, aTrack); - } else if (decoder.mError) { + } else if (decoder.HasFatalError()) { LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack)); decoder.RejectPromise(DECODE_ERROR, __func__); return; @@ -1146,7 +1163,7 @@ MediaFormatReader::Update(TrackType aTrack) // Set up the internal seek machinery to be able to resume from the // last sample decoded. LOG("Seeking to last sample time: %lld", - decoder.mLastSampleTime.ref().ToMicroseconds()); + decoder.mLastSampleTime.ref().mStart.ToMicroseconds()); InternalSeek(aTrack, InternalSeekTarget(decoder.mLastSampleTime.ref(), true)); } if (!decoder.mReceivedNewData) { @@ -1161,6 +1178,14 @@ MediaFormatReader::Update(TrackType aTrack) LOGV("Nothing more to do"); return; } + } else if (decoder.mDemuxEOS && !decoder.mNeedDraining && + !decoder.HasPendingDrain() && decoder.mQueuedSamples.IsEmpty()) { + // It is possible to transition from WAITING_FOR_DATA directly to EOS + // state during the internal seek; in which case no draining would occur. + // There is no more samples left to be decoded and we are already in + // EOS state. We can immediately reject the data promise. + LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack)); + decoder.RejectPromise(END_OF_STREAM, __func__); } } @@ -1169,6 +1194,23 @@ MediaFormatReader::Update(TrackType aTrack) return; } + if (decoder.mError && + decoder.mError.ref() == MediaDataDecoderError::DECODE_ERROR) { + decoder.mError.reset(); + if (++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) { + NotifyError(aTrack); + return; + } + LOG("%s decoded error count %d", TrackTypeToStr(aTrack), + decoder.mNumOfConsecutiveError); + media::TimeUnit nextKeyframe; + if (aTrack == TrackType::kVideoTrack && !decoder.HasInternalSeekPending() && + NS_SUCCEEDED(decoder.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe))) { + SkipVideoDemuxToNextKeyFrame(decoder.mLastSampleTime.refOr(TimeInterval()).Length()); + return; + } + } + bool needInput = NeedInput(decoder); LOGV("Update(%s) ni=%d no=%d ie=%d, in:%llu out:%llu qs=%u pending:%u waiting:%d ahead:%d sid:%u", @@ -1284,15 +1326,17 @@ MediaFormatReader::ResetDecode(TargetQueues aQueues) mSkipRequest.DisconnectIfExists(); // Do the same for any data wait promises. - mAudio.mWaitingPromise.RejectIfExists(WaitForDataRejectValue(MediaData::AUDIO_DATA, WaitForDataRejectValue::CANCELED), __func__); + if (aQueues == AUDIO_VIDEO) { + mAudio.mWaitingPromise.RejectIfExists(WaitForDataRejectValue(MediaData::AUDIO_DATA, WaitForDataRejectValue::CANCELED), __func__); + } mVideo.mWaitingPromise.RejectIfExists(WaitForDataRejectValue(MediaData::VIDEO_DATA, WaitForDataRejectValue::CANCELED), __func__); // Reset miscellaneous seeking state. mPendingSeekTime.reset(); - ResetDemuxers(); - if (HasVideo()) { + mVideo.ResetDemuxer(); + mVideo.ResetState(); Reset(TrackInfo::kVideoTrack); if (mVideo.HasPromise()) { mVideo.RejectPromise(CANCELED, __func__); @@ -1300,6 +1344,8 @@ MediaFormatReader::ResetDecode(TargetQueues aQueues) } if (HasAudio() && aQueues == AUDIO_VIDEO) { + mAudio.ResetDemuxer(); + mAudio.ResetState(); Reset(TrackInfo::kAudioTrack); if (mAudio.HasPromise()) { mAudio.RejectPromise(CANCELED, __func__); @@ -1308,32 +1354,19 @@ MediaFormatReader::ResetDecode(TargetQueues aQueues) return MediaDecoderReader::ResetDecode(aQueues); } -void -MediaFormatReader::ResetDemuxers() -{ - if (HasVideo()) { - mVideo.ResetDemuxer(); - mVideo.ResetState(); - } - if (HasAudio()) { - mAudio.ResetDemuxer(); - mAudio.ResetState(); - } -} - void MediaFormatReader::Output(TrackType aTrack, MediaData* aSample) { - LOGV("Decoded %s sample time=%lld timecode=%lld kf=%d dur=%lld", - TrackTypeToStr(aTrack), aSample->mTime, aSample->mTimecode, - aSample->mKeyframe, aSample->mDuration); - if (!aSample) { NS_WARNING("MediaFormatReader::Output() passed a null sample"); Error(aTrack); return; } + LOGV("Decoded %s sample time=%lld timecode=%lld kf=%d dur=%lld", + TrackTypeToStr(aTrack), aSample->mTime, aSample->mTimecode, + aSample->mKeyframe, aSample->mDuration); + RefPtr task = NewRunnableMethod( this, &MediaFormatReader::NotifyNewOutput, aTrack, aSample); @@ -1359,11 +1392,11 @@ MediaFormatReader::InputExhausted(TrackType aTrack) } void -MediaFormatReader::Error(TrackType aTrack) +MediaFormatReader::Error(TrackType aTrack, MediaDataDecoderError aError) { RefPtr task = - NewRunnableMethod( - this, &MediaFormatReader::NotifyError, aTrack); + NewRunnableMethod( + this, &MediaFormatReader::NotifyError, aTrack, aError); OwnerThread()->Dispatch(task.forget()); } @@ -1381,34 +1414,41 @@ MediaFormatReader::Reset(TrackType aTrack) LOG("Reset(%s) END", TrackTypeToStr(aTrack)); } +void +MediaFormatReader::DropDecodedSamples(TrackType aTrack) +{ + MOZ_ASSERT(OnTaskQueue()); + auto& decoder = GetDecoderData(aTrack); + size_t lengthDecodedQueue = decoder.mOutput.Length(); + if (lengthDecodedQueue && decoder.mTimeThreshold.isSome()) { + TimeUnit time = + TimeUnit::FromMicroseconds(decoder.mOutput.LastElement()->mTime); + if (time >= decoder.mTimeThreshold.ref().Time()) { + // We would have reached our internal seek target. + decoder.mTimeThreshold.reset(); + } + } + decoder.mOutput.Clear(); + decoder.mSizeOfQueue -= lengthDecodedQueue; + if (aTrack == TrackInfo::kVideoTrack && mDecoder) { + mDecoder->NotifyDecodedFrames(0, 0, lengthDecodedQueue); + } +} + void MediaFormatReader::SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold) { MOZ_ASSERT(OnTaskQueue()); - MOZ_ASSERT(mVideo.HasPromise()); LOG("Skipping up to %lld", aTimeThreshold.ToMicroseconds()); - // Cancel any pending demux request and pending demuxed samples. - mVideo.mDemuxRequest.DisconnectIfExists(); - - // I think it's still possible for an output to have been sent from the decoder - // and is currently sitting in our event queue waiting to be processed. The following - // flush won't clear it, and when we return to the event loop it'll be added to our - // output queue and be used. - // This code will count that as dropped, which was the intent, but not quite true. - mDecoder->NotifyDecodedFrames(0, 0, SizeOfVideoQueueInFrames()); - - if (mVideo.mTimeThreshold) { - LOGV("Internal Seek pending, cancelling it"); - } - Reset(TrackInfo::kVideoTrack); - - if (mVideo.mError) { - // We have flushed the decoder, and we are in error state, we can - // immediately reject the promise as there is nothing more to do. - mVideo.RejectPromise(DECODE_ERROR, __func__); - return; - } + // We've reached SkipVideoDemuxToNextKeyFrame when our decoding is late. + // As such we can drop all already decoded samples and discard all pending + // samples. + // TODO: Ideally we should set mOutputRequested to false so that all pending + // frames are dropped too. However, we can't do such thing as the code assumes + // that the decoder just got flushed. Once bug 1257107 land, we could set the + // decoder threshold to the value of currentTime. + DropDecodedSamples(TrackInfo::kVideoTrack); mSkipRequest.Begin(mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold) ->Then(OwnerThread(), __func__, this, @@ -1417,19 +1457,39 @@ MediaFormatReader::SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold) return; } +void +MediaFormatReader::VideoSkipReset(uint32_t aSkipped) +{ + MOZ_ASSERT(OnTaskQueue()); + + // Some frames may have been output by the decoder since we initiated the + // videoskip process and we know they would be late. + DropDecodedSamples(TrackInfo::kVideoTrack); + // Report the pending frames as dropped. + if (mDecoder) { + mDecoder->NotifyDecodedFrames(0, 0, SizeOfVideoQueueInFrames()); + } + + // Cancel any pending demux request and pending demuxed samples. + mVideo.mDemuxRequest.DisconnectIfExists(); + Reset(TrackType::kVideoTrack); + + if (mDecoder) { + mDecoder->NotifyDecodedFrames(aSkipped, 0, aSkipped); + } + + mVideo.mNumSamplesSkippedTotal += aSkipped; +} + void MediaFormatReader::OnVideoSkipCompleted(uint32_t aSkipped) { MOZ_ASSERT(OnTaskQueue()); LOG("Skipping succeeded, skipped %u frames", aSkipped); mSkipRequest.Complete(); - if (mDecoder) { - mDecoder->NotifyDecodedFrames(aSkipped, 0, aSkipped); - } - mVideo.mNumSamplesSkippedTotal += aSkipped; - mVideo.mNumSamplesSkippedTotalSinceTelemetry += aSkipped; - MOZ_ASSERT(!mVideo.mError); // We have flushed the decoder, no frame could - // have been decoded (and as such errored) + + VideoSkipReset(aSkipped); + NotifyDecodingRequested(TrackInfo::kVideoTrack); } @@ -1439,18 +1499,18 @@ MediaFormatReader::OnVideoSkipFailed(MediaTrackDemuxer::SkipFailureHolder aFailu MOZ_ASSERT(OnTaskQueue()); LOG("Skipping failed, skipped %u frames", aFailure.mSkipped); mSkipRequest.Complete(); - if (mDecoder) { - mDecoder->NotifyDecodedFrames(aFailure.mSkipped, 0, aFailure.mSkipped); - } - MOZ_ASSERT(mVideo.HasPromise()); + switch (aFailure.mFailure) { - case DemuxerFailureReason::END_OF_STREAM: - NotifyEndOfStream(TrackType::kVideoTrack); - break; + case DemuxerFailureReason::END_OF_STREAM: MOZ_FALLTHROUGH; case DemuxerFailureReason::WAITING_FOR_DATA: - NotifyWaitingForData(TrackType::kVideoTrack); + // Some frames may have been output by the decoder since we initiated the + // videoskip process and we know they would be late. + DropDecodedSamples(TrackInfo::kVideoTrack); + // We can't complete the skip operation, will just service a video frame + // normally. + NotifyDecodingRequested(TrackInfo::kVideoTrack); break; - case DemuxerFailureReason::CANCELED: + case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH; case DemuxerFailureReason::SHUTDOWN: if (mVideo.HasPromise()) { mVideo.RejectPromise(CANCELED, __func__); @@ -1485,8 +1545,8 @@ MediaFormatReader::Seek(SeekTarget aTarget, int64_t aUnused) return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } - mOriginalSeekTarget = Some(aTarget); - mPendingSeekTime = Some(aTarget.GetTime()); + mOriginalSeekTarget = aTarget; + mFallbackSeekTime = mPendingSeekTime = Some(aTarget.GetTime()); RefPtr p = mSeekPromise.Ensure(__func__); @@ -1515,7 +1575,20 @@ MediaFormatReader::AttemptSeek() if (mPendingSeekTime.isNothing()) { return; } - ResetDemuxers(); + + if (HasVideo()) { + mVideo.ResetDemuxer(); + mVideo.ResetState(); + } + + // Don't reset the audio demuxer not state when seeking video only + // as it will cause the audio to seek back to the beginning + // resulting in out-of-sync audio from video. + if (HasAudio() && !mOriginalSeekTarget.IsVideoOnly()) { + mAudio.ResetDemuxer(); + mAudio.ResetState(); + } + if (HasVideo()) { DoVideoSeek(); } else if (HasAudio()) { @@ -1538,8 +1611,8 @@ MediaFormatReader::OnSeekFailed(TrackType aTrack, DemuxerFailureReason aResult) if (aResult == DemuxerFailureReason::WAITING_FOR_DATA) { if (HasVideo() && aTrack == TrackType::kAudioTrack && - mOriginalSeekTarget.isSome() && - mPendingSeekTime.ref() != mOriginalSeekTarget.ref().GetTime()) { + mFallbackSeekTime.isSome() && + mPendingSeekTime.ref() != mFallbackSeekTime.ref()) { // We have failed to seek audio where video seeked to earlier. // Attempt to seek instead to the closest point that we know we have in // order to limit A/V sync discrepency. @@ -1555,11 +1628,11 @@ MediaFormatReader::OnSeekFailed(TrackType aTrack, DemuxerFailureReason aResult) } } if (nextSeekTime.isNothing() || - nextSeekTime.ref() > mOriginalSeekTarget.ref().GetTime()) { - nextSeekTime = Some(mOriginalSeekTarget.ref().GetTime()); + nextSeekTime.ref() > mFallbackSeekTime.ref()) { + nextSeekTime = Some(mFallbackSeekTime.ref()); LOG("Unable to seek audio to video seek time. A/V sync may be broken"); } else { - mOriginalSeekTarget.reset(); + mFallbackSeekTime.reset(); } mPendingSeekTime = nextSeekTime; DoAudioSeek(); @@ -1592,10 +1665,9 @@ MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime) LOGV("Video seeked to %lld", aTime.ToMicroseconds()); mVideo.mSeekRequest.Complete(); - MOZ_ASSERT(mOriginalSeekTarget.isSome()); - if (HasAudio() && !mOriginalSeekTarget->IsVideoOnly()) { + if (HasAudio() && !mOriginalSeekTarget.IsVideoOnly()) { MOZ_ASSERT(mPendingSeekTime.isSome()); - if (mOriginalSeekTarget->IsFast()) { + if (mOriginalSeekTarget.IsFast()) { // We are performing a fast seek. We need to seek audio to where the // video seeked to, to ensure proper A/V sync once playback resume. mPendingSeekTime = Some(aTime); @@ -1781,7 +1853,7 @@ MediaFormatReader::GetMozDebugReaderData(nsAString& aString) int(mAudio.mQueuedSamples.Length()), mAudio.mDecodingRequested, mAudio.mTimeThreshold - ? mAudio.mTimeThreshold.ref().mTime.ToSeconds() + ? mAudio.mTimeThreshold.ref().Time().ToSeconds() : -1.0, mAudio.mTimeThreshold ? mAudio.mTimeThreshold.ref().mHasSeeked @@ -1805,7 +1877,7 @@ MediaFormatReader::GetMozDebugReaderData(nsAString& aString) int(mVideo.mQueuedSamples.Length()), mVideo.mDecodingRequested, mVideo.mTimeThreshold - ? mVideo.mTimeThreshold.ref().mTime.ToSeconds() + ? mVideo.mTimeThreshold.ref().Time().ToSeconds() : -1.0, mVideo.mTimeThreshold ? mVideo.mTimeThreshold.ref().mHasSeeked @@ -1818,51 +1890,4 @@ MediaFormatReader::GetMozDebugReaderData(nsAString& aString) aString += NS_ConvertUTF8toUTF16(result); } -void -MediaFormatReader::ReportDroppedFramesTelemetry() -{ - MOZ_ASSERT(OnTaskQueue()); - - const VideoInfo* info = - mVideo.mInfo ? mVideo.mInfo->GetAsVideoInfo() : &mInfo.mVideo; - - if (!info || !mVideo.mDecoder) { - return; - } - - nsCString keyPhrase = nsCString("MimeType="); - keyPhrase.Append(info->mMimeType); - keyPhrase.Append("; "); - - keyPhrase.Append("Resolution="); - keyPhrase.AppendInt(info->mDisplay.width); - keyPhrase.Append('x'); - keyPhrase.AppendInt(info->mDisplay.height); - keyPhrase.Append("; "); - - keyPhrase.Append("HardwareAcceleration="); - if (VideoIsHardwareAccelerated()) { - keyPhrase.Append(mVideo.mDecoder->GetDescriptionName()); - keyPhrase.Append("enabled"); - } else { - keyPhrase.Append("disabled"); - } - - if (mVideo.mNumSamplesOutputTotalSinceTelemetry) { - uint32_t percentage = - 100 * mVideo.mNumSamplesSkippedTotalSinceTelemetry / - mVideo.mNumSamplesOutputTotalSinceTelemetry; - nsCOMPtr task = NS_NewRunnableFunction([=]() -> void { - LOG("Reporting telemetry DROPPED_FRAMES_IN_VIDEO_PLAYBACK"); - Telemetry::Accumulate(Telemetry::VIDEO_DETAILED_DROPPED_FRAMES_PROPORTION, - keyPhrase, - percentage); - }); - AbstractThread::MainThread()->Dispatch(task.forget()); - } - - mVideo.mNumSamplesSkippedTotalSinceTelemetry = 0; - mVideo.mNumSamplesOutputTotalSinceTelemetry = 0; -} - } // namespace mozilla diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index d7f810b1a5..4c61fcab8b 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -133,14 +133,21 @@ private: MediaRawData* aSample); struct InternalSeekTarget { - InternalSeekTarget(const media::TimeUnit& aTime, bool aDropTarget) + InternalSeekTarget(const media::TimeInterval& aTime, bool aDropTarget) : mTime(aTime) , mDropTarget(aDropTarget) , mWaiting(false) , mHasSeeked(false) {} - media::TimeUnit mTime; + media::TimeUnit Time() const { return mTime.mStart; } + media::TimeUnit EndTime() const { return mTime.mEnd; } + bool Contains(const media::TimeUnit& aTime) const + { + return mTime.Contains(aTime); + } + + media::TimeInterval mTime; bool mDropTarget; bool mWaiting; bool mHasSeeked; @@ -155,7 +162,7 @@ private: void NotifyNewOutput(TrackType aTrack, MediaData* aSample); void NotifyInputExhausted(TrackType aTrack); void NotifyDrainComplete(TrackType aTrack); - void NotifyError(TrackType aTrack); + void NotifyError(TrackType aTrack, MediaDataDecoderError aError = MediaDataDecoderError::FATAL_ERROR); void NotifyWaitingForData(TrackType aTrack); void NotifyEndOfStream(TrackType aTrack); void NotifyDecodingRequested(TrackType aTrack); @@ -169,12 +176,12 @@ private: // functions. void Output(TrackType aType, MediaData* aSample); void InputExhausted(TrackType aTrack); - void Error(TrackType aTrack); + void Error(TrackType aTrack, MediaDataDecoderError aError = MediaDataDecoderError::FATAL_ERROR); void Reset(TrackType aTrack); void DrainComplete(TrackType aTrack); + void DropDecodedSamples(TrackType aTrack); bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold); - void ResetDemuxers(); size_t SizeOfQueue(TrackType aTrack); @@ -193,8 +200,8 @@ private: void InputExhausted() override { mReader->InputExhausted(mType); } - void Error() override { - mReader->Error(mType); + void Error(MediaDataDecoderError aError) override { + mReader->Error(mType, aError); } void DrainComplete() override { mReader->DrainComplete(mType); @@ -214,7 +221,8 @@ private: struct DecoderData { DecoderData(MediaFormatReader* aOwner, MediaData::Type aType, - uint32_t aDecodeAhead) + uint32_t aDecodeAhead, + uint32_t aNumOfMaxError) : mOwner(aOwner) , mType(aType) , mMonitor("DecoderData") @@ -229,16 +237,15 @@ private: , mDecodingRequested(false) , mOutputRequested(false) , mInputExhausted(false) - , mError(false) , mNeedDraining(false) , mDraining(false) , mDrainComplete(false) + , mNumOfConsecutiveError(0) + , mMaxConsecutiveError(aNumOfMaxError) , mNumSamplesInput(0) , mNumSamplesOutput(0) , mNumSamplesOutputTotal(0) , mNumSamplesSkippedTotal(0) - , mNumSamplesOutputTotalSinceTelemetry(0) - , mNumSamplesSkippedTotalSinceTelemetry(0) , mSizeOfQueue(0) , mIsHardwareAccelerated(false) , mLastStreamSourceID(UINT32_MAX) @@ -300,16 +307,30 @@ private: bool mDecodingRequested; bool mOutputRequested; bool mInputExhausted; - bool mError; bool mNeedDraining; bool mDraining; bool mDrainComplete; + + bool HasPendingDrain() const + { + return mDraining || mDrainComplete; + } + + uint32_t mNumOfConsecutiveError; + uint32_t mMaxConsecutiveError; + + Maybe mError; + bool HasFatalError() const + { + return mError.isSome() && mError.ref() == MediaDataDecoderError::FATAL_ERROR; + } + // If set, all decoded samples prior mTimeThreshold will be dropped. // Used for internal seeking when a change of stream is detected or when // encountering data discontinuity. Maybe mTimeThreshold; // Time of last sample returned. - Maybe mLastSampleTime; + Maybe mLastSampleTime; // Decoded samples returned my mDecoder awaiting being returned to // state machine upon request. @@ -319,9 +340,6 @@ private: uint64_t mNumSamplesOutputTotal; uint64_t mNumSamplesSkippedTotal; - uint64_t mNumSamplesOutputTotalSinceTelemetry; - uint64_t mNumSamplesSkippedTotalSinceTelemetry; - // These get overridden in the templated concrete class. // Indicate if we have a pending promise for decoded frame. // Rejecting the promise will stop the reader from decoding ahead. @@ -368,7 +386,6 @@ private: MOZ_ASSERT(mOwner->OnTaskQueue()); mDemuxEOS = false; mWaitingForData = false; - mReceivedNewData = false; mDiscontinuity = true; mQueuedSamples.Clear(); mDecodingRequested = false; @@ -384,6 +401,9 @@ private: mNumSamplesOutput = 0; mSizeOfQueue = 0; mNextStreamSourceID.reset(); + if (!HasFatalError()) { + mError.reset(); + } } bool HasInternalSeekPending() const @@ -408,8 +428,9 @@ private: public: DecoderDataWithPromise(MediaFormatReader* aOwner, MediaData::Type aType, - uint32_t aDecodeAhead) - : DecoderData(aOwner, aType, aDecodeAhead) + uint32_t aDecodeAhead, + uint32_t aNumOfMaxError) + : DecoderData(aOwner, aType, aDecodeAhead, aNumOfMaxError) , mHasPromise(false) {} @@ -479,6 +500,7 @@ private: void SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold); MozPromiseRequestHolder mSkipRequest; + void VideoSkipReset(uint32_t aSkipped); void OnVideoSkipCompleted(uint32_t aSkipped); void OnVideoSkipFailed(MediaTrackDemuxer::SkipFailureHolder aFailure); @@ -508,6 +530,10 @@ private: // Seeking objects. bool IsSeeking() const { return mPendingSeekTime.isSome(); } + bool IsVideoSeeking() const + { + return IsSeeking() && mOriginalSeekTarget.IsVideoOnly(); + } void ScheduleSeek(); void AttemptSeek(); void OnSeekFailed(TrackType aTrack, DemuxerFailureReason aFailure); @@ -525,11 +551,10 @@ private: { OnSeekFailed(TrackType::kAudioTrack, aFailure); } - - void ReportDroppedFramesTelemetry(); - + // The SeekTarget that was last given to Seek() + SeekTarget mOriginalSeekTarget; // Temporary seek information while we wait for the data - Maybe mOriginalSeekTarget; + Maybe mFallbackSeekTime; Maybe mPendingSeekTime; MozPromiseHolder mSeekPromise; diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h index a6cb83a1c7..c18051928f 100644 --- a/dom/media/MediaPrefs.h +++ b/dom/media/MediaPrefs.h @@ -95,6 +95,9 @@ private: DECL_MEDIA_PREF("media.webm.intel_decoder.enabled", PDMWMFIntelDecoderEnabled, bool, false); DECL_MEDIA_PREF("media.wmf.low-latency.enabled", PDMWMFLowLatencyEnabled, bool, false); DECL_MEDIA_PREF("media.wmf.decoder.thread-count", PDMWMFThreadCount, int32_t, -1); + DECL_MEDIA_PREF("media.wmf.skip-blacklist", PDMWMFSkipBlacklist, bool, false); + DECL_MEDIA_PREF("media.windows-media-foundation.max-dxva-videos", PDMWMFMaxDXVAVideos, uint32_t, 8); + DECL_MEDIA_PREF("media.windows-media-foundation.allow-d3d11-dxva", PDMWMFAllowD3D11, bool, true); #endif DECL_MEDIA_PREF("media.decoder.fuzzing.enabled", PDMFuzzingEnabled, bool, false); DECL_MEDIA_PREF("media.decoder.fuzzing.video-output-minimum-interval-ms", PDMFuzzingInterval, uint32_t, 0); diff --git a/dom/media/SeekTask.cpp b/dom/media/SeekTask.cpp index c8093e6142..15e75e0408 100644 --- a/dom/media/SeekTask.cpp +++ b/dom/media/SeekTask.cpp @@ -237,7 +237,7 @@ SeekTask::EnsureVideoDecodeTaskQueued() IsVideoDecoding(), VideoRequestStatus()); if (!IsVideoDecoding() || - mReader->IsRequestingVidoeData() || + mReader->IsRequestingVideoData() || mVideoWaitRequest.Exists() || mSeekRequest.Exists()) { return NS_OK; @@ -264,7 +264,7 @@ const char* SeekTask::VideoRequestStatus() { AssertOwnerThread(); - if (mReader->IsRequestingVidoeData()) { + if (mReader->IsRequestingVideoData()) { MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists()); return "pending"; } else if (mVideoWaitRequest.Exists()) { diff --git a/dom/media/encoder/fmp4_muxer/ISOControl.h b/dom/media/encoder/fmp4_muxer/ISOControl.h index 65a1f77481..3c445caee1 100644 --- a/dom/media/encoder/fmp4_muxer/ISOControl.h +++ b/dom/media/encoder/fmp4_muxer/ISOControl.h @@ -6,7 +6,7 @@ #ifndef ISOCOMPOSITOR_H_ #define ISOCOMPOSITOR_H_ -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "nsTArray.h" #include "ISOTrackMetadata.h" #include "EncodedFrameContainer.h" diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 2e01991f9d..2cf296e6e3 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -153,7 +153,6 @@ MP4Decoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, } // Verify that we have a PDM that supports the whitelisted types. - PDMFactory::Init(); RefPtr platform = new PDMFactory(); for (const nsCString& codecMime : codecMimes) { if (!platform->SupportsMimeType(codecMime, aDiagnostics)) { @@ -232,8 +231,6 @@ CreateTestH264Decoder(layers::LayersBackend aBackend, aConfig.mExtraData->AppendElements(sTestH264ExtraData, MOZ_ARRAY_LENGTH(sTestH264ExtraData)); - PDMFactory::Init(); - RefPtr platform = new PDMFactory(); RefPtr decoder( platform->CreateDecoder(aConfig, aTaskQueue, nullptr, diff --git a/dom/media/gmp/GMPDiskStorage.cpp b/dom/media/gmp/GMPDiskStorage.cpp index e67f90f7d1..a77dddb9a3 100644 --- a/dom/media/gmp/GMPDiskStorage.cpp +++ b/dom/media/gmp/GMPDiskStorage.cpp @@ -10,7 +10,7 @@ #include "GMPParent.h" #include "gmp-storage.h" #include "mozilla/unused.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "nsClassHashtable.h" #include "prio.h" #include "mozIGeckoMediaPluginService.h" diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 2ed765d4d7..2b177f34a7 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -7,7 +7,7 @@ #include "ContainerParser.h" #include "WebMBufferedParser.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/ErrorResult.h" #include "mp4_demuxer/MoofParser.h" #include "mozilla/Logging.h" diff --git a/dom/media/mediasource/MediaSourceDemuxer.cpp b/dom/media/mediasource/MediaSourceDemuxer.cpp index 6ffb655277..23a018c256 100644 --- a/dom/media/mediasource/MediaSourceDemuxer.cpp +++ b/dom/media/mediasource/MediaSourceDemuxer.cpp @@ -337,7 +337,8 @@ MediaSourceTrackDemuxer::Reset() { MonitorAutoLock mon(self->mMonitor); self->mNextRandomAccessPoint = - self->mManager->GetNextRandomAccessPoint(self->mType); + self->mManager->GetNextRandomAccessPoint(self->mType, + MediaSourceDemuxer::EOS_FUZZ); } }); mParent->GetTaskQueue()->Dispatch(task.forget()); @@ -410,7 +411,8 @@ MediaSourceTrackDemuxer::DoSeek(media::TimeUnit aTime) mReset = false; { MonitorAutoLock mon(mMonitor); - mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType); + mNextRandomAccessPoint = + mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ); } return SeekPromise::CreateAndResolve(seekTime, __func__); } @@ -451,7 +453,8 @@ MediaSourceTrackDemuxer::DoGetSamples(int32_t aNumSamples) samples->mSamples.AppendElement(sample); if (mNextRandomAccessPoint.ToMicroseconds() <= sample->mTime) { MonitorAutoLock mon(mMonitor); - mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType); + mNextRandomAccessPoint = + mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ); } return SamplesPromise::CreateAndResolve(samples, __func__); } @@ -459,11 +462,19 @@ MediaSourceTrackDemuxer::DoGetSamples(int32_t aNumSamples) RefPtr MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint(media::TimeUnit aTimeThreadshold) { - bool found; - uint32_t parsed = - mManager->SkipToNextRandomAccessPoint(mType, aTimeThreadshold, found); - if (found) { - return SkipAccessPointPromise::CreateAndResolve(parsed, __func__); + uint32_t parsed = 0; + // Ensure that the data we are about to skip to is still available. + TimeIntervals buffered = mManager->Buffered(mType); + buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ); + if (buffered.Contains(aTimeThreadshold)) { + bool found; + parsed = mManager->SkipToNextRandomAccessPoint(mType, + aTimeThreadshold, + MediaSourceDemuxer::EOS_FUZZ, + found); + if (found) { + return SkipAccessPointPromise::CreateAndResolve(parsed, __func__); + } } SkipFailureHolder holder( mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM : diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index 9d001721b7..2973a443f6 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -1920,32 +1920,114 @@ TrackBuffersManager::Seek(TrackInfo::TrackType aTrack, uint32_t TrackBuffersManager::SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack, const TimeUnit& aTimeThreadshold, + const media::TimeUnit& aFuzz, bool& aFound) { MOZ_ASSERT(OnTaskQueue()); uint32_t parsed = 0; auto& trackData = GetTracksData(aTrack); const TrackBuffer& track = GetTrackBuffer(aTrack); + aFound = false; - uint32_t nextSampleIndex = trackData.mNextGetSampleIndex.valueOr(0); - for (uint32_t i = nextSampleIndex; i < track.Length(); i++) { - const RefPtr& sample = track[i]; + // SkipToNextRandomAccessPoint can only be called if aTimeThreadshold is known + // to be buffered. + + // So first determine the current position in the track buffer if necessary. + if (trackData.mNextGetSampleIndex.isNothing()) { + if (trackData.mNextSampleTimecode == TimeUnit()) { + // First demux, get first sample. + trackData.mNextGetSampleIndex = Some(0u); + } else { + int32_t pos = FindCurrentPosition(aTrack, aFuzz); + if (pos < 0) { + return 0; + } + trackData.mNextGetSampleIndex = Some(uint32_t(pos)); + } + } + + TimeUnit nextSampleTimecode = trackData.mNextSampleTimecode; + TimeUnit nextSampleTime = trackData.mNextSampleTime; + uint32_t i = trackData.mNextGetSampleIndex.ref(); + int32_t originalPos = i; + + for (; i < track.Length(); i++) { + const MediaRawData* sample = + GetSample(aTrack, + i, + nextSampleTimecode, + nextSampleTime, + aFuzz); + if (!sample) { + break; + } if (sample->mKeyframe && sample->mTime >= aTimeThreadshold.ToMicroseconds()) { - trackData.mNextSampleTimecode = - TimeUnit::FromMicroseconds(sample->mTimecode); - trackData.mNextSampleTime = - TimeUnit::FromMicroseconds(sample->mTime); - trackData.mNextGetSampleIndex = Some(i); aFound = true; break; } + nextSampleTimecode = + TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration); + nextSampleTime = TimeUnit::FromMicroseconds(sample->GetEndTime()); parsed++; } + // Adjust the next demux time and index so that the next call to + // SkipToNextRandomAccessPoint will not count again the parsed sample as + // skipped. + if (aFound) { + trackData.mNextSampleTimecode = nextSampleTimecode; + trackData.mNextSampleTime = nextSampleTime; + trackData.mNextGetSampleIndex = Some(i); + } else if (i > 0) { + // Go back to the previous keyframe or the original position so the next + // demux can succeed and be decoded. + for (int j = i - 1; j >= originalPos; j--) { + const RefPtr& sample = track[j]; + if (sample->mKeyframe) { + trackData.mNextSampleTimecode = + TimeUnit::FromMicroseconds(sample->mTimecode); + trackData.mNextSampleTime = TimeUnit::FromMicroseconds(sample->mTime); + trackData.mNextGetSampleIndex = Some(uint32_t(j)); + // We are unable to skip to a keyframe past aTimeThreshold, however + // we are speeding up decoding by dropping the unplayable frames. + // So we can mark aFound as true. + aFound = true; + break; + } + parsed--; + } + } return parsed; } +const MediaRawData* +TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, + size_t aIndex, + const TimeUnit& aExpectedDts, + const TimeUnit& aExpectedPts, + const TimeUnit& aFuzz) +{ + MOZ_ASSERT(OnTaskQueue()); + const TrackBuffer& track = GetTrackBuffer(aTrack); + + if (aIndex >= track.Length()) { + // reached the end. + return nullptr; + } + + const RefPtr& sample = track[aIndex]; + if (!aIndex || sample->mTimecode <= (aExpectedDts + aFuzz).ToMicroseconds() || + sample->mTime <= (aExpectedPts + aFuzz).ToMicroseconds()) { + return sample; + } + + // Gap is too big. End of Stream or Waiting for Data. + // TODO, check that we have continuous data based on the sanitized buffered + // range instead. + return nullptr; +} + already_AddRefed TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, const TimeUnit& aFuzz, @@ -1957,9 +2039,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, aError = false; - if (!track.Length() || - (trackData.mNextGetSampleIndex.isSome() && - trackData.mNextGetSampleIndex.ref() >= track.Length())) { + if (!track.Length()) { return nullptr; } if (trackData.mNextGetSampleIndex.isNothing() && @@ -1969,11 +2049,13 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, } if (trackData.mNextGetSampleIndex.isSome()) { - const RefPtr& sample = - track[trackData.mNextGetSampleIndex.ref()]; - if (trackData.mNextGetSampleIndex.ref() && - sample->mTimecode > (trackData.mNextSampleTimecode + aFuzz).ToMicroseconds()) { - // Gap is too big. End of Stream or Waiting for Data. + const MediaRawData* sample = + GetSample(aTrack, + trackData.mNextGetSampleIndex.ref(), + trackData.mNextSampleTimecode, + trackData.mNextSampleTime, + aFuzz); + if (!sample) { return nullptr; } @@ -1992,6 +2074,37 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, } // Our previous index has been overwritten, attempt to find the new one. + int32_t pos = FindCurrentPosition(aTrack, aFuzz); + if (pos < 0) { + MSE_DEBUG("Couldn't find sample (pts:%lld dts:%lld)", + trackData.mNextSampleTime.ToMicroseconds(), + trackData.mNextSampleTimecode.ToMicroseconds()); + return nullptr; + } + + const RefPtr& sample = track[pos]; + RefPtr p = sample->Clone(); + if (!p) { + // OOM + aError = true; + return nullptr; + } + trackData.mNextGetSampleIndex = Some(uint32_t(pos)+1); + trackData.mNextSampleTimecode = + TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration); + trackData.mNextSampleTime = + TimeUnit::FromMicroseconds(sample->GetEndTime()); + return p.forget(); +} + +int32_t +TrackBuffersManager::FindCurrentPosition(TrackInfo::TrackType aTrack, + const TimeUnit& aFuzz) +{ + MOZ_ASSERT(OnTaskQueue()); + auto& trackData = GetTracksData(aTrack); + const TrackBuffer& track = GetTrackBuffer(aTrack); + for (uint32_t i = 0; i < track.Length(); i++) { const RefPtr& sample = track[i]; TimeInterval sampleInterval{ @@ -2000,23 +2113,13 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, aFuzz}; if (sampleInterval.ContainsWithStrictEnd(trackData.mNextSampleTimecode)) { - RefPtr p = sample->Clone(); - if (!p) { - // OOM - aError = true; - return nullptr; - } - trackData.mNextGetSampleIndex = Some(i+1); - trackData.mNextSampleTimecode = sampleInterval.mEnd; - trackData.mNextSampleTime = - TimeUnit::FromMicroseconds(sample->GetEndTime()); - return p.forget(); + return i; } } // We couldn't find our sample by decode timestamp. Attempt to find it using // presentation timestamp. There will likely be small jerkiness. - for (uint32_t i = 0; i < track.Length(); i++) { + for (uint32_t i = 0; i < track.Length(); i++) { const RefPtr& sample = track[i]; TimeInterval sampleInterval{ TimeUnit::FromMicroseconds(sample->mTime), @@ -2024,42 +2127,41 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, aFuzz}; if (sampleInterval.ContainsWithStrictEnd(trackData.mNextSampleTimecode)) { - RefPtr p = sample->Clone(); - if (!p) { - // OOM - aError = true; - return nullptr; - } - trackData.mNextGetSampleIndex = Some(i+1); - // Estimate decode timestamp of the next sample. - trackData.mNextSampleTimecode = sampleInterval.mEnd; - trackData.mNextSampleTime = - TimeUnit::FromMicroseconds(sample->GetEndTime()); - return p.forget(); + return i; } } - MSE_DEBUG("Couldn't find sample (pts:%lld dts:%lld)", - trackData.mNextSampleTime.ToMicroseconds(), - trackData.mNextSampleTimecode.ToMicroseconds()); - return nullptr; + // Still not found. + return -1; } TimeUnit -TrackBuffersManager::GetNextRandomAccessPoint(TrackInfo::TrackType aTrack) +TrackBuffersManager::GetNextRandomAccessPoint(TrackInfo::TrackType aTrack, + const TimeUnit& aFuzz) { + MOZ_ASSERT(OnTaskQueue()); auto& trackData = GetTracksData(aTrack); MOZ_ASSERT(trackData.mNextGetSampleIndex.isSome()); const TrackBuffersManager::TrackBuffer& track = GetTrackBuffer(aTrack); uint32_t i = trackData.mNextGetSampleIndex.ref(); + TimeUnit nextSampleTimecode = trackData.mNextSampleTimecode; + TimeUnit nextSampleTime = trackData.mNextSampleTime; + for (; i < track.Length(); i++) { - const RefPtr& sample = track[i]; + const MediaRawData* sample = + GetSample(aTrack, i, nextSampleTimecode, nextSampleTime, aFuzz); + if (!sample) { + break; + } if (sample->mKeyframe) { return TimeUnit::FromMicroseconds(sample->mTime); } + nextSampleTimecode = + TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration); + nextSampleTime = TimeUnit::FromMicroseconds(sample->GetEndTime()); } - return media::TimeUnit::FromInfinity(); + return TimeUnit::FromInfinity(); } void diff --git a/dom/media/mediasource/TrackBuffersManager.h b/dom/media/mediasource/TrackBuffersManager.h index f05588c5b2..da8f707026 100644 --- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -141,11 +141,15 @@ public: const media::TimeUnit& aFuzz); uint32_t SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack, const media::TimeUnit& aTimeThreadshold, + const media::TimeUnit& aFuzz, bool& aFound); already_AddRefed GetSample(TrackInfo::TrackType aTrack, const media::TimeUnit& aFuzz, bool& aError); - media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack); + int32_t FindCurrentPosition(TrackInfo::TrackType aTrack, + const media::TimeUnit& aFuzz); + media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack, + const media::TimeUnit& aFuzz); void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes); @@ -339,6 +343,11 @@ private: // Find index of sample. Return a negative value if not found. uint32_t FindSampleIndex(const TrackBuffer& aTrackBuffer, const media::TimeInterval& aInterval); + const MediaRawData* GetSample(TrackInfo::TrackType aTrack, + size_t aIndex, + const media::TimeUnit& aExpectedDts, + const media::TimeUnit& aExpectedPts, + const media::TimeUnit& aFuzz); void UpdateBufferedRanges(); void RejectProcessing(nsresult aRejectValue, const char* aName); void ResolveProcessing(bool aResolveValue, const char* aName); diff --git a/dom/media/ogg/OggCodecState.cpp b/dom/media/ogg/OggCodecState.cpp index aa059481c8..55ad9b146d 100644 --- a/dom/media/ogg/OggCodecState.cpp +++ b/dom/media/ogg/OggCodecState.cpp @@ -7,7 +7,7 @@ #include #include "mozilla/DebugOnly.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include #include "nsDebug.h" diff --git a/dom/media/ogg/OpusParser.cpp b/dom/media/ogg/OpusParser.cpp index c450df9a22..d03ca26aef 100644 --- a/dom/media/ogg/OpusParser.cpp +++ b/dom/media/ogg/OpusParser.cpp @@ -7,7 +7,7 @@ #include #include "mozilla/DebugOnly.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include #include "OpusParser.h" diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index 5da68bbdd1..d12f66ca60 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -176,7 +176,7 @@ void MediaOmxReader::ReleaseMediaResources() mMediaResourceRequest.DisconnectIfExists(); mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__); - ResetDecode(); + ResetDecode(AUDIO_VIDEO); // Before freeing a video codec, all video buffers needed to be released // even from graphics pipeline. VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); diff --git a/dom/media/omx/MediaOmxReader.h b/dom/media/omx/MediaOmxReader.h index c0083aee75..24b195a722 100644 --- a/dom/media/omx/MediaOmxReader.h +++ b/dom/media/omx/MediaOmxReader.h @@ -74,11 +74,11 @@ protected: void NotifyDataArrivedInternal() override; public: - nsresult ResetDecode() override + nsresult ResetDecode(TargetQueues aQueues) override { mSeekRequest.DisconnectIfExists(); mSeekPromise.RejectIfExists(NS_OK, __func__); - return MediaDecoderReader::ResetDecode(); + return MediaDecoderReader::ResetDecode(aQueues); } bool DecodeAudioData() override; diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index e7d8636cfb..613b03a467 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -23,9 +23,10 @@ #endif #include "GMPDecoderModule.h" -#include "mozilla/TaskQueue.h" - +#include "mozilla/ClearOnShutdown.h" #include "mozilla/SharedThreadPool.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/TaskQueue.h" #include "MediaInfo.h" #include "MediaPrefs.h" @@ -46,34 +47,29 @@ namespace mozilla { extern already_AddRefed CreateAgnosticDecoderModule(); extern already_AddRefed CreateBlankDecoderModule(); -/* static */ -void -PDMFactory::Init() -{ - MOZ_ASSERT(NS_IsMainThread()); - static bool alreadyInitialized = false; - if (alreadyInitialized) { - return; - } - alreadyInitialized = true; - - // Ensure MediaPrefs are initialized. - MediaPrefs::GetSingleton(); - +class PDMFactoryImpl final { +public: + PDMFactoryImpl() + { #ifdef XP_WIN - WMFDecoderModule::Init(); + WMFDecoderModule::Init(); #endif #ifdef MOZ_APPLEMEDIA - AppleDecoderModule::Init(); + AppleDecoderModule::Init(); #endif #ifdef MOZ_FFMPEG - FFmpegRuntimeLinker::Link(); + FFmpegRuntimeLinker::Link(); #endif - GMPDecoderModule::Init(); -} + GMPDecoderModule::Init(); + } +}; + +StaticAutoPtr PDMFactory::sInstance; +StaticMutex PDMFactory::sMonitor; PDMFactory::PDMFactory() { + EnsureInit(); CreatePDMs(); } @@ -81,13 +77,29 @@ PDMFactory::~PDMFactory() { } +void +PDMFactory::EnsureInit() const +{ + StaticMutexAutoLock mon(sMonitor); + if (!sInstance) { + sInstance = new PDMFactoryImpl(); + if (NS_IsMainThread()) { + ClearOnShutdown(&sInstance); + } else { + nsCOMPtr runnable = + NS_NewRunnableFunction([]() { ClearOnShutdown(&sInstance); }); + NS_DispatchToMainThread(runnable); + } + } +} + already_AddRefed PDMFactory::CreateDecoder(const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics, layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer) + layers::ImageContainer* aImageContainer) const { bool isEncrypted = mEMEPDM && aConfig.mCrypto.mValid; @@ -138,11 +150,11 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, already_AddRefed PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM, const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics, layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer) + layers::ImageContainer* aImageContainer) const { MOZ_ASSERT(aPDM); RefPtr m; diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index 155f0b5f73..8d2d59634c 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -8,12 +8,15 @@ #define PDMFactory_h_ #include "PlatformDecoderModule.h" +#include "mozilla/StaticMutex.h" class CDMProxy; namespace mozilla { class DecoderDoctorDiagnostics; +class PDMFactoryImpl; +template class StaticAutoPtr; class PDMFactory final { public: @@ -21,10 +24,6 @@ public: PDMFactory(); - // Call on the main thread to initialize the static state - // needed by Create(). - static void Init(); - // Factory method that creates the appropriate PlatformDecoderModule for // the platform we're running on. Caller is responsible for deleting this // instance. It's expected that there will be multiple @@ -32,11 +31,11 @@ public: // This is called on the decode task queue. already_AddRefed CreateDecoder(const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics, layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, - layers::ImageContainer* aImageContainer = nullptr); + layers::ImageContainer* aImageContainer = nullptr) const; bool SupportsMimeType(const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const; @@ -63,11 +62,11 @@ private: already_AddRefed CreateDecoderWithPDM(PlatformDecoderModule* aPDM, const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics, layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer); + layers::ImageContainer* aImageContainer) const; nsTArray> mCurrentPDMs; RefPtr mEMEPDM; @@ -75,6 +74,11 @@ private: bool mWMFFailedToLoad = false; bool mFFmpegFailedToLoad = false; bool mGMPPDMFailedToStartup = false; + + void EnsureInit() const; + template friend class StaticAutoPtr; + static StaticAutoPtr sInstance; + static StaticMutex sMonitor; }; } // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp deleted file mode 100644 index a2b979c374..0000000000 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -*- 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/. */ - -#include "PlatformDecoderModule.h" - -mozilla::LogModule* GetPDMLog() { - static mozilla::LazyLogModule log("PlatformDecoderModule"); - return log; -} diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 2992ed6f8c..43a0f78098 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -7,7 +7,6 @@ #if !defined(PlatformDecoderModule_h_) #define PlatformDecoderModule_h_ -#include "FlushableTaskQueue.h" #include "MediaDecoderReader.h" #include "mozilla/MozPromise.h" #include "mozilla/layers/LayersTypes.h" @@ -28,9 +27,11 @@ class ImageContainer; class MediaDataDecoder; class MediaDataDecoderCallback; -class FlushableTaskQueue; +class TaskQueue; class CDMProxy; +static LazyLogModule sPDMLog("PlatformDecoderModule"); + // The PlatformDecoderModule interface is used by the MediaFormatReader to // abstract access to decoders provided by various // platforms. @@ -90,7 +91,7 @@ protected: CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) = 0; @@ -106,11 +107,16 @@ protected: // This is called on the decode task queue. virtual already_AddRefed CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) = 0; }; +enum MediaDataDecoderError { + FATAL_ERROR, + DECODE_ERROR +}; + // A callback used by MediaDataDecoder to return output/errors to the // MediaFormatReader. // Implementation is threadsafe, and can be called on any thread. @@ -123,7 +129,7 @@ public: // Denotes an error in the decoding process. The reader will stop calling // the decoder. - virtual void Error() = 0; + virtual void Error(MediaDataDecoderError aError) = 0; // Denotes that the last input sample has been inserted into the decoder, // and no more output can be produced unless more input is sent. diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp index b38659abcd..5c1fbae729 100644 --- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp @@ -26,7 +26,7 @@ already_AddRefed AgnosticDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -35,7 +35,7 @@ AgnosticDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, if (VPXDecoder::IsVPX(aConfig.mMimeType)) { m = new VPXDecoder(*aConfig.GetAsVideoInfo(), aImageContainer, - aVideoTaskQueue, + aTaskQueue, aCallback); } @@ -44,7 +44,7 @@ AgnosticDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, already_AddRefed AgnosticDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -52,16 +52,14 @@ AgnosticDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, if (VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), - aAudioTaskQueue, + aTaskQueue, aCallback); } else if (OpusDataDecoder::IsOpus(aConfig.mMimeType)) { m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), - aAudioTaskQueue, + aTaskQueue, aCallback); } else if (WaveDataDecoder::IsWave(aConfig.mMimeType)) { - m = new WaveDataDecoder(*aConfig.GetAsAudioInfo(), - aAudioTaskQueue, - aCallback); + m = new WaveDataDecoder(*aConfig.GetAsAudioInfo(), aCallback); } return m.forget(); diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.h b/dom/media/platforms/agnostic/AgnosticDecoderModule.h index 7b9fe6c3d5..7414475495 100644 --- a/dom/media/platforms/agnostic/AgnosticDecoderModule.h +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.h @@ -25,14 +25,14 @@ protected: CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; // Decode thread. already_AddRefed CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; }; diff --git a/dom/media/platforms/agnostic/BlankDecoderModule.cpp b/dom/media/platforms/agnostic/BlankDecoderModule.cpp index bb3dfba4df..9407940044 100644 --- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp +++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp @@ -25,11 +25,9 @@ class BlankMediaDataDecoder : public MediaDataDecoder { public: BlankMediaDataDecoder(BlankMediaDataCreator* aCreator, - FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, TrackInfo::TrackType aType) : mCreator(aCreator) - , mTaskQueue(aTaskQueue) , mCallback(aCallback) , mType(aType) { @@ -43,46 +41,21 @@ public: return NS_OK; } - class OutputEvent : public Runnable { - public: - OutputEvent(MediaRawData* aSample, - MediaDataDecoderCallback* aCallback, - BlankMediaDataCreator* aCreator) - : mSample(aSample) - , mCreator(aCreator) - , mCallback(aCallback) - { - } - NS_IMETHOD Run() override - { - RefPtr data = - mCreator->Create(media::TimeUnit::FromMicroseconds(mSample->mTime), - media::TimeUnit::FromMicroseconds(mSample->mDuration), - mSample->mOffset); - if (!data) { - return NS_ERROR_OUT_OF_MEMORY; - } - mCallback->Output(data); - return NS_OK; - } - private: - RefPtr mSample; - BlankMediaDataCreator* mCreator; - MediaDataDecoderCallback* mCallback; - }; - nsresult Input(MediaRawData* aSample) override { - // The MediaDataDecoder must delete the sample when we're finished - // with it, so the OutputEvent stores it in an nsAutoPtr and deletes - // it once it's run. - RefPtr r(new OutputEvent(aSample, mCallback, mCreator)); - mTaskQueue->Dispatch(r.forget()); + RefPtr data = + mCreator->Create(media::TimeUnit::FromMicroseconds(aSample->mTime), + media::TimeUnit::FromMicroseconds(aSample->mDuration), + aSample->mOffset); + if (!data) { + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); + } else { + mCallback->Output(data); + } return NS_OK; } nsresult Flush() override { - mTaskQueue->Flush(); return NS_OK; } @@ -98,7 +71,6 @@ public: private: nsAutoPtr mCreator; - RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; TrackInfo::TrackType mType; }; @@ -229,14 +201,13 @@ public: CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override { BlankVideoDataCreator* creator = new BlankVideoDataCreator( aConfig.mDisplay.width, aConfig.mDisplay.height, aImageContainer); RefPtr decoder = new BlankMediaDataDecoder(creator, - aVideoTaskQueue, aCallback, TrackInfo::kVideoTrack); return decoder.forget(); @@ -245,7 +216,7 @@ public: // Decode thread. already_AddRefed CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override { BlankAudioDataCreator* creator = new BlankAudioDataCreator( @@ -253,7 +224,6 @@ public: RefPtr decoder = new BlankMediaDataDecoder(creator, - aAudioTaskQueue, aCallback, TrackInfo::kAudioTrack); return decoder.forget(); diff --git a/dom/media/platforms/agnostic/OpusDecoder.cpp b/dom/media/platforms/agnostic/OpusDecoder.cpp index 9fa5e91f55..43770a6cbb 100644 --- a/dom/media/platforms/agnostic/OpusDecoder.cpp +++ b/dom/media/platforms/agnostic/OpusDecoder.cpp @@ -8,15 +8,14 @@ #include "TimeUnits.h" #include "VorbisUtils.h" #include "VorbisDecoder.h" // For VorbisLayout -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/PodOperations.h" #include "mozilla/SyncRunnable.h" #include #include // For PRId64 -extern mozilla::LogModule* GetPDMLog(); -#define OPUS_DEBUG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, \ +#define OPUS_DEBUG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \ ("OpusDataDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) namespace mozilla { @@ -146,14 +145,25 @@ OpusDataDecoder::ProcessDecode(MediaRawData* aSample) if (mIsFlushing) { return; } - if (DoDecode(aSample) == -1) { - mCallback->Error(); - } else if(mTaskQueue->IsEmpty()) { + + DecodeError err = DoDecode(aSample); + switch (err) { + case DecodeError::FATAL_ERROR: + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); + return; + case DecodeError::DECODE_ERROR: + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); + break; + case DecodeError::DECODE_SUCCESS: + break; + } + + if (mTaskQueue->IsEmpty()) { mCallback->InputExhausted(); } } -int +OpusDataDecoder::DecodeError OpusDataDecoder::DoDecode(MediaRawData* aSample) { int64_t aDiscardPadding = 0; @@ -166,7 +176,7 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample) // Discard padding should be used only on the final packet, so // decoding after a padding discard is invalid. OPUS_DEBUG("Opus error, discard padding on interstitial packet"); - return -1; + return FATAL_ERROR; } if (!mLastFrameTime || mLastFrameTime.ref() != aSample->mTime) { @@ -181,7 +191,7 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample) if (frames_number <= 0) { OPUS_DEBUG("Invalid packet header: r=%ld length=%ld", frames_number, aSample->Size()); - return -1; + return FATAL_ERROR; } int32_t samples = opus_packet_get_samples_per_frame(aSample->Data(), @@ -192,12 +202,12 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample) int32_t frames = frames_number*samples; if (frames < 120 || frames > 5760) { OPUS_DEBUG("Invalid packet frames: %ld", frames); - return -1; + return FATAL_ERROR; } AlignedAudioBuffer buffer(frames * channels); if (!buffer) { - return -1; + return FATAL_ERROR; } // Decode to the appropriate sample type. @@ -211,7 +221,7 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample) buffer.get(), frames, false); #endif if (ret < 0) { - return -1; + return DECODE_ERROR; } NS_ASSERTION(ret == frames, "Opus decoded too few audio samples"); CheckedInt64 startTime = aSample->mTime; @@ -232,7 +242,7 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample) if (aDiscardPadding < 0) { // Negative discard padding is invalid. OPUS_DEBUG("Opus error, negative discard padding"); - return -1; + return FATAL_ERROR; } if (aDiscardPadding > 0) { OPUS_DEBUG("OpusDecoder discardpadding %" PRId64 "", aDiscardPadding); @@ -241,12 +251,12 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample) mOpusParser->mRate); if (!discardFrames.isValid()) { NS_WARNING("Int overflow in DiscardPadding"); - return -1; + return FATAL_ERROR; } if (discardFrames.value() > frames) { // Discarding more than the entire packet is invalid. OPUS_DEBUG("Opus error, discard padding larger than packet"); - return -1; + return FATAL_ERROR; } OPUS_DEBUG("Opus decoder discarding %d of %d frames", int32_t(discardFrames.value()), frames); @@ -281,14 +291,14 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample) CheckedInt64 duration = FramesToUsecs(frames, mOpusParser->mRate); if (!duration.isValid()) { NS_WARNING("OpusDataDecoder: Int overflow converting WebM audio duration"); - return -1; + return FATAL_ERROR; } CheckedInt64 time = startTime - FramesToUsecs(mOpusParser->mPreSkip, mOpusParser->mRate) + FramesToUsecs(mFrames, mOpusParser->mRate); if (!time.isValid()) { NS_WARNING("OpusDataDecoder: Int overflow shifting tstamp by codec delay"); - return -1; + return FATAL_ERROR; }; mCallback->Output(new AudioData(aSample->mOffset, @@ -299,7 +309,7 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample) mOpusParser->mChannels, mOpusParser->mRate)); mFrames += frames; - return frames; + return DECODE_SUCCESS; } void diff --git a/dom/media/platforms/agnostic/OpusDecoder.h b/dom/media/platforms/agnostic/OpusDecoder.h index 13572471cb..b8c35f176e 100644 --- a/dom/media/platforms/agnostic/OpusDecoder.h +++ b/dom/media/platforms/agnostic/OpusDecoder.h @@ -36,10 +36,16 @@ public: static bool IsOpus(const nsACString& aMimeType); private: + enum DecodeError { + DECODE_SUCCESS, + DECODE_ERROR, + FATAL_ERROR + }; + nsresult DecodeHeader(const unsigned char* aData, size_t aLength); void ProcessDecode(MediaRawData* aSample); - int DoDecode(MediaRawData* aSample); + DecodeError DoDecode(MediaRawData* aSample); void ProcessDrain(); const AudioInfo& mInfo; diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp index 6b1f5ad2ce..ad97b77541 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -9,36 +9,41 @@ #include "nsError.h" #include "TimeUnits.h" #include "mozilla/PodOperations.h" +#include "mozilla/SyncRunnable.h" #include "prsystem.h" #include #undef LOG -extern mozilla::LogModule* GetPDMLog(); -#define LOG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, ("VPXDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) +#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("VPXDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) namespace mozilla { using namespace gfx; using namespace layers; +static int MimeTypeToCodec(const nsACString& aMimeType) +{ + if (aMimeType.EqualsLiteral("video/webm; codecs=vp8")) { + return VPXDecoder::Codec::VP8; + } else if (aMimeType.EqualsLiteral("video/webm; codecs=vp9")) { + return VPXDecoder::Codec::VP9; + } + return -1; +} + VPXDecoder::VPXDecoder(const VideoInfo& aConfig, ImageContainer* aImageContainer, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) : mImageContainer(aImageContainer) , mTaskQueue(aTaskQueue) , mCallback(aCallback) + , mIsFlushing(false) , mInfo(aConfig) + , mCodec(MimeTypeToCodec(aConfig.mMimeType)) { MOZ_COUNT_CTOR(VPXDecoder); - if (aConfig.mMimeType.EqualsLiteral("video/webm; codecs=vp8")) { - mCodec = Codec::VP8; - } else if (aConfig.mMimeType.EqualsLiteral("video/webm; codecs=vp9")) { - mCodec = Codec::VP9; - } else { - mCodec = -1; - } PodZero(&mVPX); } @@ -85,13 +90,20 @@ VPXDecoder::Init() nsresult VPXDecoder::Flush() { - mTaskQueue->Flush(); + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mIsFlushing = true; + nsCOMPtr r = NS_NewRunnableFunction([this] () { + // nothing to do for now. + }); + SyncRunnable::DispatchToThread(mTaskQueue, r); + mIsFlushing = false; return NS_OK; } int -VPXDecoder::DoDecodeFrame(MediaRawData* aSample) +VPXDecoder::DoDecode(MediaRawData* aSample) { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); #if defined(DEBUG) vpx_codec_stream_info_t si; PodZero(&si); @@ -174,10 +186,14 @@ VPXDecoder::DoDecodeFrame(MediaRawData* aSample) } void -VPXDecoder::DecodeFrame(MediaRawData* aSample) +VPXDecoder::ProcessDecode(MediaRawData* aSample) { - if (DoDecodeFrame(aSample) == -1) { - mCallback->Error(); + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + if (mIsFlushing) { + return; + } + if (DoDecode(aSample) == -1) { + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); } else if (mTaskQueue->IsEmpty()) { mCallback->InputExhausted(); } @@ -186,23 +202,25 @@ VPXDecoder::DecodeFrame(MediaRawData* aSample) nsresult VPXDecoder::Input(MediaRawData* aSample) { + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); mTaskQueue->Dispatch(NewRunnableMethod>( - this, &VPXDecoder::DecodeFrame, - RefPtr(aSample))); + this, &VPXDecoder::ProcessDecode, aSample)); return NS_OK; } void -VPXDecoder::DoDrain() +VPXDecoder::ProcessDrain() { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); mCallback->DrainComplete(); } nsresult VPXDecoder::Drain() { - mTaskQueue->Dispatch(NewRunnableMethod(this, &VPXDecoder::DoDrain)); + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &VPXDecoder::ProcessDrain)); return NS_OK; } diff --git a/dom/media/platforms/agnostic/VPXDecoder.h b/dom/media/platforms/agnostic/VPXDecoder.h index 2cb4ab2785..74b42eb60d 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.h +++ b/dom/media/platforms/agnostic/VPXDecoder.h @@ -16,14 +16,14 @@ namespace mozilla { - using namespace layers; +using namespace layers; class VPXDecoder : public MediaDataDecoder { public: VPXDecoder(const VideoInfo& aConfig, ImageContainer* aImageContainer, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback); ~VPXDecoder(); @@ -47,21 +47,21 @@ public: static bool IsVPX(const nsACString& aMimeType, uint8_t aCodecMask=VP8|VP9); private: - void DecodeFrame (MediaRawData* aSample); - int DoDecodeFrame (MediaRawData* aSample); - void DoDrain (); - void OutputDelayedFrames (); + void ProcessDecode(MediaRawData* aSample); + int DoDecode(MediaRawData* aSample); + void ProcessDrain(); - RefPtr mImageContainer; - RefPtr mTaskQueue; + const RefPtr mImageContainer; + const RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; + Atomic mIsFlushing; // VPx decoder state vpx_codec_ctx_t mVPX; const VideoInfo& mInfo; - int mCodec; + const int mCodec; }; } // namespace mozilla diff --git a/dom/media/platforms/agnostic/VorbisDecoder.cpp b/dom/media/platforms/agnostic/VorbisDecoder.cpp index ed7217c457..3f05fe19ea 100644 --- a/dom/media/platforms/agnostic/VorbisDecoder.cpp +++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp @@ -9,11 +9,11 @@ #include "XiphExtradata.h" #include "mozilla/PodOperations.h" +#include "mozilla/SyncRunnable.h" #include "nsAutoPtr.h" #undef LOG -extern mozilla::LogModule* GetPDMLog(); -#define LOG(type, msg) MOZ_LOG(GetPDMLog(), type, msg) +#define LOG(type, msg) MOZ_LOG(sPDMLog, type, msg) namespace mozilla { @@ -32,13 +32,14 @@ ogg_packet InitVorbisPacket(const unsigned char* aData, size_t aLength, } VorbisDataDecoder::VorbisDataDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) : mInfo(aConfig) , mTaskQueue(aTaskQueue) , mCallback(aCallback) , mPacketCount(0) , mFrames(0) + , mIsFlushing(false) { // Zero these member vars to avoid crashes in Vorbis clear functions when // destructor is called before |Init|. @@ -129,18 +130,22 @@ VorbisDataDecoder::DecodeHeader(const unsigned char* aData, size_t aLength) nsresult VorbisDataDecoder::Input(MediaRawData* aSample) { + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); mTaskQueue->Dispatch(NewRunnableMethod>( - this, &VorbisDataDecoder::Decode, - RefPtr(aSample))); + this, &VorbisDataDecoder::ProcessDecode, aSample)); return NS_OK; } void -VorbisDataDecoder::Decode(MediaRawData* aSample) +VorbisDataDecoder::ProcessDecode(MediaRawData* aSample) { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + if (mIsFlushing) { + return; + } if (DoDecode(aSample) == -1) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); } else if (mTaskQueue->IsEmpty()) { mCallback->InputExhausted(); } @@ -149,6 +154,8 @@ VorbisDataDecoder::Decode(MediaRawData* aSample) int VorbisDataDecoder::DoDecode(MediaRawData* aSample) { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + const unsigned char* aData = aSample->Data(); size_t aLength = aSample->Size(); int64_t aOffset = aSample->mOffset; @@ -255,27 +262,34 @@ VorbisDataDecoder::DoDecode(MediaRawData* aSample) } void -VorbisDataDecoder::DoDrain() +VorbisDataDecoder::ProcessDrain() { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); mCallback->DrainComplete(); } nsresult VorbisDataDecoder::Drain() { - mTaskQueue->Dispatch(NewRunnableMethod(this, &VorbisDataDecoder::DoDrain)); + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &VorbisDataDecoder::ProcessDrain)); return NS_OK; } nsresult VorbisDataDecoder::Flush() { - mTaskQueue->Flush(); - // Ignore failed results from vorbis_synthesis_restart. They - // aren't fatal and it fails when ResetDecode is called at a - // time when no vorbis data has been read. - vorbis_synthesis_restart(&mVorbisDsp); - mLastFrameTime.reset(); + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mIsFlushing = true; + nsCOMPtr r = NS_NewRunnableFunction([this] () { + // Ignore failed results from vorbis_synthesis_restart. They + // aren't fatal and it fails when ResetDecode is called at a + // time when no vorbis data has been read. + vorbis_synthesis_restart(&mVorbisDsp); + mLastFrameTime.reset(); + }); + SyncRunnable::DispatchToThread(mTaskQueue, r); + mIsFlushing = false; return NS_OK; } diff --git a/dom/media/platforms/agnostic/VorbisDecoder.h b/dom/media/platforms/agnostic/VorbisDecoder.h index b21a83ac6d..9a28b94354 100644 --- a/dom/media/platforms/agnostic/VorbisDecoder.h +++ b/dom/media/platforms/agnostic/VorbisDecoder.h @@ -22,7 +22,7 @@ class VorbisDataDecoder : public MediaDataDecoder { public: VorbisDataDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback); ~VorbisDataDecoder(); @@ -43,12 +43,12 @@ public: private: nsresult DecodeHeader(const unsigned char* aData, size_t aLength); - void Decode (MediaRawData* aSample); - int DoDecode (MediaRawData* aSample); - void DoDrain (); + void ProcessDecode(MediaRawData* aSample); + int DoDecode(MediaRawData* aSample); + void ProcessDrain(); const AudioInfo& mInfo; - RefPtr mTaskQueue; + const RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; // Vorbis decoder state @@ -61,6 +61,7 @@ private: int64_t mFrames; Maybe mLastFrameTime; UniquePtr mAudioConverter; + Atomic mIsFlushing; }; } // namespace mozilla diff --git a/dom/media/platforms/agnostic/WAVDecoder.cpp b/dom/media/platforms/agnostic/WAVDecoder.cpp index d31d514379..9d480bf5d3 100644 --- a/dom/media/platforms/agnostic/WAVDecoder.cpp +++ b/dom/media/platforms/agnostic/WAVDecoder.cpp @@ -7,6 +7,7 @@ #include "WAVDecoder.h" #include "AudioSampleFormat.h" #include "nsAutoPtr.h" +#include "mozilla/SyncRunnable.h" using mp4_demuxer::ByteReader; @@ -46,12 +47,9 @@ DecodeULawSample(uint8_t aValue) } WaveDataDecoder::WaveDataDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) : mInfo(aConfig) - , mTaskQueue(aTaskQueue) , mCallback(aCallback) - , mFrames(0) { } @@ -69,22 +67,11 @@ WaveDataDecoder::Init() nsresult WaveDataDecoder::Input(MediaRawData* aSample) -{ - mTaskQueue->Dispatch(NewRunnableMethod>( - this, &WaveDataDecoder::Decode, - RefPtr(aSample))); - - return NS_OK; -} - -void -WaveDataDecoder::Decode(MediaRawData* aSample) { if (!DoDecode(aSample)) { - mCallback->Error(); - } else if (mTaskQueue->IsEmpty()) { - mCallback->InputExhausted(); + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); } + return NS_OK; } bool @@ -142,29 +129,20 @@ WaveDataDecoder::DoDecode(MediaRawData* aSample) Move(buffer), mInfo.mChannels, mInfo.mRate)); - mFrames += frames; return true; } -void -WaveDataDecoder::DoDrain() -{ - mCallback->DrainComplete(); -} - nsresult WaveDataDecoder::Drain() { - mTaskQueue->Dispatch(NewRunnableMethod(this, &WaveDataDecoder::DoDrain)); + mCallback->DrainComplete(); return NS_OK; } nsresult WaveDataDecoder::Flush() { - mTaskQueue->Flush(); - mFrames = 0; return NS_OK; } diff --git a/dom/media/platforms/agnostic/WAVDecoder.h b/dom/media/platforms/agnostic/WAVDecoder.h index cf671f6129..6e1b2d044b 100644 --- a/dom/media/platforms/agnostic/WAVDecoder.h +++ b/dom/media/platforms/agnostic/WAVDecoder.h @@ -16,9 +16,12 @@ class WaveDataDecoder : public MediaDataDecoder { public: WaveDataDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback); + // Return true if mimetype is Wave + static bool IsWave(const nsACString& aMimeType); + +private: RefPtr Init() override; nsresult Input(MediaRawData* aSample) override; nsresult Flush() override; @@ -29,20 +32,11 @@ public: return "wave audio decoder"; } - // Return true if mimetype is Wave - static bool IsWave(const nsACString& aMimeType); - -private: - void Decode (MediaRawData* aSample); - bool DoDecode (MediaRawData* aSample); - void DoDrain (); + bool DoDecode(MediaRawData* aSample); const AudioInfo& mInfo; - RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; - - int64_t mFrames; }; } // namespace mozilla -#endif \ No newline at end of file +#endif diff --git a/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp b/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp index dc81d22951..6a9b8a5358 100644 --- a/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp +++ b/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp @@ -31,7 +31,7 @@ AudioCallbackAdapter::Decoded(const nsTArray& aPCM, uint64_t aTimeStamp if (aRate == 0 || aChannels == 0) { NS_WARNING("Invalid rate or num channels returned on GMP audio samples"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return; } @@ -39,7 +39,7 @@ AudioCallbackAdapter::Decoded(const nsTArray& aPCM, uint64_t aTimeStamp MOZ_ASSERT((aPCM.Length() % aChannels) == 0); AlignedAudioBuffer audioData(aPCM.Length()); if (!audioData) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return; } @@ -52,7 +52,7 @@ AudioCallbackAdapter::Decoded(const nsTArray& aPCM, uint64_t aTimeStamp auto timestamp = UsecsToFrames(aTimeStamp, aRate); if (!timestamp.isValid()) { NS_WARNING("Invalid timestamp"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return; } mAudioFrameOffset = timestamp.value(); @@ -62,7 +62,7 @@ AudioCallbackAdapter::Decoded(const nsTArray& aPCM, uint64_t aTimeStamp auto timestamp = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, aRate); if (!timestamp.isValid()) { NS_WARNING("Invalid timestamp on audio samples"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return; } mAudioFrameSum += numFrames; @@ -70,7 +70,7 @@ AudioCallbackAdapter::Decoded(const nsTArray& aPCM, uint64_t aTimeStamp auto duration = FramesToUsecs(numFrames, aRate); if (!duration.isValid()) { NS_WARNING("Invalid duration on audio samples"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return; } @@ -116,14 +116,14 @@ void AudioCallbackAdapter::Error(GMPErr aErr) { MOZ_ASSERT(IsOnGMPThread()); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); } void AudioCallbackAdapter::Terminated() { NS_WARNING("AAC GMP decoder terminated."); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); } void @@ -205,7 +205,7 @@ GMPAudioDecoder::Input(MediaRawData* aSample) RefPtr sample(aSample); if (!mGMP) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return NS_ERROR_FAILURE; } @@ -214,7 +214,7 @@ GMPAudioDecoder::Input(MediaRawData* aSample) gmp::GMPAudioSamplesImpl samples(sample, mConfig.mChannels, mConfig.mRate); nsresult rv = mGMP->Decode(samples); if (NS_FAILED(rv)) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); return rv; } diff --git a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp index 9c3e8ea8cc..93531b00d6 100644 --- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp +++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp @@ -13,6 +13,7 @@ #include "mozIGeckoMediaPluginService.h" #include "nsServiceManagerUtils.h" #include "mozilla/StaticMutex.h" +#include "mozilla/SyncRunnable.h" #include "gmp-audio-decode.h" #include "gmp-video-decode.h" #ifdef XP_WIN @@ -48,7 +49,7 @@ already_AddRefed GMPDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -67,14 +68,14 @@ GMPDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, wrapper->SetProxyTarget(new GMPVideoDecoder(aConfig, aLayersBackend, aImageContainer, - aVideoTaskQueue, + aTaskQueue, wrapper->Callback())); return wrapper.forget(); } already_AddRefed GMPDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -91,7 +92,7 @@ GMPDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, RefPtr wrapper = CreateDecoderWrapper(aCallback); wrapper->SetProxyTarget(new GMPAudioDecoder(aConfig, - aAudioTaskQueue, + aTaskQueue, wrapper->Callback())); return wrapper.forget(); } @@ -112,7 +113,6 @@ HasGMPFor(const nsACString& aAPI, const nsACString& aCodec, const nsACString& aGMP) { - MOZ_ASSERT(NS_IsMainThread()); #ifdef XP_WIN // gmp-clearkey uses WMF for decoding, so if we're using clearkey we must // verify that WMF works before continuing. @@ -130,6 +130,8 @@ HasGMPFor(const nsACString& aAPI, } } #endif + MOZ_ASSERT(NS_IsMainThread(), + "HasPluginForAPI must be called on the main thread"); nsTArray tags; tags.AppendElement(aCodec); tags.AppendElement(aGMP); @@ -178,8 +180,13 @@ GMPDecoderModule::UpdateUsableCodecs() void GMPDecoderModule::Init() { - MOZ_ASSERT(NS_IsMainThread()); - + if (!NS_IsMainThread()) { + nsCOMPtr mainThread = do_GetMainThread(); + nsCOMPtr runnable = + NS_NewRunnableFunction([]() { Init(); }); + SyncRunnable::DispatchToThread(mainThread, runnable); + return; + } // GMPService::HasPluginForAPI is main thread only, so to implement // SupportsMimeType() we build a table of the codecs which each whitelisted // GMP has and update it when any GMPs are removed or added at runtime. diff --git a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h index 3920282c7e..1e8edf50ad 100644 --- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h +++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h @@ -36,14 +36,14 @@ public: CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; // Decode thread. already_AddRefed CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; diff --git a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp index 052eae4ae2..93181d5310 100644 --- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp +++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp @@ -6,7 +6,7 @@ #include "GMPVideoDecoder.h" #include "GMPVideoHost.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "prsystem.h" #include "MediaData.h" #include "GMPDecoderModule.h" @@ -52,7 +52,7 @@ VideoCallbackAdapter::Decoded(GMPVideoi420Frame* aDecodedFrame) if (v) { mCallback->Output(v); } else { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); } } @@ -93,7 +93,7 @@ void VideoCallbackAdapter::Error(GMPErr aErr) { MOZ_ASSERT(IsOnGMPThread()); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); } void @@ -101,7 +101,7 @@ VideoCallbackAdapter::Terminated() { // Note that this *may* be called from the proxy thread also. NS_WARNING("H.264 GMP decoder terminated."); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); } void @@ -127,14 +127,14 @@ GMPVideoDecoder::CreateFrame(MediaRawData* aSample) GMPVideoFrame* ftmp = nullptr; GMPErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp); if (GMP_FAILED(err)) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return nullptr; } GMPUniquePtr frame(static_cast(ftmp)); err = frame->CreateEmptyFrame(aSample->Size()); if (GMP_FAILED(err)) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return nullptr; } @@ -249,7 +249,7 @@ GMPVideoDecoder::Input(MediaRawData* aSample) RefPtr sample(aSample); if (!mGMP) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return NS_ERROR_FAILURE; } @@ -257,13 +257,13 @@ GMPVideoDecoder::Input(MediaRawData* aSample) GMPUniquePtr frame = CreateFrame(sample); if (!frame) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return NS_ERROR_FAILURE; } nsTArray info; // No codec specific per-frame info to pass. nsresult rv = mGMP->Decode(Move(frame), false, info, 0); if (NS_FAILED(rv)) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); return rv; } diff --git a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp index 503de5380f..3146225a80 100644 --- a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp +++ b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp @@ -10,9 +10,9 @@ namespace mozilla { void -MediaDataDecoderCallbackProxy::Error() +MediaDataDecoderCallbackProxy::Error(MediaDataDecoderError aError) { - mProxyCallback->Error(); + mProxyCallback->Error(aError); } void diff --git a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h index 4413a78d1b..7f854bedc7 100644 --- a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h +++ b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.h @@ -74,7 +74,7 @@ public: mProxyCallback->Output(aData); } - void Error() override; + void Error(MediaDataDecoderError aError) override; void InputExhausted() override { mProxyCallback->InputExhausted(); diff --git a/dom/media/platforms/android/AndroidDecoderModule.cpp b/dom/media/platforms/android/AndroidDecoderModule.cpp index f878f49354..c83c4db1c0 100644 --- a/dom/media/platforms/android/AndroidDecoderModule.cpp +++ b/dom/media/platforms/android/AndroidDecoderModule.cpp @@ -269,7 +269,7 @@ AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType, aMimeType.EqualsLiteral("audio/wave; codecs=7") || aMimeType.EqualsLiteral("audio/wave; codecs=65534")) { return false; - } + } if ((VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP8) && !GetFeatureStatus(nsIGfxInfo::FEATURE_VP8_HW_DECODE)) || @@ -285,7 +285,7 @@ AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType, already_AddRefed AndroidDecoderModule::CreateVideoDecoder( const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, FlushableTaskQueue* aVideoTaskQueue, + layers::ImageContainer* aImageContainer, TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -305,7 +305,7 @@ AndroidDecoderModule::CreateVideoDecoder( already_AddRefed AndroidDecoderModule::CreateAudioDecoder( - const AudioInfo& aConfig, FlushableTaskQueue* aAudioTaskQueue, + const AudioInfo& aConfig, TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -378,7 +378,7 @@ MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface) { mDecoder = CreateDecoder(mMimeType); if (!mDecoder) { - INVOKE_CALLBACK(Error); + INVOKE_CALLBACK(Error, MediaDataDecoderError::FATAL_ERROR); return NS_ERROR_FAILURE; } @@ -405,7 +405,7 @@ static const int64_t kDecoderTimeout = 10000; INVOKE_CALLBACK(DrainComplete); \ State(kDecoding); \ } \ - INVOKE_CALLBACK(Error); \ + INVOKE_CALLBACK(Error, MediaDataDecoderError::FATAL_ERROR); \ break; \ } @@ -636,7 +636,7 @@ MediaCodecDataDecoder::DecoderLoop() BREAK_ON_DECODER_ERROR(); } else if (outputStatus < 0) { NS_WARNING("Unknown error from decoder!"); - INVOKE_CALLBACK(Error); + INVOKE_CALLBACK(Error, MediaDataDecoderError::DECODE_ERROR); // Don't break here just in case it's recoverable. If it's not, other // stuff will fail later and we'll bail out. } else { diff --git a/dom/media/platforms/android/AndroidDecoderModule.h b/dom/media/platforms/android/AndroidDecoderModule.h index f6bd0030e0..04a6ed36b9 100644 --- a/dom/media/platforms/android/AndroidDecoderModule.h +++ b/dom/media/platforms/android/AndroidDecoderModule.h @@ -24,13 +24,13 @@ public: CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; already_AddRefed CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; diff --git a/dom/media/platforms/apple/AppleATDecoder.cpp b/dom/media/platforms/apple/AppleATDecoder.cpp index a5da492aa1..061699599b 100644 --- a/dom/media/platforms/apple/AppleATDecoder.cpp +++ b/dom/media/platforms/apple/AppleATDecoder.cpp @@ -10,10 +10,10 @@ #include "MediaInfo.h" #include "AppleATDecoder.h" #include "mozilla/Logging.h" +#include "mozilla/SyncRunnable.h" #include "mozilla/UniquePtr.h" -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) #define FourCC2Str(n) ((char[5]){(char)(n >> 24), (char)(n >> 16), (char)(n >> 8), (char)(n), 0}) namespace mozilla { @@ -27,6 +27,7 @@ AppleATDecoder::AppleATDecoder(const AudioInfo& aConfig, , mCallback(aCallback) , mConverter(nullptr) , mStream(nullptr) + , mIsFlushing(false) { MOZ_COUNT_CTOR(AppleATDecoder); LOG("Creating Apple AudioToolbox decoder"); @@ -65,6 +66,7 @@ AppleATDecoder::Init() nsresult AppleATDecoder::Input(MediaRawData* aSample) { + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); LOG("mp4 input sample %p %lld us %lld pts%s %llu bytes audio", aSample, aSample->mDuration, @@ -83,23 +85,34 @@ AppleATDecoder::Input(MediaRawData* aSample) return NS_OK; } -nsresult -AppleATDecoder::Flush() +void +AppleATDecoder::ProcessFlush() { - LOG("Flushing AudioToolbox AAC decoder"); - mTaskQueue->Flush(); + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); mQueuedSamples.Clear(); OSStatus rv = AudioConverterReset(mConverter); if (rv) { LOG("Error %d resetting AudioConverter", rv); - return NS_ERROR_FAILURE; } +} + +nsresult +AppleATDecoder::Flush() +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + LOG("Flushing AudioToolbox AAC decoder"); + mIsFlushing = true; + nsCOMPtr runnable = + NewRunnableMethod(this, &AppleATDecoder::ProcessFlush); + SyncRunnable::DispatchToThread(mTaskQueue, runnable); + mIsFlushing = false; return NS_OK; } nsresult AppleATDecoder::Drain() { + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); LOG("Draining AudioToolbox AAC decoder"); mTaskQueue->AwaitIdle(); mCallback->DrainComplete(); @@ -109,6 +122,8 @@ AppleATDecoder::Drain() nsresult AppleATDecoder::Shutdown() { + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + LOG("Shutdown: Apple AudioToolbox AAC decoder"); mQueuedSamples.Clear(); OSStatus rv = AudioConverterDispose(mConverter); @@ -173,11 +188,17 @@ _PassthroughInputDataCallback(AudioConverterRef aAudioConverter, void AppleATDecoder::SubmitSample(MediaRawData* aSample) { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + + if (mIsFlushing) { + return; + } + nsresult rv = NS_OK; if (!mConverter) { rv = SetupDecoder(aSample); if (rv != NS_OK && rv != NS_ERROR_NOT_INITIALIZED) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return; } } @@ -188,7 +209,7 @@ AppleATDecoder::SubmitSample(MediaRawData* aSample) for (size_t i = 0; i < mQueuedSamples.Length(); i++) { if (NS_FAILED(DecodeSample(mQueuedSamples[i]))) { mQueuedSamples.Clear(); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); return; } } @@ -203,6 +224,8 @@ AppleATDecoder::SubmitSample(MediaRawData* aSample) nsresult AppleATDecoder::DecodeSample(MediaRawData* aSample) { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + // Array containing the queued decoded audio frames, about to be output. nsTArray outputData; UInt32 channels = mOutputFormat.mChannelsPerFrame; @@ -308,6 +331,8 @@ nsresult AppleATDecoder::GetInputAudioDescription(AudioStreamBasicDescription& aDesc, const nsTArray& aExtraData) { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + // Request the properties from CoreAudio using the codec magic cookie AudioFormatInfo formatInfo; PodZero(&formatInfo.mASBD); @@ -411,6 +436,8 @@ ConvertChannelLabel(AudioChannelLabel id) nsresult AppleATDecoder::SetupChannelLayout() { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + // Determine the channel layout. UInt32 propertySize; UInt32 size; @@ -510,6 +537,8 @@ AppleATDecoder::SetupChannelLayout() nsresult AppleATDecoder::SetupDecoder(MediaRawData* aSample) { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + if (mFormatID == kAudioFormatMPEG4AAC && mConfig.mExtendedProfile == 2) { // Check for implicit SBR signalling if stream is AAC-LC @@ -615,6 +644,8 @@ _SampleCallback(void* aSBR, nsresult AppleATDecoder::GetImplicitAACMagicCookie(const MediaRawData* aSample) { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + // Prepend ADTS header to AAC audio. RefPtr adtssample(aSample->Clone()); if (!adtssample) { diff --git a/dom/media/platforms/apple/AppleATDecoder.h b/dom/media/platforms/apple/AppleATDecoder.h index f5c3935fb1..4d901071d0 100644 --- a/dom/media/platforms/apple/AppleATDecoder.h +++ b/dom/media/platforms/apple/AppleATDecoder.h @@ -56,7 +56,9 @@ private: nsTArray> mQueuedSamples; UniquePtr mChannelLayout; UniquePtr mAudioConverter; + Atomic mIsFlushing; + void ProcessFlush(); void SubmitSample(MediaRawData* aSample); nsresult DecodeSample(MediaRawData* aSample); nsresult GetInputAudioDescription(AudioStreamBasicDescription& aDesc, diff --git a/dom/media/platforms/apple/AppleCMLinker.cpp b/dom/media/platforms/apple/AppleCMLinker.cpp index a61cb0e9f2..45aa98adaf 100644 --- a/dom/media/platforms/apple/AppleCMLinker.cpp +++ b/dom/media/platforms/apple/AppleCMLinker.cpp @@ -7,7 +7,6 @@ #include #include "AppleCMLinker.h" -#include "MainThreadUtils.h" #include "mozilla/ArrayUtils.h" #include "nsDebug.h" @@ -15,8 +14,7 @@ #include "nsCocoaFeatures.h" #endif -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) namespace mozilla { @@ -24,7 +22,6 @@ AppleCMLinker::LinkStatus AppleCMLinker::sLinkStatus = LinkStatus_INIT; void* AppleCMLinker::sLink = nullptr; -nsrefcnt AppleCMLinker::sRefCount = 0; CFStringRef AppleCMLinker::skPropExtensionAtoms = nullptr; CFStringRef AppleCMLinker::skPropFullRangeVideo = nullptr; @@ -35,12 +32,6 @@ CFStringRef AppleCMLinker::skPropFullRangeVideo = nullptr; /* static */ bool AppleCMLinker::Link() { - // Bump our reference count every time we're called. - // Add a lock or change the thread assertion if - // you need to call this off the main thread. - MOZ_ASSERT(NS_IsMainThread()); - ++sRefCount; - if (sLinkStatus) { return sLinkStatus == LinkStatus_SUCCEEDED; } @@ -116,10 +107,7 @@ fail: /* static */ void AppleCMLinker::Unlink() { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(sRefCount > 0, "Unbalanced Unlink()"); - --sRefCount; - if (sLink && sRefCount < 1) { + if (sLink) { LOG("Unlinking CoreMedia framework."); dlclose(sLink); sLink = nullptr; diff --git a/dom/media/platforms/apple/AppleCMLinker.h b/dom/media/platforms/apple/AppleCMLinker.h index e62558546a..74372b6af0 100644 --- a/dom/media/platforms/apple/AppleCMLinker.h +++ b/dom/media/platforms/apple/AppleCMLinker.h @@ -27,7 +27,6 @@ public: private: static void* sLink; - static nsrefcnt sRefCount; static enum LinkStatus { LinkStatus_INIT = 0, diff --git a/dom/media/platforms/apple/AppleDecoderModule.cpp b/dom/media/platforms/apple/AppleDecoderModule.cpp index 8cefd50f07..7454d2b769 100644 --- a/dom/media/platforms/apple/AppleDecoderModule.cpp +++ b/dom/media/platforms/apple/AppleDecoderModule.cpp @@ -37,8 +37,6 @@ AppleDecoderModule::~AppleDecoderModule() void AppleDecoderModule::Init() { - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - if (sInitialized) { return; } @@ -79,7 +77,7 @@ already_AddRefed AppleDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -88,7 +86,7 @@ AppleDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, if (sIsVDAAvailable && (!sIsVTHWAvailable || MediaPrefs::AppleForceVDA())) { decoder = AppleVDADecoder::CreateVDADecoder(aConfig, - aVideoTaskQueue, + aTaskQueue, aCallback, aImageContainer); if (decoder) { @@ -99,19 +97,19 @@ AppleDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, // supported by the current platform. if (sIsVTAvailable) { decoder = - new AppleVTDecoder(aConfig, aVideoTaskQueue, aCallback, aImageContainer); + new AppleVTDecoder(aConfig, aTaskQueue, aCallback, aImageContainer); } return decoder.forget(); } already_AddRefed AppleDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { RefPtr decoder = - new AppleATDecoder(aConfig, aAudioTaskQueue, aCallback); + new AppleATDecoder(aConfig, aTaskQueue, aCallback); return decoder.forget(); } diff --git a/dom/media/platforms/apple/AppleDecoderModule.h b/dom/media/platforms/apple/AppleDecoderModule.h index 2b51476f8d..e6dcb30664 100644 --- a/dom/media/platforms/apple/AppleDecoderModule.h +++ b/dom/media/platforms/apple/AppleDecoderModule.h @@ -23,14 +23,14 @@ public: CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; // Decode thread. already_AddRefed CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; diff --git a/dom/media/platforms/apple/AppleVDADecoder.cpp b/dom/media/platforms/apple/AppleVDADecoder.cpp index 2c96100401..0e317ac172 100644 --- a/dom/media/platforms/apple/AppleVDADecoder.cpp +++ b/dom/media/platforms/apple/AppleVDADecoder.cpp @@ -15,6 +15,7 @@ #include "MP4Decoder.h" #include "MediaData.h" #include "mozilla/ArrayUtils.h" +#include "mozilla/SyncRunnable.h" #include "nsAutoPtr.h" #include "nsThreadUtils.h" #include "mozilla/Logging.h" @@ -27,23 +28,42 @@ #include "MacIOSurfaceImage.h" #endif -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) //#define LOG_MEDIA_SHA1 namespace mozilla { +static uint32_t ComputeMaxRefFrames(const MediaByteBuffer* aExtraData) +{ + uint32_t maxRefFrames = 4; + // Retrieve video dimensions from H264 SPS NAL. + mp4_demuxer::SPSData spsdata; + if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata)) { + // max_num_ref_frames determines the size of the sliding window + // we need to queue that many frames in order to guarantee proper + // pts frames ordering. Use a minimum of 4 to ensure proper playback of + // non compliant videos. + maxRefFrames = + std::min(std::max(maxRefFrames, spsdata.max_num_ref_frames + 1), 16u); + } + return maxRefFrames; +} + AppleVDADecoder::AppleVDADecoder(const VideoInfo& aConfig, - FlushableTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback, - layers::ImageContainer* aImageContainer) - : mTaskQueue(aVideoTaskQueue) + TaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::ImageContainer* aImageContainer) + : mExtraData(aConfig.mExtraData) , mCallback(aCallback) - , mImageContainer(aImageContainer) , mPictureWidth(aConfig.mImage.width) , mPictureHeight(aConfig.mImage.height) , mDisplayWidth(aConfig.mDisplay.width) , mDisplayHeight(aConfig.mDisplay.height) + , mQueuedSamples(0) + , mTaskQueue(aTaskQueue) + , mDecoder(nullptr) + , mMaxRefFrames(ComputeMaxRefFrames(aConfig.mExtraData)) + , mImageContainer(aImageContainer) , mInputIncoming(0) , mIsShutDown(false) #ifdef MOZ_WIDGET_UIKIT @@ -52,28 +72,13 @@ AppleVDADecoder::AppleVDADecoder(const VideoInfo& aConfig, #else , mUseSoftwareImages(false) , mIs106(!nsCocoaFeatures::OnLionOrLater()) - #endif - , mQueuedSamples(0) +#endif , mMonitor("AppleVideoDecoder") , mIsFlushing(false) - , mDecoder(nullptr) { MOZ_COUNT_CTOR(AppleVDADecoder); // TODO: Verify aConfig.mime_type. - mExtraData = aConfig.mExtraData; - mMaxRefFrames = 4; - // Retrieve video dimensions from H264 SPS NAL. - mp4_demuxer::SPSData spsdata; - if (mp4_demuxer::H264::DecodeSPSFromExtraData(mExtraData, spsdata)) { - // max_num_ref_frames determines the size of the sliding window - // we need to queue that many frames in order to guarantee proper - // pts frames ordering. Use a minimum of 4 to ensure proper playback of - // non compliant videos. - mMaxRefFrames = - std::min(std::max(mMaxRefFrames, spsdata.max_num_ref_frames + 1), 16u); - } - LOG("Creating AppleVDADecoder for %dx%d (%dx%d) h.264 video", mPictureWidth, mPictureHeight, @@ -132,12 +137,8 @@ AppleVDADecoder::Input(MediaRawData* aSample) mInputIncoming++; - nsCOMPtr runnable = - NewRunnableMethod>( - this, - &AppleVDADecoder::SubmitFrame, - RefPtr(aSample)); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod>( + this, &AppleVDADecoder::ProcessDecode, aSample)); return NS_OK; } @@ -146,15 +147,12 @@ AppleVDADecoder::Flush() { MOZ_ASSERT(mCallback->OnReaderTaskQueue()); mIsFlushing = true; - mTaskQueue->Flush(); nsCOMPtr runnable = NewRunnableMethod(this, &AppleVDADecoder::ProcessFlush); - MonitorAutoLock mon(mMonitor); - mTaskQueue->Dispatch(runnable.forget()); - while (mIsFlushing) { - mon.Wait(); - } - mInputIncoming = 0; + SyncRunnable::DispatchToThread(mTaskQueue, runnable); + mIsFlushing = false; + // All ProcessDecode() tasks should be done. + MOZ_ASSERT(mInputIncoming == 0); return NS_OK; } @@ -171,7 +169,7 @@ AppleVDADecoder::Drain() void AppleVDADecoder::ProcessFlush() { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + AssertOnTaskQueueThread(); OSStatus rv = VDADecoderFlush(mDecoder, 0 /*dont emit*/); if (rv != noErr) { @@ -179,15 +177,12 @@ AppleVDADecoder::ProcessFlush() "with error:%d.", rv); } ClearReorderedFrames(); - MonitorAutoLock mon(mMonitor); - mIsFlushing = false; - mon.NotifyAll(); } void AppleVDADecoder::ProcessDrain() { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + AssertOnTaskQueueThread(); OSStatus rv = VDADecoderFlush(mDecoder, kVDADecoderFlush_EmitFrames); if (rv != noErr) { @@ -348,7 +343,7 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage, CVReturn rv = CVPixelBufferLockBaseAddress(aImage, kCVPixelBufferLock_ReadOnly); if (rv != kCVReturnSuccess) { NS_ERROR("error locking pixel data"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); return NS_ERROR_FAILURE; } // Y plane. @@ -416,7 +411,7 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage, if (!data) { NS_ERROR("Couldn't create VideoData for frame"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return NS_ERROR_FAILURE; } @@ -434,12 +429,31 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage, } nsresult -AppleVDADecoder::SubmitFrame(MediaRawData* aSample) +AppleVDADecoder::ProcessDecode(MediaRawData* aSample) { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + AssertOnTaskQueueThread(); mInputIncoming--; + if (mIsFlushing) { + return NS_OK; + } + + auto rv = DoDecode(aSample); + // Ask for more data. + if (NS_SUCCEEDED(rv) && !mInputIncoming && mQueuedSamples <= mMaxRefFrames) { + LOG("%s task queue empty; requesting more data", GetDescriptionName()); + mCallback->InputExhausted(); + } + + return rv; +} + +nsresult +AppleVDADecoder::DoDecode(MediaRawData* aSample) +{ + AssertOnTaskQueueThread(); + AutoCFRelease block = CFDataCreate(kCFAllocatorDefault, aSample->Data(), aSample->Size()); if (!block) { @@ -499,7 +513,7 @@ AppleVDADecoder::SubmitFrame(MediaRawData* aSample) if (rv != noErr) { NS_WARNING("AppleVDADecoder: Couldn't pass frame to decoder"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); return NS_ERROR_FAILURE; } @@ -514,12 +528,6 @@ AppleVDADecoder::SubmitFrame(MediaRawData* aSample) CFRetain(frameInfo); } - // Ask for more data. - if (!mInputIncoming && mQueuedSamples <= mMaxRefFrames) { - LOG("AppleVDADecoder task queue empty; requesting more data"); - mCallback->InputExhausted(); - } - return NS_OK; } @@ -662,7 +670,7 @@ AppleVDADecoder::CreateOutputConfiguration() already_AddRefed AppleVDADecoder::CreateVDADecoder( const VideoInfo& aConfig, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, layers::ImageContainer* aImageContainer) { @@ -672,7 +680,7 @@ AppleVDADecoder::CreateVDADecoder( } RefPtr decoder = - new AppleVDADecoder(aConfig, aVideoTaskQueue, aCallback, aImageContainer); + new AppleVDADecoder(aConfig, aTaskQueue, aCallback, aImageContainer); if (NS_FAILED(decoder->InitializeSession())) { return nullptr; diff --git a/dom/media/platforms/apple/AppleVDADecoder.h b/dom/media/platforms/apple/AppleVDADecoder.h index 6b0b0b37af..08963e3f87 100644 --- a/dom/media/platforms/apple/AppleVDADecoder.h +++ b/dom/media/platforms/apple/AppleVDADecoder.h @@ -19,7 +19,7 @@ namespace mozilla { -class FlushableTaskQueue; +class TaskQueue; class MediaDataDecoderCallback; namespace layers { class ImageContainer; @@ -62,15 +62,16 @@ public: // not supported by current configuration. static already_AddRefed CreateVDADecoder( const VideoInfo& aConfig, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, layers::ImageContainer* aImageContainer); - AppleVDADecoder(const VideoInfo& aConfig, - FlushableTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback, - layers::ImageContainer* aImageContainer); - virtual ~AppleVDADecoder(); + // Access from the taskqueue and the decoder's thread. + // OutputFrame is thread-safe. + nsresult OutputFrame(CVPixelBufferRef aImage, + AppleFrameRef aFrameRef); + +private: RefPtr Init() override; nsresult Input(MediaRawData* aSample) override; nsresult Flush() override; @@ -86,46 +87,52 @@ public: return "apple VDA decoder"; } - // Access from the taskqueue and the decoder's thread. - // OutputFrame is thread-safe. - nsresult OutputFrame(CVPixelBufferRef aImage, - AppleFrameRef aFrameRef); - protected: - // Flush and Drain operation, always run - virtual void ProcessFlush(); - virtual void ProcessDrain(); - virtual void ProcessShutdown(); + AppleVDADecoder(const VideoInfo& aConfig, + TaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::ImageContainer* aImageContainer); + virtual ~AppleVDADecoder(); + + void AssertOnTaskQueueThread() + { + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + } AppleFrameRef* CreateAppleFrameRef(const MediaRawData* aSample); void DrainReorderedFrames(); void ClearReorderedFrames(); CFDictionaryRef CreateOutputConfiguration(); - RefPtr mExtraData; - RefPtr mTaskQueue; + const RefPtr mExtraData; MediaDataDecoderCallback* mCallback; - RefPtr mImageContainer; - uint32_t mPictureWidth; - uint32_t mPictureHeight; - uint32_t mDisplayWidth; - uint32_t mDisplayHeight; - // Accessed on multiple threads, but only set in constructor. - uint32_t mMaxRefFrames; - // Increased when Input is called, and decreased when ProcessFrame runs. - // Reaching 0 indicates that there's no pending Input. - Atomic mInputIncoming; - Atomic mIsShutDown; - - const bool mUseSoftwareImages; - const bool mIs106; + const uint32_t mPictureWidth; + const uint32_t mPictureHeight; + const uint32_t mDisplayWidth; + const uint32_t mDisplayHeight; // Number of times a sample was queued via Input(). Will be decreased upon // the decoder's callback being invoked. // This is used to calculate how many frames has been buffered by the decoder. Atomic mQueuedSamples; - // For wait on mIsFlushing during Shutdown() process. +private: + // Flush and Drain operation, always run + virtual void ProcessFlush(); + virtual void ProcessDrain(); + virtual void ProcessShutdown(); + + const RefPtr mTaskQueue; + VDADecoder mDecoder; + const uint32_t mMaxRefFrames; + const RefPtr mImageContainer; + // Increased when Input is called, and decreased when ProcessFrame runs. + // Reaching 0 indicates that there's no pending Input. + Atomic mInputIncoming; + Atomic mIsShutDown; + const bool mUseSoftwareImages; + const bool mIs106; + // Protects mReorderQueue. Monitor mMonitor; // Set on reader/decode thread calling Flush() to indicate that output is @@ -134,14 +141,12 @@ protected: Atomic mIsFlushing; ReorderQueue mReorderQueue; -private: - VDADecoder mDecoder; - // Method to set up the decompression session. nsresult InitializeSession(); // Method to pass a frame to VideoToolbox for decoding. - nsresult SubmitFrame(MediaRawData* aSample); + nsresult ProcessDecode(MediaRawData* aSample); + virtual nsresult DoDecode(MediaRawData* aSample); CFDictionaryRef CreateDecoderSpecification(); }; diff --git a/dom/media/platforms/apple/AppleVDALinker.cpp b/dom/media/platforms/apple/AppleVDALinker.cpp index 045b1e24d3..c47c1e59b5 100644 --- a/dom/media/platforms/apple/AppleVDALinker.cpp +++ b/dom/media/platforms/apple/AppleVDALinker.cpp @@ -7,11 +7,9 @@ #include #include "AppleVDALinker.h" -#include "MainThreadUtils.h" #include "nsDebug.h" -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) namespace mozilla { @@ -19,7 +17,6 @@ AppleVDALinker::LinkStatus AppleVDALinker::sLinkStatus = LinkStatus_INIT; void* AppleVDALinker::sLink = nullptr; -nsrefcnt AppleVDALinker::sRefCount = 0; CFStringRef AppleVDALinker::skPropWidth = nullptr; CFStringRef AppleVDALinker::skPropHeight = nullptr; CFStringRef AppleVDALinker::skPropSourceFormat = nullptr; @@ -32,12 +29,6 @@ CFStringRef AppleVDALinker::skPropAVCCData = nullptr; /* static */ bool AppleVDALinker::Link() { - // Bump our reference count every time we're called. - // Add a lock or change the thread assertion if - // you need to call this off the main thread. - MOZ_ASSERT(NS_IsMainThread()); - ++sRefCount; - if (sLinkStatus) { return sLinkStatus == LinkStatus_SUCCEEDED; } @@ -82,14 +73,7 @@ fail: /* static */ void AppleVDALinker::Unlink() { - // We'll be called by multiple Decoders, one intantiated for - // each media element. Therefore we receive must maintain a - // reference count to avoidunloading our symbols when other - // instances still need them. - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(sRefCount > 0, "Unbalanced Unlink()"); - --sRefCount; - if (sLink && sRefCount < 1) { + if (sLink) { LOG("Unlinking VideoDecodeAcceleration framework."); #define LINK_FUNC(func) \ func = nullptr; diff --git a/dom/media/platforms/apple/AppleVTDecoder.cpp b/dom/media/platforms/apple/AppleVTDecoder.cpp index d3e444688c..8ffe21fed8 100644 --- a/dom/media/platforms/apple/AppleVTDecoder.cpp +++ b/dom/media/platforms/apple/AppleVTDecoder.cpp @@ -20,21 +20,15 @@ #include "VideoUtils.h" #include "gfxPlatform.h" -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) -//#define LOG_MEDIA_SHA1 - -#ifdef LOG_MEDIA_SHA1 -#include "mozilla/SHA1.h" -#endif +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) namespace mozilla { AppleVTDecoder::AppleVTDecoder(const VideoInfo& aConfig, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, layers::ImageContainer* aImageContainer) - : AppleVDADecoder(aConfig, aVideoTaskQueue, aCallback, aImageContainer) + : AppleVDADecoder(aConfig, aTaskQueue, aCallback, aImageContainer) , mFormat(nullptr) , mSession(nullptr) , mIsHardwareAccelerated(false) @@ -80,58 +74,22 @@ AppleVTDecoder::ProcessShutdown() } } -nsresult -AppleVTDecoder::Input(MediaRawData* aSample) -{ - MOZ_ASSERT(mCallback->OnReaderTaskQueue()); - - LOG("mp4 input sample %p pts %lld duration %lld us%s %d bytes", - aSample, - aSample->mTime, - aSample->mDuration, - aSample->mKeyframe ? " keyframe" : "", - aSample->Size()); - -#ifdef LOG_MEDIA_SHA1 - SHA1Sum hash; - hash.update(aSample->data, aSample->size); - uint8_t digest_buf[SHA1Sum::kHashSize]; - hash.finish(digest_buf); - nsAutoCString digest; - for (size_t i = 0; i < sizeof(digest_buf); i++) { - digest.AppendPrintf("%02x", digest_buf[i]); - } - LOG(" sha1 %s", digest.get()); -#endif // LOG_MEDIA_SHA1 - - mInputIncoming++; - - nsCOMPtr runnable = - NewRunnableMethod>( - this, &AppleVTDecoder::SubmitFrame, aSample); - mTaskQueue->Dispatch(runnable.forget()); - return NS_OK; -} - void AppleVTDecoder::ProcessFlush() { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + AssertOnTaskQueueThread(); nsresult rv = WaitForAsynchronousFrames(); if (NS_FAILED(rv)) { LOG("AppleVTDecoder::Flush failed waiting for platform decoder " "with error:%d.", rv); } ClearReorderedFrames(); - MonitorAutoLock mon(mMonitor); - mIsFlushing = false; - mon.NotifyAll(); } void AppleVTDecoder::ProcessDrain() { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + AssertOnTaskQueueThread(); nsresult rv = WaitForAsynchronousFrames(); if (NS_FAILED(rv)) { LOG("AppleVTDecoder::Drain failed waiting for platform decoder " @@ -205,10 +163,10 @@ TimingInfoFromSample(MediaRawData* aSample) } nsresult -AppleVTDecoder::SubmitFrame(MediaRawData* aSample) +AppleVTDecoder::DoDecode(MediaRawData* aSample) { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - mInputIncoming--; + AssertOnTaskQueueThread(); + // For some reason this gives me a double-free error with stagefright. AutoCFRelease block = nullptr; AutoCFRelease sample = nullptr; @@ -251,16 +209,10 @@ AppleVTDecoder::SubmitFrame(MediaRawData* aSample) if (rv != noErr && !(infoFlags & kVTDecodeInfo_FrameDropped)) { LOG("AppleVTDecoder: Error %d VTDecompressionSessionDecodeFrame", rv); NS_WARNING("Couldn't pass frame to decoder"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); return NS_ERROR_FAILURE; } - // Ask for more data. - if (!mInputIncoming && mQueuedSamples <= mMaxRefFrames) { - LOG("AppleVTDecoder task queue empty; requesting more data"); - mCallback->InputExhausted(); - } - return NS_OK; } @@ -269,19 +221,6 @@ AppleVTDecoder::InitializeSession() { OSStatus rv; -#ifdef LOG_MEDIA_SHA1 - SHA1Sum avc_hash; - avc_hash.update(mExtraData->Elements(),mExtraData->Length()); - uint8_t digest_buf[SHA1Sum::kHashSize]; - avc_hash.finish(digest_buf); - nsAutoCString avc_digest; - for (size_t i = 0; i < sizeof(digest_buf); i++) { - avc_digest.AppendPrintf("%02x", digest_buf[i]); - } - LOG("AVCDecoderConfig %ld bytes sha1 %s", - mExtraData->Length(), avc_digest.get()); -#endif // LOG_MEDIA_SHA1 - AutoCFRelease extensions = CreateDecoderExtensions(); rv = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, diff --git a/dom/media/platforms/apple/AppleVTDecoder.h b/dom/media/platforms/apple/AppleVTDecoder.h index 3a6536b422..1f972bfd90 100644 --- a/dom/media/platforms/apple/AppleVTDecoder.h +++ b/dom/media/platforms/apple/AppleVTDecoder.h @@ -16,12 +16,13 @@ namespace mozilla { class AppleVTDecoder : public AppleVDADecoder { public: AppleVTDecoder(const VideoInfo& aConfig, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, layers::ImageContainer* aImageContainer); + +private: virtual ~AppleVTDecoder(); RefPtr Init() override; - nsresult Input(MediaRawData* aSample) override; bool IsHardwareAccelerated(nsACString& aFailureReason) const override { return mIsHardwareAccelerated; @@ -34,17 +35,15 @@ public: : "apple software VT decoder"; } -protected: void ProcessFlush() override; void ProcessDrain() override; void ProcessShutdown() override; -private: CMVideoFormatDescriptionRef mFormat; VTDecompressionSessionRef mSession; // Method to pass a frame to VideoToolbox for decoding. - nsresult SubmitFrame(MediaRawData* aSample); + nsresult DoDecode(MediaRawData* aSample) override; // Method to set up the decompression session. nsresult InitializeSession(); nsresult WaitForAsynchronousFrames(); diff --git a/dom/media/platforms/apple/AppleVTLinker.cpp b/dom/media/platforms/apple/AppleVTLinker.cpp index 8adda27225..51a8a01227 100644 --- a/dom/media/platforms/apple/AppleVTLinker.cpp +++ b/dom/media/platforms/apple/AppleVTLinker.cpp @@ -7,12 +7,10 @@ #include #include "AppleVTLinker.h" -#include "MainThreadUtils.h" #include "mozilla/ArrayUtils.h" #include "nsDebug.h" -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) namespace mozilla { @@ -20,7 +18,6 @@ AppleVTLinker::LinkStatus AppleVTLinker::sLinkStatus = LinkStatus_INIT; void* AppleVTLinker::sLink = nullptr; -nsrefcnt AppleVTLinker::sRefCount = 0; CFStringRef AppleVTLinker::skPropEnableHWAccel = nullptr; CFStringRef AppleVTLinker::skPropUsingHWAccel = nullptr; @@ -31,12 +28,6 @@ CFStringRef AppleVTLinker::skPropUsingHWAccel = nullptr; /* static */ bool AppleVTLinker::Link() { - // Bump our reference count every time we're called. - // Add a lock or change the thread assertion if - // you need to call this off the main thread. - MOZ_ASSERT(NS_IsMainThread()); - ++sRefCount; - if (sLinkStatus) { return sLinkStatus == LinkStatus_SUCCEEDED; } @@ -85,14 +76,7 @@ fail: /* static */ void AppleVTLinker::Unlink() { - // We'll be called by multiple Decoders, one intantiated for - // each media element. Therefore we receive must maintain a - // reference count to avoidunloading our symbols when other - // instances still need them. - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(sRefCount > 0, "Unbalanced Unlink()"); - --sRefCount; - if (sLink && sRefCount < 1) { + if (sLink) { LOG("Unlinking VideoToolbox framework."); #define LINK_FUNC(func) \ func = nullptr; diff --git a/dom/media/platforms/apple/AppleVTLinker.h b/dom/media/platforms/apple/AppleVTLinker.h index 56d1b1055f..49783432d6 100644 --- a/dom/media/platforms/apple/AppleVTLinker.h +++ b/dom/media/platforms/apple/AppleVTLinker.h @@ -27,7 +27,6 @@ public: private: static void* sLink; - static nsrefcnt sRefCount; static enum LinkStatus { LinkStatus_INIT = 0, diff --git a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp index c06e449388..0bf9693cac 100644 --- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp @@ -20,7 +20,7 @@ static int (*avcodec_decode_audio4)(AVCodecContext*,AVFrame*, static void (*av_init_packet1)(AVPacket*) = nullptr; FFmpegAudioDecoder::FFmpegAudioDecoder( - FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, const AudioInfo& aConfig) : FFmpegDataDecoder(aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType)) { @@ -153,10 +153,9 @@ CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames) return audio; } -void -FFmpegAudioDecoder::DecodePacket(MediaRawData* aSample) +FFmpegAudioDecoder::DecodeResult +FFmpegAudioDecoder::DoDecode(MediaRawData* aSample) { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); AVPacket packet; av_init_packet1(&packet); @@ -165,8 +164,7 @@ FFmpegAudioDecoder::DecodePacket(MediaRawData* aSample) if (!PrepareFrame()) { NS_WARNING("FFmpeg audio decoder failed to allocate frame."); - mCallback->Error(); - return; + return DecodeResult::FATAL_ERROR; } int64_t samplePosition = aSample->mOffset; @@ -179,16 +177,14 @@ FFmpegAudioDecoder::DecodePacket(MediaRawData* aSample) if (bytesConsumed < 0) { NS_WARNING("FFmpeg audio decoder error."); - mCallback->Error(); - return; + return DecodeResult::DECODE_ERROR; } if (decoded) { uint32_t numChannels = mCodecContext->channels; AudioConfig::ChannelLayout layout(numChannels); if (!layout.IsValid()) { - mCallback->Error(); - return; + return DecodeResult::FATAL_ERROR; } uint32_t samplingRate = mCodecContext->sample_rate; @@ -200,8 +196,7 @@ FFmpegAudioDecoder::DecodePacket(MediaRawData* aSample) FramesToTimeUnit(mFrame->nb_samples, samplingRate); if (!audio || !duration.IsValid()) { NS_WARNING("Invalid count of accumulated audio samples"); - mCallback->Error(); - return; + return DecodeResult::DECODE_ERROR; } RefPtr data = new AudioData(samplePosition, @@ -215,8 +210,7 @@ FFmpegAudioDecoder::DecodePacket(MediaRawData* aSample) pts += duration; if (!pts.IsValid()) { NS_WARNING("Invalid count of accumulated audio samples"); - mCallback->Error(); - return; + return DecodeResult::DECODE_ERROR; } } packet.data += bytesConsumed; @@ -224,24 +218,12 @@ FFmpegAudioDecoder::DecodePacket(MediaRawData* aSample) samplePosition += bytesConsumed; } - if (mTaskQueue->IsEmpty()) { - mCallback->InputExhausted(); - } -} - -nsresult -FFmpegAudioDecoder::Input(MediaRawData* aSample) -{ - nsCOMPtr runnable(NewRunnableMethod>( - this, &FFmpegAudioDecoder::DecodePacket, RefPtr(aSample))); - mTaskQueue->Dispatch(runnable.forget()); - return NS_OK; + return DecodeResult::DECODE_FRAME; } void FFmpegAudioDecoder::ProcessDrain() { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); ProcessFlush(); mCallback->DrainComplete(); } diff --git a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h index eff22de964..e47efcb5bb 100644 --- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h +++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h @@ -20,14 +20,12 @@ template <> class FFmpegAudioDecoder : public FFmpegDataDecoder { public: - FFmpegAudioDecoder(FlushableTaskQueue* aTaskQueue, + FFmpegAudioDecoder(TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, const AudioInfo& aConfig); virtual ~FFmpegAudioDecoder(); RefPtr Init() override; - nsresult Input(MediaRawData* aSample) override; - void ProcessDrain() override; void InitCodecContext() override; static AVCodecID GetCodecId(const nsACString& aMimeType); const char* GetDescriptionName() const override @@ -36,7 +34,8 @@ public: } private: - void DecodePacket(MediaRawData* aSample); + DecodeResult DoDecode(MediaRawData* aSample) override; + void ProcessDrain() override; }; } // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp index fecec59617..2b08f75841 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp @@ -4,6 +4,7 @@ * 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/. */ +#include "mozilla/SyncRunnable.h" #include "mozilla/TaskQueue.h" #include @@ -23,16 +24,15 @@ namespace mozilla bool FFmpegDataDecoder::sFFmpegInitDone = false; StaticMutex FFmpegDataDecoder::sMonitor; -FFmpegDataDecoder::FFmpegDataDecoder(FlushableTaskQueue* aTaskQueue, +FFmpegDataDecoder::FFmpegDataDecoder(TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, AVCodecID aCodecID) - : mTaskQueue(aTaskQueue) - , mCallback(aCallback) + : mCallback(aCallback) , mCodecContext(nullptr) , mFrame(NULL) , mExtraData(nullptr) , mCodecID(aCodecID) - , mMonitor("FFMpegaDataDecoder") + , mTaskQueue(aTaskQueue) , mIsFlushing(false) { MOZ_COUNT_CTOR(FFmpegDataDecoder); @@ -135,19 +135,44 @@ FFmpegDataDecoder::Shutdown() return NS_OK; } +void +FFmpegDataDecoder::ProcessDecode(MediaRawData* aSample) +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + if (mIsFlushing) { + return; + } + switch (DoDecode(aSample)) { + case DecodeResult::DECODE_ERROR: + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); + break; + case DecodeResult::FATAL_ERROR: + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); + break; + default: + if (mTaskQueue->IsEmpty()) { + mCallback->InputExhausted(); + } + } +} + +nsresult +FFmpegDataDecoder::Input(MediaRawData* aSample) +{ + mTaskQueue->Dispatch(NewRunnableMethod>( + this, &FFmpegDataDecoder::ProcessDecode, aSample)); + return NS_OK; +} + nsresult FFmpegDataDecoder::Flush() { MOZ_ASSERT(mCallback->OnReaderTaskQueue()); mIsFlushing = true; - mTaskQueue->Flush(); nsCOMPtr runnable = NewRunnableMethod(this, &FFmpegDataDecoder::ProcessFlush); - MonitorAutoLock mon(mMonitor); - mTaskQueue->Dispatch(runnable.forget()); - while (mIsFlushing) { - mon.Wait(); - } + SyncRunnable::DispatchToThread(mTaskQueue, runnable); + mIsFlushing = false; return NS_OK; } @@ -172,9 +197,6 @@ FFmpegDataDecoder::ProcessFlush() avcodec_flush_buffers(mCodecContext); #endif } - MonitorAutoLock mon(mMonitor); - mIsFlushing = false; - mon.NotifyAll(); } void diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h index ad7b0ce99a..e45752a7d3 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h @@ -23,7 +23,7 @@ template <> class FFmpegDataDecoder : public MediaDataDecoder { public: - FFmpegDataDecoder(FlushableTaskQueue* aTaskQueue, + FFmpegDataDecoder(TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, AVCodecID aCodecID); virtual ~FFmpegDataDecoder(); @@ -31,7 +31,7 @@ public: static bool Link(); RefPtr Init() override = 0; - nsresult Input(MediaRawData* aSample) override = 0; + nsresult Input(MediaRawData* aSample) override; nsresult Flush() override; nsresult Drain() override; nsresult Shutdown() override; @@ -39,15 +39,20 @@ public: static AVCodec* FindAVCodec(AVCodecID aCodec); protected: + enum DecodeResult { + DECODE_FRAME, + DECODE_NO_FRAME, + DECODE_ERROR, + FATAL_ERROR + }; + // Flush and Drain operation, always run virtual void ProcessFlush(); - virtual void ProcessDrain() = 0; virtual void ProcessShutdown(); virtual void InitCodecContext() {} AVFrame* PrepareFrame(); nsresult InitDecoder(); - RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; AVCodecContext* mCodecContext; @@ -55,17 +60,17 @@ protected: RefPtr mExtraData; AVCodecID mCodecID; - // For wait on mIsFlushing during Shutdown() process. - // Protects mReorderQueue. - Monitor mMonitor; - // Set on reader/decode thread calling Flush() to indicate that output is - // not required and so input samples on mTaskQueue need not be processed. - // Cleared on mTaskQueue in ProcessDrain(). - Atomic mIsFlushing; - private: + void ProcessDecode(MediaRawData* aSample); + virtual DecodeResult DoDecode(MediaRawData* aSample) = 0; + virtual void ProcessDrain() = 0; + static bool sFFmpegInitDone; static StaticMutex sMonitor; + const RefPtr mTaskQueue; + // Set/cleared on reader thread calling Flush() to indicate that output is + // not required and so input samples on mTaskQueue need not be processed. + Atomic mIsFlushing; }; } // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h index 84b404ee8a..35f56b8191 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h +++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h @@ -33,24 +33,24 @@ public: CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override { RefPtr decoder = - new FFmpegH264Decoder(aVideoTaskQueue, aCallback, aConfig, + new FFmpegH264Decoder(aTaskQueue, aCallback, aConfig, aImageContainer); return decoder.forget(); } already_AddRefed CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override { RefPtr decoder = - new FFmpegAudioDecoder(aAudioTaskQueue, aCallback, aConfig); + new FFmpegAudioDecoder(aTaskQueue, aCallback, aConfig); return decoder.forget(); } diff --git a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp index facf89d424..c6e6fcd4db 100644 --- a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp @@ -110,13 +110,14 @@ FFmpegH264Decoder::PtsCorrectionContext::Reset() } FFmpegH264Decoder::FFmpegH264Decoder( - FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, const VideoInfo& aConfig, ImageContainer* aImageContainer) : FFmpegDataDecoder(aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType)) , mImageContainer(aImageContainer) , mInfo(aConfig) , mCodecParser(nullptr) + , mLastInputDts(INT64_MIN) { MOZ_COUNT_CTOR(FFmpegH264Decoder); // Use a new MediaByteBuffer as the object will be modified during initialization. @@ -183,10 +184,8 @@ FFmpegH264Decoder::InitCodecContext() } FFmpegH264Decoder::DecodeResult -FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample) +FFmpegH264Decoder::DoDecode(MediaRawData* aSample) { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - uint8_t* inputData = const_cast(aSample->Data()); size_t inputSize = aSample->Size(); @@ -217,13 +216,12 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample) aSample->mOffset); #endif if (size_t(len) > inputSize) { - mCallback->Error(); return DecodeResult::DECODE_ERROR; } inputData += len; inputSize -= len; if (size) { - switch (DoDecodeFrame(aSample, data, size)) { + switch (DoDecode(aSample, data, size)) { case DecodeResult::DECODE_ERROR: return DecodeResult::DECODE_ERROR; case DecodeResult::DECODE_FRAME: @@ -237,12 +235,12 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample) return gotFrame ? DecodeResult::DECODE_FRAME : DecodeResult::DECODE_NO_FRAME; } #endif - return DoDecodeFrame(aSample, inputData, inputSize); + return DoDecode(aSample, inputData, inputSize); } FFmpegH264Decoder::DecodeResult -FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample, - uint8_t* aData, int aSize) +FFmpegH264Decoder::DoDecode(MediaRawData* aSample, + uint8_t* aData, int aSize) { MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); @@ -251,7 +249,7 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample, packet.data = aData; packet.size = aSize; - packet.dts = aSample->mTimecode; + packet.dts = mLastInputDts = aSample->mTimecode; packet.pts = aSample->mTime; packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0; packet.pos = aSample->mOffset; @@ -265,8 +263,7 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample, if (!PrepareFrame()) { NS_WARNING("FFmpeg h264 decoder failed to allocate frame."); - mCallback->Error(); - return DecodeResult::DECODE_ERROR; + return DecodeResult::FATAL_ERROR; } // Required with old version of FFmpeg/LibAV @@ -284,15 +281,12 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample, if (bytesConsumed < 0) { NS_WARNING("FFmpeg video decoder error."); - mCallback->Error(); return DecodeResult::DECODE_ERROR; } // If we've decoded a frame then we need to output it if (decoded) { int64_t pts = mPtsContext.GuessCorrectPts(mFrame->pkt_pts, mFrame->pkt_dts); - FFMPEG_LOG("Got one frame output with pts=%lld opaque=%lld", - pts, mCodecContext->reordered_opaque); // Retrieve duration from dts. // We use the first entry found matching this dts (this is done to // handle damaged file with multiple frames with the same dts) @@ -306,6 +300,8 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample, // against the map becoming extremely big. mDurationMap.Clear(); } + FFMPEG_LOG("Got one frame output with pts=%lld dts=%lld duration=%lld opaque=%lld", + pts, mFrame->pkt_dts, duration, mCodecContext->reordered_opaque); VideoData::YCbCrBuffer b; b.mPlanes[0].mData = mFrame->data[0]; @@ -343,8 +339,7 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample, if (!v) { NS_WARNING("image allocation error."); - mCallback->Error(); - return DecodeResult::DECODE_ERROR; + return DecodeResult::FATAL_ERROR; } mCallback->Output(v); return DecodeResult::DECODE_FRAME; @@ -352,35 +347,12 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample, return DecodeResult::DECODE_NO_FRAME; } -void -FFmpegH264Decoder::DecodeFrame(MediaRawData* aSample) -{ - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - - if (DoDecodeFrame(aSample) != DecodeResult::DECODE_ERROR && - mTaskQueue->IsEmpty()) { - mCallback->InputExhausted(); - } -} - -nsresult -FFmpegH264Decoder::Input(MediaRawData* aSample) -{ - nsCOMPtr runnable( - NewRunnableMethod>( - this, &FFmpegH264Decoder::DecodeFrame, - RefPtr(aSample))); - mTaskQueue->Dispatch(runnable.forget()); - - return NS_OK; -} - void FFmpegH264Decoder::ProcessDrain() { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); RefPtr empty(new MediaRawData()); - while (DoDecodeFrame(empty) == DecodeResult::DECODE_FRAME) { + empty->mTimecode = mLastInputDts; + while (DoDecode(empty) == DecodeResult::DECODE_FRAME) { } mCallback->DrainComplete(); } diff --git a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.h b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.h index ace6927d95..6a1479d828 100644 --- a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.h +++ b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.h @@ -25,23 +25,14 @@ class FFmpegH264Decoder : public FFmpegDataDecoder typedef mozilla::layers::Image Image; typedef mozilla::layers::ImageContainer ImageContainer; - enum DecodeResult { - DECODE_FRAME, - DECODE_NO_FRAME, - DECODE_ERROR - }; - public: - FFmpegH264Decoder(FlushableTaskQueue* aTaskQueue, + FFmpegH264Decoder(TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, const VideoInfo& aConfig, ImageContainer* aImageContainer); virtual ~FFmpegH264Decoder(); RefPtr Init() override; - nsresult Input(MediaRawData* aSample) override; - void ProcessDrain() override; - void ProcessFlush() override; void InitCodecContext() override; const char* GetDescriptionName() const override { @@ -54,10 +45,10 @@ public: static AVCodecID GetCodecId(const nsACString& aMimeType); private: - void DecodeFrame(MediaRawData* aSample); - DecodeResult DoDecodeFrame(MediaRawData* aSample); - DecodeResult DoDecodeFrame(MediaRawData* aSample, uint8_t* aData, int aSize); - void DoDrain(); + DecodeResult DoDecode(MediaRawData* aSample) override; + DecodeResult DoDecode(MediaRawData* aSample, uint8_t* aData, int aSize); + void ProcessDrain() override; + void ProcessFlush() override; void OutputDelayedFrames(); /** @@ -80,6 +71,7 @@ private: PtsCorrectionContext(); int64_t GuessCorrectPts(int64_t aPts, int64_t aDts); void Reset(); + int64_t LastDts() const { return mLastDts; } private: int64_t mNumFaultyPts; /// Number of incorrect PTS values so far @@ -89,24 +81,25 @@ private: }; PtsCorrectionContext mPtsContext; + int64_t mLastInputDts; class DurationMap { public: typedef Pair DurationElement; - // Insert Dts and Duration pair at the end of our map. - void Insert(int64_t aDts, int64_t aDuration) + // Insert Key and Duration pair at the end of our map. + void Insert(int64_t aKey, int64_t aDuration) { - mMap.AppendElement(MakePair(aDts, aDuration)); + mMap.AppendElement(MakePair(aKey, aDuration)); } - // Sets aDuration matching aDts and remove it from the map if found. + // Sets aDuration matching aKey and remove it from the map if found. // The element returned is the first one found. // Returns true if found, false otherwise. - bool Find(int64_t aDts, int64_t& aDuration) + bool Find(int64_t aKey, int64_t& aDuration) { for (uint32_t i = 0; i < mMap.Length(); i++) { DurationElement& element = mMap[i]; - if (element.first() == aDts) { + if (element.first() == aKey) { aDuration = element.second(); mMap.RemoveElementAt(i); return true; diff --git a/dom/media/platforms/ffmpeg/FFmpegLog.h b/dom/media/platforms/ffmpeg/FFmpegLog.h index eb1d22d99c..32ceb6d2dd 100644 --- a/dom/media/platforms/ffmpeg/FFmpegLog.h +++ b/dom/media/platforms/ffmpeg/FFmpegLog.h @@ -7,7 +7,6 @@ #ifndef __FFmpegLog_h__ #define __FFmpegLog_h__ -extern mozilla::LogModule* GetPDMLog(); -#define FFMPEG_LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define FFMPEG_LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) #endif // __FFmpegLog_h__ diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp index 5798b86edc..0e50da2d61 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp @@ -66,8 +66,6 @@ FFmpegRuntimeLinker::Link() return sLinkStatus == LinkStatus_SUCCEEDED; } - MOZ_ASSERT(NS_IsMainThread()); - #if defined(XP_WIN) HKEY aKey; DWORD d; diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp index 9693a152c7..97334b61be 100644 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp @@ -27,8 +27,7 @@ #include #define GADM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkAudioDecoderManager", __VA_ARGS__) -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) using namespace android; typedef android::MediaCodecProxy MediaCodecProxy; diff --git a/dom/media/platforms/gonk/GonkDecoderModule.cpp b/dom/media/platforms/gonk/GonkDecoderModule.cpp index 8661302acd..72088c9a7d 100644 --- a/dom/media/platforms/gonk/GonkDecoderModule.cpp +++ b/dom/media/platforms/gonk/GonkDecoderModule.cpp @@ -18,18 +18,11 @@ GonkDecoderModule::~GonkDecoderModule() { } -/* static */ -void -GonkDecoderModule::Init() -{ - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); -} - already_AddRefed GonkDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, mozilla::layers::LayersBackend aLayersBackend, mozilla::layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -41,7 +34,7 @@ GonkDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, already_AddRefed GonkDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { diff --git a/dom/media/platforms/gonk/GonkDecoderModule.h b/dom/media/platforms/gonk/GonkDecoderModule.h index 69ac7a82a7..542d043bdb 100644 --- a/dom/media/platforms/gonk/GonkDecoderModule.h +++ b/dom/media/platforms/gonk/GonkDecoderModule.h @@ -21,19 +21,17 @@ public: CreateVideoDecoder(const VideoInfo& aConfig, mozilla::layers::LayersBackend aLayersBackend, mozilla::layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; // Decode thread. already_AddRefed CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; - static void Init(); - ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override; diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp index 6ed1739690..4eb6c2aa87 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp @@ -20,8 +20,7 @@ #include #endif -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) using namespace android; diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp index 78bd3dd0f0..a663b8d6e9 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp @@ -32,8 +32,7 @@ #include #define GVDM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkVideoDecoderManager", __VA_ARGS__) -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) using namespace mozilla::layers; using namespace android; typedef android::MediaCodecProxy MediaCodecProxy; diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index dfdcedc639..c8b441322e 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -24,7 +24,6 @@ UNIFIED_SOURCES += [ 'agnostic/VPXDecoder.cpp', 'agnostic/WAVDecoder.cpp', 'PDMFactory.cpp', - 'PlatformDecoderModule.cpp', 'wrappers/FuzzingWrapper.cpp', 'wrappers/H264Converter.cpp' ] diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index e1322d5f3a..1d07ab1dd4 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -12,10 +12,10 @@ #include "D3D9SurfaceImage.h" #include "mozilla/layers/D3D11ShareHandleImage.h" #include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" #include "MediaTelemetryConstants.h" #include "mfapi.h" +#include "MediaPrefs.h" #include "MFTDecoder.h" #include "DriverCrashGuard.h" #include "nsPrintfCString.h" @@ -390,8 +390,7 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason) return hr; } - if (adapter.VendorId == 0x1022 && - !Preferences::GetBool("media.wmf.skip-blacklist", false)) { + if (adapter.VendorId == 0x1022 && !MediaPrefs::PDMWMFSkipBlacklist()) { for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sAMDPreUVD4); i++) { if (adapter.DeviceId == sAMDPreUVD4[i]) { mIsAMDPreUVD4 = true; @@ -474,8 +473,7 @@ DXVA2Manager::CreateD3D9DXVA(nsACString& aFailureReason) // DXVA processing takes up a lot of GPU resources, so limit the number of // videos we use DXVA with at any one time. - const uint32_t dxvaLimit = - Preferences::GetInt("media.windows-media-foundation.max-dxva-videos", 8); + const uint32_t dxvaLimit = MediaPrefs::PDMWMFMaxDXVAVideos(); if (sDXVAVideosCount == dxvaLimit) { aFailureReason.AssignLiteral("Too many DXVA videos playing"); return nullptr; @@ -702,8 +700,7 @@ D3D11DXVA2Manager::Init(nsACString& aFailureReason) return hr; } - if (adapterDesc.VendorId == 0x1022 && - !Preferences::GetBool("media.wmf.skip-blacklist", false)) { + if (adapterDesc.VendorId == 0x1022 && !MediaPrefs::PDMWMFSkipBlacklist()) { for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sAMDPreUVD4); i++) { if (adapterDesc.DeviceId == sAMDPreUVD4[i]) { mIsAMDPreUVD4 = true; @@ -871,8 +868,7 @@ DXVA2Manager::CreateD3D11DXVA(nsACString& aFailureReason) { // DXVA processing takes up a lot of GPU resources, so limit the number of // videos we use DXVA with at any one time. - const uint32_t dxvaLimit = - Preferences::GetInt("media.windows-media-foundation.max-dxva-videos", 8); + const uint32_t dxvaLimit = MediaPrefs::PDMWMFMaxDXVAVideos(); if (sDXVAVideosCount == dxvaLimit) { aFailureReason.AssignLiteral("Too many DXVA videos playing"); return nullptr; diff --git a/dom/media/platforms/wmf/MFTDecoder.cpp b/dom/media/platforms/wmf/MFTDecoder.cpp index e5fd17da4a..e634fcff94 100644 --- a/dom/media/platforms/wmf/MFTDecoder.cpp +++ b/dom/media/platforms/wmf/MFTDecoder.cpp @@ -9,8 +9,7 @@ #include "WMFUtils.h" #include "mozilla/Logging.h" -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) namespace mozilla { diff --git a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp index 779c71ca19..9ed4246f9a 100644 --- a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp @@ -13,8 +13,7 @@ #include "mozilla/Telemetry.h" #include "mozilla/Logging.h" -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) namespace mozilla { diff --git a/dom/media/platforms/wmf/WMFDecoderModule.cpp b/dom/media/platforms/wmf/WMFDecoderModule.cpp index e161434b8c..df90ad283a 100644 --- a/dom/media/platforms/wmf/WMFDecoderModule.cpp +++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp @@ -27,7 +27,7 @@ namespace mozilla { -static bool sDXVAEnabled = false; +static Atomic sDXVAEnabled(false); WMFDecoderModule::WMFDecoderModule() : mWMFInitialized(false) @@ -46,7 +46,6 @@ WMFDecoderModule::~WMFDecoderModule() void WMFDecoderModule::Init() { - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); sDXVAEnabled = gfxPlatform::GetPlatform()->CanUseHardwareVideoDecoding(); } @@ -79,7 +78,7 @@ already_AddRefed WMFDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -94,14 +93,14 @@ WMFDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, } RefPtr decoder = - new WMFMediaDataDecoder(manager.forget(), aVideoTaskQueue, aCallback); + new WMFMediaDataDecoder(manager.forget(), aTaskQueue, aCallback); return decoder.forget(); } already_AddRefed WMFDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) { @@ -112,7 +111,7 @@ WMFDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, } RefPtr decoder = - new WMFMediaDataDecoder(manager.forget(), aAudioTaskQueue, aCallback); + new WMFMediaDataDecoder(manager.forget(), aTaskQueue, aCallback); return decoder.forget(); } diff --git a/dom/media/platforms/wmf/WMFDecoderModule.h b/dom/media/platforms/wmf/WMFDecoderModule.h index b6ae92a5fd..e94efa1f16 100644 --- a/dom/media/platforms/wmf/WMFDecoderModule.h +++ b/dom/media/platforms/wmf/WMFDecoderModule.h @@ -23,13 +23,13 @@ public: CreateVideoDecoder(const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; already_AddRefed CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) override; diff --git a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp index a947d110a2..9be56ee907 100644 --- a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp +++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp @@ -10,19 +10,18 @@ #include "nsTArray.h" #include "mozilla/Logging.h" +#include "mozilla/SyncRunnable.h" -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) namespace mozilla { WMFMediaDataDecoder::WMFMediaDataDecoder(MFTManager* aMFTManager, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) : mTaskQueue(aTaskQueue) , mCallback(aCallback) , mMFTManager(aMFTManager) - , mMonitor("WMFMediaDataDecoder") , mIsFlushing(false) , mIsShutDown(false) { @@ -84,18 +83,15 @@ WMFMediaDataDecoder::Input(MediaRawData* aSample) void WMFMediaDataDecoder::ProcessDecode(MediaRawData* aSample) { - { - MonitorAutoLock mon(mMonitor); - if (mIsFlushing) { - // Skip sample, to be released by runnable. - return; - } + if (mIsFlushing) { + // Skip sample, to be released by runnable. + return; } HRESULT hr = mMFTManager->Input(aSample); if (FAILED(hr)) { NS_WARNING("MFTManager rejected sample"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); if (!mRecordedError) { //SendTelemetry(hr); mRecordedError = true; @@ -124,7 +120,7 @@ WMFMediaDataDecoder::ProcessOutput() } } else if (FAILED(hr)) { NS_WARNING("WMFMediaDataDecoder failed to output data"); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::DECODE_ERROR); if (!mRecordedError) { //SendTelemetry(hr); mRecordedError = true; @@ -138,9 +134,6 @@ WMFMediaDataDecoder::ProcessFlush() if (mMFTManager) { mMFTManager->Flush(); } - MonitorAutoLock mon(mMonitor); - mIsFlushing = false; - mon.NotifyAll(); } nsresult @@ -149,24 +142,18 @@ WMFMediaDataDecoder::Flush() MOZ_ASSERT(mCallback->OnReaderTaskQueue()); MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); - MonitorAutoLock mon(mMonitor); mIsFlushing = true; - mTaskQueue->Dispatch(NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessFlush)); - while (mIsFlushing) { - mon.Wait(); - } + nsCOMPtr runnable = + NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessFlush); + SyncRunnable::DispatchToThread(mTaskQueue, runnable); + mIsFlushing = false; return NS_OK; } void WMFMediaDataDecoder::ProcessDrain() { - bool isFlushing; - { - MonitorAutoLock mon(mMonitor); - isFlushing = mIsFlushing; - } - if (!isFlushing && mMFTManager) { + if (!mIsFlushing && mMFTManager) { // Order the decoder to drain... mMFTManager->Drain(); // Then extract all available output. diff --git a/dom/media/platforms/wmf/WMFMediaDataDecoder.h b/dom/media/platforms/wmf/WMFMediaDataDecoder.h index ce1e23b006..7356b45ce8 100644 --- a/dom/media/platforms/wmf/WMFMediaDataDecoder.h +++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.h @@ -69,7 +69,7 @@ protected: class WMFMediaDataDecoder : public MediaDataDecoder { public: WMFMediaDataDecoder(MFTManager* aOutputSource, - FlushableTaskQueue* aAudioTaskQueue, + TaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback); ~WMFMediaDataDecoder(); @@ -116,7 +116,7 @@ private: // different configuration (typically resolution change). void ProcessConfigurationChanged(UniquePtr&& aConfig); - RefPtr mTaskQueue; + RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; nsAutoPtr mMFTManager; @@ -125,12 +125,10 @@ private: // This is used to approximate the decoder's position in the media resource. int64_t mLastStreamOffset; - // For access to and waiting on mIsFlushing - Monitor mMonitor; // Set on reader/decode thread calling Flush() to indicate that output is // not required and so input samples on mTaskQueue need not be processed. // Cleared on mTaskQueue. - bool mIsFlushing; + Atomic mIsFlushing; bool mIsShutDown; diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index 03722e927c..48280e8610 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -14,20 +14,23 @@ #include "DXVA2Manager.h" #include "nsThreadUtils.h" #include "Layers.h" +#include "mozilla/ClearOnShutdown.h" #include "mozilla/layers/LayersTypes.h" #include "MediaInfo.h" +#include "MediaPrefs.h" #include "mozilla/Logging.h" +#include "mozilla/Preferences.h" +#include "nsWindowsHelpers.h" #include "gfx2DGlue.h" #include "gfxWindowsPlatform.h" #include "IMFYCbCrImage.h" #include "mozilla/WindowsVersion.h" -#include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" #include "nsPrintfCString.h" #include "MediaTelemetryConstants.h" +#include "GMPUtils.h" // For SplitAt. TODO: Move SplitAt to a central place. -extern mozilla::LogModule* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) using mozilla::layers::Image; using mozilla::layers::IMFYCbCrImage; @@ -150,6 +153,127 @@ WMFVideoMFTManager::GetMediaSubtypeGUID() }; } +struct D3D11BlacklistingCache +{ + // D3D11-blacklist pref last seen. + nsCString mBlacklistPref; + // Non-empty if a D3D11-blacklisted DLL was found. + nsCString mBlacklistedDLL; +}; +StaticAutoPtr sD3D11BlacklistingCache; + +// If a blacklisted DLL is found, return its information, otherwise "". +static const nsACString& +FindD3D11BlacklistedDLL() +{ + NS_ASSERTION(NS_IsMainThread(), "Must be on main thread."); + + if (!sD3D11BlacklistingCache) { + // First time here, create persistent data that will be reused in all + // D3D11-blacklisting checks. + sD3D11BlacklistingCache = new D3D11BlacklistingCache(); + ClearOnShutdown(&sD3D11BlacklistingCache); + } + + nsAdoptingCString blacklist = + Preferences::GetCString("media.wmf.disable-d3d11-for-dlls"); + if (blacklist.IsEmpty()) { + // Empty blacklist -> No blacklisting. + sD3D11BlacklistingCache->mBlacklistPref.SetLength(0); + sD3D11BlacklistingCache->mBlacklistedDLL.SetLength(0); + return sD3D11BlacklistingCache->mBlacklistedDLL; + } + + // Detect changes in pref. + if (sD3D11BlacklistingCache->mBlacklistPref.Equals(blacklist)) { + // Same blacklist -> Return same result (i.e., don't check DLLs again). + return sD3D11BlacklistingCache->mBlacklistedDLL; + } + // Adopt new pref now, so we don't work on it again. + sD3D11BlacklistingCache->mBlacklistPref = blacklist; + + // media.wmf.disable-d3d11-for-dlls format: (whitespace is trimmed) + // "dll1.dll: 1.2.3.4[, more versions...][; more dlls...]" + nsTArray dlls; + SplitAt(";", blacklist, dlls); + for (const auto& dll : dlls) { + nsTArray nameAndVersions; + SplitAt(":", dll, nameAndVersions); + if (nameAndVersions.Length() != 2) { + NS_WARNING("Skipping incorrect 'media.wmf.disable-d3d11-for-dlls' dll:versions format"); + continue; + } + + nameAndVersions[0].CompressWhitespace(); + NS_ConvertUTF8toUTF16 name(nameAndVersions[0]); + WCHAR systemPath[MAX_PATH + 1]; + if (!ConstructSystem32Path(name.get(), systemPath, MAX_PATH + 1)) { + // Cannot build path -> Assume it's not the blacklisted DLL. + continue; + } + + DWORD zero; + DWORD infoSize = GetFileVersionInfoSizeW(systemPath, &zero); + if (infoSize == 0) { + // Can't get file info -> Assume we don't have the blacklisted DLL. + continue; + } + // vInfo is a pointer into infoData, that's why we keep it outside of the loop. + auto infoData = MakeUnique(infoSize); + VS_FIXEDFILEINFO *vInfo; + UINT vInfoLen; + if (!GetFileVersionInfoW(systemPath, 0, infoSize, infoData.get()) + || !VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen) + || !vInfo) { + // Can't find version -> Assume it's not blacklisted. + continue; + } + + nsTArray versions; + SplitAt(",", nameAndVersions[1], versions); + for (const auto& version : versions) { + nsTArray numberStrings; + SplitAt(".", version, numberStrings); + if (numberStrings.Length() != 4) { + NS_WARNING("Skipping incorrect 'media.wmf.disable-d3d11-for-dlls' a.b.c.d version format"); + continue; + } + DWORD numbers[4]; + nsresult errorCode = NS_OK; + for (int i = 0; i < 4; ++i) { + numberStrings[i].CompressWhitespace(); + numbers[i] = DWORD(numberStrings[i].ToInteger(&errorCode)); + if (NS_FAILED(errorCode)) { + break; + } + if (numbers[i] > UINT16_MAX) { + errorCode = NS_ERROR_FAILURE; + break; + } + } + + if (NS_FAILED(errorCode)) { + NS_WARNING("Skipping incorrect 'media.wmf.disable-d3d11-for-dlls' a.b.c.d version format"); + continue; + } + + if (vInfo->dwFileVersionMS == ((numbers[0] << 16) | numbers[1]) + && vInfo->dwFileVersionLS == ((numbers[2] << 16) | numbers[3])) { + // Blacklisted! Record bad DLL. + sD3D11BlacklistingCache->mBlacklistedDLL.SetLength(0); + sD3D11BlacklistingCache->mBlacklistedDLL.AppendPrintf( + "%s (%lu.%lu.%lu.%lu)", + nameAndVersions[0].get(), numbers[0], numbers[1], numbers[2], numbers[3]); + return sD3D11BlacklistingCache->mBlacklistedDLL; + } + } + } + + // No blacklisted DLL. + sD3D11BlacklistingCache->mBlacklistedDLL.SetLength(0); + return sD3D11BlacklistingCache->mBlacklistedDLL; +} + class CreateDXVAManagerEvent : public Runnable { public: CreateDXVAManagerEvent(LayersBackend aBackend, nsCString& aFailureReason) @@ -162,11 +286,16 @@ public: nsACString* failureReason = &mFailureReason; nsCString secondFailureReason; if (mBackend == LayersBackend::LAYERS_D3D11 && - Preferences::GetBool("media.windows-media-foundation.allow-d3d11-dxva", true) && - IsWin8OrLater()) { - mDXVA2Manager = DXVA2Manager::CreateD3D11DXVA(*failureReason); - if (mDXVA2Manager) { - return NS_OK; + MediaPrefs::PDMWMFAllowD3D11() && IsWin8OrLater()) { + const nsACString& blacklistedDLL = FindD3D11BlacklistedDLL(); + if (!blacklistedDLL.IsEmpty()) { + failureReason->AppendPrintf("D3D11 blacklisted with DLL %s", + blacklistedDLL); + } else { + mDXVA2Manager = DXVA2Manager::CreateD3D11DXVA(*failureReason); + if (mDXVA2Manager) { + return NS_OK; + } } // Try again with d3d9, but record the failure reason // into a new var to avoid overwriting the d3d11 failure. @@ -202,7 +331,9 @@ WMFVideoMFTManager::InitializeDXVA(bool aForceD3D9) // The DXVA manager must be created on the main thread. RefPtr event = - new CreateDXVAManagerEvent(aForceD3D9 ? LayersBackend::LAYERS_D3D9 : mLayersBackend, mDXVAFailureReason); + new CreateDXVAManagerEvent(aForceD3D9 ? LayersBackend::LAYERS_D3D9 + : mLayersBackend, + mDXVAFailureReason); if (NS_IsMainThread()) { event->Run(); @@ -671,17 +802,6 @@ WMFVideoMFTManager::IsHardwareAccelerated(nsACString& aFailureReason) const return mDecoder && mUseHwAccel; } -const char* -WMFVideoMFTManager::GetDescriptionName() const -{ - if (mDecoder && mUseHwAccel && mDXVA2Manager) { - return (mDXVA2Manager->IsD3D11()) ? - "D3D11 Hardware Decoder" : "D3D9 Hardware Decoder"; - } else { - return "wmf software video decoder"; - } -} - void WMFVideoMFTManager::ConfigurationChanged(const TrackInfo& aConfig) { diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.h b/dom/media/platforms/wmf/WMFVideoMFTManager.h index 8f75c37058..47031700ac 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.h +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h @@ -41,7 +41,12 @@ public: void ConfigurationChanged(const TrackInfo& aConfig) override; - const char* GetDescriptionName() const override; + const char* GetDescriptionName() const override + { + nsCString failureReason; + return IsHardwareAccelerated(failureReason) + ? "wmf hardware video decoder" : "wmf software video decoder"; + } private: diff --git a/dom/media/platforms/wrappers/FuzzingWrapper.cpp b/dom/media/platforms/wrappers/FuzzingWrapper.cpp index 3e4081f19d..a301d0006a 100644 --- a/dom/media/platforms/wrappers/FuzzingWrapper.cpp +++ b/dom/media/platforms/wrappers/FuzzingWrapper.cpp @@ -173,16 +173,19 @@ DecoderCallbackFuzzingWrapper::Output(MediaData* aData) } void -DecoderCallbackFuzzingWrapper::Error() +DecoderCallbackFuzzingWrapper::Error(MediaDataDecoderError aError) { if (!mTaskQueue->IsCurrentThreadIn()) { - mTaskQueue->Dispatch(NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::Error)); + mTaskQueue->Dispatch( + NewRunnableMethod(this, + &DecoderCallbackFuzzingWrapper::Error, + aError)); return; } CFW_LOGV(""); MOZ_ASSERT(mCallback); ClearDelayedOutput(); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); } void diff --git a/dom/media/platforms/wrappers/FuzzingWrapper.h b/dom/media/platforms/wrappers/FuzzingWrapper.h index f6b34624bf..83e5941d4c 100644 --- a/dom/media/platforms/wrappers/FuzzingWrapper.h +++ b/dom/media/platforms/wrappers/FuzzingWrapper.h @@ -60,7 +60,7 @@ private: // MediaDataDecoderCallback implementation. void Output(MediaData* aData) override; - void Error() override; + void Error(MediaDataDecoderError aError) override; void InputExhausted() override; void DrainComplete() override; void ReleaseMediaResources() override; diff --git a/dom/media/platforms/wrappers/H264Converter.cpp b/dom/media/platforms/wrappers/H264Converter.cpp index 38bbc7d20b..e179ca157d 100644 --- a/dom/media/platforms/wrappers/H264Converter.cpp +++ b/dom/media/platforms/wrappers/H264Converter.cpp @@ -19,7 +19,7 @@ H264Converter::H264Converter(PlatformDecoderModule* aPDM, const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics) : mPDM(aPDM) @@ -27,7 +27,7 @@ H264Converter::H264Converter(PlatformDecoderModule* aPDM, , mCurrentConfig(aConfig) , mLayersBackend(aLayersBackend) , mImageContainer(aImageContainer) - , mVideoTaskQueue(aVideoTaskQueue) + , mTaskQueue(aTaskQueue) , mCallback(aCallback) , mDecoder(nullptr) , mNeedAVCC(aPDM->DecoderNeedsConversion(aConfig) == PlatformDecoderModule::kNeedAVCC) @@ -149,7 +149,7 @@ H264Converter::CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics) mDecoder = mPDM->CreateVideoDecoder(mNeedAVCC ? mCurrentConfig : mOriginalConfig, mLayersBackend, mImageContainer, - mVideoTaskQueue, + mTaskQueue, mCallback, aDiagnostics); if (!mDecoder) { @@ -191,7 +191,7 @@ H264Converter::OnDecoderInitDone(const TrackType aTrackType) mInitPromiseRequest.Complete(); for (uint32_t i = 0 ; i < mMediaRawSamples.Length(); i++) { if (NS_FAILED(mDecoder->Input(mMediaRawSamples[i]))) { - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); } } mMediaRawSamples.Clear(); @@ -201,7 +201,7 @@ void H264Converter::OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason) { mInitPromiseRequest.Complete(); - mCallback->Error(); + mCallback->Error(MediaDataDecoderError::FATAL_ERROR); } nsresult diff --git a/dom/media/platforms/wrappers/H264Converter.h b/dom/media/platforms/wrappers/H264Converter.h index 4eb0627841..b5e5e11b23 100644 --- a/dom/media/platforms/wrappers/H264Converter.h +++ b/dom/media/platforms/wrappers/H264Converter.h @@ -25,7 +25,7 @@ public: const VideoInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, DecoderDoctorDiagnostics* aDiagnostics); virtual ~H264Converter(); @@ -65,7 +65,7 @@ private: VideoInfo mCurrentConfig; layers::LayersBackend mLayersBackend; RefPtr mImageContainer; - RefPtr mVideoTaskQueue; + const RefPtr mTaskQueue; nsTArray> mMediaRawSamples; MediaDataDecoderCallback* mCallback; RefPtr mDecoder; diff --git a/dom/media/wave/WaveDecoder.cpp b/dom/media/wave/WaveDecoder.cpp index e7fff4ca08..f2a0f2eab9 100644 --- a/dom/media/wave/WaveDecoder.cpp +++ b/dom/media/wave/WaveDecoder.cpp @@ -40,7 +40,6 @@ WaveDecoder::IsEnabled() if (!Preferences::GetBool("media.wave.decoder.enabled", false)) { return false; } - PDMFactory::Init(); RefPtr platform = new PDMFactory(); return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/x-wav"), /* DecoderDoctorDiagnostics* */ nullptr); diff --git a/dom/media/wave/WaveDemuxer.cpp b/dom/media/wave/WaveDemuxer.cpp index ab1c9eb637..cf127c07fa 100644 --- a/dom/media/wave/WaveDemuxer.cpp +++ b/dom/media/wave/WaveDemuxer.cpp @@ -10,7 +10,7 @@ #include #include "mozilla/Assertions.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "VideoUtils.h" #include "TimeUnits.h" #include "prenv.h" diff --git a/dom/media/wave/WaveReader.cpp b/dom/media/wave/WaveReader.cpp index 4722a7f495..13b9df2ba5 100644 --- a/dom/media/wave/WaveReader.cpp +++ b/dom/media/wave/WaveReader.cpp @@ -13,7 +13,7 @@ #include #include "mozilla/ArrayUtils.h" #include "mozilla/CheckedInt.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/UniquePtr.h" #include diff --git a/dom/media/webaudio/AlignedTArray.h b/dom/media/webaudio/AlignedTArray.h index 5fcc6824c3..afd2f1f48c 100644 --- a/dom/media/webaudio/AlignedTArray.h +++ b/dom/media/webaudio/AlignedTArray.h @@ -10,6 +10,60 @@ #include "mozilla/Alignment.h" #include "nsTArray.h" +/** + * E: element type, must be a POD type. + * N: N bytes alignment for the first element, defaults to 32 + * S: S bytes of inline storage + */ +template +class AlignedAutoTArray : private AutoTArray +{ + static_assert((N & (N-1)) == 0, "N must be power of 2"); + typedef AutoTArray base_type; +public: + typedef E elem_type; + typedef typename base_type::size_type size_type; + typedef typename base_type::index_type index_type; + + AlignedAutoTArray() {} + explicit AlignedAutoTArray(size_type capacity) : base_type(capacity + sExtra) {} + elem_type* Elements() { return getAligned(base_type::Elements()); } + const elem_type* Elements() const { return getAligned(base_type::Elements()); } + elem_type& operator[](index_type i) { return Elements()[i];} + const elem_type& operator[](index_type i) const { return Elements()[i]; } + + void SetLength(size_type newLen) + { + base_type::SetLength(newLen + sExtra); + } + + MOZ_MUST_USE + bool SetLength(size_type newLen, const mozilla::fallible_t&) + { + return base_type::SetLength(newLen + sExtra, mozilla::fallible); + } + + size_type Length() const { + return base_type::Length() <= sExtra ? 0 : base_type::Length() - sExtra; + } + + using base_type::ShallowSizeOfExcludingThis; + using base_type::ShallowSizeOfIncludingThis; + +private: + AlignedAutoTArray(const AlignedAutoTArray& other) = delete; + void operator=(const AlignedAutoTArray& other) = delete; + + static const size_type sPadding = N <= MOZ_ALIGNOF(E) ? 0 : N - MOZ_ALIGNOF(E); + static const size_type sExtra = (sPadding + sizeof(E) - 1) / sizeof(E); + + template + static U* getAligned(U* p) + { + return reinterpret_cast(((uintptr_t)p + N - 1) & ~(N-1)); + } +}; + /** * E: element type, must be a POD type. * N: N bytes alignment for the first element, defaults to 32 @@ -63,4 +117,5 @@ private: } }; + #endif // AlignedTArray_h__ diff --git a/dom/media/webaudio/AudioNodeExternalInputStream.cpp b/dom/media/webaudio/AudioNodeExternalInputStream.cpp index e7bb353e46..cd12940aca 100644 --- a/dom/media/webaudio/AudioNodeExternalInputStream.cpp +++ b/dom/media/webaudio/AudioNodeExternalInputStream.cpp @@ -205,10 +205,8 @@ AudioNodeExternalInputStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t accumulateIndex = 0; if (inputChannels) { - // TODO: See Bug 1261168. Ideally we would use an aligned version of - // AutoTArray (of size GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE) here. - AlignedTArray downmixBuffer; - downmixBuffer.SetLength(GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE); + DownmixBufferType downmixBuffer; + ASSERT_ALIGNED16(downmixBuffer.Elements()); for (uint32_t i = 0; i < audioSegments.Length(); ++i) { AudioBlock tmpChunk; ConvertSegmentToAudioBlock(&audioSegments[i], &tmpChunk, inputChannels); diff --git a/dom/media/webaudio/AudioNodeStream.cpp b/dom/media/webaudio/AudioNodeStream.cpp index 25030e7745..1378748756 100644 --- a/dom/media/webaudio/AudioNodeStream.cpp +++ b/dom/media/webaudio/AudioNodeStream.cpp @@ -454,10 +454,8 @@ AudioNodeStream::ObtainInputBlock(AudioBlock& aTmpChunk, } aTmpChunk.AllocateChannels(outputChannelCount); - // TODO: See Bug 1261168. Ideally we would use an aligned version of - // AutoTArray (of size GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE) here. - AlignedTArray downmixBuffer; - downmixBuffer.SetLength(GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE); + DownmixBufferType downmixBuffer; + ASSERT_ALIGNED16(downmixBuffer.Elements()); for (uint32_t i = 0; i < inputChunkCount; ++i) { AccumulateInputChunk(i, *inputChunks[i], &aTmpChunk, &downmixBuffer); @@ -468,7 +466,7 @@ void AudioNodeStream::AccumulateInputChunk(uint32_t aInputIndex, const AudioBlock& aChunk, AudioBlock* aBlock, - AlignedTArray* aDownmixBuffer) + DownmixBufferType* aDownmixBuffer) { AutoTArray channels; UpMixDownMixChunk(&aChunk, aBlock->ChannelCount(), channels, *aDownmixBuffer); @@ -494,7 +492,7 @@ void AudioNodeStream::UpMixDownMixChunk(const AudioBlock* aChunk, uint32_t aOutputChannelCount, nsTArray& aOutputChannels, - AlignedTArray& aDownmixBuffer) + DownmixBufferType& aDownmixBuffer) { for (uint32_t i = 0; i < aChunk->ChannelCount(); i++) { aOutputChannels.AppendElement(static_cast(aChunk->mChannelData[i])); diff --git a/dom/media/webaudio/AudioNodeStream.h b/dom/media/webaudio/AudioNodeStream.h index c0666923dc..5569ed01ee 100644 --- a/dom/media/webaudio/AudioNodeStream.h +++ b/dom/media/webaudio/AudioNodeStream.h @@ -10,6 +10,7 @@ #include "mozilla/dom/AudioNodeBinding.h" #include "AlignedTArray.h" #include "AudioBlock.h" +#include "AudioSegment.h" namespace mozilla { @@ -22,6 +23,8 @@ class AudioContext; class ThreadSharedFloatArrayBufferList; class AudioNodeEngine; +typedef AlignedAutoTArray DownmixBufferType; + /** * An AudioNodeStream produces one audio track with ID AUDIO_TRACK. * The start time of the AudioTrack is aligned to the start time of the @@ -191,10 +194,10 @@ protected: void FinishOutput(); void AccumulateInputChunk(uint32_t aInputIndex, const AudioBlock& aChunk, AudioBlock* aBlock, - AlignedTArray* aDownmixBuffer); + DownmixBufferType* aDownmixBuffer); void UpMixDownMixChunk(const AudioBlock* aChunk, uint32_t aOutputChannelCount, nsTArray& aOutputChannels, - AlignedTArray& aDownmixBuffer); + DownmixBufferType& aDownmixBuffer); uint32_t ComputedNumberOfChannels(uint32_t aInputChannelCount); void ObtainInputBlock(AudioBlock& aTmpChunk, uint32_t aPortIndex); diff --git a/dom/media/webm/EbmlComposer.cpp b/dom/media/webm/EbmlComposer.cpp index 3e9defc2da..88cf72430d 100644 --- a/dom/media/webm/EbmlComposer.cpp +++ b/dom/media/webm/EbmlComposer.cpp @@ -5,7 +5,7 @@ #include "EbmlComposer.h" #include "mozilla/UniquePtr.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "libmkv/EbmlIDs.h" #include "libmkv/EbmlWriter.h" #include "libmkv/WebMElement.h" diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index fb983ed191..8230a03d1c 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -12,7 +12,7 @@ #include "WebMBufferedParser.h" #include "gfx2DGlue.h" #include "mozilla/Atomics.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/SharedThreadPool.h" #include "MediaDataDemuxer.h" #include "nsAutoRef.h" diff --git a/dom/nfc/gonk/NfcService.cpp b/dom/nfc/gonk/NfcService.cpp index f49905a575..63718fac8d 100644 --- a/dom/nfc/gonk/NfcService.cpp +++ b/dom/nfc/gonk/NfcService.cpp @@ -10,7 +10,7 @@ #include "mozilla/dom/NfcOptionsBinding.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/dom/RootedDictionary.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Hal.h" #include "mozilla/ipc/ListenSocket.h" #include "mozilla/ipc/ListenSocketConsumer.h" diff --git a/dom/wifi/WifiCertService.cpp b/dom/wifi/WifiCertService.cpp index 3204a1d10f..7635b14317 100644 --- a/dom/wifi/WifiCertService.cpp +++ b/dom/wifi/WifiCertService.cpp @@ -7,7 +7,7 @@ #include "WifiCertService.h" #include "mozilla/ClearOnShutdown.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/ModuleUtils.h" #include "mozilla/RefPtr.h" #include "mozilla/dom/File.h" diff --git a/gfx/2d/BigEndianInts.h b/gfx/2d/BigEndianInts.h index 70a76e1d5b..aa4f0dfb29 100644 --- a/gfx/2d/BigEndianInts.h +++ b/gfx/2d/BigEndianInts.h @@ -7,7 +7,7 @@ #ifndef mozilla_BigEndianInts_h #define mozilla_BigEndianInts_h -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" namespace mozilla { @@ -77,4 +77,4 @@ private: } // mozilla -#endif // mozilla_BigEndianInts_h \ No newline at end of file +#endif // mozilla_BigEndianInts_h diff --git a/gfx/2d/Types.h b/gfx/2d/Types.h index d7c5301592..415444d72d 100644 --- a/gfx/2d/Types.h +++ b/gfx/2d/Types.h @@ -6,7 +6,7 @@ #ifndef MOZILLA_GFX_TYPES_H_ #define MOZILLA_GFX_TYPES_H_ -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include #include diff --git a/gfx/config/gfxFeature.cpp b/gfx/config/gfxFeature.cpp index 5602dcc310..96b5e35b0c 100644 --- a/gfx/config/gfxFeature.cpp +++ b/gfx/config/gfxFeature.cpp @@ -6,6 +6,7 @@ #include "mozilla/Preferences.h" #include "prprf.h" #include "gfxFeature.h" +#include "nsString.h" namespace mozilla { namespace gfx { @@ -60,9 +61,13 @@ FeatureState::SetDefaultFromPref(const char* aPrefName, if (Preferences::HasUserValue(aPrefName)) { bool userValue = Preferences::GetBool(aPrefName, aDefaultValue); if (userValue == aIsEnablePref) { - UserEnable("Enabled by user preference"); + nsCString message("Enabled via "); + message.AppendASCII(aPrefName); + UserEnable(message.get()); } else { - UserDisable("Disabled by user preference"); + nsCString message("Disabled via "); + message.AppendASCII(aPrefName); + UserDisable(message.get()); } } } diff --git a/gfx/config/gfxFeature.h b/gfx/config/gfxFeature.h index ba38224332..cbabfc38e7 100644 --- a/gfx/config/gfxFeature.h +++ b/gfx/config/gfxFeature.h @@ -18,6 +18,7 @@ namespace gfx { /* Name, Type, Description */ \ _(HW_COMPOSITING, Feature, "Compositing") \ _(D3D11_COMPOSITING, Feature, "Direct3D11 Compositing") \ + _(D3D9_COMPOSITING, Feature, "Direct3D9 Compositing") \ _(DIRECT2D, Feature, "Direct2D") \ /* Add new entries above this comment */ diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 54d935dd0c..5bd37dd2ae 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -179,7 +179,7 @@ GetAndInitDisplayForAccelANGLE(GLLibraryEGL& egl) return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE); if (gfxPrefs::WebGLANGLETryD3D11() && - gfxPlatform::CanUseDirect3D11ANGLE()) + gfxPlatform::GetPlatform()->CanUseDirect3D11ANGLE()) { ret = GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE); } diff --git a/gfx/layers/LayerScope.cpp b/gfx/layers/LayerScope.cpp index abcd14a223..a8a8436764 100644 --- a/gfx/layers/LayerScope.cpp +++ b/gfx/layers/LayerScope.cpp @@ -10,7 +10,7 @@ #include "nsAppRunner.h" #include "Composer2D.h" #include "Effects.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/Preferences.h" #include "mozilla/TimeStamp.h" diff --git a/gfx/layers/d3d9/CompositorD3D9.cpp b/gfx/layers/d3d9/CompositorD3D9.cpp index f8be57f216..138c622658 100644 --- a/gfx/layers/d3d9/CompositorD3D9.cpp +++ b/gfx/layers/d3d9/CompositorD3D9.cpp @@ -42,8 +42,6 @@ CompositorD3D9::Initialize() { ScopedGfxFeatureReporter reporter("D3D9 Layers"); - MOZ_ASSERT(gfxPlatform::CanUseDirect3D9()); - mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); if (!mDeviceManager) { return false; diff --git a/gfx/thebes/gfxColor.h b/gfx/thebes/gfxColor.h index 2cc0350f41..4ad7d9f06e 100644 --- a/gfx/thebes/gfxColor.h +++ b/gfx/thebes/gfxColor.h @@ -7,7 +7,7 @@ #define GFX_COLOR_H #include "mozilla/Attributes.h" // for MOZ_ALWAYS_INLINE -#include "mozilla/Endian.h" // for mozilla::NativeEndian::swapToBigEndian +#include "mozilla/EndianUtils.h" // for mozilla::NativeEndian::swapToBigEndian /** * GFX_BLOCK_RGB_TO_FRGB(from,to) diff --git a/gfx/thebes/gfxFontUtils.h b/gfx/thebes/gfxFontUtils.h index 2c22d1ff92..1ef5ba6768 100644 --- a/gfx/thebes/gfxFontUtils.h +++ b/gfx/thebes/gfxFontUtils.h @@ -10,7 +10,7 @@ #include "nsComponentManagerUtils.h" #include "nsTArray.h" #include "mozilla/Likely.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/MemoryReporting.h" #include "mozilla/UniquePtr.h" @@ -1023,5 +1023,4 @@ protected: static const char* gMSFontNameCharsets[]; }; - #endif /* GFX_FONT_UTILS_H */ diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 379c458e1a..dfcce44f95 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -128,6 +128,7 @@ class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted { #include "mozilla/Preferences.h" #include "mozilla/Assertions.h" +#include "mozilla/Atomics.h" #include "mozilla/Attributes.h" #include "mozilla/Mutex.h" @@ -2061,14 +2062,13 @@ gfxPlatform::OptimalFormatForContent(gfxContentType aContent) * and remember the values. Changing these preferences during the run will * not have any effect until we restart. */ -static bool sLayersSupportsD3D9 = false; bool gANGLESupportsD3D11 = false; -static bool sLayersSupportsHardwareVideoDecoding = false; +static mozilla::Atomic sLayersSupportsHardwareVideoDecoding(false); static bool sLayersHardwareVideoDecodingFailed = false; static bool sBufferRotationCheckPref = true; static bool sPrefBrowserTabsRemoteAutostart = false; -static bool sLayersAccelerationPrefsInitialized = false; +static mozilla::Atomic sLayersAccelerationPrefsInitialized(false); void gfxPlatform::InitAcceleration() @@ -2092,15 +2092,7 @@ gfxPlatform::InitAcceleration() nsCString discardFailureId; int32_t status; #ifdef XP_WIN - if (gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) { - sLayersSupportsD3D9 = true; - } else if (!gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly() && gfxInfo) { - if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, discardFailureId, &status))) { - if (status == nsIGfxInfo::FEATURE_STATUS_OK) { - MOZ_ASSERT(!sPrefBrowserTabsRemoteAutostart || IsVistaOrLater()); - sLayersSupportsD3D9 = true; - } - } + if (!gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly() && gfxInfo) { if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, discardFailureId, &status))) { if (status == nsIGfxInfo::FEATURE_STATUS_OK) { gANGLESupportsD3D11 = true; @@ -2161,15 +2153,6 @@ gfxPlatform::InitCompositorAccelerationPrefs() } } -bool -gfxPlatform::CanUseDirect3D9() -{ - // this function is called from the compositor thread, so it is not - // safe to init the prefs etc. from here. - MOZ_ASSERT(sLayersAccelerationPrefsInitialized); - return sLayersSupportsD3D9; -} - bool gfxPlatform::CanUseHardwareVideoDecoding() { @@ -2179,13 +2162,6 @@ gfxPlatform::CanUseHardwareVideoDecoding() return sLayersSupportsHardwareVideoDecoding && !sLayersHardwareVideoDecodingFailed; } -bool -gfxPlatform::CanUseDirect3D11ANGLE() -{ - MOZ_ASSERT(sLayersAccelerationPrefsInitialized); - return gANGLESupportsD3D11; -} - bool gfxPlatform::AccelerateLayersByDefault() { diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index cb2f93e7e8..b9acdbbd56 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -449,9 +449,8 @@ public: static bool OffMainThreadCompositingEnabled(); - static bool CanUseDirect3D9(); virtual bool CanUseHardwareVideoDecoding(); - static bool CanUseDirect3D11ANGLE(); + virtual bool CanUseDirect3D11ANGLE() { return false; } // Returns a prioritized list of all available compositor backends. void GetCompositorBackends(bool useAcceleration, nsTArray& aBackends); diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 705f013480..6edf653e93 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -427,6 +427,12 @@ gfxWindowsPlatform::CanUseHardwareVideoDecoding() return !IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding(); } +bool +gfxWindowsPlatform::CanUseDirect3D11ANGLE() +{ + return gANGLESupportsD3D11 && gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING); +} + bool gfxWindowsPlatform::InitDWriteSupport() { @@ -1949,10 +1955,40 @@ gfxWindowsPlatform::InitializeConfig() return; } + InitializeD3D9Config(); InitializeD3D11Config(); InitializeD2DConfig(); } +void +gfxWindowsPlatform::InitializeD3D9Config() +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + FeatureState& d3d9 = gfxConfig::GetFeature(Feature::D3D9_COMPOSITING); + + if (!IsVistaOrLater()) { + d3d9.EnableByDefault(); + } else { + d3d9.SetDefaultFromPref( + gfxPrefs::GetLayersAllowD3D9FallbackPrefName(), + true, + gfxPrefs::GetLayersAllowD3D9FallbackPrefDefault()); + + if (!d3d9.IsEnabled() && gfxPrefs::LayersPreferD3D9()) { + d3d9.UserEnable("Direct3D9 enabled via layers.prefer-d3d9"); + } + } + + if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS)) { + d3d9.Disable(FeatureStatus::Blacklisted, "Direct3D 9 for layers is blacklisted on this hardware"); + } + + if (gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) { + d3d9.UserForceEnable("Hardware compositing is force-enabled"); + } +} + void gfxWindowsPlatform::InitializeD3D11Config() { @@ -2898,23 +2934,18 @@ gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray& aB aBackends.AppendElement(LayersBackend::LAYERS_OPENGL); } - bool allowTryingD3D9 = false; - if (!gfxPrefs::LayersPreferD3D9()) { - if (mD3D11Device) { - aBackends.AppendElement(LayersBackend::LAYERS_D3D11); - } else { - allowTryingD3D9 = gfxPrefs::LayersAllowD3D9Fallback(); - NS_WARNING("Direct3D 11-accelerated layers are not supported on this system."); - } + if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && gfxPrefs::LayersPreferD3D9()) { + aBackends.AppendElement(LayersBackend::LAYERS_D3D9); } - if (gfxPrefs::LayersPreferD3D9() || !IsVistaOrLater() || allowTryingD3D9) { - // We don't want D3D9 except on Windows XP, unless we failed to get D3D11 - if (gfxPlatform::CanUseDirect3D9()) { - aBackends.AppendElement(LayersBackend::LAYERS_D3D9); - } else { - NS_WARNING("Direct3D 9-accelerated layers are not supported on this system."); - } + if (mD3D11Device) { + aBackends.AppendElement(LayersBackend::LAYERS_D3D11); + } else { + NS_WARNING("Direct3D 11-accelerated layers are not supported on this system."); + } + + if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && !gfxPrefs::LayersPreferD3D9()) { + aBackends.AppendElement(LayersBackend::LAYERS_D3D9); } } diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 725cade47a..ae216a23d7 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -97,6 +97,8 @@ struct ClearTypeParameterInfo { int32_t enhancedContrast; }; +extern bool gANGLESupportsD3D11; + class gfxWindowsPlatform : public gfxPlatform { public: enum TextRenderingMode { @@ -227,7 +229,7 @@ public: static bool IsOptimus(); - bool IsWARP() { return mIsWARP; } + bool IsWARP() const { return mIsWARP; } // Returns whether the compositor's D3D11 device supports texture sharing. bool CompositorD3D11TextureSharingWorks() const { @@ -260,6 +262,8 @@ public: } bool SupportsPluginDirectDXGIDrawing(); + virtual bool CanUseDirect3D11ANGLE(); + protected: bool AccelerateLayersByDefault() override { return true; @@ -286,6 +290,7 @@ private: void DisableD2D(mozilla::gfx::FeatureStatus aStatus, const char* aMessage); void InitializeConfig(); + void InitializeD3D9Config(); void InitializeD3D11Config(); void InitializeD2DConfig(); @@ -329,10 +334,10 @@ private: RefPtr mD3D11ContentDevice; RefPtr mD3D11ImageBridgeDevice; RefPtr mDeviceManager; - bool mIsWARP; + mozilla::Atomic mIsWARP; bool mHasDeviceReset; bool mHasFakeDeviceReset; - bool mCompositorD3D11TextureSharingWorks; + mozilla::Atomic mCompositorD3D11TextureSharingWorks; mozilla::Atomic mHasD3D9DeviceReset; DeviceResetReason mDeviceResetReason; diff --git a/image/decoders/EXIF.cpp b/image/decoders/EXIF.cpp index bdc44f70c3..8197c886c3 100644 --- a/image/decoders/EXIF.cpp +++ b/image/decoders/EXIF.cpp @@ -5,7 +5,7 @@ #include "EXIF.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" namespace mozilla { namespace image { diff --git a/image/decoders/icon/gtk/nsIconChannel.cpp b/image/decoders/icon/gtk/nsIconChannel.cpp index d83d968560..03e56c273d 100644 --- a/image/decoders/icon/gtk/nsIconChannel.cpp +++ b/image/decoders/icon/gtk/nsIconChannel.cpp @@ -7,7 +7,7 @@ #include #include "mozilla/DebugOnly.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include #ifdef MOZ_ENABLE_GIO diff --git a/image/decoders/icon/mac/nsIconChannelCocoa.mm b/image/decoders/icon/mac/nsIconChannelCocoa.mm index 69968a895f..9c2686cdd2 100644 --- a/image/decoders/icon/mac/nsIconChannelCocoa.mm +++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm @@ -6,7 +6,7 @@ #include "nsContentUtils.h" #include "nsIconChannel.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "nsIIconURI.h" #include "nsIServiceManager.h" #include "nsIInterfaceRequestor.h" diff --git a/image/decoders/icon/qt/nsIconChannel.cpp b/image/decoders/icon/qt/nsIconChannel.cpp index b864e152ae..3f732abb8c 100644 --- a/image/decoders/icon/qt/nsIconChannel.cpp +++ b/image/decoders/icon/qt/nsIconChannel.cpp @@ -8,7 +8,7 @@ #include #include -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "nsMimeTypes.h" #include "nsIMIMEService.h" diff --git a/image/decoders/nsBMPDecoder.cpp b/image/decoders/nsBMPDecoder.cpp index c7dce103fb..caa73e8eed 100644 --- a/image/decoders/nsBMPDecoder.cpp +++ b/image/decoders/nsBMPDecoder.cpp @@ -86,7 +86,7 @@ #include "ImageLogging.h" #include "mozilla/Attributes.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Likely.h" #include "nsBMPDecoder.h" diff --git a/image/decoders/nsICODecoder.cpp b/image/decoders/nsICODecoder.cpp index 80eaad22d5..e089a458bf 100644 --- a/image/decoders/nsICODecoder.cpp +++ b/image/decoders/nsICODecoder.cpp @@ -8,7 +8,7 @@ #include -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Move.h" #include "nsICODecoder.h" diff --git a/image/decoders/nsJPEGDecoder.cpp b/image/decoders/nsJPEGDecoder.cpp index 28bd835ef5..36099152d1 100644 --- a/image/decoders/nsJPEGDecoder.cpp +++ b/image/decoders/nsJPEGDecoder.cpp @@ -19,7 +19,7 @@ #include "jerror.h" #include "gfxPlatform.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Telemetry.h" extern "C" { diff --git a/image/encoders/bmp/nsBMPEncoder.cpp b/image/encoders/bmp/nsBMPEncoder.cpp index 9b47b62ff2..5ba29cb0f2 100644 --- a/image/encoders/bmp/nsBMPEncoder.cpp +++ b/image/encoders/bmp/nsBMPEncoder.cpp @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsCRT.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/UniquePtrExtensions.h" #include "nsBMPEncoder.h" #include "prprf.h" diff --git a/image/encoders/ico/nsICOEncoder.cpp b/image/encoders/ico/nsICOEncoder.cpp index 61db59a7ae..c9083a8fdc 100644 --- a/image/encoders/ico/nsICOEncoder.cpp +++ b/image/encoders/ico/nsICOEncoder.cpp @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsCRT.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "nsBMPEncoder.h" #include "nsPNGEncoder.h" #include "nsICOEncoder.h" diff --git a/intl/uconv/ucvlatin/nsUTF16ToUnicode.cpp b/intl/uconv/ucvlatin/nsUTF16ToUnicode.cpp index 6f5559ce8c..56c88ff3ed 100644 --- a/intl/uconv/ucvlatin/nsUTF16ToUnicode.cpp +++ b/intl/uconv/ucvlatin/nsUTF16ToUnicode.cpp @@ -6,7 +6,7 @@ #include "nsUTF16ToUnicode.h" #include "nsCharTraits.h" #include "mozilla/CheckedInt.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" enum { STATE_NORMAL = 0, diff --git a/intl/uconv/ucvlatin/nsUnicodeToUTF16.h b/intl/uconv/ucvlatin/nsUnicodeToUTF16.h index d7a4451e44..b024a1b421 100644 --- a/intl/uconv/ucvlatin/nsUnicodeToUTF16.h +++ b/intl/uconv/ucvlatin/nsUnicodeToUTF16.h @@ -7,7 +7,7 @@ #define nsUnicodeToUTF16_h_ #include "nsUCSupport.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" class nsUnicodeToUTF16BE: public nsBasicEncoder { diff --git a/ipc/chromium/src/base/pickle.cc b/ipc/chromium/src/base/pickle.cc index 9cb964ee08..1c3b9764c6 100644 --- a/ipc/chromium/src/base/pickle.cc +++ b/ipc/chromium/src/base/pickle.cc @@ -8,7 +8,7 @@ #include "mozilla/Alignment.h" #include "mozilla/CheckedInt.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/TypeTraits.h" #include diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 5f7658d063..0ea0cca662 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -30,7 +30,7 @@ #include "js/StructuredClone.h" #include "mozilla/CheckedInt.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/FloatingPoint.h" #include diff --git a/js/src/vm/TraceLoggingGraph.cpp b/js/src/vm/TraceLoggingGraph.cpp index 88cfbb8f7c..51957f871a 100644 --- a/js/src/vm/TraceLoggingGraph.cpp +++ b/js/src/vm/TraceLoggingGraph.cpp @@ -13,7 +13,7 @@ #include #endif -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "jsstr.h" diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index e6ce55c015..17901af6d6 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -7,7 +7,7 @@ #ifndef vm_Xdr_h #define vm_Xdr_h -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/TypeTraits.h" #include "jsatom.h" diff --git a/media/libstagefright/binding/AnnexB.cpp b/media/libstagefright/binding/AnnexB.cpp index 9ccff857c6..bce1f853db 100644 --- a/media/libstagefright/binding/AnnexB.cpp +++ b/media/libstagefright/binding/AnnexB.cpp @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/ArrayUtils.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mp4_demuxer/AnnexB.h" #include "mp4_demuxer/ByteReader.h" #include "mp4_demuxer/ByteWriter.h" diff --git a/media/libstagefright/binding/Box.cpp b/media/libstagefright/binding/Box.cpp index 7621c6500f..4d249a2472 100644 --- a/media/libstagefright/binding/Box.cpp +++ b/media/libstagefright/binding/Box.cpp @@ -6,7 +6,7 @@ #include "mp4_demuxer/Box.h" #include "mp4_demuxer/Stream.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include using namespace mozilla; diff --git a/media/libstagefright/binding/include/mp4_demuxer/AtomType.h b/media/libstagefright/binding/include/mp4_demuxer/AtomType.h index cce0baafae..95baedfe70 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/AtomType.h +++ b/media/libstagefright/binding/include/mp4_demuxer/AtomType.h @@ -8,7 +8,7 @@ #define ATOM_TYPE_H_ #include -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" using namespace mozilla; diff --git a/media/libstagefright/binding/include/mp4_demuxer/Box.h b/media/libstagefright/binding/include/mp4_demuxer/Box.h index bf87641690..a28457c6b7 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Box.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Box.h @@ -10,7 +10,7 @@ #include #include "nsTArray.h" #include "MediaResource.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mp4_demuxer/AtomType.h" #include "mp4_demuxer/ByteReader.h" diff --git a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h index d16352b5a7..7c78dfdbe9 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h +++ b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h @@ -5,7 +5,7 @@ #ifndef BYTE_READER_H_ #define BYTE_READER_H_ -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Vector.h" #include "nsTArray.h" #include "MediaData.h" diff --git a/media/libstagefright/binding/include/mp4_demuxer/ByteWriter.h b/media/libstagefright/binding/include/mp4_demuxer/ByteWriter.h index 7be1b161bb..8be314f87f 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/ByteWriter.h +++ b/media/libstagefright/binding/include/mp4_demuxer/ByteWriter.h @@ -5,7 +5,7 @@ #ifndef BYTE_WRITER_H_ #define BYTE_WRITER_H_ -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Vector.h" #include "nsTArray.h" diff --git a/mfbt/Endian.h b/mfbt/EndianUtils.h similarity index 99% rename from mfbt/Endian.h rename to mfbt/EndianUtils.h index e7674f4666..0081558078 100644 --- a/mfbt/Endian.h +++ b/mfbt/EndianUtils.h @@ -61,8 +61,8 @@ * }; */ -#ifndef mozilla_Endian_h -#define mozilla_Endian_h +#ifndef mozilla_EndianUtils_h +#define mozilla_EndianUtils_h #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" @@ -692,4 +692,4 @@ public: } /* namespace mozilla */ -#endif /* mozilla_Endian_h */ +#endif /* mozilla_EndianUtils_h */ diff --git a/mfbt/SHA1.cpp b/mfbt/SHA1.cpp index da4cb16a19..f8968c3e1f 100644 --- a/mfbt/SHA1.cpp +++ b/mfbt/SHA1.cpp @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Assertions.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/SHA1.h" #include diff --git a/mfbt/moz.build b/mfbt/moz.build index d7f104e545..99a5e0b8ed 100644 --- a/mfbt/moz.build +++ b/mfbt/moz.build @@ -35,7 +35,7 @@ EXPORTS.mozilla = [ 'decimal/Decimal.h', 'double-conversion/double-conversion.h', 'double-conversion/utils.h', - 'Endian.h', + 'EndianUtils.h', 'EnumeratedArray.h', 'EnumeratedRange.h', 'EnumSet.h', diff --git a/mfbt/tests/TestEndian.cpp b/mfbt/tests/TestEndian.cpp index b5fcd197b9..1fb8ac98f5 100644 --- a/mfbt/tests/TestEndian.cpp +++ b/mfbt/tests/TestEndian.cpp @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Assertions.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include @@ -49,7 +49,7 @@ TestSingleNoSwap(T aValue, T aUnswappedValue) #endif } -// Endian.h functions are declared as protected in an base class and +// EndianUtils.h functions are declared as protected in a base class and // then re-exported as public in public derived classes. The // standardese around explicit instantiation of templates is not clear // in such cases. Provide these wrappers to make things more explicit. diff --git a/modules/fdlibm/patches/06_use_mfbt_endian_h_in_math_private_h.patch b/modules/fdlibm/patches/06_use_mfbt_endian_h_in_math_private_h.patch index fa9b31c535..c8b30f20e3 100644 --- a/modules/fdlibm/patches/06_use_mfbt_endian_h_in_math_private_h.patch +++ b/modules/fdlibm/patches/06_use_mfbt_endian_h_in_math_private_h.patch @@ -14,7 +14,7 @@ diff --git a/modules/fdlibm/src/math_private.h b/modules/fdlibm/src/math_private #include "fdlibm.h" -+#include "mozilla/Endian.h" ++#include "mozilla/EndianUtils.h" + /* * The original fdlibm code used statements like: diff --git a/modules/fdlibm/patches/11_include_cfloat_to_use_flt_eval_method.patch b/modules/fdlibm/patches/11_include_cfloat_to_use_flt_eval_method.patch index 90aef49273..a5ddcb1caf 100644 --- a/modules/fdlibm/patches/11_include_cfloat_to_use_flt_eval_method.patch +++ b/modules/fdlibm/patches/11_include_cfloat_to_use_flt_eval_method.patch @@ -16,6 +16,6 @@ diff --git a/modules/fdlibm/src/math_private.h b/modules/fdlibm/src/math_private #include "fdlibm.h" - #include "mozilla/Endian.h" + #include "mozilla/EndianUtils.h" /* diff --git a/modules/fdlibm/src/math_private.h b/modules/fdlibm/src/math_private.h index 2cea147291..85fcd96765 100644 --- a/modules/fdlibm/src/math_private.h +++ b/modules/fdlibm/src/math_private.h @@ -23,7 +23,7 @@ #include "fdlibm.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" /* * The original fdlibm code used statements like: diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 6d2a5d7287..24b1fdc7f5 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -355,6 +355,7 @@ pref("media.wmf.decoder.thread-count", -1); pref("media.wmf.low-latency.enabled", false); pref("media.wmf.skip-blacklist", false); pref("media.windows-media-foundation.allow-d3d11-dxva", true); +pref("media.wmf.disable-d3d11-for-dlls", "igd10umd32.dll: 9.17.10.2857; isonyvideoprocessor.dll: 4.1.2247.8090, 4.1.2153.6200; tosqep.dll: 1.2.15.526, 1.1.12.201, 1.0.11.318, 1.0.11.215; tosqep64.dll: 1.1.12.201, 1.0.11.215"); #endif #if defined(MOZ_FFMPEG) pref("media.ffmpeg.enabled", true); @@ -389,6 +390,9 @@ pref("media.decoder-doctor.notifications-allowed", "MediaWidevineNoWMFNoSilverli // Whether we report partial failures. pref("media.decoder-doctor.verbose", false); +// Whether to suspend decoding of videos in background tabs. +pref("media.suspend-bkgnd-video.enabled", true); + #ifdef MOZ_WEBRTC pref("media.navigator.enabled", true); pref("media.navigator.video.enabled", true); diff --git a/netwerk/base/nsServerSocket.cpp b/netwerk/base/nsServerSocket.cpp index a074bc7e0e..8183d45c3b 100644 --- a/netwerk/base/nsServerSocket.cpp +++ b/netwerk/base/nsServerSocket.cpp @@ -13,7 +13,7 @@ #include "prio.h" #include "nsThreadUtils.h" #include "mozilla/Attributes.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/net/DNS.h" #include "nsServiceManagerUtils.h" #include "nsIFile.h" diff --git a/netwerk/base/nsUDPSocket.cpp b/netwerk/base/nsUDPSocket.cpp index 06b9fd8e9b..208c1248b2 100644 --- a/netwerk/base/nsUDPSocket.cpp +++ b/netwerk/base/nsUDPSocket.cpp @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Attributes.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/dom/TypedArray.h" #include "mozilla/HoldDropJSObjects.h" diff --git a/netwerk/cache2/CacheFileMetadata.h b/netwerk/cache2/CacheFileMetadata.h index f82fd7910b..8759d1d4cc 100644 --- a/netwerk/cache2/CacheFileMetadata.h +++ b/netwerk/cache2/CacheFileMetadata.h @@ -9,7 +9,7 @@ #include "CacheStorageService.h" #include "CacheHashUtils.h" #include "CacheObserver.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/BasePrincipal.h" #include "nsAutoPtr.h" #include "nsString.h" diff --git a/netwerk/cache2/CacheIndex.h b/netwerk/cache2/CacheIndex.h index b67a97353f..318d6002ec 100644 --- a/netwerk/cache2/CacheIndex.h +++ b/netwerk/cache2/CacheIndex.h @@ -17,7 +17,7 @@ #include "nsWeakReference.h" #include "mozilla/SHA1.h" #include "mozilla/StaticMutex.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/TimeStamp.h" class nsIFile; diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp index d66c3f571d..f2db257f68 100644 --- a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp +++ b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp @@ -5,7 +5,7 @@ #include "MDNSResponderOperator.h" #include "MDNSResponderReply.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Logging.h" #include "mozilla/ScopeExit.h" #include "nsComponentManagerUtils.h" diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp index 9b8d640b8e..7aa5b3759a 100644 --- a/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp +++ b/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MDNSResponderReply.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "private/pprio.h" namespace mozilla { diff --git a/netwerk/ipc/NeckoMessageUtils.h b/netwerk/ipc/NeckoMessageUtils.h index 710b307279..c33f65f5de 100644 --- a/netwerk/ipc/NeckoMessageUtils.h +++ b/netwerk/ipc/NeckoMessageUtils.h @@ -14,6 +14,11 @@ #include "mozilla/net/DNS.h" #include "TimingStruct.h" +#ifdef MOZ_CRASHREPORTER +#include "nsExceptionHandler.h" +#include "nsPrintfCString.h" +#endif + namespace IPC { // nsIPermissionManager utilities @@ -111,6 +116,12 @@ struct ParamTraits aMsg->WriteBytes(aParam.local.path, sizeof(aParam.local.path)); #endif } else { +#ifdef MOZ_CRASHREPORTER + if (XRE_IsParentProcess()) { + nsPrintfCString msg("%d", aParam.raw.family); + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Unknown NetAddr socket family"), msg); + } +#endif NS_RUNTIMEABORT("Unknown socket family"); } } diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp index c15ae65bd2..3e86b6e83d 100644 --- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -19,7 +19,7 @@ #include "Http2Stream.h" #include "Http2Push.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Preferences.h" #include "nsHttp.h" #include "nsHttpHandler.h" diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index 775556bd90..e092bd25a6 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -10,7 +10,7 @@ #include "mozilla/Atomics.h" #include "mozilla/Attributes.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/net/WebSocketEventService.h" diff --git a/security/manager/ssl/nsNTLMAuthModule.cpp b/security/manager/ssl/nsNTLMAuthModule.cpp index e095a51af9..cb5ce614a4 100644 --- a/security/manager/ssl/nsNTLMAuthModule.cpp +++ b/security/manager/ssl/nsNTLMAuthModule.cpp @@ -11,7 +11,7 @@ #include "md4.h" #include "mozilla/Casting.h" #include "mozilla/CheckedInt.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/Likely.h" #include "mozilla/Preferences.h" #include "mozilla/Snprintf.h" diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 4e0d726411..9a45ca3d13 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -10256,16 +10256,6 @@ "bug_numbers": [1238433], "description": "Percentage of frames decoded frames dropped in an HTMLVideoElement" }, - "VIDEO_DETAILED_DROPPED_FRAMES_PROPORTION" : { - "alert_emails": ["lchristie@mozilla.com", "cpearce@mozilla.com"], - "expires_in_version": "55", - "kind": "linear", - "high": 100, - "n_buckets": 50, - "keyed": true, - "bug_numbers": [1238433], - "description": "Percentage of frames decoded frames dropped in an HTMLVideoElement, keyed by MimeType, Resolution and Hardware Accelerated Decoding" - }, "TAB_SWITCH_CACHE_POSITION": { "expires_in_version": "55", "bug_numbers": [1242013], diff --git a/tools/profiler/core/EHABIStackWalk.cpp b/tools/profiler/core/EHABIStackWalk.cpp index 2ead36a13e..76068cdea6 100644 --- a/tools/profiler/core/EHABIStackWalk.cpp +++ b/tools/profiler/core/EHABIStackWalk.cpp @@ -30,7 +30,7 @@ #include "mozilla/Atomics.h" #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include #include diff --git a/xpcom/io/SnappyFrameUtils.cpp b/xpcom/io/SnappyFrameUtils.cpp index 1973152102..97883a3629 100644 --- a/xpcom/io/SnappyFrameUtils.cpp +++ b/xpcom/io/SnappyFrameUtils.cpp @@ -7,7 +7,7 @@ #include "mozilla/SnappyFrameUtils.h" #include "crc32c.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "nsDebug.h" #include "snappy/snappy.h" diff --git a/xpcom/io/nsBinaryStream.cpp b/xpcom/io/nsBinaryStream.cpp index ea6a5241e9..5e1a47c917 100644 --- a/xpcom/io/nsBinaryStream.cpp +++ b/xpcom/io/nsBinaryStream.cpp @@ -23,7 +23,7 @@ #include "nsBinaryStream.h" -#include "mozilla/Endian.h" +#include "mozilla/EndianUtils.h" #include "mozilla/PodOperations.h" #include "mozilla/UniquePtr.h"