media: MediaEngineExtension
This CL adds MediaEngineExtension to be used by
MediaFoundationRenderer. MediaEngineExtension implements
IMFMediaEngineExtension.
Explainer:
https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/Media/MFCdm/explainer.md
Design Doc:
https://docs.google.com/document/d/1kXMdmfsSKU3tcwTxG-wFU-MaEA6sN3by45PCGBV8zJU
Bug: 999747
Change-Id: I429687815567bc1e60ec4a7cfce5e3359e0c72a2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2100008
Commit-Queue: Frank Li <frankli@microsoft.com>
Reviewed-by: Xiaohan Wang <xhwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#754330}
diff --git a/media/renderers/BUILD.gn b/media/renderers/BUILD.gn
index f18dedf4..7cd29bd 100644
--- a/media/renderers/BUILD.gn
+++ b/media/renderers/BUILD.gn
@@ -106,6 +106,8 @@
if (is_win) {
source_set("media_foundation_renderer") {
sources = [
+ "win/media_engine_extension.cc",
+ "win/media_engine_extension.h",
"win/media_engine_notify_impl.cc",
"win/media_engine_notify_impl.h",
"win/media_foundation_audio_stream.cc",
diff --git a/media/renderers/win/media_engine_extension.cc b/media/renderers/win/media_engine_extension.cc
new file mode 100644
index 0000000..1fb3147
--- /dev/null
+++ b/media/renderers/win/media_engine_extension.cc
@@ -0,0 +1,115 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/renderers/win/media_engine_extension.h"
+
+#include <mferror.h>
+
+#include "media/base/win/mf_helpers.h"
+
+namespace media {
+
+using Microsoft::WRL::ComPtr;
+
+MediaEngineExtension::MediaEngineExtension() = default;
+MediaEngineExtension::~MediaEngineExtension() = default;
+
+HRESULT MediaEngineExtension::RuntimeClassInitialize() {
+ DVLOG(1) << __func__ << ": this=" << this;
+ return S_OK;
+}
+
+HRESULT MediaEngineExtension::CanPlayType(BOOL is_audio_only,
+ BSTR mime_type,
+ MF_MEDIA_ENGINE_CANPLAY* result) {
+ // We use MF_MEDIA_ENGINE_EXTENSION to resolve as custom media source for
+ // MFMediaEngine, MIME types are not used.
+ *result = MF_MEDIA_ENGINE_CANPLAY_NOT_SUPPORTED;
+ return S_OK;
+}
+
+HRESULT MediaEngineExtension::BeginCreateObject(BSTR url_bstr,
+ IMFByteStream* byte_stream,
+ MF_OBJECT_TYPE type,
+ IUnknown** cancel_cookie,
+ IMFAsyncCallback* callback,
+ IUnknown* state) {
+ DVLOG(1) << __func__ << ": this=" << this << ",type=" << type;
+
+ if (cancel_cookie) {
+ // We don't support a cancel cookie.
+ *cancel_cookie = nullptr;
+ }
+ ComPtr<IUnknown> local_source;
+ {
+ base::AutoLock lock(lock_);
+ if (has_shutdown_) {
+ return MF_E_SHUTDOWN;
+ }
+ local_source = mf_media_source_;
+ }
+
+ if (type == MF_OBJECT_MEDIASOURCE) {
+ DVLOG(2) << "Begin to resolve mf_media_source_: this=" << this;
+ DCHECK(local_source) << "Media Source should have been set";
+
+ ComPtr<IMFAsyncResult> async_result;
+ RETURN_IF_FAILED(MFCreateAsyncResult(local_source.Get(), callback, state,
+ &async_result));
+ RETURN_IF_FAILED(async_result->SetStatus(S_OK));
+ pending_create_object_ = true;
+ // Invoke the callback synchronously since no outstanding work is required.
+ RETURN_IF_FAILED(callback->Invoke(async_result.Get()));
+ } else {
+ // MediaEngine will try to resolve with different |type|.
+ return MF_E_UNEXPECTED;
+ }
+
+ return S_OK;
+}
+
+HRESULT MediaEngineExtension::CancelObjectCreation(
+ __in IUnknown* cancel_cookie) {
+ DVLOG(1) << __func__ << ": this=" << this;
+
+ return MF_E_UNEXPECTED;
+}
+
+HRESULT MediaEngineExtension::EndCreateObject(__in IMFAsyncResult* result,
+ __deref_out IUnknown** ret_obj) {
+ DVLOG(1) << __func__ << ": this=" << this;
+
+ *ret_obj = nullptr;
+ if (!pending_create_object_)
+ return MF_E_UNEXPECTED;
+
+ DVLOG(2) << "End to resolve mf_media_source_: this=" << this;
+ RETURN_IF_FAILED(result->GetStatus());
+ RETURN_IF_FAILED(result->GetObject(ret_obj));
+ pending_create_object_ = false;
+ return S_OK;
+}
+
+HRESULT MediaEngineExtension::SetMediaSource(IUnknown* mf_media_source) {
+ DVLOG(1) << __func__ << ": this=" << this;
+
+ base::AutoLock lock(lock_);
+ if (has_shutdown_)
+ return MF_E_SHUTDOWN;
+ mf_media_source_ = mf_media_source;
+ return S_OK;
+}
+
+// Break cycles.
+void MediaEngineExtension::Shutdown() {
+ DVLOG(1) << __func__ << ": this=" << this;
+
+ base::AutoLock lock(lock_);
+ if (!has_shutdown_) {
+ mf_media_source_.Reset();
+ has_shutdown_ = true;
+ }
+}
+
+} // namespace media
diff --git a/media/renderers/win/media_engine_extension.h b/media/renderers/win/media_engine_extension.h
new file mode 100644
index 0000000..cf57631
--- /dev/null
+++ b/media/renderers/win/media_engine_extension.h
@@ -0,0 +1,61 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_RENDERERS_WIN_MEDIA_ENGINE_EXTENSION_H_
+#define MEDIA_RENDERERS_WIN_MEDIA_ENGINE_EXTENSION_H_
+
+#include <mfapi.h>
+#include <mfmediaengine.h>
+#include <wrl.h>
+
+#include "base/synchronization/lock.h"
+
+namespace media {
+
+// Implement IMFMediaEngineExtension to load media source into the
+// IMFMediaEngine. See details from:
+// https://docs.microsoft.com/en-us/windows/win32/api/mfmediaengine/nn-mfmediaengine-imfmediaengineextension.
+//
+class MediaEngineExtension
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<
+ Microsoft::WRL::RuntimeClassType::ClassicCom>,
+ IMFMediaEngineExtension> {
+ public:
+ MediaEngineExtension();
+ ~MediaEngineExtension() override;
+
+ HRESULT RuntimeClassInitialize();
+
+ // IMFMediaEngineExtension
+ IFACEMETHODIMP CanPlayType(BOOL is_audio_only,
+ BSTR mime_type,
+ MF_MEDIA_ENGINE_CANPLAY* result) override;
+ IFACEMETHODIMP BeginCreateObject(BSTR url_bstr,
+ IMFByteStream* byte_stream,
+ MF_OBJECT_TYPE type,
+ IUnknown** cancel_cookie,
+ IMFAsyncCallback* callback,
+ IUnknown* state) override;
+ IFACEMETHODIMP CancelObjectCreation(IUnknown* cancel_cookie) override;
+ IFACEMETHODIMP EndCreateObject(IMFAsyncResult* result,
+ IUnknown** ret_obj) override;
+
+ HRESULT SetMediaSource(IUnknown* mf_media_source);
+ void Shutdown();
+
+ private:
+ bool pending_create_object_ = false;
+
+ // Need a lock to ensure thread safe operation between IMFMediaEngineExtension
+ // method calls from MFMediaEngine threadpool thread and
+ // SetMediaSource/Shutdown from MediaFoundationRenderer calling thread.
+ base::Lock lock_;
+ bool has_shutdown_ GUARDED_BY(lock_) = false;
+ Microsoft::WRL::ComPtr<IUnknown> mf_media_source_ GUARDED_BY(lock_);
+};
+
+} // namespace media
+
+#endif // MEDIA_RENDERERS_WIN_MEDIA_ENGINE_EXTENSION_H_