mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-09 00:45:56 +00:00
GESTimelinePipeline: beginning of render support
This commit is contained in:
parent
dd9d3e420c
commit
2d430098f8
3 changed files with 178 additions and 22 deletions
|
@ -167,11 +167,14 @@ ges_timeline_object_get_type
|
|||
<SECTION>
|
||||
<FILE>ges-timeline-pipeline</FILE>
|
||||
<TITLE>GESTimelinePipeline</TITLE>
|
||||
GESPipelineFlags
|
||||
ges_timeline_pipeline_new
|
||||
ges_timeline_pipeline_add_timeline
|
||||
ges_timeline_pipeline_set_mode
|
||||
ges_timeline_pipeline_set_render_settings
|
||||
<SUBSECTION Standard>
|
||||
GESTimelinePipeline
|
||||
GESTimelinePipelineClass
|
||||
ges_timeline_pipeline_add_timeline
|
||||
ges_timeline_pipeline_new
|
||||
<SUBSECTION Standard>
|
||||
ges_timeline_pipeline_get_type
|
||||
GES_TIMELINE_PIPELINE
|
||||
GES_TIMELINE_PIPELINE_CLASS
|
||||
|
|
|
@ -30,14 +30,17 @@
|
|||
#include "ges-internal.h"
|
||||
#include "ges-timeline-pipeline.h"
|
||||
|
||||
#define DEFAULT_TIMELINE_MODE TIMELINE_MODE_PREVIEW
|
||||
|
||||
/* Structure corresponding to a timeline - sink link */
|
||||
/* TODO : Don't forget we want to render also :) */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GESTimelinePipeline *pipeline;
|
||||
GstElement *queue;
|
||||
GstPad *srcpad;
|
||||
GstPad *sinkpad;
|
||||
GstPad *playsinkpad;
|
||||
GstPad *encodebinpad;
|
||||
} OutputChain;
|
||||
|
||||
G_DEFINE_TYPE (GESTimelinePipeline, ges_timeline_pipeline, GST_TYPE_PIPELINE);
|
||||
|
@ -75,10 +78,10 @@ ges_timeline_pipeline_finalize (GObject * object)
|
|||
{
|
||||
GESTimelinePipeline *self = GES_TIMELINE_PIPELINE (object);
|
||||
|
||||
if (self->sink) {
|
||||
gst_bin_remove (GST_BIN (object), self->sink);
|
||||
gst_object_unref (self->sink);
|
||||
self->sink = NULL;
|
||||
if (self->playsink) {
|
||||
gst_bin_remove (GST_BIN (object), self->playsink);
|
||||
gst_object_unref (self->playsink);
|
||||
self->playsink = NULL;
|
||||
}
|
||||
G_OBJECT_CLASS (ges_timeline_pipeline_parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -106,17 +109,16 @@ ges_timeline_pipeline_init (GESTimelinePipeline * self)
|
|||
{
|
||||
GST_INFO_OBJECT (self, "Creating new 'playsink'");
|
||||
|
||||
self->sink = gst_element_factory_make ("playsink", "internal-sinks");
|
||||
self->playsink = gst_element_factory_make ("playsink", "internal-sinks");
|
||||
self->encodebin =
|
||||
gst_element_factory_make ("encodebin", "internal-encodebin");
|
||||
|
||||
if (G_UNLIKELY (self->sink == NULL))
|
||||
if (G_UNLIKELY (self->playsink == NULL))
|
||||
GST_ERROR_OBJECT (self, "Can't create playsink instance !");
|
||||
else {
|
||||
GST_INFO_OBJECT (self, "Adding playsink to self");
|
||||
if (G_UNLIKELY (self->encodebin == NULL))
|
||||
GST_ERROR_OBJECT (self, "Can't create encodebin instance !");
|
||||
|
||||
if (G_UNLIKELY (!gst_bin_add (GST_BIN (self), self->sink))) {
|
||||
GST_ERROR_OBJECT (self, "Can't add playsink to ourselves !");
|
||||
}
|
||||
}
|
||||
ges_timeline_pipeline_set_mode (self, DEFAULT_TIMELINE_MODE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,6 +176,8 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
|
|||
|
||||
GST_DEBUG_OBJECT (self, "new pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
/* FIXME : Adapt for usage of render sink */
|
||||
|
||||
if (G_UNLIKELY (!(track =
|
||||
ges_timeline_get_track_for_pad (self->timeline, pad)))) {
|
||||
GST_WARNING_OBJECT (self, "Couldn't find coresponding track !");
|
||||
|
@ -198,7 +202,7 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
|
|||
|
||||
/* Request a sinkpad from playsink */
|
||||
if (G_UNLIKELY (!(sinkpad =
|
||||
gst_element_get_request_pad (self->sink, sinkpad_name)))) {
|
||||
gst_element_get_request_pad (self->playsink, sinkpad_name)))) {
|
||||
GST_WARNING_OBJECT (self, "Couldn't get a pad from the playsink !");
|
||||
return;
|
||||
}
|
||||
|
@ -212,14 +216,14 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
|
|||
GST_DEBUG ("Reconfiguring playsink");
|
||||
|
||||
/* reconfigure playsink */
|
||||
g_signal_emit_by_name (self->sink, "reconfigure", &reconfigured);
|
||||
g_signal_emit_by_name (self->playsink, "reconfigure", &reconfigured);
|
||||
GST_DEBUG ("'reconfigure' returned %d", reconfigured);
|
||||
|
||||
/* Create a new chain */
|
||||
chain = g_new0 (OutputChain, 1);
|
||||
chain->pipeline = self;
|
||||
chain->srcpad = pad;
|
||||
chain->sinkpad = sinkpad;
|
||||
chain->playsinkpad = sinkpad;
|
||||
|
||||
self->chains = g_list_append (self->chains, chain);
|
||||
|
||||
|
@ -229,7 +233,9 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
|
|||
static void
|
||||
pad_removed_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
|
||||
{
|
||||
GST_DEBUG ("pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
GST_DEBUG_OBJECT (self, "pad removed %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
/* FIXME : IMPLEMENT ! */
|
||||
|
||||
GST_DEBUG ("done");
|
||||
}
|
||||
|
@ -267,3 +273,122 @@ ges_timeline_pipeline_add_timeline (GESTimelinePipeline * pipeline,
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_pipeline_set_render_settings:
|
||||
* @pipeline: a #GESTimelinePipeline
|
||||
* @output_uri: the %URI to which the timeline will be rendered
|
||||
* @profile: the #GstEncodingProfile to use to render the timeline
|
||||
*
|
||||
* Specify where the pipeline shall be rendered and with what settings.
|
||||
*
|
||||
* Returns: %TRUE if the settings were aknowledged properly, else %FALSE
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_pipeline_set_render_settings (GESTimelinePipeline * pipeline,
|
||||
gchar * output_uri, GstEncodingProfile * profile)
|
||||
{
|
||||
/* Clear previous URI sink if it existed */
|
||||
/* FIXME : We should figure out if it was added to the pipeline,
|
||||
* and if so, remove it. */
|
||||
if (pipeline->urisink) {
|
||||
g_object_unref (pipeline->urisink);
|
||||
pipeline->urisink = NULL;
|
||||
}
|
||||
|
||||
pipeline->urisink =
|
||||
gst_element_make_from_uri (GST_URI_SINK, output_uri, "urisink");
|
||||
if (G_UNLIKELY (pipeline->urisink == NULL)) {
|
||||
GST_ERROR_OBJECT (pipeline, "Couldn't not create sink for URI %s",
|
||||
output_uri);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_object_set (pipeline->encodebin, "profile", profile, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_pipeline_set_mode:
|
||||
* @pipeline: a #GESTimelinePipeline
|
||||
* @mode: the #GESPipelineFlags to use
|
||||
*
|
||||
* switches the @pipeline to the specified @mode. The default mode when
|
||||
* creating a #GESTimelinePipeline is #TIMELINE_MODE_PREVIEW.
|
||||
*
|
||||
* Note: The @pipeline will be set to #GST_STATE_NULL during this call due to
|
||||
* the internal changes that happen. The caller will therefore have to
|
||||
* set the @pipeline to the requested state after calling this method.
|
||||
**/
|
||||
gboolean
|
||||
ges_timeline_pipeline_set_mode (GESTimelinePipeline * pipeline,
|
||||
GESPipelineFlags mode)
|
||||
{
|
||||
GST_DEBUG_OBJECT (pipeline, "current mode : %d, mode : %d", pipeline->mode,
|
||||
mode);
|
||||
|
||||
/* fast-path, nothing to change */
|
||||
if (mode == pipeline->mode)
|
||||
return TRUE;
|
||||
|
||||
/* FIXME: It would be nice if we are only (de)activating preview
|
||||
* modes to not set the whole pipeline to NULL, but instead just
|
||||
* do the proper (un)linking to playsink. */
|
||||
|
||||
/* Switch pipeline to NULL since we're changing the configuration */
|
||||
gst_element_set_state (GST_ELEMENT_CAST (pipeline), GST_STATE_NULL);
|
||||
|
||||
/* remove no-longer needed components */
|
||||
if (pipeline->mode & TIMELINE_MODE_PREVIEW && !(mode & TIMELINE_MODE_PREVIEW)) {
|
||||
/* Disable playsink */
|
||||
GST_DEBUG ("Disabling playsink");
|
||||
g_object_ref (pipeline->playsink);
|
||||
gst_bin_remove (GST_BIN_CAST (pipeline), pipeline->playsink);
|
||||
}
|
||||
if ((pipeline->mode & TIMELINE_MODE_RENDER) && !(mode & TIMELINE_MODE_RENDER)) {
|
||||
/* Disable render bin */
|
||||
GST_DEBUG ("Disabling rendering bin");
|
||||
g_object_ref (pipeline->encodebin);
|
||||
g_object_ref (pipeline->urisink);
|
||||
gst_bin_remove_many (GST_BIN_CAST (pipeline),
|
||||
pipeline->encodebin, pipeline->urisink, NULL);
|
||||
}
|
||||
|
||||
/* Add new elements */
|
||||
if (!(pipeline->mode & TIMELINE_MODE_PREVIEW) &&
|
||||
(mode & TIMELINE_MODE_PREVIEW)) {
|
||||
/* Add playsink */
|
||||
GST_DEBUG ("Adding playsink");
|
||||
|
||||
if (!gst_bin_add (GST_BIN_CAST (pipeline), pipeline->playsink)) {
|
||||
GST_ERROR_OBJECT (pipeline, "Couldn't add playsink");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (!(pipeline->mode & TIMELINE_MODE_RENDER) && (mode & TIMELINE_MODE_RENDER)) {
|
||||
/* Adding render bin */
|
||||
GST_DEBUG ("Adding render bin");
|
||||
|
||||
if (G_UNLIKELY (pipeline->urisink == NULL)) {
|
||||
GST_ERROR_OBJECT (pipeline, "Output URI not set !");
|
||||
return FALSE;
|
||||
}
|
||||
if (!gst_bin_add (GST_BIN_CAST (pipeline), pipeline->encodebin)) {
|
||||
GST_ERROR_OBJECT (pipeline, "Couldn't add encodebin");
|
||||
return FALSE;
|
||||
}
|
||||
if (!gst_bin_add (GST_BIN_CAST (pipeline), pipeline->urisink)) {
|
||||
GST_ERROR_OBJECT (pipeline, "Couldn't add URI sink");
|
||||
return FALSE;
|
||||
}
|
||||
gst_element_link (pipeline->encodebin, pipeline->urisink);
|
||||
}
|
||||
|
||||
/* FIXUPS */
|
||||
/* FIXME
|
||||
* If we are rendering, set playsink to sync=False,
|
||||
* If we are NOT rendering, set playsink to sync=TRUE */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <glib-object.h>
|
||||
#include <ges/ges.h>
|
||||
#include <gst/profile/gstprofile.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -43,12 +44,33 @@ G_BEGIN_DECLS
|
|||
#define GES_TIMELINE_PIPELINE_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), GES_TYPE_TIMELINE_PIPELINE, GESTimelinePipelineClass))
|
||||
|
||||
/**
|
||||
* GESPipelineFlags:
|
||||
* @TIMELINE_MODE_PREVIEW_AUDIO: output audio to the soundcard
|
||||
* @TIMELINE_MODE_PREVIEW_VIDEO: output video to the screen
|
||||
* @TIMELINE_MODE_PREVIEW: output audio/video to soundcard/screen (default)
|
||||
* @TIMELINE_MODE_RENDER: render timeline
|
||||
*
|
||||
* The various modes the #GESTimelinePipeline can be configured to.
|
||||
*/
|
||||
typedef enum {
|
||||
TIMELINE_MODE_PREVIEW_AUDIO = 1 << 0,
|
||||
TIMELINE_MODE_PREVIEW_VIDEO = 1 << 1,
|
||||
TIMELINE_MODE_PREVIEW = TIMELINE_MODE_PREVIEW_AUDIO | TIMELINE_MODE_PREVIEW_VIDEO,
|
||||
TIMELINE_MODE_RENDER = 1 << 2
|
||||
} GESPipelineFlags;
|
||||
|
||||
struct _GESTimelinePipeline {
|
||||
GstPipeline parent;
|
||||
|
||||
/* <private> */
|
||||
GESTimeline * timeline;
|
||||
GstElement * sink;
|
||||
GstElement * playsink;
|
||||
GstElement * encodebin;
|
||||
/* Note : urisink is only created when a URI has been provided */
|
||||
GstElement * urisink;
|
||||
|
||||
GESPipelineFlags mode;
|
||||
|
||||
GList *chains;
|
||||
};
|
||||
|
@ -64,6 +86,12 @@ GESTimelinePipeline* ges_timeline_pipeline_new (void);
|
|||
gboolean ges_timeline_pipeline_add_timeline (GESTimelinePipeline * pipeline,
|
||||
GESTimeline * timeline);
|
||||
|
||||
gboolean ges_timeline_pipeline_set_render_settings (GESTimelinePipeline *pipeline,
|
||||
gchar * output_uri,
|
||||
GstEncodingProfile *profile);
|
||||
gboolean ges_timeline_pipeline_set_mode (GESTimelinePipeline *pipeline,
|
||||
GESPipelineFlags mode);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _GES_TIMELINE_PIPELINE */
|
||||
|
|
Loading…
Reference in a new issue