mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-29 18:48:44 +00:00
gst-launch: Port to the direct use of GMainLoop
... instead of custom event loop. This can make it easy to use GMainLoop related APIs in code.
This commit is contained in:
parent
966d013bf0
commit
15423723fe
1 changed files with 131 additions and 157 deletions
|
@ -49,23 +49,37 @@ static void fault_restore (void);
|
|||
static void fault_spin (void);
|
||||
#endif
|
||||
|
||||
/* event_loop return codes */
|
||||
typedef enum _EventLoopResult
|
||||
/* exit codes */
|
||||
typedef enum _LaunchExitCode
|
||||
{
|
||||
ELR_NO_ERROR = 0,
|
||||
ELR_ERROR,
|
||||
ELR_INTERRUPT
|
||||
} EventLoopResult;
|
||||
LEC_STATE_CHANGE_FAILURE = -1,
|
||||
LEC_NO_ERROR = 0,
|
||||
LEC_ERROR,
|
||||
LEC_INTERRUPT
|
||||
} LaunchExitCode;
|
||||
|
||||
static GstElement *pipeline;
|
||||
static EventLoopResult caught_error = ELR_NO_ERROR;
|
||||
static GMainLoop *loop = NULL;
|
||||
static GstElement *pipeline = NULL;
|
||||
|
||||
/* options */
|
||||
static gboolean quiet = FALSE;
|
||||
static gboolean tags = FALSE;
|
||||
static gboolean toc = FALSE;
|
||||
static gboolean messages = FALSE;
|
||||
static gboolean is_live = FALSE;
|
||||
static gboolean eos_on_shutdown = FALSE;
|
||||
static gchar **exclude_args = NULL;
|
||||
|
||||
/* pipeline status */
|
||||
static gboolean is_live = FALSE;
|
||||
static gboolean buffering = FALSE;
|
||||
static LaunchExitCode last_launch_code = LEC_NO_ERROR;
|
||||
static GstState target_state = GST_STATE_PAUSED;
|
||||
static gboolean prerolled = FALSE;
|
||||
static gboolean in_progress = FALSE;
|
||||
static GstClockTime tfthen = GST_CLOCK_TIME_NONE;
|
||||
static gboolean interrupting = FALSE;
|
||||
static gboolean waiting_eos = FALSE;
|
||||
|
||||
/* convenience macro so we don't have to litter the code with if(!quiet) */
|
||||
#define PRINT if(!quiet)gst_print
|
||||
|
||||
|
@ -470,9 +484,6 @@ static guint signal_watch_hup_id;
|
|||
#endif
|
||||
#if defined(G_OS_UNIX) || defined(G_OS_WIN32)
|
||||
static guint signal_watch_intr_id;
|
||||
#if defined(G_OS_WIN32)
|
||||
static GstElement *intr_pipeline;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(G_OS_UNIX) || defined(G_OS_WIN32)
|
||||
|
@ -521,47 +532,39 @@ hup_handler (gpointer user_data)
|
|||
static BOOL WINAPI
|
||||
w32_intr_handler (DWORD dwCtrlType)
|
||||
{
|
||||
intr_handler ((gpointer) intr_pipeline);
|
||||
intr_pipeline = NULL;
|
||||
if (pipeline)
|
||||
intr_handler ((gpointer) pipeline);
|
||||
|
||||
SetConsoleCtrlHandler (w32_intr_handler, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* G_OS_WIN32 */
|
||||
#endif /* G_OS_UNIX */
|
||||
|
||||
/* returns ELR_ERROR if there was an error
|
||||
* or ELR_INTERRUPT if we caught a keyboard interrupt
|
||||
* or ELR_NO_ERROR otherwise. */
|
||||
static EventLoopResult
|
||||
event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
||||
GstState target_state)
|
||||
static void
|
||||
do_initial_play (GstElement * pipeline)
|
||||
{
|
||||
GstBus *bus;
|
||||
GstMessage *message = NULL;
|
||||
EventLoopResult res = ELR_NO_ERROR;
|
||||
gboolean buffering = FALSE, in_progress = FALSE;
|
||||
gboolean prerolled = target_state != GST_STATE_PAUSED;
|
||||
PRINT (_("Setting pipeline to PLAYING ...\n"));
|
||||
|
||||
bus = gst_element_get_bus (GST_ELEMENT (pipeline));
|
||||
tfthen = gst_util_get_timestamp ();
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
signal_watch_intr_id =
|
||||
g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline);
|
||||
signal_watch_hup_id =
|
||||
g_unix_signal_add (SIGHUP, (GSourceFunc) hup_handler, pipeline);
|
||||
#elif defined(G_OS_WIN32)
|
||||
intr_pipeline = NULL;
|
||||
if (SetConsoleCtrlHandler (w32_intr_handler, TRUE))
|
||||
intr_pipeline = pipeline;
|
||||
#endif
|
||||
if (gst_element_set_state (pipeline,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
|
||||
gst_printerr (_("ERROR: pipeline doesn't want to play.\n"));
|
||||
last_launch_code = LEC_STATE_CHANGE_FAILURE;
|
||||
|
||||
while (TRUE) {
|
||||
message = gst_bus_poll (bus, GST_MESSAGE_ANY, blocking ? -1 : 0);
|
||||
/* error message will be posted later */
|
||||
return;
|
||||
}
|
||||
|
||||
/* if the poll timed out, only when !blocking */
|
||||
if (message == NULL)
|
||||
goto exit;
|
||||
target_state = GST_STATE_PLAYING;
|
||||
}
|
||||
|
||||
/* check if we need to dump messages to the console */
|
||||
static gboolean
|
||||
bus_handler (GstBus * bus, GstMessage * message, gpointer data)
|
||||
{
|
||||
{
|
||||
if (messages) {
|
||||
GstObject *src_obj;
|
||||
const GstStructure *s;
|
||||
|
@ -619,7 +622,11 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
|||
case GST_MESSAGE_EOS:{
|
||||
PRINT (_("Got EOS from element \"%s\".\n"),
|
||||
GST_MESSAGE_SRC_NAME (message));
|
||||
goto exit;
|
||||
|
||||
if (eos_on_shutdown)
|
||||
PRINT (_("EOS received - stopping pipeline...\n"));
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_TAG:
|
||||
if (tags) {
|
||||
|
@ -706,9 +713,16 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
|||
|
||||
print_error_message (message);
|
||||
|
||||
if (target_state == GST_STATE_PAUSED) {
|
||||
gst_printerr (_("ERROR: pipeline doesn't want to preroll.\n"));
|
||||
} else if (interrupting) {
|
||||
PRINT (_("An error happened while waiting for EOS\n"));
|
||||
}
|
||||
|
||||
/* we have an error */
|
||||
res = ELR_ERROR;
|
||||
goto exit;
|
||||
last_launch_code = LEC_ERROR;
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_STATE_CHANGED:{
|
||||
GstState old, new, pending;
|
||||
|
@ -719,9 +733,10 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
|||
|
||||
gst_message_parse_state_changed (message, &old, &new, &pending);
|
||||
|
||||
/* if we reached the final target state, exit */
|
||||
if (target_state == GST_STATE_PAUSED && new == target_state) {
|
||||
prerolled = TRUE;
|
||||
|
||||
PRINT (_("Pipeline is PREROLLED ...\n"));
|
||||
/* ignore when we are buffering since then we mess with the states
|
||||
* ourselves. */
|
||||
if (buffering) {
|
||||
|
@ -732,7 +747,8 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
|||
PRINT (_("Prerolled, waiting for progress to finish...\n"));
|
||||
break;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
do_initial_play (pipeline);
|
||||
}
|
||||
/* else not an interesting message */
|
||||
break;
|
||||
|
@ -750,12 +766,17 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
|||
if (percent == 100) {
|
||||
/* a 100% message means buffering is done */
|
||||
buffering = FALSE;
|
||||
|
||||
if (target_state == GST_STATE_PAUSED) {
|
||||
do_initial_play (pipeline);
|
||||
break;
|
||||
}
|
||||
|
||||
/* if the desired state is playing, go back */
|
||||
if (target_state == GST_STATE_PLAYING) {
|
||||
PRINT (_("Done buffering, setting pipeline to PLAYING ...\n"));
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
} else if (prerolled && !in_progress)
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
/* buffering busy */
|
||||
if (!buffering && target_state == GST_STATE_PLAYING) {
|
||||
|
@ -797,8 +818,26 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
|||
/* this application message is posted when we caught an interrupt and
|
||||
* we need to stop the pipeline. */
|
||||
PRINT (_("Interrupt: Stopping pipeline ...\n"));
|
||||
res = ELR_INTERRUPT;
|
||||
goto exit;
|
||||
interrupting = TRUE;
|
||||
|
||||
if (eos_on_shutdown) {
|
||||
if (waiting_eos) {
|
||||
PRINT (_
|
||||
("Interrupt while waiting for EOS - stopping pipeline...\n"));
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
} else {
|
||||
PRINT (_
|
||||
("EOS on shutdown enabled -- Forcing EOS on the pipeline\n"));
|
||||
gst_element_send_event (pipeline, gst_event_new_eos ());
|
||||
|
||||
PRINT (_("Waiting for EOS...\n"));
|
||||
|
||||
waiting_eos = TRUE;
|
||||
}
|
||||
} else {
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -812,10 +851,7 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
|||
switch (type) {
|
||||
case GST_PROGRESS_TYPE_START:
|
||||
case GST_PROGRESS_TYPE_CONTINUE:
|
||||
if (do_progress) {
|
||||
in_progress = TRUE;
|
||||
blocking = TRUE;
|
||||
}
|
||||
in_progress = TRUE;
|
||||
break;
|
||||
case GST_PROGRESS_TYPE_COMPLETE:
|
||||
case GST_PROGRESS_TYPE_CANCELED:
|
||||
|
@ -829,8 +865,9 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
|||
g_free (code);
|
||||
g_free (text);
|
||||
|
||||
if (do_progress && !in_progress && !buffering && prerolled)
|
||||
goto exit;
|
||||
if (!in_progress && prerolled && target_state == GST_STATE_PAUSED) {
|
||||
do_initial_play (pipeline);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_ELEMENT:{
|
||||
|
@ -906,27 +943,9 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
|
|||
/* just be quiet by default */
|
||||
break;
|
||||
}
|
||||
if (message)
|
||||
gst_message_unref (message);
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
|
||||
exit:
|
||||
{
|
||||
if (message)
|
||||
gst_message_unref (message);
|
||||
gst_object_unref (bus);
|
||||
#ifdef G_OS_UNIX
|
||||
if (signal_watch_intr_id > 0)
|
||||
g_source_remove (signal_watch_intr_id);
|
||||
if (signal_watch_hup_id > 0)
|
||||
g_source_remove (signal_watch_hup_id);
|
||||
#elif defined(G_OS_WIN32)
|
||||
intr_pipeline = NULL;
|
||||
SetConsoleCtrlHandler (w32_intr_handler, FALSE);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstBusSyncReply
|
||||
|
@ -978,7 +997,6 @@ main (int argc, char *argv[])
|
|||
/* options */
|
||||
gboolean verbose = FALSE;
|
||||
gboolean no_fault = FALSE;
|
||||
gboolean eos_on_shutdown = FALSE;
|
||||
#if 0
|
||||
gboolean check_index = FALSE;
|
||||
#endif
|
||||
|
@ -1020,7 +1038,7 @@ main (int argc, char *argv[])
|
|||
gchar **argvn;
|
||||
GError *error = NULL;
|
||||
gulong deep_notify_id = 0;
|
||||
gint res = 0;
|
||||
guint bus_watch_id = 0;
|
||||
|
||||
free (malloc (8)); /* -lefence */
|
||||
|
||||
|
@ -1086,6 +1104,8 @@ main (int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
if (!savefile) {
|
||||
GstState state, pending;
|
||||
GstStateChangeReturn ret;
|
||||
|
@ -1125,6 +1145,7 @@ main (int argc, char *argv[])
|
|||
|
||||
bus = gst_element_get_bus (pipeline);
|
||||
gst_bus_set_sync_handler (bus, bus_sync_handler, (gpointer) pipeline, NULL);
|
||||
bus_watch_id = gst_bus_add_watch (bus, bus_handler, NULL);
|
||||
gst_object_unref (bus);
|
||||
|
||||
PRINT (_("Setting pipeline to PAUSED ...\n"));
|
||||
|
@ -1133,8 +1154,7 @@ main (int argc, char *argv[])
|
|||
switch (ret) {
|
||||
case GST_STATE_CHANGE_FAILURE:
|
||||
gst_printerr (_("ERROR: Pipeline doesn't want to pause.\n"));
|
||||
res = -1;
|
||||
event_loop (pipeline, FALSE, FALSE, GST_STATE_VOID_PENDING);
|
||||
last_launch_code = LEC_STATE_CHANGE_FAILURE;
|
||||
goto end;
|
||||
case GST_STATE_CHANGE_NO_PREROLL:
|
||||
PRINT (_("Pipeline is live and does not need PREROLL ...\n"));
|
||||
|
@ -1142,94 +1162,39 @@ main (int argc, char *argv[])
|
|||
break;
|
||||
case GST_STATE_CHANGE_ASYNC:
|
||||
PRINT (_("Pipeline is PREROLLING ...\n"));
|
||||
caught_error = event_loop (pipeline, TRUE, TRUE, GST_STATE_PAUSED);
|
||||
if (caught_error) {
|
||||
gst_printerr (_("ERROR: pipeline doesn't want to preroll.\n"));
|
||||
res = caught_error;
|
||||
goto end;
|
||||
}
|
||||
state = GST_STATE_PAUSED;
|
||||
/* fallthrough */
|
||||
case GST_STATE_CHANGE_SUCCESS:
|
||||
PRINT (_("Pipeline is PREROLLED ...\n"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
caught_error = event_loop (pipeline, FALSE, TRUE, GST_STATE_PLAYING);
|
||||
#ifdef G_OS_UNIX
|
||||
signal_watch_intr_id =
|
||||
g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline);
|
||||
signal_watch_hup_id =
|
||||
g_unix_signal_add (SIGHUP, (GSourceFunc) hup_handler, pipeline);
|
||||
#elif defined(G_OS_WIN32)
|
||||
SetConsoleCtrlHandler (w32_intr_handler, TRUE);
|
||||
#endif
|
||||
|
||||
if (caught_error) {
|
||||
gst_printerr (_("ERROR: pipeline doesn't want to preroll.\n"));
|
||||
res = caught_error;
|
||||
} else {
|
||||
GstClockTime tfthen, tfnow;
|
||||
/* playing state will be set on state-changed message handler */
|
||||
g_main_loop_run (loop);
|
||||
|
||||
{
|
||||
GstClockTime tfnow;
|
||||
GstClockTimeDiff diff;
|
||||
|
||||
PRINT (_("Setting pipeline to PLAYING ...\n"));
|
||||
if (GST_CLOCK_TIME_IS_VALID (tfthen)) {
|
||||
tfnow = gst_util_get_timestamp ();
|
||||
diff = GST_CLOCK_DIFF (tfthen, tfnow);
|
||||
|
||||
if (gst_element_set_state (pipeline,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
|
||||
GstMessage *err_msg;
|
||||
GstBus *bus;
|
||||
|
||||
gst_printerr (_("ERROR: pipeline doesn't want to play.\n"));
|
||||
bus = gst_element_get_bus (pipeline);
|
||||
if ((err_msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0))) {
|
||||
print_error_message (err_msg);
|
||||
gst_message_unref (err_msg);
|
||||
}
|
||||
gst_object_unref (bus);
|
||||
res = -1;
|
||||
goto end;
|
||||
PRINT (_("Execution ended after %" GST_TIME_FORMAT "\n"),
|
||||
GST_TIME_ARGS (diff));
|
||||
}
|
||||
|
||||
tfthen = gst_util_get_timestamp ();
|
||||
caught_error = event_loop (pipeline, TRUE, FALSE, GST_STATE_PLAYING);
|
||||
res = caught_error;
|
||||
if (eos_on_shutdown && caught_error != ELR_NO_ERROR) {
|
||||
gboolean ignore_errors;
|
||||
|
||||
if (caught_error == ELR_INTERRUPT) {
|
||||
PRINT (_("EOS on shutdown enabled -- Forcing EOS on the pipeline\n"));
|
||||
gst_element_send_event (pipeline, gst_event_new_eos ());
|
||||
ignore_errors = FALSE;
|
||||
} else {
|
||||
PRINT (_("EOS on shutdown enabled -- waiting for EOS after Error\n"));
|
||||
ignore_errors = TRUE;
|
||||
}
|
||||
PRINT (_("Waiting for EOS...\n"));
|
||||
|
||||
while (TRUE) {
|
||||
caught_error = event_loop (pipeline, TRUE, FALSE, GST_STATE_PLAYING);
|
||||
|
||||
if (caught_error == ELR_NO_ERROR) {
|
||||
/* we got EOS */
|
||||
PRINT (_("EOS received - stopping pipeline...\n"));
|
||||
break;
|
||||
} else if (caught_error == ELR_INTERRUPT) {
|
||||
PRINT (_
|
||||
("Interrupt while waiting for EOS - stopping pipeline...\n"));
|
||||
res = caught_error;
|
||||
break;
|
||||
} else if (caught_error == ELR_ERROR) {
|
||||
if (!ignore_errors) {
|
||||
PRINT (_("An error happened while waiting for EOS\n"));
|
||||
res = caught_error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tfnow = gst_util_get_timestamp ();
|
||||
|
||||
diff = GST_CLOCK_DIFF (tfthen, tfnow);
|
||||
|
||||
PRINT (_("Execution ended after %" GST_TIME_FORMAT "\n"),
|
||||
GST_TIME_ARGS (diff));
|
||||
}
|
||||
|
||||
PRINT (_("Setting pipeline to PAUSED ...\n"));
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
if (caught_error == ELR_NO_ERROR)
|
||||
if (last_launch_code == LEC_NO_ERROR)
|
||||
gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
|
||||
|
||||
/* iterate mainloop to process pending stuff */
|
||||
|
@ -1253,6 +1218,15 @@ main (int argc, char *argv[])
|
|||
end:
|
||||
PRINT (_("Setting pipeline to NULL ...\n"));
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
if (signal_watch_intr_id > 0)
|
||||
g_source_remove (signal_watch_intr_id);
|
||||
if (signal_watch_hup_id > 0)
|
||||
g_source_remove (signal_watch_hup_id);
|
||||
#endif
|
||||
g_source_remove (bus_watch_id);
|
||||
g_main_loop_unref (loop);
|
||||
}
|
||||
|
||||
PRINT (_("Freeing pipeline ...\n"));
|
||||
|
@ -1260,5 +1234,5 @@ main (int argc, char *argv[])
|
|||
|
||||
gst_deinit ();
|
||||
|
||||
return res;
|
||||
return last_launch_code;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue