WMF.h (7983B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef WMF_H_ 8 #define WMF_H_ 9 10 // clang-format off 11 #include <windows.h> 12 #include <mfapi.h> 13 #include <mfidl.h> 14 #include <mfreadwrite.h> 15 #include <mfobjects.h> 16 #include <ks.h> 17 #include <mferror.h> 18 #include <propvarutil.h> 19 #include <wmcodecdsp.h> 20 #include <d3d9.h> 21 #include <dxva2api.h> 22 #include <wmcodecdsp.h> 23 #include <codecapi.h> 24 // clang-format on 25 26 #include "mozilla/AppShutdown.h" 27 #include "mozilla/Atomics.h" 28 #include "mozilla/ClearOnShutdown.h" 29 #include "mozilla/StaticMutex.h" 30 #include "nsThreadUtils.h" 31 32 // The Windows headers helpfully declare min and max macros, which don't 33 // compile in the presence of std::min and std::max and unified builds. 34 // So undef them here. 35 #ifdef min 36 # undef min 37 #endif 38 #ifdef max 39 # undef max 40 #endif 41 42 // https://stackoverflow.com/questions/25759700/ms-format-tag-for-opus-codec 43 #ifndef MFAudioFormat_Opus 44 DEFINE_GUID(MFAudioFormat_Opus, WAVE_FORMAT_OPUS, 0x000, 0x0010, 0x80, 0x00, 45 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); 46 #endif 47 48 const inline GUID CLSID_CMSVPXDecMFT = { 49 0xe3aaf548, 50 0xc9a4, 51 0x4c6e, 52 {0x23, 0x4d, 0x5a, 0xda, 0x37, 0x4b, 0x00, 0x00}}; 53 54 namespace mozilla::wmf { 55 56 // A helper class for automatically starting and shuting down the Media 57 // Foundation. Prior to using Media Foundation in a process, users should call 58 // MediaFoundationInitializer::HasInitialized() to ensure Media Foundation is 59 // initialized. Users should also check the result of this call, in case the 60 // internal call to MFStartup fails. The first check to HasInitialized will 61 // cause the helper to start up Media Foundation and set up a runnable to handle 62 // Media Foundation shutdown at XPCOM shutdown. Calls after the first will not 63 // cause any extra startups or shutdowns, so it's safe to check multiple times 64 // in the same process. Users do not need to do any manual shutdown, the helper 65 // will handle this internally. 66 class MediaFoundationInitializer final { 67 public: 68 ~MediaFoundationInitializer() { 69 if (mHasInitialized) { 70 if (FAILED(MFShutdown())) { 71 NS_WARNING("MFShutdown failed"); 72 } 73 } 74 } 75 static bool HasInitialized() { 76 if (sIsShutdown) { 77 return false; 78 } 79 auto* rv = Get(); 80 return rv ? rv->mHasInitialized : false; 81 } 82 83 private: 84 static MediaFoundationInitializer* Get() { 85 { 86 StaticMutexAutoLock lock(sCreateMutex); 87 if (!sInitializer) { 88 // Already in shutdown. 89 if (AppShutdown::GetCurrentShutdownPhase() != 90 ShutdownPhase::NotInShutdown) { 91 sIsShutdown = true; 92 return nullptr; 93 } 94 sInitializer.reset(new MediaFoundationInitializer()); 95 auto shutdownCleanUp = [&] { 96 if (AppShutdown::GetCurrentShutdownPhase() != 97 ShutdownPhase::NotInShutdown) { 98 sInitializer.reset(); 99 sIsShutdown = true; 100 return; 101 } 102 // As MFShutdown needs to run on the MTA thread that is destroyed 103 // on XPCOMShutdownThreads, so we need to run cleanup before that 104 // phase. 105 RunOnShutdown( 106 [&]() { 107 sInitializer.reset(); 108 sIsShutdown = true; 109 }, 110 ShutdownPhase::XPCOMShutdown); 111 }; 112 if (NS_IsMainThread()) { 113 shutdownCleanUp(); 114 } else { 115 GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction( 116 "MediaFoundationInitializer::Get", shutdownCleanUp)); 117 } 118 } 119 } 120 return sInitializer.get(); 121 } 122 123 MediaFoundationInitializer() : mHasInitialized(SUCCEEDED(MFStartup())) { 124 if (!mHasInitialized) { 125 NS_WARNING("MFStartup failed"); 126 } 127 } 128 129 // If successful, loads all required WMF DLLs and calls the WMF MFStartup() 130 // function. This delegates the WMF MFStartup() call to the MTA thread if 131 // the current thread is not MTA. This is to ensure we always interact with 132 // WMF from threads with the same COM compartment model. 133 HRESULT MFStartup(); 134 135 // Calls the WMF MFShutdown() function. Call this once for every time 136 // wmf::MFStartup() succeeds. Note: does not unload the WMF DLLs loaded by 137 // MFStartup(); leaves them in memory to save I/O at next MFStartup() call. 138 // This delegates the WMF MFShutdown() call to the MTA thread if the current 139 // thread is not MTA. This is to ensure we always interact with 140 // WMF from threads with the same COM compartment model. 141 HRESULT MFShutdown(); 142 143 constinit static inline UniquePtr<MediaFoundationInitializer> sInitializer; 144 static inline StaticMutex sCreateMutex; 145 static inline Atomic<bool> sIsShutdown{false}; 146 const bool mHasInitialized; 147 }; 148 149 // All functions below are wrappers around the corresponding WMF function, 150 // and automatically locate and call the corresponding function in the WMF DLLs. 151 152 HRESULT MFCreateMediaType(IMFMediaType** aOutMFType); 153 154 HRESULT MFGetStrideForBitmapInfoHeader(DWORD aFormat, DWORD aWidth, 155 LONG* aOutStride); 156 157 HRESULT MFGetService(IUnknown* punkObject, REFGUID guidService, REFIID riid, 158 LPVOID* ppvObject); 159 160 HRESULT DXVA2CreateDirect3DDeviceManager9( 161 UINT* pResetToken, IDirect3DDeviceManager9** ppDXVAManager); 162 163 HRESULT MFCreateDXGIDeviceManager(UINT* pResetToken, 164 IMFDXGIDeviceManager** ppDXVAManager); 165 166 HRESULT MFCreateSample(IMFSample** ppIMFSample); 167 168 HRESULT MFCreateAlignedMemoryBuffer(DWORD cbMaxLength, DWORD fAlignmentFlags, 169 IMFMediaBuffer** ppBuffer); 170 171 HRESULT MFCreateDXGISurfaceBuffer(REFIID riid, IUnknown* punkSurface, 172 UINT uSubresourceIndex, 173 BOOL fButtomUpWhenLinear, 174 IMFMediaBuffer** ppBuffer); 175 176 HRESULT MFTEnumEx(GUID guidCategory, UINT32 Flags, 177 const MFT_REGISTER_TYPE_INFO* pInputType, 178 const MFT_REGISTER_TYPE_INFO* pOutputType, 179 IMFActivate*** pppMFTActivate, UINT32* pnumMFTActivate); 180 181 HRESULT MFTGetInfo(CLSID clsidMFT, LPWSTR* pszName, 182 MFT_REGISTER_TYPE_INFO** ppInputTypes, UINT32* pcInputTypes, 183 MFT_REGISTER_TYPE_INFO** ppOutputTypes, 184 UINT32* pcOutputTypes, IMFAttributes** ppAttributes); 185 186 HRESULT MFCreateAttributes(IMFAttributes** ppMFAttributes, UINT32 cInitialSize); 187 188 HRESULT MFCreateEventQueue(IMFMediaEventQueue** ppMediaEventQueue); 189 190 HRESULT MFCreateStreamDescriptor(DWORD dwStreamIdentifier, DWORD cMediaTypes, 191 IMFMediaType** apMediaTypes, 192 IMFStreamDescriptor** ppDescriptor); 193 194 HRESULT MFCreateAsyncResult(IUnknown* punkObject, IMFAsyncCallback* pCallback, 195 IUnknown* punkState, 196 IMFAsyncResult** ppAsyncResult); 197 198 HRESULT MFCreatePresentationDescriptor( 199 DWORD cStreamDescriptors, IMFStreamDescriptor** apStreamDescriptors, 200 IMFPresentationDescriptor** ppPresentationDescriptor); 201 202 HRESULT MFCreateMemoryBuffer(DWORD cbMaxLength, IMFMediaBuffer** ppBuffer); 203 204 HRESULT MFLockDXGIDeviceManager(UINT* pResetToken, 205 IMFDXGIDeviceManager** ppManager); 206 207 HRESULT MFUnlockDXGIDeviceManager(); 208 209 HRESULT MFPutWorkItem(DWORD dwQueue, IMFAsyncCallback* pCallback, 210 IUnknown* pState); 211 212 HRESULT MFSerializeAttributesToStream(IMFAttributes* pAttr, DWORD dwOptions, 213 IStream* pStm); 214 215 HRESULT MFWrapMediaType(IMFMediaType* pOrig, REFGUID MajorType, REFGUID SubType, 216 IMFMediaType** ppWrap); 217 218 } // namespace mozilla::wmf 219 220 #endif