diff --git a/subprojects/gst-plugins-base/gst-libs/gst/video/gstvideometa.c b/subprojects/gst-plugins-base/gst-libs/gst/video/gstvideometa.c index f191820818..794d920aaa 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/video/gstvideometa.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/video/gstvideometa.c @@ -124,6 +124,68 @@ gst_video_meta_transform (GstBuffer * dest, GstMeta * meta, return TRUE; } +static gboolean +gst_video_meta_api_params_aggregator (GstStructure ** aggregated_params, + const GstStructure * params0, const GstStructure * params1) +{ + GstVideoAlignment align0; + GstVideoAlignment align1; + GstVideoAlignment aggregated_align; + + gst_video_alignment_reset (&align0); + gst_video_alignment_reset (&align1); + gst_video_alignment_reset (&aggregated_align); + + if (params0 && (!gst_structure_has_name (params0, "video-meta") || + !gst_buffer_pool_config_get_video_alignment (params0, &align0))) { + GST_WARNING ("Invalid params"); + params0 = NULL; + } + + if (params1 && (!gst_structure_has_name (params1, "video-meta") || + !gst_buffer_pool_config_get_video_alignment (params1, &align1))) { + GST_WARNING ("Invalid params"); + params1 = NULL; + } + + if (!params0 && !params1) { + *aggregated_params = NULL; + return TRUE; + } + + if (params0 && !params1) { + *aggregated_params = gst_structure_copy (params0); + return TRUE; + } + + if (!params0 && params1) { + *aggregated_params = gst_structure_copy (params1); + return TRUE; + } + + aggregated_align.padding_top = MAX (align0.padding_top, align1.padding_top); + + aggregated_align.padding_bottom = + MAX (align0.padding_bottom, align1.padding_bottom); + + aggregated_align.padding_left = + MAX (align0.padding_left, align1.padding_left); + + aggregated_align.padding_right = + MAX (align0.padding_right, align1.padding_right); + + for (int n = 0; n < GST_VIDEO_MAX_PLANES; ++n) + aggregated_align.stride_align[n] = + align0.stride_align[n] | align1.stride_align[n]; + + *aggregated_params = gst_structure_new_empty ("video-meta"); + + gst_buffer_pool_config_set_video_alignment (*aggregated_params, + &aggregated_align); + + return TRUE; +} + GType gst_video_meta_api_get_type (void) { @@ -136,6 +198,9 @@ gst_video_meta_api_get_type (void) if (g_once_init_enter (&type)) { GType _type = gst_meta_api_type_register ("GstVideoMetaAPI", tags); + + gst_meta_api_type_set_params_aggregator (_type, + gst_video_meta_api_params_aggregator); g_once_init_leave (&type, _type); } return type; diff --git a/subprojects/gstreamer/gst/gstmeta.c b/subprojects/gstreamer/gst/gstmeta.c index 96b273e5d5..1e961e6410 100644 --- a/subprojects/gstreamer/gst/gstmeta.c +++ b/subprojects/gstreamer/gst/gstmeta.c @@ -58,6 +58,7 @@ GQuark _gst_meta_transform_copy; GQuark _gst_meta_tag_memory; GQuark _gst_meta_tag_memory_reference; static GQuark _gst_meta_tags_quark; +static GQuark _gst_allocation_meta_params_aggregator_quark; typedef struct { @@ -85,6 +86,8 @@ _priv_gst_meta_initialize (void) _gst_meta_tag_memory_reference = g_quark_from_static_string ("memory-reference"); _gst_meta_tags_quark = g_quark_from_static_string ("tags"); + _gst_allocation_meta_params_aggregator_quark = + g_quark_from_static_string ("GstAllocationMetaParamsAggregator"); } static gboolean @@ -409,6 +412,62 @@ gst_meta_api_type_get_tags (GType api) return (const gchar * const *) tags; } +/** + * gst_meta_api_type_aggregate_params: + * @api: the GType of the API for which the parameters are being aggregated. + * @aggregated_params: This structure will be updated with the + * combined parameters from both @params0 and @params1. + * @params0: a #GstStructure containing the new parameters to be aggregated. + * @params1: a #GstStructure containing the new parameters to be aggregated. + * + * When a element like `tee` decides the allocation, each downstream element may + * fill different parameters and pass them to gst_query_add_allocation_meta(). + * In order to keep these parameters, a merge operation is needed. This + * aggregate function can combine the parameters from @params0 and @param1, and + * write the result back into @aggregated_params. + * + * Returns: %TRUE if the parameters were successfully aggregated, %FALSE otherwise. + * + * Since: 1.26 + */ +gboolean +gst_meta_api_type_aggregate_params (GType api, + GstStructure ** aggregated_params, const GstStructure * params0, + const GstStructure * params1) +{ + g_return_val_if_fail (api != 0, FALSE); + g_return_val_if_fail (aggregated_params != NULL, FALSE); + + GstAllocationMetaParamsAggregator aggregator_func = + g_type_get_qdata (api, _gst_allocation_meta_params_aggregator_quark); + + if (!aggregator_func) + return FALSE; + + return aggregator_func (aggregated_params, params0, params1); +} + +/** + * gst_meta_api_type_set_params_aggregator: + * @api: the #GType of the API for which the aggregator function is being set. + * @aggregator: the aggregator function to be associated with the given API + * type. + * + * This function sets the aggregator function for a specific API type. + * + * Since: 1.26 + */ +void +gst_meta_api_type_set_params_aggregator (GType api, + GstAllocationMetaParamsAggregator aggregator) +{ + g_return_if_fail (api != 0); + g_return_if_fail (aggregator != NULL); + + g_type_set_qdata (api, _gst_allocation_meta_params_aggregator_quark, + (GstAllocationMetaParamsAggregator) aggregator); +} + static const GstMetaInfo * gst_meta_register_internal (GType api, const gchar * impl, gsize size, GstMetaInitFunction init_func, GstMetaFreeFunction free_func, diff --git a/subprojects/gstreamer/gst/gstmeta.h b/subprojects/gstreamer/gst/gstmeta.h index 214847146c..ddeb0988ab 100644 --- a/subprojects/gstreamer/gst/gstmeta.h +++ b/subprojects/gstreamer/gst/gstmeta.h @@ -292,6 +292,24 @@ typedef GstMeta *(*GstMetaDeserializeFunction) (const GstMetaInfo *info, */ typedef void (*GstMetaClearFunction) (GstBuffer *buffer, GstMeta *meta); +/** + * GstAllocationMetaParamsAggregator: + * @aggregated_params: This structure will be updated with the + * combined parameters from both @params0 and @params1. + * @params0: a #GstStructure containing the new parameters to be aggregated. + * @params1: a #GstStructure containing the new parameters to be aggregated. + * + * The aggregator function will combine the parameters from @params0 and @param1 + * and write the result back into @aggregated_params. + * + * Returns: %TRUE if the parameters were successfully aggregated, %FALSE otherwise. + * + * Since: 1.26 + */ +typedef gboolean (*GstAllocationMetaParamsAggregator) (GstStructure ** aggregated_params, + const GstStructure * params0, + const GstStructure * params1); + /** * GstMetaInfo.serialize_func: * @@ -359,6 +377,16 @@ GType gst_meta_api_type_register (const gchar *api, GST_API gboolean gst_meta_api_type_has_tag (GType api, GQuark tag); +GST_API +gboolean gst_meta_api_type_aggregate_params (GType api, + GstStructure ** aggregated_params, + const GstStructure * params0, + const GstStructure * params1); + +GST_API +void gst_meta_api_type_set_params_aggregator (GType api, + GstAllocationMetaParamsAggregator aggregator); + GST_API const GstMetaInfo * gst_meta_register (GType api, const gchar *impl, gsize size, diff --git a/subprojects/gstreamer/plugins/elements/gsttee.c b/subprojects/gstreamer/plugins/elements/gsttee.c index dd90c38671..27a4b76fec 100644 --- a/subprojects/gstreamer/plugins/elements/gsttee.c +++ b/subprojects/gstreamer/plugins/elements/gsttee.c @@ -685,6 +685,7 @@ gst_tee_query_allocation (const GValue * item, GValue * ret, gpointer user_data) /* Afterward, aggregate the common params */ if (gst_query_find_allocation_meta (ctx->query, api, &ctx_index)) { const GstStructure *ctx_param; + GstStructure *aggregated_params = NULL; gst_query_parse_nth_allocation_meta (ctx->query, ctx_index, &ctx_param); @@ -692,7 +693,17 @@ gst_tee_query_allocation (const GValue * item, GValue * ret, gpointer user_data) if (ctx_param == NULL && param == NULL) continue; - GST_DEBUG_OBJECT (ctx->tee, "Dropping allocation meta %s", + /* Aggregate the two params, if successful, add it to the query. + * and then, we always Drop the old params from the query. */ + if (gst_meta_api_type_aggregate_params (api, &aggregated_params, + ctx_param, param)) { + gst_query_add_allocation_meta (ctx->query, api, aggregated_params); + + if (aggregated_params) + gst_structure_free (aggregated_params); + } + + GST_DEBUG_OBJECT (ctx->tee, "Dropping old allocation meta %s", g_type_name (api)); gst_query_remove_nth_allocation_meta (ctx->query, ctx_index); }