| /* GStreamer |
| * |
| * codec-select.c: sample application to dynamically select a codec |
| * |
| * Copyright (C) <2008> Wim Taymans <wim dot taymans at gmail dot com> |
| * |
| * 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., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| /* |
| * This example sets up a pipeline to 'encode' an audiotestsrc into 3 different |
| * formats. The format can be selected dynamically at runtime. |
| * |
| * Each of the encoders require the audio in a specific different format. |
| * |
| * This example uses identity as the encoder and enforces the caps on identity |
| * with a capsfilter. |
| * |
| * This is a good example of input and output selector and how these elements |
| * preserve segment and timing information while switching between streams. |
| */ |
| |
| #include <string.h> |
| #include <gst/gst.h> |
| |
| /* Create an encoder element. |
| * We make a bin containing: |
| * |
| * audioresample ! <enccaps> ! identity |
| * |
| * The sinkpad of audioresample and source pad of identity are ghosted on the |
| * bin. |
| */ |
| static GstElement * |
| make_encoder (const GstCaps * caps) |
| { |
| GstElement *result; |
| GstElement *audioresample; |
| GstElement *capsfilter; |
| GstElement *identity; |
| GstPad *pad; |
| |
| /* create result bin */ |
| result = gst_bin_new (NULL); |
| g_assert (result); |
| |
| /* create elements */ |
| audioresample = gst_element_factory_make ("audioresample", NULL); |
| g_assert (audioresample); |
| |
| capsfilter = gst_element_factory_make ("capsfilter", NULL); |
| g_assert (capsfilter); |
| g_object_set (capsfilter, "caps", caps, NULL); |
| |
| identity = gst_element_factory_make ("identity", NULL); |
| g_assert (identity); |
| g_object_set (identity, "silent", TRUE, NULL); |
| |
| /* add elements to result bin */ |
| gst_bin_add (GST_BIN (result), audioresample); |
| gst_bin_add (GST_BIN (result), capsfilter); |
| gst_bin_add (GST_BIN (result), identity); |
| |
| /* link elements */ |
| gst_element_link_pads (audioresample, "src", capsfilter, "sink"); |
| gst_element_link_pads (capsfilter, "src", identity, "sink"); |
| |
| /* ghost src and sink pads */ |
| pad = gst_element_get_static_pad (audioresample, "sink"); |
| gst_element_add_pad (result, gst_ghost_pad_new ("sink", pad)); |
| gst_object_unref (pad); |
| |
| pad = gst_element_get_static_pad (identity, "src"); |
| gst_element_add_pad (result, gst_ghost_pad_new ("src", pad)); |
| gst_object_unref (pad); |
| |
| return result; |
| } |
| |
| /* |
| * We generate: |
| * |
| * audiotestsrc ! <audiocaps> ! output-selector ! [enc1 .. enc3] ! input-selector |
| * select-all = true ! fakesink |
| * |
| * <audiocaps> makes sure we only produce one format from the audiotestsrc. |
| * |
| * Each encX element consists of: |
| * |
| * audioresample ! <enccaps> ! identity ! |
| * |
| * This way we can simply switch encoders without having to renegotiate. |
| */ |
| static GstElement * |
| make_pipeline (void) |
| { |
| GstElement *result; |
| GstElement *audiotestsrc; |
| GstElement *audiocaps; |
| GstElement *outputselect; |
| GstElement *inputselect; |
| GstElement *sink; |
| GstCaps *caps; |
| GstCaps *capslist[3]; |
| gint i; |
| |
| /* create result pipeline */ |
| result = gst_pipeline_new (NULL); |
| g_assert (result); |
| |
| /* create various elements */ |
| audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL); |
| g_object_set (audiotestsrc, "num-buffers", 1000, NULL); |
| g_assert (audiotestsrc); |
| |
| audiocaps = gst_element_factory_make ("capsfilter", NULL); |
| g_assert (audiocaps); |
| |
| caps = |
| gst_caps_from_string ("audio/x-raw,format=S16LE,rate=48000,channels=1"); |
| g_object_set (audiocaps, "caps", caps, NULL); |
| gst_caps_unref (caps); |
| |
| outputselect = gst_element_factory_make ("output-selector", "select"); |
| g_assert (outputselect); |
| |
| inputselect = gst_element_factory_make ("input-selector", NULL); |
| g_assert (inputselect); |
| g_object_set (inputselect, "select-all", TRUE, NULL); |
| |
| sink = gst_element_factory_make ("fakesink", NULL); |
| g_object_set (sink, "sync", TRUE, NULL); |
| g_object_set (sink, "silent", TRUE, NULL); |
| g_assert (sink); |
| |
| /* add elements */ |
| gst_bin_add (GST_BIN (result), audiotestsrc); |
| gst_bin_add (GST_BIN (result), audiocaps); |
| gst_bin_add (GST_BIN (result), outputselect); |
| gst_bin_add (GST_BIN (result), inputselect); |
| gst_bin_add (GST_BIN (result), sink); |
| |
| /* link elements */ |
| gst_element_link_pads (audiotestsrc, "src", audiocaps, "sink"); |
| gst_element_link_pads (audiocaps, "src", outputselect, "sink"); |
| gst_element_link_pads (inputselect, "src", sink, "sink"); |
| |
| /* make caps */ |
| capslist[0] = |
| gst_caps_from_string ("audio/x-raw,format=S16LE,rate=48000,channels=1"); |
| capslist[1] = |
| gst_caps_from_string ("audio/x-raw,format=S16LE,rate=16000,channels=1"); |
| capslist[2] = |
| gst_caps_from_string ("audio/x-raw,format=S16LE,rate=8000,channels=1"); |
| |
| /* create encoder elements */ |
| for (i = 0; i < 3; i++) { |
| GstElement *encoder; |
| GstPad *srcpad, *sinkpad; |
| |
| encoder = make_encoder (capslist[i]); |
| g_assert (encoder); |
| |
| gst_bin_add (GST_BIN (result), encoder); |
| |
| srcpad = gst_element_get_request_pad (outputselect, "src_%u"); |
| sinkpad = gst_element_get_static_pad (encoder, "sink"); |
| gst_pad_link (srcpad, sinkpad); |
| gst_object_unref (srcpad); |
| gst_object_unref (sinkpad); |
| |
| srcpad = gst_element_get_static_pad (encoder, "src"); |
| sinkpad = gst_element_get_request_pad (inputselect, "sink_%u"); |
| gst_pad_link (srcpad, sinkpad); |
| gst_object_unref (srcpad); |
| gst_object_unref (sinkpad); |
| } |
| |
| return result; |
| } |
| |
| static gboolean |
| do_switch (GstElement * pipeline) |
| { |
| gint rand; |
| GstElement *select; |
| gchar *name; |
| GstPad *pad; |
| |
| rand = g_random_int_range (0, 3); |
| |
| g_print ("switching to %d\n", rand); |
| |
| /* find the selector */ |
| select = gst_bin_get_by_name (GST_BIN (pipeline), "select"); |
| |
| /* get the named pad */ |
| name = g_strdup_printf ("src_%u", rand); |
| pad = gst_element_get_static_pad (select, name); |
| g_free (name); |
| |
| /* set the active pad */ |
| g_object_set (select, "active-pad", pad, NULL); |
| gst_object_unref (select); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| my_bus_callback (GstBus * bus, GstMessage * message, gpointer data) |
| { |
| GstElement *sender = (GstElement *) GST_MESSAGE_SRC (message); |
| gchar *name = gst_element_get_name (sender); |
| GMainLoop *loop = (GMainLoop *) data; |
| |
| g_print ("Got %s message from %s\n", GST_MESSAGE_TYPE_NAME (message), name); |
| g_free (name); |
| |
| 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: |
| /* end-of-stream */ |
| g_main_loop_quit (loop); |
| break; |
| default: |
| /* unhandled message */ |
| break; |
| } |
| |
| return TRUE; |
| } |
| |
| gint |
| main (gint argc, gchar * argv[]) |
| { |
| GstElement *pipeline; |
| GstBus *bus; |
| GMainLoop *loop; |
| |
| /* init GStreamer */ |
| gst_init (&argc, &argv); |
| loop = g_main_loop_new (NULL, FALSE); |
| |
| /* set up */ |
| pipeline = make_pipeline (); |
| |
| g_signal_connect (pipeline, "deep_notify", |
| G_CALLBACK (gst_object_default_deep_notify), NULL); |
| |
| bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); |
| gst_bus_add_watch (bus, my_bus_callback, loop); |
| gst_object_unref (bus); |
| |
| g_print ("Starting pipeline\n"); |
| |
| gst_element_set_state (pipeline, GST_STATE_PLAYING); |
| |
| /* add a timeout to cycle between the formats */ |
| g_timeout_add_seconds (1, (GSourceFunc) do_switch, pipeline); |
| |
| /* now run */ |
| g_main_loop_run (loop); |
| |
| g_print ("Nulling pipeline\n"); |
| |
| /* also clean up */ |
| gst_element_set_state (pipeline, GST_STATE_NULL); |
| gst_object_unref (pipeline); |
| |
| return 0; |
| } |