mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
ges: Move TimeOverlayClip out of GESTestClip
This was complexifying the implementation for very little gain. Each source type should ideally have its own API. In that patch we make it so we do not have to subclass anything but instead use GESAsset to pass information about how the pipeline should look like. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/175>
This commit is contained in:
parent
b79e5e3508
commit
5e448921d8
19 changed files with 459 additions and 231 deletions
201
docs/libs/GESTimeOverlayClip-children-props.md
Normal file
201
docs/libs/GESTimeOverlayClip-children-props.md
Normal file
|
@ -0,0 +1,201 @@
|
|||
#### `alpha`
|
||||
|
||||
alpha of the stream
|
||||
|
||||
Value type: #gdouble
|
||||
|
||||
#### `background-color`
|
||||
|
||||
Background color to use (big-endian ARGB)
|
||||
|
||||
Value type: #guint
|
||||
|
||||
See #videotestsrc:background-color
|
||||
|
||||
#### `font-desc`
|
||||
|
||||
Pango font description of font to be used for rendering. See documentation of
|
||||
pango_font_description_from_string for syntax.
|
||||
|
||||
Value type: #gchararray
|
||||
|
||||
See #timeoverlay:font-desc
|
||||
|
||||
#### `foreground-color`
|
||||
|
||||
Foreground color to use (big-endian ARGB)
|
||||
|
||||
Value type: #guint
|
||||
|
||||
See #videotestsrc:foreground-color
|
||||
|
||||
#### `freq`
|
||||
|
||||
Frequency of test signal. The sample rate needs to be at least 2 times higher.
|
||||
|
||||
Value type: #gdouble
|
||||
|
||||
See #audiotestsrc:freq
|
||||
|
||||
#### `halignment`
|
||||
|
||||
Horizontal alignment of the text
|
||||
|
||||
Valid values:
|
||||
- **left** (0) – left
|
||||
- **center** (1) – center
|
||||
- **right** (2) – right
|
||||
- **position** (4) – Absolute position clamped to canvas
|
||||
- **absolute** (5) – Absolute position
|
||||
|
||||
See #timeoverlay:halignment
|
||||
|
||||
#### `height`
|
||||
|
||||
height of the source
|
||||
|
||||
Value type: #gint
|
||||
|
||||
#### `mute`
|
||||
|
||||
mute channel
|
||||
|
||||
Value type: #gboolean
|
||||
|
||||
See #volume:mute
|
||||
|
||||
#### `pattern`
|
||||
|
||||
Type of test pattern to generate
|
||||
|
||||
Valid values:
|
||||
- **SMPTE 100% color bars** (0) – smpte
|
||||
- **Random (television snow)** (1) – snow
|
||||
- **100% Black** (2) – black
|
||||
- **100% White** (3) – white
|
||||
- **Red** (4) – red
|
||||
- **Green** (5) – green
|
||||
- **Blue** (6) – blue
|
||||
- **Checkers 1px** (7) – checkers-1
|
||||
- **Checkers 2px** (8) – checkers-2
|
||||
- **Checkers 4px** (9) – checkers-4
|
||||
- **Checkers 8px** (10) – checkers-8
|
||||
- **Circular** (11) – circular
|
||||
- **Blink** (12) – blink
|
||||
- **SMPTE 75% color bars** (13) – smpte75
|
||||
- **Zone plate** (14) – zone-plate
|
||||
- **Gamut checkers** (15) – gamut
|
||||
- **Chroma zone plate** (16) – chroma-zone-plate
|
||||
- **Solid color** (17) – solid-color
|
||||
- **Moving ball** (18) – ball
|
||||
- **SMPTE 100% color bars** (19) – smpte100
|
||||
- **Bar** (20) – bar
|
||||
- **Pinwheel** (21) – pinwheel
|
||||
- **Spokes** (22) – spokes
|
||||
- **Gradient** (23) – gradient
|
||||
- **Colors** (24) – colors
|
||||
|
||||
See #videotestsrc:pattern
|
||||
|
||||
#### `posx`
|
||||
|
||||
x position of the stream
|
||||
|
||||
Value type: #gint
|
||||
|
||||
#### `posy`
|
||||
|
||||
y position of the stream
|
||||
|
||||
Value type: #gint
|
||||
|
||||
#### `text-width`
|
||||
|
||||
Resulting width of font rendering
|
||||
|
||||
Value type: #guint
|
||||
|
||||
See #timeoverlay:text-width
|
||||
|
||||
#### `text-x`
|
||||
|
||||
Resulting X position of font rendering.
|
||||
|
||||
Value type: #gint
|
||||
|
||||
See #timeoverlay:text-x
|
||||
|
||||
#### `text-y`
|
||||
|
||||
Resulting X position of font rendering.
|
||||
|
||||
Value type: #gint
|
||||
|
||||
See #timeoverlay:text-y
|
||||
|
||||
#### `time-mode`
|
||||
|
||||
What time to show
|
||||
|
||||
Valid values:
|
||||
- **buffer-time** (0) – buffer-time
|
||||
- **stream-time** (1) – stream-time
|
||||
- **running-time** (2) – running-time
|
||||
- **time-code** (3) – time-code
|
||||
|
||||
See #timeoverlay:time-mode
|
||||
|
||||
#### `valignment`
|
||||
|
||||
Vertical alignment of the text
|
||||
|
||||
Valid values:
|
||||
- **baseline** (0) – baseline
|
||||
- **bottom** (1) – bottom
|
||||
- **top** (2) – top
|
||||
- **position** (3) – Absolute position clamped to canvas
|
||||
- **center** (4) – center
|
||||
- **absolute** (5) – Absolute position
|
||||
|
||||
See #timeoverlay:valignment
|
||||
|
||||
#### `video-direction`
|
||||
|
||||
Video direction: rotation and flipping
|
||||
|
||||
Valid values:
|
||||
- **GST_VIDEO_ORIENTATION_IDENTITY** (0) – identity
|
||||
- **GST_VIDEO_ORIENTATION_90R** (1) – 90r
|
||||
- **GST_VIDEO_ORIENTATION_180** (2) – 180
|
||||
- **GST_VIDEO_ORIENTATION_90L** (3) – 90l
|
||||
- **GST_VIDEO_ORIENTATION_HORIZ** (4) – horiz
|
||||
- **GST_VIDEO_ORIENTATION_VERT** (5) – vert
|
||||
- **GST_VIDEO_ORIENTATION_UL_LR** (6) – ul-lr
|
||||
- **GST_VIDEO_ORIENTATION_UR_LL** (7) – ur-ll
|
||||
- **GST_VIDEO_ORIENTATION_AUTO** (8) – auto
|
||||
- **GST_VIDEO_ORIENTATION_CUSTOM** (9) – custom
|
||||
|
||||
See #videoflip:video-direction
|
||||
|
||||
#### `volume`
|
||||
|
||||
Volume of test signal
|
||||
|
||||
Value type: #gdouble
|
||||
|
||||
See #audiotestsrc:volume
|
||||
|
||||
#### `volume`
|
||||
|
||||
volume factor, 1.0=100%
|
||||
|
||||
Value type: #gdouble
|
||||
|
||||
See #volume:volume
|
||||
|
||||
#### `width`
|
||||
|
||||
width of the source
|
||||
|
||||
Value type: #gint
|
||||
|
20
docs/libs/document-children-props.py
Executable file → Normal file
20
docs/libs/document-children-props.py
Executable file → Normal file
|
@ -33,24 +33,32 @@ if __name__ == "__main__":
|
|||
layer = tl.append_layer()
|
||||
|
||||
elements = []
|
||||
def add_clip(c, add=True):
|
||||
def add_clip(c, add=True, override_name=None):
|
||||
c.props.duration = Gst.SECOND
|
||||
c.props.start = layer.get_duration()
|
||||
layer.add_clip(c)
|
||||
if add:
|
||||
elements.extend(c.children)
|
||||
else:
|
||||
if override_name:
|
||||
elements.append((c, override_name))
|
||||
else:
|
||||
elements.append(c)
|
||||
|
||||
add_clip(GES.UriClipAsset.request_sync(Gst.filename_to_uri(os.path.join("../../", "tests/check/assets/audio_video.ogg"))).extract())
|
||||
add_clip(GES.TestClip.new())
|
||||
add_clip(GES.TitleClip.new())
|
||||
transition = GES.TransitionClip.new_for_nick("crossfade")
|
||||
add_clip(transition, False)
|
||||
elements.append(transition)
|
||||
|
||||
add_clip(GES.SourceClip.new_time_overlay(), False, "GESTimeOverlaySourceClip")
|
||||
add_clip(GES.TransitionClip.new_for_nick("crossfade"), False)
|
||||
|
||||
for element in elements:
|
||||
gtype = element.__gtype__
|
||||
if isinstance(element, tuple):
|
||||
element, gtype = element
|
||||
else:
|
||||
gtype = element.__gtype__.name
|
||||
print(gtype)
|
||||
with open(gtype.name + '-children-props.md', 'w') as f:
|
||||
with open(gtype + '-children-props.md', 'w') as f:
|
||||
for prop in GES.TimelineElement.list_children_properties(element):
|
||||
prefix = '#### `%s`\n\n' % (prop.name)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ gi-index
|
|||
ges-uri-clip.h
|
||||
ges-title-clip.h
|
||||
ges-test-clip.h
|
||||
ges-time-overlay-clip.h
|
||||
ges-effect-clip.h
|
||||
ges-transition-clip.h
|
||||
ges-pipeline.h
|
||||
|
|
|
@ -504,6 +504,8 @@ ges_video_uri_source_get_natural_size(GESVideoSource* source, gint* width, gint*
|
|||
G_GNUC_INTERNAL gboolean ges_test_clip_asset_get_natural_size (GESAsset *self,
|
||||
gint *width,
|
||||
gint *height);
|
||||
G_GNUC_INTERNAL gchar *ges_test_source_asset_check_id (GType type, const gchar *id,
|
||||
GError **error);
|
||||
|
||||
/************************
|
||||
* Our property masks *
|
||||
|
|
|
@ -53,10 +53,52 @@ enum
|
|||
PROP_0,
|
||||
};
|
||||
|
||||
static GESExtractableInterface *parent_extractable_iface = NULL;
|
||||
|
||||
static gchar *
|
||||
extractable_check_id (GType type, const gchar * id, GError ** error)
|
||||
{
|
||||
if (type == GES_TYPE_SOURCE_CLIP) {
|
||||
g_set_error (error, GES_ERROR, GES_ERROR_ASSET_WRONG_ID,
|
||||
"Only `time-overlay` is supported as an ID for type: `GESSourceClip`,"
|
||||
" got: '%s'", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return parent_extractable_iface->check_id (type, id, error);
|
||||
}
|
||||
|
||||
static GType
|
||||
extractable_get_real_extractable_type (GType wanted_type, const gchar * id)
|
||||
{
|
||||
GstStructure *structure;
|
||||
|
||||
if (!id || (wanted_type != GES_TYPE_SOURCE_CLIP
|
||||
&& wanted_type != GES_TYPE_TEST_CLIP))
|
||||
return wanted_type;
|
||||
|
||||
structure = gst_structure_new_from_string (id);
|
||||
if (!structure)
|
||||
return wanted_type;
|
||||
|
||||
if (gst_structure_has_name (structure, "time-overlay"))
|
||||
/* Just reusing TestClip to create a GESTimeOverlayClip
|
||||
* as it already does the job! */
|
||||
wanted_type = GES_TYPE_TEST_CLIP;
|
||||
|
||||
gst_structure_free (structure);
|
||||
|
||||
return wanted_type;
|
||||
}
|
||||
|
||||
static void
|
||||
extractable_interface_init (GESExtractableInterface * iface)
|
||||
{
|
||||
iface->asset_type = GES_TYPE_SOURCE_CLIP_ASSET;
|
||||
iface->get_real_extractable_type = extractable_get_real_extractable_type;
|
||||
iface->check_id = extractable_check_id;
|
||||
|
||||
parent_extractable_iface = g_type_interface_peek_parent (iface);
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GESSourceClip, ges_source_clip,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* GStreamer Editing Services
|
||||
* Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
|
||||
* 2009 Nokia Corporation
|
||||
* Copyright (C) 2020 Igalia S.L
|
||||
* Author: 2020 Thibault Saunier <tsaunier@igalia.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -28,7 +30,7 @@
|
|||
* ## Asset
|
||||
*
|
||||
* The default asset ID is GESTestClip, but the framerate and video
|
||||
* size can be overriden using an ID of the form:
|
||||
* size can be overridden using an ID of the form:
|
||||
*
|
||||
* ```
|
||||
* framerate=60/1, width=1920, height=1080, max-duration=5.0
|
||||
|
@ -167,15 +169,21 @@ typedef struct
|
|||
GType type;
|
||||
} ValidField;
|
||||
|
||||
static gchar *
|
||||
ges_extractable_check_id (GType type, const gchar * id, GError ** error)
|
||||
gchar *
|
||||
ges_test_source_asset_check_id (GType type, const gchar * id, GError ** error)
|
||||
{
|
||||
if (id && g_strcmp0 (id, g_type_name (type))) {
|
||||
gchar *struct_str = g_strdup_printf ("%s,%s", g_type_name (type), id);
|
||||
gchar *res = NULL;
|
||||
GstStructure *structure = gst_structure_from_string (struct_str, NULL);
|
||||
GstStructure *structure = gst_structure_from_string (id, NULL);
|
||||
|
||||
GST_DEBUG ("Structure is %s %" GST_PTR_FORMAT, struct_str, structure);
|
||||
if (!structure) {
|
||||
gchar *struct_str = g_strdup_printf ("%s,%s", g_type_name (type), id);
|
||||
|
||||
structure = gst_structure_from_string (struct_str, NULL);
|
||||
g_free (struct_str);
|
||||
}
|
||||
|
||||
GST_INFO ("Test source ID: %" GST_PTR_FORMAT, structure);
|
||||
if (!structure) {
|
||||
g_set_error (error, GES_ERROR, GES_ERROR_ASSET_WRONG_ID,
|
||||
"GESTestClipAsset ID should be in the form: `framerate=30/1, "
|
||||
|
@ -186,6 +194,7 @@ ges_extractable_check_id (GType type, const gchar * id, GError ** error)
|
|||
{"height", G_TYPE_INT},
|
||||
{"framerate", G_TYPE_NONE}, /* GST_TYPE_FRACTION is not constant */
|
||||
{"max-duration", GST_TYPE_CLOCK_TIME},
|
||||
{"disable-timecodestamper", G_TYPE_BOOLEAN},
|
||||
};
|
||||
gint i;
|
||||
|
||||
|
@ -209,7 +218,6 @@ ges_extractable_check_id (GType type, const gchar * id, GError ** error)
|
|||
field.name)), g_type_name (type));
|
||||
|
||||
gst_structure_free (structure);
|
||||
g_free (struct_str);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -219,7 +227,6 @@ ges_extractable_check_id (GType type, const gchar * id, GError ** error)
|
|||
gst_structure_free (structure);
|
||||
}
|
||||
|
||||
g_free (struct_str);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -230,7 +237,7 @@ static void
|
|||
ges_extractable_interface_init (GESExtractableInterface * iface)
|
||||
{
|
||||
iface->asset_type = GES_TYPE_TEST_CLIP_ASSET;
|
||||
iface->check_id = ges_extractable_check_id;
|
||||
iface->check_id = ges_test_source_asset_check_id;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GESTestClip, ges_test_clip, GES_TYPE_SOURCE_CLIP,
|
||||
|
@ -517,7 +524,25 @@ ges_test_clip_create_track_element (GESClip * clip, GESTrackType type)
|
|||
ges_track_type_name (type));
|
||||
|
||||
if (type == GES_TRACK_TYPE_VIDEO) {
|
||||
res = (GESTrackElement *) ges_video_test_source_new ();
|
||||
gchar *id = NULL;
|
||||
GESAsset *videoasset;
|
||||
|
||||
if (asset) {
|
||||
GstStructure *structure =
|
||||
gst_structure_from_string (ges_asset_get_id (asset), NULL);
|
||||
|
||||
if (structure) {
|
||||
id = g_strdup (gst_structure_get_name (structure));
|
||||
gst_structure_free (structure);
|
||||
}
|
||||
}
|
||||
/* Our asset ID has been verified and thus this should not fail ever */
|
||||
videoasset = ges_asset_request (GES_TYPE_VIDEO_TEST_SOURCE, id, NULL);
|
||||
g_assert (videoasset);
|
||||
g_free (id);
|
||||
|
||||
res = (GESTrackElement *) ges_asset_extract (videoasset, NULL);
|
||||
gst_object_unref (videoasset);
|
||||
ges_video_test_source_set_pattern (
|
||||
(GESVideoTestSource *) res, priv->vpattern);
|
||||
} else if (type == GES_TRACK_TYPE_AUDIO) {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* GStreamer Editing Services
|
||||
* Copyright (C) 2009 Brandon Lewis <brandon.lewis@collabora.co.uk>
|
||||
* 2009 Nokia Corporation
|
||||
* Copyright (C) 2020 Igalia S.L
|
||||
* Author: 2020 Thibault Saunier <tsaunier@igalia.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
|
53
ges/ges-time-overlay-clip.c
Normal file
53
ges/ges-time-overlay-clip.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* SECTION:gestimeoverlayclip
|
||||
* @title: GESTimeOverlayClip
|
||||
* @short_description: Source with a time overlay on top
|
||||
* @symbols:
|
||||
* - ges_source_clip_new_time_overlay
|
||||
*
|
||||
* A #GESSourceClip that overlays timing information on top.
|
||||
*
|
||||
* ## Asset
|
||||
*
|
||||
* The default asset ID is "time-overlay" (of type #GES_TYPE_SOURCE_CLIP),
|
||||
* but the framerate and video size can be overridden using an ID of the form:
|
||||
*
|
||||
* ```
|
||||
* time-overlay, framerate=60/1, width=1920, height=1080, max-duration=5.0
|
||||
* ```
|
||||
*
|
||||
* ## Children properties
|
||||
*
|
||||
* {{ libs/GESTimeOverlayClip-children-props.md }}
|
||||
*
|
||||
* ## Symbols
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "ges-asset.h"
|
||||
#include "ges-time-overlay-clip.h"
|
||||
|
||||
|
||||
/**
|
||||
* ges_source_clip_new_time_overlay:
|
||||
*
|
||||
* Creates a new #GESSourceClip that renders a time overlay on top
|
||||
*
|
||||
* Returns: (transfer floating) (nullable): The newly created #GESSourceClip,
|
||||
* or %NULL if there was an error.
|
||||
*/
|
||||
GESSourceClip *
|
||||
ges_source_clip_new_time_overlay (void)
|
||||
{
|
||||
GESSourceClip *new_clip;
|
||||
GESAsset *asset = ges_asset_request (GES_TYPE_SOURCE_CLIP,
|
||||
"time-overlay", NULL);
|
||||
|
||||
new_clip = GES_SOURCE_CLIP (ges_asset_extract (asset, NULL));
|
||||
gst_object_unref (asset);
|
||||
|
||||
return new_clip;
|
||||
}
|
30
ges/ges-time-overlay-clip.h
Normal file
30
ges/ges-time-overlay-clip.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* GStreamer Editing Services
|
||||
* Copyright (C) 2020 Igalia S.L
|
||||
* Author: 2020 Thibault Saunier <tsaunier@igalia.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ges-source-clip.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GES_API
|
||||
GESSourceClip* ges_source_clip_new_time_overlay (void);
|
||||
|
||||
G_END_DECLS
|
|
@ -63,6 +63,8 @@ static void
|
|||
ges_extractable_interface_init (GESExtractableInterface * iface)
|
||||
{
|
||||
iface->set_asset = ges_video_source_set_asset;
|
||||
|
||||
parent_extractable_iface = g_type_interface_peek_parent (iface);
|
||||
}
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GESVideoSource, ges_video_source,
|
||||
|
@ -233,16 +235,6 @@ ges_video_source_class_init (GESVideoSourceClass * klass)
|
|||
static void
|
||||
ges_video_source_init (GESVideoSource * self)
|
||||
{
|
||||
if (g_once_init_enter (&parent_extractable_iface)) {
|
||||
GESExtractableInterface *iface, *parent_iface;
|
||||
|
||||
iface =
|
||||
G_TYPE_INSTANCE_GET_INTERFACE (self, GES_TYPE_EXTRACTABLE,
|
||||
GESExtractableInterface);
|
||||
parent_iface = g_type_interface_peek_parent (iface);
|
||||
g_once_init_leave (&parent_extractable_iface, parent_iface);
|
||||
}
|
||||
|
||||
self->priv = ges_video_source_get_instance_private (self);
|
||||
self->priv->positioner = NULL;
|
||||
self->priv->capsfilter = NULL;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* GStreamer Editing Services
|
||||
* Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
|
||||
* 2010 Nokia Corporation
|
||||
* Copyright (C) 2020 Igalia S.L
|
||||
* Author: 2020 Thibault Saunier <tsaunier@igalia.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -38,18 +40,30 @@ struct _GESVideoTestSourcePrivate
|
|||
{
|
||||
GESVideoTestPattern pattern;
|
||||
|
||||
gboolean use_overlay;
|
||||
GstElement *overlay;
|
||||
GstPad *is_passthrough_pad;
|
||||
GstPad *os_passthrough_pad;
|
||||
GstPad *is_overlay_pad;
|
||||
GstPad *os_overlay_pad;
|
||||
|
||||
GstElement *capsfilter;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GESVideoTestSource, ges_video_test_source,
|
||||
GES_TYPE_VIDEO_SOURCE);
|
||||
static void
|
||||
ges_extractable_interface_init (GESExtractableInterface * iface)
|
||||
{
|
||||
iface->check_id = ges_test_source_asset_check_id;
|
||||
iface->asset_type = GES_TYPE_TRACK_ELEMENT_ASSET;
|
||||
}
|
||||
|
||||
static GstStructure *
|
||||
ges_video_test_source_asset_get_config (GESAsset * asset)
|
||||
{
|
||||
const gchar *id = ges_asset_get_id (asset);
|
||||
if (g_strcmp0 (id, g_type_name (ges_asset_get_extractable_type (asset))))
|
||||
return gst_structure_from_string (ges_asset_get_id (asset), NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GESVideoTestSource, ges_video_test_source,
|
||||
GES_TYPE_VIDEO_SOURCE, G_ADD_PRIVATE (GESVideoTestSource)
|
||||
G_IMPLEMENT_INTERFACE (GES_TYPE_EXTRACTABLE,
|
||||
ges_extractable_interface_init));
|
||||
|
||||
static GstElement *ges_video_test_source_create_source (GESTrackElement * self);
|
||||
|
||||
|
@ -74,101 +88,6 @@ get_natural_size (GESVideoSource * source, gint * width, gint * height)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_USE_TIME_OVERLAY,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec *properties[PROP_LAST];
|
||||
|
||||
static void
|
||||
get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_USE_TIME_OVERLAY:
|
||||
g_value_set_boolean (value, self->priv->use_overlay);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_USE_TIME_OVERLAY:
|
||||
{
|
||||
GstElement *os, *is;
|
||||
gboolean used_overlay = self->priv->use_overlay;
|
||||
|
||||
if (!self->priv->overlay) {
|
||||
GST_ERROR_OBJECT (object, "Overlaying is disabled, you are probably"
|
||||
"missing some GStreamer plugin");
|
||||
return;
|
||||
}
|
||||
|
||||
self->priv->use_overlay = g_value_get_boolean (value);
|
||||
if (used_overlay == self->priv->use_overlay)
|
||||
return;
|
||||
|
||||
is = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (self->
|
||||
priv->is_overlay_pad)));
|
||||
|
||||
if (!is)
|
||||
return;
|
||||
|
||||
os = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (self->
|
||||
priv->os_overlay_pad)));
|
||||
if (!os) {
|
||||
gst_object_unref (is);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_set (is, "active-pad",
|
||||
self->priv->use_overlay ? self->priv->is_overlay_pad : self->
|
||||
priv->is_passthrough_pad, NULL);
|
||||
g_object_set (os, "active-pad",
|
||||
self->priv->use_overlay ? self->priv->os_overlay_pad : self->
|
||||
priv->os_passthrough_pad, NULL);
|
||||
|
||||
gst_object_unref (is);
|
||||
gst_object_unref (os);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_set_child_property (GESTimelineElement * self, GObject * child,
|
||||
GParamSpec * pspec, GValue * value)
|
||||
{
|
||||
GstElementFactory *f =
|
||||
GST_IS_ELEMENT (child) ? gst_element_get_factory (GST_ELEMENT (child)) :
|
||||
NULL;
|
||||
|
||||
if (!f || g_strcmp0 (GST_OBJECT_NAME (f), "timeoverlay"))
|
||||
goto done;
|
||||
|
||||
GST_INFO_OBJECT (self, "Activating time overlay as time mode is being set");
|
||||
g_object_set (self, "use-time-overlay", TRUE, NULL);
|
||||
|
||||
done:
|
||||
GES_TIMELINE_ELEMENT_CLASS (ges_video_test_source_parent_class)
|
||||
->set_child_property (self, child, pspec, value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_set_parent (GESTimelineElement * element, GESTimelineElement * parent)
|
||||
{
|
||||
|
@ -231,13 +150,6 @@ _get_natural_framerate (GESTimelineElement * element, gint * fps_n,
|
|||
static void
|
||||
dispose (GObject * object)
|
||||
{
|
||||
GESVideoTestSourcePrivate *priv = GES_VIDEO_TEST_SOURCE (object)->priv;
|
||||
|
||||
gst_clear_object (&priv->is_overlay_pad);
|
||||
gst_clear_object (&priv->is_passthrough_pad);
|
||||
gst_clear_object (&priv->os_overlay_pad);
|
||||
gst_clear_object (&priv->os_passthrough_pad);
|
||||
|
||||
G_OBJECT_CLASS (ges_video_test_source_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@ -250,33 +162,11 @@ ges_video_test_source_class_init (GESVideoTestSourceClass * klass)
|
|||
source_class->create_source = ges_video_test_source_create_source;
|
||||
source_class->ABI.abi.get_natural_size = get_natural_size;
|
||||
|
||||
/**
|
||||
* GESVideoTestSource:use-overlay:
|
||||
*
|
||||
* Whether to overlay the test video source with a clock time.
|
||||
* This property is also registered as a child property for the video
|
||||
* test source, so you can set it like any other child property.
|
||||
*
|
||||
* The properties of the corresponding #timeoverlay are also registered
|
||||
* as children properties. If you set any child property from the underlying
|
||||
* `timeoverlay`, this property will be set to %TRUE by default.
|
||||
*/
|
||||
properties[PROP_USE_TIME_OVERLAY] =
|
||||
g_param_spec_boolean ("use-time-overlay", "Use-time-overlay",
|
||||
"Use time overlay, setting a child property corresponding to"
|
||||
" GstTimeOverlay will switch this on by default.", FALSE,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
object_class->dispose = dispose;
|
||||
|
||||
GES_TIMELINE_ELEMENT_CLASS (klass)->set_child_property = _set_child_property;
|
||||
GES_TIMELINE_ELEMENT_CLASS (klass)->set_parent = _set_parent;
|
||||
GES_TIMELINE_ELEMENT_CLASS (klass)->get_natural_framerate =
|
||||
_get_natural_framerate;
|
||||
|
||||
g_object_class_install_properties (object_class, PROP_LAST, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -287,63 +177,40 @@ ges_video_test_source_init (GESVideoTestSource * self)
|
|||
self->priv->pattern = DEFAULT_VPATTERN;
|
||||
}
|
||||
|
||||
#define CREATE_ELEMENT(var, ename) \
|
||||
if (!(var = gst_element_factory_make(ename, NULL))) { \
|
||||
GST_ERROR_OBJECT(self, "Could not create %s", ename); \
|
||||
goto done; \
|
||||
} \
|
||||
gst_object_ref(var);
|
||||
static GstStructure *
|
||||
ges_video_test_source_get_config (GESVideoTestSource * self)
|
||||
{
|
||||
GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
|
||||
if (asset)
|
||||
return ges_video_test_source_asset_get_config (asset);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
ges_video_test_source_create_overlay (GESVideoTestSource * self)
|
||||
{
|
||||
GstElement *bin = NULL, *os = NULL, *is = NULL, *toverlay = NULL, *tcstamper =
|
||||
NULL;
|
||||
GstPad *tmppad;
|
||||
const gchar *bindesc = NULL;
|
||||
GstStructure *config = ges_video_test_source_get_config (self);
|
||||
|
||||
CREATE_ELEMENT (os, "output-selector");
|
||||
gst_util_set_object_arg (G_OBJECT (os), "pad-negotiation-mode", "active");
|
||||
CREATE_ELEMENT (is, "input-selector");
|
||||
CREATE_ELEMENT (tcstamper, "timecodestamper");
|
||||
CREATE_ELEMENT (toverlay, "timeoverlay");
|
||||
if (!config)
|
||||
return NULL;
|
||||
|
||||
bin = gst_bin_new (NULL);
|
||||
if (gst_structure_has_name (config, "time-overlay")) {
|
||||
gboolean disable_timecodestamper;
|
||||
|
||||
gst_bin_add_many (GST_BIN (bin), os, is, tcstamper, toverlay, NULL);
|
||||
self->priv->os_passthrough_pad = gst_element_get_request_pad (os, "src_%u");
|
||||
self->priv->is_passthrough_pad = gst_element_get_request_pad (is, "sink_%u");
|
||||
if (gst_structure_get_boolean (config, "disable-timecodestamper",
|
||||
&disable_timecodestamper))
|
||||
bindesc = "timeoverlay";
|
||||
else
|
||||
bindesc = "timecodestamper ! timeoverlay";
|
||||
}
|
||||
gst_structure_free (config);
|
||||
|
||||
gst_pad_link_full (self->priv->os_passthrough_pad,
|
||||
self->priv->is_passthrough_pad, GST_PAD_LINK_CHECK_NOTHING);
|
||||
gst_element_link (tcstamper, toverlay);
|
||||
if (!bindesc)
|
||||
return NULL;
|
||||
|
||||
self->priv->os_overlay_pad = gst_element_get_request_pad (os, "src_%u");
|
||||
tmppad = gst_element_get_static_pad (tcstamper, "sink");
|
||||
gst_pad_link_full (self->priv->os_overlay_pad, tmppad,
|
||||
GST_PAD_LINK_CHECK_NOTHING);
|
||||
gst_object_unref (tmppad);
|
||||
|
||||
tmppad = gst_element_get_static_pad (toverlay, "src");
|
||||
self->priv->is_overlay_pad = gst_element_get_request_pad (is, "sink_%u");
|
||||
gst_pad_link_full (tmppad, self->priv->is_overlay_pad,
|
||||
GST_PAD_LINK_CHECK_NOTHING);
|
||||
gst_object_unref (tmppad);
|
||||
|
||||
tmppad = gst_element_get_static_pad (os, "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", tmppad));
|
||||
gst_object_unref (tmppad);
|
||||
|
||||
tmppad = gst_element_get_static_pad (is, "src");
|
||||
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", tmppad));
|
||||
gst_object_unref (tmppad);
|
||||
|
||||
done:
|
||||
gst_clear_object (&os);
|
||||
gst_clear_object (&is);
|
||||
gst_clear_object (&tcstamper);
|
||||
gst_clear_object (&toverlay);
|
||||
|
||||
return bin;
|
||||
return gst_parse_bin_from_description (bindesc, TRUE, NULL);
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
|
@ -352,6 +219,7 @@ ges_video_test_source_create_source (GESTrackElement * element)
|
|||
GstCaps *caps;
|
||||
gint pattern;
|
||||
GstElement *testsrc, *res;
|
||||
GstElement *overlay;
|
||||
const gchar *props[] =
|
||||
{ "pattern", "background-color", "foreground-color", NULL };
|
||||
GPtrArray *elements;
|
||||
|
@ -374,18 +242,16 @@ ges_video_test_source_create_source (GESTrackElement * element)
|
|||
g_object_set (self->priv->capsfilter, "caps", caps, NULL);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
self->priv->overlay = ges_video_test_source_create_overlay (self);
|
||||
if (self->priv->overlay) {
|
||||
overlay = ges_video_test_source_create_overlay (self);
|
||||
if (overlay) {
|
||||
const gchar *overlay_props[] =
|
||||
{ "time-mode", "text-y", "text-x", "text-width", "test-height",
|
||||
"halignment", "valignment", "font-desc", NULL
|
||||
};
|
||||
|
||||
ges_track_element_add_children_props (element, self->priv->overlay, NULL,
|
||||
ges_track_element_add_children_props (element, overlay, NULL,
|
||||
NULL, overlay_props);
|
||||
ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT (self),
|
||||
properties[PROP_USE_TIME_OVERLAY], G_OBJECT (self));
|
||||
g_ptr_array_add (elements, self->priv->overlay);
|
||||
g_ptr_array_add (elements, overlay);
|
||||
}
|
||||
|
||||
ges_track_element_add_children_props (element, testsrc, NULL, NULL, props);
|
||||
|
@ -440,7 +306,8 @@ ges_video_test_source_get_pattern (GESVideoTestSource * source)
|
|||
return g_value_get_enum (&val);
|
||||
}
|
||||
|
||||
/* ges_video_test_source_new:
|
||||
/**
|
||||
* ges_video_test_source_new:
|
||||
*
|
||||
* Creates a new #GESVideoTestSource.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* GStreamer Editing Services
|
||||
* Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
|
||||
* 2010 Nokia Corporation
|
||||
* Copyright (C) 2020 Igalia S.L
|
||||
* Author: 2020 Thibault Saunier <tsaunier@igalia.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <ges/ges-clip.h>
|
||||
#include <ges/ges-pipeline.h>
|
||||
#include <ges/ges-source-clip.h>
|
||||
#include <ges/ges-time-overlay-clip.h>
|
||||
#include <ges/ges-test-clip.h>
|
||||
#include <ges/ges-title-clip.h>
|
||||
#include <ges/ges-operation-clip.h>
|
||||
|
|
|
@ -14,6 +14,7 @@ ges_sources = files([
|
|||
'ges-operation-clip.c',
|
||||
'ges-base-transition-clip.c',
|
||||
'ges-transition-clip.c',
|
||||
'ges-time-overlay-clip.c',
|
||||
'ges-test-clip.c',
|
||||
'ges-title-clip.c',
|
||||
'ges-overlay-clip.c',
|
||||
|
@ -86,6 +87,7 @@ ges_headers = files([
|
|||
'ges-base-transition-clip.h',
|
||||
'ges-transition-clip.h',
|
||||
'ges-test-clip.h',
|
||||
'ges-time-overlay-clip.h',
|
||||
'ges-title-clip.h',
|
||||
'ges-overlay-clip.h',
|
||||
'ges-text-overlay-clip.h',
|
||||
|
|
|
@ -3999,7 +3999,7 @@ GST_START_TEST (test_copy_paste_children_properties)
|
|||
|
||||
timeline = ges_timeline_new_audio_video ();
|
||||
layer = ges_timeline_append_layer (timeline);
|
||||
clip = GES_TIMELINE_ELEMENT (ges_test_clip_new ());
|
||||
clip = GES_TIMELINE_ELEMENT (ges_source_clip_new_time_overlay ());
|
||||
assert_set_duration (clip, 50);
|
||||
|
||||
fail_unless (ges_layer_add_clip (layer, GES_CLIP (clip)));
|
||||
|
|
|
@ -5,7 +5,7 @@ description, handles-states=true,
|
|||
"--videosink=fakesink"\
|
||||
}
|
||||
|
||||
add-clip, name=clip, asset-id="framerate=120/1", layer-priority=0, type=GESTestClip, pattern=blue, duration=f240, inpoint=f100
|
||||
add-clip, name=clip, asset-id="time-overlay,framerate=120/1", layer-priority=0, type=GESSourceClip, pattern=blue, duration=f240, inpoint=f100
|
||||
set-child-properties, element-name=clip, time-mode=time-code
|
||||
pause
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@ meta,
|
|||
"$(validateflow), pad=videosink:sink, record-buffers=true, ignored-fields=\"stream-start={stream-id,group-id,stream}\"",
|
||||
}
|
||||
|
||||
add-clip, name=c0, asset-id=GESTestClip, layer-priority=0, type=GESTestClip, start=0, duration=1.0
|
||||
set-child-properties, element-name=c0, pattern=blue, time-mode=time-code, valignment=center, halignment=center
|
||||
add-clip, name=c0, asset-id=time-overlay, layer-priority=0, type=GESSourceClip, start=0, duration=1.0
|
||||
set-child-properties, element-name=c0, pattern=blue, valignment=center, halignment=center, time-mode=time-code
|
||||
|
||||
add-clip, name=c1, asset-id=GESTestClip, layer-priority=0, type=GESTestClip, start=1.0, duration=1.0
|
||||
set-child-properties, element-name=c1, pattern=red, time-mode=time-code, valignment=center, halignment=center
|
||||
add-clip, name=c1, asset-id=time-overlay, layer-priority=0, type=GESSourceClip, start=1.0, duration=1.0
|
||||
set-child-properties, element-name=c1, pattern=red, valignment=center, halignment=center, time-mode=time-code
|
||||
commit;
|
||||
play
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@ meta,
|
|||
"$(validateflow), pad=videosink:sink, record-buffers=true, ignored-fields=\"stream-start={stream-id,group-id,stream}\"",
|
||||
}
|
||||
|
||||
add-clip, name=c0, asset-id=GESTestClip, layer-priority=0, type=GESTestClip, start=0, duration=1.0
|
||||
set-child-properties, element-name=c0, pattern=blue, time-mode=time-code, valignment=center, halignment=center
|
||||
add-clip, name=c0, asset-id=time-overlay, layer-priority=0, type=GESSourceClip, start=0, duration=1.0
|
||||
set-child-properties, element-name=c0, pattern=blue, valignment=center, halignment=center, time-mode=time-code
|
||||
|
||||
add-clip, name=c1, asset-id=GESTestClip, layer-priority=0, type=GESTestClip, start=1.0, duration=1.0
|
||||
set-child-properties, element-name=c1, pattern=red, time-mode=time-code, valignment=center, halignment=center
|
||||
add-clip, name=c1, asset-id=time-overlay, layer-priority=0, type=GESSourceClip, start=1.0, duration=1.0
|
||||
set-child-properties, element-name=c1, pattern=red, valignment=center, halignment=center, time-mode=time-code
|
||||
commit;
|
||||
play
|
||||
|
||||
|
|
|
@ -11,11 +11,11 @@ meta,
|
|||
"$(validateflow), pad=audiosink:sink, record-buffers=true, ignored-fields=\"stream-start={stream-id,group-id,stream}, segment={position,}\"",
|
||||
}
|
||||
|
||||
add-clip, name=c0, asset-id=GESTestClip, layer-priority=0, type=GESTestClip, start=0, duration=1.0
|
||||
set-child-properties, element-name=c0, pattern=blue, time-mode=time-code, valignment=center, halignment=center
|
||||
add-clip, name=c0, asset-id=time-overlay, layer-priority=0, type=GESSourceClip, start=0, duration=1.0
|
||||
set-child-properties, element-name=c0, pattern=blue, valignment=center, halignment=center, time-mode=time-code
|
||||
|
||||
add-clip, name=c1, asset-id=GESTestClip, layer-priority=0, type=GESTestClip, start=1.0, duration=1.0
|
||||
set-child-properties, element-name=c1, pattern=red, time-mode=time-code, valignment=center, halignment=center
|
||||
add-clip, name=c1, asset-id=time-overlay, layer-priority=0, type=GESSourceClip, start=1.0, duration=1.0
|
||||
set-child-properties, element-name=c1, pattern=red, valignment=center, halignment=center, time-mode=time-code
|
||||
pause
|
||||
|
||||
seek, start=0.0, stop=0.5, flags=accurate+flush
|
||||
|
|
Loading…
Reference in a new issue