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