1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
#include <gst/gst.h>
#define SWITCH_TIMEOUT 1
#define NUM_VIDEO_BUFFERS 500
static GMainLoop *loop;
/* Output selector src pads */
static GstPad *osel_src1 = NULL;
static GstPad *osel_src2 = NULL;
static gboolean
my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
{
g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR:{
GError *err;
gchar *debug;
gst_message_parse_error (message, &err, &debug);
g_print ("Error: %s\n", err->message);
g_error_free (err);
g_free (debug);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_EOS:
/* end-of-stream */
g_main_loop_quit (loop);
break;
default:
/* unhandled message */
break;
}
/* we want to be notified again the next time there is a message
* on the bus, so returning TRUE (FALSE means we want to stop watching
* for messages on the bus and our callback should not be called again)
*/
return TRUE;
}
static gboolean
switch_cb (gpointer user_data)
{
GstElement *sel = GST_ELEMENT (user_data);
GstPad *old_pad, *new_pad = NULL;
g_object_get (G_OBJECT (sel), "active-pad", &old_pad, NULL);
if (old_pad == osel_src1)
new_pad = osel_src2;
else
new_pad = osel_src1;
g_object_set (G_OBJECT (sel), "active-pad", new_pad, NULL);
g_print ("switched from %s:%s to %s:%s\n", GST_DEBUG_PAD_NAME (old_pad),
GST_DEBUG_PAD_NAME (new_pad));
gst_object_unref (old_pad);
return TRUE;
}
static void
on_bin_element_added (GstBin * bin, GstElement * element, gpointer user_data)
{
g_object_set (G_OBJECT (element), "sync", FALSE, "async", FALSE, NULL);
}
gint
main (gint argc, gchar * argv[])
{
GstElement *pipeline, *src, *toverlay, *osel, *sink1, *sink2, *c1, *c2, *c0;
GstPad *sinkpad;
GstBus *bus;
/* init GStreamer */
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
/* create elements */
pipeline = gst_element_factory_make ("pipeline", "pipeline");
src = gst_element_factory_make ("videotestsrc", "src");
c0 = gst_element_factory_make ("videoconvert", NULL);
toverlay = gst_element_factory_make ("timeoverlay", "timeoverlay");
osel = gst_element_factory_make ("output-selector", "osel");
c1 = gst_element_factory_make ("videoconvert", NULL);
c2 = gst_element_factory_make ("videoconvert", NULL);
sink1 = gst_element_factory_make ("autovideosink", "sink1");
sink2 = gst_element_factory_make ("autovideosink", "sink2");
if (!pipeline || !src || !c0 || !toverlay || !osel || !c1 || !c2 || !sink1 ||
!sink2) {
g_print ("missing element\n");
return -1;
}
/* add them to bin */
gst_bin_add_many (GST_BIN (pipeline), src, c0, toverlay, osel, c1, sink1, c2,
sink2, NULL);
/* set properties */
g_object_set (G_OBJECT (src), "is-live", TRUE, NULL);
g_object_set (G_OBJECT (src), "do-timestamp", TRUE, NULL);
g_object_set (G_OBJECT (src), "num-buffers", NUM_VIDEO_BUFFERS, NULL);
g_object_set (G_OBJECT (osel), "resend-latest", TRUE, NULL);
/* handle deferred properties */
g_signal_connect (G_OBJECT (sink1), "element-added",
G_CALLBACK (on_bin_element_added), NULL);
g_signal_connect (G_OBJECT (sink2), "element-added",
G_CALLBACK (on_bin_element_added), NULL);
/* link src ! timeoverlay ! osel */
if (!gst_element_link_many (src, c0, toverlay, osel, NULL)) {
g_print ("linking failed\n");
return -1;
}
/* link output 1 */
sinkpad = gst_element_get_static_pad (c1, "sink");
osel_src1 = gst_element_request_pad_simple (osel, "src_%u");
if (gst_pad_link (osel_src1, sinkpad) != GST_PAD_LINK_OK) {
g_print ("linking output 1 converter failed\n");
return -1;
}
gst_object_unref (sinkpad);
if (!gst_element_link (c1, sink1)) {
g_print ("linking output 1 failed\n");
return -1;
}
/* link output 2 */
sinkpad = gst_element_get_static_pad (c2, "sink");
osel_src2 = gst_element_request_pad_simple (osel, "src_%u");
if (gst_pad_link (osel_src2, sinkpad) != GST_PAD_LINK_OK) {
g_print ("linking output 2 converter failed\n");
return -1;
}
gst_object_unref (sinkpad);
if (!gst_element_link (c2, sink2)) {
g_print ("linking output 2 failed\n");
return -1;
}
/* add switch callback */
g_timeout_add_seconds (SWITCH_TIMEOUT, switch_cb, osel);
/* change to playing */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_watch (bus, my_bus_callback, loop);
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* now run */
g_main_loop_run (loop);
/* also clean up */
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_element_release_request_pad (osel, osel_src1);
gst_element_release_request_pad (osel, osel_src2);
gst_object_unref (GST_OBJECT (pipeline));
return 0;
}
|