mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-04 22:48:54 +00:00
Merge remote-tracking branch 'origin/master' into 0.11
Conflicts: bindings/python/Makefile.am bindings/python/ges-types.defs bindings/python/ges.defs bindings/python/ges.override bindings/python/gesmodule.c bindings/python/testsuite/test_textoverlay.py
This commit is contained in:
commit
5d02075d9b
39 changed files with 3871 additions and 329 deletions
|
@ -193,6 +193,14 @@ AC_SUBST(GLIB_PREFIX)
|
|||
AC_SUBST(GST_PREFIX)
|
||||
AC_SUBST(GSTPB_PREFIX)
|
||||
|
||||
dnl pitivi formatter needs libxml
|
||||
PKG_CHECK_MODULES(XML, libxml-2.0, HAVE_LIBXML="yes", HAVE_LIBXML="no")
|
||||
if test "x$HAVE_LIBXML" != "xyes"; then
|
||||
AC_ERROR([libxml2 is required])
|
||||
fi
|
||||
AC_SUBST(XML_LIBS)
|
||||
AC_SUBST(XML_CFLAGS)
|
||||
|
||||
dnl GTK is optional and only used in examples
|
||||
HAVE_GTK=no
|
||||
HAVE_GTK_X11=no
|
||||
|
|
|
@ -88,6 +88,7 @@ platform as well as Windows. It is released under the GNU Library General Public
|
|||
<title>Serialization Classes</title>
|
||||
<xi:include href="xml/ges-formatter.xml"/>
|
||||
<xi:include href="xml/ges-keyfile-formatter.xml"/>
|
||||
<xi:include href="xml/ges-pitivi-formatter.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="ges-hierarchy">
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
<FILE>ges-common</FILE>
|
||||
<TITLE>Initialization</TITLE>
|
||||
ges_init
|
||||
ges_version
|
||||
GES_VERSION_MAJOR
|
||||
GES_VERSION_MICRO
|
||||
GES_VERSION_MINOR
|
||||
GES_VERSION_NANO
|
||||
<SUBSECTION Standard>
|
||||
GES_PADDING
|
||||
</SECTION>
|
||||
|
@ -51,6 +56,8 @@ ges_track_add_object
|
|||
ges_track_remove_object
|
||||
ges_track_set_caps
|
||||
ges_track_get_caps
|
||||
ges_track_enable_update
|
||||
ges_track_get_objects
|
||||
<SUBSECTION Standard>
|
||||
GESTrackClass
|
||||
GESTrackPrivate
|
||||
|
@ -236,11 +243,13 @@ ges_timeline_new
|
|||
ges_timeline_new_audio_video
|
||||
ges_timeline_new_from_uri
|
||||
ges_timeline_add_layer
|
||||
ges_timeline_append_layer
|
||||
ges_timeline_remove_layer
|
||||
ges_timeline_add_track
|
||||
ges_timeline_remove_track
|
||||
ges_timeline_load_from_uri
|
||||
ges_timeline_save_to_uri
|
||||
ges_timeline_enable_update
|
||||
<SUBSECTION usage>
|
||||
ges_timeline_get_tracks
|
||||
ges_timeline_get_layers
|
||||
|
@ -269,6 +278,8 @@ ges_timeline_layer_remove_object
|
|||
ges_timeline_layer_set_priority
|
||||
ges_timeline_layer_get_priority
|
||||
ges_timeline_layer_get_objects
|
||||
ges_timeline_layer_get_auto_transition
|
||||
ges_timeline_layer_set_auto_transition
|
||||
<SUBSECTION Standard>
|
||||
GESTimelineLayerPrivate
|
||||
ges_timeline_layer_set_timeline
|
||||
|
@ -298,7 +309,11 @@ ges_timeline_object_find_track_object
|
|||
ges_timeline_object_add_track_object
|
||||
ges_timeline_object_get_top_effects
|
||||
ges_timeline_object_get_top_effect_position
|
||||
ges_timeline_object_move_to_layer
|
||||
ges_timeline_object_set_top_effect_priority
|
||||
ges_timeline_object_set_supported_formats
|
||||
ges_timeline_object_get_supported_formats
|
||||
ges_timeline_object_split
|
||||
<SUBSECTION Standard>
|
||||
GES_TIMELINE_OBJECT_DURATION
|
||||
GES_TIMELINE_OBJECT_INPOINT
|
||||
|
@ -308,10 +323,13 @@ GES_TIMELINE_OBJECT_HEIGHT
|
|||
ges_timeline_object_create_track_objects
|
||||
ges_timeline_object_create_track_object
|
||||
ges_timeline_object_fill_track_object
|
||||
ges_timeline_object_is_moving_from_layer
|
||||
ges_timeline_object_release_track_object
|
||||
ges_timeline_object_get_track_objects
|
||||
ges_timeline_object_set_layer
|
||||
ges_timeline_object_set_moving_from_layer
|
||||
ges_timeline_object_set_priority
|
||||
ges_timeline_object_lock_track_objects
|
||||
GESTimelineObjectPrivate
|
||||
GES_IS_TIMELINE_OBJECT
|
||||
GES_IS_TIMELINE_OBJECT_CLASS
|
||||
|
@ -331,6 +349,10 @@ ges_timeline_pipeline_new
|
|||
ges_timeline_pipeline_add_timeline
|
||||
ges_timeline_pipeline_set_mode
|
||||
ges_timeline_pipeline_set_render_settings
|
||||
ges_timeline_pipeline_preview_get_audio_sink
|
||||
ges_timeline_pipeline_preview_get_video_sink
|
||||
ges_timeline_pipeline_preview_set_audio_sink
|
||||
ges_timeline_pipeline_preview_set_video_sink
|
||||
ges_timeline_pipeline_get_thumbnail_buffer
|
||||
ges_timeline_pipeline_get_thumbnail_rgb24
|
||||
ges_timeline_pipeline_save_thumbnail
|
||||
|
@ -732,12 +754,15 @@ GESFormatter
|
|||
GESFormatterClass
|
||||
GESFormatterLoadFromURIMethod
|
||||
GESFormatterSaveToURIMethod
|
||||
GESFormatterSourceMovedMethod
|
||||
GESFormatterLoadedMethod
|
||||
ges_default_formatter_new
|
||||
ges_formatter_load_from_uri
|
||||
ges_formatter_save_to_uri
|
||||
ges_formatter_new_for_uri
|
||||
ges_formatter_can_load_uri
|
||||
ges_formatter_can_save_uri
|
||||
ges_formatter_update_source_uri
|
||||
<SUBSECTION Standard>
|
||||
ges_formatter_get_type
|
||||
GES_FORMATTER
|
||||
|
@ -775,6 +800,26 @@ GES_TYPE_KEYFILE_FORMATTER
|
|||
ges_keyfile_formatter_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>ges-pitivi-formatter</FILE>
|
||||
<TITLE>GESPitiviFormatter</TITLE>
|
||||
GESPitiviFormatter
|
||||
ges_pitivi_formatter_new
|
||||
ges_pitivi_formatter_set_sources
|
||||
ges_pitivi_formatter_get_sources
|
||||
<SUBSECTION Standard>
|
||||
GESPitiviFormatterClass
|
||||
GESPitiviFormatterPrivate
|
||||
GES_TYPE_PITIVI_FORMATTER
|
||||
GES_IS_PITIVI_FORMATTER
|
||||
GES_IS_PITIVI_FORMATTER_CLASS
|
||||
GES_PITIVI_FORMATTER
|
||||
GES_PITIVI_FORMATTER_CLASS
|
||||
GES_PITIVI_FORMATTER_GET_CLASS
|
||||
GES_TYPE_PITIVIFORMATTER
|
||||
ges_pitivi_formatter_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>ges-track-effect</FILE>
|
||||
<TITLE>GESTrackEffect</TITLE>
|
||||
|
|
|
@ -46,6 +46,7 @@ libges_@GST_MAJORMINOR@_la_SOURCES = \
|
|||
ges-screenshot.c \
|
||||
ges-formatter.c \
|
||||
ges-keyfile-formatter.c \
|
||||
ges-pitivi-formatter.c \
|
||||
ges-utils.c
|
||||
|
||||
libges_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/ges/
|
||||
|
@ -89,13 +90,14 @@ libges_@GST_MAJORMINOR@include_HEADERS = \
|
|||
ges-screenshot.h \
|
||||
ges-formatter.h \
|
||||
ges-keyfile-formatter.h \
|
||||
ges-pitivi-formatter.h \
|
||||
ges-utils.h
|
||||
|
||||
noinst_HEADERS = \
|
||||
ges-internal.h
|
||||
|
||||
libges_@GST_MAJORMINOR@_la_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) $(GST_CONTROLLER_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
||||
libges_@GST_MAJORMINOR@_la_LIBADD = $(GST_PBUTILS_LIBS) $(GST_VIDEO_LIBS) $(GST_CONTROLLER_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS)
|
||||
libges_@GST_MAJORMINOR@_la_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) $(GST_CONTROLLER_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(XML_CFLAGS)
|
||||
libges_@GST_MAJORMINOR@_la_LIBADD = $(GST_PBUTILS_LIBS) $(GST_VIDEO_LIBS) $(GST_CONTROLLER_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) $(XML_LIBS)
|
||||
libges_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) -export-symbols-regex \^_*\(ges_\|GES_\).*
|
||||
|
||||
DISTCLEANFILE = $(CLEANFILES)
|
||||
|
|
|
@ -38,13 +38,19 @@
|
|||
*
|
||||
* Support for saving or loading new formats can be added by creating a subclass of
|
||||
* #GESFormatter and implement the various vmethods of #GESFormatterClass.
|
||||
*
|
||||
* Note that subclasses should call project_loaded wen they are done loading
|
||||
* a project.
|
||||
**/
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gesmarshal.h"
|
||||
#include "ges-formatter.h"
|
||||
#include "ges-keyfile-formatter.h"
|
||||
#include "ges-internal.h"
|
||||
#include "ges.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (GESFormatter, ges_formatter, G_TYPE_OBJECT);
|
||||
|
||||
|
@ -52,6 +58,10 @@ struct _GESFormatterPrivate
|
|||
{
|
||||
gchar *data;
|
||||
gsize length;
|
||||
|
||||
/* Make sure not to emit several times "moved-source" when the user already
|
||||
* provided the new source URI. */
|
||||
GHashTable *uri_newuri_table;
|
||||
};
|
||||
|
||||
static void ges_formatter_dispose (GObject * object);
|
||||
|
@ -61,6 +71,20 @@ static gboolean save_to_uri (GESFormatter * formatter, GESTimeline *
|
|||
timeline, const gchar * uri);
|
||||
static gboolean default_can_load_uri (const gchar * uri);
|
||||
static gboolean default_can_save_uri (const gchar * uri);
|
||||
static void discovery_error_cb (GESTimeline * timeline,
|
||||
GESTimelineFileSource * tfs, GError * error, GESFormatter * formatter);
|
||||
|
||||
static gboolean project_loaded (GESFormatter * formatter,
|
||||
GESTimeline * timeline);
|
||||
|
||||
enum
|
||||
{
|
||||
SOURCE_MOVED_SIGNAL,
|
||||
LOADED_SIGNAL,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint ges_formatter_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
ges_formatter_class_init (GESFormatterClass * klass)
|
||||
|
@ -69,12 +93,35 @@ ges_formatter_class_init (GESFormatterClass * klass)
|
|||
|
||||
g_type_class_add_private (klass, sizeof (GESFormatterPrivate));
|
||||
|
||||
/**
|
||||
* GESFormatter::source-moved:
|
||||
* @formatter: the #GESFormatter
|
||||
* @source: The #GESTimelineFileSource that has an invalid URI. When this happens,
|
||||
* you can call #ges_formatter_update_source_uri with the new URI of the source so
|
||||
* the project can be loaded properly.
|
||||
*/
|
||||
ges_formatter_signals[SOURCE_MOVED_SIGNAL] =
|
||||
g_signal_new ("source-moved", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE,
|
||||
1, GES_TYPE_TIMELINE_FILE_SOURCE);
|
||||
|
||||
/**
|
||||
* GESFormatter::loaded:
|
||||
* @formatter: the #GESFormatter that is done loading a project.
|
||||
*/
|
||||
ges_formatter_signals[LOADED_SIGNAL] =
|
||||
g_signal_new ("loaded", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE,
|
||||
1, GES_TYPE_TIMELINE);
|
||||
|
||||
object_class->dispose = ges_formatter_dispose;
|
||||
|
||||
klass->can_load_uri = default_can_load_uri;
|
||||
klass->can_save_uri = default_can_save_uri;
|
||||
klass->load_from_uri = load_from_uri;
|
||||
klass->save_to_uri = save_to_uri;
|
||||
klass->update_source_uri = NULL;
|
||||
klass->project_loaded = project_loaded;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -82,6 +129,9 @@ ges_formatter_init (GESFormatter * object)
|
|||
{
|
||||
object->priv = G_TYPE_INSTANCE_GET_PRIVATE (object,
|
||||
GES_TYPE_FORMATTER, GESFormatterPrivate);
|
||||
|
||||
object->priv->uri_newuri_table = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal, g_free, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -92,6 +142,7 @@ ges_formatter_dispose (GObject * object)
|
|||
if (priv->data) {
|
||||
g_free (priv->data);
|
||||
}
|
||||
g_hash_table_destroy (priv->uri_newuri_table);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,7 +195,7 @@ default_can_save_uri (const gchar * uri)
|
|||
/**
|
||||
* ges_formatter_can_load_uri:
|
||||
* @uri: a #gchar * pointing to the URI
|
||||
*
|
||||
*
|
||||
* Checks if there is a #GESFormatter available which can load a #GESTimeline
|
||||
* from the given URI.
|
||||
*
|
||||
|
@ -177,7 +228,7 @@ ges_formatter_can_load_uri (const gchar * uri)
|
|||
/**
|
||||
* ges_formatter_can_save_uri:
|
||||
* @uri: a #gchar * pointing to a URI
|
||||
*
|
||||
*
|
||||
* Returns TRUE if there is a #GESFormatter available which can save a
|
||||
* #GESTimeline to the given URI.
|
||||
*
|
||||
|
@ -188,7 +239,7 @@ gboolean
|
|||
ges_formatter_can_save_uri (const gchar * uri)
|
||||
{
|
||||
if (!(gst_uri_is_valid (uri))) {
|
||||
GST_ERROR ("Invalid uri!");
|
||||
GST_ERROR ("%s invalid uri!", uri);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -237,7 +288,7 @@ ges_formatter_set_data (GESFormatter * formatter, void *data, gsize length)
|
|||
*
|
||||
* Lets you get the data @formatter used for loading.
|
||||
*
|
||||
* Returns: a pointer to the data.
|
||||
* Returns: (transfer none): a pointer to the data.
|
||||
*/
|
||||
void *
|
||||
ges_formatter_get_data (GESFormatter * formatter, gsize * length)
|
||||
|
@ -334,7 +385,7 @@ ges_formatter_save (GESFormatter * formatter, GESTimeline * timeline)
|
|||
* @formatter: a #GESFormatter
|
||||
* @timeline: a #GESTimeline
|
||||
* @uri: a #gchar * pointing to a URI
|
||||
*
|
||||
*
|
||||
* Load data from the given URI into timeline.
|
||||
*
|
||||
* Returns: TRUE if the timeline data was successfully loaded from the URI,
|
||||
|
@ -347,6 +398,11 @@ ges_formatter_load_from_uri (GESFormatter * formatter, GESTimeline * timeline,
|
|||
{
|
||||
GESFormatterClass *klass = GES_FORMATTER_GET_CLASS (formatter);
|
||||
|
||||
g_return_val_if_fail (GES_IS_FORMATTER (formatter), FALSE);
|
||||
g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
|
||||
|
||||
g_signal_connect (timeline, "discovery-error",
|
||||
G_CALLBACK (discovery_error_cb), formatter);
|
||||
if (klass->load_from_uri)
|
||||
return klass->load_from_uri (formatter, timeline, uri);
|
||||
|
||||
|
@ -451,3 +507,56 @@ save_to_uri (GESFormatter * formatter, GESTimeline * timeline,
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ges_formatter_update_source_uri (GESFormatter * formatter,
|
||||
GESTimelineFileSource * source, gchar * new_uri)
|
||||
{
|
||||
GESFormatterClass *klass = GES_FORMATTER_GET_CLASS (formatter);
|
||||
|
||||
if (klass->update_source_uri) {
|
||||
const gchar *uri = ges_timeline_filesource_get_uri (source);
|
||||
gchar *cached_uri =
|
||||
g_hash_table_lookup (formatter->priv->uri_newuri_table, uri);
|
||||
|
||||
if (!cached_uri) {
|
||||
g_hash_table_insert (formatter->priv->uri_newuri_table, g_strdup (uri),
|
||||
g_strdup (new_uri));
|
||||
|
||||
GST_DEBUG ("Adding %s to the new uri cache", new_uri);
|
||||
}
|
||||
|
||||
return klass->update_source_uri (formatter, source, new_uri);
|
||||
}
|
||||
|
||||
GST_ERROR ("not implemented!");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
discovery_error_cb (GESTimeline * timeline,
|
||||
GESTimelineFileSource * tfs, GError * error, GESFormatter * formatter)
|
||||
{
|
||||
if (error->domain == GST_RESOURCE_ERROR &&
|
||||
error->code == GST_RESOURCE_ERROR_NOT_FOUND) {
|
||||
const gchar *uri = ges_timeline_filesource_get_uri (tfs);
|
||||
gchar *new_uri =
|
||||
g_hash_table_lookup (formatter->priv->uri_newuri_table, uri);
|
||||
|
||||
if (new_uri) {
|
||||
ges_formatter_update_source_uri (formatter, tfs, new_uri);
|
||||
GST_DEBUG ("%s found in the cache, new uri: %s", uri, new_uri);
|
||||
} else
|
||||
g_signal_emit (formatter, ges_formatter_signals[SOURCE_MOVED_SIGNAL], 0,
|
||||
tfs);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
project_loaded (GESFormatter * formatter, GESTimeline * timeline)
|
||||
{
|
||||
g_signal_emit (formatter, ges_formatter_signals[LOADED_SIGNAL], 0, timeline);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -100,6 +100,34 @@ typedef gboolean (*GESFormatterSaveMethod) (GESFormatter * formatter,
|
|||
typedef gboolean (*GESFormatterLoadMethod) (GESFormatter * formatter,
|
||||
GESTimeline * timeline);
|
||||
|
||||
/**
|
||||
* GESFormatterSourceMovedMethod:
|
||||
* @formatter: a #GESFormatter
|
||||
* @tfs: a #GESTimelineFileSource
|
||||
* @new_uri: the new URI of @tfs
|
||||
*
|
||||
* Virtual method for changing the URI of a #GESTimelineFileSource that has been
|
||||
* moved between the saving and the loading of the timeline.
|
||||
*
|
||||
* This virtual method is not 100% necessary to be implemented as it is an
|
||||
* extra feature.
|
||||
*
|
||||
* Returns: %TRUE if the source URI could be modified properly, %FALSE otherwize.
|
||||
*/
|
||||
typedef gboolean (*GESFormatterSourceMovedMethod) (GESFormatter *formatter,
|
||||
GESTimelineFileSource *tfs, gchar *new_uri);
|
||||
|
||||
/**
|
||||
* GESFormatterLoadedMethod
|
||||
* @formatter: The #GESFormatter that is done loading
|
||||
* @timeline: The #GESTimeline that has finnished to load
|
||||
*
|
||||
* This method should be called by sublcasses when they are done
|
||||
* loading @timeline
|
||||
*/
|
||||
typedef gboolean (*GESFormatterLoadedMethod) (GESFormatter *formatter,
|
||||
GESTimeline *timeline);
|
||||
|
||||
/**
|
||||
* GESFormatterClass:
|
||||
* @parent_class: the parent class structure
|
||||
|
@ -107,6 +135,9 @@ typedef gboolean (*GESFormatterLoadMethod) (GESFormatter * formatter,
|
|||
* @can_save_uri: Whether the URI can be saved
|
||||
* @load_from_uri: class method to deserialize data from a URI
|
||||
* @save_to_uri: class method to serialize data to a URI
|
||||
* @update_source_uri: virtual method to specify that a source has moved, and thus its URI
|
||||
* must be set to its new location (specified by the user)
|
||||
* @project_loaded: Must be called by subclasses when done loading a project
|
||||
*
|
||||
* GES Formatter class. Override the vmethods to implement the formatter functionnality.
|
||||
*/
|
||||
|
@ -118,6 +149,8 @@ struct _GESFormatterClass {
|
|||
GESFormatterCanSaveURIMethod can_save_uri;
|
||||
GESFormatterLoadFromURIMethod load_from_uri;
|
||||
GESFormatterSaveToURIMethod save_to_uri;
|
||||
GESFormatterSourceMovedMethod update_source_uri;
|
||||
GESFormatterLoadedMethod project_loaded;
|
||||
|
||||
/*< private >*/
|
||||
/* FIXME : formatter name */
|
||||
|
@ -148,6 +181,10 @@ gboolean ges_formatter_save_to_uri (GESFormatter * formatter,
|
|||
GESTimeline *timeline,
|
||||
const gchar *uri);
|
||||
|
||||
gboolean
|
||||
ges_formatter_update_source_uri (GESFormatter * formatter,
|
||||
GESTimelineFileSource * source, gchar * new_uri);
|
||||
|
||||
/* Non-standard methods. WILL BE DEPRECATED */
|
||||
gboolean ges_formatter_load (GESFormatter * formatter,
|
||||
GESTimeline * timeline);
|
||||
|
|
1173
ges/ges-pitivi-formatter.c
Normal file
1173
ges/ges-pitivi-formatter.c
Normal file
File diff suppressed because it is too large
Load diff
55
ges/ges-pitivi-formatter.h
Normal file
55
ges/ges-pitivi-formatter.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#ifndef _GES_PITIVI_FORMATTER
|
||||
#define _GES_PITIVI_FORMATTER
|
||||
|
||||
#define GES_TYPE_PITIVI_FORMATTER ges_pitivi_formatter_get_type()
|
||||
|
||||
#define GES_PITIVI_FORMATTER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GES_TYPE_PITIVI_FORMATTER, GESPitiviFormatter))
|
||||
|
||||
#define GES_PITIVI_FORMATTER_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), GES_TYPE_PITIVI_FORMATTER, GESPitiviFormatterClass))
|
||||
|
||||
#define GES_IS_PITIVI_FORMATTER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GES_TYPE_PITIVI_FORMATTER))
|
||||
|
||||
#define GES_IS_PITIVI_FORMATTER_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), GES_TYPE_PITIVI_FORMATTER))
|
||||
|
||||
#define GES_PITIVI_FORMATTER_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), GES_TYPE_PITIVI_FORMATTER, GESPitiviFormatterClass))
|
||||
|
||||
typedef struct _GESPitiviFormatterPrivate GESPitiviFormatterPrivate;
|
||||
|
||||
/**
|
||||
* GESPitiviFormatter:
|
||||
*
|
||||
* Serializes a #GESTimeline to a file using
|
||||
*/
|
||||
|
||||
struct _GESPitiviFormatter {
|
||||
GESFormatter parent;
|
||||
|
||||
/*< private >*/
|
||||
GESPitiviFormatterPrivate *priv;
|
||||
|
||||
/* Padding for API extension */
|
||||
gpointer _ges_reserved[GES_PADDING];
|
||||
};
|
||||
|
||||
struct _GESPitiviFormatterClass {
|
||||
/*< private >*/
|
||||
GESFormatterClass parent_class;
|
||||
|
||||
/* Padding for API extension */
|
||||
gpointer _ges_reserved[GES_PADDING];
|
||||
};
|
||||
|
||||
GType ges_pitivi_formatter_get_type (void);
|
||||
|
||||
GESPitiviFormatter *ges_pitivi_formatter_new (void);
|
||||
|
||||
gboolean ges_pitivi_formatter_set_sources (GESPitiviFormatter * formatter, GList * infos);
|
||||
|
||||
GList * ges_pitivi_formatter_get_sources(GESPitiviFormatter * formatter);
|
||||
|
||||
#endif /* _GES_PITIVI_FORMATTER */
|
|
@ -163,7 +163,7 @@ static void
|
|||
gstl_recalculate (GESSimpleTimelineLayer * self)
|
||||
{
|
||||
GList *tmp;
|
||||
GstClockTime pos = 0;
|
||||
gint64 pos = 0;
|
||||
gint priority = 0;
|
||||
gint transition_priority = 0;
|
||||
gint height;
|
||||
|
@ -210,9 +210,11 @@ gstl_recalculate (GESSimpleTimelineLayer * self)
|
|||
} else if (GES_IS_TIMELINE_TRANSITION (obj)) {
|
||||
|
||||
pos -= dur;
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
|
||||
GST_LOG ("%p obj: height: %d: trans_priority %d", obj, height,
|
||||
transition_priority);
|
||||
GST_LOG ("%p obj: height: %d: trans_priority %d Position: %d, "
|
||||
"duration %d", obj, height, transition_priority, pos);
|
||||
|
||||
g_assert (transition_priority != -1);
|
||||
|
||||
|
|
|
@ -44,10 +44,6 @@ struct _GESTimelineFileSourcePrivate
|
|||
gboolean is_image;
|
||||
|
||||
guint64 maxduration;
|
||||
|
||||
/* The formats supported by this filesource
|
||||
* TODO : Could maybe be moved to a parent class */
|
||||
GESTrackType supportedformats;
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -56,7 +52,6 @@ enum
|
|||
PROP_URI,
|
||||
PROP_MAX_DURATION,
|
||||
PROP_MUTE,
|
||||
PROP_SUPPORTED_FORMATS,
|
||||
PROP_IS_IMAGE,
|
||||
};
|
||||
|
||||
|
@ -64,6 +59,8 @@ enum
|
|||
static GESTrackObject
|
||||
* ges_timeline_filesource_create_track_object (GESTimelineObject * obj,
|
||||
GESTrack * track);
|
||||
void
|
||||
ges_timeline_filesource_set_uri (GESTimelineFileSource * self, gchar * uri);
|
||||
|
||||
static void
|
||||
ges_timeline_filesource_get_property (GObject * object, guint property_id,
|
||||
|
@ -81,9 +78,6 @@ ges_timeline_filesource_get_property (GObject * object, guint property_id,
|
|||
case PROP_MAX_DURATION:
|
||||
g_value_set_uint64 (value, priv->maxduration);
|
||||
break;
|
||||
case PROP_SUPPORTED_FORMATS:
|
||||
g_value_set_flags (value, priv->supportedformats);
|
||||
break;
|
||||
case PROP_IS_IMAGE:
|
||||
g_value_set_boolean (value, priv->is_image);
|
||||
break;
|
||||
|
@ -100,7 +94,7 @@ ges_timeline_filesource_set_property (GObject * object, guint property_id,
|
|||
|
||||
switch (property_id) {
|
||||
case PROP_URI:
|
||||
tfs->priv->uri = g_value_dup_string (value);
|
||||
ges_timeline_filesource_set_uri (tfs, g_value_dup_string (value));
|
||||
break;
|
||||
case PROP_MUTE:
|
||||
ges_timeline_filesource_set_mute (tfs, g_value_get_boolean (value));
|
||||
|
@ -109,10 +103,6 @@ ges_timeline_filesource_set_property (GObject * object, guint property_id,
|
|||
ges_timeline_filesource_set_max_duration (tfs,
|
||||
g_value_get_uint64 (value));
|
||||
break;
|
||||
case PROP_SUPPORTED_FORMATS:
|
||||
ges_timeline_filesource_set_supported_formats (tfs,
|
||||
g_value_get_flags (value));
|
||||
break;
|
||||
case PROP_IS_IMAGE:
|
||||
ges_timeline_filesource_set_is_image (tfs, g_value_get_boolean (value));
|
||||
break;
|
||||
|
@ -151,7 +141,7 @@ ges_timeline_filesource_class_init (GESTimelineFileSourceClass * klass)
|
|||
*/
|
||||
g_object_class_install_property (object_class, PROP_URI,
|
||||
g_param_spec_string ("uri", "URI", "uri of the resource",
|
||||
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
/**
|
||||
* GESTimelineFileSource:max-duration:
|
||||
|
@ -175,16 +165,6 @@ ges_timeline_filesource_class_init (GESTimelineFileSourceClass * klass)
|
|||
g_param_spec_boolean ("mute", "Mute", "Mute audio track",
|
||||
FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
/**
|
||||
* GESTimelineFileSource:supported-formats:
|
||||
*
|
||||
* The formats supported by the filesource.
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_SUPPORTED_FORMATS,
|
||||
g_param_spec_flags ("supported-formats", "Supported formats",
|
||||
"Formats supported by the file", GES_TYPE_TRACK_TYPE,
|
||||
GES_TRACK_TYPE_UNKNOWN, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
/**
|
||||
* GESTimelineFileSource:is-image:
|
||||
*
|
||||
|
@ -255,6 +235,7 @@ ges_timeline_filesource_set_max_duration (GESTimelineFileSource * self,
|
|||
guint64 maxduration)
|
||||
{
|
||||
GESTimelineObject *object = GES_TIMELINE_OBJECT (self);
|
||||
GList *tmp, *tckobjs;
|
||||
|
||||
self->priv->maxduration = maxduration;
|
||||
if (object->duration == GST_CLOCK_TIME_NONE || object->duration == 0) {
|
||||
|
@ -262,6 +243,15 @@ ges_timeline_filesource_set_max_duration (GESTimelineFileSource * self,
|
|||
g_object_set (self, "duration", self->priv->maxduration - object->inpoint,
|
||||
NULL);
|
||||
}
|
||||
|
||||
tckobjs = ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (self));
|
||||
for (tmp = tckobjs; tmp; tmp = g_list_next (tmp)) {
|
||||
g_object_set (tmp->data, "max-duration", maxduration, NULL);
|
||||
|
||||
/* We free the list in the same loop */
|
||||
g_object_unref (tmp->data);
|
||||
g_list_free_1 (tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -276,7 +266,8 @@ void
|
|||
ges_timeline_filesource_set_supported_formats (GESTimelineFileSource * self,
|
||||
GESTrackType supportedformats)
|
||||
{
|
||||
self->priv->supportedformats = supportedformats;
|
||||
ges_timeline_object_set_supported_formats (GES_TIMELINE_OBJECT (self),
|
||||
supportedformats);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -360,7 +351,7 @@ ges_timeline_filesource_get_uri (GESTimelineFileSource * self)
|
|||
GESTrackType
|
||||
ges_timeline_filesource_get_supported_formats (GESTimelineFileSource * self)
|
||||
{
|
||||
return self->priv->supportedformats;
|
||||
return ges_timeline_object_get_supported_formats (GES_TIMELINE_OBJECT (self));
|
||||
}
|
||||
|
||||
static GESTrackObject *
|
||||
|
@ -370,15 +361,15 @@ ges_timeline_filesource_create_track_object (GESTimelineObject * obj,
|
|||
GESTimelineFileSourcePrivate *priv = GES_TIMELINE_FILE_SOURCE (obj)->priv;
|
||||
GESTrackObject *res;
|
||||
|
||||
if (!(priv->supportedformats & track->type)) {
|
||||
if (!(ges_timeline_object_get_supported_formats (obj) & track->type)) {
|
||||
GST_DEBUG ("We don't support this track format");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (priv->is_image) {
|
||||
if (track->type != GES_TRACK_TYPE_VIDEO) {
|
||||
GST_DEBUG ("Object is still image, creating silent audio source");
|
||||
res = (GESTrackObject *) ges_track_audio_test_source_new ();
|
||||
GST_DEBUG ("Object is still image, not adding any audio source");
|
||||
return NULL;
|
||||
} else {
|
||||
GST_DEBUG ("Creating a GESTrackImageSource");
|
||||
res = (GESTrackObject *) ges_track_image_source_new (priv->uri);
|
||||
|
@ -418,3 +409,20 @@ ges_timeline_filesource_new (gchar * uri)
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
ges_timeline_filesource_set_uri (GESTimelineFileSource * self, gchar * uri)
|
||||
{
|
||||
GESTimelineObject *tlobj = GES_TIMELINE_OBJECT (self);
|
||||
GList *tckobjs = ges_timeline_object_get_track_objects (tlobj);
|
||||
|
||||
if (tckobjs) {
|
||||
/* FIXME handle this case properly */
|
||||
GST_WARNING_OBJECT (tlobj, "Can not change uri when already"
|
||||
"containing TrackObjects");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
self->priv->uri = uri;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* GStreamer Editing Services
|
||||
* Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
|
||||
* 2009 Nokia Corporation
|
||||
* 2011 Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -20,7 +21,7 @@
|
|||
|
||||
/**
|
||||
* SECTION:ges-timeline-layer
|
||||
* @short_description: Non-overlaping sequence of #GESTimelineObject
|
||||
* @short_description: Non-overlapping sequence of #GESTimelineObject
|
||||
*
|
||||
* Responsible for the ordering of the various contained TimelineObject(s). A
|
||||
* timeline layer has a "priority" property, which is used to manage the
|
||||
|
@ -32,23 +33,48 @@
|
|||
#include "gesmarshal.h"
|
||||
#include "ges-timeline-layer.h"
|
||||
#include "ges.h"
|
||||
#include "ges-timeline-source.h"
|
||||
|
||||
#define LAYER_HEIGHT 1000
|
||||
|
||||
static void
|
||||
track_object_removed_cb (GESTimelineObject * object,
|
||||
GESTrackObject * track_object);
|
||||
static void track_object_added_cb (GESTimelineObject * object,
|
||||
GESTrackObject * track_object, GHashTable * signal_table);
|
||||
static void track_object_changed_cb (GESTrackObject * track_object,
|
||||
GParamSpec * arg G_GNUC_UNUSED);
|
||||
static void calculate_transitions (GESTrackObject * track_object);
|
||||
static void calculate_next_transition (GESTrackObject * track_object,
|
||||
GESTimelineLayer * layer);
|
||||
|
||||
static void
|
||||
timeline_object_height_changed_cb (GESTimelineObject * obj,
|
||||
GESTrackEffect * tr_eff, GESTimelineObject * second_obj);
|
||||
|
||||
G_DEFINE_TYPE (GESTimelineLayer, ges_timeline_layer, G_TYPE_INITIALLY_UNOWNED);
|
||||
|
||||
struct _GESTimelineLayerPrivate
|
||||
{
|
||||
/*< private > */
|
||||
GSList *objects_start; /* The TimelineObjects sorted by start and
|
||||
GList *objects_start; /* The TimelineObjects sorted by start and
|
||||
* priority */
|
||||
|
||||
guint32 priority; /* The priority of the layer within the
|
||||
* containing timeline */
|
||||
|
||||
gboolean auto_transition;
|
||||
|
||||
|
||||
GHashTable *signal_table;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PRIORITY,
|
||||
PROP_AUTO_TRANSITION,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -62,6 +88,11 @@ static guint ges_timeline_layer_signals[LAST_SIGNAL] = { 0 };
|
|||
|
||||
static gboolean ges_timeline_layer_resync_priorities (GESTimelineLayer * layer);
|
||||
|
||||
static GList *track_get_by_layer (GESTimelineLayer * layer, GESTrack * track);
|
||||
|
||||
static void compare (GList * compared, GESTrackObject * track_object,
|
||||
gboolean ahead);
|
||||
|
||||
static void
|
||||
ges_timeline_layer_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
|
@ -72,6 +103,9 @@ ges_timeline_layer_get_property (GObject * object, guint property_id,
|
|||
case PROP_PRIORITY:
|
||||
g_value_set_uint (value, layer->priv->priority);
|
||||
break;
|
||||
case PROP_AUTO_TRANSITION:
|
||||
g_value_set_boolean (value, layer->priv->auto_transition);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
|
@ -87,6 +121,10 @@ ges_timeline_layer_set_property (GObject * object, guint property_id,
|
|||
case PROP_PRIORITY:
|
||||
ges_timeline_layer_set_priority (layer, g_value_get_uint (value));
|
||||
break;
|
||||
case PROP_AUTO_TRANSITION:
|
||||
ges_timeline_layer_set_auto_transition (layer,
|
||||
g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
|
@ -130,6 +168,15 @@ ges_timeline_layer_class_init (GESTimelineLayerClass * klass)
|
|||
g_param_spec_uint ("priority", "Priority",
|
||||
"The priority of the layer", 0, G_MAXUINT, 0, G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* GESTimelineLayer:auto-transition
|
||||
*
|
||||
* Sets whether transitions are added automagically when timeline objects overlap.
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_AUTO_TRANSITION,
|
||||
g_param_spec_boolean ("auto-transition", "Auto-Transition",
|
||||
"whether the transitions are added", FALSE, G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* GESTimelineLayer::object-added
|
||||
* @layer: the #GESTimelineLayer
|
||||
|
@ -155,7 +202,6 @@ ges_timeline_layer_class_init (GESTimelineLayerClass * klass)
|
|||
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineLayerClass,
|
||||
object_removed), NULL, NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
|
||||
GES_TYPE_TIMELINE_OBJECT);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -164,10 +210,13 @@ ges_timeline_layer_init (GESTimelineLayer * self)
|
|||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
GES_TYPE_TIMELINE_LAYER, GESTimelineLayerPrivate);
|
||||
|
||||
/* TODO : Keep those 3 values in sync */
|
||||
self->priv->priority = 0;
|
||||
self->priv->auto_transition = FALSE;
|
||||
self->min_gnl_priority = 0;
|
||||
self->max_gnl_priority = 9;
|
||||
self->max_gnl_priority = LAYER_HEIGHT;
|
||||
self->priv->signal_table =
|
||||
g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,6 +258,27 @@ objects_start_compare (GESTimelineObject * a, GESTimelineObject * b)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static GList *
|
||||
track_get_by_layer (GESTimelineLayer * layer, GESTrack * track)
|
||||
{
|
||||
GList *tck_objects_list = NULL, *tmp = NULL, *return_list = NULL;
|
||||
GESTimelineObject *tl_obj;
|
||||
|
||||
tck_objects_list = ges_track_get_objects (track);
|
||||
for (tmp = tck_objects_list; tmp; tmp = tmp->next) {
|
||||
tl_obj = ges_track_object_get_timeline_object (tmp->data);
|
||||
|
||||
if (ges_timeline_object_get_layer (tl_obj) == layer) {
|
||||
/* We steal the reference from tck_objects_list */
|
||||
return_list = g_list_append (return_list, tmp->data);
|
||||
|
||||
} else
|
||||
g_object_unref (tmp->data);
|
||||
}
|
||||
|
||||
return return_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_layer_add_object:
|
||||
* @layer: a #GESTimelineLayer
|
||||
|
@ -222,12 +292,12 @@ objects_start_compare (GESTimelineObject * a, GESTimelineObject * b)
|
|||
* Returns: TRUE if the object was properly added to the layer, or FALSE
|
||||
* if the @layer refuses to add the object.
|
||||
*/
|
||||
|
||||
gboolean
|
||||
ges_timeline_layer_add_object (GESTimelineLayer * layer,
|
||||
GESTimelineObject * object)
|
||||
{
|
||||
GESTimelineLayer *tl_obj_layer;
|
||||
guint32 maxprio, minprio, prio;
|
||||
|
||||
GST_DEBUG ("layer:%p, object:%p", layer, object);
|
||||
|
||||
|
@ -243,9 +313,19 @@ ges_timeline_layer_add_object (GESTimelineLayer * layer,
|
|||
|
||||
/* Take a reference to the object and store it stored by start/priority */
|
||||
layer->priv->objects_start =
|
||||
g_slist_insert_sorted (layer->priv->objects_start, object,
|
||||
g_list_insert_sorted (layer->priv->objects_start, object,
|
||||
(GCompareFunc) objects_start_compare);
|
||||
|
||||
/* We have to wait for the track objects to be created to calculate transitions */
|
||||
if (layer->priv->auto_transition) {
|
||||
if (GES_IS_TIMELINE_SOURCE (object)) {
|
||||
g_signal_connect (G_OBJECT (object), "track-object-added",
|
||||
G_CALLBACK (track_object_added_cb), layer->priv->signal_table);
|
||||
g_signal_connect (G_OBJECT (object), "track-object-removed",
|
||||
G_CALLBACK (track_object_removed_cb), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Inform the object it's now in this layer */
|
||||
ges_timeline_object_set_layer (object, layer);
|
||||
|
||||
|
@ -254,13 +334,19 @@ ges_timeline_layer_add_object (GESTimelineLayer * layer,
|
|||
layer->min_gnl_priority, layer->max_gnl_priority);
|
||||
|
||||
/* Set the priority. */
|
||||
if (GES_TIMELINE_OBJECT_PRIORITY (object) > (layer->max_gnl_priority)) {
|
||||
ges_timeline_object_set_priority (object, layer->max_gnl_priority);
|
||||
maxprio = layer->max_gnl_priority;
|
||||
minprio = layer->min_gnl_priority;
|
||||
prio = GES_TIMELINE_OBJECT_PRIORITY (object);
|
||||
if (minprio + prio > (maxprio)) {
|
||||
GST_WARNING ("%p is out of the layer %p space, setting its priority to "
|
||||
"setting its priority %d to failthe maximum priority of the layer %d",
|
||||
object, layer, prio, maxprio - minprio);
|
||||
ges_timeline_object_set_priority (object, LAYER_HEIGHT - 1);
|
||||
}
|
||||
/* If the object has an acceptable priority, we just let it with its current
|
||||
* priority */
|
||||
|
||||
else if (GES_TIMELINE_OBJECT_PRIORITY (object) < (layer->min_gnl_priority)) {
|
||||
ges_timeline_object_set_priority (object, layer->min_gnl_priority);
|
||||
}
|
||||
ges_timeline_layer_resync_priorities (layer);
|
||||
|
||||
/* emit 'object-added' */
|
||||
g_signal_emit (layer, ges_timeline_layer_signals[OBJECT_ADDED], 0, object);
|
||||
|
@ -268,6 +354,412 @@ ges_timeline_layer_add_object (GESTimelineLayer * layer,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
track_object_duration_cb (GESTrackObject * track_object,
|
||||
GParamSpec * arg G_GNUC_UNUSED)
|
||||
{
|
||||
GESTimelineLayer *layer;
|
||||
GESTimelineObject *tlobj;
|
||||
|
||||
tlobj = ges_track_object_get_timeline_object (track_object);
|
||||
layer = ges_timeline_object_get_layer (tlobj);
|
||||
if (G_LIKELY (GES_IS_TRACK_SOURCE (track_object)))
|
||||
GST_DEBUG ("Here we should recalculate");
|
||||
calculate_next_transition (track_object, layer);
|
||||
}
|
||||
|
||||
static void
|
||||
track_object_deleted_cb (GESTrack * track, GESTrackObject * track_object)
|
||||
{
|
||||
GList *track_objects, *tmp, *cur;
|
||||
GESTimelineLayer *layer;
|
||||
|
||||
track_objects = ges_track_get_objects (track);
|
||||
cur = g_list_find (track_objects, track_object);
|
||||
for (tmp = cur->next; tmp; tmp = tmp->next) {
|
||||
if (GES_IS_TRACK_SOURCE (tmp->data)) {
|
||||
break;
|
||||
}
|
||||
if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
|
||||
|| GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
|
||||
layer =
|
||||
ges_timeline_object_get_layer (ges_track_object_get_timeline_object
|
||||
(tmp->data));
|
||||
if (ges_timeline_layer_get_auto_transition (layer)) {
|
||||
ges_track_enable_update (track, FALSE);
|
||||
ges_timeline_layer_remove_object (layer,
|
||||
ges_track_object_get_timeline_object (tmp->data));
|
||||
ges_track_enable_update (track, TRUE);
|
||||
}
|
||||
g_object_unref (layer);
|
||||
}
|
||||
}
|
||||
|
||||
for (tmp = cur->prev; tmp; tmp = tmp->prev) {
|
||||
if (GES_IS_TRACK_SOURCE (tmp->data)) {
|
||||
break;
|
||||
}
|
||||
if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
|
||||
|| GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
|
||||
layer =
|
||||
ges_timeline_object_get_layer (ges_track_object_get_timeline_object
|
||||
(tmp->data));
|
||||
if (ges_timeline_layer_get_auto_transition (layer)) {
|
||||
ges_track_enable_update (track, FALSE);
|
||||
ges_timeline_layer_remove_object (layer,
|
||||
ges_track_object_get_timeline_object (tmp->data));
|
||||
ges_track_enable_update (track, TRUE);
|
||||
}
|
||||
g_object_unref (layer);
|
||||
}
|
||||
}
|
||||
g_object_unref (track_object);
|
||||
}
|
||||
|
||||
static void
|
||||
track_object_added_cb (GESTimelineObject * object,
|
||||
GESTrackObject * track_object, GHashTable * signal_table)
|
||||
{
|
||||
GESTrack *track;
|
||||
gint ptr;
|
||||
|
||||
if (GES_IS_TRACK_SOURCE (track_object)) {
|
||||
g_signal_connect (G_OBJECT (track_object), "notify::start",
|
||||
G_CALLBACK (track_object_changed_cb), NULL);
|
||||
g_signal_connect (G_OBJECT (track_object), "notify::duration",
|
||||
G_CALLBACK (track_object_duration_cb), NULL);
|
||||
calculate_transitions (track_object);
|
||||
}
|
||||
track = ges_track_object_get_track (track_object);
|
||||
if (!g_hash_table_lookup (signal_table, track)) {
|
||||
ptr = g_signal_connect (track, "track-object-removed",
|
||||
(GCallback) track_object_deleted_cb, NULL);
|
||||
g_hash_table_insert (signal_table, track, GINT_TO_POINTER (ptr));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
track_object_removed_cb (GESTimelineObject * object,
|
||||
GESTrackObject * track_object)
|
||||
{
|
||||
return;
|
||||
if (GES_IS_TRACK_SOURCE (track_object)) {
|
||||
g_signal_handlers_disconnect_by_func (track_object, track_object_changed_cb,
|
||||
object);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_object_height_changed_cb (GESTimelineObject * obj,
|
||||
GESTrackEffect * tr_eff, GESTimelineObject * second_obj)
|
||||
{
|
||||
gint priority, height;
|
||||
g_object_get (obj, "height", &height, "priority", &priority, NULL);
|
||||
g_object_set (second_obj, "priority", priority + height, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
track_object_changed_cb (GESTrackObject * track_object,
|
||||
GParamSpec * arg G_GNUC_UNUSED)
|
||||
{
|
||||
if (G_LIKELY (GES_IS_TRACK_SOURCE (track_object)))
|
||||
calculate_transitions (track_object);
|
||||
}
|
||||
|
||||
static void
|
||||
calculate_next_transition_with_list (GESTrackObject * track_object,
|
||||
GList * tckobjs_in_layer, GESTimelineLayer * layer)
|
||||
{
|
||||
GList *compared;
|
||||
|
||||
if (!(compared = g_list_find (tckobjs_in_layer, track_object)))
|
||||
return;
|
||||
|
||||
if (compared == NULL)
|
||||
/* This is the last TrackObject of the Track */
|
||||
return;
|
||||
|
||||
do {
|
||||
compared = compared->next;
|
||||
if (compared == NULL)
|
||||
return;
|
||||
} while (!GES_IS_TRACK_SOURCE (compared->data));
|
||||
|
||||
compare (compared, track_object, FALSE);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calculate_next_transition (GESTrackObject * track_object,
|
||||
GESTimelineLayer * layer)
|
||||
{
|
||||
GESTrack *track = ges_track_object_get_track (track_object);
|
||||
GList *tckobjs_in_layer = track_get_by_layer (layer, track);
|
||||
|
||||
if (ges_track_object_get_track (track_object)) {
|
||||
calculate_next_transition_with_list (track_object, tckobjs_in_layer, layer);
|
||||
}
|
||||
|
||||
g_list_foreach (tckobjs_in_layer, (GFunc) g_object_unref, NULL);
|
||||
g_list_free (tckobjs_in_layer);
|
||||
}
|
||||
|
||||
static void
|
||||
calculate_transitions (GESTrackObject * track_object)
|
||||
{
|
||||
GList *tckobjs_in_layer, *compared;
|
||||
GESTrack *track = ges_track_object_get_track (track_object);
|
||||
GESTimelineLayer *layer;
|
||||
GESTimelineObject *tlobj;
|
||||
|
||||
tlobj = ges_track_object_get_timeline_object (track_object);
|
||||
layer = ges_timeline_object_get_layer (tlobj);
|
||||
tckobjs_in_layer = track_get_by_layer (layer, track);
|
||||
if (!(compared = g_list_find (tckobjs_in_layer, track_object)))
|
||||
return;
|
||||
do {
|
||||
compared = compared->prev;
|
||||
|
||||
if (compared == NULL) {
|
||||
/* Nothing before, let's check after */
|
||||
calculate_next_transition_with_list (track_object, tckobjs_in_layer,
|
||||
layer);
|
||||
goto done;
|
||||
|
||||
}
|
||||
} while (!GES_IS_TRACK_SOURCE (compared->data));
|
||||
|
||||
compare (compared, track_object, TRUE);
|
||||
|
||||
calculate_next_transition_with_list (track_object, tckobjs_in_layer, layer);
|
||||
|
||||
done:
|
||||
g_list_foreach (tckobjs_in_layer, (GFunc) g_object_unref, NULL);
|
||||
g_list_free (tckobjs_in_layer);
|
||||
}
|
||||
|
||||
|
||||
/* Compare:
|
||||
* @compared: The #GList of #GESTrackObjects that we compare with @track_object
|
||||
* @track_object: The #GESTrackObject that serves as a reference
|
||||
* @ahead: %TRUE if we are comparing frontward %FALSE if we are comparing
|
||||
* backward*/
|
||||
static void
|
||||
compare (GList * compared, GESTrackObject * track_object, gboolean ahead)
|
||||
{
|
||||
GList *tmp;
|
||||
gint64 start, duration, compared_start, compared_duration, end, compared_end,
|
||||
tr_start, tr_duration;
|
||||
GESTimelineStandardTransition *trans = NULL;
|
||||
GESTrack *track;
|
||||
GESTimelineLayer *layer;
|
||||
GESTimelineObject *object, *compared_object, *first_object, *second_object;
|
||||
gint priority;
|
||||
|
||||
g_return_if_fail (compared);
|
||||
|
||||
GST_DEBUG ("Recalculating transitions");
|
||||
|
||||
object = ges_track_object_get_timeline_object (track_object);
|
||||
|
||||
if (!object) {
|
||||
GST_WARNING ("Trackobject not in a timeline object: "
|
||||
"Can not calulate transitions");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
compared_object = ges_track_object_get_timeline_object (compared->data);
|
||||
layer = ges_timeline_object_get_layer (object);
|
||||
|
||||
start = ges_track_object_get_start (track_object);
|
||||
duration = ges_track_object_get_duration (track_object);
|
||||
compared_start = ges_track_object_get_start (compared->data);
|
||||
compared_duration = ges_track_object_get_duration (compared->data);
|
||||
end = start + duration;
|
||||
compared_end = compared_start + compared_duration;
|
||||
|
||||
if (ahead) {
|
||||
/* Make sure we remove the last transition we created it is not needed
|
||||
* FIXME make it a smarter way */
|
||||
if (compared->prev && GES_IS_TRACK_TRANSITION (compared->prev->data)) {
|
||||
trans = GES_TIMELINE_STANDARD_TRANSITION
|
||||
(ges_track_object_get_timeline_object (compared->prev->data));
|
||||
g_object_get (compared->prev->data, "start", &tr_start, "duration",
|
||||
&tr_duration, NULL);
|
||||
if (tr_start >= compared_start && tr_start + tr_duration <= compared_end)
|
||||
ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
|
||||
trans = NULL;
|
||||
}
|
||||
|
||||
for (tmp = compared->next; tmp; tmp = tmp->next) {
|
||||
/* If we have a transitionmnmnm we recaluculuculate its values */
|
||||
if (GES_IS_TRACK_TRANSITION (tmp->data)) {
|
||||
g_object_get (tmp->data, "start", &tr_start, "duration", &tr_duration,
|
||||
NULL);
|
||||
|
||||
if (tr_start + tr_duration == compared_start + compared_duration) {
|
||||
GESTimelineObject *tlobj;
|
||||
tlobj = ges_track_object_get_timeline_object (tmp->data);
|
||||
|
||||
trans = GES_TIMELINE_STANDARD_TRANSITION (tlobj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (compared_end <= start) {
|
||||
if (trans) {
|
||||
ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
|
||||
g_object_get (compared_object, "priority", &priority, NULL);
|
||||
g_object_set (object, "priority", priority, NULL);
|
||||
}
|
||||
|
||||
goto clean;
|
||||
} else if (start > compared_start && end < compared_end) {
|
||||
if (trans) {
|
||||
/* Transition not needed anymore */
|
||||
ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
|
||||
}
|
||||
goto clean;
|
||||
} else if (start <= compared_start) {
|
||||
if (trans) {
|
||||
ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
|
||||
}
|
||||
|
||||
goto clean;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (compared->next && GES_IS_TRACK_TRANSITION (compared->next->data)) {
|
||||
trans = GES_TIMELINE_STANDARD_TRANSITION
|
||||
(ges_track_object_get_timeline_object (compared->next->data));
|
||||
g_object_get (compared->prev->data, "start", &tr_start, "duration",
|
||||
&tr_duration, NULL);
|
||||
if (tr_start >= compared_start && tr_start + tr_duration <= compared_end)
|
||||
ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
|
||||
trans = NULL;
|
||||
}
|
||||
for (tmp = compared->prev; tmp; tmp = tmp->prev) {
|
||||
if GES_IS_TRACK_TRANSITION
|
||||
(tmp->data) {
|
||||
g_object_get (tmp->data, "start", &tr_start, "duration", &tr_duration,
|
||||
NULL);
|
||||
if (tr_start == compared_start) {
|
||||
trans = GES_TIMELINE_STANDARD_TRANSITION
|
||||
(ges_track_object_get_timeline_object (tmp->data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start + duration <= compared_start) {
|
||||
if (trans) {
|
||||
ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
|
||||
g_object_get (object, "priority", &priority, NULL);
|
||||
g_object_set (compared_object, "priority", priority, NULL);
|
||||
}
|
||||
goto clean;
|
||||
|
||||
} else if (start > compared_start) {
|
||||
if (trans)
|
||||
ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
|
||||
|
||||
goto clean;
|
||||
} else if (start < compared_start && end > compared_end) {
|
||||
if (trans) {
|
||||
ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
|
||||
}
|
||||
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
if (!trans) {
|
||||
gint height;
|
||||
|
||||
trans =
|
||||
ges_timeline_standard_transition_new_for_nick ((gchar *) "crossfade");
|
||||
track = ges_track_object_get_track (track_object);
|
||||
|
||||
ges_timeline_object_set_supported_formats (GES_TIMELINE_OBJECT (trans),
|
||||
track->type);
|
||||
|
||||
ges_timeline_layer_add_object (layer, GES_TIMELINE_OBJECT (trans));
|
||||
|
||||
if (ahead) {
|
||||
first_object = ges_track_object_get_timeline_object (compared->data);
|
||||
second_object = object;
|
||||
} else {
|
||||
second_object = ges_track_object_get_timeline_object (compared->data);
|
||||
first_object = object;
|
||||
}
|
||||
|
||||
g_object_get (first_object, "priority", &priority, "height", &height, NULL);
|
||||
g_object_set (second_object, "priority", priority + height, NULL);
|
||||
g_signal_connect (first_object, "notify::height",
|
||||
(GCallback) timeline_object_height_changed_cb, second_object);
|
||||
}
|
||||
|
||||
if (ahead) {
|
||||
g_object_set (trans, "start", start, "duration",
|
||||
compared_duration + compared_start - start, NULL);
|
||||
} else {
|
||||
g_object_set (trans, "start", compared_start, "duration",
|
||||
start + duration - compared_start, NULL);
|
||||
}
|
||||
|
||||
clean:
|
||||
g_object_unref (layer);
|
||||
}
|
||||
|
||||
static void
|
||||
look_for_transition (GESTrackObject * track_object, GESTimelineLayer * layer)
|
||||
{
|
||||
GESTrack *track;
|
||||
GList *track_objects, *tmp, *cur;
|
||||
|
||||
track = ges_track_object_get_track (track_object);
|
||||
|
||||
track_objects = ges_track_get_objects (track);
|
||||
|
||||
cur = g_list_find (track_objects, track_object);
|
||||
|
||||
for (tmp = cur->next; tmp; tmp = tmp->next) {
|
||||
if (GES_IS_TRACK_SOURCE (tmp->data)) {
|
||||
break;
|
||||
}
|
||||
if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
|
||||
|| GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
|
||||
ges_timeline_layer_remove_object (layer,
|
||||
ges_track_object_get_timeline_object (tmp->data));
|
||||
}
|
||||
}
|
||||
|
||||
for (tmp = cur->prev; tmp; tmp = tmp->prev) {
|
||||
if (GES_IS_TRACK_SOURCE (tmp->data)) {
|
||||
break;
|
||||
}
|
||||
if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
|
||||
|| GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
|
||||
ges_timeline_layer_remove_object (layer,
|
||||
ges_track_object_get_timeline_object (tmp->data));
|
||||
}
|
||||
}
|
||||
g_list_foreach (track_objects, (GFunc) g_object_unref, NULL);
|
||||
g_list_free (track_objects);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
disconnect_handlers (GESTrack * track, gpointer * ptr)
|
||||
{
|
||||
g_signal_handler_disconnect (track, GPOINTER_TO_INT (ptr));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_layer_remove_object:
|
||||
* @layer: a #GESTimelineLayer
|
||||
|
@ -286,6 +778,7 @@ ges_timeline_layer_remove_object (GESTimelineLayer * layer,
|
|||
GESTimelineObject * object)
|
||||
{
|
||||
GESTimelineLayer *tl_obj_layer;
|
||||
GList *trackobjects, *tmp;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), FALSE);
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
@ -301,6 +794,20 @@ ges_timeline_layer_remove_object (GESTimelineLayer * layer,
|
|||
}
|
||||
g_object_unref (tl_obj_layer);
|
||||
|
||||
if (layer->priv->auto_transition) {
|
||||
trackobjects = ges_timeline_object_get_track_objects (object);
|
||||
|
||||
for (tmp = trackobjects; tmp; tmp = tmp->next) {
|
||||
look_for_transition (tmp->data, layer);
|
||||
}
|
||||
|
||||
g_list_foreach (trackobjects, (GFunc) g_object_unref, NULL);
|
||||
g_list_free (trackobjects);
|
||||
}
|
||||
|
||||
g_hash_table_foreach_remove (layer->priv->signal_table,
|
||||
(GHRFunc) disconnect_handlers, NULL);
|
||||
|
||||
/* emit 'object-removed' */
|
||||
g_signal_emit (layer, ges_timeline_layer_signals[OBJECT_REMOVED], 0, object);
|
||||
|
||||
|
@ -309,7 +816,7 @@ ges_timeline_layer_remove_object (GESTimelineLayer * layer,
|
|||
|
||||
/* Remove it from our list of controlled objects */
|
||||
layer->priv->objects_start =
|
||||
g_slist_remove (layer->priv->objects_start, object);
|
||||
g_list_remove (layer->priv->objects_start, object);
|
||||
|
||||
/* Remove our reference to the object */
|
||||
g_object_unref (object);
|
||||
|
@ -327,18 +834,18 @@ ges_timeline_layer_remove_object (GESTimelineLayer * layer,
|
|||
gboolean
|
||||
ges_timeline_layer_resync_priorities (GESTimelineLayer * layer)
|
||||
{
|
||||
GSList *tmp;
|
||||
GList *tmp;
|
||||
GESTimelineObject *obj;
|
||||
|
||||
GST_DEBUG ("Resync priorities of %p", layer);
|
||||
|
||||
/* TODO : Inhibit composition updates while doing this.
|
||||
* Ideally we want to do it from an even higher level, but here will
|
||||
* do in the meantime. */
|
||||
|
||||
/* TODO : This is the dumb version where we put everything linearly,
|
||||
* will need to be adjusted for more complex usages (like with
|
||||
* transitions). */
|
||||
for (tmp = layer->priv->objects_start; tmp; tmp = tmp->next) {
|
||||
ges_timeline_object_set_priority ((GESTimelineObject *) tmp->data,
|
||||
layer->min_gnl_priority);
|
||||
obj = GES_TIMELINE_OBJECT (tmp->data);
|
||||
ges_timeline_object_set_priority (obj, GES_TIMELINE_OBJECT_PRIORITY (obj));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -361,14 +868,60 @@ ges_timeline_layer_set_priority (GESTimelineLayer * layer, guint priority)
|
|||
|
||||
if (priority != layer->priv->priority) {
|
||||
layer->priv->priority = priority;
|
||||
layer->min_gnl_priority = (priority * 10);
|
||||
layer->max_gnl_priority = ((priority + 1) * 10) - 1;
|
||||
layer->min_gnl_priority = (priority * LAYER_HEIGHT);
|
||||
layer->max_gnl_priority = ((priority + 1) * LAYER_HEIGHT) - 1;
|
||||
|
||||
/* FIXME : Update controlled object's gnl priority accordingly */
|
||||
ges_timeline_layer_resync_priorities (layer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_layer_get_auto_transition:
|
||||
* @layer: a #GESTimelineLayer
|
||||
*
|
||||
* Gets whether transitions are automatically added when objects
|
||||
* overlap or not.
|
||||
*
|
||||
* Returns: %TRUE if transitions are automatically added, else %FALSE.
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_layer_get_auto_transition (GESTimelineLayer * layer)
|
||||
{
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), 0);
|
||||
|
||||
return layer->priv->auto_transition;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_layer_set_auto_transition:
|
||||
* @layer: a #GESTimelineLayer
|
||||
* @auto_transition: whether the auto_transition is active
|
||||
*
|
||||
* Sets the layer to the given @auto_transition. See the documentation of the
|
||||
* property auto_transition for more information.
|
||||
*/
|
||||
void
|
||||
ges_timeline_layer_set_auto_transition (GESTimelineLayer * layer,
|
||||
gboolean auto_transition)
|
||||
{
|
||||
|
||||
GList *tmp;
|
||||
g_return_if_fail (GES_IS_TIMELINE_LAYER (layer));
|
||||
|
||||
if (auto_transition) {
|
||||
for (tmp = layer->priv->objects_start; tmp; tmp = tmp->next) {
|
||||
if (GES_IS_TIMELINE_SOURCE (tmp->data)) {
|
||||
g_signal_connect (G_OBJECT (tmp->data), "track-object-added",
|
||||
G_CALLBACK (track_object_added_cb), layer);
|
||||
g_signal_connect (G_OBJECT (tmp->data), "track-object-removed",
|
||||
G_CALLBACK (track_object_removed_cb), layer);
|
||||
}
|
||||
}
|
||||
/* FIXME calculate all the transitions at that time */
|
||||
}
|
||||
layer->priv->auto_transition = auto_transition;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_layer_get_priority:
|
||||
* @layer: a #GESTimelineLayer
|
||||
|
@ -400,7 +953,7 @@ GList *
|
|||
ges_timeline_layer_get_objects (GESTimelineLayer * layer)
|
||||
{
|
||||
GList *ret = NULL;
|
||||
GSList *tmp;
|
||||
GList *tmp;
|
||||
GESTimelineLayerClass *klass;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), NULL);
|
||||
|
|
|
@ -102,7 +102,14 @@ gboolean ges_timeline_layer_remove_object (GESTimelineLayer * layer,
|
|||
|
||||
void ges_timeline_layer_set_priority (GESTimelineLayer * layer,
|
||||
guint priority);
|
||||
guint ges_timeline_layer_get_priority (GESTimelineLayer * layer);
|
||||
|
||||
guint ges_timeline_layer_get_priority (GESTimelineLayer * layer);
|
||||
|
||||
gboolean ges_timeline_layer_get_auto_transition (GESTimelineLayer * layer);
|
||||
|
||||
void ges_timeline_layer_set_auto_transition (GESTimelineLayer * layer,
|
||||
gboolean auto_transition);
|
||||
|
||||
GList* ges_timeline_layer_get_objects (GESTimelineLayer * layer);
|
||||
|
||||
G_END_DECLS
|
||||
|
|
|
@ -56,8 +56,28 @@ track_object_priority_changed_cb (GESTrackObject * child,
|
|||
GParamSpec * arg G_GNUC_UNUSED, GESTimelineObject * object);
|
||||
static void update_height (GESTimelineObject * object);
|
||||
|
||||
void
|
||||
tck_object_added_cb (GESTimelineObject * object,
|
||||
GESTrackObject * track_object, GList * track_objects);
|
||||
|
||||
static gint sort_track_effects (gpointer a, gpointer b,
|
||||
GESTimelineObject * object);
|
||||
static void
|
||||
get_layer_priorities (GESTimelineLayer * layer, guint32 * layer_min_gnl_prio,
|
||||
guint32 * layer_max_gnl_prio);
|
||||
|
||||
static gboolean
|
||||
ges_timeline_object_set_start_internal (GESTimelineObject * object,
|
||||
guint64 start);
|
||||
static gboolean ges_timeline_object_set_inpoint_internal (GESTimelineObject *
|
||||
object, guint64 inpoint);
|
||||
static gboolean ges_timeline_object_set_duration_internal (GESTimelineObject *
|
||||
object, guint64 duration);
|
||||
static gboolean ges_timeline_object_set_priority_internal (GESTimelineObject *
|
||||
object, guint32 priority);
|
||||
|
||||
static GESTimelineObject *ges_timeline_object_copy (GESTimelineObject * object,
|
||||
gboolean * deep);
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (GESTimelineObject, ges_timeline_object,
|
||||
G_TYPE_INITIALLY_UNOWNED);
|
||||
|
@ -87,6 +107,8 @@ enum
|
|||
{
|
||||
EFFECT_ADDED,
|
||||
EFFECT_REMOVED,
|
||||
TRACK_OBJECT_ADDED,
|
||||
TRACK_OBJECT_REMOVED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
@ -106,10 +128,16 @@ struct _GESTimelineObjectPrivate
|
|||
* properties so we don't end up in infinite property update loops
|
||||
*/
|
||||
gboolean ignore_notifies;
|
||||
gboolean is_moving;
|
||||
|
||||
GList *mappings;
|
||||
|
||||
guint nb_effects;
|
||||
|
||||
GESTrackObject *initiated_move;
|
||||
|
||||
/* The formats supported by this TimelineObject */
|
||||
GESTrackType supportedformats;
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -121,6 +149,7 @@ enum
|
|||
PROP_PRIORITY,
|
||||
PROP_HEIGHT,
|
||||
PROP_LAYER,
|
||||
PROP_SUPPORTED_FORMATS,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -151,6 +180,9 @@ ges_timeline_object_get_property (GObject * object, guint property_id,
|
|||
case PROP_LAYER:
|
||||
g_value_set_object (value, tobj->priv->layer);
|
||||
break;
|
||||
case PROP_SUPPORTED_FORMATS:
|
||||
g_value_set_flags (value, tobj->priv->supportedformats);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
|
@ -164,16 +196,23 @@ ges_timeline_object_set_property (GObject * object, guint property_id,
|
|||
|
||||
switch (property_id) {
|
||||
case PROP_START:
|
||||
ges_timeline_object_set_start (tobj, g_value_get_uint64 (value));
|
||||
ges_timeline_object_set_start_internal (tobj, g_value_get_uint64 (value));
|
||||
break;
|
||||
case PROP_INPOINT:
|
||||
ges_timeline_object_set_inpoint (tobj, g_value_get_uint64 (value));
|
||||
ges_timeline_object_set_inpoint_internal (tobj,
|
||||
g_value_get_uint64 (value));
|
||||
break;
|
||||
case PROP_DURATION:
|
||||
ges_timeline_object_set_duration (tobj, g_value_get_uint64 (value));
|
||||
ges_timeline_object_set_duration_internal (tobj,
|
||||
g_value_get_uint64 (value));
|
||||
break;
|
||||
case PROP_PRIORITY:
|
||||
ges_timeline_object_set_priority (tobj, g_value_get_uint (value));
|
||||
ges_timeline_object_set_priority_internal (tobj,
|
||||
g_value_get_uint (value));
|
||||
break;
|
||||
case PROP_SUPPORTED_FORMATS:
|
||||
ges_timeline_object_set_supported_formats (tobj,
|
||||
g_value_get_flags (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
|
@ -251,6 +290,21 @@ ges_timeline_object_class_init (GESTimelineObjectClass * klass)
|
|||
g_object_class_install_property (object_class, PROP_HEIGHT,
|
||||
properties[PROP_HEIGHT]);
|
||||
|
||||
/**
|
||||
* GESTimelineObject:supported-formats:
|
||||
*
|
||||
* The formats supported by the object.
|
||||
*
|
||||
* Since: 0.10.XX
|
||||
*/
|
||||
properties[PROP_SUPPORTED_FORMATS] = g_param_spec_flags ("supported-formats",
|
||||
"Supported formats", "Formats supported by the file",
|
||||
GES_TYPE_TRACK_TYPE, GES_TRACK_TYPE_UNKNOWN,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SUPPORTED_FORMATS,
|
||||
properties[PROP_SUPPORTED_FORMATS]);
|
||||
|
||||
/**
|
||||
* GESTimelineObject:layer
|
||||
*
|
||||
|
@ -290,6 +344,34 @@ ges_timeline_object_class_init (GESTimelineObjectClass * klass)
|
|||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, ges_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, GES_TYPE_TRACK_EFFECT);
|
||||
|
||||
/**
|
||||
* GESTimelineObject::track-object-added
|
||||
* @object: the #GESTimelineObject
|
||||
* @tckobj: the #GESTrackObject that was added.
|
||||
*
|
||||
* Will be emitted after a track object was added to the object.
|
||||
*
|
||||
* Since: 0.10.2
|
||||
*/
|
||||
ges_timeline_object_signals[TRACK_OBJECT_ADDED] =
|
||||
g_signal_new ("track-object-added", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, ges_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, GES_TYPE_TRACK_OBJECT);
|
||||
|
||||
/**
|
||||
* GESTimelineObject::track-object-removed
|
||||
* @object: the #GESTimelineObject
|
||||
* @tckobj: the #GESTrackObject that was removed.
|
||||
*
|
||||
* Will be emitted after a track object was removed from @object.
|
||||
*
|
||||
* Since: 0.10.2
|
||||
*/
|
||||
ges_timeline_object_signals[TRACK_OBJECT_REMOVED] =
|
||||
g_signal_new ("track-object-removed", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, ges_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, GES_TYPE_TRACK_OBJECT);
|
||||
|
||||
klass->need_fill_track = TRUE;
|
||||
}
|
||||
|
||||
|
@ -303,6 +385,7 @@ ges_timeline_object_init (GESTimelineObject * self)
|
|||
self->priv->trackobjects = NULL;
|
||||
self->priv->layer = NULL;
|
||||
self->priv->nb_effects = 0;
|
||||
self->priv->is_moving = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -325,6 +408,9 @@ ges_timeline_object_create_track_object (GESTimelineObject * object,
|
|||
GESTimelineObjectClass *class;
|
||||
GESTrackObject *res;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), NULL);
|
||||
g_return_val_if_fail (GES_IS_TRACK (track), NULL);
|
||||
|
||||
class = GES_TIMELINE_OBJECT_GET_CLASS (object);
|
||||
|
||||
if (G_UNLIKELY (class->create_track_object == NULL)) {
|
||||
|
@ -333,7 +419,6 @@ ges_timeline_object_create_track_object (GESTimelineObject * object,
|
|||
}
|
||||
|
||||
res = class->create_track_object (object, track);
|
||||
ges_timeline_object_add_track_object (object, res);
|
||||
return res;
|
||||
|
||||
}
|
||||
|
@ -358,13 +443,15 @@ ges_timeline_object_create_track_objects (GESTimelineObject * object,
|
|||
{
|
||||
GESTimelineObjectClass *klass;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
|
||||
|
||||
klass = GES_TIMELINE_OBJECT_GET_CLASS (object);
|
||||
|
||||
if (!(klass->create_track_objects)) {
|
||||
GST_WARNING ("no GESTimelineObject::create_track_objects implentation");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return klass->create_track_objects (object, track);
|
||||
}
|
||||
|
||||
|
@ -376,13 +463,17 @@ ges_timeline_object_create_track_objects_func (GESTimelineObject * object,
|
|||
GESTrack * track)
|
||||
{
|
||||
GESTrackObject *result;
|
||||
gboolean ret;
|
||||
|
||||
result = ges_timeline_object_create_track_object (object, track);
|
||||
if (!result) {
|
||||
GST_WARNING ("couldn't create track object");
|
||||
GST_DEBUG ("Did not create track object");
|
||||
return FALSE;
|
||||
}
|
||||
return ges_track_add_object (track, result);
|
||||
ges_track_object_set_timeline_object (result, object);
|
||||
ret = ges_track_add_object (track, result);
|
||||
ges_timeline_object_add_track_object (object, result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -404,10 +495,14 @@ ges_timeline_object_add_track_object (GESTimelineObject * object, GESTrackObject
|
|||
{
|
||||
ObjectMapping *mapping;
|
||||
GList *tmp;
|
||||
guint max_prio, min_prio;
|
||||
GESTimelineObjectPrivate *priv = object->priv;
|
||||
gboolean is_effect = GES_IS_TRACK_EFFECT (trobj);
|
||||
GESTimelineObjectClass *klass = GES_TIMELINE_OBJECT_GET_CLASS (object);
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
g_return_val_if_fail (GES_IS_TRACK_OBJECT (trobj), FALSE);
|
||||
|
||||
GST_LOG ("Got a TrackObject : %p , setting the timeline object as its"
|
||||
"creator. Is a TrackEffect %i", trobj, is_effect);
|
||||
|
||||
|
@ -415,6 +510,7 @@ ges_timeline_object_add_track_object (GESTimelineObject * object, GESTrackObject
|
|||
return FALSE;
|
||||
|
||||
ges_track_object_set_timeline_object (trobj, object);
|
||||
|
||||
g_object_ref (trobj);
|
||||
|
||||
mapping = g_slice_new0 (ObjectMapping);
|
||||
|
@ -451,10 +547,6 @@ ges_timeline_object_add_track_object (GESTimelineObject * object, GESTrackObject
|
|||
}
|
||||
|
||||
priv->nb_effects++;
|
||||
|
||||
/* emit 'effect-added' */
|
||||
g_signal_emit (object, ges_timeline_object_signals[EFFECT_ADDED], 0,
|
||||
GES_TRACK_EFFECT (trobj));
|
||||
}
|
||||
|
||||
object->priv->trackobjects =
|
||||
|
@ -487,10 +579,19 @@ ges_timeline_object_add_track_object (GESTimelineObject * object, GESTrackObject
|
|||
g_signal_connect (G_OBJECT (trobj), "notify::priority",
|
||||
G_CALLBACK (track_object_priority_changed_cb), object);
|
||||
|
||||
ges_track_object_set_priority (trobj,
|
||||
object->priority + mapping->priority_offset);
|
||||
get_layer_priorities (priv->layer, &min_prio, &max_prio);
|
||||
ges_track_object_set_priority (trobj, min_prio + object->priority
|
||||
+ mapping->priority_offset);
|
||||
|
||||
GST_DEBUG ("Returning trobj:%p", trobj);
|
||||
if (!GES_IS_TRACK_PARSE_LAUNCH_EFFECT (trobj)) {
|
||||
g_signal_emit (object, ges_timeline_object_signals[TRACK_OBJECT_ADDED], 0,
|
||||
GES_TRACK_OBJECT (trobj));
|
||||
} else {
|
||||
/* emit 'effect-added' */
|
||||
g_signal_emit (object, ges_timeline_object_signals[EFFECT_ADDED], 0,
|
||||
GES_TRACK_EFFECT (trobj));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -512,6 +613,9 @@ ges_timeline_object_release_track_object (GESTimelineObject * object,
|
|||
ObjectMapping *mapping = NULL;
|
||||
GESTimelineObjectClass *klass = GES_TIMELINE_OBJECT_GET_CLASS (object);
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
g_return_val_if_fail (GES_IS_TRACK_OBJECT (trackobject), FALSE);
|
||||
|
||||
GST_DEBUG ("object:%p, trackobject:%p", object, trackobject);
|
||||
|
||||
if (!(g_list_find (object->priv->trackobjects, trackobject))) {
|
||||
|
@ -545,7 +649,9 @@ ges_timeline_object_release_track_object (GESTimelineObject * object,
|
|||
/* emit 'object-removed' */
|
||||
g_signal_emit (object, ges_timeline_object_signals[EFFECT_REMOVED], 0,
|
||||
GES_TRACK_EFFECT (trackobject));
|
||||
}
|
||||
} else
|
||||
g_signal_emit (object, ges_timeline_object_signals[TRACK_OBJECT_REMOVED], 0,
|
||||
GES_TRACK_OBJECT (trackobject));
|
||||
|
||||
ges_track_object_set_timeline_object (trackobject, NULL);
|
||||
|
||||
|
@ -621,20 +727,16 @@ find_object_mapping (GESTimelineObject * object, GESTrackObject * child)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_set_start:
|
||||
* @object: a #GESTimelineObject
|
||||
* @start: the position in #GstClockTime
|
||||
*
|
||||
* Set the position of the object in its containing layer
|
||||
*/
|
||||
void
|
||||
ges_timeline_object_set_start (GESTimelineObject * object, guint64 start)
|
||||
static gboolean
|
||||
ges_timeline_object_set_start_internal (GESTimelineObject * object,
|
||||
guint64 start)
|
||||
{
|
||||
GList *tmp;
|
||||
GESTrackObject *tr;
|
||||
ObjectMapping *map;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
GST_DEBUG ("object:%p, start:%" GST_TIME_FORMAT,
|
||||
object, GST_TIME_ARGS (start));
|
||||
|
||||
|
@ -644,9 +746,17 @@ ges_timeline_object_set_start (GESTimelineObject * object, guint64 start)
|
|||
tr = (GESTrackObject *) tmp->data;
|
||||
map = find_object_mapping (object, tr);
|
||||
|
||||
if (ges_track_object_is_locked (tr)) {
|
||||
if (ges_track_object_is_locked (tr) && tr != object->priv->initiated_move) {
|
||||
gint64 new_start = start - map->start_offset;
|
||||
|
||||
/* Move the child... */
|
||||
ges_track_object_set_start (tr, start + map->start_offset);
|
||||
if (new_start < 0) {
|
||||
GST_ERROR ("Trying to set start to a negative value %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (-(start + map->start_offset)));
|
||||
continue;
|
||||
}
|
||||
|
||||
ges_track_object_set_start (tr, new_start);
|
||||
} else {
|
||||
/* ... or update the offset */
|
||||
map->start_offset = start - tr->start;
|
||||
|
@ -656,22 +766,36 @@ ges_timeline_object_set_start (GESTimelineObject * object, guint64 start)
|
|||
object->priv->ignore_notifies = FALSE;
|
||||
|
||||
object->start = start;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_set_inpoint:
|
||||
* ges_timeline_object_set_start:
|
||||
* @object: a #GESTimelineObject
|
||||
* @inpoint: the in-point in #GstClockTime
|
||||
* @start: the position in #GstClockTime
|
||||
*
|
||||
* Set the in-point, that is the moment at which the @object will start
|
||||
* outputting data from its contents.
|
||||
* Set the position of the object in its containing layer
|
||||
*/
|
||||
void
|
||||
ges_timeline_object_set_inpoint (GESTimelineObject * object, guint64 inpoint)
|
||||
ges_timeline_object_set_start (GESTimelineObject * object, guint64 start)
|
||||
{
|
||||
if (ges_timeline_object_set_start_internal (object, start))
|
||||
#if GLIB_CHECK_VERSION(2,26,0)
|
||||
g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_START]);
|
||||
#else
|
||||
g_object_notify (G_OBJECT (object), "start");
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ges_timeline_object_set_inpoint_internal (GESTimelineObject * object,
|
||||
guint64 inpoint)
|
||||
{
|
||||
GList *tmp;
|
||||
GESTrackObject *tr;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
GST_DEBUG ("object:%p, inpoint:%" GST_TIME_FORMAT,
|
||||
object, GST_TIME_ARGS (inpoint));
|
||||
|
||||
|
@ -684,21 +808,37 @@ ges_timeline_object_set_inpoint (GESTimelineObject * object, guint64 inpoint)
|
|||
}
|
||||
|
||||
object->inpoint = inpoint;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_set_duration:
|
||||
* ges_timeline_object_set_inpoint:
|
||||
* @object: a #GESTimelineObject
|
||||
* @duration: the duration in #GstClockTime
|
||||
* @inpoint: the in-point in #GstClockTime
|
||||
*
|
||||
* Set the duration of the object
|
||||
* Set the in-point, that is the moment at which the @object will start
|
||||
* outputting data from its contents.
|
||||
*/
|
||||
void
|
||||
ges_timeline_object_set_duration (GESTimelineObject * object, guint64 duration)
|
||||
ges_timeline_object_set_inpoint (GESTimelineObject * object, guint64 inpoint)
|
||||
{
|
||||
if (ges_timeline_object_set_inpoint_internal (object, inpoint))
|
||||
#if GLIB_CHECK_VERSION(2,26,0)
|
||||
g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_INPOINT]);
|
||||
#else
|
||||
g_object_notify (G_OBJECT (object), "in-point");
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ges_timeline_object_set_duration_internal (GESTimelineObject * object,
|
||||
guint64 duration)
|
||||
{
|
||||
GList *tmp;
|
||||
GESTrackObject *tr;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
GST_DEBUG ("object:%p, duration:%" GST_TIME_FORMAT,
|
||||
object, GST_TIME_ARGS (duration));
|
||||
|
||||
|
@ -711,6 +851,162 @@ ges_timeline_object_set_duration (GESTimelineObject * object, guint64 duration)
|
|||
}
|
||||
|
||||
object->duration = duration;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_set_duration:
|
||||
* @object: a #GESTimelineObject
|
||||
* @duration: the duration in #GstClockTime
|
||||
*
|
||||
* Set the duration of the object
|
||||
*/
|
||||
void
|
||||
ges_timeline_object_set_duration (GESTimelineObject * object, guint64 duration)
|
||||
{
|
||||
if (ges_timeline_object_set_duration_internal (object, duration))
|
||||
#if GLIB_CHECK_VERSION(2,26,0)
|
||||
g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_DURATION]);
|
||||
#else
|
||||
g_object_notify (G_OBJECT (object), "duration");
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ges_timeline_object_set_priority_internal (GESTimelineObject * object,
|
||||
guint priority)
|
||||
{
|
||||
GList *tmp;
|
||||
GESTrackObject *tr;
|
||||
ObjectMapping *map;
|
||||
GESTimelineObjectPrivate *priv;
|
||||
guint32 layer_min_gnl_prio, layer_max_gnl_prio;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
GST_DEBUG ("object:%p, priority:%" G_GUINT32_FORMAT, object, priority);
|
||||
|
||||
priv = object->priv;
|
||||
priv->ignore_notifies = TRUE;
|
||||
|
||||
object->priv->ignore_notifies = TRUE;
|
||||
|
||||
get_layer_priorities (priv->layer, &layer_min_gnl_prio, &layer_max_gnl_prio);
|
||||
|
||||
for (tmp = priv->trackobjects; tmp; tmp = g_list_next (tmp)) {
|
||||
tr = (GESTrackObject *) tmp->data;
|
||||
map = find_object_mapping (object, tr);
|
||||
|
||||
if (ges_track_object_is_locked (tr)) {
|
||||
guint32 real_tck_prio;
|
||||
|
||||
/* Move the child... */
|
||||
real_tck_prio = layer_min_gnl_prio + priority + map->priority_offset;
|
||||
|
||||
if (real_tck_prio > layer_max_gnl_prio) {
|
||||
GST_WARNING ("%p priority of %i, is outside of the its containing "
|
||||
"layer space. (%d/%d) setting it to the maximum it can be", object,
|
||||
priority, layer_min_gnl_prio, layer_max_gnl_prio);
|
||||
|
||||
real_tck_prio = layer_max_gnl_prio;
|
||||
}
|
||||
|
||||
ges_track_object_set_priority (tr, real_tck_prio);
|
||||
|
||||
} else {
|
||||
/* ... or update the offset */
|
||||
map->priority_offset = tr->priority - layer_min_gnl_prio + priority;
|
||||
}
|
||||
}
|
||||
|
||||
priv->trackobjects = g_list_sort_with_data (priv->trackobjects,
|
||||
(GCompareDataFunc) sort_track_effects, object);
|
||||
priv->ignore_notifies = FALSE;
|
||||
|
||||
object->priority = priority;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_set_moving_from_layer:
|
||||
* @object: a #GESTimelineObject
|
||||
* @is_moving: %TRUE if you want to start moving @object to another layer
|
||||
* %FALSE when you finished moving it.
|
||||
*
|
||||
* Sets the object in a moving to layer state. You might rather use the
|
||||
* ges_timeline_object_move_to_layer function to move #GESTimelineObject-s
|
||||
* from a layer to another.
|
||||
**/
|
||||
void
|
||||
ges_timeline_object_set_moving_from_layer (GESTimelineObject * object,
|
||||
gboolean is_moving)
|
||||
{
|
||||
g_return_if_fail (GES_IS_TRACK_OBJECT (object));
|
||||
|
||||
object->priv->is_moving = is_moving;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_is_moving_from_layer:
|
||||
* @object: a #GESTimelineObject
|
||||
*
|
||||
* Tells you if the object is currently moving from a layer to another.
|
||||
* You might rather use the ges_timeline_object_move_to_layer function to
|
||||
* move #GESTimelineObject-s from a layer to another.
|
||||
*
|
||||
*
|
||||
* Returns: %TRUE if @object is currently moving from its current layer
|
||||
* %FALSE otherwize
|
||||
**/
|
||||
gboolean
|
||||
ges_timeline_object_is_moving_from_layer (GESTimelineObject * object)
|
||||
{
|
||||
return object->priv->is_moving;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_move_to_layer:
|
||||
* @object: a #GESTimelineObject
|
||||
* @layer: the new #GESTimelineLayer
|
||||
*
|
||||
* Moves @object to @layer. If @object is not in any layer, it adds it to
|
||||
* @layer, else, it removes it from its current layer, and adds it to @layer.
|
||||
*
|
||||
* Returns: %TRUE if @object could be moved %FALSE otherwize
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_object_move_to_layer (GESTimelineObject * object, GESTimelineLayer
|
||||
* layer)
|
||||
{
|
||||
gboolean ret;
|
||||
GESTimelineLayer *current_layer;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), FALSE);
|
||||
|
||||
current_layer = object->priv->layer;
|
||||
|
||||
if (current_layer == NULL) {
|
||||
GST_DEBUG ("Not moving %p, only adding it to %p", object, layer);
|
||||
|
||||
return ges_timeline_layer_add_object (layer, object);
|
||||
}
|
||||
|
||||
object->priv->is_moving = TRUE;
|
||||
g_object_ref (object);
|
||||
ret = ges_timeline_layer_remove_object (current_layer, object);
|
||||
|
||||
if (!ret) {
|
||||
g_object_unref (object);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = ges_timeline_layer_add_object (layer, object);
|
||||
object->priv->is_moving = FALSE;
|
||||
|
||||
g_object_unref (object);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -723,33 +1019,12 @@ ges_timeline_object_set_duration (GESTimelineObject * object, guint64 duration)
|
|||
void
|
||||
ges_timeline_object_set_priority (GESTimelineObject * object, guint priority)
|
||||
{
|
||||
GList *tmp;
|
||||
GESTrackObject *tr;
|
||||
ObjectMapping *map;
|
||||
GESTimelineObjectPrivate *priv = object->priv;
|
||||
|
||||
GST_DEBUG ("object:%p, priority:%" G_GUINT32_FORMAT, object, priority);
|
||||
|
||||
priv->ignore_notifies = TRUE;
|
||||
|
||||
for (tmp = priv->trackobjects; tmp; tmp = g_list_next (tmp)) {
|
||||
tr = (GESTrackObject *) tmp->data;
|
||||
map = find_object_mapping (object, tr);
|
||||
|
||||
if (ges_track_object_is_locked (tr)) {
|
||||
/* Move the child... */
|
||||
ges_track_object_set_priority (tr, priority + map->priority_offset);
|
||||
} else {
|
||||
/* ... or update the offset */
|
||||
map->priority_offset = priority - tr->priority;
|
||||
}
|
||||
}
|
||||
|
||||
priv->trackobjects = g_list_sort_with_data (priv->trackobjects,
|
||||
(GCompareDataFunc) sort_track_effects, object);
|
||||
priv->ignore_notifies = FALSE;
|
||||
|
||||
object->priority = priority;
|
||||
if (ges_timeline_object_set_priority_internal (object, priority))
|
||||
#if GLIB_CHECK_VERSION(2,26,0)
|
||||
g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_PRIORITY]);
|
||||
#else
|
||||
g_object_notify (G_OBJECT (object), "priority");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -889,12 +1164,15 @@ ges_timeline_object_get_top_effects (GESTimelineObject * object)
|
|||
GList *tmp, *ret;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), NULL);
|
||||
|
||||
GST_DEBUG_OBJECT (object, "Getting the %i top effects",
|
||||
object->priv->nb_effects);
|
||||
ret = NULL;
|
||||
|
||||
for (tmp = object->priv->trackobjects, i = 0; i < object->priv->nb_effects;
|
||||
tmp = tmp->next, i++) {
|
||||
ret = g_list_append (ret, tmp->data);
|
||||
g_object_ref (tmp->data);
|
||||
ret = g_list_append (ret, g_object_ref (tmp->data));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -915,6 +1193,8 @@ gint
|
|||
ges_timeline_object_get_top_effect_position (GESTimelineObject * object,
|
||||
GESTrackEffect * effect)
|
||||
{
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), -1);
|
||||
|
||||
return find_object_mapping (object,
|
||||
GES_TRACK_OBJECT (effect))->priority_offset;
|
||||
}
|
||||
|
@ -936,12 +1216,18 @@ gboolean
|
|||
ges_timeline_object_set_top_effect_priority (GESTimelineObject * object,
|
||||
GESTrackEffect * effect, guint newpriority)
|
||||
{
|
||||
GList *tmp;
|
||||
gint inc;
|
||||
GESTrackObject *tck_obj = GES_TRACK_OBJECT (effect);
|
||||
GESTimelineObjectPrivate *priv = object->priv;
|
||||
GList *tmp;
|
||||
guint current_prio;
|
||||
GESTrackObject *tck_obj;
|
||||
GESTimelineObjectPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
tck_obj = GES_TRACK_OBJECT (effect);
|
||||
priv = object->priv;
|
||||
current_prio = ges_track_object_get_priority (tck_obj);
|
||||
|
||||
guint current_prio = ges_track_object_get_priority (tck_obj);
|
||||
/* We don't change the priority */
|
||||
if (current_prio == newpriority ||
|
||||
(G_UNLIKELY (ges_track_object_get_timeline_object (tck_obj) != object)))
|
||||
|
@ -979,6 +1265,193 @@ ges_timeline_object_set_top_effect_priority (GESTimelineObject * object,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
tck_object_added_cb (GESTimelineObject * object,
|
||||
GESTrackObject * track_object, GList * track_objects)
|
||||
{
|
||||
gint64 duration, start, inpoint, position;
|
||||
GList *tmp;
|
||||
gboolean locked;
|
||||
|
||||
ges_track_object_set_locked (track_object, FALSE);
|
||||
g_object_get (object, "start", &position, NULL);
|
||||
for (tmp = track_objects; tmp; tmp = tmp->next) {
|
||||
if (ges_track_object_get_track (track_object)->type ==
|
||||
ges_track_object_get_track (tmp->data)->type) {
|
||||
locked = ges_track_object_is_locked (tmp->data);
|
||||
ges_track_object_set_locked (tmp->data, FALSE);
|
||||
g_object_get (tmp->data, "duration", &duration, "start", &start,
|
||||
"in-point", &inpoint, NULL);
|
||||
g_object_set (tmp->data, "duration",
|
||||
duration - (duration + start - position), NULL);
|
||||
g_object_set (track_object, "start", position, "in-point",
|
||||
duration - (duration + start - inpoint - position), "duration",
|
||||
duration + start - position, NULL);
|
||||
ges_track_object_set_locked (tmp->data, locked);
|
||||
ges_track_object_set_locked (track_object, locked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_split:
|
||||
* @object: the #GESTimelineObject to split
|
||||
* @position: The position at which to split the @object (in nanosecond)
|
||||
*
|
||||
* The function modifies @object, and creates another #GESTimelineObject so
|
||||
* we have two clips at the end, splitted at the time specified by @position.
|
||||
*
|
||||
* Returns: (transfer full): The newly created #GESTimelineObject resulting from
|
||||
* the splitting
|
||||
*
|
||||
* Since: 0.10.XX
|
||||
*/
|
||||
GESTimelineObject *
|
||||
ges_timeline_object_split (GESTimelineObject * object, gint64 position)
|
||||
{
|
||||
GList *track_objects, *tmp;
|
||||
GESTimelineLayer *layer;
|
||||
GESTimelineObject *new_object;
|
||||
gint64 duration, start, inpoint;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), NULL);
|
||||
|
||||
g_object_get (object, "duration", &duration, "start", &start, "in-point",
|
||||
&inpoint, NULL);
|
||||
|
||||
track_objects = ges_timeline_object_get_track_objects (object);
|
||||
layer = ges_timeline_object_get_layer (object);
|
||||
|
||||
new_object = ges_timeline_object_copy (object, FALSE);
|
||||
|
||||
if (g_list_length (track_objects) == 2) {
|
||||
g_object_set (new_object, "start", position, NULL);
|
||||
g_signal_connect (G_OBJECT (new_object), "track-object-added",
|
||||
G_CALLBACK (tck_object_added_cb), track_objects);
|
||||
} else {
|
||||
for (tmp = track_objects; tmp; tmp = tmp->next) {
|
||||
g_object_set (tmp->data, "duration",
|
||||
duration - (duration + start - position), NULL);
|
||||
g_object_set (new_object, "start", position, "in-point",
|
||||
duration - (duration + start - position), "duration",
|
||||
(duration + start - position), NULL);
|
||||
g_object_set (object, "duration",
|
||||
duration - (duration + start - position), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
ges_timeline_layer_add_object (layer, new_object);
|
||||
|
||||
return new_object;
|
||||
}
|
||||
|
||||
/* TODO implement the deep parameter, and make it public */
|
||||
static GESTimelineObject *
|
||||
ges_timeline_object_copy (GESTimelineObject * object, gboolean * deep)
|
||||
{
|
||||
GESTimelineObject *ret = NULL;
|
||||
GParameter *params;
|
||||
GParamSpec **specs;
|
||||
guint n, n_specs, n_params;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), NULL);
|
||||
|
||||
specs =
|
||||
g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &n_specs);
|
||||
params = g_new0 (GParameter, n_specs);
|
||||
n_params = 0;
|
||||
|
||||
for (n = 0; n < n_specs; ++n) {
|
||||
if (strcmp (specs[n]->name, "parent") &&
|
||||
(specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE) {
|
||||
params[n_params].name = g_intern_string (specs[n]->name);
|
||||
g_value_init (¶ms[n_params].value, specs[n]->value_type);
|
||||
g_object_get_property (G_OBJECT (object), specs[n]->name,
|
||||
¶ms[n_params].value);
|
||||
++n_params;
|
||||
}
|
||||
}
|
||||
|
||||
ret = g_object_newv (G_TYPE_FROM_INSTANCE (object), n_params, params);
|
||||
|
||||
if (GES_IS_TIMELINE_FILE_SOURCE (ret)) {
|
||||
GList *tck_objects;
|
||||
tck_objects = ges_timeline_object_get_track_objects (object);
|
||||
if (g_list_length (tck_objects) == 1) {
|
||||
GESTrackType type;
|
||||
type = ges_track_object_get_track (tck_objects->data)->type;
|
||||
ges_timeline_filesource_set_supported_formats (GES_TIMELINE_FILE_SOURCE
|
||||
(ret), type);
|
||||
}
|
||||
g_list_free (tck_objects);
|
||||
}
|
||||
|
||||
g_free (specs);
|
||||
g_free (params);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_set_supported_formats:
|
||||
* @object: the #GESTimelineObject to set supported formats on
|
||||
* @supportedformats: the #GESTrackType defining formats supported by @object
|
||||
*
|
||||
* Sets the formats supported by the file.
|
||||
*
|
||||
* Since: 0.10.XX
|
||||
*/
|
||||
void
|
||||
ges_timeline_object_set_supported_formats (GESTimelineObject * object,
|
||||
GESTrackType supportedformats)
|
||||
{
|
||||
g_return_if_fail (GES_IS_TIMELINE_OBJECT (object));
|
||||
|
||||
object->priv->supportedformats = supportedformats;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_get_supported_formats:
|
||||
* @object: the #GESTimelineObject
|
||||
*
|
||||
* Get the formats supported by @object.
|
||||
*
|
||||
* Returns: The formats supported by @object.
|
||||
*
|
||||
* Since: 0.10.XX
|
||||
*/
|
||||
GESTrackType
|
||||
ges_timeline_object_get_supported_formats (GESTimelineObject * object)
|
||||
{
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object),
|
||||
GES_TRACK_TYPE_UNKNOWN);
|
||||
|
||||
return object->priv->supportedformats;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_objects_set_locked:
|
||||
* @object: the #GESTimelineObject
|
||||
* @locked: whether the #GESTrackObject contained in @object are locked to it.
|
||||
*
|
||||
* Set the locking status of all the #GESTrackObject contained in @object to @locked.
|
||||
* See the ges_track_object_set_locked documentation for more details.
|
||||
*
|
||||
* Since: 0.10.XX
|
||||
*/
|
||||
void
|
||||
ges_timeline_object_objects_set_locked (GESTimelineObject * object,
|
||||
gboolean locked)
|
||||
{
|
||||
GList *tmp;
|
||||
|
||||
g_return_if_fail (GES_IS_TIMELINE_OBJECT (object));
|
||||
|
||||
for (tmp = object->priv->mappings; tmp; tmp = g_list_next (tmp)) {
|
||||
ges_track_object_set_locked (((ObjectMapping *) tmp->data)->object, locked);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_height (GESTimelineObject * object)
|
||||
{
|
||||
|
@ -1031,7 +1504,9 @@ track_object_start_changed_cb (GESTrackObject * child,
|
|||
map->start_offset = object->start - child->start;
|
||||
} else {
|
||||
/* Or update the parent start */
|
||||
object->priv->initiated_move = child;
|
||||
ges_timeline_object_set_start (object, child->start + map->start_offset);
|
||||
object->priv->initiated_move = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1058,26 +1533,64 @@ track_object_priority_changed_cb (GESTrackObject * child,
|
|||
GParamSpec * arg G_GNUC_UNUSED, GESTimelineObject * object)
|
||||
{
|
||||
ObjectMapping *map;
|
||||
guint32 layer_min_gnl_prio, layer_max_gnl_prio;
|
||||
|
||||
guint tck_priority = ges_track_object_get_priority (child);
|
||||
|
||||
GST_DEBUG ("Priority changed");
|
||||
GST_DEBUG ("TrackObject %p priority changed to %i", child,
|
||||
ges_track_object_get_priority (child));
|
||||
|
||||
if (object->priv->ignore_notifies)
|
||||
return;
|
||||
|
||||
update_height (object);
|
||||
map = find_object_mapping (object, child);
|
||||
get_layer_priorities (object->priv->layer, &layer_min_gnl_prio,
|
||||
&layer_max_gnl_prio);
|
||||
|
||||
if (G_UNLIKELY (map == NULL))
|
||||
/* something massively screwed up if we get this */
|
||||
return;
|
||||
|
||||
if (!ges_track_object_is_locked (child)) {
|
||||
if (tck_priority < layer_min_gnl_prio || tck_priority > layer_max_gnl_prio) {
|
||||
GST_WARNING ("%p priority of %i, is outside of its containing "
|
||||
"layer space. (%d/%d). This is a bug in the program.", object,
|
||||
tck_priority, layer_min_gnl_prio, layer_max_gnl_prio);
|
||||
}
|
||||
|
||||
/* Update the internal priority_offset */
|
||||
map->priority_offset = object->priority - tck_priority;
|
||||
} else if (tck_priority < object->priority) {
|
||||
map->priority_offset =
|
||||
tck_priority - (layer_min_gnl_prio + object->priority);
|
||||
|
||||
} else if (tck_priority < layer_min_gnl_prio + object->priority) {
|
||||
/* Or update the parent priority, the object priority is always the
|
||||
* highest priority (smaller number) */
|
||||
if (tck_priority < layer_min_gnl_prio || layer_max_gnl_prio < tck_priority) {
|
||||
|
||||
GST_WARNING ("%p priority of %i, is outside of its containing "
|
||||
"layer space. (%d/%d). This is a bug in the program.", object,
|
||||
tck_priority, layer_min_gnl_prio, layer_max_gnl_prio);
|
||||
return;
|
||||
}
|
||||
|
||||
ges_timeline_object_set_priority (object,
|
||||
tck_priority + map->priority_offset);
|
||||
tck_priority - layer_min_gnl_prio);
|
||||
}
|
||||
|
||||
GST_DEBUG ("object %p priority %d child %p priority %d", object,
|
||||
object->priority, child, ges_track_object_get_priority (child));
|
||||
}
|
||||
|
||||
static void
|
||||
get_layer_priorities (GESTimelineLayer * layer, guint32 * layer_min_gnl_prio,
|
||||
guint32 * layer_max_gnl_prio)
|
||||
{
|
||||
if (layer) {
|
||||
*layer_min_gnl_prio = layer->min_gnl_priority;
|
||||
*layer_max_gnl_prio = layer->max_gnl_priority;
|
||||
} else {
|
||||
*layer_min_gnl_prio = 0;
|
||||
*layer_max_gnl_prio = G_MAXUINT32;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <glib-object.h>
|
||||
#include <gst/gst.h>
|
||||
#include <ges/ges-types.h>
|
||||
#include <ges/ges-track.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -210,57 +211,67 @@ struct _GESTimelineObjectClass {
|
|||
gpointer _ges_reserved[GES_PADDING - 2];
|
||||
};
|
||||
|
||||
GType ges_timeline_object_get_type (void);
|
||||
GType ges_timeline_object_get_type (void);
|
||||
|
||||
/* Setters */
|
||||
void ges_timeline_object_set_start (GESTimelineObject * object,
|
||||
void ges_timeline_object_set_start (GESTimelineObject * object,
|
||||
guint64 start);
|
||||
void ges_timeline_object_set_inpoint (GESTimelineObject * object,
|
||||
void ges_timeline_object_set_inpoint (GESTimelineObject * object,
|
||||
guint64 inpoint);
|
||||
void ges_timeline_object_set_duration (GESTimelineObject * object,
|
||||
void ges_timeline_object_set_duration (GESTimelineObject * object,
|
||||
guint64 duration);
|
||||
void ges_timeline_object_set_priority (GESTimelineObject * object,
|
||||
void ges_timeline_object_set_priority (GESTimelineObject * object,
|
||||
guint priority);
|
||||
|
||||
void ges_timeline_object_set_layer (GESTimelineObject * object,
|
||||
void ges_timeline_object_set_layer (GESTimelineObject * object,
|
||||
GESTimelineLayer * layer);
|
||||
|
||||
/* TrackObject handling */
|
||||
GESTrackObject *
|
||||
ges_timeline_object_create_track_object (GESTimelineObject * object,
|
||||
ges_timeline_object_create_track_object (GESTimelineObject * object,
|
||||
GESTrack * track);
|
||||
|
||||
gboolean
|
||||
ges_timeline_object_create_track_objects (GESTimelineObject * object,
|
||||
ges_timeline_object_create_track_objects (GESTimelineObject * object,
|
||||
GESTrack * track);
|
||||
|
||||
gboolean
|
||||
ges_timeline_object_release_track_object (GESTimelineObject * object,
|
||||
ges_timeline_object_release_track_object (GESTimelineObject * object,
|
||||
GESTrackObject * trackobject);
|
||||
|
||||
gboolean
|
||||
ges_timeline_object_fill_track_object (GESTimelineObject * object,
|
||||
GESTrackObject * trackobj,
|
||||
GstElement * gnlobj);
|
||||
ges_timeline_object_fill_track_object (GESTimelineObject * object,
|
||||
GESTrackObject * trackobj, GstElement * gnlobj);
|
||||
|
||||
GESTrackObject *
|
||||
ges_timeline_object_find_track_object (GESTimelineObject * object,
|
||||
ges_timeline_object_find_track_object (GESTimelineObject * object,
|
||||
GESTrack * track, GType type);
|
||||
|
||||
GList *
|
||||
ges_timeline_object_get_track_objects (GESTimelineObject *object);
|
||||
ges_timeline_object_get_track_objects (GESTimelineObject *object);
|
||||
|
||||
gboolean
|
||||
ges_timeline_object_add_track_object (GESTimelineObject *object,
|
||||
ges_timeline_object_add_track_object (GESTimelineObject *object,
|
||||
GESTrackObject *trobj);
|
||||
|
||||
/* Layer */
|
||||
GESTimelineLayer *
|
||||
ges_timeline_object_get_layer (GESTimelineObject *object);
|
||||
ges_timeline_object_get_layer (GESTimelineObject *object);
|
||||
|
||||
gboolean
|
||||
ges_timeline_object_move_to_layer (GESTimelineObject *object,
|
||||
GESTimelineLayer *layer);
|
||||
|
||||
gboolean
|
||||
ges_timeline_object_is_moving_from_layer (GESTimelineObject *object);
|
||||
|
||||
void
|
||||
ges_timeline_object_set_moving_from_layer (GESTimelineObject * object,
|
||||
gboolean is_moving);
|
||||
|
||||
/* Effects */
|
||||
GList *
|
||||
ges_timeline_object_get_top_effects (GESTimelineObject *object);
|
||||
ges_timeline_object_get_top_effects (GESTimelineObject *object);
|
||||
|
||||
gint
|
||||
ges_timeline_object_get_top_effect_position (GESTimelineObject *object,
|
||||
|
@ -271,6 +282,18 @@ ges_timeline_object_set_top_effect_priority (GESTimelineObject *object,
|
|||
GESTrackEffect *effect,
|
||||
guint newpriority);
|
||||
|
||||
GESTrackType
|
||||
ges_timeline_object_get_supported_formats (GESTimelineObject * object);
|
||||
|
||||
void
|
||||
ges_timeline_object_set_supported_formats (GESTimelineObject * object,
|
||||
GESTrackType supportedformats);
|
||||
|
||||
GESTimelineObject *
|
||||
ges_timeline_object_split (GESTimelineObject * object, gint64 position);
|
||||
|
||||
void
|
||||
ges_timeline_object_objects_set_locked (GESTimelineObject * object, gboolean locked);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _GES_TIMELINE_OBJECT */
|
||||
|
|
|
@ -44,6 +44,7 @@ typedef struct
|
|||
GstPad *srcpad; /* Timeline source pad */
|
||||
GstPad *playsinkpad;
|
||||
GstPad *encodebinpad;
|
||||
GstPad *blocked_pad;
|
||||
} OutputChain;
|
||||
|
||||
G_DEFINE_TYPE (GESTimelinePipeline, ges_timeline_pipeline, GST_TYPE_PIPELINE);
|
||||
|
@ -380,6 +381,13 @@ no_pad:
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
|
||||
{
|
||||
/* no nothing */
|
||||
GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
|
||||
}
|
||||
|
||||
static void
|
||||
pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
|
||||
{
|
||||
|
@ -470,7 +478,9 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
|
|||
gst_object_unref (tmppad);
|
||||
goto error;
|
||||
}
|
||||
gst_object_unref (tmppad);
|
||||
chain->blocked_pad = tmppad;
|
||||
GST_DEBUG ("blocking pad %" GST_PTR_FORMAT, tmppad);
|
||||
gst_pad_set_blocked_async (tmppad, TRUE, pad_blocked, NULL);
|
||||
|
||||
GST_DEBUG ("Reconfiguring playsink");
|
||||
|
||||
|
@ -574,6 +584,13 @@ pad_removed_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
|
|||
gst_object_unref (chain->playsinkpad);
|
||||
}
|
||||
|
||||
if (chain->blocked_pad) {
|
||||
GST_DEBUG ("unblocking pad %" GST_PTR_FORMAT, chain->blocked_pad);
|
||||
gst_pad_set_blocked_async (chain->blocked_pad, FALSE, pad_blocked, NULL);
|
||||
gst_object_unref (chain->blocked_pad);
|
||||
chain->blocked_pad = NULL;
|
||||
}
|
||||
|
||||
/* Unlike/remove tee */
|
||||
peer = gst_element_get_static_pad (chain->tee, "sink");
|
||||
gst_pad_unlink (pad, peer);
|
||||
|
@ -587,6 +604,22 @@ pad_removed_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
|
|||
GST_DEBUG ("done");
|
||||
}
|
||||
|
||||
static void
|
||||
no_more_pads_cb (GstElement * timeline, GESTimelinePipeline * self)
|
||||
{
|
||||
GList *tmp;
|
||||
|
||||
GST_DEBUG ("received no-more-pads");
|
||||
for (tmp = self->priv->chains; tmp; tmp = g_list_next (tmp)) {
|
||||
OutputChain *chain = (OutputChain *) tmp->data;
|
||||
|
||||
if (chain->blocked_pad) {
|
||||
GST_DEBUG ("unblocking pad %" GST_PTR_FORMAT, chain->blocked_pad);
|
||||
gst_pad_set_blocked_async (chain->blocked_pad, FALSE, pad_blocked, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_pipeline_add_timeline:
|
||||
* @pipeline: a #GESTimelinePipeline
|
||||
|
@ -618,6 +651,8 @@ ges_timeline_pipeline_add_timeline (GESTimelinePipeline * pipeline,
|
|||
g_signal_connect (timeline, "pad-added", (GCallback) pad_added_cb, pipeline);
|
||||
g_signal_connect (timeline, "pad-removed", (GCallback) pad_removed_cb,
|
||||
pipeline);
|
||||
g_signal_connect (timeline, "no-more-pads", (GCallback) no_more_pads_cb,
|
||||
pipeline);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -192,16 +192,21 @@ ges_tl_transition_create_track_object (GESTimelineObject * obj,
|
|||
GESTimelineStandardTransition *transition =
|
||||
(GESTimelineStandardTransition *) obj;
|
||||
GESTrackObject *res;
|
||||
GESTrackType supportedformats;
|
||||
|
||||
GST_DEBUG ("Creating a GESTrackTransition");
|
||||
|
||||
if (track->type == GES_TRACK_TYPE_VIDEO) {
|
||||
supportedformats = ges_timeline_object_get_supported_formats (obj);
|
||||
if (track->type == GES_TRACK_TYPE_VIDEO &&
|
||||
(supportedformats == GES_TRACK_TYPE_UNKNOWN ||
|
||||
supportedformats & GES_TRACK_TYPE_VIDEO)) {
|
||||
res = GES_TRACK_OBJECT (ges_track_video_transition_new ());
|
||||
ges_track_video_transition_set_transition_type ((GESTrackVideoTransition *)
|
||||
res, transition->vtype);
|
||||
}
|
||||
|
||||
else if (track->type == GES_TRACK_TYPE_AUDIO) {
|
||||
} else if (track->type == GES_TRACK_TYPE_AUDIO &&
|
||||
(supportedformats == GES_TRACK_TYPE_UNKNOWN ||
|
||||
supportedformats & GES_TRACK_TYPE_AUDIO)) {
|
||||
res = GES_TRACK_OBJECT (ges_track_audio_transition_new ());
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ struct _GESTimelineTitleSourcePrivate
|
|||
gboolean mute;
|
||||
gchar *text;
|
||||
gchar *font_desc;
|
||||
GESTextVAlign halign;
|
||||
GESTextHAlign valign;
|
||||
GESTextHAlign halign;
|
||||
GESTextVAlign valign;
|
||||
GSList *track_titles;
|
||||
guint32 color;
|
||||
gdouble xpos;
|
||||
|
|
|
@ -43,18 +43,32 @@
|
|||
#include "ges-timeline-layer.h"
|
||||
#include "ges.h"
|
||||
|
||||
static void track_duration_cb (GstElement * track,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline);
|
||||
|
||||
G_DEFINE_TYPE (GESTimeline, ges_timeline, GST_TYPE_BIN);
|
||||
|
||||
#define GES_TIMELINE_PENDINGOBJS_GET_LOCK(timeline) \
|
||||
(GES_TIMELINE(timeline)->priv->pendingobjects_lock)
|
||||
#define GES_TIMELINE_PENDINGOBJS_LOCK(timeline) \
|
||||
(g_mutex_lock(GES_TIMELINE_PENDINGOBJS_GET_LOCK (timeline)))
|
||||
#define GES_TIMELINE_PENDINGOBJS_UNLOCK(timeline) \
|
||||
(g_mutex_unlock(GES_TIMELINE_PENDINGOBJS_GET_LOCK (timeline)))
|
||||
|
||||
struct _GESTimelinePrivate
|
||||
{
|
||||
GList *layers; /* A list of GESTimelineLayer sorted by priority */
|
||||
GList *tracks; /* A list of private track data */
|
||||
|
||||
/* The duration of the timeline */
|
||||
gint64 duration;
|
||||
|
||||
/* discoverer used for virgin sources */
|
||||
GstDiscoverer *discoverer;
|
||||
/* Objects that are being discovered FIXME : LOCK ! */
|
||||
GList *pendingobjects;
|
||||
/* lock to avoid discovery of objects that will be removed */
|
||||
GMutex *pendingobjects_lock;
|
||||
|
||||
/* Whether we are changing state asynchronously or not */
|
||||
gboolean async_pending;
|
||||
};
|
||||
|
@ -69,12 +83,22 @@ typedef struct
|
|||
GstPad *ghostpad;
|
||||
} TrackPrivate;
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DURATION,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec *properties[PROP_LAST];
|
||||
|
||||
enum
|
||||
{
|
||||
TRACK_ADDED,
|
||||
TRACK_REMOVED,
|
||||
LAYER_ADDED,
|
||||
LAYER_REMOVED,
|
||||
DISCOVERY_ERROR,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
@ -91,13 +115,23 @@ static void
|
|||
discoverer_discovered_cb (GstDiscoverer * discoverer,
|
||||
GstDiscovererInfo * info, GError * err, GESTimeline * timeline);
|
||||
|
||||
void look_for_transition (GESTrackObject * track_object,
|
||||
GESTimelineLayer * layer);
|
||||
void track_object_removed_cb (GESTrack * track, GESTrackObject * track_object,
|
||||
GESTimeline * timeline);
|
||||
|
||||
static void
|
||||
ges_timeline_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GESTimeline *timeline = GES_TIMELINE (object);
|
||||
|
||||
switch (property_id) {
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
case PROP_DURATION:
|
||||
g_value_set_uint64 (value, timeline->priv->duration);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,6 +177,10 @@ ges_timeline_dispose (GObject * object)
|
|||
static void
|
||||
ges_timeline_finalize (GObject * object)
|
||||
{
|
||||
GESTimeline *timeline = GES_TIMELINE (object);
|
||||
|
||||
g_mutex_free (timeline->priv->pendingobjects_lock);
|
||||
|
||||
G_OBJECT_CLASS (ges_timeline_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
@ -163,6 +201,20 @@ ges_timeline_class_init (GESTimelineClass * klass)
|
|||
object_class->dispose = ges_timeline_dispose;
|
||||
object_class->finalize = ges_timeline_finalize;
|
||||
|
||||
/**
|
||||
* GESTimelineObject:duration
|
||||
*
|
||||
* Current duration (in nanoseconds) of the #GESTimeline
|
||||
*
|
||||
* Default value: 0
|
||||
*/
|
||||
properties[PROP_DURATION] =
|
||||
g_param_spec_uint64 ("duration", "Duration",
|
||||
"The duration of the timeline", 0, G_MAXUINT64,
|
||||
GST_CLOCK_TIME_NONE, G_PARAM_READABLE);
|
||||
g_object_class_install_property (object_class, PROP_DURATION,
|
||||
properties[PROP_DURATION]);
|
||||
|
||||
/**
|
||||
* GESTimeline::track-added
|
||||
* @timeline: the #GESTimeline
|
||||
|
@ -211,6 +263,18 @@ ges_timeline_class_init (GESTimelineClass * klass)
|
|||
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, layer_removed),
|
||||
NULL, NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
|
||||
GES_TYPE_TIMELINE_LAYER);
|
||||
|
||||
/**
|
||||
* GESTimeline::discovery-error:
|
||||
* @formatter: the #GESFormatter
|
||||
* @source: The #GESTimelineFileSource that could not be discovered properly
|
||||
* @error: (type GLib.Error): #GError, which will be non-NULL if an error
|
||||
* occurred during discovery
|
||||
*/
|
||||
ges_timeline_signals[DISCOVERY_ERROR] =
|
||||
g_signal_new ("discovery-error", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, gst_marshal_VOID__OBJECT_BOXED,
|
||||
G_TYPE_NONE, 2, GES_TYPE_TIMELINE_FILE_SOURCE, GST_TYPE_G_ERROR);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -222,7 +286,9 @@ ges_timeline_init (GESTimeline * self)
|
|||
|
||||
self->priv->layers = NULL;
|
||||
self->priv->tracks = NULL;
|
||||
self->priv->duration = 0;
|
||||
|
||||
self->priv->pendingobjects_lock = g_mutex_new ();
|
||||
/* New discoverer with a 15s timeout */
|
||||
self->priv->discoverer = gst_discoverer_new (15 * GST_SECOND, NULL);
|
||||
g_signal_connect (self->priv->discoverer, "finished",
|
||||
|
@ -232,6 +298,26 @@ ges_timeline_init (GESTimeline * self)
|
|||
gst_discoverer_start (self->priv->discoverer);
|
||||
}
|
||||
|
||||
static gint
|
||||
sort_layers (gpointer a, gpointer b)
|
||||
{
|
||||
GESTimelineLayer *layer_a, *layer_b;
|
||||
guint prio_a, prio_b;
|
||||
|
||||
layer_a = GES_TIMELINE_LAYER (a);
|
||||
layer_b = GES_TIMELINE_LAYER (b);
|
||||
|
||||
prio_a = ges_timeline_layer_get_priority (layer_a);
|
||||
prio_b = ges_timeline_layer_get_priority (layer_b);
|
||||
|
||||
if ((gint) prio_a > (guint) prio_b)
|
||||
return 1;
|
||||
if ((guint) prio_a < (guint) prio_b)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_new:
|
||||
*
|
||||
|
@ -435,13 +521,16 @@ discoverer_discovered_cb (GstDiscoverer * discoverer,
|
|||
GstDiscovererInfo * info, GError * err, GESTimeline * timeline)
|
||||
{
|
||||
GList *tmp;
|
||||
GList *stream_list;
|
||||
GESTrackType tfs_supportedformats;
|
||||
|
||||
gboolean found = FALSE;
|
||||
gboolean is_image = FALSE;
|
||||
GESTimelineFileSource *tfs = NULL;
|
||||
GESTimelinePrivate *priv = timeline->priv;
|
||||
const gchar *uri = gst_discoverer_info_get_uri (info);
|
||||
|
||||
GST_DEBUG ("Discovered uri %s", uri);
|
||||
GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
|
||||
|
||||
/* Find corresponding TimelineFileSource in the sources */
|
||||
for (tmp = priv->pendingobjects; tmp; tmp = tmp->next) {
|
||||
|
@ -453,57 +542,85 @@ discoverer_discovered_cb (GstDiscoverer * discoverer,
|
|||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
GList *stream_list;
|
||||
GESTrackType tfs_supportedformats;
|
||||
if (!found) {
|
||||
GST_WARNING ("Discovered %s, that seems not to be in the list of sources"
|
||||
"to discover", uri);
|
||||
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
GError *propagate_error = NULL;
|
||||
|
||||
/* Remove object from list */
|
||||
priv->pendingobjects = g_list_delete_link (priv->pendingobjects, tmp);
|
||||
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||
GST_WARNING ("Error while discovering %s: %s", uri, err->message);
|
||||
|
||||
/* FIXME : Handle errors in discovery */
|
||||
stream_list = gst_discoverer_info_get_stream_list (info);
|
||||
g_propagate_error (&propagate_error, err);
|
||||
g_signal_emit (timeline, ges_timeline_signals[DISCOVERY_ERROR], 0, tfs,
|
||||
propagate_error);
|
||||
|
||||
/* Update timelinefilesource properties based on info */
|
||||
for (tmp = stream_list; tmp; tmp = tmp->next) {
|
||||
GstDiscovererStreamInfo *sinf = (GstDiscovererStreamInfo *) tmp->data;
|
||||
return;
|
||||
}
|
||||
|
||||
tfs_supportedformats =
|
||||
ges_timeline_filesource_get_supported_formats (tfs);
|
||||
/* Everything went fine... let's do our job! */
|
||||
GST_DEBUG ("Discovered uri %s", uri);
|
||||
|
||||
if (GST_IS_DISCOVERER_AUDIO_INFO (sinf)) {
|
||||
/* The timeline file source will be updated with discovered information
|
||||
* so it needs to not be finalized during this process */
|
||||
g_object_ref (tfs);
|
||||
|
||||
/* Remove object from list */
|
||||
priv->pendingobjects = g_list_delete_link (priv->pendingobjects, tmp);
|
||||
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||
|
||||
/* FIXME : Handle errors in discovery */
|
||||
stream_list = gst_discoverer_info_get_stream_list (info);
|
||||
|
||||
tfs_supportedformats = ges_timeline_filesource_get_supported_formats (tfs);
|
||||
if (tfs_supportedformats != GES_TRACK_TYPE_UNKNOWN)
|
||||
goto check_image;
|
||||
|
||||
/* Update timelinefilesource properties based on info */
|
||||
for (tmp = stream_list; tmp; tmp = tmp->next) {
|
||||
GstDiscovererStreamInfo *sinf = (GstDiscovererStreamInfo *) tmp->data;
|
||||
|
||||
if (GST_IS_DISCOVERER_AUDIO_INFO (sinf)) {
|
||||
tfs_supportedformats |= GES_TRACK_TYPE_AUDIO;
|
||||
ges_timeline_filesource_set_supported_formats (tfs, tfs_supportedformats);
|
||||
} else if (GST_IS_DISCOVERER_VIDEO_INFO (sinf)) {
|
||||
tfs_supportedformats |= GES_TRACK_TYPE_VIDEO;
|
||||
ges_timeline_filesource_set_supported_formats (tfs, tfs_supportedformats);
|
||||
if (gst_discoverer_video_info_is_image ((GstDiscovererVideoInfo *)
|
||||
sinf)) {
|
||||
tfs_supportedformats |= GES_TRACK_TYPE_AUDIO;
|
||||
ges_timeline_filesource_set_supported_formats (tfs,
|
||||
tfs_supportedformats);
|
||||
} else if (GST_IS_DISCOVERER_VIDEO_INFO (sinf)) {
|
||||
tfs_supportedformats |= GES_TRACK_TYPE_VIDEO;
|
||||
ges_timeline_filesource_set_supported_formats (tfs,
|
||||
tfs_supportedformats);
|
||||
if (gst_discoverer_video_info_is_image ((GstDiscovererVideoInfo *)
|
||||
sinf)) {
|
||||
tfs_supportedformats |= GES_TRACK_TYPE_AUDIO;
|
||||
ges_timeline_filesource_set_supported_formats (tfs,
|
||||
tfs_supportedformats);
|
||||
is_image = TRUE;
|
||||
}
|
||||
is_image = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (stream_list)
|
||||
gst_discoverer_stream_info_list_free (stream_list);
|
||||
|
||||
if (is_image) {
|
||||
/* don't set max-duration on still images */
|
||||
g_object_set (tfs, "is_image", (gboolean) TRUE, NULL);
|
||||
}
|
||||
|
||||
else {
|
||||
g_object_set (tfs, "max-duration",
|
||||
gst_discoverer_info_get_duration (info), NULL);
|
||||
}
|
||||
|
||||
/* Continue the processing on tfs */
|
||||
add_object_to_tracks (timeline, GES_TIMELINE_OBJECT (tfs));
|
||||
}
|
||||
|
||||
if (stream_list)
|
||||
gst_discoverer_stream_info_list_free (stream_list);
|
||||
|
||||
check_image:
|
||||
|
||||
if (is_image) {
|
||||
/* don't set max-duration on still images */
|
||||
g_object_set (tfs, "is_image", (gboolean) TRUE, NULL);
|
||||
}
|
||||
|
||||
/* Continue the processing on tfs */
|
||||
add_object_to_tracks (timeline, GES_TIMELINE_OBJECT (tfs));
|
||||
|
||||
if (!is_image) {
|
||||
g_object_set (tfs, "max-duration",
|
||||
gst_discoverer_info_get_duration (info), NULL);
|
||||
}
|
||||
|
||||
/* Remove the ref as the timeline file source is no longer needed here */
|
||||
g_object_unref (tfs);
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
|
@ -514,9 +631,13 @@ ges_timeline_change_state (GstElement * element, GstStateChange transition)
|
|||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
|
||||
if (timeline->priv->pendingobjects) {
|
||||
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||
do_async_start (timeline);
|
||||
ret = GST_STATE_CHANGE_ASYNC;
|
||||
} else {
|
||||
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -549,6 +670,12 @@ static void
|
|||
layer_object_added_cb (GESTimelineLayer * layer, GESTimelineObject * object,
|
||||
GESTimeline * timeline)
|
||||
{
|
||||
if (ges_timeline_object_is_moving_from_layer (object)) {
|
||||
GST_DEBUG ("TimelineObject %p is moving from a layer to another, not doing"
|
||||
" anything on it", object);
|
||||
return;
|
||||
}
|
||||
|
||||
GST_DEBUG ("New TimelineObject %p added to layer %p", object, layer);
|
||||
|
||||
if (GES_IS_TIMELINE_FILE_SOURCE (object)) {
|
||||
|
@ -567,8 +694,12 @@ layer_object_added_cb (GESTimelineLayer * layer, GESTimelineObject * object,
|
|||
tfs_maxdur == GST_CLOCK_TIME_NONE || object->duration == 0) {
|
||||
GST_LOG ("Incomplete TimelineFileSource, discovering it");
|
||||
tfs_uri = ges_timeline_filesource_get_uri (tfs);
|
||||
|
||||
GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
|
||||
timeline->priv->pendingobjects =
|
||||
g_list_append (timeline->priv->pendingobjects, object);
|
||||
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||
|
||||
gst_discoverer_discover_uri_async (timeline->priv->discoverer, tfs_uri);
|
||||
} else
|
||||
add_object_to_tracks (timeline, object);
|
||||
|
@ -579,12 +710,25 @@ layer_object_added_cb (GESTimelineLayer * layer, GESTimelineObject * object,
|
|||
GST_DEBUG ("done");
|
||||
}
|
||||
|
||||
static void
|
||||
layer_priority_changed_cb (GESTimelineLayer * layer,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
|
||||
{
|
||||
timeline->priv->layers = g_list_sort (timeline->priv->layers, (GCompareFunc)
|
||||
sort_layers);
|
||||
}
|
||||
|
||||
static void
|
||||
layer_object_removed_cb (GESTimelineLayer * layer, GESTimelineObject * object,
|
||||
GESTimeline * timeline)
|
||||
{
|
||||
GList *tmp, *trackobjects;
|
||||
GList *trackobjects, *tmp;
|
||||
|
||||
if (ges_timeline_object_is_moving_from_layer (object)) {
|
||||
GST_DEBUG ("TimelineObject %p is moving from a layer to another, not doing"
|
||||
" anything on it", object);
|
||||
return;
|
||||
}
|
||||
|
||||
GST_DEBUG ("TimelineObject %p removed from layer %p", object, layer);
|
||||
|
||||
|
@ -604,15 +748,50 @@ layer_object_removed_cb (GESTimelineLayer * layer, GESTimelineObject * object,
|
|||
|
||||
ges_timeline_object_release_track_object (object, trobj);
|
||||
}
|
||||
|
||||
/* removing the reference added by _get_track_objects() */
|
||||
g_object_unref (trobj);
|
||||
}
|
||||
|
||||
g_list_free (trackobjects);
|
||||
|
||||
/* if the object is a timeline file source that has not yet been discovered,
|
||||
* it no longer needs to be discovered so remove it from the pendingobjects
|
||||
* list if it belongs to this layer */
|
||||
if (GES_IS_TIMELINE_FILE_SOURCE (object)) {
|
||||
GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
|
||||
timeline->priv->pendingobjects =
|
||||
g_list_remove_all (timeline->priv->pendingobjects, object);
|
||||
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||
}
|
||||
|
||||
GST_DEBUG ("Done");
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_append_layer:
|
||||
* @timeline: a #GESTimeline
|
||||
* @layer: the #GESTimelineLayer to add
|
||||
*
|
||||
* Convenience method to append @layer to @timeline which means that the
|
||||
* priority of @layer is changed to correspond to the last layer of @timeline.
|
||||
* The reference to the @layer will be stolen by @timeline.
|
||||
*
|
||||
* Returns: TRUE if the layer was properly added, else FALSE.
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_append_layer (GESTimeline * timeline, GESTimelineLayer * layer)
|
||||
{
|
||||
guint32 priority;
|
||||
GESTimelinePrivate *priv = timeline->priv;
|
||||
|
||||
GST_DEBUG ("Appending layer to layer:%p, timeline:%p", timeline, layer);
|
||||
priority = g_list_length (priv->layers);
|
||||
|
||||
ges_timeline_layer_set_priority (layer, priority);
|
||||
|
||||
return ges_timeline_add_layer (timeline, layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_add_layer:
|
||||
* @timeline: a #GESTimeline
|
||||
|
@ -644,7 +823,8 @@ ges_timeline_add_layer (GESTimeline * timeline, GESTimelineLayer * layer)
|
|||
}
|
||||
|
||||
g_object_ref_sink (layer);
|
||||
priv->layers = g_list_append (priv->layers, layer);
|
||||
priv->layers = g_list_insert_sorted (priv->layers, layer,
|
||||
(GCompareFunc) sort_layers);
|
||||
|
||||
/* Inform the layer that it belongs to a new timeline */
|
||||
ges_timeline_layer_set_timeline (layer, timeline);
|
||||
|
@ -654,6 +834,8 @@ ges_timeline_add_layer (GESTimeline * timeline, GESTimelineLayer * layer)
|
|||
timeline);
|
||||
g_signal_connect (layer, "object-removed",
|
||||
G_CALLBACK (layer_object_removed_cb), timeline);
|
||||
g_signal_connect (layer, "notify::priority",
|
||||
G_CALLBACK (layer_priority_changed_cb), timeline);
|
||||
|
||||
GST_DEBUG ("Done adding layer, emitting 'layer-added' signal");
|
||||
g_signal_emit (timeline, ges_timeline_signals[LAYER_ADDED], 0, layer);
|
||||
|
@ -726,7 +908,8 @@ static void
|
|||
pad_added_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
|
||||
{
|
||||
gchar *padname;
|
||||
|
||||
gboolean no_more;
|
||||
GList *tmp;
|
||||
|
||||
GST_DEBUG ("track:%p, pad:%s:%s", track, GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
|
@ -736,8 +919,20 @@ pad_added_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
|
|||
}
|
||||
|
||||
/* Remember the pad */
|
||||
GST_OBJECT_LOCK (track);
|
||||
tr_priv->pad = pad;
|
||||
|
||||
no_more = TRUE;
|
||||
for (tmp = tr_priv->timeline->priv->tracks; tmp; tmp = g_list_next (tmp)) {
|
||||
TrackPrivate *tr_priv = (TrackPrivate *) tmp->data;
|
||||
|
||||
if (!tr_priv->pad) {
|
||||
GST_LOG ("Found track without pad %p", tr_priv->track);
|
||||
no_more = FALSE;
|
||||
}
|
||||
}
|
||||
GST_OBJECT_UNLOCK (track);
|
||||
|
||||
/* ghost it ! */
|
||||
GST_DEBUG ("Ghosting pad and adding it to ourself");
|
||||
padname = g_strdup_printf ("track_%p_src", track);
|
||||
|
@ -745,6 +940,11 @@ pad_added_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
|
|||
g_free (padname);
|
||||
gst_pad_set_active (tr_priv->ghostpad, TRUE);
|
||||
gst_element_add_pad (GST_ELEMENT (tr_priv->timeline), tr_priv->ghostpad);
|
||||
|
||||
if (no_more) {
|
||||
GST_DEBUG ("Signaling no-more-pads");
|
||||
gst_element_no_more_pads (GST_ELEMENT (tr_priv->timeline));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -849,6 +1049,12 @@ ges_timeline_add_track (GESTimeline * timeline, GESTrack * track)
|
|||
g_list_free (objects);
|
||||
}
|
||||
|
||||
/* We connect to the duration change notify, so we can update
|
||||
* our duration accordingly */
|
||||
g_signal_connect (G_OBJECT (track), "notify::duration",
|
||||
G_CALLBACK (track_duration_cb), timeline);
|
||||
track_duration_cb (GST_ELEMENT (track), NULL, timeline);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -901,6 +1107,8 @@ ges_timeline_remove_track (GESTimeline * timeline, GESTrack * track)
|
|||
/* Remove pad-added/-removed handlers */
|
||||
g_signal_handlers_disconnect_by_func (track, pad_added_cb, tr_priv);
|
||||
g_signal_handlers_disconnect_by_func (track, pad_removed_cb, tr_priv);
|
||||
g_signal_handlers_disconnect_by_func (track, track_duration_cb,
|
||||
tr_priv->track);
|
||||
|
||||
/* Signal track removal to all layers/objects */
|
||||
g_signal_emit (timeline, ges_timeline_signals[TRACK_REMOVED], 0, track);
|
||||
|
@ -978,7 +1186,7 @@ ges_timeline_get_tracks (GESTimeline * timeline)
|
|||
* Get the list of #GESTimelineLayer present in the Timeline.
|
||||
*
|
||||
* Returns: (transfer full) (element-type GESTimelineLayer): the list of
|
||||
* #GESTimelineLayer present in the Timeline.
|
||||
* #GESTimelineLayer present in the Timeline sorted by priority.
|
||||
* The caller should unref each Layer once he is done with them.
|
||||
*/
|
||||
GList *
|
||||
|
@ -987,8 +1195,71 @@ ges_timeline_get_layers (GESTimeline * timeline)
|
|||
GList *tmp, *res = NULL;
|
||||
|
||||
for (tmp = timeline->priv->layers; tmp; tmp = g_list_next (tmp)) {
|
||||
res = g_list_append (res, g_object_ref (tmp->data));
|
||||
res = g_list_insert_sorted (res, g_object_ref (tmp->data),
|
||||
(GCompareFunc) sort_layers);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_enable_update:
|
||||
* @timeline: a #GESTimeline
|
||||
* @enabled: Whether the timeline should update on every change or not.
|
||||
*
|
||||
* Control whether the timeline is updated for every change happening within.
|
||||
*
|
||||
* Users will want to use this method with %FALSE before doing lots of changes,
|
||||
* and then call again with %TRUE for the changes to take effect in one go.
|
||||
*
|
||||
* Returns: %TRUE if the update status could be changed, else %FALSE.
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_enable_update (GESTimeline * timeline, gboolean enabled)
|
||||
{
|
||||
GList *tmp, *tracks;
|
||||
gboolean res = TRUE;
|
||||
|
||||
GST_DEBUG_OBJECT (timeline, "%s updates", enabled ? "Enabling" : "Disabling");
|
||||
|
||||
tracks = ges_timeline_get_tracks (timeline);
|
||||
|
||||
for (tmp = tracks; tmp; tmp = tmp->next) {
|
||||
if (!ges_track_enable_update (tmp->data, enabled)) {
|
||||
res = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (tracks);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
track_duration_cb (GstElement * track,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
|
||||
{
|
||||
guint64 duration, max_duration = 0;
|
||||
GList *tmp;
|
||||
|
||||
for (tmp = timeline->priv->tracks; tmp; tmp = g_list_next (tmp)) {
|
||||
TrackPrivate *tr_priv = (TrackPrivate *) tmp->data;
|
||||
g_object_get (tr_priv->track, "duration", &duration, NULL);
|
||||
GST_DEBUG ("track duration : %" GST_TIME_FORMAT, GST_TIME_ARGS (duration));
|
||||
max_duration = MAX (duration, max_duration);
|
||||
}
|
||||
|
||||
if (timeline->priv->duration != max_duration) {
|
||||
GST_DEBUG ("track duration : %" GST_TIME_FORMAT " current : %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (max_duration),
|
||||
GST_TIME_ARGS (timeline->priv->duration));
|
||||
|
||||
timeline->priv->duration = max_duration;
|
||||
|
||||
#if GLIB_CHECK_VERSION(2,26,0)
|
||||
g_object_notify_by_pspec (G_OBJECT (timeline), properties[PROP_DURATION]);
|
||||
#else
|
||||
g_object_notify (G_OBJECT (timeline), "duration");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ gboolean ges_timeline_load_from_uri (GESTimeline *timeline, const gchar *uri);
|
|||
gboolean ges_timeline_save_to_uri (GESTimeline *timeline, const gchar *uri);
|
||||
|
||||
gboolean ges_timeline_add_layer (GESTimeline *timeline, GESTimelineLayer *layer);
|
||||
gboolean ges_timeline_append_layer (GESTimeline * timeline, GESTimelineLayer * layer);
|
||||
gboolean ges_timeline_remove_layer (GESTimeline *timeline, GESTimelineLayer *layer);
|
||||
GList* ges_timeline_get_layers (GESTimeline *timeline);
|
||||
|
||||
|
@ -98,6 +99,8 @@ gboolean ges_timeline_remove_track (GESTimeline *timeline, GESTrack *track);
|
|||
GESTrack * ges_timeline_get_track_for_pad (GESTimeline *timeline, GstPad *pad);
|
||||
GList *ges_timeline_get_tracks (GESTimeline *timeline);
|
||||
|
||||
gboolean ges_timeline_enable_update(GESTimeline * timeline, gboolean enabled);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _GES_TIMELINE */
|
||||
|
|
|
@ -34,14 +34,14 @@ G_DEFINE_TYPE (GESTrackFileSource, ges_track_filesource, GES_TYPE_TRACK_SOURCE);
|
|||
|
||||
struct _GESTrackFileSourcePrivate
|
||||
{
|
||||
/* Dummy variable */
|
||||
void *nothing;
|
||||
guint64 maxduration;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_URI
|
||||
PROP_URI,
|
||||
PROP_MAX_DURATION
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -54,6 +54,9 @@ ges_track_filesource_get_property (GObject * object, guint property_id,
|
|||
case PROP_URI:
|
||||
g_value_set_string (value, tfs->uri);
|
||||
break;
|
||||
case PROP_MAX_DURATION:
|
||||
g_value_set_uint64 (value, tfs->priv->maxduration);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
|
@ -69,6 +72,9 @@ ges_track_filesource_set_property (GObject * object, guint property_id,
|
|||
case PROP_URI:
|
||||
tfs->uri = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_MAX_DURATION:
|
||||
tfs->priv->maxduration = g_value_get_uint64 (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
|
@ -108,6 +114,19 @@ ges_track_filesource_class_init (GESTrackFileSourceClass * klass)
|
|||
object_class->set_property = ges_track_filesource_set_property;
|
||||
object_class->dispose = ges_track_filesource_dispose;
|
||||
|
||||
/**
|
||||
* GESTrackFileSource:max-duration:
|
||||
*
|
||||
* The maximum duration (in nanoseconds) of the file.
|
||||
*
|
||||
* If not set before adding the object to a layer, it will be discovered
|
||||
* asynchronously. Connect to 'notify::max-duration' to be notified of it.
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_MAX_DURATION,
|
||||
g_param_spec_uint64 ("max-duration", "Maximum duration",
|
||||
"The duration of the file", 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
/**
|
||||
* GESTrackFileSource:uri
|
||||
*
|
||||
|
|
|
@ -73,6 +73,7 @@ enum
|
|||
PROP_DURATION,
|
||||
PROP_PRIORITY,
|
||||
PROP_ACTIVE,
|
||||
PROP_LOCKED,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -118,6 +119,8 @@ static inline gboolean ges_track_object_set_duration_internal (GESTrackObject *
|
|||
object, guint64 duration);
|
||||
static inline gboolean ges_track_object_set_priority_internal (GESTrackObject *
|
||||
object, guint32 priority);
|
||||
static inline void
|
||||
ges_track_object_set_locked_internal (GESTrackObject * object, gboolean locked);
|
||||
|
||||
static GParamSpec **default_list_children_properties (GESTrackObject * object,
|
||||
guint * n_properties);
|
||||
|
@ -144,6 +147,9 @@ ges_track_object_get_property (GObject * object, guint property_id,
|
|||
case PROP_ACTIVE:
|
||||
g_value_set_boolean (value, ges_track_object_is_active (tobj));
|
||||
break;
|
||||
case PROP_LOCKED:
|
||||
g_value_set_boolean (value, ges_track_object_is_locked (tobj));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
|
@ -171,6 +177,9 @@ ges_track_object_set_property (GObject * object, guint property_id,
|
|||
case PROP_ACTIVE:
|
||||
ges_track_object_set_active (tobj, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_LOCKED:
|
||||
ges_track_object_set_locked_internal (tobj, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
|
@ -270,6 +279,18 @@ ges_track_object_class_init (GESTrackObjectClass * klass)
|
|||
g_object_class_install_property (object_class, PROP_ACTIVE,
|
||||
properties[PROP_ACTIVE]);
|
||||
|
||||
/**
|
||||
* GESTrackObject:locked
|
||||
*
|
||||
* If %TRUE, then moves in sync with its controlling #GESTimelineObject
|
||||
*/
|
||||
properties[PROP_LOCKED] =
|
||||
g_param_spec_boolean ("locked", "Locked",
|
||||
"Moves in sync with its controling TimelineObject", TRUE,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (object_class, PROP_LOCKED,
|
||||
properties[PROP_LOCKED]);
|
||||
|
||||
/**
|
||||
* GESTrackObject::deep-notify:
|
||||
* @track_object: a #GESTrackObject
|
||||
|
@ -876,6 +897,12 @@ ges_track_object_get_element (GESTrackObject * object)
|
|||
return object->priv->element;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ges_track_object_set_locked_internal (GESTrackObject * object, gboolean locked)
|
||||
{
|
||||
object->priv->locked = locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_track_object_set_locked:
|
||||
* @object: a #GESTrackObject
|
||||
|
@ -888,7 +915,17 @@ ges_track_object_get_element (GESTrackObject * object)
|
|||
void
|
||||
ges_track_object_set_locked (GESTrackObject * object, gboolean locked)
|
||||
{
|
||||
object->priv->locked = locked;
|
||||
g_return_if_fail (GES_IS_TRACK_OBJECT (object));
|
||||
|
||||
GST_DEBUG_OBJECT (object, "%s object", locked ? "Locking" : "Unlocking");
|
||||
|
||||
ges_track_object_set_locked_internal (object, locked);
|
||||
#if GLIB_CHECK_VERSION(2,26,0)
|
||||
g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_LOCKED]);
|
||||
#else
|
||||
g_object_notify (G_OBJECT (object), "locked");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1051,8 +1088,7 @@ ges_track_object_lookup_child (GESTrackObject * object, const gchar * prop_name,
|
|||
if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) {
|
||||
if (classename == NULL ||
|
||||
g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (value)), classename) == 0) {
|
||||
GST_DEBUG ("The %s property from %s has been found in %s", name,
|
||||
classename, GST_OBJECT_NAME (GST_OBJECT (element)));
|
||||
GST_DEBUG ("The %s property from %s has been found", name, classename);
|
||||
if (element)
|
||||
*element = g_object_ref (value);
|
||||
|
||||
|
|
|
@ -132,80 +132,96 @@ struct _GESTrackObjectClass {
|
|||
|
||||
/*< private >*/
|
||||
/* signals (currently unused) */
|
||||
void (*changed) (GESTrackObject * object);
|
||||
void (*changed) (GESTrackObject * object);
|
||||
|
||||
/*< public >*/
|
||||
/* virtual methods for subclasses */
|
||||
GHashTable* (*get_props_hastable) (GESTrackObject * object);
|
||||
GParamSpec** (*list_children_properties) (GESTrackObject * object,
|
||||
guint *n_properties);
|
||||
guint *n_properties);
|
||||
/*< private >*/
|
||||
/* Padding for API extension */
|
||||
gpointer _ges_reserved[GES_PADDING - 2];
|
||||
};
|
||||
|
||||
GType ges_track_object_get_type (void);
|
||||
GType ges_track_object_get_type (void);
|
||||
|
||||
gboolean ges_track_object_set_track (GESTrackObject * object,
|
||||
GESTrack * track);
|
||||
GESTrack* ges_track_object_get_track (GESTrackObject * object);
|
||||
gboolean ges_track_object_set_track (GESTrackObject * object,
|
||||
GESTrack * track);
|
||||
GESTrack* ges_track_object_get_track (GESTrackObject * object);
|
||||
|
||||
void ges_track_object_set_timeline_object (GESTrackObject * object,
|
||||
GESTimelineObject * tlobject);
|
||||
void ges_track_object_set_timeline_object (GESTrackObject * object,
|
||||
GESTimelineObject * tlobject);
|
||||
GESTimelineObject *
|
||||
ges_track_object_get_timeline_object (GESTrackObject* object);
|
||||
ges_track_object_get_timeline_object (GESTrackObject* object);
|
||||
|
||||
GstElement * ges_track_object_get_gnlobject (GESTrackObject * object);
|
||||
GstElement * ges_track_object_get_element (GESTrackObject * object);
|
||||
GstElement * ges_track_object_get_gnlobject (GESTrackObject * object);
|
||||
|
||||
void ges_track_object_set_locked (GESTrackObject * object,
|
||||
gboolean locked);
|
||||
gboolean ges_track_object_is_locked (GESTrackObject * object);
|
||||
GstElement * ges_track_object_get_element (GESTrackObject * object);
|
||||
|
||||
void ges_track_object_set_start (GESTrackObject * object,
|
||||
guint64 start);
|
||||
void ges_track_object_set_inpoint (GESTrackObject * object,
|
||||
guint64 inpoint);
|
||||
void ges_track_object_set_duration (GESTrackObject * object,
|
||||
guint64 duration);
|
||||
void ges_track_object_set_priority (GESTrackObject * object,
|
||||
guint32 priority);
|
||||
gboolean ges_track_object_set_active (GESTrackObject * object,
|
||||
gboolean active);
|
||||
void ges_track_object_set_locked (GESTrackObject * object,
|
||||
gboolean locked);
|
||||
|
||||
guint64 ges_track_object_get_start (GESTrackObject * object);
|
||||
guint64 ges_track_object_get_inpoint (GESTrackObject * object);
|
||||
guint64 ges_track_object_get_duration (GESTrackObject * object);
|
||||
guint32 ges_track_object_get_priority (GESTrackObject * object);
|
||||
gboolean ges_track_object_is_active (GESTrackObject * object);
|
||||
gboolean ges_track_object_is_locked (GESTrackObject * object);
|
||||
|
||||
void ges_track_object_set_start (GESTrackObject * object,
|
||||
guint64 start);
|
||||
|
||||
void ges_track_object_set_inpoint (GESTrackObject * object,
|
||||
guint64 inpoint);
|
||||
|
||||
void ges_track_object_set_duration (GESTrackObject * object,
|
||||
guint64 duration);
|
||||
|
||||
void ges_track_object_set_priority (GESTrackObject * object,
|
||||
guint32 priority);
|
||||
|
||||
gboolean ges_track_object_set_active (GESTrackObject * object,
|
||||
gboolean active);
|
||||
|
||||
guint64 ges_track_object_get_start (GESTrackObject * object);
|
||||
guint64 ges_track_object_get_inpoint (GESTrackObject * object);
|
||||
guint64 ges_track_object_get_duration (GESTrackObject * object);
|
||||
guint32 ges_track_object_get_priority (GESTrackObject * object);
|
||||
gboolean ges_track_object_is_active (GESTrackObject * object);
|
||||
|
||||
GParamSpec **
|
||||
ges_track_object_list_children_properties (GESTrackObject *object,
|
||||
guint *n_properties);
|
||||
gboolean ges_track_object_lookup_child (GESTrackObject *object,
|
||||
const gchar *prop_name,
|
||||
GstElement **element,
|
||||
GParamSpec **pspec);
|
||||
ges_track_object_list_children_properties (GESTrackObject *object,
|
||||
guint *n_properties);
|
||||
|
||||
void ges_track_object_get_child_property_by_pspec (GESTrackObject * object,
|
||||
GParamSpec * pspec,
|
||||
GValue * value);
|
||||
void ges_track_object_get_child_property_valist (GESTrackObject * object,
|
||||
const gchar * first_property_name,
|
||||
va_list var_args);
|
||||
void ges_track_object_get_child_property (GESTrackObject *object,
|
||||
const gchar * first_property_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
gboolean ges_track_object_lookup_child (GESTrackObject *object,
|
||||
const gchar *prop_name,
|
||||
GstElement **element,
|
||||
GParamSpec **pspec);
|
||||
|
||||
void
|
||||
ges_track_object_get_child_property_by_pspec (GESTrackObject * object,
|
||||
GParamSpec * pspec,
|
||||
GValue * value);
|
||||
|
||||
void
|
||||
ges_track_object_get_child_property_valist (GESTrackObject * object,
|
||||
const gchar * first_property_name,
|
||||
va_list var_args);
|
||||
|
||||
void ges_track_object_get_child_property (GESTrackObject *object,
|
||||
const gchar * first_property_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
void
|
||||
ges_track_object_set_child_property_valist (GESTrackObject * object,
|
||||
const gchar * first_property_name,
|
||||
va_list var_args);
|
||||
|
||||
void
|
||||
ges_track_object_set_child_property_by_pspec (GESTrackObject * object,
|
||||
GParamSpec * pspec,
|
||||
GValue * value);
|
||||
|
||||
void ges_track_object_set_child_property (GESTrackObject * object,
|
||||
const gchar * first_property_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
void ges_track_object_set_child_property_valist (GESTrackObject * object,
|
||||
const gchar * first_property_name,
|
||||
va_list var_args);
|
||||
void ges_track_object_set_child_property_by_pspec (GESTrackObject * object,
|
||||
GParamSpec * pspec,
|
||||
GValue * value);
|
||||
void ges_track_object_set_child_property (GESTrackObject * object,
|
||||
const gchar * first_property_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* _GES_TRACK_OBJECT */
|
||||
|
|
213
ges/ges-track.c
213
ges/ges-track.c
|
@ -32,6 +32,7 @@
|
|||
#include "ges-internal.h"
|
||||
#include "ges-track.h"
|
||||
#include "ges-track-object.h"
|
||||
#include "gesmarshal.h"
|
||||
|
||||
G_DEFINE_TYPE (GESTrack, ges_track, GST_TYPE_BIN);
|
||||
|
||||
|
@ -45,6 +46,7 @@ struct _GESTrackPrivate
|
|||
GstCaps *caps;
|
||||
|
||||
GstElement *composition; /* The composition associated with this track */
|
||||
GstElement *background; /* The backgrond, handle the gaps in the track */
|
||||
GstPad *srcpad; /* The source GhostPad */
|
||||
};
|
||||
|
||||
|
@ -54,9 +56,14 @@ enum
|
|||
ARG_CAPS,
|
||||
ARG_TYPE,
|
||||
ARG_DURATION,
|
||||
ARG_LAST
|
||||
ARG_LAST,
|
||||
TRACK_OBJECT_ADDED,
|
||||
TRACK_OBJECT_REMOVED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint ges_track_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static GParamSpec *properties[ARG_LAST];
|
||||
|
||||
static void pad_added_cb (GstElement * element, GstPad * pad, GESTrack * track);
|
||||
|
@ -64,6 +71,12 @@ static void
|
|||
pad_removed_cb (GstElement * element, GstPad * pad, GESTrack * track);
|
||||
static void composition_duration_cb (GstElement * composition, GParamSpec * arg
|
||||
G_GNUC_UNUSED, GESTrack * obj);
|
||||
static void
|
||||
sort_track_objects_cb (GESTrackObject * child,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESTrack * track);
|
||||
|
||||
static void timeline_duration_cb (GESTimeline * timeline,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESTrack * track);
|
||||
|
||||
static void
|
||||
ges_track_get_property (GObject * object, guint property_id,
|
||||
|
@ -130,6 +143,48 @@ ges_track_dispose (GObject * object)
|
|||
G_OBJECT_CLASS (ges_track_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
ges_track_constructed (GObject * object)
|
||||
{
|
||||
GObjectClass *parent_class;
|
||||
GstElement *background = NULL;
|
||||
GESTrack *self = GES_TRACK (object);
|
||||
GESTrackPrivate *priv = self->priv;
|
||||
|
||||
if ((priv->background = gst_element_factory_make ("gnlsource", "background"))) {
|
||||
g_object_set (priv->background, "priority", G_MAXUINT, NULL);
|
||||
|
||||
switch (self->type) {
|
||||
case GES_TRACK_TYPE_VIDEO:
|
||||
background = gst_element_factory_make ("videotestsrc", "background");
|
||||
g_object_set (background, "pattern", 2, NULL);
|
||||
break;
|
||||
case GES_TRACK_TYPE_AUDIO:
|
||||
background = gst_element_factory_make ("audiotestsrc", "background");
|
||||
g_object_set (background, "wave", 4, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (background) {
|
||||
if (!gst_bin_add (GST_BIN (priv->background), background))
|
||||
GST_ERROR ("Couldn't add background");
|
||||
else {
|
||||
if (!gst_bin_add (GST_BIN (priv->composition), priv->background))
|
||||
GST_ERROR ("Couldn't add background");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
parent_class = ges_track_parent_class;
|
||||
if (parent_class->constructed)
|
||||
parent_class->constructed (object);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
ges_track_finalize (GObject * object)
|
||||
{
|
||||
|
@ -147,6 +202,7 @@ ges_track_class_init (GESTrackClass * klass)
|
|||
object_class->set_property = ges_track_set_property;
|
||||
object_class->dispose = ges_track_dispose;
|
||||
object_class->finalize = ges_track_finalize;
|
||||
object_class->constructed = ges_track_constructed;
|
||||
|
||||
/**
|
||||
* GESTrack:caps
|
||||
|
@ -191,6 +247,34 @@ ges_track_class_init (GESTrackClass * klass)
|
|||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (object_class, ARG_TYPE,
|
||||
properties[ARG_TYPE]);
|
||||
|
||||
/**
|
||||
* GESTrack::track-object-added
|
||||
* @object: the #GESTrack
|
||||
* @effect: the #GESTrackObject that was added.
|
||||
*
|
||||
* Will be emitted after a track object was added to the track.
|
||||
*
|
||||
* Since: 0.10.2
|
||||
*/
|
||||
ges_track_signals[TRACK_OBJECT_ADDED] =
|
||||
g_signal_new ("track-object-added", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, ges_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, GES_TYPE_TRACK_OBJECT);
|
||||
|
||||
/**
|
||||
* GESTrack::track-object-removed
|
||||
* @object: the #GESTrack
|
||||
* @effect: the #GESTrackObject that was removed.
|
||||
*
|
||||
* Will be emitted after a track object was removed from the track.
|
||||
*
|
||||
* Since: 0.10.2
|
||||
*/
|
||||
ges_track_signals[TRACK_OBJECT_REMOVED] =
|
||||
g_signal_new ("track-object-removed", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, ges_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, GES_TYPE_TRACK_OBJECT);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -285,6 +369,14 @@ ges_track_set_timeline (GESTrack * track, GESTimeline * timeline)
|
|||
{
|
||||
GST_DEBUG ("track:%p, timeline:%p", track, timeline);
|
||||
|
||||
if (track->priv->timeline)
|
||||
g_signal_handlers_disconnect_by_func (track,
|
||||
timeline_duration_cb, track->priv->timeline);
|
||||
|
||||
if (timeline)
|
||||
g_signal_connect (G_OBJECT (timeline), "notify::duration",
|
||||
G_CALLBACK (timeline_duration_cb), track);
|
||||
|
||||
track->priv->timeline = timeline;
|
||||
}
|
||||
|
||||
|
@ -315,6 +407,26 @@ ges_track_set_caps (GESTrack * track, const GstCaps * caps)
|
|||
/* FIXME : update all trackobjects ? */
|
||||
}
|
||||
|
||||
|
||||
/* FIXME : put the compare function in the utils */
|
||||
|
||||
static gint
|
||||
objects_start_compare (GESTrackObject * a, GESTrackObject * b)
|
||||
{
|
||||
if (a->start == b->start) {
|
||||
if (a->priority < b->priority)
|
||||
return -1;
|
||||
if (a->priority > b->priority)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if (a->start < b->start)
|
||||
return -1;
|
||||
if (a->start > b->start)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_track_add_object:
|
||||
* @track: a #GESTrack
|
||||
|
@ -354,7 +466,9 @@ ges_track_add_object (GESTrack * track, GESTrackObject * object)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Adding object to ourself");
|
||||
GST_DEBUG ("Adding object %s to ourself %s",
|
||||
GST_OBJECT_NAME (ges_track_object_get_gnlobject (object)),
|
||||
GST_OBJECT_NAME (track->priv->composition));
|
||||
|
||||
if (G_UNLIKELY (!gst_bin_add (GST_BIN (track->priv->composition),
|
||||
ges_track_object_get_gnlobject (object)))) {
|
||||
|
@ -363,12 +477,48 @@ ges_track_add_object (GESTrack * track, GESTrackObject * object)
|
|||
}
|
||||
|
||||
g_object_ref_sink (object);
|
||||
track->priv->trackobjects =
|
||||
g_list_insert_sorted (track->priv->trackobjects, object,
|
||||
(GCompareFunc) objects_start_compare);
|
||||
|
||||
track->priv->trackobjects = g_list_append (track->priv->trackobjects, object);
|
||||
g_signal_emit (track, ges_track_signals[TRACK_OBJECT_ADDED], 0,
|
||||
GES_TRACK_OBJECT (object));
|
||||
|
||||
g_signal_connect (GES_TRACK_OBJECT (object), "notify::start",
|
||||
G_CALLBACK (sort_track_objects_cb), track);
|
||||
|
||||
g_signal_connect (GES_TRACK_OBJECT (object), "notify::priority",
|
||||
G_CALLBACK (sort_track_objects_cb), track);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_track_get_objects:
|
||||
* @track: a #GESTrack
|
||||
*
|
||||
* Gets the #GESTrackObject contained in @track
|
||||
*
|
||||
* Returns: (transfer full) (element-type GESTrackObject): the list of
|
||||
* #GESTrackObject present in the Track sorted by priority and start.
|
||||
*/
|
||||
GList *
|
||||
ges_track_get_objects (GESTrack * track)
|
||||
{
|
||||
GList *ret = NULL;
|
||||
GList *tmp;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TRACK (track), NULL);
|
||||
|
||||
for (tmp = track->priv->trackobjects; tmp; tmp = tmp->next) {
|
||||
ret = g_list_prepend (ret, tmp->data);
|
||||
g_object_ref (tmp->data);
|
||||
}
|
||||
|
||||
ret = g_list_reverse (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_track_remove_object:
|
||||
* @track: a #GESTrack
|
||||
|
@ -409,7 +559,13 @@ ges_track_remove_object (GESTrack * track, GESTrackObject * object)
|
|||
}
|
||||
}
|
||||
|
||||
g_signal_handlers_disconnect_by_func (object, sort_track_objects_cb, NULL);
|
||||
|
||||
ges_track_object_set_track (object, NULL);
|
||||
|
||||
g_signal_emit (track, ges_track_signals[TRACK_OBJECT_REMOVED], 0,
|
||||
GES_TRACK_OBJECT (object));
|
||||
|
||||
priv->trackobjects = g_list_remove (priv->trackobjects, object);
|
||||
|
||||
g_object_unref (object);
|
||||
|
@ -474,6 +630,29 @@ composition_duration_cb (GstElement * composition,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sort_track_objects_cb (GESTrackObject * child,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESTrack * track)
|
||||
{
|
||||
track->priv->trackobjects =
|
||||
g_list_sort (track->priv->trackobjects,
|
||||
(GCompareFunc) objects_start_compare);
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_duration_cb (GESTimeline * timeline,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESTrack * track)
|
||||
{
|
||||
guint64 duration;
|
||||
|
||||
g_object_get (timeline, "duration", &duration, NULL);
|
||||
g_object_set (GES_TRACK (track)->priv->background, "duration", duration,
|
||||
NULL);
|
||||
|
||||
GST_DEBUG_OBJECT (track, "Updating background duration to %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_track_get_caps:
|
||||
* @track: a #GESTrack
|
||||
|
@ -505,3 +684,31 @@ ges_track_get_timeline (GESTrack * track)
|
|||
|
||||
return track->priv->timeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_track_enable_update:
|
||||
* @track: a #GESTrack
|
||||
* @enabled: Whether the track should update on every change or not.
|
||||
*
|
||||
* Control whether the track is updated for every change happening within.
|
||||
*
|
||||
* Users will want to use this method with %FALSE before doing lots of changes,
|
||||
* and then call again with %TRUE for the changes to take effect in one go.
|
||||
*
|
||||
* Returns: %TRUE if the update status could be changed, else %FALSE.
|
||||
*/
|
||||
gboolean
|
||||
ges_track_enable_update (GESTrack * track, gboolean enabled)
|
||||
{
|
||||
gboolean update;
|
||||
|
||||
g_object_set (track->priv->composition, "update", enabled, NULL);
|
||||
|
||||
g_object_get (track->priv->composition, "update", &update, NULL);
|
||||
|
||||
if (update == enabled) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,24 +79,32 @@ struct _GESTrackClass {
|
|||
gpointer _ges_reserved[GES_PADDING];
|
||||
};
|
||||
|
||||
GType ges_track_get_type (void);
|
||||
GType ges_track_get_type (void);
|
||||
|
||||
GESTrack* ges_track_new (GESTrackType type, GstCaps * caps);
|
||||
GESTrack* ges_track_new (GESTrackType type, GstCaps * caps);
|
||||
|
||||
void ges_track_set_timeline (GESTrack * track,
|
||||
GESTimeline *timeline);
|
||||
|
||||
void ges_track_set_caps (GESTrack * track,
|
||||
const GstCaps * caps);
|
||||
|
||||
const GstCaps * ges_track_get_caps (GESTrack *track);
|
||||
|
||||
void ges_track_set_timeline (GESTrack * track,
|
||||
GESTimeline *timeline);
|
||||
void ges_track_set_caps (GESTrack * track,
|
||||
const GstCaps * caps);
|
||||
const GstCaps * ges_track_get_caps (GESTrack *track);
|
||||
const GESTimeline *ges_track_get_timeline (GESTrack *track);
|
||||
|
||||
gboolean ges_track_add_object (GESTrack * track,
|
||||
GESTrackObject * object);
|
||||
gboolean ges_track_remove_object (GESTrack * track,
|
||||
GESTrackObject * object);
|
||||
gboolean ges_track_add_object (GESTrack * track,
|
||||
GESTrackObject * object);
|
||||
|
||||
GESTrack *ges_track_video_raw_new (void);
|
||||
GESTrack *ges_track_audio_raw_new (void);
|
||||
gboolean ges_track_remove_object (GESTrack * track,
|
||||
GESTrackObject * object);
|
||||
|
||||
GESTrack *ges_track_video_raw_new (void);
|
||||
GESTrack *ges_track_audio_raw_new (void);
|
||||
|
||||
gboolean ges_track_enable_update (GESTrack * track, gboolean enabled);
|
||||
|
||||
GList* ges_track_get_objects (GESTrack *track);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -134,5 +134,7 @@ typedef struct _GESFormatterClass GESFormatterClass;
|
|||
typedef struct _GESKeyfileFormatter GESKeyfileFormatter;
|
||||
typedef struct _GESKeyfileFormatterClass GESKeyfileFormatterClass;
|
||||
|
||||
typedef struct _GESPitiviFormatter GESPitiviFormatter;
|
||||
typedef struct _GESPitiviFormatterClass GESPitiviFormatterClass;
|
||||
|
||||
#endif /* __GES_TYPES_H__ */
|
||||
|
|
24
ges/ges.c
24
ges/ges.c
|
@ -80,3 +80,27 @@ ges_init (void)
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ges_version:
|
||||
* @major: (out): pointer to a guint to store the major version number
|
||||
* @minor: (out): pointer to a guint to store the minor version number
|
||||
* @micro: (out): pointer to a guint to store the micro version number
|
||||
* @nano: (out): pointer to a guint to store the nano version number
|
||||
*
|
||||
* Gets the version number of the GStreamer Editing Services library.
|
||||
*/
|
||||
void
|
||||
ges_version (guint * major, guint * minor, guint * micro, guint * nano)
|
||||
{
|
||||
g_return_if_fail (major);
|
||||
g_return_if_fail (minor);
|
||||
g_return_if_fail (micro);
|
||||
g_return_if_fail (nano);
|
||||
|
||||
*major = GES_VERSION_MAJOR;
|
||||
*minor = GES_VERSION_MINOR;
|
||||
*micro = GES_VERSION_MICRO;
|
||||
*nano = GES_VERSION_NANO;
|
||||
}
|
||||
|
|
14
ges/ges.h
14
ges/ges.h
|
@ -20,7 +20,6 @@
|
|||
|
||||
#ifndef __GES_H__
|
||||
#define __GES_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
|
@ -63,15 +62,22 @@
|
|||
#include <ges/ges-track-audio-transition.h>
|
||||
#include <ges/ges-track-effect.h>
|
||||
#include <ges/ges-track-parse-launch-effect.h>
|
||||
|
||||
#include <ges/ges-formatter.h>
|
||||
#include <ges/ges-keyfile-formatter.h>
|
||||
|
||||
#include <ges/ges-pitivi-formatter.h>
|
||||
#include <ges/ges-utils.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean ges_init (void);
|
||||
#define GES_VERSION_MAJOR (0)
|
||||
#define GES_VERSION_MINOR (10)
|
||||
#define GES_VERSION_MICRO (1)
|
||||
#define GES_VERSION_NANO (1)
|
||||
|
||||
gboolean ges_init (void);
|
||||
|
||||
void ges_version (guint * major, guint * minor, guint * micro,
|
||||
guint * nano);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# the standard variables don't make sense for an uninstalled copy
|
||||
prefix=
|
||||
exec_prefix=
|
||||
libdir=${pcfiledir}/../ges
|
||||
includedir=${pcfiledir}/..
|
||||
libdir=@abs_top_builddir@/ges
|
||||
includedir=@abs_top_builddir@
|
||||
|
||||
Name: gst-editing-services
|
||||
Description: GStreamer Editing Services
|
||||
Version: @VERSION@
|
||||
Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@ gstreamer-controller-@GST_MAJORMINOR@ gstreamer-pbutils-@GST_MAJORMINOR@
|
||||
Libs: ${libdir}/libges-@GST_MAJORMINOR@
|
||||
Cflags: -I${includedir} -I@srcdir@/..
|
||||
Libs: @abs_top_builddir@/ges/libges-@GST_MAJORMINOR@.la
|
||||
Cflags: -I@abs_top_srcdir@ -I@abs_top_builddir@
|
||||
|
|
|
@ -72,6 +72,7 @@ GST_START_TEST (test_test_source_properties)
|
|||
assert_equals_uint64 (GES_TIMELINE_OBJECT_INPOINT (object), 12);
|
||||
|
||||
trackobject = ges_timeline_object_create_track_object (object, track);
|
||||
ges_timeline_object_add_track_object (object, trackobject);
|
||||
fail_unless (trackobject != NULL);
|
||||
fail_unless (ges_track_object_set_track (trackobject, track));
|
||||
|
||||
|
@ -169,10 +170,12 @@ GST_START_TEST (test_test_source_in_layer)
|
|||
assert_equals_float (volume, 0);
|
||||
|
||||
|
||||
freq = ges_track_audio_test_source_get_freq (
|
||||
GES_TRACK_AUDIO_TEST_SOURCE (trobj));
|
||||
volume = ges_track_audio_test_source_get_volume (
|
||||
GES_TRACK_AUDIO_TEST_SOURCE (trobj));
|
||||
freq =
|
||||
ges_track_audio_test_source_get_freq (GES_TRACK_AUDIO_TEST_SOURCE
|
||||
(trobj));
|
||||
volume =
|
||||
ges_track_audio_test_source_get_volume (GES_TRACK_AUDIO_TEST_SOURCE
|
||||
(trobj));
|
||||
g_assert (freq == 440);
|
||||
g_assert (volume == 0);
|
||||
|
||||
|
@ -183,10 +186,12 @@ GST_START_TEST (test_test_source_in_layer)
|
|||
assert_equals_float (freq, 2000);
|
||||
assert_equals_float (volume, 0.5);
|
||||
|
||||
freq = ges_track_audio_test_source_get_freq (
|
||||
GES_TRACK_AUDIO_TEST_SOURCE (trobj));
|
||||
volume = ges_track_audio_test_source_get_volume (
|
||||
GES_TRACK_AUDIO_TEST_SOURCE (trobj));
|
||||
freq =
|
||||
ges_track_audio_test_source_get_freq (GES_TRACK_AUDIO_TEST_SOURCE
|
||||
(trobj));
|
||||
volume =
|
||||
ges_track_audio_test_source_get_volume (GES_TRACK_AUDIO_TEST_SOURCE
|
||||
(trobj));
|
||||
g_assert (freq == 2000);
|
||||
g_assert (volume == 0.5);
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ GST_START_TEST (test_filesource_basic)
|
|||
trackobject =
|
||||
ges_timeline_object_create_track_object (GES_TIMELINE_OBJECT (source),
|
||||
track);
|
||||
ges_timeline_object_add_track_object (GES_TIMELINE_OBJECT (source),
|
||||
trackobject);
|
||||
fail_unless (trackobject != NULL);
|
||||
|
||||
/* The track holds a reference to the object
|
||||
|
@ -110,6 +112,7 @@ GST_START_TEST (test_filesource_properties)
|
|||
assert_equals_uint64 (GES_TIMELINE_OBJECT_INPOINT (object), 12);
|
||||
|
||||
trackobject = ges_timeline_object_create_track_object (object, track);
|
||||
ges_timeline_object_add_track_object (object, trackobject);
|
||||
fail_unless (trackobject != NULL);
|
||||
fail_unless (ges_track_object_set_track (trackobject, track));
|
||||
|
||||
|
@ -174,6 +177,7 @@ GST_START_TEST (test_filesource_images)
|
|||
|
||||
/* the returned track object should be an image source */
|
||||
trobj = ges_timeline_object_create_track_object (tlobj, v);
|
||||
ges_timeline_object_add_track_object (tlobj, trobj);
|
||||
fail_unless (GES_IS_TRACK_IMAGE_SOURCE (trobj));
|
||||
|
||||
/* The track holds a reference to the object
|
||||
|
@ -183,19 +187,9 @@ GST_START_TEST (test_filesource_images)
|
|||
ges_track_remove_object (v, trobj);
|
||||
ges_timeline_object_release_track_object (tlobj, trobj);
|
||||
|
||||
/* the timeline object should create an audio test source when the is_image
|
||||
* property is set true */
|
||||
|
||||
/* the timeline object should not create any TrackObject in the audio track */
|
||||
trobj = ges_timeline_object_create_track_object (tlobj, a);
|
||||
fail_unless (GES_IS_TRACK_AUDIO_TEST_SOURCE (trobj));
|
||||
|
||||
/* The track holds a reference to the object
|
||||
* And the timelineobject holds a reference to the object */
|
||||
ASSERT_OBJECT_REFCOUNT (trobj, "Audio Track Object", 2);
|
||||
|
||||
ges_track_remove_object (v, trobj);
|
||||
ges_timeline_object_release_track_object (tlobj, trobj);
|
||||
|
||||
fail_unless (trobj == NULL);
|
||||
|
||||
g_object_unref (a);
|
||||
g_object_unref (v);
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <ges/ges.h>
|
||||
#include <gst/check/gstcheck.h>
|
||||
|
||||
#define LAYER_HEIGHT 1000
|
||||
|
||||
static gboolean
|
||||
my_fill_track_func (GESTimelineObject * object,
|
||||
GESTrackObject * trobject, GstElement * gnlobj, gpointer user_data)
|
||||
|
@ -116,16 +118,16 @@ GST_START_TEST (test_layer_properties)
|
|||
/* Change the priority of the layer */
|
||||
g_object_set (layer, "priority", 1, NULL);
|
||||
assert_equals_int (ges_timeline_layer_get_priority (layer), 1);
|
||||
assert_equals_uint64 (GES_TIMELINE_OBJECT_PRIORITY (object), 10);
|
||||
assert_equals_uint64 (GES_TIMELINE_OBJECT_PRIORITY (object), 0);
|
||||
gnl_object_check (ges_track_object_get_gnlobject (trackobject), 42, 51, 12,
|
||||
51, 10, TRUE);
|
||||
51, LAYER_HEIGHT, TRUE);
|
||||
|
||||
/* Change it to an insanely high value */
|
||||
g_object_set (layer, "priority", 1000000, NULL);
|
||||
assert_equals_int (ges_timeline_layer_get_priority (layer), 1000000);
|
||||
assert_equals_uint64 (GES_TIMELINE_OBJECT_PRIORITY (object), 10000000);
|
||||
g_object_set (layer, "priority", 31, NULL);
|
||||
assert_equals_int (ges_timeline_layer_get_priority (layer), 31);
|
||||
assert_equals_uint64 (GES_TIMELINE_OBJECT_PRIORITY (object), 0);
|
||||
gnl_object_check (ges_track_object_get_gnlobject (trackobject), 42, 51, 12,
|
||||
51, 10000000, TRUE);
|
||||
51, LAYER_HEIGHT * 31, TRUE);
|
||||
|
||||
/* and back to 0 */
|
||||
g_object_set (layer, "priority", 0, NULL);
|
||||
|
@ -143,6 +145,192 @@ GST_START_TEST (test_layer_properties)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_layer_priorities)
|
||||
{
|
||||
GESTrack *track;
|
||||
GESTimeline *timeline;
|
||||
GESTimelineLayer *layer1, *layer2, *layer3;
|
||||
GESTrackObject *tckobj1, *tckobj2, *tckobj3;
|
||||
GESTimelineObject *object1, *object2, *object3;
|
||||
GstElement *gnlobj1, *gnlobj2, *gnlobj3;
|
||||
guint prio1, prio2, prio3;
|
||||
GList *objs, *tmp;
|
||||
|
||||
ges_init ();
|
||||
|
||||
/* Timeline and 3 Layer */
|
||||
timeline = ges_timeline_new ();
|
||||
layer1 = (GESTimelineLayer *) ges_timeline_layer_new ();
|
||||
layer2 = (GESTimelineLayer *) ges_timeline_layer_new ();
|
||||
layer3 = (GESTimelineLayer *) ges_timeline_layer_new ();
|
||||
|
||||
ges_timeline_layer_set_priority (layer2, 1);
|
||||
ges_timeline_layer_set_priority (layer3, 2);
|
||||
|
||||
fail_unless (ges_timeline_add_layer (timeline, layer1));
|
||||
fail_unless (ges_timeline_add_layer (timeline, layer2));
|
||||
fail_unless (ges_timeline_add_layer (timeline, layer3));
|
||||
fail_unless_equals_int (ges_timeline_layer_get_priority (layer1), 0);
|
||||
fail_unless_equals_int (ges_timeline_layer_get_priority (layer2), 1);
|
||||
fail_unless_equals_int (ges_timeline_layer_get_priority (layer3), 2);
|
||||
|
||||
track = ges_track_video_raw_new ();
|
||||
fail_unless (track != NULL);
|
||||
fail_unless (ges_timeline_add_track (timeline, track));
|
||||
|
||||
object1 =
|
||||
GES_TIMELINE_OBJECT (ges_custom_timeline_source_new (my_fill_track_func,
|
||||
NULL));
|
||||
object2 =
|
||||
GES_TIMELINE_OBJECT (ges_custom_timeline_source_new (my_fill_track_func,
|
||||
NULL));
|
||||
object3 =
|
||||
GES_TIMELINE_OBJECT (ges_custom_timeline_source_new (my_fill_track_func,
|
||||
NULL));
|
||||
fail_unless (object1 != NULL);
|
||||
fail_unless (object2 != NULL);
|
||||
fail_unless (object3 != NULL);
|
||||
|
||||
/* Set priorities on the objects */
|
||||
g_object_set (object1, "priority", 0, NULL);
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object1), 0);
|
||||
g_object_set (object2, "priority", 1, NULL);
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object2), 1);
|
||||
g_object_set (object3, "priority", LAYER_HEIGHT + 1, NULL);
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object3), LAYER_HEIGHT + 1);
|
||||
|
||||
/* Add objects to the timeline */
|
||||
fail_unless (ges_timeline_layer_add_object (layer1, object1));
|
||||
tckobj1 = ges_timeline_object_find_track_object (object1, track, G_TYPE_NONE);
|
||||
fail_unless (tckobj1 != NULL);
|
||||
|
||||
fail_unless (ges_timeline_layer_add_object (layer2, object2));
|
||||
tckobj2 = ges_timeline_object_find_track_object (object2, track, G_TYPE_NONE);
|
||||
fail_unless (tckobj2 != NULL);
|
||||
|
||||
fail_unless (ges_timeline_layer_add_object (layer3, object3));
|
||||
tckobj3 = ges_timeline_object_find_track_object (object3, track, G_TYPE_NONE);
|
||||
fail_unless (tckobj3 != NULL);
|
||||
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object1), 0);
|
||||
gnlobj1 = ges_track_object_get_gnlobject (tckobj1);
|
||||
fail_unless (gnlobj1 != NULL);
|
||||
g_object_get (gnlobj1, "priority", &prio1, NULL);
|
||||
assert_equals_int (prio1, 0);
|
||||
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object2), 1);
|
||||
gnlobj2 = ges_track_object_get_gnlobject (tckobj2);
|
||||
fail_unless (gnlobj2 != NULL);
|
||||
g_object_get (gnlobj2, "priority", &prio2, NULL);
|
||||
/* object2 is on the second layer and has a priority of 1 */
|
||||
assert_equals_int (prio2, LAYER_HEIGHT + 1);
|
||||
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object3), LAYER_HEIGHT - 1);
|
||||
gnlobj3 = ges_track_object_get_gnlobject (tckobj3);
|
||||
fail_unless (gnlobj3 != NULL);
|
||||
/* object3 is on the third layer and has a priority of LAYER_HEIGHT + 1
|
||||
* it priority must have the maximum priority of this layer*/
|
||||
g_object_get (gnlobj3, "priority", &prio3, NULL);
|
||||
assert_equals_int (prio3, LAYER_HEIGHT * 3 - 1);
|
||||
|
||||
/* Move layers around */
|
||||
g_object_set (layer1, "priority", 2, NULL);
|
||||
g_object_set (layer2, "priority", 0, NULL);
|
||||
g_object_set (layer3, "priority", 1, NULL);
|
||||
|
||||
/* And check the new priorities */
|
||||
assert_equals_int (ges_timeline_layer_get_priority (layer1), 2);
|
||||
assert_equals_int (ges_timeline_layer_get_priority (layer2), 0);
|
||||
assert_equals_int (ges_timeline_layer_get_priority (layer3), 1);
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object1), 0);
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object2), 1);
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object3), LAYER_HEIGHT - 1);
|
||||
g_object_get (gnlobj1, "priority", &prio1, NULL);
|
||||
g_object_get (gnlobj2, "priority", &prio2, NULL);
|
||||
g_object_get (gnlobj3, "priority", &prio3, NULL);
|
||||
assert_equals_int (prio1, 2 * LAYER_HEIGHT);
|
||||
assert_equals_int (prio2, 1);
|
||||
assert_equals_int (prio3, LAYER_HEIGHT * 2 - 1);
|
||||
|
||||
/* And move objects around */
|
||||
fail_unless (ges_timeline_object_move_to_layer (object2, layer1));
|
||||
fail_unless (ges_timeline_object_move_to_layer (object3, layer1));
|
||||
|
||||
objs = ges_timeline_layer_get_objects (layer1);
|
||||
assert_equals_int (g_list_length (objs), 3);
|
||||
fail_unless (ges_timeline_layer_get_objects (layer2) == NULL);
|
||||
fail_unless (ges_timeline_layer_get_objects (layer3) == NULL);
|
||||
|
||||
for (tmp = objs; tmp; tmp = g_list_next (tmp)) {
|
||||
g_object_unref (tmp->data);
|
||||
}
|
||||
g_list_free (objs);
|
||||
|
||||
/* Check their priorities (layer1 priority is now 2) */
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object1), 0);
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object2), 1);
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object3), LAYER_HEIGHT - 1);
|
||||
g_object_get (gnlobj1, "priority", &prio1, NULL);
|
||||
g_object_get (gnlobj2, "priority", &prio2, NULL);
|
||||
g_object_get (gnlobj3, "priority", &prio3, NULL);
|
||||
assert_equals_int (prio1, 2 * LAYER_HEIGHT);
|
||||
assert_equals_int (prio2, 2 * LAYER_HEIGHT + 1);
|
||||
assert_equals_int (prio3, LAYER_HEIGHT * 3 - 1);
|
||||
|
||||
/* And change TrackObject-s priorities and check that changes are well
|
||||
* refected on it containing TimelineObject */
|
||||
ges_track_object_set_priority (tckobj3, LAYER_HEIGHT * 2);
|
||||
g_object_get (gnlobj3, "priority", &prio3, NULL);
|
||||
assert_equals_int (prio3, 2 * LAYER_HEIGHT);
|
||||
assert_equals_int (GES_TIMELINE_OBJECT_PRIORITY (object3), 0);
|
||||
|
||||
g_object_unref (tckobj1);
|
||||
g_object_unref (tckobj2);
|
||||
g_object_unref (tckobj3);
|
||||
g_object_unref (timeline);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_layer_automatic_transition)
|
||||
{
|
||||
GESTimeline *timeline;
|
||||
GESTimelineLayer *layer;
|
||||
GESTimelineTestSource *src, *srcbis;
|
||||
GList *objects = NULL, *tmp = NULL;
|
||||
gboolean res = FALSE;
|
||||
|
||||
ges_init ();
|
||||
|
||||
timeline = ges_timeline_new_audio_video ();
|
||||
layer = ges_timeline_layer_new ();
|
||||
ges_timeline_add_layer (timeline, layer);
|
||||
|
||||
g_object_set (layer, "auto-transition", TRUE, NULL);
|
||||
src = ges_timeline_test_source_new ();
|
||||
srcbis = ges_timeline_test_source_new ();
|
||||
|
||||
g_object_set (srcbis, "start", (gint64) 5000, "duration", (gint64) 10000LL,
|
||||
NULL);
|
||||
g_object_set (src, "start", (gint64) 0, "duration", (gint64) 10000LL, NULL);
|
||||
|
||||
ges_timeline_layer_add_object (layer, GES_TIMELINE_OBJECT (src));
|
||||
ges_timeline_layer_add_object (layer, GES_TIMELINE_OBJECT (srcbis));
|
||||
|
||||
objects = ges_timeline_layer_get_objects (layer);
|
||||
|
||||
for (tmp = objects; tmp; tmp = tmp->next) {
|
||||
if (GES_IS_TIMELINE_STANDARD_TRANSITION (tmp->data)) {
|
||||
res = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
fail_unless (res == TRUE);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
|
||||
static Suite *
|
||||
ges_suite (void)
|
||||
{
|
||||
|
@ -152,6 +340,8 @@ ges_suite (void)
|
|||
suite_add_tcase (s, tc_chain);
|
||||
|
||||
tcase_add_test (tc_chain, test_layer_properties);
|
||||
tcase_add_test (tc_chain, test_layer_priorities);
|
||||
tcase_add_test (tc_chain, test_layer_automatic_transition);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ GST_START_TEST (test_overlay_properties)
|
|||
assert_equals_uint64 (GES_TIMELINE_OBJECT_INPOINT (object), 12);
|
||||
|
||||
trackobject = ges_timeline_object_create_track_object (object, track);
|
||||
ges_timeline_object_add_track_object (object, trackobject);
|
||||
fail_unless (trackobject != NULL);
|
||||
fail_unless (ges_track_object_set_track (trackobject, track));
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <ges/ges.h>
|
||||
#include <gst/check/gstcheck.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#define GetCurrentDir getcwd
|
||||
|
||||
#include <gst/audio/audio.h>
|
||||
|
||||
|
@ -121,6 +123,7 @@ GST_START_TEST (test_keyfile_save)
|
|||
KEY ("Object0", "in-point", "0");
|
||||
KEY ("Object0", "duration", "2000000000");
|
||||
KEY ("Object0", "priority", "2");
|
||||
KEY ("Object0", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
|
||||
KEY ("Object0", "mute", "false");
|
||||
KEY ("Object0", "vpattern", "100% Black");
|
||||
KEY ("Object0", "freq", "440");
|
||||
|
@ -140,6 +143,7 @@ GST_START_TEST (test_keyfile_save)
|
|||
KEY ("Object1", "in-point", "0");
|
||||
KEY ("Object1", "duration", "500000000");
|
||||
KEY ("Object1", "priority", "1");
|
||||
KEY ("Object1", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
|
||||
KEY ("Object1", "vtype", "A bar moves from left to right");
|
||||
COMPARE;
|
||||
|
||||
|
@ -154,6 +158,7 @@ GST_START_TEST (test_keyfile_save)
|
|||
KEY ("Object2", "in-point", "0");
|
||||
KEY ("Object2", "duration", "2000000000");
|
||||
KEY ("Object2", "priority", "3");
|
||||
KEY ("Object2", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
|
||||
KEY ("Object2", "mute", "false");
|
||||
KEY ("Object2", "vpattern", "100% Black");
|
||||
KEY ("Object2", "freq", "440");
|
||||
|
@ -183,8 +188,8 @@ GST_START_TEST (test_keyfile_save)
|
|||
KEY ("Object3", "start", "5000000000");
|
||||
KEY ("Object3", "in-point", "0");
|
||||
KEY ("Object3", "duration", "1000000000");
|
||||
/* The second layer's minimum priority will be 10 */
|
||||
KEY ("Object3", "priority", "10");
|
||||
KEY ("Object3", "priority", "0");
|
||||
KEY ("Object3", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
|
||||
KEY ("Object3", "mute", "false");
|
||||
KEY ("Object3", "text", "\"the\\\\ quick\\\\ brown\\\\ fox\"");
|
||||
KEY ("Object3", "font-desc", "\"Serif\\\\ 36\"");
|
||||
|
@ -626,6 +631,53 @@ GST_START_TEST (test_keyfile_load)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_pitivi_file_load)
|
||||
{
|
||||
GESFormatter *formatter;
|
||||
GESTimeline *timeline, *expected;
|
||||
GMainLoop *mainloop;
|
||||
char cCurrentPath[FILENAME_MAX];
|
||||
char *a;
|
||||
gchar *uri, *save_uri;
|
||||
|
||||
/*create the expected timeline */
|
||||
timeline = ges_timeline_new ();
|
||||
mainloop = g_main_loop_new (NULL, FALSE);
|
||||
expected = ges_timeline_new ();
|
||||
|
||||
/* create the timeline from formatter */
|
||||
formatter = GES_FORMATTER (ges_pitivi_formatter_new ());
|
||||
a = GetCurrentDir (cCurrentPath, sizeof (cCurrentPath));
|
||||
uri = g_strconcat (a, "/test.xptv", NULL);
|
||||
save_uri = g_strconcat (a, "/testsave.xptv", NULL);
|
||||
if (g_file_test (uri, G_FILE_TEST_EXISTS) == FALSE) {
|
||||
GST_ERROR ("Could not test GESPitiviFormatter as no project file found");
|
||||
return;
|
||||
}
|
||||
|
||||
ges_formatter_load_from_uri (formatter, timeline, uri);
|
||||
g_timeout_add (1000, (GSourceFunc) g_main_loop_quit, mainloop);
|
||||
g_main_loop_run (mainloop);
|
||||
|
||||
formatter = GES_FORMATTER (ges_pitivi_formatter_new ());
|
||||
ges_formatter_save_to_uri (formatter, timeline, save_uri);
|
||||
formatter = GES_FORMATTER (ges_pitivi_formatter_new ());
|
||||
ges_formatter_load_from_uri (formatter, expected, uri);
|
||||
g_timeout_add (1000, (GSourceFunc) g_main_loop_quit, mainloop);
|
||||
g_main_loop_run (mainloop);
|
||||
|
||||
/* compare the two timelines and fail test if they are different */
|
||||
TIMELINE_COMPARE (expected, timeline);
|
||||
g_free (uri);
|
||||
g_free (save_uri);
|
||||
g_main_loop_unref (mainloop);
|
||||
g_object_unref (formatter);
|
||||
g_object_unref (timeline);
|
||||
g_object_unref (expected);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_keyfile_identity)
|
||||
{
|
||||
|
||||
|
@ -679,9 +731,11 @@ GST_START_TEST (test_keyfile_identity)
|
|||
"freq", (gdouble) 600,
|
||||
"volume", 1.0, "vpattern", GES_VIDEO_TEST_PATTERN_RED);
|
||||
|
||||
} LAYER_END;
|
||||
}
|
||||
LAYER_END;
|
||||
|
||||
} TIMELINE_END;
|
||||
}
|
||||
TIMELINE_END;
|
||||
|
||||
serialized = ges_timeline_new ();
|
||||
|
||||
|
@ -708,6 +762,7 @@ ges_suite (void)
|
|||
tcase_add_test (tc_chain, test_keyfile_save);
|
||||
tcase_add_test (tc_chain, test_keyfile_load);
|
||||
tcase_add_test (tc_chain, test_keyfile_identity);
|
||||
tcase_add_test (tc_chain, test_pitivi_file_load);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ GST_START_TEST (test_object_properties)
|
|||
assert_equals_uint64 (GES_TIMELINE_OBJECT_INPOINT (object), 12);
|
||||
|
||||
trackobject = ges_timeline_object_create_track_object (object, track);
|
||||
ges_timeline_object_add_track_object (object, trackobject);
|
||||
fail_unless (trackobject != NULL);
|
||||
fail_unless (ges_track_object_set_track (trackobject, track));
|
||||
|
||||
|
@ -146,6 +147,7 @@ GST_START_TEST (test_object_properties_unlocked)
|
|||
assert_equals_uint64 (GES_TIMELINE_OBJECT_INPOINT (object), 12);
|
||||
|
||||
trackobject = ges_timeline_object_create_track_object (object, track);
|
||||
ges_timeline_object_add_track_object (object, trackobject);
|
||||
fail_unless (trackobject != NULL);
|
||||
fail_unless (ges_track_object_set_track (trackobject, track));
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ GST_START_TEST (test_title_source_properties)
|
|||
assert_equals_uint64 (GES_TIMELINE_OBJECT_INPOINT (object), 12);
|
||||
|
||||
trackobject = ges_timeline_object_create_track_object (object, track);
|
||||
ges_timeline_object_add_track_object (object, trackobject);
|
||||
fail_unless (trackobject != NULL);
|
||||
fail_unless (ges_track_object_set_track (trackobject, track));
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ GST_START_TEST (test_transition_basic)
|
|||
trackobject =
|
||||
ges_timeline_object_create_track_object (GES_TIMELINE_OBJECT (tr2),
|
||||
track);
|
||||
ges_timeline_object_add_track_object (GES_TIMELINE_OBJECT (tr2), trackobject);
|
||||
|
||||
fail_unless (trackobject != NULL);
|
||||
fail_unless (ges_track_video_transition_get_transition_type
|
||||
|
@ -103,6 +104,7 @@ GST_START_TEST (test_transition_properties)
|
|||
assert_equals_uint64 (GES_TIMELINE_OBJECT_INPOINT (object), 12);
|
||||
|
||||
trackobject = ges_timeline_object_create_track_object (object, track);
|
||||
ges_timeline_object_add_track_object (object, trackobject);
|
||||
fail_unless (trackobject != NULL);
|
||||
fail_unless (ges_track_object_set_track (trackobject, track));
|
||||
|
||||
|
@ -157,6 +159,7 @@ GST_START_TEST (test_transition_properties)
|
|||
|
||||
GST_DEBUG ("creating track object");
|
||||
trackobject = ges_timeline_object_create_track_object (object, track);
|
||||
ges_timeline_object_add_track_object (object, trackobject);
|
||||
fail_unless (trackobject != NULL);
|
||||
fail_unless (ges_track_object_set_track (trackobject, track));
|
||||
|
||||
|
|
|
@ -112,6 +112,7 @@ gboolean window_delete_event_cb (GtkObject * window, GdkEvent * event,
|
|||
void new_activate_cb (GtkMenuItem * item, App * app);
|
||||
void open_activate_cb (GtkMenuItem * item, App * app);
|
||||
void save_as_activate_cb (GtkMenuItem * item, App * app);
|
||||
void launch_pitivi_project_activate_cb (GtkMenuItem * item, App * app);
|
||||
void quit_item_activate_cb (GtkMenuItem * item, App * app);
|
||||
void delete_activate_cb (GtkAction * item, App * app);
|
||||
void play_activate_cb (GtkAction * item, App * app);
|
||||
|
@ -451,6 +452,24 @@ pipeline_state_changed_cb (App * app)
|
|||
gtk_widget_set_sensitive (app->properties, !playing_or_paused);
|
||||
}
|
||||
|
||||
static void
|
||||
project_bus_message_cb (GstBus * bus, GstMessage * message,
|
||||
GMainLoop * mainloop)
|
||||
{
|
||||
switch (GST_MESSAGE_TYPE (message)) {
|
||||
case GST_MESSAGE_ERROR:
|
||||
g_printerr ("ERROR\n");
|
||||
g_main_loop_quit (mainloop);
|
||||
break;
|
||||
case GST_MESSAGE_EOS:
|
||||
g_printerr ("Done\n");
|
||||
g_main_loop_quit (mainloop);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bus_message_cb (GstBus * bus, GstMessage * message, App * app)
|
||||
{
|
||||
|
@ -1148,6 +1167,33 @@ app_add_file (App * app, gchar * uri)
|
|||
obj, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
app_launch_project (App * app, gchar * uri)
|
||||
{
|
||||
GESTimeline *timeline;
|
||||
GMainLoop *mainloop;
|
||||
GESTimelinePipeline *pipeline;
|
||||
GstBus *bus;
|
||||
GESFormatter *formatter;
|
||||
|
||||
uri = g_strsplit (uri, "//", 2)[1];
|
||||
printf ("we will launch this uri : %s\n", uri);
|
||||
formatter = GES_FORMATTER (ges_pitivi_formatter_new ());
|
||||
timeline = ges_timeline_new ();
|
||||
pipeline = ges_timeline_pipeline_new ();
|
||||
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||
mainloop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
ges_timeline_pipeline_add_timeline (pipeline, timeline);
|
||||
ges_formatter_load_from_uri (formatter, timeline, uri);
|
||||
ges_timeline_pipeline_set_mode (pipeline, TIMELINE_MODE_PREVIEW_VIDEO);
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
gst_bus_add_signal_watch (bus);
|
||||
g_signal_connect (bus, "message", G_CALLBACK (project_bus_message_cb),
|
||||
mainloop);
|
||||
g_main_loop_run (mainloop);
|
||||
}
|
||||
|
||||
static void
|
||||
app_add_title (App * app)
|
||||
{
|
||||
|
@ -1371,6 +1417,35 @@ new_activate_cb (GtkMenuItem * item, App * app)
|
|||
app_new ();
|
||||
}
|
||||
|
||||
void
|
||||
launch_pitivi_project_activate_cb (GtkMenuItem * item, App * app)
|
||||
{
|
||||
GtkFileChooserDialog *dlg;
|
||||
GtkFileFilter *filter;
|
||||
|
||||
GST_DEBUG ("add file signal handler");
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, "pitivi projects");
|
||||
gtk_file_filter_add_pattern (filter, "*.xptv");
|
||||
dlg = (GtkFileChooserDialog *)
|
||||
gtk_file_chooser_dialog_new ("Preview Project...",
|
||||
GTK_WINDOW (app->main_window),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL,
|
||||
GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), filter);
|
||||
|
||||
g_object_set (G_OBJECT (dlg), "select-multiple", FALSE, NULL);
|
||||
|
||||
if (gtk_dialog_run ((GtkDialog *) dlg) == GTK_RESPONSE_OK) {
|
||||
gchar *uri;
|
||||
uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dlg));
|
||||
gtk_widget_destroy ((GtkWidget *) dlg);
|
||||
app_launch_project (app, uri);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
open_activate_cb (GtkMenuItem * item, App * app)
|
||||
{
|
||||
|
|
|
@ -90,6 +90,16 @@
|
|||
<signal name="activate" handler="save_as_activate_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="launch_pitivi_project">
|
||||
<property name="label" translatable="yes">Preview Pitivi Project</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Launches a .xptv project</property>
|
||||
<property name="image">image1</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="launch_pitivi_project_activate_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -271,8 +281,8 @@
|
|||
<child>
|
||||
<object class="GtkToolButton" id="play_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">play</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">play</property>
|
||||
<property name="label" translatable="yes">toolbutton1</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -284,8 +294,8 @@
|
|||
<child>
|
||||
<object class="GtkToolButton" id="toolbutton6">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">stop</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">stop</property>
|
||||
<property name="label" translatable="yes">toolbutton6</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -306,8 +316,8 @@
|
|||
<child>
|
||||
<object class="GtkToolButton" id="delete_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">delete</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">delete</property>
|
||||
<property name="label" translatable="yes">Delete</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -328,8 +338,8 @@
|
|||
<child>
|
||||
<object class="GtkToolButton" id="add_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">add_file</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">add_file</property>
|
||||
<property name="label" translatable="yes">toolbutton1</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -341,8 +351,8 @@
|
|||
<child>
|
||||
<object class="GtkToolButton" id="toolbutton2">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">add_text</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">add_text</property>
|
||||
<property name="label" translatable="yes">toolbutton2</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -354,8 +364,8 @@
|
|||
<child>
|
||||
<object class="GtkToolButton" id="toolbutton4">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">add_test</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">add_test</property>
|
||||
<property name="label" translatable="yes">toolbutton4</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -367,8 +377,8 @@
|
|||
<child>
|
||||
<object class="GtkToolButton" id="toolbutton5">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">add_transition</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">add_transition</property>
|
||||
<property name="label" translatable="yes">toolbutton5</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -402,8 +412,8 @@
|
|||
<child>
|
||||
<object class="GtkToolButton" id="toolbutton8">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">move_up</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">move_up</property>
|
||||
<property name="label" translatable="yes">toolbutton8</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -415,8 +425,8 @@
|
|||
<child>
|
||||
<object class="GtkToolButton" id="toolbutton9">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">move_down</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">move_down</property>
|
||||
<property name="label" translatable="yes">toolbutton9</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -437,8 +447,8 @@
|
|||
<child>
|
||||
<object class="GtkToggleToolButton" id="toolbutton11">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">audio_track</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">audio_track</property>
|
||||
<property name="label" translatable="yes">toolbutton11</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -450,8 +460,8 @@
|
|||
<child>
|
||||
<object class="GtkToggleToolButton" id="toolbutton12">
|
||||
<property name="visible">True</property>
|
||||
<property name="related_action">video_track</property>
|
||||
<property name="use_action_appearance">True</property>
|
||||
<property name="related_action">video_track</property>
|
||||
<property name="label" translatable="yes">toolbutton12</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
|
@ -1013,6 +1023,10 @@
|
|||
<action-widget response="0">button1</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
<object class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-floppy</property>
|
||||
</object>
|
||||
<object class="GtkSizeGroup" id="LabelSizeGroup">
|
||||
<widgets>
|
||||
<widget name="label4"/>
|
||||
|
|
|
@ -35,6 +35,8 @@ static guint repeat = 0;
|
|||
static GESTimelinePipeline *pipeline = NULL;
|
||||
static gboolean seenerrors = FALSE;
|
||||
|
||||
void load_project (gchar * uri);
|
||||
|
||||
static gchar *
|
||||
ensure_uri (gchar * location)
|
||||
{
|
||||
|
@ -396,6 +398,31 @@ print_pattern_list (void)
|
|||
print_enum (GES_VIDEO_TEST_PATTERN_TYPE);
|
||||
}
|
||||
|
||||
void
|
||||
load_project (gchar * uri)
|
||||
{
|
||||
GESFormatter *formatter;
|
||||
GESTimeline *timeline;
|
||||
GMainLoop *mainloop;
|
||||
GESTimelinePipeline *pipeline;
|
||||
GstBus *bus;
|
||||
|
||||
formatter = GES_FORMATTER (ges_pitivi_formatter_new ());
|
||||
timeline = ges_timeline_new ();
|
||||
pipeline = ges_timeline_pipeline_new ();
|
||||
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||
mainloop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
ges_timeline_pipeline_add_timeline (pipeline, timeline);
|
||||
ges_formatter_load_from_uri (formatter, timeline, uri);
|
||||
ges_timeline_pipeline_set_mode (pipeline, TIMELINE_MODE_PREVIEW_VIDEO);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
gst_bus_add_signal_watch (bus);
|
||||
g_signal_connect (bus, "message", G_CALLBACK (bus_message_cb), mainloop);
|
||||
g_main_loop_run (mainloop);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, gchar ** argv)
|
||||
{
|
||||
|
@ -416,6 +443,7 @@ main (int argc, gchar ** argv)
|
|||
static gboolean verbose = FALSE;
|
||||
gchar *save_path = NULL;
|
||||
gchar *load_path = NULL;
|
||||
gchar *project_path = NULL;
|
||||
GOptionEntry options[] = {
|
||||
{"thumbnail", 'm', 0.0, G_OPTION_ARG_DOUBLE, &thumbinterval,
|
||||
"Take thumbnails every n seconds (saved in current directory)", "N"},
|
||||
|
@ -451,6 +479,8 @@ main (int argc, gchar ** argv)
|
|||
"Output status information and property notifications", NULL},
|
||||
{"exclude", 'X', 0, G_OPTION_ARG_NONE, &exclude_args,
|
||||
"Do not output status information of TYPE", "TYPE1,TYPE2,..."},
|
||||
{"load-xptv", 'y', 0, G_OPTION_ARG_STRING, &project_path,
|
||||
"Load xptv project from file for previewing", "<path>"},
|
||||
{NULL}
|
||||
};
|
||||
GOptionContext *ctx;
|
||||
|
@ -499,6 +529,10 @@ main (int argc, gchar ** argv)
|
|||
exit (0);
|
||||
}
|
||||
|
||||
if (project_path) {
|
||||
load_project (project_path);
|
||||
exit (0);
|
||||
}
|
||||
if (((!load_path && (argc < 4))) || (outputuri && (!render && !smartrender))) {
|
||||
g_printf ("%s", g_option_context_get_help (ctx, TRUE, NULL));
|
||||
g_option_context_free (ctx);
|
||||
|
|
Loading…
Reference in a new issue