1 #include <obs-module.h>
2 #include <util/platform.h>
3 #include <memory>
4 #include <algorithm>
5
6 #include "mf-encoder-descriptor.hpp"
7
8 using namespace MF;
9
10 template<class T> class ComHeapPtr {
11
12 protected:
13 T *ptr;
14
Kill()15 inline void Kill()
16 {
17 if (ptr)
18 CoTaskMemFree(ptr);
19 }
20
Replace(T * p)21 inline void Replace(T *p)
22 {
23 if (ptr != p) {
24 if (ptr) ptr->Kill();
25 ptr = p;
26 }
27 }
28
29 public:
ComHeapPtr()30 inline ComHeapPtr() : ptr(nullptr) {}
ComHeapPtr(T * p)31 inline ComHeapPtr(T *p) : ptr(p) {}
32 inline ComHeapPtr(const ComHeapPtr<T> &c) = delete;
33 inline ComHeapPtr(ComHeapPtr<T> &&c) = delete;
~ComHeapPtr()34 inline ~ComHeapPtr() { Kill(); }
35
Clear()36 inline void Clear()
37 {
38 if (ptr) {
39 Kill();
40 ptr = nullptr;
41 }
42 }
43
operator =(T * p)44 inline ComPtr<T> &operator=(T *p)
45 {
46 Replace(p);
47 return *this;
48 }
49
Detach()50 inline T *Detach()
51 {
52 T *out = ptr;
53 ptr = nullptr;
54 return out;
55 }
56
Assign()57 inline T **Assign() { Clear(); return &ptr; }
Set(T * p)58 inline void Set(T *p) { Kill(); ptr = p; }
59
Get() const60 inline T *Get() const { return ptr; }
61
operator &()62 inline T **operator&() { return Assign(); }
63
operator T*() const64 inline operator T*() const { return ptr; }
operator ->() const65 inline T *operator->() const { return ptr; }
66
operator ==(T * p) const67 inline bool operator==(T *p) const { return ptr == p; }
operator !=(T * p) const68 inline bool operator!=(T *p) const { return ptr != p; }
69
operator !() const70 inline bool operator!() const { return !ptr; }
71 };
72
73 struct EncoderEntry {
74 const char *guid;
75 const char *name;
76 const char *id;
77 EncoderType type;
78
79 } guidNameMap[] = {
80 {
81 "{6CA50344-051A-4DED-9779-A43305165E35}",
82 "MF.H264.EncoderSWMicrosoft",
83 "mf_h264_software",
84 EncoderType::H264_SOFTWARE
85 },
86 {
87 "{ADC9BC80-0F41-46C6-AB75-D693D793597D}",
88 "MF.H264.EncoderHWAMD",
89 "mf_h264_vce",
90 EncoderType::H264_VCE,
91 },
92 {
93 "{4BE8D3C0-0515-4A37-AD55-E4BAE19AF471}",
94 "MF.H264.EncoderHWIntel",
95 "mf_h264_qsv",
96 EncoderType::H264_QSV
97 },
98 {
99 "{60F44560-5A20-4857-BFEF-D29773CB8040}",
100 "MF.H264.EncoderHWNVIDIA",
101 "mf_h264_nvenc",
102 EncoderType::H264_NVENC
103 }
104 };
105
MBSToString(wchar_t * mbs)106 static std::string MBSToString(wchar_t *mbs)
107 {
108 char *cstr;
109 os_wcs_to_utf8_ptr(mbs, 0, &cstr);
110 std::string str = cstr;
111 bfree(cstr);
112 return str;
113 }
114
CreateDescriptor(ComPtr<IMFActivate> activate)115 static std::unique_ptr<EncoderDescriptor> CreateDescriptor(
116 ComPtr<IMFActivate> activate)
117 {
118 UINT32 flags;
119 if (FAILED(activate->GetUINT32(MF_TRANSFORM_FLAGS_Attribute, &flags)))
120 return nullptr;
121
122 bool isAsync = !(flags & MFT_ENUM_FLAG_SYNCMFT);
123 isAsync |= !!(flags & MFT_ENUM_FLAG_ASYNCMFT);
124 bool isHardware = !!(flags & MFT_ENUM_FLAG_HARDWARE);
125
126 GUID guid = {0};
127
128 if (FAILED(activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &guid)))
129 return nullptr;
130
131 ComHeapPtr<WCHAR> guidW;
132 StringFromIID(guid, &guidW);
133 std::string guidString = MBSToString(guidW);
134
135 auto pred = [guidString](const EncoderEntry &name) {
136 return guidString == name.guid;
137 };
138
139 EncoderEntry *entry = std::find_if(std::begin(guidNameMap),
140 std::end(guidNameMap), pred);
141
142 std::unique_ptr<EncoderDescriptor> descriptor(new EncoderDescriptor(
143 activate, entry->name, entry->id, guid, guidString,
144 isAsync, isHardware, entry->type));
145
146 return descriptor;
147 }
148
Enumerate()149 std::vector<std::shared_ptr<EncoderDescriptor>> EncoderDescriptor::Enumerate()
150 {
151 HRESULT hr;
152 UINT32 count = 0;
153 std::vector<std::shared_ptr<EncoderDescriptor>> descriptors;
154
155 ComHeapPtr<IMFActivate *> ppActivate;
156
157 MFT_REGISTER_TYPE_INFO info = { MFMediaType_Video, MFVideoFormat_H264 };
158
159 UINT32 unFlags = 0;
160
161 unFlags |= MFT_ENUM_FLAG_LOCALMFT;
162 unFlags |= MFT_ENUM_FLAG_TRANSCODE_ONLY;
163
164 unFlags |= MFT_ENUM_FLAG_SYNCMFT;
165 unFlags |= MFT_ENUM_FLAG_ASYNCMFT;
166 unFlags |= MFT_ENUM_FLAG_HARDWARE;
167
168 unFlags |= MFT_ENUM_FLAG_SORTANDFILTER;
169
170 hr = MFTEnumEx(MFT_CATEGORY_VIDEO_ENCODER,
171 unFlags,
172 NULL,
173 &info,
174 &ppActivate,
175 &count);
176
177 if (SUCCEEDED(hr) && count == 0) {
178 return descriptors;
179 }
180
181 if (SUCCEEDED(hr)) {
182 for (decltype(count) i = 0; i < count; i++) {
183 auto p = std::move(CreateDescriptor(ppActivate[i]));
184 if (p)
185 descriptors.emplace_back(std::move(p));
186 }
187 }
188
189 for (UINT32 i = 0; i < count; i++) {
190 ppActivate[i]->Release();
191 }
192
193 return descriptors;
194 }
195