Skip to content

Instantly share code, notes, and snippets.

@cfoch
Created April 8, 2020 06:05
Show Gist options
  • Save cfoch/bce6aa07ed4799af6c78cfed45d9b50c to your computer and use it in GitHub Desktop.
Save cfoch/bce6aa07ed4799af6c78cfed45d9b50c to your computer and use it in GitHub Desktop.
Sends manually created colored frames every 1 second
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include <string.h>
#define _STR(x) #x
#define STR(x) _STR(x)
#define WIDTH 640
#define HEIGHT 460
#define BUFFER_SIZE WIDTH * HEIGHT * 4
#define RED 0x000000FF
#define GREEN 0x00FF0000
#define BLUE 0x0000FF00
#define CAPS \
"caps=video/x-raw,format=RGBx,"\
"width=" STR(WIDTH) ","\
"height=" STR(HEIGHT) ","\
"framerate=30/1"
static GMainLoop *loop;
static guint feed_source_id;
static guint frame_number = 0;
static guint32 colors[] = { RED, GREEN, BLUE };
static gboolean push_data (gpointer user_data) {
GstElement *pipeline = GST_ELEMENT (user_data);
GstElement *src;
GstBuffer *buffer;
GstMapInfo map;
GstFlowReturn ret;
gint32 *raw_data;
guint i;
src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
buffer = gst_buffer_new_and_alloc (WIDTH * HEIGHT * 4);
GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (frame_number++, GST_SECOND, 1);
GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 1);
gst_buffer_map (buffer, &map, GST_MAP_WRITE);
raw_data = (guint32 *) map.data;
for (i = 0; i < WIDTH * HEIGHT; ++i) {
raw_data[i] = colors[frame_number % 3];
}
gst_buffer_unmap (buffer, &map);
g_signal_emit_by_name (src, "push-buffer", buffer, &ret);
g_object_unref (src);
if (ret != GST_FLOW_OK)
return FALSE;
return TRUE;
}
static void start_feed (GstElement *source, guint size, gpointer user_data) {
if (feed_source_id == 0) {
g_print ("Start feeding\n");
feed_source_id = g_idle_add ((GSourceFunc) push_data, user_data);
}
}
static void stop_feed (GstElement *source, gpointer user_data) {
if (feed_source_id != 0) {
g_source_remove (feed_source_id);
feed_source_id = 0;
}
}
static void
window_realize_cb (GtkWidget *window, gpointer user_data)
{
GstElement *pipeline = GST_ELEMENT (user_data);
GstElement *sink;
GtkWidget *viewer;
sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
g_object_get (G_OBJECT (sink), "widget", &viewer, NULL);
gtk_container_add (GTK_CONTAINER (window), viewer);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
gtk_widget_show (viewer);
g_object_unref (sink);
g_object_unref (viewer);
}
int
main (int argc, char ** argv)
{
GstElement *pipeline;
GstElement *src;
GtkWidget *window;
gst_init (&argc, &argv);
gtk_init (&argc, &argv);
g_print ("caps: %s\n", CAPS);
pipeline = gst_parse_launch (
"appsrc name=src " CAPS " ! videoconvert ! gtksink name=sink", NULL);
src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
g_signal_connect (src, "need-data", G_CALLBACK (start_feed), pipeline);
g_signal_connect (src, "enough-data", G_CALLBACK (stop_feed), NULL);
g_object_unref (src);
/* Create UI */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), WIDTH, HEIGHT);
g_signal_connect (window, "realize", G_CALLBACK (window_realize_cb),
pipeline);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (GTK_WIDGET (window));
gtk_main ();
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment