Skip to content

Instantly share code, notes, and snippets.

@paulbarber
Last active November 23, 2021 14:16
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paulbarber/7d2e43d1e3365b2042aa to your computer and use it in GitHub Desktop.
Save paulbarber/7d2e43d1e3365b2042aa to your computer and use it in GitHub Desktop.
Test of GStreamer saving to file from C code
gst-launch-1.0 videotestsrc num-buffers=100 ! tee name=t ! queue ! videoconvert ! xvimagesink sync=false t. ! queue ! videorate ! video/x-raw,framerate=25/1 ! videoconvert ! avenc_mpeg2video bitrate=3000000 ! avimux ! filesink location=test_file.avi async=0
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gst-app.h"
int
main (int argc, char *argv[])
{
// Before calling any GLib or GStreamer function, we must initialise
// the GLib threading system
if (!g_thread_supported())
g_thread_init (NULL);
gst_init(&argc, &argv);
// For this test, just go straight to playing some pipeline
play_camera();
return 0;
}
/* Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "play.h"
static GMainLoop *loop;
static gboolean
my_bus_callback (GstBus *bus, GstMessage *message, gpointer data)
{
g_print("Got %s message from %s\n", GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_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 (%s)\n", err->message, debug);
g_error_free(err);
g_free(debug);
g_main_loop_quit(loop);
break;
}
case GST_MESSAGE_EOS:
g_main_loop_quit(loop);
break;
default:
break;
}
return TRUE; // continue to watch for messages
}
void
play_camera(void)
{
GstBus *bus;
guint bus_watch_id;
GstElement *pipeline;
GstElement *videoconvert1, *videoconvert2;
GstElement *sink;
GstElement *tee;
GstElement *frameratefilter, *videorate;
GstElement *queue1, *queue2;
GstElement *avenc, *avimux;
GstElement *filesink;
GstElement *source;
GstPadTemplate *tee_src_pad_template;
GstPad *teepad1, *teepad2, *qpad1, *qpad2;
// The full video pipeline
pipeline = gst_pipeline_new("VideoPipeline");
// Create pipeline elements
source = gst_element_factory_make("videotestsrc", NULL);
videoconvert1 = gst_element_factory_make("videoconvert", "videoconvert1");
videoconvert2 = gst_element_factory_make("videoconvert", "videoconvert2");
queue1 = gst_element_factory_make("queue", "queue1");
queue2 = gst_element_factory_make("queue", "queue2");
tee = gst_element_factory_make("tee", "tee");
sink = gst_element_factory_make("xvimagesink", NULL);
frameratefilter = gst_element_factory_make("capsfilter", NULL);
videorate = gst_element_factory_make("videorate", NULL);
avenc = gst_element_factory_make("avenc_mpeg2video", NULL);
avimux = gst_element_factory_make("avimux", NULL);
filesink = gst_element_factory_make("filesink", NULL);
// check the elements
if(!source || !videoconvert1 || !videoconvert2 || !queue1 || !queue2 || !tee || !sink || !filesink){
g_error("Creation of one element failed.");
return;
}
// Set parameters for some elements
g_object_set(G_OBJECT(source), "num-buffers", 100, NULL);
g_object_set(G_OBJECT(filesink), "location", "AFileFromCode.avi", "async", 0, NULL);
g_object_set(G_OBJECT(frameratefilter), "caps", gst_caps_from_string("video/x-raw,framerate=25/1"), NULL);
g_print ("Add elements to a bin ... \n");
gst_bin_add_many(GST_BIN(pipeline), source, videoconvert1, videoconvert2, queue1, queue2, tee, sink, frameratefilter, videorate, avenc, avimux, filesink, NULL);
g_print ("and link them ... \n");
if (!gst_element_link_many(source, tee, NULL))
g_error("Failed to link source elements!");
if (!gst_element_link_many(queue1, videoconvert1, sink, NULL))
g_error("Failed to link display elements!");
if (!gst_element_link_many(queue2, videorate, frameratefilter, videoconvert2, avenc, avimux, filesink, NULL))
g_error("Failed to link save elements!");
if ( !(tee_src_pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (tee), "src_%u"))) {
g_critical ("Unable to get pad template!");
return;
}
// get the queue pads and request some source pads from the tee
qpad1 = gst_element_get_static_pad(queue1, "sink");
qpad2 = gst_element_get_static_pad(queue2, "sink");
teepad1 = gst_element_request_pad (tee, tee_src_pad_template, NULL, NULL);
g_print ("Obtained request pad %s for queue1 branch.\n", gst_pad_get_name (teepad1));
teepad2 = gst_element_request_pad (tee, tee_src_pad_template, NULL, NULL);
g_print ("Obtained request pad %s for queue2 branch.\n", gst_pad_get_name (teepad2));
if(!teepad1 || !teepad2 || !qpad1 || !qpad2){
g_error("Creation of one tee pad failed.");
return;
}
gst_pad_link (teepad1, qpad1);
gst_pad_link (teepad2, qpad2);
gst_object_unref (GST_OBJECT (qpad1));
gst_object_unref (GST_OBJECT (qpad2));
gst_object_unref (GST_OBJECT (teepad1));
gst_object_unref (GST_OBJECT (teepad2));
// Output a dot file of the pipeline
// Be sure to $ export GST_DEBUG_DUMP_DOT_DIR=/tmp
// and run with the --gst-enable-gst-debug command line switch
GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline_graph");
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
bus_watch_id = gst_bus_add_watch (bus, my_bus_callback, NULL);
gst_object_unref(bus);
g_print ("Play the pipeline ... \n");
gst_element_set_state(pipeline, GST_STATE_PLAYING);
// To receive messages on the bus callback, start a main loop here, and unref below
g_print ("Start g_main_loop ... \n");
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
g_print ("Stop the pipeline ... \n");
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
g_main_loop_unref(loop);
return;
}
#ifndef _MY_APP_PLAY_H_INCLUDED_
#define _MY_APP_PLAY_H_INCLUDED_
#include <gst/gst.h>
void play_camera(void);
#endif /* _MY_APP_PLAY_H_INCLUDED_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment