obs-x264.c 21.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/******************************************************************************
    Copyright (C) 2014 by Hugh Bailey <obs.jim@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

J
jp9000 已提交
18
#include <stdio.h>
19 20
#include <util/dstr.h>
#include <util/darray.h>
21
#include <util/platform.h>
J
jp9000 已提交
22
#include <obs-module.h>
23 24 25 26 27

#ifndef _STDINT_H_INCLUDED
#define _STDINT_H_INCLUDED
#endif

28 29
#include <x264.h>

J
jp9000 已提交
30 31
#define do_log(level, format, ...) \
	blog(level, "[x264 encoder: '%s'] " format, \
32
			obs_encoder_get_name(obsx264->encoder), ##__VA_ARGS__)
J
jp9000 已提交
33 34 35 36 37

#define warn(format, ...)  do_log(LOG_WARNING, format, ##__VA_ARGS__)
#define info(format, ...)  do_log(LOG_INFO,    format, ##__VA_ARGS__)
#define debug(format, ...) do_log(LOG_DEBUG,   format, ##__VA_ARGS__)

38 39
//#define ENABLE_VFR

J
jp9000 已提交
40 41
/* ------------------------------------------------------------------------- */

42
struct obs_x264 {
43
	obs_encoder_t          *encoder;
44

45 46
	x264_param_t           params;
	x264_t                 *context;
47

48
	DARRAY(uint8_t)        packet_data;
49

50 51
	uint8_t                *extra_data;
	uint8_t                *sei;
52

53 54 55
	size_t                 extra_data_size;
	size_t                 sei_size;

56
	os_performance_token_t *performance_token;
57 58 59 60
};

/* ------------------------------------------------------------------------- */

61
static const char *obs_x264_getname(void *unused)
62
{
63
	UNUSED_PARAMETER(unused);
64 65 66 67 68
	return "x264";
}

static void obs_x264_stop(void *data);

J
jp9000 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81
static void clear_data(struct obs_x264 *obsx264)
{
	if (obsx264->context) {
		x264_encoder_close(obsx264->context);
		bfree(obsx264->sei);
		bfree(obsx264->extra_data);

		obsx264->context    = NULL;
		obsx264->sei        = NULL;
		obsx264->extra_data = NULL;
	}
}

82 83 84 85 86
static void obs_x264_destroy(void *data)
{
	struct obs_x264 *obsx264 = data;

	if (obsx264) {
87
		os_end_high_performance(obsx264->performance_token);
J
jp9000 已提交
88
		clear_data(obsx264);
89 90 91 92 93
		da_free(obsx264->packet_data);
		bfree(obsx264);
	}
}

94
static void obs_x264_defaults(obs_data_t *settings)
95
{
J
jp9000 已提交
96 97 98
	obs_data_set_default_int   (settings, "bitrate",     2500);
	obs_data_set_default_bool  (settings, "use_bufsize", false);
	obs_data_set_default_int   (settings, "buffer_size", 2500);
99
	obs_data_set_default_int   (settings, "keyint_sec",  0);
100
	obs_data_set_default_int   (settings, "crf",         23);
101
#ifdef ENABLE_VFR
102
	obs_data_set_default_bool  (settings, "vfr",         false);
103
#endif
104
	obs_data_set_default_string(settings, "rate_control","CBR");
105 106 107 108 109 110 111

	obs_data_set_default_string(settings, "preset",      "veryfast");
	obs_data_set_default_string(settings, "profile",     "");
	obs_data_set_default_string(settings, "tune",        "");
	obs_data_set_default_string(settings, "x264opts",    "");
}

112
static inline void add_strings(obs_property_t *list, const char *const *strings)
113 114
{
	while (*strings) {
J
jp9000 已提交
115
		obs_property_list_add_string(list, *strings, *strings);
116 117 118 119
		strings++;
	}
}

