}
}
+/* Determines the largest supported profile by the underlying hardware */
+static gboolean
+ensure_hw_profile_limits (GstVaapiEncoderH264 * encoder)
+{
+ GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+ GArray *profiles;
+ guint i, profile_idc, max_profile_idc;
+
+ if (encoder->hw_max_profile_idc)
+ return TRUE;
+
+ profiles = gst_vaapi_display_get_encode_profiles (display);
+ if (!profiles)
+ return FALSE;
+
+ max_profile_idc = 0;
+ for (i = 0; i < profiles->len; i++) {
+ const GstVaapiProfile profile =
+ g_array_index (profiles, GstVaapiProfile, i);
+ profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
+ if (!profile_idc)
+ continue;
+ if (max_profile_idc < profile_idc)
+ max_profile_idc = profile_idc;
+ }
+ g_array_unref (profiles);
+
+ encoder->hw_max_profile_idc = max_profile_idc;
+ return TRUE;
+}
+
/* Derives the profile supported by the underlying hardware */
static gboolean
ensure_hw_profile (GstVaapiEncoderH264 * encoder)
}
}
+/* Check target decoder constraints */
+static gboolean
+ensure_profile_limits (GstVaapiEncoderH264 * encoder)
+{
+ GstVaapiProfile profile;
+
+ if (!encoder->max_profile_idc
+ || encoder->profile_idc <= encoder->max_profile_idc)
+ return TRUE;
+
+ GST_WARNING ("lowering coding tools to meet target decoder constraints");
+
+ /* Try Main profile coding tools */
+ if (encoder->max_profile_idc < 100) {
+ encoder->use_dct8x8 = FALSE;
+ profile = GST_VAAPI_PROFILE_H264_MAIN;
+ }
+
+ /* Try Constrained Baseline profile coding tools */
+ if (encoder->max_profile_idc < 77) {
+ encoder->num_bframes = 0;
+ encoder->use_cabac = FALSE;
+ profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
+ }
+
+ encoder->profile = profile;
+ encoder->profile_idc = encoder->max_profile_idc;
+ return TRUE;
+}
+
/* Derives the minimum profile from the active coding tools */
static gboolean
ensure_profile (GstVaapiEncoderH264 * encoder)
return TRUE;
}
-static gboolean
+static GstVaapiEncoderStatus
ensure_profile_and_level (GstVaapiEncoderH264 * encoder)
{
- if (!ensure_profile (encoder))
- return FALSE;
+ if (!ensure_profile (encoder) || !ensure_profile_limits (encoder))
+ return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
if (!ensure_level (encoder))
- return FALSE;
- return TRUE;
+ return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+
+ /* Check HW constraints */
+ if (!ensure_hw_profile_limits (encoder))
+ return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+ if (encoder->profile_idc > encoder->hw_max_profile_idc)
+ return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+ return GST_VAAPI_ENCODER_STATUS_SUCCESS;
}
static gboolean
{
GstVaapiEncoderH264 *const encoder =
GST_VAAPI_ENCODER_H264_CAST (base_encoder);
+ GstVaapiEncoderStatus status;
encoder->mb_width = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16;
encoder->mb_height = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16;
- if (!ensure_profile_and_level (encoder))
- goto error;
+ status = ensure_profile_and_level (encoder);
+ if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+ return status;
+
if (!ensure_bitrate (encoder))
goto error;
return props;
}
+/**
+ * gst_vaapi_encoder_h264_set_max_profile:
+ * @encoder: a #GstVaapiEncoderH264
+ * @profile: an H.264 #GstVaapiProfile
+ *
+ * Notifies the @encoder to use coding tools from the supplied
+ * @profile at most.
+ *
+ * This means that if the minimal profile derived to
+ * support the specified coding tools is greater than this @profile,
+ * then an error is returned when the @encoder is configured.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_encoder_h264_set_max_profile (GstVaapiEncoderH264 * encoder,
+ GstVaapiProfile profile)
+{
+ guint8 profile_idc;
+
+ g_return_val_if_fail (encoder != NULL, FALSE);
+ g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN, FALSE);
+
+ if (gst_vaapi_profile_get_codec (profile) != GST_VAAPI_CODEC_H264)
+ return FALSE;
+
+ profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
+ if (!profile_idc)
+ return FALSE;
+
+ encoder->max_profile_idc = profile_idc;
+ return TRUE;
+}
+
/**
* gst_vaapi_encoder_h264_get_profile_and_level:
* @encoder: a #GstVaapiEncoderH264
#include "gst/vaapi/sysdeps.h"
#include <gst/vaapi/gstvaapidisplay.h>
#include <gst/vaapi/gstvaapiencoder_h264.h>
+#include <gst/vaapi/gstvaapiutils_h264.h>
#include "gstvaapiencode_h264.h"
#include "gstvaapipluginutil.h"
#if GST_CHECK_VERSION(1,0,0)
/* *INDENT-OFF* */
static const char gst_vaapiencode_h264_src_caps_str[] =
- GST_CODEC_CAPS;
+ GST_CODEC_CAPS ", "
+ "profile = (string) { constrained-baseline, baseline, main, high }";
/* *INDENT-ON* */
/* *INDENT-OFF* */
}
}
+typedef struct
+{
+ GstVaapiProfile best_profile;
+ guint best_score;
+} FindBestProfileData;
+
+static void
+find_best_profile_value (FindBestProfileData * data, const GValue * value)
+{
+ const gchar *str;
+ GstVaapiProfile profile;
+ guint score;
+
+ if (!value || !G_VALUE_HOLDS_STRING (value))
+ return;
+
+ str = g_value_get_string (value);
+ if (!str)
+ return;
+ profile = gst_vaapi_utils_h264_get_profile_from_string (str);
+ if (!profile)
+ return;
+ score = gst_vaapi_utils_h264_get_profile_score (profile);
+ if (score < data->best_score)
+ return;
+ data->best_profile = profile;
+ data->best_score = score;
+}
+
+static GstVaapiProfile
+find_best_profile (GstCaps * caps)
+{
+ FindBestProfileData data;
+ guint i, j, num_structures, num_values;
+
+ data.best_profile = GST_VAAPI_PROFILE_UNKNOWN;
+ data.best_score = 0;
+
+ num_structures = gst_caps_get_size (caps);
+ for (i = 0; i < num_structures; i++) {
+ GstStructure *const structure = gst_caps_get_structure (caps, i);
+ const GValue *const value = gst_structure_get_value (structure, "profile");
+
+ if (!value)
+ continue;
+ if (G_VALUE_HOLDS_STRING (value))
+ find_best_profile_value (&data, value);
+ else if (GST_VALUE_HOLDS_LIST (value)) {
+ num_values = gst_value_list_get_size (value);
+ for (j = 0; j < num_values; j++)
+ find_best_profile_value (&data, gst_value_list_get_value (value, j));
+ }
+ }
+ return data.best_profile;
+}
+
+static gboolean
+gst_vaapiencode_h264_set_config (GstVaapiEncode * base_encode)
+{
+ GstVaapiEncoderH264 *const encoder =
+ GST_VAAPI_ENCODER_H264 (base_encode->encoder);
+ GstCaps *allowed_caps;
+ GstVaapiProfile profile;
+
+ /* Check for the largest profile that is supported */
+ allowed_caps =
+ gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (base_encode));
+ if (!allowed_caps)
+ return TRUE;
+
+ profile = find_best_profile (allowed_caps);
+ gst_caps_unref (allowed_caps);
+ if (profile) {
+ GST_INFO ("using %s profile as target decoder constraints",
+ gst_vaapi_utils_h264_get_profile_string (profile));
+ if (!gst_vaapi_encoder_h264_set_max_profile (encoder, profile))
+ return FALSE;
+ }
+ return TRUE;
+}
+
static GstCaps *
gst_vaapiencode_h264_get_caps (GstVaapiEncode * base_encode)
{
object_class->get_property = gst_vaapiencode_h264_get_property;
encode_class->get_properties = gst_vaapi_encoder_h264_get_default_properties;
+ encode_class->set_config = gst_vaapiencode_h264_set_config;
encode_class->get_caps = gst_vaapiencode_h264_get_caps;
encode_class->alloc_encoder = gst_vaapiencode_h264_alloc_encoder;
encode_class->alloc_buffer = gst_vaapiencode_h264_alloc_buffer;