mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
autovideoconvert: Handle passing bin description instead of factories
This way we can build our own well know bins for conversion keeping the code simple. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/899>
This commit is contained in:
parent
292d8453d3
commit
b0fdbcec64
7 changed files with 451 additions and 362 deletions
|
@ -43,6 +43,8 @@
|
||||||
#include "gstautoconvert.h"
|
#include "gstautoconvert.h"
|
||||||
#include <gst/pbutils/pbutils.h>
|
#include <gst/pbutils/pbutils.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY (autoconvert_debug);
|
||||||
|
#define GST_CAT_DEFAULT (autoconvert_debug)
|
||||||
struct _GstAutoConvert
|
struct _GstAutoConvert
|
||||||
{
|
{
|
||||||
GstBaseAutoConvert parent;
|
GstBaseAutoConvert parent;
|
||||||
|
@ -155,6 +157,9 @@ gst_auto_convert_class_init (GstAutoConvertClass * klass)
|
||||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (autoconvert_debug, "autoconvert", 0,
|
||||||
|
"Auto convert element");
|
||||||
|
|
||||||
gobject_class->set_property = gst_auto_convert_set_property;
|
gobject_class->set_property = gst_auto_convert_set_property;
|
||||||
gobject_class->get_property = gst_auto_convert_get_property;
|
gobject_class->get_property = gst_auto_convert_get_property;
|
||||||
|
|
||||||
|
@ -187,6 +192,8 @@ gst_auto_convert_class_init (GstAutoConvertClass * klass)
|
||||||
"An element factory name", NULL,
|
"An element factory name", NULL,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
GST_BASE_AUTO_CONVERT_CLASS (klass)->registers_filters = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright 2010 ST-Ericsson SA
|
* Copyright 2010 ST-Ericsson SA
|
||||||
* @author: Benjamin Gaignard <benjamin.gaignard@stericsson.com>
|
* @author: Benjamin Gaignard <benjamin.gaignard@stericsson.com>
|
||||||
|
* Copyright 2023 Igalia S.L.
|
||||||
|
* @author: Thibault Saunier <tsaunier@igalia.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -39,215 +41,20 @@ GST_DEBUG_CATEGORY (autovideoconvert_debug);
|
||||||
|
|
||||||
struct _GstAutoVideoConvert
|
struct _GstAutoVideoConvert
|
||||||
{
|
{
|
||||||
GstAutoConvert parent;
|
GstBaseAutoConvert parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (GstAutoVideoConvert, gst_auto_video_convert,
|
G_DEFINE_TYPE (GstAutoVideoConvert, gst_auto_video_convert,
|
||||||
GST_TYPE_AUTO_CONVERT);
|
GST_TYPE_BASE_AUTO_CONVERT);
|
||||||
|
|
||||||
GST_ELEMENT_REGISTER_DEFINE (autovideoconvert, "autovideoconvert",
|
GST_ELEMENT_REGISTER_DEFINE (autovideoconvert, "autovideoconvert",
|
||||||
GST_RANK_NONE, gst_auto_video_convert_get_type ());
|
GST_RANK_NONE, gst_auto_video_convert_get_type ());
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_auto_video_convert_element_filter (GstPluginFeature * feature,
|
|
||||||
GstAutoVideoConvert * autovideoconvert)
|
|
||||||
{
|
|
||||||
const gchar *klass;
|
|
||||||
|
|
||||||
/* we only care about element factories */
|
|
||||||
if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature)))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (!g_strcmp0 (GST_OBJECT_NAME (feature), "autovideoconvert"))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (gst_plugin_feature_get_rank (feature) <= GST_RANK_NONE)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY_CAST (feature),
|
|
||||||
GST_ELEMENT_METADATA_KLASS);
|
|
||||||
/* only select color space converter */
|
|
||||||
if (strstr (klass, "Colorspace") && strstr (klass, "Scaler") &&
|
|
||||||
strstr (klass, "Converter") && strstr (klass, "Video")) {
|
|
||||||
GST_DEBUG_OBJECT (autovideoconvert,
|
|
||||||
"gst_auto_video_convert_element_filter found %s",
|
|
||||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE_CAST (feature)));
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
const gchar *name;
|
|
||||||
const gchar *bindesc;
|
|
||||||
GstRank rank;
|
|
||||||
} KnownBin;
|
|
||||||
|
|
||||||
#define GST_AUTOCONVERT_WNBIN_QUARK g_quark_from_static_string("autovideoconvert-wn-bin-quark")
|
|
||||||
static void
|
|
||||||
gst_auto_convert_wn_bin_class_init (GstBinClass * class)
|
|
||||||
{
|
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (class);
|
|
||||||
KnownBin *b = g_type_get_qdata (G_OBJECT_CLASS_TYPE (class),
|
|
||||||
GST_AUTOCONVERT_WNBIN_QUARK);
|
|
||||||
gchar **factory_names = g_strsplit (b->bindesc, " ! ", -1);
|
|
||||||
gint nfactories = 0;
|
|
||||||
GstElementFactory *factory;
|
|
||||||
GstStaticPadTemplate *template = NULL;
|
|
||||||
|
|
||||||
for (nfactories = 0; factory_names[nfactories + 1]; nfactories++);
|
|
||||||
|
|
||||||
factory = gst_element_factory_find (factory_names[0]);
|
|
||||||
for (GList * tmp =
|
|
||||||
(GList *) gst_element_factory_get_static_pad_templates (factory); tmp;
|
|
||||||
tmp = tmp->next) {
|
|
||||||
if (((GstStaticPadTemplate *) tmp->data)->direction == GST_PAD_SINK) {
|
|
||||||
template = tmp->data;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gst_element_class_add_static_pad_template (element_class, template);
|
|
||||||
|
|
||||||
template = NULL;
|
|
||||||
factory = gst_element_factory_find (factory_names[nfactories]);
|
|
||||||
for (GList * tmp =
|
|
||||||
(GList *) gst_element_factory_get_static_pad_templates (factory); tmp;
|
|
||||||
tmp = tmp->next) {
|
|
||||||
if (((GstStaticPadTemplate *) tmp->data)->direction == GST_PAD_SRC) {
|
|
||||||
template = tmp->data;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_assert (template);
|
|
||||||
gst_element_class_add_static_pad_template (element_class, template);
|
|
||||||
|
|
||||||
gst_element_class_set_metadata (element_class, b->name,
|
|
||||||
"Scaler/Colorspace/Converter/Video", b->name,
|
|
||||||
"Thibault Saunier <tsaunier@igalia.com>");
|
|
||||||
|
|
||||||
g_strfreev (factory_names);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_auto_convert_wn_bin_init (GstBin * self)
|
|
||||||
{
|
|
||||||
KnownBin *b =
|
|
||||||
g_type_get_qdata (G_OBJECT_TYPE (self), GST_AUTOCONVERT_WNBIN_QUARK);
|
|
||||||
GError *err = NULL;
|
|
||||||
GstElement *subbin = gst_parse_bin_from_description (b->bindesc, TRUE, &err);
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
g_error ("%s couldn't be built?!: %s", b->name, err->message);
|
|
||||||
|
|
||||||
gst_bin_add (self, subbin);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (self), gst_ghost_pad_new ("sink",
|
|
||||||
subbin->sinkpads->data));
|
|
||||||
gst_element_add_pad (GST_ELEMENT (self), gst_ghost_pad_new ("src",
|
|
||||||
subbin->srcpads->data));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
register_well_known_bins (void)
|
|
||||||
{
|
|
||||||
GTypeInfo typeinfo = {
|
|
||||||
sizeof (GstBinClass),
|
|
||||||
(GBaseInitFunc) NULL,
|
|
||||||
NULL,
|
|
||||||
(GClassInitFunc) gst_auto_convert_wn_bin_class_init,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
sizeof (GstBin),
|
|
||||||
0,
|
|
||||||
(GInstanceInitFunc) gst_auto_convert_wn_bin_init,
|
|
||||||
};
|
|
||||||
/* *INDENT-OFF* */
|
|
||||||
const KnownBin subbins[] = {
|
|
||||||
{
|
|
||||||
.name = "auto+bayer2rgbcolorconvert",
|
|
||||||
.bindesc = "bayer2rgb ! videoconvertscale ! videoflip method=automatic ! videoconvertscale",
|
|
||||||
.rank = GST_RANK_SECONDARY,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "auto+colorconvertrgb2bayer",
|
|
||||||
.bindesc = "videoconvertscale ! videoflip method=automatic ! videoconvertscale ! rgb2bayer",
|
|
||||||
.rank = GST_RANK_SECONDARY,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
/* Fallback to only videoconvertscale if videoflip is not available */
|
|
||||||
.name = "auto+colorconvert-fallback",
|
|
||||||
.bindesc = "videoconvertscale",
|
|
||||||
.rank = GST_RANK_MARGINAL,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "auto+colorconvert",
|
|
||||||
.bindesc = "videoconvertscale ! videoflip method=automatic ! videoconvertscale",
|
|
||||||
.rank = GST_RANK_SECONDARY,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "auto+glcolorconvert",
|
|
||||||
.bindesc = "glcolorconvert ! glcolorscale ! glvideoflip method=automatic ! glcolorconvert",
|
|
||||||
.rank = GST_RANK_PRIMARY,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
/* *INDENT-ON* */
|
|
||||||
|
|
||||||
for (gint i = 0; i < G_N_ELEMENTS (subbins); i++) {
|
|
||||||
GType type = 0;
|
|
||||||
KnownBin *b = NULL;
|
|
||||||
GstElement *subbin = gst_parse_launch (subbins[i].bindesc, NULL);
|
|
||||||
|
|
||||||
if (!subbin) {
|
|
||||||
GST_INFO ("Ignoring possible Converting scaler: %s '%s'", subbins[i].name,
|
|
||||||
subbins[i].bindesc);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_object_unref (subbin);
|
|
||||||
|
|
||||||
type = g_type_register_static (GST_TYPE_BIN, subbins[i].name, &typeinfo, 0);
|
|
||||||
b = g_malloc0 (sizeof (KnownBin));
|
|
||||||
b->name = g_strdup (subbins[i].name);
|
|
||||||
b->bindesc = g_strdup (subbins[i].bindesc);
|
|
||||||
b->rank = subbins[i].rank;
|
|
||||||
|
|
||||||
g_type_set_qdata (type, GST_AUTOCONVERT_WNBIN_QUARK, b);
|
|
||||||
|
|
||||||
if (!gst_element_register (NULL, b->name, b->rank, type)) {
|
|
||||||
g_warning ("Failed to register %s", "autoglcolorconverter");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GList *
|
|
||||||
gst_auto_video_convert_create_factory_list (GstAutoConvert * autoconvert)
|
|
||||||
{
|
|
||||||
GList *result = NULL;
|
|
||||||
static gpointer registered_well_known_bins = FALSE;
|
|
||||||
|
|
||||||
if (g_once_init_enter (®istered_well_known_bins)) {
|
|
||||||
register_well_known_bins ();
|
|
||||||
g_once_init_leave (®istered_well_known_bins, (gpointer) TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get the feature list using the filter */
|
|
||||||
result = gst_registry_feature_filter (gst_registry_get (),
|
|
||||||
(GstPluginFeatureFilter) gst_auto_video_convert_element_filter,
|
|
||||||
FALSE, autoconvert);
|
|
||||||
|
|
||||||
/* sort on rank and name */
|
|
||||||
result = g_list_sort (result, gst_plugin_feature_rank_compare_func);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_auto_video_convert_class_init (GstAutoVideoConvertClass * klass)
|
gst_auto_video_convert_class_init (GstAutoVideoConvertClass * klass)
|
||||||
{
|
{
|
||||||
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
||||||
|
|
||||||
((GstAutoConvertClass *) klass)->load_factories =
|
|
||||||
gst_auto_video_convert_create_factory_list;
|
|
||||||
GST_DEBUG_CATEGORY_INIT (autovideoconvert_debug, "autovideoconvert", 0,
|
GST_DEBUG_CATEGORY_INIT (autovideoconvert_debug, "autovideoconvert", 0,
|
||||||
"Auto color space converter");
|
"Auto color space converter");
|
||||||
|
|
||||||
|
@ -255,10 +62,123 @@ gst_auto_video_convert_class_init (GstAutoVideoConvertClass * klass)
|
||||||
"Select color space converter and scalers based on caps",
|
"Select color space converter and scalers based on caps",
|
||||||
"Bin/Colorspace/Scale/Video/Converter",
|
"Bin/Colorspace/Scale/Video/Converter",
|
||||||
"Selects the right color space converter based on the caps",
|
"Selects the right color space converter based on the caps",
|
||||||
"Benjamin Gaignard <benjamin.gaignard@stericsson.com>");
|
"Thibault Saunier <tsaunier@igalia.com>");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_auto_video_convert_init (GstAutoVideoConvert * autovideoconvert)
|
gst_auto_video_convert_init (GstAutoVideoConvert * autovideoconvert)
|
||||||
{
|
{
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
static const GstAutoVideoFilterGenerator gen[] = {
|
||||||
|
{
|
||||||
|
.first_elements = { "bayer2rgb", NULL},
|
||||||
|
.colorspace_converters = { "videoconvertscale", NULL },
|
||||||
|
.last_elements = { NULL } ,
|
||||||
|
.filters = { NULL},
|
||||||
|
.rank = GST_RANK_SECONDARY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.first_elements = { NULL, },
|
||||||
|
.colorspace_converters = { "videoconvertscale", NULL },
|
||||||
|
.last_elements = { "rgb2bayer", NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_SECONDARY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.first_elements = { NULL, },
|
||||||
|
.colorspace_converters = { "videoconvertscale", NULL },
|
||||||
|
.last_elements = { NULL, },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_SECONDARY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.first_elements = { NULL, },
|
||||||
|
.colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL },
|
||||||
|
.last_elements = { NULL, },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_PRIMARY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.first_elements = { "glupload", },
|
||||||
|
.colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL },
|
||||||
|
.last_elements = { NULL, },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_PRIMARY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.first_elements = { "videoconvertscale", "glupload", NULL },
|
||||||
|
.colorspace_converters = { NULL },
|
||||||
|
.last_elements = { NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_MARGINAL + 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.first_elements = { "glcolorconvert", "gldownload", NULL },
|
||||||
|
.colorspace_converters = { NULL },
|
||||||
|
.last_elements = { NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_MARGINAL + 2,
|
||||||
|
},
|
||||||
|
{ /* Worst case we upload/download as required */
|
||||||
|
.first_elements = { "glupload", "gldownload", NULL },
|
||||||
|
.colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL },
|
||||||
|
.last_elements = { "glupload", "gldownload", NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_MARGINAL + 1,
|
||||||
|
},
|
||||||
|
{ /* Pure cuda is preferred */
|
||||||
|
.first_elements = { NULL },
|
||||||
|
.colorspace_converters = { "cudaconvertscale", NULL },
|
||||||
|
.last_elements = { NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_PRIMARY,
|
||||||
|
},
|
||||||
|
{ /* CUDA -> GL */
|
||||||
|
.first_elements = { "capsfilter caps=video/x-raw(memory:CUDAMemory)", "cudadownload", NULL },
|
||||||
|
.colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL },
|
||||||
|
.last_elements = { "glupload", "gldownload", NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_SECONDARY,
|
||||||
|
},
|
||||||
|
{ /* GL memory to cuda */
|
||||||
|
.first_elements = { NULL },
|
||||||
|
.colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL },
|
||||||
|
.last_elements = { "cudaupload", "capsfilter caps=video/x-raw(memory:CUDAMemory)", NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_MARGINAL,
|
||||||
|
},
|
||||||
|
{ /* System memory to cuda */
|
||||||
|
.first_elements = { NULL },
|
||||||
|
.colorspace_converters = { "videoconvertscale", NULL },
|
||||||
|
.last_elements = { "cudaupload", "capsfilter caps=video/x-raw(memory:CUDAMemory)", NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_MARGINAL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.first_elements = { NULL, },
|
||||||
|
.colorspace_converters = { "d3d11convert", NULL },
|
||||||
|
.last_elements = { NULL, },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_PRIMARY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.first_elements = { "d3d11download", "d3d11upload", NULL},
|
||||||
|
.colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL },
|
||||||
|
.last_elements = { "d3d11download", "d3d11upload", NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = GST_RANK_MARGINAL,
|
||||||
|
},
|
||||||
|
{ /* Worst case we upload/download as required */
|
||||||
|
.first_elements = { NULL},
|
||||||
|
.colorspace_converters = { NULL },
|
||||||
|
.last_elements = { NULL },
|
||||||
|
.filters = { NULL },
|
||||||
|
.rank = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
|
||||||
|
gst_auto_video_register_well_known_bins (GST_BASE_AUTO_CONVERT
|
||||||
|
(autovideoconvert), gen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright 2010 ST-Ericsson SA
|
* Copyright 2010 ST-Ericsson SA
|
||||||
* @author: Benjamin Gaignard <benjamin.gaignard@stericsson.com>
|
* @author: Benjamin Gaignard <benjamin.gaignard@stericsson.com>
|
||||||
|
* Copyright 2023 Igalia S.L.
|
||||||
|
* @author: Thibault Saunier <tsaunier@igalia.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -27,8 +29,20 @@
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE(GstAutoVideoConvert, gst_auto_video_convert, GST, AUTO_VIDEO_CONVERT, GstAutoConvert);
|
G_DECLARE_FINAL_TYPE(GstAutoVideoConvert, gst_auto_video_convert, GST, AUTO_VIDEO_CONVERT, GstBaseAutoConvert);
|
||||||
GST_ELEMENT_REGISTER_DECLARE (autovideoconvert);
|
GST_ELEMENT_REGISTER_DECLARE (autovideoconvert);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const gchar *first_elements[4];
|
||||||
|
const gchar *colorspace_converters[4];
|
||||||
|
const gchar *last_elements[4];
|
||||||
|
|
||||||
|
const gchar *possible_filters[4];
|
||||||
|
GstRank rank;
|
||||||
|
} GstAutoVideoConvertFilterBinsGenerator;
|
||||||
|
|
||||||
|
void gst_auto_video_register_well_known_bins (GstAutoVideoConvert *self, GstAutoVideoConvertFilterBinsGenerator *gen);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
#endif /* __GST_AUTO_VIDEO_CONVERT_H__ */
|
#endif /* __GST_AUTO_VIDEO_CONVERT_H__ */
|
||||||
|
|
|
@ -102,8 +102,8 @@ static gboolean gst_base_auto_convert_internal_src_event (GstPad * pad,
|
||||||
GstObject * parent, GstEvent * event);
|
GstObject * parent, GstEvent * event);
|
||||||
static gboolean gst_base_auto_convert_internal_src_query (GstPad * pad,
|
static gboolean gst_base_auto_convert_internal_src_query (GstPad * pad,
|
||||||
GstObject * parent, GstQuery * query);
|
GstObject * parent, GstQuery * query);
|
||||||
static GList *gst_base_auto_convert_get_or_load_factories (GstBaseAutoConvert *
|
static GList *gst_base_auto_convert_get_or_load_filters_info (GstBaseAutoConvert
|
||||||
self);
|
* self);
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (GstBaseAutoConvertPad, gst_base_auto_convert_pad, GST,
|
G_DECLARE_FINAL_TYPE (GstBaseAutoConvertPad, gst_base_auto_convert_pad, GST,
|
||||||
BASE_AUTO_CONVERT_PAD, GstPad);
|
BASE_AUTO_CONVERT_PAD, GstPad);
|
||||||
|
@ -184,6 +184,112 @@ gst_base_auto_convert_element_removed (GstBin * bin, GstElement * child)
|
||||||
g_hash_table_remove (self->elements, child);
|
g_hash_table_remove (self->elements, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_auto_convert_filter_info_free (GstAutoConvertFilterInfo * knwon_bin)
|
||||||
|
{
|
||||||
|
g_free (knwon_bin->name);
|
||||||
|
g_free (knwon_bin->bindesc);
|
||||||
|
|
||||||
|
g_free (knwon_bin);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
g_auto_convert_filter_info_compare (GstAutoConvertFilterInfo * b1,
|
||||||
|
GstAutoConvertFilterInfo * b2)
|
||||||
|
{
|
||||||
|
gint diff;
|
||||||
|
|
||||||
|
diff = b2->rank - b1->rank;
|
||||||
|
if (diff != 0)
|
||||||
|
return diff;
|
||||||
|
|
||||||
|
diff = g_strcmp0 (b2->name, b1->name);
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstCaps *
|
||||||
|
gst_base_auto_convert_get_template_caps_for (GstElement * subbin,
|
||||||
|
GstPadDirection dir)
|
||||||
|
{
|
||||||
|
GstElement *element = NULL;
|
||||||
|
GstPad *pad = NULL;
|
||||||
|
GstCaps *res = NULL;
|
||||||
|
|
||||||
|
g_assert (g_list_length (subbin->sinkpads) == 1);
|
||||||
|
g_assert (g_list_length (subbin->srcpads) == 1);
|
||||||
|
if (GST_IS_BIN (subbin)) {
|
||||||
|
GstPad *ghostpad =
|
||||||
|
(dir == GST_PAD_SINK) ? subbin->sinkpads->data : subbin->srcpads->data;
|
||||||
|
GstPad *internal = gst_pad_get_single_internal_link (ghostpad);
|
||||||
|
|
||||||
|
pad = gst_pad_get_peer (internal);
|
||||||
|
|
||||||
|
gst_object_unref (internal);
|
||||||
|
} else {
|
||||||
|
pad =
|
||||||
|
(dir ==
|
||||||
|
GST_PAD_SINK) ? gst_object_ref (subbin->
|
||||||
|
sinkpads->data) : gst_object_ref (subbin->srcpads->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
element = GST_ELEMENT (GST_OBJECT_PARENT (pad));
|
||||||
|
g_assert (element);
|
||||||
|
|
||||||
|
if (!g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (element)),
|
||||||
|
"capsfilter")) {
|
||||||
|
g_object_get (G_OBJECT (element), "caps", &res, NULL);
|
||||||
|
} else {
|
||||||
|
res = gst_pad_get_pad_template_caps (pad);
|
||||||
|
}
|
||||||
|
gst_object_unref (pad);
|
||||||
|
|
||||||
|
return gst_caps_make_writable (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_base_auto_convert_register_filter (GstBaseAutoConvert * self, gchar * name,
|
||||||
|
gchar * bindesc, GstRank rank)
|
||||||
|
{
|
||||||
|
g_assert (name);
|
||||||
|
|
||||||
|
for (GList * tmp = self->filters_info; tmp; tmp = tmp->next) {
|
||||||
|
g_return_val_if_fail (g_strcmp0 (name,
|
||||||
|
((GstAutoConvertFilterInfo *) tmp->data)->name), FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
GError *err = NULL;
|
||||||
|
bindesc = g_strchomp (bindesc);
|
||||||
|
GstElement *subbin = gst_parse_bin_from_description_full (bindesc, TRUE,
|
||||||
|
NULL, GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS | GST_PARSE_FLAG_PLACE_IN_BIN,
|
||||||
|
&err);
|
||||||
|
|
||||||
|
if (!subbin) {
|
||||||
|
GST_INFO ("Could not create subbin for %s", name);
|
||||||
|
g_free (name);
|
||||||
|
g_free (bindesc);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstAutoConvertFilterInfo *filter_info = g_new0 (GstAutoConvertFilterInfo, 1);
|
||||||
|
filter_info->sink_caps =
|
||||||
|
gst_base_auto_convert_get_template_caps_for (subbin, GST_PAD_SINK);
|
||||||
|
filter_info->src_caps =
|
||||||
|
gst_base_auto_convert_get_template_caps_for (subbin, GST_PAD_SRC);
|
||||||
|
filter_info->name = name;
|
||||||
|
filter_info->bindesc = bindesc;
|
||||||
|
filter_info->rank = rank;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (self);
|
||||||
|
self->filters_info =
|
||||||
|
g_list_insert_sorted (self->filters_info, filter_info,
|
||||||
|
(GCompareFunc) g_auto_convert_filter_info_compare);
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_base_auto_convert_class_init (GstBaseAutoConvertClass * klass)
|
gst_base_auto_convert_class_init (GstBaseAutoConvertClass * klass)
|
||||||
{
|
{
|
||||||
|
@ -201,6 +307,8 @@ gst_base_auto_convert_class_init (GstBaseAutoConvertClass * klass)
|
||||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_auto_convert_finalize);
|
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_auto_convert_finalize);
|
||||||
|
|
||||||
gstbin_class->element_removed = gst_base_auto_convert_element_removed;
|
gstbin_class->element_removed = gst_base_auto_convert_element_removed;
|
||||||
|
|
||||||
|
klass->registers_filters = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -255,34 +363,12 @@ gst_base_auto_convert_finalize (GObject * object)
|
||||||
if (self->factories)
|
if (self->factories)
|
||||||
gst_plugin_feature_list_free (self->factories);
|
gst_plugin_feature_list_free (self->factories);
|
||||||
g_hash_table_unref (self->elements);
|
g_hash_table_unref (self->elements);
|
||||||
|
g_list_free_full (self->filters_info,
|
||||||
|
(GDestroyNotify) gst_auto_convert_filter_info_free);
|
||||||
|
|
||||||
G_OBJECT_CLASS (gst_base_auto_convert_parent_class)->finalize (object);
|
G_OBJECT_CLASS (gst_base_auto_convert_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstElement *
|
|
||||||
gst_base_auto_convert_get_element_by_type (GstBaseAutoConvert * self,
|
|
||||||
GType type)
|
|
||||||
{
|
|
||||||
GList *item, *elements;
|
|
||||||
GstElement *element = NULL;
|
|
||||||
|
|
||||||
g_return_val_if_fail (type != 0, NULL);
|
|
||||||
|
|
||||||
GST_BASEAUTOCONVERT_LOCK (self);
|
|
||||||
elements = g_hash_table_get_keys (self->elements);
|
|
||||||
for (item = elements; item; item = item->next) {
|
|
||||||
if (G_OBJECT_TYPE (item->data) == type) {
|
|
||||||
element = gst_object_ref (item->data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GST_BASEAUTOCONVERT_UNLOCK (self);
|
|
||||||
|
|
||||||
g_list_free (elements);
|
|
||||||
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get_pad_by_direction:
|
* get_pad_by_direction:
|
||||||
* @element: The Element
|
* @element: The Element
|
||||||
|
@ -401,18 +487,28 @@ gst_base_auto_convert_get_internal_srcpad (GstBaseAutoConvert * self)
|
||||||
|
|
||||||
static GstElement *
|
static GstElement *
|
||||||
gst_base_auto_convert_add_element (GstBaseAutoConvert * self,
|
gst_base_auto_convert_add_element (GstBaseAutoConvert * self,
|
||||||
GstElementFactory * factory)
|
GstAutoConvertFilterInfo * filter_info)
|
||||||
{
|
{
|
||||||
GstElement *element = NULL;
|
GstElement *element = NULL;
|
||||||
InternalPads *pads;
|
InternalPads *pads;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Adding element %s to the baseautoconvert bin",
|
GST_DEBUG_OBJECT (self, "Adding element %s to the baseautoconvert bin",
|
||||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
|
filter_info->name);
|
||||||
|
|
||||||
|
element = gst_parse_bin_from_description_full (filter_info->bindesc, TRUE,
|
||||||
|
NULL, GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS | GST_PARSE_FLAG_PLACE_IN_BIN,
|
||||||
|
&error);
|
||||||
|
if (!element) {
|
||||||
|
GST_INFO_OBJECT (self, "Could not build %s: %s", filter_info->name,
|
||||||
|
error->message);
|
||||||
|
|
||||||
|
g_error_free (error);
|
||||||
|
|
||||||
element = gst_element_factory_create (factory, NULL);
|
|
||||||
if (!element)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_object_set_name (GST_OBJECT (element), filter_info->name);
|
||||||
pads = internal_pads_new (self, GST_OBJECT_NAME (element));
|
pads = internal_pads_new (self, GST_OBJECT_NAME (element));
|
||||||
g_hash_table_insert (self->elements, element, pads);
|
g_hash_table_insert (self->elements, element, pads);
|
||||||
|
|
||||||
|
@ -434,26 +530,17 @@ gst_base_auto_convert_add_element (GstBaseAutoConvert * self,
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstElement *
|
static GstElement *
|
||||||
gst_base_auto_convert_get_or_make_element_from_factory (GstBaseAutoConvert *
|
gst_base_auto_convert_get_or_make_element_from_filter_info (GstBaseAutoConvert *
|
||||||
self, GstElementFactory * factory)
|
self, GstAutoConvertFilterInfo * nb)
|
||||||
{
|
{
|
||||||
GstElement *element = NULL;
|
GstElement *element = NULL;
|
||||||
GstElementFactory *loaded_factory =
|
|
||||||
GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
|
|
||||||
(factory)));
|
|
||||||
|
|
||||||
if (!loaded_factory)
|
element = gst_bin_get_by_name (GST_BIN (self), nb->name);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
element = gst_base_auto_convert_get_element_by_type (self,
|
|
||||||
gst_element_factory_get_element_type (loaded_factory));
|
|
||||||
|
|
||||||
if (!element) {
|
if (!element) {
|
||||||
element = gst_base_auto_convert_add_element (self, loaded_factory);
|
element = gst_base_auto_convert_add_element (self, nb);
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_object_unref (loaded_factory);
|
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,51 +551,25 @@ gst_base_auto_convert_get_or_make_element_from_factory (GstBaseAutoConvert *
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
factory_can_intersect (GstBaseAutoConvert * self,
|
filter_info_can_intersect (GstBaseAutoConvert * self,
|
||||||
GstElementFactory * factory, GstPadDirection direction, GstCaps * caps)
|
GstAutoConvertFilterInfo * filter_info, GstPadDirection direction,
|
||||||
|
GstCaps * caps)
|
||||||
{
|
{
|
||||||
const GList *templates;
|
gboolean res;
|
||||||
gint has_direction = FALSE;
|
GST_LOG_OBJECT (self, "Checking if %s (bin_desc=%s) supports %s caps:",
|
||||||
gboolean ret = FALSE;
|
filter_info->name, filter_info->bindesc,
|
||||||
|
direction == GST_PAD_SINK ? "sink" : "src");
|
||||||
|
GST_LOG_OBJECT (self, "Supported caps: %" GST_PTR_FORMAT,
|
||||||
|
direction ==
|
||||||
|
GST_PAD_SINK ? filter_info->sink_caps : filter_info->src_caps);
|
||||||
|
GST_LOG_OBJECT (self, "Caps: %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
g_return_val_if_fail (factory != NULL, FALSE);
|
res =
|
||||||
g_return_val_if_fail (caps != NULL, FALSE);
|
gst_caps_can_intersect (direction ==
|
||||||
|
GST_PAD_SINK ? filter_info->sink_caps : filter_info->src_caps, caps);
|
||||||
|
GST_LOG_OBJECT (self, "Intersect result: %d", res);
|
||||||
|
|
||||||
templates = gst_element_factory_get_static_pad_templates (factory);
|
return res;
|
||||||
|
|
||||||
while (templates) {
|
|
||||||
GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
|
|
||||||
|
|
||||||
if (template->direction == direction) {
|
|
||||||
GstCaps *tmpl_caps = NULL;
|
|
||||||
gboolean intersect;
|
|
||||||
|
|
||||||
/* If there is more than one pad in this direction, we return FALSE
|
|
||||||
* Only transform elements (with one sink and one source pad)
|
|
||||||
* are accepted
|
|
||||||
*/
|
|
||||||
if (has_direction) {
|
|
||||||
GST_ERROR_OBJECT (self, "Factory %p"
|
|
||||||
" has more than one static template with dir %d",
|
|
||||||
template, direction);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
has_direction = TRUE;
|
|
||||||
|
|
||||||
tmpl_caps = gst_static_caps_get (&template->static_caps);
|
|
||||||
intersect = gst_caps_can_intersect (tmpl_caps, caps);
|
|
||||||
GST_DEBUG_OBJECT (self, "Factories %" GST_PTR_FORMAT
|
|
||||||
" static caps %" GST_PTR_FORMAT " and caps %" GST_PTR_FORMAT
|
|
||||||
" can%s intersect", factory, tmpl_caps, caps,
|
|
||||||
intersect ? "" : " not");
|
|
||||||
gst_caps_unref (tmpl_caps);
|
|
||||||
|
|
||||||
ret |= intersect;
|
|
||||||
}
|
|
||||||
templates = g_list_next (templates);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -633,6 +694,9 @@ gst_base_auto_convert_activate_element (GstBaseAutoConvert * self,
|
||||||
GST_OBJECT_NAME (GST_OBJECT (element)));
|
GST_OBJECT_NAME (GST_OBJECT (element)));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
GST_DEBUG_OBJECT (element, "Activating element %s",
|
||||||
|
res ? "succeeded" : "failed");
|
||||||
|
|
||||||
gst_object_unref (element);
|
gst_object_unref (element);
|
||||||
internal_pads_unref (pads);
|
internal_pads_unref (pads);
|
||||||
gst_clear_object (&srcpad);
|
gst_clear_object (&srcpad);
|
||||||
|
@ -677,6 +741,22 @@ gst_base_auto_convert_iterate_internal_links (GstPad * pad, GstObject * parent)
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstAutoConvertFilterInfo *
|
||||||
|
gst_auto_convert_get_filter_info (GstBaseAutoConvert * self,
|
||||||
|
GstElement * element)
|
||||||
|
{
|
||||||
|
GList *tmp;
|
||||||
|
|
||||||
|
for (tmp = self->filters_info; tmp; tmp = tmp->next) {
|
||||||
|
GstAutoConvertFilterInfo *filter_info = tmp->data;
|
||||||
|
|
||||||
|
if (!g_strcmp0 (filter_info->name, GST_OBJECT_NAME (element)))
|
||||||
|
return filter_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is already an internal element, it will try to call set_caps on it
|
* If there is already an internal element, it will try to call set_caps on it
|
||||||
*
|
*
|
||||||
|
@ -689,9 +769,9 @@ static gboolean
|
||||||
gst_base_auto_convert_sink_setcaps (GstBaseAutoConvert * self, GstCaps * caps,
|
gst_base_auto_convert_sink_setcaps (GstBaseAutoConvert * self, GstCaps * caps,
|
||||||
gboolean check_downstream)
|
gboolean check_downstream)
|
||||||
{
|
{
|
||||||
GList *elem;
|
GList *tmp;
|
||||||
GstCaps *other_caps = NULL;
|
GstCaps *other_caps = NULL;
|
||||||
GList *factories;
|
GList *filters_info = NULL;
|
||||||
GstCaps *current_caps = NULL;
|
GstCaps *current_caps = NULL;
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
GstElement *current_subelement = NULL;
|
GstElement *current_subelement = NULL;
|
||||||
|
@ -709,66 +789,81 @@ gst_base_auto_convert_sink_setcaps (GstBaseAutoConvert * self, GstCaps * caps,
|
||||||
other_caps = gst_pad_peer_query_caps (self->srcpad, NULL);
|
other_caps = gst_pad_peer_query_caps (self->srcpad, NULL);
|
||||||
|
|
||||||
current_subelement = gst_base_auto_convert_get_subelement (self);
|
current_subelement = gst_base_auto_convert_get_subelement (self);
|
||||||
|
GST_DEBUG_OBJECT (self,
|
||||||
|
"'%" GST_PTR_FORMAT "' Setting caps to: %" GST_PTR_FORMAT
|
||||||
|
" - other caps: %" GST_PTR_FORMAT, current_subelement, caps, other_caps);
|
||||||
if (current_subelement) {
|
if (current_subelement) {
|
||||||
if (gst_pad_peer_query_accept_caps (self->current_internal_srcpad, caps)) {
|
if (gst_pad_peer_query_accept_caps (self->current_internal_srcpad, caps)) {
|
||||||
|
GstAutoConvertFilterInfo *filter_info =
|
||||||
|
gst_auto_convert_get_filter_info (self, current_subelement);
|
||||||
|
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
if (other_caps) {
|
if (other_caps) {
|
||||||
GstElementFactory *factory =
|
GST_DEBUG_OBJECT (self,
|
||||||
gst_element_get_factory (current_subelement);
|
"Checking if known bin %s can intersect with %" GST_PTR_FORMAT,
|
||||||
|
filter_info->name, other_caps);
|
||||||
if (!factory_can_intersect (self, factory, GST_PAD_SRC, other_caps)) {
|
if (!filter_info_can_intersect (self, filter_info, GST_PAD_SRC,
|
||||||
|
other_caps)) {
|
||||||
GST_LOG_OBJECT (self,
|
GST_LOG_OBJECT (self,
|
||||||
"Factory %s does not accept src caps %" GST_PTR_FORMAT,
|
"filter_info %s does not accept src caps %" GST_PTR_FORMAT,
|
||||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
|
filter_info->name, other_caps);
|
||||||
other_caps);
|
|
||||||
res = FALSE;
|
res = FALSE;
|
||||||
}
|
}
|
||||||
|
GST_DEBUG_OBJECT (self, "Filter %s can intersect", filter_info->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
/* If we can set the new caps on the current element,
|
/* If we can set the new caps on the current element,
|
||||||
* then we just get out
|
* then we just get out
|
||||||
*/
|
*/
|
||||||
GST_ERROR_OBJECT (self, "Could set %s:%s to %" GST_PTR_FORMAT,
|
GST_DEBUG_OBJECT (self,
|
||||||
GST_DEBUG_PAD_NAME (self->current_internal_srcpad), caps);
|
"Could set %s:%s to %" GST_PTR_FORMAT " reusing %s",
|
||||||
|
GST_DEBUG_PAD_NAME (self->current_internal_srcpad), caps,
|
||||||
|
filter_info->name);
|
||||||
goto get_out;
|
goto get_out;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (self,
|
||||||
|
"Can't reuse currently configured subelement: %s",
|
||||||
|
filter_info->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check_downstream)
|
if (!check_downstream)
|
||||||
other_caps = gst_pad_peer_query_caps (self->srcpad, NULL);
|
other_caps = gst_pad_peer_query_caps (self->srcpad, NULL);
|
||||||
/* We already queries downstream caps otherwise */
|
/* We already queried downstream caps otherwise */
|
||||||
|
|
||||||
factories = gst_base_auto_convert_get_or_load_factories (self);
|
filters_info = gst_base_auto_convert_get_or_load_filters_info (self);
|
||||||
|
for (tmp = filters_info; tmp; tmp = g_list_next (tmp)) {
|
||||||
for (elem = factories; elem; elem = g_list_next (elem)) {
|
GstAutoConvertFilterInfo *filter_info = tmp->data;
|
||||||
GstElementFactory *factory = GST_ELEMENT_FACTORY (elem->data);
|
|
||||||
GstElement *element;
|
GstElement *element;
|
||||||
|
|
||||||
/* Lets first check if according to the static pad templates on the factory
|
GST_DEBUG_OBJECT (self, "Trying %s (bin_desc=%s)", filter_info->name,
|
||||||
|
filter_info->bindesc);
|
||||||
|
/* Lets first check if according to the static pad templates on the known bin
|
||||||
* these caps have any chance of success
|
* these caps have any chance of success
|
||||||
*/
|
*/
|
||||||
if (!factory_can_intersect (self, factory, GST_PAD_SINK, caps)) {
|
if (!filter_info_can_intersect (self, filter_info, GST_PAD_SINK, caps)) {
|
||||||
GST_LOG_OBJECT (self, "Factory %s does not accept sink caps %"
|
GST_DEBUG_OBJECT (self, "Known bin %s does not accept sink caps %"
|
||||||
GST_PTR_FORMAT,
|
GST_PTR_FORMAT, filter_info->name, caps);
|
||||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), caps);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (other_caps != NULL) {
|
if (other_caps != NULL) {
|
||||||
if (!factory_can_intersect (self, factory, GST_PAD_SRC, other_caps)) {
|
if (!filter_info_can_intersect (self, filter_info, GST_PAD_SRC,
|
||||||
GST_LOG_OBJECT (self,
|
other_caps)) {
|
||||||
"Factory %s does not accept src caps %" GST_PTR_FORMAT,
|
GST_DEBUG_OBJECT (self,
|
||||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
|
"Known bin %s does not accept src caps %" GST_PTR_FORMAT,
|
||||||
other_caps);
|
filter_info->name, other_caps);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
GST_DEBUG_OBJECT (self, "Filter %s can intersect", filter_info->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The element had a chance of success, lets make it */
|
/* The element had a chance of success, lets make it */
|
||||||
|
GST_DEBUG_OBJECT (self, "Trying bin %s", filter_info->name);
|
||||||
element =
|
element =
|
||||||
gst_base_auto_convert_get_or_make_element_from_factory (self, factory);
|
gst_base_auto_convert_get_or_make_element_from_filter_info (self,
|
||||||
|
filter_info);
|
||||||
if (!element)
|
if (!element)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -786,9 +881,10 @@ get_out:
|
||||||
gst_clear_caps (&other_caps);
|
gst_clear_caps (&other_caps);
|
||||||
gst_clear_caps (¤t_caps);
|
gst_clear_caps (¤t_caps);
|
||||||
|
|
||||||
if (!res)
|
if (!res) {
|
||||||
GST_WARNING_OBJECT (self,
|
GST_WARNING_OBJECT (self,
|
||||||
"Could not find a matching element for caps: %" GST_PTR_FORMAT, caps);
|
"Could not find a matching element for caps: %" GST_PTR_FORMAT, caps);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -870,32 +966,51 @@ compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GList *
|
static GList *
|
||||||
gst_base_auto_convert_get_or_load_factories (GstBaseAutoConvert * self)
|
gst_base_auto_convert_get_or_load_filters_info (GstBaseAutoConvert * self)
|
||||||
{
|
{
|
||||||
GList *all_factories;
|
GList *all_factories;
|
||||||
GstBaseAutoConvertClass *klass = GST_BASE_AUTO_CONVERT_GET_CLASS (self);
|
|
||||||
|
|
||||||
GST_OBJECT_LOCK (self);
|
GST_OBJECT_LOCK (self);
|
||||||
if (self->factories)
|
if (self->filters_info) {
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
goto done;
|
goto done;
|
||||||
GST_OBJECT_UNLOCK (self);
|
}
|
||||||
|
|
||||||
|
if (GST_BASE_AUTO_CONVERT_GET_CLASS (self)->registers_filters) {
|
||||||
|
GST_ERROR_OBJECT (self,
|
||||||
|
"Filters should have been registered but none found");
|
||||||
|
|
||||||
|
GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, ("No known filter found."),
|
||||||
|
(NULL));
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!self->factories) {
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
|
||||||
if (klass->load_factories) {
|
|
||||||
all_factories = klass->load_factories (self);
|
|
||||||
} else {
|
|
||||||
all_factories =
|
all_factories =
|
||||||
g_list_sort (gst_registry_feature_filter (gst_registry_get (),
|
g_list_sort (gst_registry_feature_filter (gst_registry_get (),
|
||||||
gst_base_auto_convert_default_filter_func, FALSE, NULL),
|
gst_base_auto_convert_default_filter_func, FALSE, NULL),
|
||||||
(GCompareFunc) compare_ranks);
|
(GCompareFunc) compare_ranks);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (self);
|
||||||
|
self->factories = all_factories;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_OBJECT_LOCK (self);
|
|
||||||
self->factories = all_factories;
|
|
||||||
|
|
||||||
done:
|
|
||||||
GST_OBJECT_UNLOCK (self);
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
|
||||||
return self->factories;
|
for (GList * tmp = self->factories; tmp; tmp = g_list_next (tmp)) {
|
||||||
|
GstElementFactory *factory = tmp->data;
|
||||||
|
|
||||||
|
gst_base_auto_convert_register_filter (self,
|
||||||
|
gst_object_get_name (GST_OBJECT (factory)),
|
||||||
|
gst_object_get_name (GST_OBJECT (factory)),
|
||||||
|
gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return self->filters_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In this case, we should almost always have an internal element, because
|
/* In this case, we should almost always have an internal element, because
|
||||||
|
@ -1078,7 +1193,7 @@ gst_base_auto_convert_getcaps (GstBaseAutoConvert * self, GstCaps * filter,
|
||||||
GstPadDirection dir)
|
GstPadDirection dir)
|
||||||
{
|
{
|
||||||
GstCaps *caps = NULL, *other_caps = NULL;
|
GstCaps *caps = NULL, *other_caps = NULL;
|
||||||
GList *elem, *factories;
|
GList *kb, *filters_info;
|
||||||
|
|
||||||
caps = gst_caps_new_empty ();
|
caps = gst_caps_new_empty ();
|
||||||
|
|
||||||
|
@ -1095,35 +1210,35 @@ gst_base_auto_convert_getcaps (GstBaseAutoConvert * self, GstCaps * filter,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
factories = gst_base_auto_convert_get_or_load_factories (self);
|
filters_info = gst_base_auto_convert_get_or_load_filters_info (self);
|
||||||
for (elem = factories; elem; elem = g_list_next (elem)) {
|
for (kb = filters_info; kb; kb = g_list_next (kb)) {
|
||||||
GstElementFactory *factory = GST_ELEMENT_FACTORY (elem->data);
|
GstAutoConvertFilterInfo *filter_info = kb->data;
|
||||||
GstElement *element = NULL;
|
GstElement *element = NULL;
|
||||||
GstCaps *element_caps;
|
GstCaps *element_caps;
|
||||||
InternalPads *pads;
|
InternalPads *pads;
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
if (!factory_can_intersect (self, factory, dir, filter)) {
|
if (!filter_info_can_intersect (self, filter_info, dir, filter)) {
|
||||||
GST_LOG_OBJECT (self,
|
GST_LOG_OBJECT (self,
|
||||||
"Factory %s does not accept src caps %" GST_PTR_FORMAT,
|
"Bin %s does not accept %s caps %" GST_PTR_FORMAT,
|
||||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
|
filter_info->name, dir == GST_PAD_SRC ? "src" : "sink", other_caps);
|
||||||
other_caps);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other_caps != NULL) {
|
if (other_caps != NULL) {
|
||||||
if (!factory_can_intersect (self, factory,
|
if (!filter_info_can_intersect (self, filter_info,
|
||||||
dir == GST_PAD_SINK ? GST_PAD_SRC : GST_PAD_SINK, other_caps)) {
|
dir == GST_PAD_SINK ? GST_PAD_SRC : GST_PAD_SINK, other_caps)) {
|
||||||
GST_LOG_OBJECT (self,
|
GST_LOG_OBJECT (self,
|
||||||
"Factory %s does not accept src caps %" GST_PTR_FORMAT,
|
"%s does not accept %s caps %" GST_PTR_FORMAT,
|
||||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
|
filter_info->name,
|
||||||
other_caps);
|
dir == GST_PAD_SINK ? "src" : "sink", other_caps);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
element = gst_base_auto_convert_get_or_make_element_from_factory (self,
|
element =
|
||||||
factory);
|
gst_base_auto_convert_get_or_make_element_from_filter_info (self,
|
||||||
|
filter_info);
|
||||||
if (element == NULL)
|
if (element == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1141,24 +1256,16 @@ gst_base_auto_convert_getcaps (GstBaseAutoConvert * self, GstCaps * filter,
|
||||||
if (gst_caps_is_any (caps))
|
if (gst_caps_is_any (caps))
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
const GList *tmp;
|
GstCaps *static_caps =
|
||||||
|
dir == GST_PAD_SRC ? filter_info->src_caps : filter_info->sink_caps;
|
||||||
|
|
||||||
for (tmp = gst_element_factory_get_static_pad_templates (factory);
|
if (static_caps) {
|
||||||
tmp; tmp = g_list_next (tmp)) {
|
caps = gst_caps_merge (caps, static_caps);
|
||||||
GstStaticPadTemplate *template = tmp->data;
|
|
||||||
|
|
||||||
if (GST_PAD_TEMPLATE_DIRECTION (template) == dir) {
|
|
||||||
GstCaps *static_caps = gst_static_pad_template_get_caps (template);
|
|
||||||
|
|
||||||
if (static_caps) {
|
|
||||||
caps = gst_caps_merge (caps, static_caps);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Early out, any is absorbing */
|
|
||||||
if (gst_caps_is_any (caps))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Early out, any is absorbing */
|
||||||
|
if (gst_caps_is_any (caps))
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1191,7 +1298,7 @@ gst_base_auto_convert_src_event (GstPad * pad, GstObject * parent,
|
||||||
gst_object_unref (internal_sinkpad);
|
gst_object_unref (internal_sinkpad);
|
||||||
} else if (GST_EVENT_TYPE (event) != GST_EVENT_RECONFIGURE) {
|
} else if (GST_EVENT_TYPE (event) != GST_EVENT_RECONFIGURE) {
|
||||||
GST_WARNING_OBJECT (self,
|
GST_WARNING_OBJECT (self,
|
||||||
"Got upstream event while no element was selected," "forwarding.");
|
"Got upstream event while no element was selected, forwarding.");
|
||||||
ret = gst_pad_push_event (self->sinkpad, event);
|
ret = gst_pad_push_event (self->sinkpad, event);
|
||||||
} else
|
} else
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
|
@ -1339,3 +1446,14 @@ gst_base_auto_convert_internal_src_query (GstPad * pad, GstObject * parent,
|
||||||
|
|
||||||
return gst_pad_peer_query (self->sinkpad, query);
|
return gst_pad_peer_query (self->sinkpad, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_base_auto_convert_reset_filters (GstBaseAutoConvert * self)
|
||||||
|
{
|
||||||
|
GST_OBJECT_LOCK (self);
|
||||||
|
g_list_free_full (self->filters_info,
|
||||||
|
(GDestroyNotify) gst_auto_convert_filter_info_free);
|
||||||
|
self->filters_info = NULL;
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ struct _GstBaseAutoConvert
|
||||||
GstBin bin; /* we extend GstBin */
|
GstBin bin; /* we extend GstBin */
|
||||||
|
|
||||||
GList *factories;
|
GList *factories;
|
||||||
|
GList *filters_info;
|
||||||
|
|
||||||
GstPad *sinkpad;
|
GstPad *sinkpad;
|
||||||
GstPad *srcpad;
|
GstPad *srcpad;
|
||||||
|
@ -54,17 +55,36 @@ struct _GstBaseAutoConvert
|
||||||
GstPad *current_internal_srcpad;
|
GstPad *current_internal_srcpad;
|
||||||
GstPad *current_internal_sinkpad;
|
GstPad *current_internal_sinkpad;
|
||||||
|
|
||||||
GHashTable * elements;
|
GHashTable *elements;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* This structure is used to allow handling random bin from their description
|
||||||
|
without needing to register a factory. The data it contains is pretty similar
|
||||||
|
but is specific for filters (1sinkpad and 1 srcpad).
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* Name of the filter, each instance of should have that name */
|
||||||
|
gchar *name;
|
||||||
|
gchar *bindesc;
|
||||||
|
GstRank rank;
|
||||||
|
GstCaps *sink_caps;
|
||||||
|
GstCaps *src_caps;
|
||||||
|
} GstAutoConvertFilterInfo;
|
||||||
|
|
||||||
struct _GstBaseAutoConvertClass
|
struct _GstBaseAutoConvertClass
|
||||||
{
|
{
|
||||||
GstBinClass parent_class;
|
GstBinClass parent_class;
|
||||||
|
|
||||||
GList* (*load_factories)(GstBaseAutoConvert *base_autoconvert);
|
gboolean registers_filters;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstBaseAutoConvert, gst_object_unref)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstBaseAutoConvert, gst_object_unref)
|
||||||
GType gst_base_auto_convert_get_type (void);
|
GType gst_base_auto_convert_get_type (void);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_base_auto_convert_register_filter(GstBaseAutoConvert *self, gchar *name,
|
||||||
|
gchar * bindesc, GstRank rank);
|
||||||
|
void gst_base_auto_convert_reset_filters (GstBaseAutoConvert * self);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -3,7 +3,7 @@ meta,
|
||||||
"gltestsrc ! gldownload ! autovideoconvert name=convert ! capsfilter name=capsfilter caps=\"video/x-raw(memory:GLMemory)\" ! fakevideosink name=sink",
|
"gltestsrc ! gldownload ! autovideoconvert name=convert ! capsfilter name=capsfilter caps=\"video/x-raw(memory:GLMemory)\" ! fakevideosink name=sink",
|
||||||
},
|
},
|
||||||
configs = {
|
configs = {
|
||||||
"$(validateflow), pad=convert:src, record-buffers=true, ignored-fields=\"stream-start={stream-id,group-id,stream},buffer={meta}\"",
|
"$(validateflow), pad=\"^convert:src$\", record-buffers=true, ignored-fields=\"stream-start={stream-id,group-id,stream},buffer={meta}\"",
|
||||||
}
|
}
|
||||||
|
|
||||||
crank-clock, repeat=2
|
crank-clock, repeat=2
|
||||||
|
@ -15,8 +15,9 @@ foreach,
|
||||||
"video/x-raw",
|
"video/x-raw",
|
||||||
>,
|
>,
|
||||||
actions = {
|
actions = {
|
||||||
|
[checkpoint, text="Setup capsfilter caps=$(caps)"],
|
||||||
[set-properties, capsfilter::caps="$(caps)"],
|
[set-properties, capsfilter::caps="$(caps)"],
|
||||||
[crank-clock, repeat=2],
|
[crank-clock, repeat=2],
|
||||||
[wait, on-clock=true],
|
[wait, on-clock=true],
|
||||||
}
|
}
|
||||||
stop
|
stop
|
||||||
|
|
|
@ -4,12 +4,21 @@ event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, s
|
||||||
buffer: pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont
|
buffer: pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont
|
||||||
buffer: pts=0:00:00.033333333, dur=0:00:00.033333333
|
buffer: pts=0:00:00.033333333, dur=0:00:00.033333333
|
||||||
buffer: pts=0:00:00.066666666, dur=0:00:00.033333334
|
buffer: pts=0:00:00.066666666, dur=0:00:00.033333334
|
||||||
event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320;
|
|
||||||
|
CHECKPOINT: Setup capsfilter caps=video/x-raw
|
||||||
|
|
||||||
|
event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, width=(int)320;
|
||||||
buffer: pts=0:00:00.100000000, dur=0:00:00.033333333
|
buffer: pts=0:00:00.100000000, dur=0:00:00.033333333
|
||||||
buffer: pts=0:00:00.133333333, dur=0:00:00.033333333
|
buffer: pts=0:00:00.133333333, dur=0:00:00.033333333
|
||||||
|
|
||||||
|
CHECKPOINT: Setup capsfilter caps=video/x-raw(memory:GLMemory)
|
||||||
|
|
||||||
event caps: video/x-raw(memory:GLMemory), format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320;
|
event caps: video/x-raw(memory:GLMemory), format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320;
|
||||||
buffer: pts=0:00:00.166666666, dur=0:00:00.033333334
|
buffer: pts=0:00:00.166666666, dur=0:00:00.033333334
|
||||||
buffer: pts=0:00:00.200000000, dur=0:00:00.033333333
|
buffer: pts=0:00:00.200000000, dur=0:00:00.033333333
|
||||||
event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320;
|
|
||||||
|
CHECKPOINT: Setup capsfilter caps=video/x-raw
|
||||||
|
|
||||||
|
event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, width=(int)320;
|
||||||
buffer: pts=0:00:00.233333333, dur=0:00:00.033333333
|
buffer: pts=0:00:00.233333333, dur=0:00:00.033333333
|
||||||
buffer: pts=0:00:00.266666666, dur=0:00:00.033333334
|
buffer: pts=0:00:00.266666666, dur=0:00:00.033333334
|
Loading…
Reference in a new issue