|
|
@@ -115,6 +115,12 @@ static const char *obs_qsv_getname(void *type_data)
|
|
|
return "QuickSync H.264";
|
|
|
}
|
|
|
|
|
|
+static const char *obs_qsv_getname_av1(void *type_data)
|
|
|
+{
|
|
|
+ UNUSED_PARAMETER(type_data);
|
|
|
+ return "QuickSync AV1";
|
|
|
+}
|
|
|
+
|
|
|
static void obs_qsv_stop(void *data);
|
|
|
|
|
|
static void clear_data(struct obs_qsv *obsqsv)
|
|
|
@@ -145,7 +151,7 @@ static void obs_qsv_destroy(void *data)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void obs_qsv_defaults_h264(obs_data_t *settings)
|
|
|
+static void obs_qsv_defaults(obs_data_t *settings, int ver)
|
|
|
{
|
|
|
obs_data_set_default_string(settings, "target_usage", "balanced");
|
|
|
obs_data_set_default_int(settings, "bitrate", 2500);
|
|
|
@@ -153,8 +159,11 @@ static void obs_qsv_defaults_h264(obs_data_t *settings)
|
|
|
obs_data_set_default_string(settings, "profile", "high");
|
|
|
obs_data_set_default_string(settings, "rate_control", "CBR");
|
|
|
|
|
|
+ obs_data_set_default_int(settings, "__ver", ver);
|
|
|
+
|
|
|
obs_data_set_default_int(settings, "accuracy", 1000);
|
|
|
obs_data_set_default_int(settings, "convergence", 1);
|
|
|
+ obs_data_set_default_int(settings, "cqp", 23);
|
|
|
obs_data_set_default_int(settings, "qpi", 23);
|
|
|
obs_data_set_default_int(settings, "qpp", 23);
|
|
|
obs_data_set_default_int(settings, "qpb", 23);
|
|
|
@@ -166,6 +175,16 @@ static void obs_qsv_defaults_h264(obs_data_t *settings)
|
|
|
obs_data_set_default_bool(settings, "enhancements", false);
|
|
|
}
|
|
|
|
|
|
+static void obs_qsv_defaults_v1(obs_data_t *settings)
|
|
|
+{
|
|
|
+ obs_qsv_defaults(settings, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static void obs_qsv_defaults_v2(obs_data_t *settings)
|
|
|
+{
|
|
|
+ obs_qsv_defaults(settings, 2);
|
|
|
+}
|
|
|
+
|
|
|
static inline void add_strings(obs_property_t *list, const char *const *strings)
|
|
|
{
|
|
|
while (*strings) {
|
|
|
@@ -289,11 +308,17 @@ static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p,
|
|
|
|
|
|
bVisible = astrcmpi(rate_control, "CQP") == 0;
|
|
|
p = obs_properties_get(ppts, "qpi");
|
|
|
- obs_property_set_visible(p, bVisible);
|
|
|
+ if (p)
|
|
|
+ obs_property_set_visible(p, bVisible);
|
|
|
p = obs_properties_get(ppts, "qpb");
|
|
|
- obs_property_set_visible(p, bVisible);
|
|
|
+ if (p)
|
|
|
+ obs_property_set_visible(p, bVisible);
|
|
|
p = obs_properties_get(ppts, "qpp");
|
|
|
- obs_property_set_visible(p, bVisible);
|
|
|
+ if (p)
|
|
|
+ obs_property_set_visible(p, bVisible);
|
|
|
+ p = obs_properties_get(ppts, "cqp");
|
|
|
+ if (p)
|
|
|
+ obs_property_set_visible(p, bVisible);
|
|
|
|
|
|
bVisible = astrcmpi(rate_control, "ICQ") == 0 ||
|
|
|
astrcmpi(rate_control, "LA_ICQ") == 0;
|
|
|
@@ -337,13 +362,44 @@ static inline void add_rate_controls(obs_property_t *list,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static obs_properties_t *obs_qsv_props(enum qsv_codec codec, void *unused)
|
|
|
+static obs_properties_t *obs_qsv_props(enum qsv_codec codec, void *unused,
|
|
|
+ int ver)
|
|
|
{
|
|
|
UNUSED_PARAMETER(unused);
|
|
|
|
|
|
obs_properties_t *props = obs_properties_create();
|
|
|
obs_property_t *prop;
|
|
|
|
|
|
+ prop = obs_properties_add_list(props, "rate_control", TEXT_RATE_CONTROL,
|
|
|
+ OBS_COMBO_TYPE_LIST,
|
|
|
+ OBS_COMBO_FORMAT_STRING);
|
|
|
+ if (codec == QSV_CODEC_AVC)
|
|
|
+ add_rate_controls(prop, qsv_ratecontrols);
|
|
|
+ else if (codec == QSV_CODEC_AV1)
|
|
|
+ add_rate_controls(prop, qsv_av1_ratecontrols);
|
|
|
+
|
|
|
+ obs_property_set_modified_callback(prop, rate_control_modified);
|
|
|
+
|
|
|
+ prop = obs_properties_add_int(props, "bitrate", TEXT_TARGET_BITRATE, 50,
|
|
|
+ 10000000, 50);
|
|
|
+ obs_property_int_set_suffix(prop, " Kbps");
|
|
|
+
|
|
|
+ prop = obs_properties_add_int(props, "max_bitrate", TEXT_MAX_BITRATE,
|
|
|
+ 50, 10000000, 50);
|
|
|
+ obs_property_int_set_suffix(prop, " Kbps");
|
|
|
+
|
|
|
+ if (ver >= 2) {
|
|
|
+ obs_properties_add_int(props, "cqp", "CQP", 1,
|
|
|
+ codec == QSV_CODEC_AV1 ? 63 : 51, 1);
|
|
|
+ } else {
|
|
|
+ obs_properties_add_int(props, "qpi", "QPI", 1, 51, 1);
|
|
|
+ obs_properties_add_int(props, "qpp", "QPP", 1, 51, 1);
|
|
|
+ obs_properties_add_int(props, "qpb", "QPB", 1, 51, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ obs_properties_add_int(props, "icq_quality", TEXT_ICQ_QUALITY, 1, 51,
|
|
|
+ 1);
|
|
|
+
|
|
|
prop = obs_properties_add_list(props, "target_usage", TEXT_SPEED,
|
|
|
OBS_COMBO_TYPE_LIST,
|
|
|
OBS_COMBO_FORMAT_STRING);
|
|
|
@@ -355,6 +411,8 @@ static obs_properties_t *obs_qsv_props(enum qsv_codec codec, void *unused)
|
|
|
|
|
|
if (codec == QSV_CODEC_AVC)
|
|
|
add_strings(prop, qsv_profile_names);
|
|
|
+ else if (codec == QSV_CODEC_AV1)
|
|
|
+ add_strings(prop, qsv_profile_names_av1);
|
|
|
|
|
|
obs_property_set_modified_callback(prop, profile_modified);
|
|
|
|
|
|
@@ -362,52 +420,35 @@ static obs_properties_t *obs_qsv_props(enum qsv_codec codec, void *unused)
|
|
|
20, 1);
|
|
|
obs_property_int_set_suffix(prop, " s");
|
|
|
|
|
|
- prop = obs_properties_add_list(props, "rate_control", TEXT_RATE_CONTROL,
|
|
|
+ obs_properties_add_int(props, "accuracy", TEXT_ACCURACY, 0, 10000, 1);
|
|
|
+ obs_properties_add_int(props, "convergence", TEXT_CONVERGENCE, 0, 10,
|
|
|
+ 1);
|
|
|
+ prop = obs_properties_add_list(props, "latency", TEXT_LATENCY,
|
|
|
OBS_COMBO_TYPE_LIST,
|
|
|
OBS_COMBO_FORMAT_STRING);
|
|
|
- if (codec == QSV_CODEC_AVC)
|
|
|
- add_rate_controls(prop, qsv_ratecontrols);
|
|
|
-
|
|
|
- obs_property_set_modified_callback(prop, rate_control_modified);
|
|
|
-
|
|
|
- prop = obs_properties_add_int(props, "bitrate", TEXT_TARGET_BITRATE, 50,
|
|
|
- 10000000, 50);
|
|
|
- obs_property_int_set_suffix(prop, " Kbps");
|
|
|
-
|
|
|
- prop = obs_properties_add_int(props, "max_bitrate", TEXT_MAX_BITRATE,
|
|
|
- 50, 10000000, 50);
|
|
|
- obs_property_int_set_suffix(prop, " Kbps");
|
|
|
-
|
|
|
- if (codec == QSV_CODEC_AVC) {
|
|
|
- obs_properties_add_int(props, "accuracy", TEXT_ACCURACY, 0,
|
|
|
- 10000, 1);
|
|
|
- obs_properties_add_int(props, "convergence", TEXT_CONVERGENCE,
|
|
|
- 0, 10, 1);
|
|
|
- obs_properties_add_int(props, "qpi", "QPI", 1, 51, 1);
|
|
|
- obs_properties_add_int(props, "qpp", "QPP", 1, 51, 1);
|
|
|
- obs_properties_add_int(props, "qpb", "QPB", 1, 51, 1);
|
|
|
- obs_properties_add_int(props, "icq_quality", TEXT_ICQ_QUALITY,
|
|
|
- 1, 51, 1);
|
|
|
- prop = obs_properties_add_list(props, "latency", TEXT_LATENCY,
|
|
|
- OBS_COMBO_TYPE_LIST,
|
|
|
- OBS_COMBO_FORMAT_STRING);
|
|
|
- add_strings(prop, qsv_latency_names);
|
|
|
- obs_property_set_long_description(
|
|
|
- prop, obs_module_text("Latency.ToolTip"));
|
|
|
+ add_strings(prop, qsv_latency_names);
|
|
|
+ obs_property_set_long_description(prop,
|
|
|
+ obs_module_text("Latency.ToolTip"));
|
|
|
|
|
|
+ if (codec != QSV_CODEC_AV1)
|
|
|
obs_properties_add_int(props, "bframes", TEXT_BFRAMES, 0, 3, 1);
|
|
|
|
|
|
- if (is_skl_or_greater_platform())
|
|
|
- obs_properties_add_bool(props, "enhancements",
|
|
|
- TEXT_PERCEPTUAL_ENHANCEMENTS);
|
|
|
- }
|
|
|
+ if (is_skl_or_greater_platform())
|
|
|
+ obs_properties_add_bool(props, "enhancements",
|
|
|
+ TEXT_PERCEPTUAL_ENHANCEMENTS);
|
|
|
return props;
|
|
|
}
|
|
|
|
|
|
static obs_properties_t *obs_qsv_props_h264(void *unused)
|
|
|
{
|
|
|
UNUSED_PARAMETER(unused);
|
|
|
- return obs_qsv_props(QSV_CODEC_AVC, unused);
|
|
|
+ return obs_qsv_props(QSV_CODEC_AVC, unused, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static obs_properties_t *obs_qsv_props_av1(void *unused)
|
|
|
+{
|
|
|
+ UNUSED_PARAMETER(unused);
|
|
|
+ return obs_qsv_props(QSV_CODEC_AV1, unused, 2);
|
|
|
}
|
|
|
|
|
|
static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings)
|
|
|
@@ -430,6 +471,8 @@ static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings)
|
|
|
int qpi = (int)obs_data_get_int(settings, "qpi");
|
|
|
int qpp = (int)obs_data_get_int(settings, "qpp");
|
|
|
int qpb = (int)obs_data_get_int(settings, "qpb");
|
|
|
+ int cqp = (int)obs_data_get_int(settings, "cqp");
|
|
|
+ int ver = (int)obs_data_get_int(settings, "__ver");
|
|
|
int icq_quality = (int)obs_data_get_int(settings, "icq_quality");
|
|
|
int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
|
|
|
bool cbr_override = obs_data_get_bool(settings, "cbr");
|
|
|
@@ -440,7 +483,8 @@ static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings)
|
|
|
bFrames = (int)obs_data_get_int(settings, "bf");
|
|
|
|
|
|
enum qsv_cpu_platform plat = qsv_get_cpu_platform();
|
|
|
- if (plat == QSV_CPU_PLATFORM_IVB || plat == QSV_CPU_PLATFORM_SNB)
|
|
|
+ if (obsqsv->codec == QSV_CODEC_AV1 || plat == QSV_CPU_PLATFORM_IVB ||
|
|
|
+ plat == QSV_CPU_PLATFORM_SNB)
|
|
|
bFrames = 0;
|
|
|
|
|
|
int width = (int)obs_encoder_get_width(obsqsv->encoder);
|
|
|
@@ -466,12 +510,81 @@ static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings)
|
|
|
else if (astrcmpi(target_usage, "veryfast") == 0)
|
|
|
obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_7;
|
|
|
|
|
|
- if (astrcmpi(profile, "baseline") == 0)
|
|
|
- obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_BASELINE;
|
|
|
- else if (astrcmpi(profile, "main") == 0)
|
|
|
- obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_MAIN;
|
|
|
- else if (astrcmpi(profile, "high") == 0)
|
|
|
- obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_HIGH;
|
|
|
+ if (obsqsv->codec == QSV_CODEC_AVC) {
|
|
|
+ if (astrcmpi(profile, "baseline") == 0)
|
|
|
+ obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_BASELINE;
|
|
|
+ else if (astrcmpi(profile, "main") == 0)
|
|
|
+ obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_MAIN;
|
|
|
+ else if (astrcmpi(profile, "high") == 0)
|
|
|
+ obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_HIGH;
|
|
|
+
|
|
|
+ } else if (obsqsv->codec == QSV_CODEC_AV1) {
|
|
|
+ obsqsv->params.nCodecProfile = MFX_PROFILE_AV1_MAIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ obsqsv->params.VideoFormat = 5;
|
|
|
+ obsqsv->params.VideoFullRange = voi->range == VIDEO_RANGE_FULL;
|
|
|
+
|
|
|
+ switch (voi->colorspace) {
|
|
|
+ case VIDEO_CS_601:
|
|
|
+ obsqsv->params.ColourPrimaries = 6;
|
|
|
+ obsqsv->params.TransferCharacteristics = 6;
|
|
|
+ obsqsv->params.MatrixCoefficients = 6;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 0;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 0;
|
|
|
+ break;
|
|
|
+ case VIDEO_CS_DEFAULT:
|
|
|
+ case VIDEO_CS_709:
|
|
|
+ obsqsv->params.ColourPrimaries = 1;
|
|
|
+ obsqsv->params.TransferCharacteristics = 1;
|
|
|
+ obsqsv->params.MatrixCoefficients = 1;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 0;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 0;
|
|
|
+ break;
|
|
|
+ case VIDEO_CS_SRGB:
|
|
|
+ obsqsv->params.ColourPrimaries = 1;
|
|
|
+ obsqsv->params.TransferCharacteristics = 13;
|
|
|
+ obsqsv->params.MatrixCoefficients = 1;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 0;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 0;
|
|
|
+ break;
|
|
|
+ case VIDEO_CS_2100_PQ:
|
|
|
+ obsqsv->params.ColourPrimaries = 9;
|
|
|
+ obsqsv->params.TransferCharacteristics = 16;
|
|
|
+ obsqsv->params.MatrixCoefficients = 9;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 2;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 2;
|
|
|
+ break;
|
|
|
+ case VIDEO_CS_2100_HLG:
|
|
|
+ obsqsv->params.ColourPrimaries = 9;
|
|
|
+ obsqsv->params.TransferCharacteristics = 18;
|
|
|
+ obsqsv->params.MatrixCoefficients = 9;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 2;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ const bool pq = voi->colorspace == VIDEO_CS_2100_PQ;
|
|
|
+ const bool hlg = voi->colorspace == VIDEO_CS_2100_HLG;
|
|
|
+ if (pq || hlg) {
|
|
|
+ const int hdr_nominal_peak_level =
|
|
|
+ pq ? (int)obs_get_video_hdr_nominal_peak_level()
|
|
|
+ : (hlg ? 1000 : 0);
|
|
|
+
|
|
|
+ obsqsv->params.DisplayPrimariesX[0] = 34000;
|
|
|
+ obsqsv->params.DisplayPrimariesX[1] = 13250;
|
|
|
+ obsqsv->params.DisplayPrimariesX[2] = 7500;
|
|
|
+ obsqsv->params.DisplayPrimariesY[0] = 16000;
|
|
|
+ obsqsv->params.DisplayPrimariesY[1] = 34500;
|
|
|
+ obsqsv->params.DisplayPrimariesY[2] = 3000;
|
|
|
+ obsqsv->params.WhitePointX = 15635;
|
|
|
+ obsqsv->params.WhitePointY = 16450;
|
|
|
+ obsqsv->params.MaxDisplayMasteringLuminance =
|
|
|
+ hdr_nominal_peak_level * 10000;
|
|
|
+ obsqsv->params.MinDisplayMasteringLuminance = 0;
|
|
|
+
|
|
|
+ obsqsv->params.MaxContentLightLevel = hdr_nominal_peak_level;
|
|
|
+ obsqsv->params.MaxPicAverageLightLevel = hdr_nominal_peak_level;
|
|
|
+ }
|
|
|
|
|
|
/* internal convenience parameter, overrides rate control param
|
|
|
* XXX: Deprecated */
|
|
|
@@ -503,16 +616,22 @@ static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings)
|
|
|
else if (astrcmpi(rate_control, "LA_CBR") == 0)
|
|
|
obsqsv->params.nRateControl = MFX_RATECONTROL_LA_HRD;
|
|
|
|
|
|
- if (astrcmpi(latency, "ultra-low") == 0) {
|
|
|
- obsqsv->params.nAsyncDepth = 1;
|
|
|
- obsqsv->params.nLADEPTH = (mfxU16)0;
|
|
|
- } else if (astrcmpi(latency, "low") == 0) {
|
|
|
+ if (obsqsv->codec == QSV_CODEC_AV1) {
|
|
|
obsqsv->params.nAsyncDepth = 4;
|
|
|
- obsqsv->params.nLADEPTH =
|
|
|
- (mfxU16)(voi->fps_num / voi->fps_den / 2);
|
|
|
- } else if (astrcmpi(latency, "normal") == 0) {
|
|
|
- obsqsv->params.nAsyncDepth = 4;
|
|
|
- obsqsv->params.nLADEPTH = (mfxU16)(voi->fps_num / voi->fps_den);
|
|
|
+ obsqsv->params.nLADEPTH = 0;
|
|
|
+ } else {
|
|
|
+ if (astrcmpi(latency, "ultra-low") == 0) {
|
|
|
+ obsqsv->params.nAsyncDepth = 1;
|
|
|
+ obsqsv->params.nLADEPTH = (mfxU16)0;
|
|
|
+ } else if (astrcmpi(latency, "low") == 0) {
|
|
|
+ obsqsv->params.nAsyncDepth = 4;
|
|
|
+ obsqsv->params.nLADEPTH =
|
|
|
+ (mfxU16)(voi->fps_num / voi->fps_den / 2);
|
|
|
+ } else if (astrcmpi(latency, "normal") == 0) {
|
|
|
+ obsqsv->params.nAsyncDepth = 4;
|
|
|
+ obsqsv->params.nLADEPTH =
|
|
|
+ (mfxU16)(voi->fps_num / voi->fps_den);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (obsqsv->params.nLADEPTH > 0) {
|
|
|
@@ -524,9 +643,18 @@ static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings)
|
|
|
|
|
|
obsqsv->params.nAccuracy = (mfxU16)accuracy;
|
|
|
obsqsv->params.nConvergence = (mfxU16)convergence;
|
|
|
- obsqsv->params.nQPI = (mfxU16)qpi;
|
|
|
- obsqsv->params.nQPP = (mfxU16)qpp;
|
|
|
- obsqsv->params.nQPB = (mfxU16)qpb;
|
|
|
+ if (ver == 1) {
|
|
|
+ obsqsv->params.nQPI = (mfxU16)qpi;
|
|
|
+ obsqsv->params.nQPP = (mfxU16)qpp;
|
|
|
+ obsqsv->params.nQPB = (mfxU16)qpb;
|
|
|
+ } else {
|
|
|
+ int actual_cqp = cqp;
|
|
|
+ if (obsqsv->codec == QSV_CODEC_AV1)
|
|
|
+ actual_cqp *= 4;
|
|
|
+ obsqsv->params.nQPI = actual_cqp;
|
|
|
+ obsqsv->params.nQPP = actual_cqp;
|
|
|
+ obsqsv->params.nQPB = actual_cqp;
|
|
|
+ }
|
|
|
obsqsv->params.nTargetBitRate = (mfxU16)target_bitrate;
|
|
|
obsqsv->params.nMaxBitRate = (mfxU16)max_bitrate;
|
|
|
obsqsv->params.nWidth = (mfxU16)width;
|
|
|
@@ -580,6 +708,118 @@ static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings)
|
|
|
info("debug info:");
|
|
|
}
|
|
|
|
|
|
+static void update_params_av1(struct obs_qsv *obsqsv, obs_data_t *settings)
|
|
|
+{
|
|
|
+ video_t *video = obs_encoder_video(obsqsv->encoder);
|
|
|
+ const struct video_output_info *voi = video_output_get_info(video);
|
|
|
+
|
|
|
+ const char *target_usage =
|
|
|
+ obs_data_get_string(settings, "target_usage");
|
|
|
+ const char *profile = obs_data_get_string(settings, "profile");
|
|
|
+ const char *rate_control =
|
|
|
+ obs_data_get_string(settings, "rate_control");
|
|
|
+ int target_bitrate = (int)obs_data_get_int(settings, "bitrate");
|
|
|
+ int max_bitrate = (int)obs_data_get_int(settings, "max_bitrate");
|
|
|
+ int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
|
|
|
+
|
|
|
+ int width = (int)obs_encoder_get_width(obsqsv->encoder);
|
|
|
+ int height = (int)obs_encoder_get_height(obsqsv->encoder);
|
|
|
+ if (astrcmpi(target_usage, "quality") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_BEST_QUALITY;
|
|
|
+ else if (astrcmpi(target_usage, "balanced") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_BALANCED;
|
|
|
+ else if (astrcmpi(target_usage, "speed") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_BEST_SPEED;
|
|
|
+ else if (astrcmpi(target_usage, "veryslow") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_1;
|
|
|
+ else if (astrcmpi(target_usage, "slower") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_2;
|
|
|
+ else if (astrcmpi(target_usage, "slow") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_3;
|
|
|
+ else if (astrcmpi(target_usage, "medium") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_4;
|
|
|
+ else if (astrcmpi(target_usage, "fast") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_5;
|
|
|
+ else if (astrcmpi(target_usage, "faster") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_6;
|
|
|
+ else if (astrcmpi(target_usage, "veryfast") == 0)
|
|
|
+ obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_7;
|
|
|
+
|
|
|
+ if (astrcmpi(profile, "main") == 0)
|
|
|
+ obsqsv->params.nCodecProfile = MFX_PROFILE_AV1_MAIN;
|
|
|
+
|
|
|
+ if (astrcmpi(rate_control, "CBR") == 0)
|
|
|
+ obsqsv->params.nRateControl = MFX_RATECONTROL_CBR;
|
|
|
+ else if (astrcmpi(rate_control, "VBR") == 0)
|
|
|
+ obsqsv->params.nRateControl = MFX_RATECONTROL_VBR;
|
|
|
+
|
|
|
+ obsqsv->params.nAsyncDepth = 4;
|
|
|
+
|
|
|
+ obsqsv->params.nTargetBitRate = (mfxU16)target_bitrate;
|
|
|
+ obsqsv->params.nMaxBitRate = (mfxU16)max_bitrate;
|
|
|
+ obsqsv->params.nWidth = (mfxU16)width;
|
|
|
+ obsqsv->params.nHeight = (mfxU16)height;
|
|
|
+ obsqsv->params.nFpsNum = (mfxU16)voi->fps_num;
|
|
|
+ obsqsv->params.nFpsDen = (mfxU16)voi->fps_den;
|
|
|
+ obsqsv->params.nKeyIntSec = (mfxU16)keyint_sec;
|
|
|
+
|
|
|
+ obsqsv->params.VideoFormat = 5;
|
|
|
+ obsqsv->params.VideoFullRange = voi->range == VIDEO_RANGE_FULL;
|
|
|
+
|
|
|
+ switch (voi->colorspace) {
|
|
|
+ case VIDEO_CS_601:
|
|
|
+ obsqsv->params.ColourPrimaries = 6;
|
|
|
+ obsqsv->params.TransferCharacteristics = 6;
|
|
|
+ obsqsv->params.MatrixCoefficients = 6;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 0;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 0;
|
|
|
+ break;
|
|
|
+ case VIDEO_CS_DEFAULT:
|
|
|
+ case VIDEO_CS_709:
|
|
|
+ obsqsv->params.ColourPrimaries = 1;
|
|
|
+ obsqsv->params.TransferCharacteristics = 1;
|
|
|
+ obsqsv->params.MatrixCoefficients = 1;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 0;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 0;
|
|
|
+ break;
|
|
|
+ case VIDEO_CS_SRGB:
|
|
|
+ obsqsv->params.ColourPrimaries = 1;
|
|
|
+ obsqsv->params.TransferCharacteristics = 13;
|
|
|
+ obsqsv->params.MatrixCoefficients = 1;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 0;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 0;
|
|
|
+ break;
|
|
|
+ case VIDEO_CS_2100_PQ:
|
|
|
+ obsqsv->params.ColourPrimaries = 9;
|
|
|
+ obsqsv->params.TransferCharacteristics = 16;
|
|
|
+ obsqsv->params.MatrixCoefficients = 9;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 2;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 2;
|
|
|
+ break;
|
|
|
+ case VIDEO_CS_2100_HLG:
|
|
|
+ obsqsv->params.ColourPrimaries = 9;
|
|
|
+ obsqsv->params.TransferCharacteristics = 18;
|
|
|
+ obsqsv->params.MatrixCoefficients = 9;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeTopField = 2;
|
|
|
+ obsqsv->params.ChromaSampleLocTypeBottomField = 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ info("settings:\n\trate_control: %s", rate_control);
|
|
|
+
|
|
|
+ if (obsqsv->params.nRateControl == MFX_RATECONTROL_VBR)
|
|
|
+ blog(LOG_INFO, "\tmax_bitrate: %d",
|
|
|
+ (int)obsqsv->params.nMaxBitRate);
|
|
|
+
|
|
|
+ blog(LOG_INFO,
|
|
|
+ "\tfps_num: %d\n"
|
|
|
+ "\tfps_den: %d\n"
|
|
|
+ "\twidth: %d\n"
|
|
|
+ "\theight: %d",
|
|
|
+ voi->fps_num, voi->fps_den, width, height);
|
|
|
+
|
|
|
+ info("debug info:");
|
|
|
+}
|
|
|
+
|
|
|
static bool update_settings(struct obs_qsv *obsqsv, obs_data_t *settings)
|
|
|
{
|
|
|
update_params(obsqsv, settings);
|
|
|
@@ -601,9 +841,13 @@ static void load_headers(struct obs_qsv *obsqsv)
|
|
|
|
|
|
uint8_t *pSPS, *pPPS;
|
|
|
uint16_t nSPS, nPPS;
|
|
|
+
|
|
|
qsv_encoder_headers(obsqsv->context, &pSPS, &pPPS, &nSPS, &nPPS);
|
|
|
da_push_back_array(header, pSPS, nSPS);
|
|
|
- da_push_back_array(header, pPPS, nPPS);
|
|
|
+
|
|
|
+ // AV1 does not need PPS
|
|
|
+ if (obsqsv->codec != QSV_CODEC_AV1)
|
|
|
+ da_push_back_array(header, pPPS, nPPS);
|
|
|
|
|
|
obsqsv->extra_data = header.array;
|
|
|
obsqsv->extra_data_size = header.num;
|
|
|
@@ -645,6 +889,7 @@ static void *obs_qsv_create(enum qsv_codec codec, obs_data_t *settings,
|
|
|
bfree(obsqsv);
|
|
|
return NULL;
|
|
|
}
|
|
|
+ obsqsv->params.video_fmt_10bit = true;
|
|
|
break;
|
|
|
default:
|
|
|
switch (voi->colorspace) {
|
|
|
@@ -715,6 +960,11 @@ static void *obs_qsv_create_h264(obs_data_t *settings, obs_encoder_t *encoder)
|
|
|
return obs_qsv_create(QSV_CODEC_AVC, settings, encoder);
|
|
|
}
|
|
|
|
|
|
+static void *obs_qsv_create_av1(obs_data_t *settings, obs_encoder_t *encoder)
|
|
|
+{
|
|
|
+ return obs_qsv_create(QSV_CODEC_AV1, settings, encoder);
|
|
|
+}
|
|
|
+
|
|
|
static HANDLE get_lib(const char *lib)
|
|
|
{
|
|
|
HMODULE mod = GetModuleHandleA(lib);
|
|
|
@@ -729,30 +979,38 @@ static HANDLE get_lib(const char *lib)
|
|
|
|
|
|
typedef HRESULT(WINAPI *CREATEDXGIFACTORY1PROC)(REFIID, void **);
|
|
|
|
|
|
-static bool is_intel_gpu_primary(void)
|
|
|
-{
|
|
|
- struct obs_video_info ovi;
|
|
|
- obs_get_video_info(&ovi);
|
|
|
-
|
|
|
- return adapters[ovi.adapter].is_intel;
|
|
|
-}
|
|
|
-
|
|
|
static void *obs_qsv_create_tex(enum qsv_codec codec, obs_data_t *settings,
|
|
|
obs_encoder_t *encoder)
|
|
|
{
|
|
|
char *encoder_id;
|
|
|
if (codec == QSV_CODEC_AVC)
|
|
|
encoder_id = "obs_qsv11_soft";
|
|
|
+ else if (codec == QSV_CODEC_AV1)
|
|
|
+ encoder_id = "obs_qsv11_av1_soft";
|
|
|
|
|
|
- if (!is_intel_gpu_primary()) {
|
|
|
+ struct obs_video_info ovi;
|
|
|
+ obs_get_video_info(&ovi);
|
|
|
+
|
|
|
+ if (!adapters[ovi.adapter].is_intel) {
|
|
|
blog(LOG_INFO,
|
|
|
">>> app not on intel GPU, fall back to old qsv encoder");
|
|
|
return obs_encoder_create_rerouted(encoder,
|
|
|
(const char *)encoder_id);
|
|
|
}
|
|
|
|
|
|
+ if (codec == QSV_CODEC_AV1 && !adapters[ovi.adapter].supports_av1) {
|
|
|
+ blog(LOG_INFO,
|
|
|
+ ">>> cap on different device, fall back to non-texture sharing AV1 qsv encoder");
|
|
|
+ return obs_encoder_create_rerouted(encoder,
|
|
|
+ (const char *)encoder_id);
|
|
|
+ }
|
|
|
+
|
|
|
bool gpu_texture_active = obs_nv12_tex_active();
|
|
|
|
|
|
+ if (codec == QSV_CODEC_AV1)
|
|
|
+ gpu_texture_active = gpu_texture_active ||
|
|
|
+ obs_p010_tex_active();
|
|
|
+
|
|
|
if (!gpu_texture_active) {
|
|
|
blog(LOG_INFO,
|
|
|
">>> gpu tex not active, fall back to old qsv encoder");
|
|
|
@@ -777,6 +1035,12 @@ static void *obs_qsv_create_tex_h264(obs_data_t *settings,
|
|
|
return obs_qsv_create_tex(QSV_CODEC_AVC, settings, encoder);
|
|
|
}
|
|
|
|
|
|
+static void *obs_qsv_create_tex_av1(obs_data_t *settings,
|
|
|
+ obs_encoder_t *encoder)
|
|
|
+{
|
|
|
+ return obs_qsv_create_tex(QSV_CODEC_AV1, settings, encoder);
|
|
|
+}
|
|
|
+
|
|
|
static bool obs_qsv_extra_data(void *data, uint8_t **extra_data, size_t *size)
|
|
|
{
|
|
|
struct obs_qsv *obsqsv = data;
|
|
|
@@ -806,6 +1070,11 @@ static inline bool valid_format(enum video_format format)
|
|
|
return format == VIDEO_FORMAT_NV12;
|
|
|
}
|
|
|
|
|
|
+static inline bool valid_av1_format(enum video_format format)
|
|
|
+{
|
|
|
+ return format == VIDEO_FORMAT_NV12 || format == VIDEO_FORMAT_P010;
|
|
|
+}
|
|
|
+
|
|
|
static inline void cap_resolution(obs_encoder_t *encoder,
|
|
|
struct video_scale_info *info)
|
|
|
{
|
|
|
@@ -844,6 +1113,23 @@ static void obs_qsv_video_info(void *data, struct video_scale_info *info)
|
|
|
cap_resolution(obsqsv->encoder, info);
|
|
|
}
|
|
|
|
|
|
+static void obs_qsv_av1_video_info(void *data, struct video_scale_info *info)
|
|
|
+{
|
|
|
+ struct obs_qsv *obsqsv = data;
|
|
|
+ enum video_format pref_format;
|
|
|
+
|
|
|
+ pref_format = obs_encoder_get_preferred_video_format(obsqsv->encoder);
|
|
|
+
|
|
|
+ if (!valid_av1_format(pref_format)) {
|
|
|
+ pref_format = valid_av1_format(info->format)
|
|
|
+ ? info->format
|
|
|
+ : VIDEO_FORMAT_NV12;
|
|
|
+ }
|
|
|
+
|
|
|
+ info->format = pref_format;
|
|
|
+ cap_resolution(obsqsv->encoder, info);
|
|
|
+}
|
|
|
+
|
|
|
static mfxU64 ts_obs_to_mfx(int64_t ts, const struct video_output_info *voi)
|
|
|
{
|
|
|
return ts * 90000 / voi->fps_num;
|
|
|
@@ -956,6 +1242,57 @@ static void parse_packet(struct obs_qsv *obsqsv, struct encoder_packet *packet,
|
|
|
g_bFirst = false;
|
|
|
}
|
|
|
|
|
|
+static void parse_packet_av1(struct obs_qsv *obsqsv,
|
|
|
+ struct encoder_packet *packet, mfxBitstream *pBS,
|
|
|
+ const struct video_output_info *voi,
|
|
|
+ bool *received_packet)
|
|
|
+{
|
|
|
+ if (pBS == NULL || pBS->DataLength == 0) {
|
|
|
+ *received_packet = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ da_resize(obsqsv->packet_data, 0);
|
|
|
+ da_push_back_array(obsqsv->packet_data, &pBS->Data[pBS->DataOffset],
|
|
|
+ pBS->DataLength);
|
|
|
+
|
|
|
+ packet->data = obsqsv->packet_data.array;
|
|
|
+ packet->size = obsqsv->packet_data.num;
|
|
|
+ packet->type = OBS_ENCODER_VIDEO;
|
|
|
+ packet->pts = ts_mfx_to_obs((mfxI64)pBS->TimeStamp, voi);
|
|
|
+ packet->keyframe = (pBS->FrameType & MFX_FRAMETYPE_IDR);
|
|
|
+
|
|
|
+ uint16_t frameType = pBS->FrameType;
|
|
|
+ uint8_t priority;
|
|
|
+
|
|
|
+ if (frameType & MFX_FRAMETYPE_I)
|
|
|
+ priority = OBS_NAL_PRIORITY_HIGHEST;
|
|
|
+ else if ((frameType & MFX_FRAMETYPE_P) ||
|
|
|
+ (frameType & MFX_FRAMETYPE_REF))
|
|
|
+ priority = OBS_NAL_PRIORITY_HIGH;
|
|
|
+ else
|
|
|
+ priority = OBS_NAL_PRIORITY_DISPOSABLE;
|
|
|
+
|
|
|
+ packet->priority = priority;
|
|
|
+
|
|
|
+ bool pFrame = pBS->FrameType & MFX_FRAMETYPE_P;
|
|
|
+
|
|
|
+ packet->dts = ts_mfx_to_obs(pBS->DecodeTimeStamp, voi);
|
|
|
+
|
|
|
+#if 0
|
|
|
+ info("parse packet:\n"
|
|
|
+ "\tFrameType: %d\n"
|
|
|
+ "\tpts: %d\n"
|
|
|
+ "\tdts: %d",
|
|
|
+ iType, packet->pts, packet->dts);
|
|
|
+#endif
|
|
|
+
|
|
|
+ *received_packet = true;
|
|
|
+ pBS->DataLength = 0;
|
|
|
+
|
|
|
+ g_bFirst = false;
|
|
|
+}
|
|
|
+
|
|
|
static bool obs_qsv_encode(void *data, struct encoder_frame *frame,
|
|
|
struct encoder_packet *packet, bool *received_packet)
|
|
|
{
|
|
|
@@ -994,6 +1331,8 @@ static bool obs_qsv_encode(void *data, struct encoder_frame *frame,
|
|
|
|
|
|
if (obsqsv->codec == QSV_CODEC_AVC)
|
|
|
parse_packet(obsqsv, packet, pBS, voi, received_packet);
|
|
|
+ else if (obsqsv->codec == QSV_CODEC_AV1)
|
|
|
+ parse_packet_av1(obsqsv, packet, pBS, voi, received_packet);
|
|
|
|
|
|
ReleaseSRWLockExclusive(&g_QsvLock);
|
|
|
|
|
|
@@ -1038,6 +1377,8 @@ static bool obs_qsv_encode_tex(void *data, uint32_t handle, int64_t pts,
|
|
|
|
|
|
if (obsqsv->codec == QSV_CODEC_AVC)
|
|
|
parse_packet(obsqsv, packet, pBS, voi, received_packet);
|
|
|
+ else if (obsqsv->codec == QSV_CODEC_AV1)
|
|
|
+ parse_packet_av1(obsqsv, packet, pBS, voi, received_packet);
|
|
|
|
|
|
ReleaseSRWLockExclusive(&g_QsvLock);
|
|
|
|
|
|
@@ -1054,7 +1395,7 @@ struct obs_encoder_info obs_qsv_encoder = {
|
|
|
.encode = obs_qsv_encode,
|
|
|
.update = obs_qsv_update,
|
|
|
.get_properties = obs_qsv_props_h264,
|
|
|
- .get_defaults = obs_qsv_defaults_h264,
|
|
|
+ .get_defaults = obs_qsv_defaults_v1,
|
|
|
.get_extra_data = obs_qsv_extra_data,
|
|
|
.get_sei_data = obs_qsv_sei,
|
|
|
.get_video_info = obs_qsv_video_info,
|
|
|
@@ -1072,8 +1413,40 @@ struct obs_encoder_info obs_qsv_encoder_tex = {
|
|
|
.encode_texture = obs_qsv_encode_tex,
|
|
|
.update = obs_qsv_update,
|
|
|
.get_properties = obs_qsv_props_h264,
|
|
|
- .get_defaults = obs_qsv_defaults_h264,
|
|
|
+ .get_defaults = obs_qsv_defaults_v1,
|
|
|
.get_extra_data = obs_qsv_extra_data,
|
|
|
.get_sei_data = obs_qsv_sei,
|
|
|
.get_video_info = obs_qsv_video_info,
|
|
|
};
|
|
|
+
|
|
|
+struct obs_encoder_info obs_qsv_av1_encoder_tex = {
|
|
|
+ .id = "obs_qsv11_av1",
|
|
|
+ .type = OBS_ENCODER_VIDEO,
|
|
|
+ .codec = "av1",
|
|
|
+ .get_name = obs_qsv_getname_av1,
|
|
|
+ .create = obs_qsv_create_tex_av1,
|
|
|
+ .destroy = obs_qsv_destroy,
|
|
|
+ .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE,
|
|
|
+ .encode_texture = obs_qsv_encode_tex,
|
|
|
+ .update = obs_qsv_update,
|
|
|
+ .get_properties = obs_qsv_props_av1,
|
|
|
+ .get_defaults = obs_qsv_defaults_v2,
|
|
|
+ .get_extra_data = obs_qsv_extra_data,
|
|
|
+ .get_video_info = obs_qsv_av1_video_info,
|
|
|
+};
|
|
|
+
|
|
|
+struct obs_encoder_info obs_qsv_av1_encoder = {
|
|
|
+ .id = "obs_qsv11_av1_soft",
|
|
|
+ .type = OBS_ENCODER_VIDEO,
|
|
|
+ .codec = "av1",
|
|
|
+ .get_name = obs_qsv_getname_av1,
|
|
|
+ .create = obs_qsv_create_av1,
|
|
|
+ .destroy = obs_qsv_destroy,
|
|
|
+ .encode = obs_qsv_encode,
|
|
|
+ .update = obs_qsv_update,
|
|
|
+ .get_properties = obs_qsv_props_av1,
|
|
|
+ .get_defaults = obs_qsv_defaults_v2,
|
|
|
+ .get_extra_data = obs_qsv_extra_data,
|
|
|
+ .get_video_info = obs_qsv_av1_video_info,
|
|
|
+ .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL,
|
|
|
+};
|