1 #include <obs-module.h>
2 #include <util/profiler.hpp>
3 
4 #include <memory>
5 #include <chrono>
6 
7 #include "mf-h264-encoder.hpp"
8 #include "mf-encoder-descriptor.hpp"
9 #include <VersionHelpers.h>
10 
11 using namespace MF;
12 
13 struct MFH264_Encoder {
14 	obs_encoder_t *encoder;
15 	std::shared_ptr<EncoderDescriptor> descriptor;
16 	std::unique_ptr<H264Encoder> h264Encoder;
17 	uint32_t width;
18 	uint32_t height;
19 	uint32_t framerateNum;
20 	uint32_t framerateDen;
21 	uint32_t keyint;
22 	bool advanced;
23 	uint32_t bitrate;
24 	uint32_t maxBitrate;
25 	bool useMaxBitrate;
26 	uint32_t bufferSize;
27 	bool useBufferSize;
28 	H264Profile profile;
29 	H264RateControl rateControl;
30 	H264QP qp;
31 	uint32_t minQp;
32 	uint32_t maxQp;
33 	bool lowLatency;
34 	uint32_t bFrames;
35 
36 	const char *profiler_encode = nullptr;
37 };
38 
39 #define MFTEXT(x) obs_module_text("MF.H264." x)
40 #define TEXT_ADVANCED        MFTEXT("Advanced")
41 #define TEXT_LOW_LAT         MFTEXT("LowLatency")
42 #define TEXT_B_FRAMES        MFTEXT("BFrames")
43 #define TEXT_BITRATE         MFTEXT("Bitrate")
44 #define TEXT_CUSTOM_BUF      MFTEXT("CustomBufsize")
45 #define TEXT_BUF_SIZE        MFTEXT("BufferSize")
46 #define TEXT_USE_MAX_BITRATE MFTEXT("CustomMaxBitrate")
47 #define TEXT_MAX_BITRATE     MFTEXT("MaxBitrate")
48 #define TEXT_KEYINT_SEC      MFTEXT("KeyframeIntervalSec")
49 #define TEXT_RATE_CONTROL    MFTEXT("RateControl")
50 #define TEXT_MIN_QP          MFTEXT("MinQP")
51 #define TEXT_MAX_QP          MFTEXT("MaxQP")
52 #define TEXT_QPI             MFTEXT("QPI")
53 #define TEXT_QPP             MFTEXT("QPP")
54 #define TEXT_QPB             MFTEXT("QPB")
55 #define TEXT_PROFILE         MFTEXT("Profile")
56 #define TEXT_CBR             MFTEXT("CBR")
57 #define TEXT_VBR             MFTEXT("VBR")
58 #define TEXT_CQP             MFTEXT("CQP")
59 
60 #define MFP(x) "mf_h264_" ## x
61 #define MFP_USE_ADVANCED     MFP("use_advanced")
62 #define MFP_USE_LOWLAT       MFP("use_low_latency")
63 #define MFP_B_FRAMES         MFP("b_frames")
64 #define MFP_BITRATE          MFP("bitrate")
65 #define MFP_USE_BUF_SIZE     MFP("use_buf_size")
66 #define MFP_BUF_SIZE         MFP("buf_size")
67 #define MFP_USE_MAX_BITRATE  MFP("use_max_bitrate")
68 #define MFP_MAX_BITRATE      MFP("max_bitrate")
69 #define MFP_KEY_INT          MFP("key_int")
70 #define MFP_RATE_CONTROL     MFP("rate_control")
71 #define MFP_MIN_QP           MFP("min_qp")
72 #define MFP_MAX_QP           MFP("max_qp")
73 #define MFP_QP_I             MFP("qp_i")
74 #define MFP_QP_P             MFP("qp_p")
75 #define MFP_QP_B             MFP("qp_b")
76 #define MFP_PROFILE          MFP("profile")
77 
78 struct TypeData {
79 	std::shared_ptr<EncoderDescriptor> descriptor;
80 
TypeDataTypeData81 	inline TypeData(std::shared_ptr<EncoderDescriptor> descriptor_)
82 		: descriptor(descriptor_)
83 	{}
84 };
85 
MFH264_GetName(void * type_data)86 static const char *MFH264_GetName(void *type_data)
87 {
88 	TypeData &typeData = *reinterpret_cast<TypeData*>(type_data);
89 	return obs_module_text(typeData.descriptor->Name());
90 }
91 
set_visible(obs_properties_t * ppts,const char * name,bool visible)92 static void set_visible(obs_properties_t *ppts, const char *name, bool visible)
93 {
94 	obs_property_t *p = obs_properties_get(ppts, name);
95 	obs_property_set_visible(p, visible);
96 }
97 
use_bufsize_modified(obs_properties_t * ppts,obs_property_t * p,obs_data_t * settings)98 static bool use_bufsize_modified(obs_properties_t *ppts, obs_property_t *p,
99 	obs_data_t *settings)
100 {
101 	UNUSED_PARAMETER(p);
102 
103 	bool use_bufsize = obs_data_get_bool(settings, MFP_USE_BUF_SIZE);
104 
105 	set_visible(ppts, MFP_BUF_SIZE, use_bufsize);
106 
107 	return true;
108 }
109 
use_max_bitrate_modified(obs_properties_t * ppts,obs_property_t * p,obs_data_t * settings)110 static bool use_max_bitrate_modified(obs_properties_t *ppts, obs_property_t *p,
111 	obs_data_t *settings)
112 {
113 	UNUSED_PARAMETER(p);
114 
115 	bool advanced        = obs_data_get_bool(settings, MFP_USE_ADVANCED);
116 	bool use_max_bitrate = obs_data_get_bool(settings, MFP_USE_MAX_BITRATE);
117 
118 	set_visible(ppts, MFP_MAX_BITRATE, advanced && use_max_bitrate);
119 
120 	return true;
121 }
122 
use_advanced_modified(obs_properties_t * ppts,obs_property_t * p,obs_data_t * settings)123 static bool use_advanced_modified(obs_properties_t *ppts, obs_property_t *p,
124 	obs_data_t *settings)
125 {
126 	UNUSED_PARAMETER(p);
127 
128 	bool advanced = obs_data_get_bool(settings, MFP_USE_ADVANCED);
129 
130 	set_visible(ppts, MFP_MIN_QP,       advanced);
131 	set_visible(ppts, MFP_MAX_QP,       advanced);
132 	set_visible(ppts, MFP_USE_LOWLAT,   advanced);
133 	set_visible(ppts, MFP_B_FRAMES,     advanced);
134 
135 	H264RateControl rateControl = (H264RateControl)obs_data_get_int(
136 		settings, MFP_RATE_CONTROL);
137 
138 	if (rateControl == H264RateControlCBR ||
139 	    rateControl == H264RateControlVBR) {
140 		set_visible(ppts, MFP_USE_MAX_BITRATE, advanced);
141 		use_max_bitrate_modified(ppts, NULL, settings);
142 	}
143 
144 	return true;
145 }
146 
rate_control_modified(obs_properties_t * ppts,obs_property_t * p,obs_data_t * settings)147 static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p,
148 	obs_data_t *settings)
149 {
150 	UNUSED_PARAMETER(p);
151 
152 	H264RateControl rateControl = (H264RateControl)obs_data_get_int(
153 		settings, MFP_RATE_CONTROL);
154 
155 	bool advanced = obs_data_get_bool(settings, MFP_USE_ADVANCED);
156 
157 	set_visible(ppts, MFP_BITRATE,         false);
158 	set_visible(ppts, MFP_USE_BUF_SIZE,    false);
159 	set_visible(ppts, MFP_BUF_SIZE,        false);
160 	set_visible(ppts, MFP_USE_MAX_BITRATE, false);
161 	set_visible(ppts, MFP_MAX_BITRATE,     false);
162 	set_visible(ppts, MFP_QP_I,            false);
163 	set_visible(ppts, MFP_QP_P,            false);
164 	set_visible(ppts, MFP_QP_B,            false);
165 
166 	switch (rateControl) {
167 	case H264RateControlCBR:
168 		use_bufsize_modified(ppts,     NULL, settings);
169 		use_max_bitrate_modified(ppts, NULL, settings);
170 
171 		set_visible(ppts, MFP_BITRATE,         true);
172 		set_visible(ppts, MFP_USE_BUF_SIZE,    true);
173 		set_visible(ppts, MFP_USE_MAX_BITRATE, advanced);
174 
175 		break;
176 	case H264RateControlVBR:
177 		use_bufsize_modified(ppts,     NULL, settings);
178 		use_max_bitrate_modified(ppts, NULL, settings);
179 
180 		set_visible(ppts, MFP_BITRATE,         true);
181 		set_visible(ppts, MFP_USE_BUF_SIZE,    true);
182 		set_visible(ppts, MFP_USE_MAX_BITRATE, advanced);
183 
184 		break;
185 	case H264RateControlCQP:
186 		set_visible(ppts, MFP_QP_I,            true);
187 		set_visible(ppts, MFP_QP_P,            true);
188 		set_visible(ppts, MFP_QP_B,            true);
189 
190 		break;
191 	default: break;
192 	}
193 
194 	return true;
195 }
196 
MFH264_GetProperties(void *)197 static obs_properties_t *MFH264_GetProperties(void *)
198 {
199 	obs_properties_t *props = obs_properties_create();
200 	obs_property_t *p;
201 
202 	obs_property_t *list = obs_properties_add_list(props, MFP_PROFILE,
203 		TEXT_PROFILE, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
204 
205 	obs_property_list_add_int(list, "baseline", H264ProfileBaseline);
206 	obs_property_list_add_int(list, "main",     H264ProfileMain);
207 	obs_property_list_add_int(list, "high",     H264ProfileHigh);
208 
209 	obs_properties_add_int(props, MFP_KEY_INT, TEXT_KEYINT_SEC, 0, 20, 1);
210 
211 	list = obs_properties_add_list(props, MFP_RATE_CONTROL,
212 		TEXT_RATE_CONTROL, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
213 
214 	obs_property_list_add_int(list, TEXT_CBR, H264RateControlCBR);
215 	obs_property_list_add_int(list, TEXT_VBR, H264RateControlVBR);
216 	obs_property_list_add_int(list, TEXT_CQP, H264RateControlCQP);
217 
218 	obs_property_set_modified_callback(list, rate_control_modified);
219 
220 	obs_properties_add_int(props, MFP_BITRATE, TEXT_BITRATE, 50, 10000000,
221 			1);
222 
223 	p = obs_properties_add_bool(props, MFP_USE_BUF_SIZE, TEXT_CUSTOM_BUF);
224 	obs_property_set_modified_callback(p, use_bufsize_modified);
225 	obs_properties_add_int(props, MFP_BUF_SIZE, TEXT_BUF_SIZE, 0,
226 			10000000, 1);
227 
228 	obs_properties_add_int(props, MFP_QP_I, TEXT_QPI, 0, 51, 1);
229 	obs_properties_add_int(props, MFP_QP_P, TEXT_QPP, 0, 51, 1);
230 	obs_properties_add_int(props, MFP_QP_B, TEXT_QPB, 0, 51, 1);
231 
232 	p = obs_properties_add_bool(props, MFP_USE_ADVANCED, TEXT_ADVANCED);
233 	obs_property_set_modified_callback(p, use_advanced_modified);
234 
235 	p = obs_properties_add_bool(props, MFP_USE_MAX_BITRATE,
236 		TEXT_USE_MAX_BITRATE);
237 	obs_property_set_modified_callback(p, use_max_bitrate_modified);
238 	obs_properties_add_int(props, MFP_MAX_BITRATE, TEXT_MAX_BITRATE, 50,
239 		10000000, 1);
240 
241 	obs_properties_add_bool(props, MFP_USE_LOWLAT, TEXT_LOW_LAT);
242 	obs_properties_add_int(props,  MFP_B_FRAMES,   TEXT_B_FRAMES, 0, 16, 1);
243 	obs_properties_add_int(props,  MFP_MIN_QP,     TEXT_MIN_QP,   1, 51, 1);
244 	obs_properties_add_int(props,  MFP_MAX_QP,     TEXT_MAX_QP,   1, 51, 1);
245 	return props;
246 }
247 
MFH264_GetDefaults(obs_data_t * settings)248 static void MFH264_GetDefaults(obs_data_t *settings)
249 {
250 #define PROP_DEF(x, y, z) obs_data_set_default_ ## x(settings, y, z)
251 	PROP_DEF(int,    MFP_BITRATE,         2500);
252 	PROP_DEF(bool,   MFP_USE_LOWLAT,      true);
253 	PROP_DEF(int,    MFP_B_FRAMES,        2);
254 	PROP_DEF(bool,   MFP_USE_BUF_SIZE,    false);
255 	PROP_DEF(int,    MFP_BUF_SIZE,        2500);
256 	PROP_DEF(bool,   MFP_USE_MAX_BITRATE, false);
257 	PROP_DEF(int,    MFP_MAX_BITRATE,     2500);
258 	PROP_DEF(int,    MFP_KEY_INT,         2);
259 	PROP_DEF(int,    MFP_RATE_CONTROL,    H264RateControlCBR);
260 	PROP_DEF(int,    MFP_PROFILE,         H264ProfileMain);
261 	PROP_DEF(int,    MFP_MIN_QP,          1);
262 	PROP_DEF(int,    MFP_MAX_QP,          51);
263 	PROP_DEF(int,    MFP_QP_I,            26);
264 	PROP_DEF(int,    MFP_QP_B,            26);
265 	PROP_DEF(int,    MFP_QP_P,            26);
266 	PROP_DEF(bool,   MFP_USE_ADVANCED,    false);
267 #undef DEF
268 }
269 
UpdateParams(MFH264_Encoder * enc,obs_data_t * settings)270 static void UpdateParams(MFH264_Encoder *enc, obs_data_t *settings)
271 {
272 	video_t *video = obs_encoder_video(enc->encoder);
273 	const struct video_output_info *voi = video_output_get_info(video);
274 	TypeData &typeData = *reinterpret_cast<TypeData*>(
275 			obs_encoder_get_type_data(enc->encoder));
276 
277 	enc->width = (uint32_t)obs_encoder_get_width(enc->encoder);
278 	enc->height = (uint32_t)obs_encoder_get_height(enc->encoder);
279 	enc->framerateNum = voi->fps_num;
280 	enc->framerateDen = voi->fps_den;
281 
282 	enc->descriptor = typeData.descriptor;
283 
284 #define PROP_GET(x, y, z) (z)obs_data_get_ ## x(settings, y)
285 	enc->profile       = PROP_GET(int,  MFP_PROFILE,      H264Profile);
286 	enc->rateControl   = PROP_GET(int,  MFP_RATE_CONTROL, H264RateControl);
287 	enc->keyint        = PROP_GET(int,  MFP_KEY_INT,      uint32_t);
288 	enc->bitrate       = PROP_GET(int,  MFP_BITRATE,      uint32_t);
289 	enc->useBufferSize = PROP_GET(bool, MFP_USE_BUF_SIZE, bool);
290 	enc->bufferSize    = PROP_GET(int,  MFP_BUF_SIZE,     uint32_t);
291 	enc->useMaxBitrate = PROP_GET(bool, MFP_USE_MAX_BITRATE, uint32_t);
292 	enc->maxBitrate    = PROP_GET(int,  MFP_MAX_BITRATE,  uint32_t);
293 	enc->minQp         = PROP_GET(int,  MFP_MIN_QP,       uint16_t);
294 	enc->maxQp         = PROP_GET(int,  MFP_MAX_QP,       uint16_t);
295 	enc->qp.defaultQp  = PROP_GET(int,  MFP_QP_I,         uint16_t);
296 	enc->qp.i          = PROP_GET(int,  MFP_QP_I,         uint16_t);
297 	enc->qp.p          = PROP_GET(int,  MFP_QP_P,         uint16_t);
298 	enc->qp.b          = PROP_GET(int,  MFP_QP_B,         uint16_t);
299 	enc->lowLatency    = PROP_GET(bool, MFP_USE_LOWLAT,   bool);
300 	enc->bFrames       = PROP_GET(int,  MFP_B_FRAMES,     uint32_t);
301 	enc->advanced      = PROP_GET(bool, MFP_USE_ADVANCED, bool);
302 #undef PROP_GET
303 }
304 
305 #undef MFTEXT
306 #undef MFP
307 
ApplyCBR(MFH264_Encoder * enc)308 static bool ApplyCBR(MFH264_Encoder *enc)
309 {
310 	enc->h264Encoder->SetBitrate(enc->bitrate);
311 
312 	if (enc->useMaxBitrate)
313 		enc->h264Encoder->SetMaxBitrate(enc->maxBitrate);
314 	else
315 		enc->h264Encoder->SetMaxBitrate(enc->bitrate);
316 
317 	if (enc->useBufferSize)
318 		enc->h264Encoder->SetBufferSize(enc->bufferSize);
319 
320 	return true;
321 }
322 
ApplyCVBR(MFH264_Encoder * enc)323 static bool ApplyCVBR(MFH264_Encoder *enc)
324 {
325 	enc->h264Encoder->SetBitrate(enc->bitrate);
326 
327 	if (enc->advanced && enc->useMaxBitrate)
328 		enc->h264Encoder->SetMaxBitrate(enc->maxBitrate);
329 	else
330 		enc->h264Encoder->SetMaxBitrate(enc->bitrate);
331 
332 	if (enc->useBufferSize)
333 		enc->h264Encoder->SetBufferSize(enc->bufferSize);
334 
335 	return true;
336 }
337 
ApplyVBR(MFH264_Encoder * enc)338 static bool ApplyVBR(MFH264_Encoder *enc)
339 {
340 	enc->h264Encoder->SetBitrate(enc->bitrate);
341 
342 	if (enc->useBufferSize)
343 		enc->h264Encoder->SetBufferSize(enc->bufferSize);
344 
345 	return true;
346 }
347 
ApplyCQP(MFH264_Encoder * enc)348 static bool ApplyCQP(MFH264_Encoder *enc)
349 {
350 	enc->h264Encoder->SetQP(enc->qp);
351 
352 	return true;
353 }
354 
MFH264_Create(obs_data_t * settings,obs_encoder_t * encoder)355 static void *MFH264_Create(obs_data_t *settings, obs_encoder_t *encoder)
356 {
357 	ProfileScope("MFH264_Create");
358 
359 	std::unique_ptr<MFH264_Encoder> enc(new MFH264_Encoder());
360 	enc->encoder = encoder;
361 
362 	UpdateParams(enc.get(), settings);
363 
364 	ProfileScope(enc->descriptor->Name());
365 
366 	enc->h264Encoder.reset(new H264Encoder(encoder,
367 			enc->descriptor,
368 			enc->width,
369 			enc->height,
370 			enc->framerateNum,
371 			enc->framerateDen,
372 			enc->profile,
373 			enc->bitrate));
374 
375 	auto applySettings = [&]() {
376 		enc.get()->h264Encoder->SetRateControl(enc->rateControl);
377 		enc.get()->h264Encoder->SetKeyframeInterval(enc->keyint);
378 
379 		enc.get()->h264Encoder->SetEntropyEncoding(
380 				H264EntropyEncodingCABAC);
381 
382 		if (enc->advanced) {
383 			enc.get()->h264Encoder->SetLowLatency(enc->lowLatency);
384 			enc.get()->h264Encoder->SetBFrameCount(enc->bFrames);
385 
386 			enc.get()->h264Encoder->SetMinQP(enc->minQp);
387 			enc.get()->h264Encoder->SetMaxQP(enc->maxQp);
388 		}
389 
390 		if (enc->rateControl == H264RateControlVBR &&
391 		    enc->advanced &&
392 		    enc->useMaxBitrate)
393 			enc->rateControl = H264RateControlConstrainedVBR;
394 
395 
396 		switch (enc->rateControl) {
397 		case H264RateControlCBR:
398 			return ApplyCBR(enc.get());
399 		case H264RateControlConstrainedVBR:
400 			return ApplyCVBR(enc.get());
401 		case H264RateControlVBR:
402 			return ApplyVBR(enc.get());
403 		case H264RateControlCQP:
404 			return ApplyCQP(enc.get());
405 		default: return false;
406 		}
407 	};
408 
409 	if (!enc->h264Encoder->Initialize(applySettings))
410 		return nullptr;
411 
412 	return enc.release();
413 }
414 
MFH264_Destroy(void * data)415 static void MFH264_Destroy(void *data)
416 {
417 	MFH264_Encoder *enc = static_cast<MFH264_Encoder *>(data);
418 	delete enc;
419 }
420 
MFH264_Encode(void * data,struct encoder_frame * frame,struct encoder_packet * packet,bool * received_packet)421 static bool MFH264_Encode(void *data, struct encoder_frame *frame,
422 		struct encoder_packet *packet, bool *received_packet)
423 {
424 	MFH264_Encoder *enc = static_cast<MFH264_Encoder *>(data);
425 	Status status;
426 
427 	if (!enc->profiler_encode)
428 		 enc->profiler_encode = profile_store_name(
429 				obs_get_profiler_name_store(),
430 				"MFH264_Encode(%s)", enc->descriptor->Name());
431 
432 	ProfileScope(enc->profiler_encode);
433 
434 	*received_packet = false;
435 
436 	if (!enc->h264Encoder->ProcessInput(frame->data, frame->linesize,
437 			frame->pts, &status))
438 		return false;
439 
440 	UINT8 *outputData;
441 	UINT32 outputDataLength;
442 	UINT64 outputPts;
443 	UINT64 outputDts;
444 	bool keyframe;
445 
446 	if (!enc->h264Encoder->ProcessOutput(&outputData, &outputDataLength,
447 			&outputPts, &outputDts, &keyframe, &status))
448 		return false;
449 
450 	// Needs more input, not a failure case
451 	if (status == NEED_MORE_INPUT)
452 		return true;
453 
454 	packet->type = OBS_ENCODER_VIDEO;
455 	packet->pts = outputPts;
456 	packet->dts = outputPts;
457 	packet->data = outputData;
458 	packet->size = outputDataLength;
459 	packet->keyframe = keyframe;
460 
461 	*received_packet = true;
462 	return true;
463 }
464 
MFH264_GetExtraData(void * data,uint8_t ** extra_data,size_t * size)465 static bool MFH264_GetExtraData(void *data, uint8_t **extra_data, size_t *size)
466 {
467 	MFH264_Encoder *enc = static_cast<MFH264_Encoder *>(data);
468 
469 	uint8_t *extraData;
470 	UINT32 extraDataLength;
471 
472 	if (!enc->h264Encoder->ExtraData(&extraData, &extraDataLength))
473 		return false;
474 
475 	*extra_data = extraData;
476 	*size = extraDataLength;
477 
478 	return true;
479 }
480 
MFH264_GetSEIData(void * data,uint8_t ** sei_data,size_t * size)481 static bool MFH264_GetSEIData(void *data, uint8_t **sei_data, size_t *size)
482 {
483 	UNUSED_PARAMETER(data);
484 	UNUSED_PARAMETER(sei_data);
485 	UNUSED_PARAMETER(size);
486 
487 	return false;
488 }
489 
MFH264_GetVideoInfo(void *,struct video_scale_info * info)490 static void MFH264_GetVideoInfo(void *, struct video_scale_info *info)
491 {
492 	info->format = VIDEO_FORMAT_NV12;
493 }
494 
MFH264_Update(void * data,obs_data_t * settings)495 static bool MFH264_Update(void *data, obs_data_t *settings)
496 {
497 	MFH264_Encoder *enc = static_cast<MFH264_Encoder *>(data);
498 
499 	UpdateParams(enc, settings);
500 
501 	enc->h264Encoder->SetBitrate(enc->bitrate);
502 	enc->h264Encoder->SetQP(enc->qp);
503 
504 	return true;
505 }
506 
CanSpawnEncoder(std::shared_ptr<EncoderDescriptor> descriptor)507 static bool CanSpawnEncoder(std::shared_ptr<EncoderDescriptor> descriptor)
508 {
509 	HRESULT hr;
510 	ComPtr<IMFTransform> transform;
511 
512 	hr = CoCreateInstance(descriptor->Guid(), nullptr,
513 			CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&transform));
514 	return hr == S_OK;
515 }
516 
RegisterMFH264Encoders()517 void RegisterMFH264Encoders()
518 {
519 	obs_encoder_info info = { 0 };
520 	info.type = OBS_ENCODER_VIDEO;
521 	info.get_name = MFH264_GetName;
522 	info.create = MFH264_Create;
523 	info.destroy = MFH264_Destroy;
524 	info.encode = MFH264_Encode;
525 	info.update = MFH264_Update;
526 	info.get_properties = MFH264_GetProperties;
527 	info.get_defaults = MFH264_GetDefaults;
528 	info.get_extra_data = MFH264_GetExtraData;
529 	info.get_sei_data = MFH264_GetSEIData;
530 	info.get_video_info = MFH264_GetVideoInfo;
531 	info.codec = "h264";
532 
533 	auto encoders = EncoderDescriptor::Enumerate();
534 	for (auto e : encoders) {
535 		/* ignore the software encoder due to the fact that we already
536 		 * have an objectively superior software encoder available */
537 		if (e->Type() == EncoderType::H264_SOFTWARE)
538 			continue;
539 
540 		/* certain encoders such as quicksync will be "available" but
541 		 * not usable with certain processors */
542 		if (!CanSpawnEncoder(e))
543 			continue;
544 
545 		info.caps = OBS_ENCODER_CAP_DEPRECATED;
546 		info.id = e->Id();
547 		info.type_data = new TypeData(e);
548 		info.free_type_data = [] (void *type_data) {
549 			delete reinterpret_cast<TypeData*>(type_data);
550 		};
551 
552 		obs_register_encoder(&info);
553 	}
554 }
555