120
#define TEXT_RATE_CONTROL obs_module_text("RateControl")
J
jp9000 已提交
121
#define TEXT_BITRATE    obs_module_text("Bitrate")
J
jp9000 已提交
122
#define TEXT_CUSTOM_BUF obs_module_text("CustomBufsize")
J
jp9000 已提交
123
#define TEXT_BUF_SIZE   obs_module_text("BufferSize")
124
#define TEXT_VFR        obs_module_text("VFR")
J
jp9000 已提交
125
#define TEXT_CRF        obs_module_text("CRF")
J
jp9000 已提交
126 127 128 129
#define TEXT_KEYINT_SEC obs_module_text("KeyframeIntervalSec")
#define TEXT_PRESET     obs_module_text("CPUPreset")
#define TEXT_PROFILE    obs_module_text("Profile")
#define TEXT_TUNE       obs_module_text("Tune")
130
#define TEXT_NONE       obs_module_text("None")
J
jp9000 已提交
131 132
#define TEXT_X264_OPTS  obs_module_text("EncoderOptions")

J
jp9000 已提交
133 134 135 136
static bool use_bufsize_modified(obs_properties_t *ppts, obs_property_t *p,
		obs_data_t *settings)
{
	bool use_bufsize = obs_data_get_bool(settings, "use_bufsize");
137 138 139
	const char *rc = obs_data_get_string(settings, "rate_control");
	bool rc_crf = astrcmpi(rc, "CRF") == 0;

J
jp9000 已提交
140
	p = obs_properties_get(ppts, "buffer_size");
141
	obs_property_set_visible(p, use_bufsize && !rc_crf);
J
jp9000 已提交
142 143 144
	return true;
}

145
static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p,
J
jp9000 已提交
146 147
		obs_data_t *settings)
{
148
	const char *rc = obs_data_get_string(settings, "rate_control");
149
	bool use_bufsize = obs_data_get_bool(settings, "use_bufsize");
150 151 152
	bool abr = astrcmpi(rc, "CBR") == 0 || astrcmpi(rc, "ABR") == 0;
	bool rc_crf = astrcmpi(rc, "CRF") == 0;

J
jp9000 已提交
153
	p = obs_properties_get(ppts, "crf");
154 155 156 157 158 159
	obs_property_set_visible(p, !abr);

	p = obs_properties_get(ppts, "bitrate");
	obs_property_set_visible(p, !rc_crf);
	p = obs_properties_get(ppts, "use_bufsize");
	obs_property_set_visible(p, !rc_crf);
S
SuslikV 已提交
160
	p = obs_properties_get(ppts, "buffer_size");
161
	obs_property_set_visible(p, !rc_crf && use_bufsize);
J
jp9000 已提交
162 163 164
	return true;
}

