Skip to content

Instantly share code, notes, and snippets.

@stylesuxx
Created September 30, 2014 20:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stylesuxx/7c5c796ebe2b154e8fe3 to your computer and use it in GitHub Desktop.
Save stylesuxx/7c5c796ebe2b154e8fe3 to your computer and use it in GitHub Desktop.
gst trick player
#include <stdio.h>
#include <stdlib.h>
#include <gst/gst.h>
typedef struct _AppElements {
GMainLoop *loop;
GstElement *pipeline;
GstElement *source;
GstElement *demuxer;
GstElement *convert;
GstElement *sink;
} AppElements;
gboolean loop = FALSE;
static gboolean
handle_keyboard (GIOChannel *source, GIOCondition cond, AppElements *app) {
gchar *str = NULL;
if (g_io_channel_read_line (source, &str, NULL, NULL, NULL) != G_IO_STATUS_NORMAL) {
return TRUE;
}
switch (g_ascii_tolower (str[0])) {
case 'q':
g_main_loop_quit (app->loop);
break;
case 'l':
g_print ("Looping activated\n");
loop = TRUE;
break;
default:
break;
}
g_free (str);
return TRUE;
}
GstElement *
gst_element_factory_make_or_error (const gchar *factoryname, const gchar *name) {
GstElement *element;
element = gst_element_factory_make (factoryname, name);
if (!element) {
g_printerr ("Element \'%s\' could not be created. Exiting...\n", factoryname);
exit(1);
}
return element;
}
static gboolean
bus_callback (GstBus *bus, GstMessage *msg, gpointer data) {
AppElements *app = (AppElements*) data;
switch (GST_MESSAGE_TYPE(msg))
{
case GST_MESSAGE_EOS: {
/* end of stream received */
g_print("Received End-of-Stream Signal\n");
if (loop) {
g_print ("Performing loop\n");
if (!gst_element_seek (app->pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
GST_SEEK_TYPE_SET, 2 * GST_SECOND,
GST_SEEK_TYPE_SET, 5 *GST_SECOND)) {
g_print ("Seek failed!\n");
}
}
else {
g_main_loop_quit (app->loop);
}
break;
}
case GST_MESSAGE_SEGMENT_DONE: {
g_print ("Received SEGMENT DONE Message\n");
break;
}
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *error;
gst_message_parse_error (msg, &error, &debug);
g_free (debug);
g_printerr ("Error: %s\n", error->message);
g_error_free (error);
g_main_loop_quit (app->loop);
break;
}
default:
/* unhandled message */
break;
}
return TRUE;
}
/* This function will be called by the pad-added signal */
static void
pad_added_handler (GstElement *src, GstPad *new_pad, AppElements *data) {
GstPad *sink_pad = gst_element_get_static_pad (data->convert, "sink");
GstPadLinkReturn ret;
GstCaps *new_pad_caps = NULL;
GstStructure *new_pad_struct = NULL;
const gchar *new_pad_type = NULL;
g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src));
/* If our converter is already linked, we have nothing to do here */
if (gst_pad_is_linked (sink_pad)) {
g_print (" We are already linked. Ignoring.\n");
goto exit;
}
/* Check the new pad's type */
new_pad_caps = gst_pad_query_caps (new_pad, NULL);
new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
new_pad_type = gst_structure_get_name (new_pad_struct);
if (!g_str_has_prefix (new_pad_type, "video/x-raw")) {
g_print (" It has type '%s' which is not raw video. Ignoring.\n", new_pad_type);
goto exit;
}
/* Attempt the link */
ret = gst_pad_link (new_pad, sink_pad);
if (GST_PAD_LINK_FAILED (ret)) {
g_print (" Type is '%s' but link failed.\n", new_pad_type);
} else {
g_print (" Link succeeded (type '%s').\n", new_pad_type);
}
exit:
/* Unreference the new pad's caps, if we got them */
if (new_pad_caps != NULL)
gst_caps_unref (new_pad_caps);
/* Unreference the sink pad */
gst_object_unref (sink_pad);
}
int
main(int argc, gchar *argv[]) {
AppElements app;
GstBus *bus;
GIOChannel *io_stdin;
guint bus_watch_id;
gst_init (&argc, &argv);
if (argc != 2) {
g_print("Usage: %s FILE\n", argv[0]);
return -1;
}
app.loop = g_main_loop_new(NULL, FALSE);
app.pipeline = gst_pipeline_new ("autovideo-pipe");
if (!app.pipeline) {
g_printerr ("Pipeline could not be created. Exiting.\n");
return -1;
}
app.source = gst_element_factory_make_or_error ("filesrc", "filesrc");
app.demuxer = gst_element_factory_make_or_error ("decodebin", "decodebin");
app.convert = gst_element_factory_make_or_error ("videoconvert", "convert");
app.sink = gst_element_factory_make_or_error ("autovideosink", "sink");
g_object_set (app.source, "location", argv[1], NULL);
/* Connect the Pipeline Bus with out callback */
bus = gst_pipeline_get_bus (GST_PIPELINE (app.pipeline));
bus_watch_id = gst_bus_add_watch (bus, bus_callback, &app);
gst_object_unref (bus);
gst_bin_add_many (GST_BIN (app.pipeline), app.source, app.demuxer, app.convert, app.sink, NULL);
gst_element_link (app.source, app.demuxer);
gst_element_link (app.convert, app.sink);
// TODO connect the singals
g_signal_connect (app.demuxer, "pad-added", G_CALLBACK (pad_added_handler), &app);
/* Setting up the Pipeline using Segments */
gst_element_set_state (app.pipeline, GST_STATE_PAUSED);
io_stdin = g_io_channel_unix_new (fileno (stdin));
g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc) handle_keyboard, &app);
/* run the pipeline */
g_print ("Running...\n");
gst_element_set_state (app.pipeline, GST_STATE_PLAYING);
g_main_loop_run (app.loop);
/* cleanup */
g_print ("STOPPING Pipeline\n");
gst_element_set_state (app.pipeline, GST_STATE_NULL);
g_print ("DELETING Pipeline\n");
gst_object_unref (GST_OBJECT (app.pipeline));
g_print ("DELETING Bus\n");
g_source_remove (bus_watch_id);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment