GStreamer + AVI (made in C!)

This is a GStreamer test application similar to the one presented here, but with AVI support. While it isn't hard to get a gst-launch (cf. code) working, creating a working pipeline programmatically is a bit more tricky due to callbacks and the like. This example works at least with I420 (YUV) input format, it was created just for testing, hence the "image processing" part is only a mirroring of the luma part, leaving chroma aside (i.e. even un-initialized, leading to nice ghost color effects).

Maybe this one helps the one or the other who wants to test a video plugin or who wants to just implement GStreamer pipelines and bins from scratch.

#include <gst/gst.h> static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data) { GMainLoop *loop = 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 = NULL; GError *err = NULL; gst_message_parse_error (msg, &err, &debug); g_print ("Error: %s\n", err->message); g_error_free (err); if (debug) { g_print ("Debug details: %s\n", debug); g_free (debug); } g_main_loop_quit (loop); break; } default: break; } return TRUE; } GstElement *pipeline,*filesrc, *avidemux, *decodera, *audioconvert, *audioresample, *asink, *queuea, *queuev, *decoderv, *csc, *vscale, *vsink, *filter; static void on_decpad_added(GstElement *element, GstPad *pad ) { g_debug ("Signal: decoder pad-added"); GstCaps *caps; GstStructure *str; caps = gst_pad_get_caps (pad); g_assert (caps != NULL); str = gst_caps_get_structure (caps, 0); g_assert (str != NULL); g_debug ("Linking video pad to queue_vd"); // Link it actually GstPad *targetsink = gst_element_get_pad (element == decodera ? queuea : queuev, "sink"); g_assert (targetsink != NULL); gst_pad_link (pad, targetsink); gst_object_unref (targetsink); gst_caps_unref (caps); } static void on_pad_added (GstElement *element, GstPad *pad) { g_debug ("Signal: pad-added"); GstCaps *caps; GstStructure *str; caps = gst_pad_get_caps (pad); g_assert (caps != NULL); str = gst_caps_get_structure (caps, 0); g_assert (str != NULL); const gchar *c = gst_structure_get_name(str); if (g_strrstr (c, "video") || g_strrstr (c, "image")) { g_debug ("Linking video pad to dec_vd"); // Link it actually GstPad *targetsink = gst_element_get_pad (decoderv, "sink"); g_assert (targetsink != NULL); gst_pad_link (pad, targetsink); gst_object_unref (targetsink); } if (g_strrstr (c, "audio")) { g_debug ("Linking audio pad to dec_ad"); // Link it actually GstPad *targetsink = gst_element_get_pad (decodera, "sink"); g_assert (targetsink != NULL); gst_pad_link (pad, targetsink); gst_object_unref (targetsink); } gst_caps_unref (caps); } void g_ass(gboolean b) { /* if(!b)g_debug("Error"); else g_debug("OK");*/ } gint main (gint argc, gchar *argv[]) { GstStateChangeReturn ret; GMainLoop *loop; GstBus *bus; /* initialization */ gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); if (argc != 2) { g_print ("Usage: %s <avi filename>\n", argv[0]); return 01; } /* * command line: * gst-launch filesrc location=/home/myself/r0013001.avi ! avidemux name=demux demux.audio_00 ! decodebin ! queue ! audioconvert ! audioresample ! autoaudiosink demux.video_00 ! decodebin ! queue ! ffmpegcolorspace ! videoscale ! autovideosink * */ /* create elements */ pipeline = gst_pipeline_new ("pipeline0"); /* watch for messages on the pipeline's bus (note that this will only * work like this when a GLib main loop is running) */ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_add_watch (bus, bus_call, loop); gst_object_unref (bus); filesrc = gst_element_factory_make ("filesrc", "filesource"); avidemux = gst_element_factory_make ("avidemux", "dmux"); decodera = gst_element_factory_make ("decodebin", "decoder0"); decoderv = gst_element_factory_make ("decodebin", "decoder1"); vscale = gst_element_factory_make ("videoscale", "Scaler"); /* putting an audioconvert element here to convert the output of the * decoder into a format that my_filter can handle (we are assuming it * will handle any sample rate here though) */ audioconvert = gst_element_factory_make ("audioconvert", "audioconvert1"); queuea = gst_element_factory_make ("queue", "queue0"); queuev = gst_element_factory_make ("queue", "queue1"); /* there should always be audioconvert and audioresample elements before * the audio sink, since the capabilities of the audio sink usually vary * depending on the environment (output used, sound card, driver etc.) */ audioresample = gst_element_factory_make ("audioresample", "audioresample0"); csc = gst_element_factory_make ("ffmpegcolorspace", "ffmpegcsp0"); vsink = gst_element_factory_make ("autovideosink", "Video Renderer"); asink = gst_element_factory_make ("autoaudiosink", "AudioSink"); /* the test-filter */ filter = gst_element_factory_make ("myFilter", "My Filter"); if (!filter) { g_print ("Your self-written filter could not be found. Make sure it " "is installed correctly in $(libdir)/gstreamer-0.10/ or " "~/.gstreamer-0.10/plugins/ and that gst-inspect-0.10 lists it.\n " "If it doesn't, check with 'GST_DEBUG=*:2 gst-inspect-0.10' for " "the reason why it is not being loaded. (or set the GST_PLUGIN_PATH - env variable)"); return -1; } g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); gst_bin_add_many (GST_BIN (pipeline), filesrc, avidemux, filter, decodera, audioconvert, audioresample, asink, queuev, queuea, decoderv, csc, vscale, vsink, NULL); g_ass(gst_element_link (filesrc, avidemux)); g_ass(gst_element_link (queuev, filter)); g_ass(gst_element_link (filter, csc)); g_ass(gst_element_link (csc, vscale)); g_ass(gst_element_link (vscale, vsink)); g_ass(gst_element_link (queuea, audioconvert)); g_ass(gst_element_link (audioconvert, audioresample)); g_ass(gst_element_link (audioresample, asink)); g_signal_connect (avidemux, "pad-added", G_CALLBACK (on_pad_added), NULL); g_signal_connect (decodera, "pad-added", G_CALLBACK (on_decpad_added), decodera); g_signal_connect (decoderv, "pad-added", G_CALLBACK (on_decpad_added), decoderv); /* run */ ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) { GstMessage *msg; g_print ("Failed to start up pipeline!\n"); /* check if there is an error message with details on the bus */ msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0); if (msg) { GError *err = NULL; gst_message_parse_error (msg, &err, NULL); g_print ("ERROR: %s\n", err->message); g_error_free (err); gst_message_unref (msg); } return -1; } g_main_loop_run (loop); /* clean up */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); return 0; }