From effb4083f50f11be92c925b0ca449efd16f14811 Mon Sep 17 00:00:00 2001 From: Johannes Randerath Date: Sun, 12 Oct 2025 22:10:47 +0200 Subject: [PATCH] Initial commit; added webcam stream to gstreamer pipeline --- .gitignore | 1 + meson.build | 3 ++ stream_source.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 .gitignore create mode 100644 meson.build create mode 100644 stream_source.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a007fea --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/* diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..1e5db2e --- /dev/null +++ b/meson.build @@ -0,0 +1,3 @@ +project('fancybirds', 'c') +gstdep = dependency('gstreamer-1.0') +executable('stream_source', 'stream_source.c', dependencies : gstdep) diff --git a/stream_source.c b/stream_source.c new file mode 100644 index 0000000..2065052 --- /dev/null +++ b/stream_source.c @@ -0,0 +1,92 @@ +#include "gst/gstbin.h" +#include "gst/gstbus.h" +#include "gst/gstclock.h" +#include "gst/gstelement.h" +#include "gst/gstelementfactory.h" +#include "gst/gstmessage.h" +#include "gst/gstobject.h" +#include "gst/gstpipeline.h" +#include "gst/gstutils.h" +#include + +typedef struct _CustomData { + GstElement *pipeline; + GstElement *source; +} CustomData; + +int main(int argc, char *argv[]) { + GstBus *bus; + GstMessage *msg; + GstElement *video_queue; + GstElement *video_convert; + GstElement *video_sink; + CustomData data; + GstStateChangeReturn ret; + gboolean terminate = FALSE; + + gst_init(&argc, &argv); + data.source = gst_element_factory_make("v4l2src", "source"); + video_queue = gst_element_factory_make("queue", "video_queue"); + video_convert = gst_element_factory_make("videoconvert", "video_convert"); + video_sink = gst_element_factory_make("autovideosink", "video_sink"); + data.pipeline = gst_pipeline_new("media-pipeline"); + + if (!data.source || !video_queue || !video_convert || !video_sink || !data.pipeline) { + g_printerr("Couldn't create all elements.\n"); + return -1; + } + g_object_set(data.source, "device", "/dev/video2", NULL); + + gst_bin_add_many(GST_BIN(data.pipeline), data.source, video_queue, video_convert, video_sink, NULL); + if (!gst_element_link_many(data.source, video_queue, video_convert, video_sink, NULL)) { + g_printerr("Couldn't link stream elements.\n"); + gst_object_unref(data.pipeline); + return -1; + } + + ret = gst_element_set_state(data.pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_printerr("Failed to start playing.\n"); + return -1; + } + + 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); + + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_ERROR: { + GError *err; + gchar *debug_info; + gst_message_parse_error(msg, &err, &debug_info); + g_printerr("Error received from element %s: %s\n", GST_ELEMENT_NAME(msg->src), err->message); + g_printerr("Debug info: %s\n", debug_info ? debug_info : "none"); + + g_error_free(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: + 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("Changed from state %d to state %d\n", old_state, new_state); + } + break; + default: + break; + } + + }while (!terminate); + + gst_object_unref(bus); + gst_element_set_state(data.pipeline, GST_STATE_NULL); + gst_object_unref(data.pipeline); + + return 0; +}