summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/wmf/MFMediaEngineVideoStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/platforms/wmf/MFMediaEngineVideoStream.cpp')
-rw-r--r--dom/media/platforms/wmf/MFMediaEngineVideoStream.cpp108
1 files changed, 93 insertions, 15 deletions
diff --git a/dom/media/platforms/wmf/MFMediaEngineVideoStream.cpp b/dom/media/platforms/wmf/MFMediaEngineVideoStream.cpp
index ca043478f0..0fedcd31b9 100644
--- a/dom/media/platforms/wmf/MFMediaEngineVideoStream.cpp
+++ b/dom/media/platforms/wmf/MFMediaEngineVideoStream.cpp
@@ -49,7 +49,7 @@ void MFMediaEngineVideoStream::SetKnowsCompositor(
this]() {
mKnowsCompositor = knowCompositor;
LOG("Set SetKnowsCompositor=%p", mKnowsCompositor.get());
- ResolvePendingDrainPromiseIfNeeded();
+ ResolvePendingPromisesIfNeeded();
}));
}
@@ -74,7 +74,7 @@ void MFMediaEngineVideoStream::SetDCompSurfaceHandle(HANDLE aDCompSurfaceHandle,
}
}
LOG("Set DCompSurfaceHandle, handle=%p", mDCompSurfaceHandle);
- ResolvePendingDrainPromiseIfNeeded();
+ ResolvePendingPromisesIfNeeded();
}));
}
@@ -209,7 +209,7 @@ HRESULT MFMediaEngineVideoStream::CreateMediaType(const TrackInfo& aInfo,
bool MFMediaEngineVideoStream::HasEnoughRawData() const {
// If more than this much raw video is queued, we'll hold off request more
// video.
- return mRawDataQueueForFeedingEngine.Duration() >=
+ return mRawDataQueueForFeedingEngine.PreciseDuration() >=
StaticPrefs::media_wmf_media_engine_raw_data_threshold_video();
}
@@ -240,6 +240,32 @@ bool MFMediaEngineVideoStream::IsDCompImageReady() {
return true;
}
+RefPtr<MediaDataDecoder::DecodePromise> MFMediaEngineVideoStream::OutputData(
+ RefPtr<MediaRawData> aSample) {
+ if (IsShutdown()) {
+ return MediaDataDecoder::DecodePromise::CreateAndReject(
+ MediaResult(NS_ERROR_FAILURE,
+ RESULT_DETAIL("MFMediaEngineStream is shutdown")),
+ __func__);
+ }
+ AssertOnTaskQueue();
+ NotifyNewData(aSample);
+ MediaDataDecoder::DecodedData outputs;
+ if (RefPtr<MediaData> outputData = OutputDataInternal()) {
+ outputs.AppendElement(outputData);
+ LOGV("Output data [%" PRId64 ",%" PRId64 "]",
+ outputData->mTime.ToMicroseconds(),
+ outputData->GetEndTime().ToMicroseconds());
+ }
+ if (ShouldDelayVideoDecodeBeforeDcompReady()) {
+ LOG("Dcomp isn't ready and we already have enough video data. We will send "
+ "them back together at one when Dcomp is ready");
+ return mVideoDecodeBeforeDcompPromise.Ensure(__func__);
+ }
+ return MediaDataDecoder::DecodePromise::CreateAndResolve(std::move(outputs),
+ __func__);
+}
+
already_AddRefed<MediaData> MFMediaEngineVideoStream::OutputDataInternal() {
AssertOnTaskQueue();
if (mRawDataQueueForGeneratingOutput.GetSize() == 0 || !IsDCompImageReady()) {
@@ -261,28 +287,62 @@ RefPtr<MediaDataDecoder::DecodePromise> MFMediaEngineVideoStream::Drain() {
MediaDataDecoder::DecodedData outputs;
if (!IsDCompImageReady()) {
LOGV("Waiting for dcomp image for draining");
+ // A workaround for a special case where we have sent all input data to the
+ // media engine, and waiting for an output. Sometime media engine would
+ // never return the first frame to us, unless we notify it the end event,
+ // which happens on the case where the video only contains one frame. If we
+ // don't send end event to the media engine, the drain promise would be
+ // pending forever.
+ if (!mSampleRequestTokens.empty() &&
+ mRawDataQueueForFeedingEngine.GetSize() == 0) {
+ NotifyEndEvent();
+ }
return mPendingDrainPromise.Ensure(__func__);
}
return MFMediaEngineStream::Drain();
}
-void MFMediaEngineVideoStream::ResolvePendingDrainPromiseIfNeeded() {
+RefPtr<MediaDataDecoder::FlushPromise> MFMediaEngineVideoStream::Flush() {
+ AssertOnTaskQueue();
+ auto promise = MFMediaEngineStream::Flush();
+ mPendingDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
+ mVideoDecodeBeforeDcompPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED,
+ __func__);
+ return promise;
+}
+
+void MFMediaEngineVideoStream::ResolvePendingPromisesIfNeeded() {
AssertOnTaskQueue();
- if (mPendingDrainPromise.IsEmpty()) {
- return;
- }
if (!IsDCompImageReady()) {
return;
}
- MediaDataDecoder::DecodedData outputs;
- while (RefPtr<MediaData> outputData = OutputDataInternal()) {
- outputs.AppendElement(outputData);
- LOGV("Output data [%" PRId64 ",%" PRId64 "]",
- outputData->mTime.ToMicroseconds(),
- outputData->GetEndTime().ToMicroseconds());
+
+ // Resolve decoding promise first, then drain promise
+ if (!mVideoDecodeBeforeDcompPromise.IsEmpty()) {
+ MediaDataDecoder::DecodedData outputs;
+ while (RefPtr<MediaData> outputData = OutputDataInternal()) {
+ outputs.AppendElement(outputData);
+ LOGV("Output data [%" PRId64 ",%" PRId64 "]",
+ outputData->mTime.ToMicroseconds(),
+ outputData->GetEndTime().ToMicroseconds());
+ }
+ mVideoDecodeBeforeDcompPromise.Resolve(std::move(outputs), __func__);
+ LOG("Resolved video decode before Dcomp promise");
+ }
+
+ // This drain promise could return no data, if all data has been processed in
+ // the decoding promise.
+ if (!mPendingDrainPromise.IsEmpty()) {
+ MediaDataDecoder::DecodedData outputs;
+ while (RefPtr<MediaData> outputData = OutputDataInternal()) {
+ outputs.AppendElement(outputData);
+ LOGV("Output data [%" PRId64 ",%" PRId64 "]",
+ outputData->mTime.ToMicroseconds(),
+ outputData->GetEndTime().ToMicroseconds());
+ }
+ mPendingDrainPromise.Resolve(std::move(outputs), __func__);
+ LOG("Resolved pending drain promise");
}
- mPendingDrainPromise.Resolve(std::move(outputs), __func__);
- LOG("Resolved pending drain promise");
}
MediaDataDecoder::ConversionRequired MFMediaEngineVideoStream::NeedsConversion()
@@ -336,6 +396,20 @@ void MFMediaEngineVideoStream::UpdateConfig(const VideoInfo& aInfo) {
void MFMediaEngineVideoStream::ShutdownCleanUpOnTaskQueue() {
AssertOnTaskQueue();
mPendingDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
+ mVideoDecodeBeforeDcompPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED,
+ __func__);
+}
+
+void MFMediaEngineVideoStream::SendRequestSampleEvent(bool aIsEnough) {
+ AssertOnTaskQueue();
+ MFMediaEngineStream::SendRequestSampleEvent(aIsEnough);
+ // We need more data to be sent in, we should resolve the promise to allow
+ // more input data to be sent.
+ if (!aIsEnough && !mVideoDecodeBeforeDcompPromise.IsEmpty()) {
+ LOG("Resolved pending input promise to allow more input be sent in");
+ mVideoDecodeBeforeDcompPromise.Resolve(MediaDataDecoder::DecodedData{},
+ __func__);
+ }
}
bool MFMediaEngineVideoStream::IsEnded() const {
@@ -352,6 +426,10 @@ bool MFMediaEngineVideoStream::IsEnded() const {
bool MFMediaEngineVideoStream::IsEncrypted() const { return mIsEncrypted; }
+bool MFMediaEngineVideoStream::ShouldDelayVideoDecodeBeforeDcompReady() {
+ return HasEnoughRawData() && !IsDCompImageReady();
+}
+
nsCString MFMediaEngineVideoStream::GetCodecName() const {
switch (mStreamType) {
case WMFStreamType::H264: