Using gst_parse_launch now instead of manual pipeline.

This commit is contained in:
Armin Novak 2014-05-25 10:08:50 +02:00
parent 2610f7ff50
commit bbd63b6024
2 changed files with 38 additions and 240 deletions

View File

@ -45,7 +45,6 @@
static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder); static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder);
static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder); static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder);
static void tsmf_gstreamer_clean_up_pad(TSMFGstreamerDecoder *mdecoder);
static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder,
GstState desired_state); GstState desired_state);
@ -105,6 +104,7 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d
{ {
GstStateChangeReturn state_change; GstStateChangeReturn state_change;
const char *name; const char *name;
const char *sname = get_type(mdecoder);
if (!mdecoder) if (!mdecoder)
return 0; return 0;
@ -116,14 +116,14 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d
return 0; /* Redundant request - Nothing to do */ return 0; /* Redundant request - Nothing to do */
name = gst_element_state_get_name(desired_state); /* For debug */ name = gst_element_state_get_name(desired_state); /* For debug */
DEBUG_TSMF("%s to %s", get_type(mdecoder), name); DEBUG_TSMF("%s to %s", sname, name);
state_change = gst_element_set_state(mdecoder->pipe, desired_state); state_change = gst_element_set_state(mdecoder->pipe, desired_state);
if (state_change == GST_STATE_CHANGE_FAILURE) if (state_change == GST_STATE_CHANGE_FAILURE)
DEBUG_WARN("(%s) GST_STATE_CHANGE_FAILURE.", name); DEBUG_WARN("%s: (%s) GST_STATE_CHANGE_FAILURE.", sname, name);
else if (state_change == GST_STATE_CHANGE_ASYNC) else if (state_change == GST_STATE_CHANGE_ASYNC)
{ {
DEBUG_WARN("(%s) GST_STATE_CHANGE_ASYNC.", name); DEBUG_WARN("%s: (%s) GST_STATE_CHANGE_ASYNC.", sname, name);
mdecoder->state = desired_state; mdecoder->state = desired_state;
} }
else else
@ -399,18 +399,6 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m
return TRUE; return TRUE;
} }
void tsmf_gstreamer_clean_up_pad(TSMFGstreamerDecoder *mdecoder)
{
if (!mdecoder || !mdecoder->pipe)
return;
mdecoder->outconv = NULL;
mdecoder->outrate = NULL;
mdecoder->outresample = NULL;
mdecoder->outsink = NULL;
mdecoder->volume = NULL;
}
void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder) void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder)
{ {
//Cleaning up elements //Cleaning up elements
@ -423,186 +411,28 @@ void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder)
gst_object_unref(mdecoder->pipe); gst_object_unref(mdecoder->pipe);
} }
tsmf_gstreamer_clean_up_pad(mdecoder);
tsmf_window_destroy(mdecoder); tsmf_window_destroy(mdecoder);
mdecoder->ready = FALSE; mdecoder->ready = FALSE;
mdecoder->pipe = NULL; mdecoder->pipe = NULL;
mdecoder->src = NULL; mdecoder->src = NULL;
mdecoder->queue = NULL;
mdecoder->decbin = NULL;
mdecoder->outbin = NULL;
}
static void
cb_newpad(GstElement *decodebin,
GstPad *pad,
gpointer data)
{
GstPad *outpad;
TSMFGstreamerDecoder *mdecoder = data;
/* only link once */
outpad = gst_element_get_static_pad(mdecoder->outbin, "sink");
if (GST_PAD_IS_LINKED(outpad))
{
DEBUG_WARN("sink already linded!");
gst_object_unref(outpad);
return;
}
/* link'n'play */
gst_pad_link(pad, outpad);
gst_object_unref(outpad);
}
static void
cb_freepad(GstElement *decodebin,
GstPad *pad,
gpointer data)
{
GstPad *outpad;
TSMFGstreamerDecoder *mdecoder = data;
outpad = gst_element_get_static_pad(mdecoder->outbin, "sink");
if (!outpad)
{
DEBUG_WARN("sink pad does not exist!");
return;
}
if (!GST_PAD_IS_LINKED(outpad))
{
DEBUG_WARN("sink not linded!");
gst_object_unref(outpad);
return;
}
/* link'n'play */
gst_pad_unlink(pad, outpad);
gst_object_unref(outpad);
}
void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder *mdecoder)
{
if (mdecoder->outbin)
{
gst_element_remove_pad(mdecoder->outbin, mdecoder->ghost_pad);
gst_object_unref(mdecoder->ghost_pad);
mdecoder->ghost_pad = NULL;
}
}
BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder)
{
GstPad *out_pad;
gboolean linkResult = FALSE;
switch (mdecoder->media_type)
{
case TSMF_MAJOR_TYPE_VIDEO:
{
#if GST_VERSION_MAJOR > 0
mdecoder->outconv = gst_element_factory_make("videoconvert", "videoconvert");
#else
mdecoder->outconv = gst_element_factory_make("ffmpegcolorspace", "videoconvert");
#endif
mdecoder->outrate = gst_element_factory_make("videorate", "videorate");
mdecoder->outsink = gst_element_factory_make(tsmf_platform_get_video_sink(), "videosink");
mdecoder->outresample = gst_element_factory_make("videoscale", "videoscale");
mdecoder->volume = NULL;
DEBUG_TSMF("building Video Pipe");
break;
}
case TSMF_MAJOR_TYPE_AUDIO:
{
mdecoder->outconv = gst_element_factory_make("audioconvert", "audioconvert");
mdecoder->outrate = gst_element_factory_make("audiorate", "audiorate");
mdecoder->outresample = gst_element_factory_make("audioresample", "audioresample");
mdecoder->volume = gst_element_factory_make("volume", "audiovolume");
mdecoder->outsink = gst_element_factory_make(tsmf_platform_get_audio_sink(), "audiosink");
DEBUG_TSMF("building Audio Pipe");
break;
}
default:
DEBUG_WARN("Invalid media type %08X", mdecoder->media_type);
tsmf_gstreamer_clean_up_pad(mdecoder);
return FALSE;
}
/* Add audio / video specific elements to pipe */
if (mdecoder->outconv)
gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outconv);
if (mdecoder->outrate)
gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outrate);
if (mdecoder->outresample)
gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outresample);
if (mdecoder->volume)
gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->volume);
if (mdecoder->outsink)
gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outsink);
if (!mdecoder->outconv || !mdecoder->outrate || ! mdecoder->outsink || !mdecoder->outresample)
{
DEBUG_WARN("Failed to load (some) output pipe elements");
DEBUG_WARN("converter=%p, rate=%p, sink=%p, resample=%p",
mdecoder->outconv, mdecoder->outrate, mdecoder->outsink, mdecoder->outresample);
tsmf_gstreamer_clean_up_pad(mdecoder);
return FALSE;
}
if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO)
{
if (!mdecoder->volume)
{
DEBUG_WARN("Failed to load (some) audio output pipe elements");
DEBUG_WARN("volume=%p", mdecoder->volume);
tsmf_gstreamer_clean_up_pad(mdecoder);
return FALSE;
}
}
out_pad = gst_element_get_static_pad(mdecoder->outconv, "sink");
if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO)
{
g_object_set(mdecoder->volume, "mute", mdecoder->gstMuted, NULL);
g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL);
linkResult = gst_element_link_many(mdecoder->outconv, mdecoder->outresample,
mdecoder->volume, mdecoder->outsink, NULL);
}
else
{
linkResult = gst_element_link_many(mdecoder->outconv,
mdecoder->outresample, mdecoder->outsink, NULL);
}
if (!linkResult)
{
DEBUG_WARN("Failed to link these elements: converter->sink");
tsmf_gstreamer_clean_up_pad(mdecoder);
return FALSE;
}
mdecoder->ghost_pad = gst_ghost_pad_new("sink", out_pad);
gst_element_add_pad(mdecoder->outbin, mdecoder->ghost_pad);
gst_object_unref(out_pad);
return TRUE;
} }
BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder)
{ {
gboolean linkResult; const char *appsrc = "appsrc name=source ! decodebin name=decoder !";
const char *video = "autovideoconvert ! videorate ! videoscale !";
const char *audio = "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !";
char pipeline[1024];
if (!mdecoder) if (!mdecoder)
return FALSE; return FALSE;
mdecoder->pipe = gst_pipeline_new("pipeline"); if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
snprintf(pipeline, sizeof(pipeline), "%s %s %s name=outsink", appsrc, video, tsmf_platform_get_video_sink());
else
snprintf(pipeline, sizeof(pipeline), "%s %s %s name=outsink", appsrc, audio, tsmf_platform_get_audio_sink());
DEBUG_WARN("pipeline=%s", pipeline);
mdecoder->pipe = gst_parse_launch(pipeline, NULL);
if (!mdecoder->pipe) if (!mdecoder->pipe)
{ {
@ -610,37 +440,32 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder)
return FALSE; return FALSE;
} }
tsmf_platform_register_handler(mdecoder); mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "source");
mdecoder->src = gst_element_factory_make("appsrc", "source"); if (!mdecoder->src)
mdecoder->queue = gst_element_factory_make("queue2", "queue");
mdecoder->decbin = gst_element_factory_make("decodebin", "decoder");
mdecoder->outbin = gst_bin_new("outbin");
/* Add all elements to the bin allowing proper resource cleanup,
* if any step failed. */
if (mdecoder->src)
gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->src);
if (mdecoder->queue)
gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->queue);
if (mdecoder->decbin)
gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->decbin);
if (mdecoder->outbin)
gst_bin_add(GST_BIN(mdecoder->pipe), mdecoder->outbin);
/* Check, if everything was loaded correctly. */
if (!mdecoder->src || !mdecoder->queue || !mdecoder->decbin ||
!mdecoder->outbin)
{ {
DEBUG_WARN("Failed to load (some) pipeline stage"); DEBUG_WARN("Failed to get appsrc");
DEBUG_WARN("src=%p, queue=%p, decoder=%p, output=%p",
mdecoder->src, mdecoder->queue, mdecoder->decbin, mdecoder->outbin);
tsmf_gstreamer_clean_up(mdecoder);
return FALSE; return FALSE;
} }
mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "outsink");
if (!mdecoder->outsink)
{
DEBUG_WARN("Failed to get sink");
return FALSE;
}
if (mdecoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
{
mdecoder->volume = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiovolume");
if (!mdecoder->volume)
{
DEBUG_WARN("Failed to get volume");
return FALSE;
}
}
tsmf_platform_register_handler(mdecoder);
gst_pipeline_set_delay((GstPipeline *)mdecoder->pipe, 5000); gst_pipeline_set_delay((GstPipeline *)mdecoder->pipe, 5000);
/* AppSrc settings */ /* AppSrc settings */
GstAppSrcCallbacks callbacks = GstAppSrcCallbacks callbacks =
@ -655,25 +480,9 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder)
gst_app_src_set_callbacks((GstAppSrc *)mdecoder->src, &callbacks, mdecoder, NULL); gst_app_src_set_callbacks((GstAppSrc *)mdecoder->src, &callbacks, mdecoder, NULL);
gst_app_src_set_stream_type((GstAppSrc *) mdecoder->src, GST_APP_STREAM_TYPE_SEEKABLE); gst_app_src_set_stream_type((GstAppSrc *) mdecoder->src, GST_APP_STREAM_TYPE_SEEKABLE);
gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps); gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps);
/* Queue2 settings */
g_object_set(mdecoder->queue, "use-buffering", FALSE, NULL);
g_object_set(mdecoder->queue, "max-size-buffers", 2, NULL);
/* DecodeBin settings */
g_signal_connect(mdecoder->decbin, "pad-added", G_CALLBACK(cb_newpad), mdecoder);
g_signal_connect(mdecoder->decbin, "pad-removed", G_CALLBACK(cb_freepad), mdecoder);
/* Sink settings */
linkResult = gst_element_link_many(mdecoder->src, mdecoder->queue,
mdecoder->decbin, NULL);
if (!linkResult)
{
DEBUG_WARN("Failed to link elements.");
tsmf_gstreamer_clean_up(mdecoder);
return FALSE;
}
tsmf_gstreamer_add_pad(mdecoder);
tsmf_window_create(mdecoder); tsmf_window_create(mdecoder);
tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY); tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY);
tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING);
mdecoder->pipeline_start_time_valid = 0; mdecoder->pipeline_start_time_valid = 0;
@ -776,6 +585,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN
tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING);
} }
return TRUE; return TRUE;
} }
@ -876,13 +686,8 @@ static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder *decoder)
if (!mdecoder) if (!mdecoder)
return FALSE; return FALSE;
if (!G_IS_OBJECT(mdecoder->queue))
return FALSE;
guint buff_max = 0; guint buff_max = 0;
g_object_get(mdecoder->queue, "max-size-buffers", &buff_max, NULL);
guint clbuff = 0; guint clbuff = 0;
g_object_get(mdecoder->queue, "current-level-buffers", &clbuff, NULL);
DEBUG_TSMF("%s buffer fill %u/%u", get_type(mdecoder), clbuff, buff_max); DEBUG_TSMF("%s buffer fill %u/%u", get_type(mdecoder), clbuff, buff_max);
return clbuff >= buff_max ? TRUE : FALSE; return clbuff >= buff_max ? TRUE : FALSE;
} }

View File

@ -17,15 +17,8 @@ typedef struct _TSMFGstreamerDecoder
GstElement *pipe; GstElement *pipe;
GstElement *src; GstElement *src;
GstElement *queue;
GstElement *decbin;
GstElement *outbin;
GstElement *outconv;
GstElement *outrate;
GstElement *outresample;
GstElement *outsink; GstElement *outsink;
GstElement *volume; GstElement *volume;
GstPad *ghost_pad;
BOOL ready; BOOL ready;
BOOL paused; BOOL paused;