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