mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
v4l2videoenc: Move the profile/level negotation in the base class
This removes duplicated code across different codec.
This commit is contained in:
parent
b0fb95b956
commit
783ac9a9f9
6 changed files with 258 additions and 749 deletions
|
@ -267,222 +267,9 @@ v4l2_level_to_string (gint v4l2_level)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct ProfileLevelCtx
|
||||
{
|
||||
GstV4l2H264Enc *self;
|
||||
const gchar *profile;
|
||||
const gchar *level;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
get_string_list (GstStructure * s, const gchar * field, GQueue * queue)
|
||||
{
|
||||
const GValue *value;
|
||||
|
||||
value = gst_structure_get_value (s, field);
|
||||
|
||||
if (!value)
|
||||
return FALSE;
|
||||
|
||||
if (GST_VALUE_HOLDS_LIST (value)) {
|
||||
guint i;
|
||||
|
||||
if (gst_value_list_get_size (value) == 0)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < gst_value_list_get_size (value); i++) {
|
||||
const GValue *item = gst_value_list_get_value (value, i);
|
||||
|
||||
if (G_VALUE_HOLDS_STRING (item))
|
||||
g_queue_push_tail (queue, g_value_dup_string (item));
|
||||
}
|
||||
} else if (G_VALUE_HOLDS_STRING (value)) {
|
||||
g_queue_push_tail (queue, g_value_dup_string (value));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ProfileLevelCtx *ctx = user_data;
|
||||
GstV4l2Object *v4l2object = GST_V4L2_VIDEO_ENC (ctx->self)->v4l2output;
|
||||
GQueue profiles = G_QUEUE_INIT;
|
||||
GQueue levels = G_QUEUE_INIT;
|
||||
gboolean failed = FALSE;
|
||||
|
||||
if (get_string_list (s, "profile", &profiles)) {
|
||||
GList *l;
|
||||
|
||||
for (l = profiles.head; l; l = l->next) {
|
||||
struct v4l2_control control = { 0, };
|
||||
gint v4l2_profile;
|
||||
const gchar *profile = l->data;
|
||||
|
||||
GST_TRACE_OBJECT (ctx->self, "Trying profile %s", profile);
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
|
||||
control.value = v4l2_profile = v4l2_profile_from_string (profile);
|
||||
|
||||
if (control.value < 0)
|
||||
continue;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_WARNING_OBJECT (ctx->self, "Failed to set H264 profile: '%s'",
|
||||
g_strerror (errno));
|
||||
break;
|
||||
}
|
||||
|
||||
profile = v4l2_profile_to_string (control.value);
|
||||
|
||||
if (control.value == v4l2_profile) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_list_find_custom (l, profile, g_str_equal)) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (profiles.length && !ctx->profile)
|
||||
failed = TRUE;
|
||||
|
||||
g_queue_foreach (&profiles, (GFunc) g_free, NULL);
|
||||
g_queue_clear (&profiles);
|
||||
}
|
||||
|
||||
if (!failed && get_string_list (s, "level", &levels)) {
|
||||
GList *l;
|
||||
|
||||
for (l = levels.head; l; l = l->next) {
|
||||
struct v4l2_control control = { 0, };
|
||||
gint v4l2_level;
|
||||
const gchar *level = l->data;
|
||||
|
||||
GST_TRACE_OBJECT (ctx->self, "Trying level %s", level);
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
|
||||
control.value = v4l2_level = v4l2_level_from_string (level);
|
||||
|
||||
if (control.value < 0)
|
||||
continue;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_WARNING_OBJECT (ctx->self, "Failed to set H264 level: '%s'",
|
||||
g_strerror (errno));
|
||||
break;
|
||||
}
|
||||
|
||||
level = v4l2_level_to_string (control.value);
|
||||
|
||||
if (control.value == v4l2_level) {
|
||||
ctx->level = level;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_list_find_custom (l, level, g_str_equal)) {
|
||||
ctx->level = level;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (levels.length && !ctx->level)
|
||||
failed = TRUE;
|
||||
|
||||
g_queue_foreach (&levels, (GFunc) g_free, NULL);
|
||||
g_queue_clear (&levels);
|
||||
}
|
||||
|
||||
/* If it failed, we continue */
|
||||
return failed;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_h264_enc_negotiate (GstVideoEncoder * encoder)
|
||||
{
|
||||
GstV4l2H264Enc *self = GST_V4L2_H264_ENC (encoder);
|
||||
GstV4l2VideoEnc *venc = GST_V4L2_VIDEO_ENC (encoder);
|
||||
GstV4l2Object *v4l2object = venc->v4l2output;
|
||||
GstCaps *allowed_caps;
|
||||
struct ProfileLevelCtx ctx = { self, NULL, NULL };
|
||||
GstVideoCodecState *state;
|
||||
GstStructure *s;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Negotiating H264 profile and level.");
|
||||
|
||||
allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
|
||||
|
||||
if (allowed_caps) {
|
||||
|
||||
if (gst_caps_is_empty (allowed_caps))
|
||||
goto not_negotiated;
|
||||
|
||||
allowed_caps = gst_caps_make_writable (allowed_caps);
|
||||
|
||||
/* negotiate_profile_and_level() will return TRUE on failure to keep
|
||||
* iterating, if gst_caps_foreach() returns TRUE it means there was no
|
||||
* compatible profile and level in any of the structure */
|
||||
if (gst_caps_foreach (allowed_caps, negotiate_profile_and_level, &ctx)) {
|
||||
goto no_profile_level;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx.profile) {
|
||||
struct v4l2_control control = { 0, };
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
|
||||
goto g_ctrl_failed;
|
||||
|
||||
ctx.profile = v4l2_profile_to_string (control.value);
|
||||
}
|
||||
|
||||
if (!ctx.level) {
|
||||
struct v4l2_control control = { 0, };
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
|
||||
goto g_ctrl_failed;
|
||||
|
||||
ctx.level = v4l2_level_to_string (control.value);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Selected H264 profile %s at level %s",
|
||||
ctx.profile, ctx.level);
|
||||
|
||||
state = gst_video_encoder_get_output_state (encoder);
|
||||
s = gst_caps_get_structure (state->caps, 0);
|
||||
gst_structure_set (s, "profile", G_TYPE_STRING, ctx.profile,
|
||||
"level", G_TYPE_STRING, ctx.level, NULL);
|
||||
|
||||
return GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder);
|
||||
|
||||
g_ctrl_failed:
|
||||
GST_WARNING_OBJECT (self, "Failed to get H264 profile and level: '%s'",
|
||||
g_strerror (errno));
|
||||
goto not_negotiated;
|
||||
|
||||
no_profile_level:
|
||||
GST_WARNING_OBJECT (self, "No compatible level and profiled in caps: %"
|
||||
GST_PTR_FORMAT, allowed_caps);
|
||||
goto not_negotiated;
|
||||
|
||||
not_negotiated:
|
||||
if (allowed_caps)
|
||||
gst_caps_unref (allowed_caps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2_h264_enc_init (GstV4l2H264Enc * self)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -490,13 +277,13 @@ gst_v4l2_h264_enc_class_init (GstV4l2H264EncClass * klass)
|
|||
{
|
||||
GstElementClass *element_class;
|
||||
GObjectClass *gobject_class;
|
||||
GstVideoEncoderClass *baseclass;
|
||||
GstV4l2VideoEncClass *baseclass;
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
element_class = (GstElementClass *) klass;
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
baseclass = GST_VIDEO_ENCODER_CLASS (klass);
|
||||
baseclass = (GstV4l2VideoEncClass *) (klass);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_v4l2_h264_enc_debug, "v4l2h264enc", 0,
|
||||
"V4L2 H.264 Encoder");
|
||||
|
@ -510,7 +297,14 @@ gst_v4l2_h264_enc_class_init (GstV4l2H264EncClass * klass)
|
|||
GST_DEBUG_FUNCPTR (gst_v4l2_h264_enc_set_property);
|
||||
gobject_class->get_property =
|
||||
GST_DEBUG_FUNCPTR (gst_v4l2_h264_enc_get_property);
|
||||
baseclass->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2_h264_enc_negotiate);
|
||||
|
||||
baseclass->codec_name = "H264";
|
||||
baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
|
||||
baseclass->profile_to_string = v4l2_profile_to_string;
|
||||
baseclass->profile_from_string = v4l2_profile_from_string;
|
||||
baseclass->level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
|
||||
baseclass->level_to_string = v4l2_level_to_string;
|
||||
baseclass->level_from_string = v4l2_level_from_string;
|
||||
}
|
||||
|
||||
/* Probing functions */
|
||||
|
|
|
@ -163,218 +163,6 @@ v4l2_level_to_string (gint v4l2_level)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct ProfileLevelCtx
|
||||
{
|
||||
GstV4l2Mpeg4Enc *self;
|
||||
const gchar *profile;
|
||||
const gchar *level;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
get_string_list (GstStructure * s, const gchar * field, GQueue * queue)
|
||||
{
|
||||
const GValue *value;
|
||||
|
||||
value = gst_structure_get_value (s, field);
|
||||
|
||||
if (!value)
|
||||
return FALSE;
|
||||
|
||||
if (GST_VALUE_HOLDS_LIST (value)) {
|
||||
guint i;
|
||||
|
||||
if (gst_value_list_get_size (value) == 0)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < gst_value_list_get_size (value); i++) {
|
||||
const GValue *item = gst_value_list_get_value (value, i);
|
||||
|
||||
if (G_VALUE_HOLDS_STRING (item))
|
||||
g_queue_push_tail (queue, g_value_dup_string (item));
|
||||
}
|
||||
} else if (G_VALUE_HOLDS_STRING (value)) {
|
||||
g_queue_push_tail (queue, g_value_dup_string (value));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ProfileLevelCtx *ctx = user_data;
|
||||
GstV4l2Object *v4l2object = GST_V4L2_VIDEO_ENC (ctx->self)->v4l2output;
|
||||
GQueue profiles = G_QUEUE_INIT;
|
||||
GQueue levels = G_QUEUE_INIT;
|
||||
gboolean failed = FALSE;
|
||||
|
||||
if (get_string_list (s, "profile", &profiles)) {
|
||||
GList *l;
|
||||
|
||||
for (l = profiles.head; l; l = l->next) {
|
||||
struct v4l2_control control = { 0, };
|
||||
gint v4l2_profile;
|
||||
const gchar *profile = l->data;
|
||||
|
||||
GST_TRACE_OBJECT (ctx->self, "Trying profile %s", profile);
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE;
|
||||
control.value = v4l2_profile = v4l2_profile_from_string (profile);
|
||||
|
||||
if (control.value < 0)
|
||||
continue;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_WARNING_OBJECT (ctx->self, "Failed to set MPEG4 profile: '%s'",
|
||||
g_strerror (errno));
|
||||
break;
|
||||
}
|
||||
|
||||
profile = v4l2_profile_to_string (control.value);
|
||||
|
||||
if (control.value == v4l2_profile) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_list_find_custom (l, profile, g_str_equal)) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (profiles.length && !ctx->profile)
|
||||
failed = TRUE;
|
||||
|
||||
g_queue_foreach (&profiles, (GFunc) g_free, NULL);
|
||||
g_queue_clear (&profiles);
|
||||
}
|
||||
|
||||
if (!failed && get_string_list (s, "level", &levels)) {
|
||||
GList *l;
|
||||
|
||||
for (l = levels.head; l; l = l->next) {
|
||||
struct v4l2_control control = { 0, };
|
||||
gint v4l2_level;
|
||||
const gchar *level = l->data;
|
||||
|
||||
GST_TRACE_OBJECT (ctx->self, "Trying level %s", level);
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL;
|
||||
control.value = v4l2_level = v4l2_level_from_string (level);
|
||||
|
||||
if (control.value < 0)
|
||||
continue;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_WARNING_OBJECT (ctx->self, "Failed to set MPEG4 level: '%s'",
|
||||
g_strerror (errno));
|
||||
break;
|
||||
}
|
||||
|
||||
level = v4l2_level_to_string (control.value);
|
||||
|
||||
if (control.value == v4l2_level) {
|
||||
ctx->level = level;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_list_find_custom (l, level, g_str_equal)) {
|
||||
ctx->level = level;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (levels.length && !ctx->level)
|
||||
failed = TRUE;
|
||||
|
||||
g_queue_foreach (&levels, (GFunc) g_free, NULL);
|
||||
g_queue_clear (&levels);
|
||||
}
|
||||
|
||||
/* If it failed, we continue */
|
||||
return failed;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_mpeg4_enc_negotiate (GstVideoEncoder * encoder)
|
||||
{
|
||||
GstV4l2Mpeg4Enc *self = GST_V4L2_MPEG4_ENC (encoder);
|
||||
GstV4l2VideoEnc *venc = GST_V4L2_VIDEO_ENC (encoder);
|
||||
GstV4l2Object *v4l2object = venc->v4l2output;
|
||||
GstCaps *allowed_caps;
|
||||
struct ProfileLevelCtx ctx = { self, NULL, NULL };
|
||||
GstVideoCodecState *state;
|
||||
GstStructure *s;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Negotiating MPEG4 profile and level.");
|
||||
|
||||
allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
|
||||
|
||||
if (allowed_caps) {
|
||||
|
||||
if (gst_caps_is_empty (allowed_caps))
|
||||
goto not_negotiated;
|
||||
|
||||
allowed_caps = gst_caps_make_writable (allowed_caps);
|
||||
|
||||
/* negotiate_profile_and_level() will return TRUE on failure to keep
|
||||
* iterating, if gst_caps_foreach() returns TRUE it means there was no
|
||||
* compatible profile and level in any of the structure */
|
||||
if (gst_caps_foreach (allowed_caps, negotiate_profile_and_level, &ctx)) {
|
||||
goto no_profile_level;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx.profile) {
|
||||
struct v4l2_control control = { 0, };
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
|
||||
goto g_ctrl_failed;
|
||||
|
||||
ctx.profile = v4l2_profile_to_string (control.value);
|
||||
}
|
||||
|
||||
if (!ctx.level) {
|
||||
struct v4l2_control control = { 0, };
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
|
||||
goto g_ctrl_failed;
|
||||
|
||||
ctx.level = v4l2_level_to_string (control.value);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Selected MPEG4 profile %s at level %s",
|
||||
ctx.profile, ctx.level);
|
||||
|
||||
state = gst_video_encoder_get_output_state (encoder);
|
||||
s = gst_caps_get_structure (state->caps, 0);
|
||||
gst_structure_set (s, "profile", G_TYPE_STRING, ctx.profile,
|
||||
"level", G_TYPE_STRING, ctx.level, NULL);
|
||||
|
||||
return GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder);
|
||||
|
||||
g_ctrl_failed:
|
||||
GST_WARNING_OBJECT (self, "Failed to get MPEG4 profile and level: '%s'",
|
||||
g_strerror (errno));
|
||||
goto not_negotiated;
|
||||
|
||||
no_profile_level:
|
||||
GST_WARNING_OBJECT (self, "No compatible level and profiled in caps: %"
|
||||
GST_PTR_FORMAT, allowed_caps);
|
||||
goto not_negotiated;
|
||||
|
||||
not_negotiated:
|
||||
if (allowed_caps)
|
||||
gst_caps_unref (allowed_caps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2_mpeg4_enc_init (GstV4l2Mpeg4Enc * self)
|
||||
{
|
||||
|
@ -385,13 +173,13 @@ gst_v4l2_mpeg4_enc_class_init (GstV4l2Mpeg4EncClass * klass)
|
|||
{
|
||||
GstElementClass *element_class;
|
||||
GObjectClass *gobject_class;
|
||||
GstVideoEncoderClass *baseclass;
|
||||
GstV4l2VideoEncClass *baseclass;
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
element_class = (GstElementClass *) klass;
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
baseclass = GST_VIDEO_ENCODER_CLASS (klass);
|
||||
baseclass = (GstV4l2VideoEncClass *) (klass);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_v4l2_mpeg4_enc_debug, "v4l2mpeg4enc", 0,
|
||||
"V4L2 MPEG4 Encoder");
|
||||
|
@ -406,7 +194,14 @@ gst_v4l2_mpeg4_enc_class_init (GstV4l2Mpeg4EncClass * klass)
|
|||
GST_DEBUG_FUNCPTR (gst_v4l2_mpeg4_enc_set_property);
|
||||
gobject_class->get_property =
|
||||
GST_DEBUG_FUNCPTR (gst_v4l2_mpeg4_enc_get_property);
|
||||
baseclass->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2_mpeg4_enc_negotiate);
|
||||
|
||||
baseclass->codec_name = "MPEG4";
|
||||
baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE;
|
||||
baseclass->profile_to_string = v4l2_profile_to_string;
|
||||
baseclass->profile_from_string = v4l2_profile_from_string;
|
||||
baseclass->level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL;
|
||||
baseclass->level_to_string = v4l2_level_to_string;
|
||||
baseclass->level_from_string = v4l2_level_from_string;
|
||||
}
|
||||
|
||||
/* Probing functions */
|
||||
|
|
|
@ -373,10 +373,205 @@ gst_v4l2_video_enc_flush (GstVideoEncoder * encoder)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
struct ProfileLevelCtx
|
||||
{
|
||||
GstV4l2VideoEnc *self;
|
||||
const gchar *profile;
|
||||
const gchar *level;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
get_string_list (GstStructure * s, const gchar * field, GQueue * queue)
|
||||
{
|
||||
const GValue *value;
|
||||
|
||||
value = gst_structure_get_value (s, field);
|
||||
|
||||
if (!value)
|
||||
return FALSE;
|
||||
|
||||
if (GST_VALUE_HOLDS_LIST (value)) {
|
||||
guint i;
|
||||
|
||||
if (gst_value_list_get_size (value) == 0)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < gst_value_list_get_size (value); i++) {
|
||||
const GValue *item = gst_value_list_get_value (value, i);
|
||||
|
||||
if (G_VALUE_HOLDS_STRING (item))
|
||||
g_queue_push_tail (queue, g_value_dup_string (item));
|
||||
}
|
||||
} else if (G_VALUE_HOLDS_STRING (value)) {
|
||||
g_queue_push_tail (queue, g_value_dup_string (value));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ProfileLevelCtx *ctx = user_data;
|
||||
GstV4l2VideoEncClass *klass = GST_V4L2_VIDEO_ENC_GET_CLASS (ctx->self);
|
||||
GstV4l2Object *v4l2object = GST_V4L2_VIDEO_ENC (ctx->self)->v4l2output;
|
||||
GQueue profiles = G_QUEUE_INIT;
|
||||
GQueue levels = G_QUEUE_INIT;
|
||||
gboolean failed = FALSE;
|
||||
|
||||
if (klass->profile_cid && get_string_list (s, "profile", &profiles)) {
|
||||
GList *l;
|
||||
|
||||
for (l = profiles.head; l; l = l->next) {
|
||||
struct v4l2_control control = { 0, };
|
||||
gint v4l2_profile;
|
||||
const gchar *profile = l->data;
|
||||
|
||||
GST_TRACE_OBJECT (ctx->self, "Trying profile %s", profile);
|
||||
|
||||
control.id = klass->profile_cid;
|
||||
control.value = v4l2_profile = klass->profile_from_string (profile);
|
||||
|
||||
if (control.value < 0)
|
||||
continue;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_WARNING_OBJECT (ctx->self, "Failed to set %s profile: '%s'",
|
||||
klass->codec_name, g_strerror (errno));
|
||||
break;
|
||||
}
|
||||
|
||||
profile = klass->profile_to_string (control.value);
|
||||
|
||||
if (control.value == v4l2_profile) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_list_find_custom (l, profile, g_str_equal)) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (profiles.length && !ctx->profile)
|
||||
failed = TRUE;
|
||||
|
||||
g_queue_foreach (&profiles, (GFunc) g_free, NULL);
|
||||
g_queue_clear (&profiles);
|
||||
}
|
||||
|
||||
if (!failed && klass->level_cid && get_string_list (s, "level", &levels)) {
|
||||
GList *l;
|
||||
|
||||
for (l = levels.head; l; l = l->next) {
|
||||
struct v4l2_control control = { 0, };
|
||||
gint v4l2_level;
|
||||
const gchar *level = l->data;
|
||||
|
||||
GST_TRACE_OBJECT (ctx->self, "Trying level %s", level);
|
||||
|
||||
control.id = klass->level_cid;
|
||||
control.value = v4l2_level = klass->level_from_string (level);
|
||||
|
||||
if (control.value < 0)
|
||||
continue;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_WARNING_OBJECT (ctx->self, "Failed to set %s level: '%s'",
|
||||
klass->codec_name, g_strerror (errno));
|
||||
break;
|
||||
}
|
||||
|
||||
level = klass->level_to_string (control.value);
|
||||
|
||||
if (control.value == v4l2_level) {
|
||||
ctx->level = level;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_list_find_custom (l, level, g_str_equal)) {
|
||||
ctx->level = level;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (levels.length && !ctx->level)
|
||||
failed = TRUE;
|
||||
|
||||
g_queue_foreach (&levels, (GFunc) g_free, NULL);
|
||||
g_queue_clear (&levels);
|
||||
}
|
||||
|
||||
/* If it failed, we continue */
|
||||
return failed;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_video_enc_negotiate (GstVideoEncoder * encoder)
|
||||
{
|
||||
GstV4l2VideoEncClass *klass = GST_V4L2_VIDEO_ENC_GET_CLASS (encoder);
|
||||
GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder);
|
||||
GstV4l2Object *v4l2object = self->v4l2output;
|
||||
GstCaps *allowed_caps;
|
||||
struct ProfileLevelCtx ctx = { self, NULL, NULL };
|
||||
GstVideoCodecState *state;
|
||||
GstStructure *s;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Negotiating %s profile and level.",
|
||||
klass->codec_name);
|
||||
|
||||
allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
|
||||
|
||||
if (allowed_caps) {
|
||||
|
||||
if (gst_caps_is_empty (allowed_caps))
|
||||
goto not_negotiated;
|
||||
|
||||
allowed_caps = gst_caps_make_writable (allowed_caps);
|
||||
|
||||
/* negotiate_profile_and_level() will return TRUE on failure to keep
|
||||
* iterating, if gst_caps_foreach() returns TRUE it means there was no
|
||||
* compatible profile and level in any of the structure */
|
||||
if (gst_caps_foreach (allowed_caps, negotiate_profile_and_level, &ctx)) {
|
||||
goto no_profile_level;
|
||||
}
|
||||
}
|
||||
|
||||
if (klass->profile_cid && !ctx.profile) {
|
||||
struct v4l2_control control = { 0, };
|
||||
|
||||
control.id = klass->profile_cid;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
|
||||
goto g_ctrl_failed;
|
||||
|
||||
ctx.profile = klass->profile_to_string (control.value);
|
||||
}
|
||||
|
||||
if (klass->level_cid && !ctx.level) {
|
||||
struct v4l2_control control = { 0, };
|
||||
|
||||
control.id = klass->level_cid;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
|
||||
goto g_ctrl_failed;
|
||||
|
||||
ctx.level = klass->level_to_string (control.value);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Selected %s profile %s at level %s",
|
||||
klass->codec_name, ctx.profile, ctx.level);
|
||||
|
||||
state = gst_video_encoder_get_output_state (encoder);
|
||||
s = gst_caps_get_structure (state->caps, 0);
|
||||
|
||||
if (klass->profile_cid)
|
||||
gst_structure_set (s, "profile", G_TYPE_STRING, ctx.profile, NULL);
|
||||
|
||||
if (klass->level_cid)
|
||||
gst_structure_set (s, "level", G_TYPE_STRING, ctx.level, NULL);
|
||||
|
||||
if (!GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder))
|
||||
return FALSE;
|
||||
|
@ -388,6 +583,21 @@ gst_v4l2_video_enc_negotiate (GstVideoEncoder * encoder)
|
|||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
g_ctrl_failed:
|
||||
GST_WARNING_OBJECT (self, "Failed to get %s profile and level: '%s'",
|
||||
klass->codec_name, g_strerror (errno));
|
||||
goto not_negotiated;
|
||||
|
||||
no_profile_level:
|
||||
GST_WARNING_OBJECT (self, "No compatible level and profile in caps: %"
|
||||
GST_PTR_FORMAT, allowed_caps);
|
||||
goto not_negotiated;
|
||||
|
||||
not_negotiated:
|
||||
if (allowed_caps)
|
||||
gst_caps_unref (allowed_caps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstVideoCodecFrame *
|
||||
|
@ -783,6 +993,7 @@ gst_v4l2_video_enc_change_state (GstElement * element,
|
|||
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2_video_enc_dispose (GObject * object)
|
||||
{
|
||||
|
@ -805,6 +1016,7 @@ gst_v4l2_video_enc_finalize (GObject * object)
|
|||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2_video_enc_init (GstV4l2VideoEnc * self)
|
||||
{
|
||||
|
|
|
@ -43,6 +43,9 @@ G_BEGIN_DECLS
|
|||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_VIDEO_ENC))
|
||||
#define GST_IS_V4L2_VIDEO_ENC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_VIDEO_ENC))
|
||||
#define GST_V4L2_VIDEO_ENC_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_V4L2_VIDEO_ENC, GstV4l2VideoEncClass))
|
||||
|
||||
typedef struct _GstV4l2VideoEnc GstV4l2VideoEnc;
|
||||
typedef struct _GstV4l2VideoEncClass GstV4l2VideoEncClass;
|
||||
|
||||
|
@ -71,9 +74,15 @@ struct _GstV4l2VideoEncClass
|
|||
GstVideoEncoderClass parent_class;
|
||||
|
||||
gchar *default_device;
|
||||
const char *codec_name;
|
||||
|
||||
GstFlowReturn (*get_output_caps) (GstVideoEncoder * encoder,
|
||||
GstCaps ** outcaps);
|
||||
guint32 profile_cid;
|
||||
const gchar * (*profile_to_string) (gint v4l2_profile);
|
||||
gint (*profile_from_string) (const gchar * profile);
|
||||
|
||||
guint32 level_cid;
|
||||
const gchar * (*level_to_string) (gint v4l2_level);
|
||||
gint (*level_from_string) (const gchar * level);
|
||||
};
|
||||
|
||||
GType gst_v4l2_video_enc_get_type (void);
|
||||
|
|
|
@ -104,161 +104,6 @@ v4l2_profile_to_string (gint v4l2_profile)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct ProfileCtx
|
||||
{
|
||||
GstV4l2Vp8Enc *self;
|
||||
const gchar *profile;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
get_string_list (GstStructure * s, const gchar * field, GQueue * queue)
|
||||
{
|
||||
const GValue *value;
|
||||
|
||||
value = gst_structure_get_value (s, field);
|
||||
|
||||
if (!value)
|
||||
return FALSE;
|
||||
|
||||
if (GST_VALUE_HOLDS_LIST (value)) {
|
||||
guint i;
|
||||
|
||||
if (gst_value_list_get_size (value) == 0)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < gst_value_list_get_size (value); i++) {
|
||||
const GValue *item = gst_value_list_get_value (value, i);
|
||||
|
||||
if (G_VALUE_HOLDS_STRING (item))
|
||||
g_queue_push_tail (queue, g_value_dup_string (item));
|
||||
}
|
||||
} else if (G_VALUE_HOLDS_STRING (value)) {
|
||||
g_queue_push_tail (queue, g_value_dup_string (value));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
negotiate_profile (GstCapsFeatures * features, GstStructure * s,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ProfileCtx *ctx = user_data;
|
||||
GstV4l2Object *v4l2object = GST_V4L2_VIDEO_ENC (ctx->self)->v4l2output;
|
||||
GQueue profiles = G_QUEUE_INIT;
|
||||
gboolean failed = FALSE;
|
||||
|
||||
if (get_string_list (s, "profile", &profiles)) {
|
||||
GList *l;
|
||||
|
||||
for (l = profiles.head; l; l = l->next) {
|
||||
struct v4l2_control control = { 0, };
|
||||
gint v4l2_profile;
|
||||
const gchar *profile = l->data;
|
||||
|
||||
GST_TRACE_OBJECT (ctx->self, "Trying profile %s", profile);
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
|
||||
control.value = v4l2_profile = v4l2_profile_from_string (profile);
|
||||
|
||||
if (control.value < 0)
|
||||
continue;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_WARNING_OBJECT (ctx->self, "Failed to set VP8 profile: '%s'",
|
||||
g_strerror (errno));
|
||||
break;
|
||||
}
|
||||
|
||||
profile = v4l2_profile_to_string (control.value);
|
||||
|
||||
if (control.value == v4l2_profile) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_list_find_custom (l, profile, g_str_equal)) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (profiles.length && !ctx->profile)
|
||||
failed = TRUE;
|
||||
|
||||
g_queue_foreach (&profiles, (GFunc) g_free, NULL);
|
||||
g_queue_clear (&profiles);
|
||||
}
|
||||
|
||||
/* If it failed, we continue */
|
||||
return failed;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_vp8_enc_negotiate (GstVideoEncoder * encoder)
|
||||
{
|
||||
GstV4l2Vp8Enc *self = GST_V4L2_VP8_ENC (encoder);
|
||||
GstV4l2VideoEnc *venc = GST_V4L2_VIDEO_ENC (encoder);
|
||||
GstV4l2Object *v4l2object = venc->v4l2output;
|
||||
GstCaps *allowed_caps;
|
||||
struct ProfileCtx ctx = { self, NULL };
|
||||
GstVideoCodecState *state;
|
||||
GstStructure *s;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Negotiating VP8 profile.");
|
||||
|
||||
allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
|
||||
|
||||
if (allowed_caps) {
|
||||
|
||||
if (gst_caps_is_empty (allowed_caps))
|
||||
goto not_negotiated;
|
||||
|
||||
allowed_caps = gst_caps_make_writable (allowed_caps);
|
||||
|
||||
/* negotiate_profile() will return TRUE on failure to keep
|
||||
* iterating, if gst_caps_foreach() returns TRUE it means there was no
|
||||
* compatible profile in any of the structure */
|
||||
if (gst_caps_foreach (allowed_caps, negotiate_profile, &ctx)) {
|
||||
goto no_profile;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx.profile) {
|
||||
struct v4l2_control control = { 0, };
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
|
||||
goto g_ctrl_failed;
|
||||
|
||||
ctx.profile = v4l2_profile_to_string (control.value);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Selected VP8 profile %s", ctx.profile);
|
||||
|
||||
state = gst_video_encoder_get_output_state (encoder);
|
||||
s = gst_caps_get_structure (state->caps, 0);
|
||||
gst_structure_set (s, "profile", G_TYPE_STRING, ctx.profile, NULL);
|
||||
|
||||
return GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder);
|
||||
|
||||
g_ctrl_failed:
|
||||
GST_WARNING_OBJECT (self, "Failed to get VP8 profile: '%s'",
|
||||
g_strerror (errno));
|
||||
goto not_negotiated;
|
||||
|
||||
no_profile:
|
||||
GST_WARNING_OBJECT (self, "No compatible profile in caps: %" GST_PTR_FORMAT,
|
||||
allowed_caps);
|
||||
goto not_negotiated;
|
||||
|
||||
not_negotiated:
|
||||
if (allowed_caps)
|
||||
gst_caps_unref (allowed_caps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2_vp8_enc_init (GstV4l2Vp8Enc * self)
|
||||
{
|
||||
|
@ -269,13 +114,14 @@ gst_v4l2_vp8_enc_class_init (GstV4l2Vp8EncClass * klass)
|
|||
{
|
||||
GstElementClass *element_class;
|
||||
GObjectClass *gobject_class;
|
||||
GstVideoEncoderClass *baseclass;
|
||||
GstV4l2VideoEncClass *baseclass;
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
element_class = (GstElementClass *) klass;
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
baseclass = GST_VIDEO_ENCODER_CLASS (klass);
|
||||
baseclass = (GstV4l2VideoEncClass *) (klass);
|
||||
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_v4l2_vp8_enc_debug, "v4l2vp8enc", 0,
|
||||
"V4L2 VP8 Encoder");
|
||||
|
@ -290,7 +136,11 @@ gst_v4l2_vp8_enc_class_init (GstV4l2Vp8EncClass * klass)
|
|||
GST_DEBUG_FUNCPTR (gst_v4l2_vp8_enc_set_property);
|
||||
gobject_class->get_property =
|
||||
GST_DEBUG_FUNCPTR (gst_v4l2_vp8_enc_get_property);
|
||||
baseclass->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2_vp8_enc_negotiate);
|
||||
|
||||
baseclass->codec_name = "VP8";
|
||||
baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
|
||||
baseclass->profile_to_string = v4l2_profile_to_string;
|
||||
baseclass->profile_from_string = v4l2_profile_from_string;
|
||||
}
|
||||
|
||||
/* Probing functions */
|
||||
|
|
|
@ -104,161 +104,6 @@ v4l2_profile_to_string (gint v4l2_profile)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct ProfileCtx
|
||||
{
|
||||
GstV4l2Vp9Enc *self;
|
||||
const gchar *profile;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
get_string_list (GstStructure * s, const gchar * field, GQueue * queue)
|
||||
{
|
||||
const GValue *value;
|
||||
|
||||
value = gst_structure_get_value (s, field);
|
||||
|
||||
if (!value)
|
||||
return FALSE;
|
||||
|
||||
if (GST_VALUE_HOLDS_LIST (value)) {
|
||||
guint i;
|
||||
|
||||
if (gst_value_list_get_size (value) == 0)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < gst_value_list_get_size (value); i++) {
|
||||
const GValue *item = gst_value_list_get_value (value, i);
|
||||
|
||||
if (G_VALUE_HOLDS_STRING (item))
|
||||
g_queue_push_tail (queue, g_value_dup_string (item));
|
||||
}
|
||||
} else if (G_VALUE_HOLDS_STRING (value)) {
|
||||
g_queue_push_tail (queue, g_value_dup_string (value));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
negotiate_profile (GstCapsFeatures * features, GstStructure * s,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ProfileCtx *ctx = user_data;
|
||||
GstV4l2Object *v4l2object = GST_V4L2_VIDEO_ENC (ctx->self)->v4l2output;
|
||||
GQueue profiles = G_QUEUE_INIT;
|
||||
gboolean failed = FALSE;
|
||||
|
||||
if (get_string_list (s, "profile", &profiles)) {
|
||||
GList *l;
|
||||
|
||||
for (l = profiles.head; l; l = l->next) {
|
||||
struct v4l2_control control = { 0, };
|
||||
gint v4l2_profile;
|
||||
const gchar *profile = l->data;
|
||||
|
||||
GST_TRACE_OBJECT (ctx->self, "Trying profile %s", profile);
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
|
||||
control.value = v4l2_profile = v4l2_profile_from_string (profile);
|
||||
|
||||
if (control.value < 0)
|
||||
continue;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
GST_WARNING_OBJECT (ctx->self, "Failed to set VP9 profile: '%s'",
|
||||
g_strerror (errno));
|
||||
break;
|
||||
}
|
||||
|
||||
profile = v4l2_profile_to_string (control.value);
|
||||
|
||||
if (control.value == v4l2_profile) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_list_find_custom (l, profile, g_str_equal)) {
|
||||
ctx->profile = profile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (profiles.length && !ctx->profile)
|
||||
failed = TRUE;
|
||||
|
||||
g_queue_foreach (&profiles, (GFunc) g_free, NULL);
|
||||
g_queue_clear (&profiles);
|
||||
}
|
||||
|
||||
/* If it failed, we continue */
|
||||
return failed;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_vp9_enc_negotiate (GstVideoEncoder * encoder)
|
||||
{
|
||||
GstV4l2Vp9Enc *self = GST_V4L2_VP9_ENC (encoder);
|
||||
GstV4l2VideoEnc *venc = GST_V4L2_VIDEO_ENC (encoder);
|
||||
GstV4l2Object *v4l2object = venc->v4l2output;
|
||||
GstCaps *allowed_caps;
|
||||
struct ProfileCtx ctx = { self, NULL };
|
||||
GstVideoCodecState *state;
|
||||
GstStructure *s;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Negotiating VP8 profile.");
|
||||
|
||||
allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
|
||||
|
||||
if (allowed_caps) {
|
||||
|
||||
if (gst_caps_is_empty (allowed_caps))
|
||||
goto not_negotiated;
|
||||
|
||||
allowed_caps = gst_caps_make_writable (allowed_caps);
|
||||
|
||||
/* negotiate_profile() will return TRUE on failure to keep
|
||||
* iterating, if gst_caps_foreach() returns TRUE it means there was no
|
||||
* compatible profile in any of the structure */
|
||||
if (gst_caps_foreach (allowed_caps, negotiate_profile, &ctx)) {
|
||||
goto no_profile;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx.profile) {
|
||||
struct v4l2_control control = { 0, };
|
||||
|
||||
control.id = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
|
||||
|
||||
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
|
||||
goto g_ctrl_failed;
|
||||
|
||||
ctx.profile = v4l2_profile_to_string (control.value);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Selected VP9 profile %s", ctx.profile);
|
||||
|
||||
state = gst_video_encoder_get_output_state (encoder);
|
||||
s = gst_caps_get_structure (state->caps, 0);
|
||||
gst_structure_set (s, "profile", G_TYPE_STRING, ctx.profile, NULL);
|
||||
|
||||
return GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder);
|
||||
|
||||
g_ctrl_failed:
|
||||
GST_WARNING_OBJECT (self, "Failed to get VP9 profile: '%s'",
|
||||
g_strerror (errno));
|
||||
goto not_negotiated;
|
||||
|
||||
no_profile:
|
||||
GST_WARNING_OBJECT (self, "No compatible profile in caps: %" GST_PTR_FORMAT,
|
||||
allowed_caps);
|
||||
goto not_negotiated;
|
||||
|
||||
not_negotiated:
|
||||
if (allowed_caps)
|
||||
gst_caps_unref (allowed_caps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2_vp9_enc_init (GstV4l2Vp9Enc * self)
|
||||
{
|
||||
|
@ -269,13 +114,13 @@ gst_v4l2_vp9_enc_class_init (GstV4l2Vp9EncClass * klass)
|
|||
{
|
||||
GstElementClass *element_class;
|
||||
GObjectClass *gobject_class;
|
||||
GstVideoEncoderClass *baseclass;
|
||||
GstV4l2VideoEncClass *baseclass;
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
element_class = (GstElementClass *) klass;
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
baseclass = GST_VIDEO_ENCODER_CLASS (klass);
|
||||
baseclass = (GstV4l2VideoEncClass *) (klass);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_v4l2_vp9_enc_debug, "v4l2vp9enc", 0,
|
||||
"V4L2 VP9 Encoder");
|
||||
|
@ -290,7 +135,11 @@ gst_v4l2_vp9_enc_class_init (GstV4l2Vp9EncClass * klass)
|
|||
GST_DEBUG_FUNCPTR (gst_v4l2_vp9_enc_set_property);
|
||||
gobject_class->get_property =
|
||||
GST_DEBUG_FUNCPTR (gst_v4l2_vp9_enc_get_property);
|
||||
baseclass->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2_vp9_enc_negotiate);
|
||||
|
||||
baseclass->codec_name = "VP9";
|
||||
baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE;
|
||||
baseclass->profile_to_string = v4l2_profile_to_string;
|
||||
baseclass->profile_from_string = v4l2_profile_from_string;
|
||||
}
|
||||
|
||||
/* Probing functions */
|
||||
|
|
Loading…
Reference in a new issue