mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-25 19:21:06 +00:00
nle: Use a message based mechanism to detect parent nleobject duration
Recursing up is pretty ugly and will fail when we start using ancillary pipelines for sources in nle, using a message/event based mechanism is a common pattern that is much cleaner. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5983>
This commit is contained in:
parent
b730e7a1b2
commit
b14207cc9e
3 changed files with 152 additions and 60 deletions
|
@ -32,6 +32,7 @@
|
|||
* uri scheme.
|
||||
**/
|
||||
|
||||
#include "plugins/shared/nlegesplugin.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
@ -71,6 +72,10 @@ struct _GESDemux
|
|||
G_DEFINE_TYPE (GESDemux, ges_demux, ges_base_bin_get_type ());
|
||||
#define GES_DEMUX(obj) ((GESDemux*)obj)
|
||||
|
||||
static void
|
||||
ges_demux_adapt_timeline_duration (GESDemux * self, GESTimeline * timeline,
|
||||
GstElement * parent);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
@ -344,75 +349,61 @@ ges_demux_set_srcpad_probe (GstElement * element, GstPad * pad,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ges_demux_adapt_timeline_duration (GESDemux * self, GESTimeline * timeline)
|
||||
void
|
||||
ges_demux_adapt_timeline_duration (GESDemux * self, GESTimeline * timeline,
|
||||
GstElement * parent)
|
||||
{
|
||||
GType nleobject_type = g_type_from_name ("NleObject");
|
||||
GstObject *parent, *tmpparent;
|
||||
GstClockTime duration, inpoint, timeline_duration;
|
||||
|
||||
parent = gst_object_get_parent (GST_OBJECT (self));
|
||||
while (parent) {
|
||||
if (g_type_is_a (G_OBJECT_TYPE (parent), nleobject_type)) {
|
||||
GstClockTime duration, inpoint, timeline_duration;
|
||||
g_object_get (parent, "duration", &duration, "inpoint", &inpoint, NULL);
|
||||
g_object_get (timeline, "duration", &timeline_duration, NULL);
|
||||
|
||||
g_object_get (parent, "duration", &duration, "inpoint", &inpoint, NULL);
|
||||
g_object_get (timeline, "duration", &timeline_duration, NULL);
|
||||
GST_DEBUG_OBJECT (self, "Adapting duration");
|
||||
if (inpoint + duration > timeline_duration) {
|
||||
GESLayer *layer = ges_timeline_get_layer (timeline, 0);
|
||||
|
||||
if (inpoint + duration > timeline_duration) {
|
||||
GESLayer *layer = ges_timeline_get_layer (timeline, 0);
|
||||
if (layer) {
|
||||
GESClip *clip = GES_CLIP (ges_test_clip_new ());
|
||||
GList *tmp, *tracks = ges_timeline_get_tracks (timeline);
|
||||
|
||||
if (layer) {
|
||||
GESClip *clip = GES_CLIP (ges_test_clip_new ());
|
||||
GList *tmp, *tracks = ges_timeline_get_tracks (timeline);
|
||||
|
||||
g_object_set (clip, "start", timeline_duration, "duration",
|
||||
inpoint + duration, "vpattern", GES_VIDEO_TEST_PATTERN_SMPTE75,
|
||||
NULL);
|
||||
ges_layer_add_clip (layer, clip);
|
||||
for (tmp = tracks; tmp; tmp = tmp->next) {
|
||||
if (GES_IS_VIDEO_TRACK (tmp->data)) {
|
||||
GESEffect *text;
|
||||
GstCaps *caps;
|
||||
gchar *effect_str_full = NULL;
|
||||
const gchar *effect_str =
|
||||
"textoverlay text=\"Nested timeline too short, please FIX!\" halignment=center valignment=center";
|
||||
|
||||
g_object_get (tmp->data, "restriction-caps", &caps, NULL);
|
||||
if (caps) {
|
||||
gchar *caps_str = gst_caps_to_string (caps);
|
||||
effect_str = effect_str_full =
|
||||
g_strdup_printf
|
||||
("videoconvertscale ! capsfilter caps=\"%s\" ! %s",
|
||||
caps_str, effect_str);
|
||||
g_free (caps_str);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
text = ges_effect_new (effect_str);
|
||||
g_free (effect_str_full);
|
||||
|
||||
if (!ges_container_add (GES_CONTAINER (clip),
|
||||
GES_TIMELINE_ELEMENT (text))) {
|
||||
GST_ERROR ("Could not add text overlay to ending clip!");
|
||||
}
|
||||
}
|
||||
g_object_set (clip, "start", timeline_duration, "duration",
|
||||
inpoint + duration, "vpattern", GES_VIDEO_TEST_PATTERN_SMPTE75, NULL);
|
||||
ges_layer_add_clip (layer, clip);
|
||||
for (tmp = tracks; tmp; tmp = tmp->next) {
|
||||
if (GES_IS_VIDEO_TRACK (tmp->data)) {
|
||||
GESEffect *text;
|
||||
GstCaps *caps;
|
||||
gchar *effect_str_full = NULL;
|
||||
const gchar *effect_str =
|
||||
"textoverlay text=\"Nested timeline too short, please FIX!\" halignment=center valignment=center";
|
||||
|
||||
g_object_get (tmp->data, "restriction-caps", &caps, NULL);
|
||||
if (caps) {
|
||||
gchar *caps_str = gst_caps_to_string (caps);
|
||||
effect_str = effect_str_full =
|
||||
g_strdup_printf
|
||||
("videoconvertscale ! capsfilter caps=\"%s\" ! %s", caps_str,
|
||||
effect_str);
|
||||
g_free (caps_str);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
text = ges_effect_new (effect_str);
|
||||
g_free (effect_str_full);
|
||||
|
||||
if (!ges_container_add (GES_CONTAINER (clip),
|
||||
GES_TIMELINE_ELEMENT (text))) {
|
||||
GST_ERROR ("Could not add text overlay to ending clip!");
|
||||
}
|
||||
g_list_free_full (tracks, gst_object_unref);
|
||||
GST_INFO_OBJECT (timeline,
|
||||
"Added test clip with duration: %" GST_TIME_FORMAT " - %"
|
||||
GST_TIME_FORMAT " to match parent nleobject duration",
|
||||
GST_TIME_ARGS (timeline_duration),
|
||||
GST_TIME_ARGS (inpoint + duration - timeline_duration));
|
||||
}
|
||||
|
||||
}
|
||||
gst_object_unref (parent);
|
||||
|
||||
return;
|
||||
g_list_free_full (tracks, gst_object_unref);
|
||||
GST_INFO_OBJECT (timeline,
|
||||
"Added test clip with duration: %" GST_TIME_FORMAT " - %"
|
||||
GST_TIME_FORMAT " to match parent nleobject duration",
|
||||
GST_TIME_ARGS (timeline_duration),
|
||||
GST_TIME_ARGS (inpoint + duration - timeline_duration));
|
||||
}
|
||||
|
||||
tmpparent = parent;
|
||||
parent = gst_object_get_parent (GST_OBJECT (parent));
|
||||
gst_object_unref (tmpparent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,7 +441,20 @@ ges_demux_create_timeline (GESDemux * self, gchar * uri, GError ** error)
|
|||
if (data.error)
|
||||
goto done;
|
||||
|
||||
ges_demux_adapt_timeline_duration (self, data.timeline);
|
||||
NleQueryParentNleObject *query_parent =
|
||||
g_atomic_rc_box_new0 (NleQueryParentNleObject);
|
||||
GType query_gtype = g_type_from_name ("NleQueryParentNleObject");
|
||||
gst_element_post_message (GST_ELEMENT (self),
|
||||
gst_message_new_element (GST_OBJECT (self),
|
||||
gst_structure_new (NLE_QUERY_PARENT_NLE_OBJECT, "query",
|
||||
query_gtype, query_parent, NULL)));
|
||||
g_mutex_lock (&query_parent->lock);
|
||||
if (query_parent->nle_object) {
|
||||
ges_demux_adapt_timeline_duration (self, data.timeline,
|
||||
query_parent->nle_object);
|
||||
}
|
||||
g_mutex_unlock (&query_parent->lock);
|
||||
g_boxed_free (query_gtype, query_parent);
|
||||
|
||||
query = gst_query_new_uri ();
|
||||
if (gst_pad_peer_query (self->sinkpad, query)) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <string.h>
|
||||
#include "nle.h"
|
||||
#include "../shared/nlegesplugin.h"
|
||||
|
||||
/**
|
||||
* SECTION:nleobject
|
||||
|
@ -33,6 +34,22 @@
|
|||
* properties provided by all the GNonLin elements.
|
||||
*/
|
||||
|
||||
static void
|
||||
nle_query_parent_nle_object_free (NleQueryParentNleObject * query)
|
||||
{
|
||||
gst_clear_object (&query->nle_object);
|
||||
}
|
||||
|
||||
void
|
||||
nle_query_parent_nle_object_release (NleQueryParentNleObject * query)
|
||||
{
|
||||
g_atomic_rc_box_release_full (query,
|
||||
(GDestroyNotify) nle_query_parent_nle_object_free);
|
||||
}
|
||||
|
||||
G_DEFINE_BOXED_TYPE (NleQueryParentNleObject,
|
||||
nle_query_parent_nle_object,
|
||||
g_atomic_rc_box_acquire, nle_query_parent_nle_object_release);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (nleobject_debug);
|
||||
#define GST_CAT_DEFAULT nleobject_debug
|
||||
|
@ -103,26 +120,58 @@ static gboolean nle_object_commit_func (NleObject * object, gboolean recurse);
|
|||
|
||||
static GstStateChangeReturn nle_object_prepare (NleObject * object);
|
||||
|
||||
static void
|
||||
nle_bin_handle_message (GstBin * bin, GstMessage * message)
|
||||
{
|
||||
if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) {
|
||||
const GstStructure *s = gst_message_get_structure (message);
|
||||
|
||||
if (gst_structure_has_name (s, NLE_QUERY_PARENT_NLE_OBJECT)) {
|
||||
NleQueryParentNleObject *query;
|
||||
|
||||
gst_structure_get (s, "query", NLE_TYPE_QUERY_PARENT_NLE_OBJECT, &query,
|
||||
NULL);
|
||||
g_assert (query);
|
||||
|
||||
g_mutex_lock (&query->lock);
|
||||
query->nle_object = gst_object_ref (GST_ELEMENT (bin));
|
||||
g_mutex_unlock (&query->lock);
|
||||
nle_query_parent_nle_object_release (query);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return GST_BIN_CLASS (parent_class)->handle_message (bin, message);
|
||||
}
|
||||
|
||||
static void
|
||||
nle_object_class_init (NleObjectClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBinClass *gstbin_class;
|
||||
NleObjectClass *nleobject_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbin_class = (GstBinClass *) klass;
|
||||
nleobject_class = (NleObjectClass *) klass;
|
||||
GST_DEBUG_CATEGORY_INIT (nleobject_debug, "nleobject",
|
||||
GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "GNonLin object");
|
||||
parent_class = g_type_class_ref (GST_TYPE_BIN);
|
||||
|
||||
/* Ensure the NleQueryParentObject GType is registered */
|
||||
GType t = NLE_TYPE_QUERY_PARENT_NLE_OBJECT;
|
||||
g_assert (t);
|
||||
|
||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (nle_object_set_property);
|
||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (nle_object_get_property);
|
||||
gobject_class->constructed = GST_DEBUG_FUNCPTR (nle_object_constructed);
|
||||
gobject_class->dispose = GST_DEBUG_FUNCPTR (nle_object_dispose);
|
||||
|
||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (nle_object_change_state);
|
||||
gstbin_class->handle_message = GST_DEBUG_FUNCPTR (nle_bin_handle_message);
|
||||
|
||||
nleobject_class->prepare = GST_DEBUG_FUNCPTR (nle_object_prepare_func);
|
||||
nleobject_class->cleanup = GST_DEBUG_FUNCPTR (nle_object_cleanup_func);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* GES and NLE plugins shared header
|
||||
*
|
||||
* Copyright (C) 2024 Thibault Saunier <tsaunier@igalia.com>
|
||||
*
|
||||
* nlegesplugin.h
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#define NLE_QUERY_PARENT_NLE_OBJECT "nle-query-parent-nle-object"
|
||||
typedef struct
|
||||
{
|
||||
GMutex lock;
|
||||
GstElement *nle_object;
|
||||
} NleQueryParentNleObject;
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#define NLE_TYPE_QUERY_PARENT_NLE_OBJECT nle_query_parent_nle_object_get_type ()
|
||||
GType nle_query_parent_nle_object_get_type (void) G_GNUC_CONST;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
void nle_query_parent_nle_object_release (NleQueryParentNleObject * query);
|
Loading…
Reference in a new issue