165
static obs_properties_t *obs_x264_props(void *unused)
166
{
167 168
	UNUSED_PARAMETER(unused);

169 170
	obs_properties_t *props = obs_properties_create();
	obs_property_t *list;
J
jp9000 已提交
171
	obs_property_t *p;
172

173 174 175 176 177 178 179 180 181
	list = obs_properties_add_list(props, "rate_control", TEXT_RATE_CONTROL,
			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
	obs_property_list_add_string(list, "CBR", "CBR");
	obs_property_list_add_string(list, "ABR", "ABR");
	obs_property_list_add_string(list, "VBR", "VBR");
	obs_property_list_add_string(list, "CRF", "CRF");

	obs_property_set_modified_callback(list, rate_control_modified);

182 183 184
	p = obs_properties_add_int(props, "bitrate",
			TEXT_BITRATE, 50, 10000000, 50);
	obs_property_int_set_suffix(p, " Kbps");
J
jp9000 已提交
185 186 187

	p = obs_properties_add_bool(props, "use_bufsize", TEXT_CUSTOM_BUF);
	obs_property_set_modified_callback(p, use_bufsize_modified);
188
	obs_properties_add_int(props, "buffer_size", TEXT_BUF_SIZE, 0,
189
			10000000, 1);
J
jp9000 已提交
190 191 192

	obs_properties_add_int(props, "crf", TEXT_CRF, 0, 51, 1);

193
	obs_properties_add_int(props, "keyint_sec", TEXT_KEYINT_SEC, 0, 20, 1);
194

J
jp9000 已提交
195
	list = obs_properties_add_list(props, "preset", TEXT_PRESET,
196 197 198
			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
	add_strings(list, x264_preset_names);

J
jp9000 已提交
199
	list = obs_properties_add_list(props, "profile", TEXT_PROFILE,
200
			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
201
	obs_property_list_add_string(list, TEXT_NONE, "");
J
jp9000 已提交
202 203 204
	obs_property_list_add_string(list, "baseline", "baseline");
	obs_property_list_add_string(list, "main", "main");
	obs_property_list_add_string(list, "high", "high");
205

J
jp9000 已提交
206
	list = obs_properties_add_list(props, "tune", TEXT_TUNE,
207
			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
208
	obs_property_list_add_string(list, TEXT_NONE, "");
209 210
	add_strings(list, x264_tune_names);

211
#ifdef ENABLE_VFR
212
	obs_properties_add_bool(props, "vfr", TEXT_VFR);
213
#endif
214

J
jp9000 已提交
215
	obs_properties_add_text(props, "x264opts", TEXT_X264_OPTS,
216
			OBS_TEXT_DEFAULT);
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236

	return props;
}

static bool getparam(const char *param, char **name, const char **value)
{
	const char *assign;

	if (!param || !*param || (*param == '='))
		return false;

	assign = strchr(param, '=');
	if (!assign || !*assign || !*(assign+1))
		return false;

	*name  = bstrdup_n(param, assign-param);
	*value = assign+1;
	return true;
}

J
jp9000 已提交
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
static const char *validate(struct obs_x264 *obsx264,
		const char *val, const char *name,
		const char *const *list)
{
	if (!val || !*val)
		return val;

	while (*list) {
		if (strcmp(val, *list) == 0)
			return val;

		list++;
	}

	warn("Invalid %s: %s", name, val);
	return NULL;
}

static void override_base_param(struct obs_x264 *obsx264, const char *param,
256 257 258 259 260 261 262
		char **preset, char **profile, char **tune)
{
	char       *name;
	const char *val;

	if (getparam(param, &name, &val)) {
		if (astrcmpi(name, "preset") == 0) {
J
jp9000 已提交
263 264 265 266 267 268
			const char *valid_name = validate(obsx264, val,
					"preset", x264_preset_names);
			if (valid_name) {
				bfree(*preset);
				*preset = bstrdup(val);
			}
269 270

		} else if (astrcmpi(name, "profile") == 0) {
J
jp9000 已提交
271 272 273 274 275 276
			const char *valid_name = validate(obsx264, val,
					"profile", x264_profile_names);
			if (valid_name) {
				bfree(*profile);
				*profile = bstrdup(val);
			}
277 278

		} else if (astrcmpi(name, "tune") == 0) {
J
jp9000 已提交
279 280 281 282 283 284
			const char *valid_name = validate(obsx264, val,
					"tune", x264_tune_names);
			if (valid_name) {
				bfree(*tune);
				*tune = bstrdup(val);
			}
285 286 287 288 289 290
		}

		bfree(name);
	}
}

J
jp9000 已提交
291
static inline void override_base_params(struct obs_x264 *obsx264, char **params,
292 293 294
		char **preset, char **profile, char **tune)
{
	while (*params)
J
jp9000 已提交
295 296
		override_base_param(obsx264, *(params++),
				preset, profile, tune);
297 298
}

299 300
#define OPENCL_ALIAS "opencl_is_experimental_and_potentially_unstable"

301 302 303 304 305 306
static inline void set_param(struct obs_x264 *obsx264, const char *param)
{
	char       *name;
	const char *val;

	if (getparam(param, &name, &val)) {
J
jp9000 已提交
307 308 309 310 311 312
		if (strcmp(name, "preset")    != 0 &&
		    strcmp(name, "profile")   != 0 &&
		    strcmp(name, "tune")      != 0 &&
		    strcmp(name, "fps")       != 0 &&
		    strcmp(name, "force-cfr") != 0 &&
		    strcmp(name, "width")     != 0 &&
D
derrod 已提交
313 314
		    strcmp(name, "height")    != 0 &&
		    strcmp(name, "opencl")    != 0) {
315 316
			if (strcmp(name, OPENCL_ALIAS) == 0)
				strcpy(name, "opencl");
J
jp9000 已提交
317 318 319
			if (x264_param_parse(&obsx264->params, name, val) != 0)
				warn("x264 param: %s failed", param);
		}
320 321 322 323 324 325 326 327

		bfree(name);
	}
}

static inline void apply_x264_profile(struct obs_x264 *obsx264,
		const char *profile)
{
328
	if (!obsx264->context && profile && *profile) {
329 330
		int ret = x264_param_apply_profile(&obsx264->params, profile);
		if (ret != 0)
J
jp9000 已提交
331
			warn("Failed to set x264 profile '%s'", profile);
332 333 334
	}
}

J
jp9000 已提交
335 336 337 338 339 340 341 342
static inline const char *validate_preset(struct obs_x264 *obsx264,
		const char *preset)
{
	const char *new_preset = validate(obsx264, preset, "preset",
			x264_preset_names);
	return new_preset ? new_preset : "veryfast";
}

343 344 345
static bool reset_x264_params(struct obs_x264 *obsx264,
		const char *preset, const char *tune)
{
J
jp9000 已提交
346 347 348 349
	int ret = x264_param_default_preset(&obsx264->params,
			validate_preset(obsx264, preset),
			validate(obsx264, tune, "tune", x264_tune_names));
	return ret == 0;
350 351 352 353
}

static void log_x264(void *param, int level, const char *format, va_list args)
{
354 355 356 357 358
	struct obs_x264 *obsx264 = param;
	char str[1024];

	vsnprintf(str, 1024, format, args);
	info("%s", str);
359 360 361 362

	UNUSED_PARAMETER(level);
}

363 364 365 366 367
static inline const char *get_x264_colorspace_name(enum video_colorspace cs)
{
	switch (cs) {
	case VIDEO_CS_DEFAULT:
	case VIDEO_CS_601:
368
		return "undef";
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
	case VIDEO_CS_709:;
	}

	return "bt709";
}

static inline int get_x264_cs_val(enum video_colorspace cs,
		const char *const names[])
{
	const char *name = get_x264_colorspace_name(cs);
	int idx = 0;
	do {
		if (strcmp(names[idx], name) == 0)
			return idx;
	} while (!!names[++idx]);

	return 0;
}

388 389
static void obs_x264_video_info(void *data, struct video_scale_info *info);

390 391 392 393 394 395 396
enum rate_control {
	RATE_CONTROL_CBR,
	RATE_CONTROL_VBR,
	RATE_CONTROL_ABR,
	RATE_CONTROL_CRF
};

397
static void update_params(struct obs_x264 *obsx264, obs_data_t *settings,
398 399
		char **params)
{
400
	video_t *video = obs_encoder_video(obsx264->encoder);
401
	const struct video_output_info *voi = video_output_get_info(video);
402 403 404 405 406 407 408
	struct video_scale_info info;

	info.format = voi->format;
	info.colorspace = voi->colorspace;
	info.range = voi->range;

	obs_x264_video_info(obsx264, &info);
409

410 411
	const char *rate_control = obs_data_get_string(settings, "rate_control");

J
jp9000 已提交
412 413 414 415
	int bitrate      = (int)obs_data_get_int(settings, "bitrate");
	int buffer_size  = (int)obs_data_get_int(settings, "buffer_size");
	int keyint_sec   = (int)obs_data_get_int(settings, "keyint_sec");
	int crf          = (int)obs_data_get_int(settings, "crf");
416 417
	int width        = (int)obs_encoder_get_width(obsx264->encoder);
	int height       = (int)obs_encoder_get_height(obsx264->encoder);
418
	int bf           = (int)obs_data_get_int(settings, "bf");
J
jp9000 已提交
419
	bool use_bufsize = obs_data_get_bool(settings, "use_bufsize");
420 421 422
	bool cbr_override= obs_data_get_bool(settings, "cbr");
	enum rate_control rc;

423 424 425 426
#ifdef ENABLE_VFR
	bool vfr         = obs_data_get_bool(settings, "vfr");
#endif

427 428 429 430 431 432 433 434 435 436
	/* XXX: "cbr" setting has been deprecated */
	if (cbr_override) {
		warn("\"cbr\" setting has been deprecated for all encoders!  "
		     "Please set \"rate_control\" to \"CBR\" instead.  "
		     "Forcing CBR mode.  "
		     "(Note to all: this is why you shouldn't use strings for "
		     "common settings)");
		rate_control = "CBR";
	}

437
	if (astrcmpi(rate_control, "ABR") == 0) {
438 439 440 441 442 443 444 445 446 447
		rc = RATE_CONTROL_ABR;
		crf = 0;

	} else if (astrcmpi(rate_control, "VBR") == 0) {
		rc = RATE_CONTROL_VBR;

	} else if (astrcmpi(rate_control, "CRF") == 0) {
		rc = RATE_CONTROL_CRF;
		bitrate = 0;
		buffer_size = 0;
448 449 450 451

	} else { /* CBR */
		rc = RATE_CONTROL_CBR;
		crf = 0;
452
	}
453 454 455 456 457

	if (keyint_sec)
		obsx264->params.i_keyint_max =
			keyint_sec * voi->fps_num / voi->fps_den;

J
jp9000 已提交
458 459 460
	if (!use_bufsize)
		buffer_size = bitrate;

461
#ifdef ENABLE_VFR
462
	obsx264->params.b_vfr_input          = vfr;
463 464 465
#else
	obsx264->params.b_vfr_input          = false;
#endif
466 467 468
	obsx264->params.rc.i_vbv_max_bitrate = bitrate;
	obsx264->params.rc.i_vbv_buffer_size = buffer_size;
	obsx264->params.rc.i_bitrate         = bitrate;
469 470
	obsx264->params.i_width              = width;
	obsx264->params.i_height             = height;
471 472 473
	obsx264->params.i_fps_num            = voi->fps_num;
	obsx264->params.i_fps_den            = voi->fps_den;
	obsx264->params.pf_log               = log_x264;
474
	obsx264->params.p_log_private        = obsx264;
475 476
	obsx264->params.i_log_level          = X264_LOG_WARNING;

477 478 479
	if (obs_data_has_user_value(settings, "bf"))
		obsx264->params.i_bframe = bf;

480
	obsx264->params.vui.i_transfer =
481
		get_x264_cs_val(info.colorspace, x264_transfer_names);
482
	obsx264->params.vui.i_colmatrix =
483
		get_x264_cs_val(info.colorspace, x264_colmatrix_names);
484
	obsx264->params.vui.i_colorprim =
485
		get_x264_cs_val(info.colorspace, x264_colorprim_names);
486
	obsx264->params.vui.b_fullrange =
487
		info.range == VIDEO_RANGE_FULL;
488

489 490
	/* use the new filler method for CBR to allow real-time adjusting of
	 * the bitrate */
491
	if (rc == RATE_CONTROL_CBR || rc == RATE_CONTROL_ABR) {
J
jp9000 已提交
492
		obsx264->params.rc.i_rc_method   = X264_RC_ABR;
493

494
		if (rc == RATE_CONTROL_CBR) {
495
#if X264_BUILD >= 139
496
			obsx264->params.rc.b_filler = true;
497
#else
498
			obsx264->params.i_nal_hrd = X264_NAL_HRD_CBR;
499
#endif
500
		}
501 502 503 504
	} else {
		obsx264->params.rc.i_rc_method   = X264_RC_CRF;
	}

505 506
	obsx264->params.rc.f_rf_constant = (float)crf;

507
	if (info.format == VIDEO_FORMAT_NV12)
508
		obsx264->params.i_csp = X264_CSP_NV12;
509
	else if (info.format == VIDEO_FORMAT_I420)
510
		obsx264->params.i_csp = X264_CSP_I420;
511
	else if (info.format == VIDEO_FORMAT_I444)
512
		obsx264->params.i_csp = X264_CSP_I444;
513 514 515 516 517
	else
		obsx264->params.i_csp = X264_CSP_NV12;

	while (*params)
		set_param(obsx264, *(params++));
518 519

	info("settings:\n"
520 521 522 523 524 525 526 527
	     "\trate_control: %s\n"
	     "\tbitrate:      %d\n"
	     "\tbuffer size:  %d\n"
	     "\tcrf:          %d\n"
	     "\tfps_num:      %d\n"
	     "\tfps_den:      %d\n"
	     "\twidth:        %d\n"
	     "\theight:       %d\n"
528
	     "\tkeyint:       %d\n",
529
	     rate_control,
530 531
	     obsx264->params.rc.i_vbv_max_bitrate,
	     obsx264->params.rc.i_vbv_buffer_size,
J
jp9000 已提交
532
	     (int)obsx264->params.rc.f_rf_constant,
533 534
	     voi->fps_num, voi->fps_den,
	     width, height,
535
	     obsx264->params.i_keyint_max);
536 537
}

538
static bool update_settings(struct obs_x264 *obsx264, obs_data_t *settings)
539
{
J
jp9000 已提交
540 541 542 543
	char *preset     = bstrdup(obs_data_get_string(settings, "preset"));
	char *profile    = bstrdup(obs_data_get_string(settings, "profile"));
	char *tune       = bstrdup(obs_data_get_string(settings, "tune"));
	const char *opts = obs_data_get_string(settings, "x264opts");
544 545 546 547

	char **paramlist;
	bool success = true;

J
jp9000 已提交
548
	paramlist = strlist_split(opts, ' ', false);
549

J
jp9000 已提交
550 551
	blog(LOG_INFO, "---------------------------------");

552
	if (!obsx264->context) {
J
jp9000 已提交
553
		override_base_params(obsx264, paramlist,
554
				&preset, &profile, &tune);
555 556 557 558 559

		if (preset  && *preset)  info("preset: %s",  preset);
		if (profile && *profile) info("profile: %s", profile);
		if (tune    && *tune)    info("tune: %s",    tune);

560 561 562 563 564
		success = reset_x264_params(obsx264, preset, tune);
	}

	if (success) {
		update_params(obsx264, settings, paramlist);
565 566
		if (opts && *opts)
			info("custom settings: %s", opts);
567 568 569 570 571

		if (!obsx264->context)
			apply_x264_profile(obsx264, profile);
	}

572 573
	obsx264->params.b_repeat_headers = false;

574 575 576 577 578 579 580 581
	strlist_free(paramlist);
	bfree(preset);
	bfree(profile);
	bfree(tune);

	return success;
}

582
static bool obs_x264_update(void *data, obs_data_t *settings)
583 584 585 586 587 588 589 590
{
	struct obs_x264 *obsx264 = data;
	bool success = update_settings(obsx264, settings);
	int ret;

	if (success) {
		ret = x264_encoder_reconfig(obsx264->context, &obsx264->params);
		if (ret != 0)
J
jp9000 已提交
591
			warn("Failed to reconfigure: %d", ret);
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
		return ret == 0;
	}

	return false;
}

static void load_headers(struct obs_x264 *obsx264)
{
	x264_nal_t      *nals;
	int             nal_count;
	DARRAY(uint8_t) header;
	DARRAY(uint8_t) sei;

	da_init(header);
	da_init(sei);

	x264_encoder_headers(obsx264->context, &nals, &nal_count);

	for (int i = 0; i < nal_count; i++) {
		x264_nal_t *nal = nals+i;

		if (nal->i_type == NAL_SEI)
			da_push_back_array(sei, nal->p_payload, nal->i_payload);
		else
			da_push_back_array(header, nal->p_payload,
					nal->i_payload);
	}

	obsx264->extra_data      = header.array;
	obsx264->extra_data_size = header.num;
	obsx264->sei             = sei.array;
	obsx264->sei_size        = sei.num;
}

626
static void *obs_x264_create(obs_data_t *settings, obs_encoder_t *encoder)
627
{
628 629
	struct obs_x264 *obsx264 = bzalloc(sizeof(struct obs_x264));
	obsx264->encoder = encoder;
630 631 632 633 634

	if (update_settings(obsx264, settings)) {
		obsx264->context = x264_encoder_open(&obsx264->params);

		if (obsx264->context == NULL)
J
jp9000 已提交
635
			warn("x264 failed to load");
636 637 638
		else
			load_headers(obsx264);
	} else {
J
jp9000 已提交
639
		warn("bad settings specified");
640 641
	}

642 643 644 645
	if (!obsx264->context) {
		bfree(obsx264);
		return NULL;
	}
J
jp9000 已提交
646

647 648 649
	obsx264->performance_token =
		os_request_high_performance("x264 encoding");

650
	return obsx264;
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
}

static void parse_packet(struct obs_x264 *obsx264,
		struct encoder_packet *packet, x264_nal_t *nals,
		int nal_count, x264_picture_t *pic_out)
{
	if (!nal_count) return;

	da_resize(obsx264->packet_data, 0);

	for (int i = 0; i < nal_count; i++) {
		x264_nal_t *nal = nals+i;
		da_push_back_array(obsx264->packet_data, nal->p_payload,
				nal->i_payload);
	}

	packet->data          = obsx264->packet_data.array;
	packet->size          = obsx264->packet_data.num;
	packet->type          = OBS_ENCODER_VIDEO;
	packet->pts           = pic_out->i_pts;
	packet->dts           = pic_out->i_dts;
672
	packet->keyframe      = pic_out->b_keyframe != 0;
673 674 675 676 677 678 679 680 681 682 683 684 685 686
}

static inline void init_pic_data(struct obs_x264 *obsx264, x264_picture_t *pic,
		struct encoder_frame *frame)
{
	x264_picture_init(pic);

	pic->i_pts = frame->pts;
	pic->img.i_csp = obsx264->params.i_csp;

	if (obsx264->params.i_csp == X264_CSP_NV12)
		pic->img.i_plane = 2;
	else if (obsx264->params.i_csp == X264_CSP_I420)
		pic->img.i_plane = 3;
687 688
	else if (obsx264->params.i_csp == X264_CSP_I444)
		pic->img.i_plane = 3;
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707

	for (int i = 0; i < pic->img.i_plane; i++) {
		pic->img.i_stride[i] = (int)frame->linesize[i];
		pic->img.plane[i]    = frame->data[i];
	}
}

static bool obs_x264_encode(void *data, struct encoder_frame *frame,
		struct encoder_packet *packet, bool *received_packet)
{
	struct obs_x264 *obsx264 = data;
	x264_nal_t      *nals;
	int             nal_count;
	int             ret;
	x264_picture_t  pic, pic_out;

	if (!frame || !packet || !received_packet)
		return false;

J
jp9000 已提交
708 709
	if (frame)
		init_pic_data(obsx264, &pic, frame);
710

J
jp9000 已提交
711 712
	ret = x264_encoder_encode(obsx264->context, &nals, &nal_count,
			(frame ? &pic : NULL), &pic_out);
713
	if (ret < 0) {
J
jp9000 已提交
714
		warn("encode failed");
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
		return false;
	}

	*received_packet = (nal_count != 0);
	parse_packet(obsx264, packet, nals, nal_count, &pic_out);

	return true;
}

static bool obs_x264_extra_data(void *data, uint8_t **extra_data, size_t *size)
{
	struct obs_x264 *obsx264 = data;

	if (!obsx264->context)
		return false;

	*extra_data = obsx264->extra_data;
	*size       = obsx264->extra_data_size;
	return true;
}

static bool obs_x264_sei(void *data, uint8_t **sei, size_t *size)
{
	struct obs_x264 *obsx264 = data;

	if (!obsx264->context)
		return false;

	*sei  = obsx264->sei;
	*size = obsx264->sei_size;
	return true;
}

748 749 750
static inline bool valid_format(enum video_format format)
{
	return format == VIDEO_FORMAT_I420 ||
751 752
	       format == VIDEO_FORMAT_NV12 ||
	       format == VIDEO_FORMAT_I444;
753 754 755
}

static void obs_x264_video_info(void *data, struct video_scale_info *info)
756 757
{
	struct obs_x264 *obsx264 = data;
758
	enum video_format pref_format;
759

760
	pref_format = obs_encoder_get_preferred_video_format(obsx264->encoder);
761

762 763 764 765
	if (!valid_format(pref_format)) {
		pref_format = valid_format(info->format) ?
			info->format : VIDEO_FORMAT_NV12;
	}
766

767
	info->format = pref_format;
768 769 770
}

struct obs_encoder_info obs_x264_encoder = {
771 772 773 774 775 776 777 778 779 780 781 782 783
	.id             = "obs_x264",
	.type           = OBS_ENCODER_VIDEO,
	.codec          = "h264",
	.get_name       = obs_x264_getname,
	.create         = obs_x264_create,
	.destroy        = obs_x264_destroy,
	.encode         = obs_x264_encode,
	.update         = obs_x264_update,
	.get_properties = obs_x264_props,
	.get_defaults   = obs_x264_defaults,
	.get_extra_data = obs_x264_extra_data,
	.get_sei_data   = obs_x264_sei,
	.get_video_info = obs_x264_video_info
784
};