Last active
August 29, 2015 14:07
-
-
Save stylesuxx/fa529f0c2b13526e48a9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <gst/gst.h> | |
typedef struct _AppElements { | |
GMainLoop *loop; | |
GstElement *pipeline; | |
GstElement *source; | |
GstElement *demuxer; | |
GstElement *convert; | |
GstElement *encoder; | |
GstElement *muxer; | |
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; | |
} | |
/* | |
filesrc location="test.avi" ! decodebin ! videoconvert ! x264enc bitrate=2000 ! flvmux name=mux \ | |
! rtmpsink location="rtmp://127.0.0.1:1935/example/live live=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.encoder = gst_element_factory_make_or_error ("x264enc", "encoder"); | |
app.muxer = gst_element_factory_make_or_error ("flvmux", "muxer"); | |
app.sink = gst_element_factory_make_or_error ("rtmpsink", "sink"); | |
g_object_set (app.source, "location", argv[1], NULL); | |
g_object_set (app.sink, "location", "rtmp://127.0.0.1:1935/example/live live=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.encoder, app.muxer, app.sink, NULL); | |
gst_element_link (app.source, app.demuxer); | |
gst_element_link_many (app.convert, app.encoder, app.muxer, app.sink, NULL); | |
// 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