Created
November 10, 2019 16:32
-
-
Save dlbas/392dd262fa84c350ae27ec5f85de1102 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
// | |
// Created by daniel on 09/11/2019. | |
// | |
#include <gst/gst.h> | |
typedef struct _CustomData { | |
GstElement *pipeline; | |
GstElement *v4l2src; | |
GstElement *caps_filter1; | |
GstElement *decodebin; | |
GstElement *ximagesrc; | |
GstElement *caps_filter3; | |
GstElement *videoscale; | |
GstElement *caps_filter4; | |
GstElement *alpha; | |
GstElement *videobox; | |
GstElement *videotestsrc; | |
GstElement *caps_filter2; | |
GstElement *videomixer; | |
GstElement *videoconvert; | |
GstElement *xvimagesink; | |
} CustomData; | |
#define BALL_PATTERN 18 | |
static void decodebin_pad_added(GstElement *src, GstPad *new_pad, CustomData *data); | |
int main(int argc, char *argv[]) { | |
CustomData data; | |
GstBus *bus; | |
GstMessage *msg; | |
GstStateChangeReturn ret; | |
gboolean terminate = FALSE; | |
GstCaps *caps; | |
GstPad *mixerpad_1, *mixerpad_2, *mixerpad_3; | |
GstPad *videotestsrc_pad, *videobox_pad; | |
// initialize | |
gst_init(&argc, &argv); | |
// create elements | |
data.v4l2src = gst_element_factory_make("v4l2src", NULL); | |
data.caps_filter1 = gst_element_factory_make("capsfilter", "caps_filter1"); | |
data.decodebin = gst_element_factory_make("decodebin", NULL); | |
data.ximagesrc = gst_element_factory_make("ximagesrc", NULL); | |
data.caps_filter3 = gst_element_factory_make("capsfilter", "caps_filter3"); | |
data.videoscale = gst_element_factory_make("videoscale", NULL); | |
data.caps_filter4 = gst_element_factory_make("capsfilter", "caps_filter4"); | |
data.alpha = gst_element_factory_make("alpha", NULL); | |
data.videobox = gst_element_factory_make("videobox", NULL); | |
data.videotestsrc = gst_element_factory_make("videotestsrc", NULL); | |
data.caps_filter2 = gst_element_factory_make("capsfilter", "caps_filter2"); | |
data.videomixer = gst_element_factory_make("videomixer", "mix"); | |
data.videoconvert = gst_element_factory_make("videoconvert", NULL); | |
data.xvimagesink = gst_element_factory_make("xvimagesink", NULL); | |
// set element properties | |
g_object_set(data.xvimagesink, "sync", FALSE, NULL); | |
g_object_set(data.v4l2src, "device", "/dev/video0", NULL); | |
g_object_set(data.videotestsrc, "pattern", BALL_PATTERN, NULL); | |
g_object_set(data.ximagesrc, "startx", 0, NULL); | |
g_object_set(data.ximagesrc, "use-damage", 0, NULL); | |
g_object_set(data.videoscale, "method", 0, NULL); | |
g_object_set(data.alpha, "alpha", 1.0, NULL); | |
g_object_set(data.videobox, "border-alpha", 0.0, NULL); | |
g_object_set(data.videobox, "top", -600, NULL); | |
g_object_set(data.videobox, "left", -1280, NULL); | |
// set appropriate caps | |
caps = gst_caps_new_simple("image/jpeg", | |
"framerate", GST_TYPE_FRACTION, 30, 1, | |
"width", G_TYPE_INT, 640, | |
"height", G_TYPE_INT, 480, | |
NULL); | |
g_object_set(data.caps_filter1, "caps", caps, NULL); | |
caps = gst_caps_new_simple("video/x-raw", | |
"framerate", GST_TYPE_FRACTION, 30, 1, | |
"width", G_TYPE_INT, 1920, | |
"height", G_TYPE_INT, 1080, | |
NULL); | |
g_object_set(data.caps_filter2, "caps", caps, NULL); | |
caps = gst_caps_new_simple("video/x-raw", | |
"framerate", GST_TYPE_FRACTION, 30, 1, | |
NULL); | |
g_object_set(data.caps_filter3, "caps", caps, NULL); | |
caps = gst_caps_new_simple("video/x-raw", | |
"width", G_TYPE_INT, 640, | |
"height", G_TYPE_INT, 480, | |
NULL); | |
g_object_set(data.caps_filter4, "caps", caps, NULL); | |
data.pipeline = gst_pipeline_new("pipeline"); | |
if (!data.v4l2src || !data.decodebin || !data.ximagesrc || !data.videoscale || !data.alpha || !data.videobox || | |
!data.videotestsrc || !data.videomixer || !data.videoconvert || !data.xvimagesink || !data.caps_filter1 || | |
!data.caps_filter2 || | |
!data.caps_filter3 || !data.caps_filter4) { | |
g_printerr("Not all element could be created\n"); | |
return -1; | |
} | |
gst_bin_add_many(GST_BIN(data.pipeline), | |
data.v4l2src, | |
data.caps_filter1, | |
data.decodebin, | |
data.ximagesrc, | |
data.caps_filter3, | |
data.videoscale, | |
data.caps_filter4, | |
data.alpha, | |
data.videobox, | |
data.videotestsrc, | |
data.caps_filter2, | |
data.videomixer, | |
data.videoconvert, | |
data.xvimagesink, | |
NULL); | |
if ( | |
!gst_element_link_many(data.videomixer, data.videoconvert, data.xvimagesink, NULL) || | |
!gst_element_link_many(data.v4l2src, data.caps_filter1, data.decodebin, NULL) || | |
!gst_element_link_many(data.videotestsrc, data.caps_filter2, NULL) || | |
!gst_element_link_many(data.ximagesrc, data.caps_filter3, data.videoscale, data.caps_filter4, data.alpha, | |
data.videobox, NULL) | |
) { | |
g_printerr("Elements could not be linked.\n"); | |
gst_object_unref(data.pipeline); | |
return -1; | |
} | |
// link on-request pads | |
// this one for decodebin | |
// NOTE: linking of decodebin pad should be done in callback | |
// this one for videotestsrc | |
mixerpad_2 = gst_element_get_request_pad(data.videomixer, "sink_%u"); | |
videotestsrc_pad = gst_element_get_static_pad(data.caps_filter2, "src"); | |
if (gst_pad_link(videotestsrc_pad, mixerpad_2) != GST_PAD_LINK_OK) { | |
g_printerr("Videotestsrc pad could not be linked\n"); | |
g_object_unref(data.pipeline); | |
return -1; | |
} | |
// this one for videobox | |
mixerpad_3 = gst_element_get_request_pad(data.videomixer, "sink_%u"); | |
videobox_pad = gst_element_get_static_pad(data.videobox, "src"); | |
if (gst_pad_link(videobox_pad, mixerpad_3) != GST_PAD_LINK_OK) { | |
g_printerr("Videobox pad could not be linked\n"); | |
g_object_unref(data.pipeline); | |
return -1; | |
} | |
// connect to the pad-added signal | |
g_signal_connect(data.decodebin, "pad-added", G_CALLBACK(decodebin_pad_added), &data); | |
// start playing | |
ret = gst_element_set_state(data.pipeline, GST_STATE_PLAYING); | |
if (ret == GST_STATE_CHANGE_FAILURE) { | |
g_printerr("Unable to set the pipeline to the playing state.\n"); | |
gst_object_unref(data.pipeline); | |
return -1; | |
} | |
// listen to the bus | |
bus = gst_element_get_bus(data.pipeline); | |
do { | |
msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, | |
GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS); | |
// parse message | |
if (msg != NULL) { | |
GError *err; | |
gchar *debug_info; | |
switch (GST_MESSAGE_TYPE(msg)) { | |
case GST_MESSAGE_ERROR: | |
gst_message_parse_error(msg, &err, &debug_info); | |
g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message); | |
g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none"); | |
g_clear_error(&err); | |
g_free(debug_info); | |
terminate = TRUE; | |
break; | |
case GST_MESSAGE_EOS: | |
g_print("End-Of-Stream reached.\n"); | |
terminate = TRUE; | |
break; | |
case GST_MESSAGE_STATE_CHANGED: | |
/* We are only interested in state-changed messages from the pipeline */ | |
if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data.pipeline)) { | |
GstState old_state, new_state, pending_state; | |
gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state); | |
g_print("Pipeline state changed from %s to %s:\n", | |
gst_element_state_get_name(old_state), gst_element_state_get_name(new_state)); | |
} | |
break; | |
default: | |
/* We should not reach here */ | |
g_printerr("Unexpected message received.\n"); | |
break; | |
} | |
gst_message_unref(msg); | |
} | |
} while (!terminate); | |
// free resources | |
gst_object_unref(bus); | |
gst_element_set_state(data.pipeline, GST_STATE_NULL); | |
gst_object_unref(data.pipeline); | |
return 0; | |
} | |
static void decodebin_pad_added(GstElement *src, GstPad *new_pad, CustomData *data) { | |
GstPad *mixer_pad = gst_element_get_request_pad(data->videomixer, "sink_%u"); | |
GstPadLinkReturn ret; | |
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 (gst_pad_is_linked(new_pad)) { | |
g_print("Pad is already linked - ignoring\n"); | |
goto exit; | |
} | |
ret = gst_pad_link(new_pad, mixer_pad); | |
if (GST_PAD_LINK_FAILED(ret)) { | |
g_print("Type is %s, but link has failed.\n", new_pad_type); | |
goto exit; | |
} else { | |
g_print("Link has been successful (type '%s').\n", new_pad_type); | |
} | |
exit: | |
/* Unreference the sink pad */ | |
gst_object_unref(mixer_pad); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment