I am making a video recording program that takes input from a v4l2 webcam and outputs to an avi file. Using gstreamer in c, I have got most of the program to work, and the file is created. I can get the pipeline to display the video to the screen, but I can't get the video file to record anything. It compiles, but I get some run-time errors that allow the program to keep running. If anyone could help, that would be great.
The program is compiled by the following (on a Linux box): gcc -Wall $(pkg-config --cflags --libs gstreamer-0.10) videorecord.c -o recorder
And run by ./recorder testvid.avi
Errors:
(gst-plugin-scanner:3501): GLib-GObject-WARNING **: specified instance size for type `GstRTPBVPay' is smaller than the parent type's `GstBaseRTPAudioPayload' instance size
(gst-plugin-scanner:3501): GLib-CRITICAL **: g_once_init_leave: assertion `initialization_value != 0' failed
(gst-plugin-scanner:3501): GStreamer-CRITICAL **: gst_element_register: assertion `g_type_is_a (type, GST_TYPE_ELEMENT)' failed
(gst-plugin-scanner:3501): GStreamer-CRITICAL **: Could not convert static caps "image/png, width = (int) [ 16, 4096 ], height = (int) [ 16, 4096 ], framerate = (fraction) [ 0.0, MAX ]"
This program is linked against GStreamer 0.10.34
(recorder:3500): GStreamer-CRITICAL **: gst_pad_link_full: assertion `GST_IS_PAD (sinkpad)' failed
(recorder:3500): GStreamer-CRITICAL **: gst_ghost_pad_new: assertion `GST_IS_PAD (target)' failed
(recorder:3500): GStreamer-CRITICAL **: gst_element_add_pad: assertion `GST_IS_PAD (pad)' failed
(recorder:3500): GStreamer-CRITICAL **: gst_pad_set_caps: assertion `GST_IS_PAD (pad)' failed
(recorder:3500): GStreamer-CRITICAL **: gst_pad_link_full: assertion `GST_IS_PAD (srcpad)' failed
(recorder:3500): GStreamer-CRITICAL **: gst_ghost_pad_new: assertion `GST_IS_PAD (target)' failed
(recorder:3500): GStreamer-CRITICAL **: gst_element_add_pad: assertion `GST_IS_PAD (pad)' failed
(recorder:3500): GStreamer-CRITICAL **: gst_pad_link_full: assertion `GST_IS_PAD (srcpad)' failed
(recorder:3500): GStreamer-CRITICAL **: gst_ghost_pad_new: assertion `GST_IS_PAD (target)' failed
(recorder:3500): GStreamer-CRITICAL **: gst_element_add_pad: assertion `GST_IS_PAD (pad)' failed
Code (videorecord.c):
#include <gst/gst.h>
#include <glib.h>
static gboolean
bus_call (GstBus *bus,
GstMessage *msg,
gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
g_print ("End of stream\n");
g_main_loop_quit (loop);
break;
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *error;
gst_message_parse_error (msg, &error, &debug);
g_free (debug);
g_printerr ("Error: %s\n", error->message);
g_error_free (error);
g_main_loop_quit (loop);
break;
}
default:
break;
}
return TRUE;
}
static void
on_pad_added (GstElement *element,
GstPad *pad,
gpointer data)
{
GstPad *sinkpad;
GstElement *source1 = (GstElement *) data;
g_print ("Dynamic pad created, linking ...\n");
sinkpad = gst_element_get_static_pad (source1, "output1");
gst_pad_link (pad, sinkpad);
gst_object_unref (sinkpad);
}
int main (int argc, char *argv[])
{
guint major, minor, micro, nano;
gst_init (&argc, &argv);
gst_version (&major, &minor, µ, &nano);
printf ("This program is linked against GStreamer %d.%d.%d \n",
major, minor, micro);
GMainLoop *loop;
GstElement *pipeline;
GstElement *source1, *encoder1, *muxer, *output2;
GstBus *bus;
loop = g_main_loop_new (NULL, FALSE);
pipeline = gst_pipeline_new ("video-pipeline");
source1 = gst_element_factory_make("v4l2src", "video-source"); //video input from webcam
encoder1 = gst_element_factory_make("x264enc", "video-encoder"); //video encoder for input
muxer = gst_element_factory_make("avimux", "combining-muxer"); //muxer for A/V streams
output2 = gst_element_factory_make("filesink", "file-output"); //combo output to file
if(!source1 | !encoder1 | !muxer | !output2)
{ printf ("One element could not be created. Exiting.\n");
return -1; }
g_object_set (G_OBJECT (output2), "location", argv[1], NULL); //set the ouput filename to the sink element
GstCaps *caps1;
caps1 = gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING, "byte-stream", "alignment", G_TYPE_STRING, "au", "width", G_TYPE_INT, 320, "height", G_TYPE_INT, 240, NULL);
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
GstPad *sinkpadvideo, *srcpadvideo;
srcpadvideo = gst_element_get_static_pad(source1, "src");
sinkpadvideo = gst_element_get_request_pad(encoder1, "e264");
gst_pad_link(srcpadvideo, sinkpadvideo);
gst_element_link(source1, encoder1); //linking v4l2src to x264enc
gst_element_add_pad(pipeline, gst_ghost_pad_new("ghst-pad-enc", sinkpadvideo));
g_signal_connect(source1, "pad-added", G_CALLBACK(on_pad_added), encoder1);
srcpadvideo = gst_element_get_static_pad(encoder1, "e264");
sinkpadvideo = gst_element_get_request_pad(muxer, "mux");
gst_pad_set_caps(sinkpadvideo, caps1); //set caps to avimux
gst_pad_link(srcpadvideo, sinkpadvideo);
gst_element_link(encoder1, muxer); //linking x264enc to avimux
gst_element_add_pad(pipeline, gst_ghost_pad_new("ghst-pad-mux", sinkpadvideo));
g_signal_connect(encoder1, "pad-added", G_CALLBACK(on_pad_added), muxer);
srcpadvideo = gst_element_get_static_pad(muxer, "mux");
sinkpadvideo = gst_element_get_request_pad(output2, "sink");
gst_pad_link(srcpadvideo, sinkpadvideo);
gst_element_link(muxer, output2); //linking avimux to filesink
gst_element_add_pad(pipeline, gst_ghost_pad_new("ghst-pad-rec", sinkpadvideo));
g_signal_connect(muxer, "pad-added", G_CALLBACK(on_pad_added), output2);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_bin_add_many (GST_BIN (pipeline), source1, encoder1, muxer, output2, NULL);
gst_element_link_many (source1, encoder1, muxer, output2, NULL);
gst_element_link(source1, output2);
g_signal_connect (source1, "pad-added", G_CALLBACK (on_pad_added), output2);
g_print ("Now recording to file: %s\n", argv[1]);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
g_print ("Ending recording\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
g_print ("Cleaning...\n");
gst_object_unref (GST_OBJECT (pipeline));