Hi I a beginner with GStreamer, I am clueless about of the behavior and role of some GStreamer elements.<br>I am trying to do a player with a transition-crossfade effect, it works for avi files, but without sound. My piplene was compound by the composition, queue and videosink elements.<br>
I was said I need to add an avidemuxer and I did, but doesn't work anymore.<br>I use this example as a base <a href="http://lists.freedesktop.org/archives/gstreamer-devel/2008-October/019240.html">http://lists.freedesktop.org/archives/gstreamer-devel/2008-October/019240.html</a>, but any adaptation didn't work for me. <br>
<br>This is the runtime error I got:<br><br>"GStreamer-CRITICAL **: gst_pad_link_full: assertion `GST_IS_PAD (sinkpad)' failed"<br><br>it seems it couldn't get the pad between the composition and the avidemuxer, I have been working around with decoders, but there are pad linking errors as well.<br>
<br>Thanks for any suggestion, regards<br><br>Rossana<br><br><br>This is the code and the pipeline is below it.<br><br><br><br><br>const gint dur_crossfade = 500;<br><br>static GstElement *play = NULL;<br>static GstElement *comp = NULL;<br>
static GstElement *op = NULL;<br>static GstElement *video1,*video2;<br><br>// error handler<br>static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)<br>{<br><br>// code for hadling errors<br> return TRUE;<br>
}<br><br>static void on_pad_added (GstElement *element, GstPad *pad, gpointer data)<br>{<br> GstPad *sinkpad = NULL;<br> GstElement * queue = (GstElement *) data;<br><br> g_print ("Dynamic pad created, linking queue\n");<br>
<br> sinkpad = gst_element_get_compatible_pad(queue,pad ,gst_pad_get_caps(pad));<br> gst_pad_link (pad, sinkpad);<br><br> gst_object_unref (sinkpad);<br><br>}<br><br>void on_pad_added2 (GstElement *element, GstPad *pad,GstElement *dec )<br>
{<br> g_debug ("Signal: pad-added");<br> GstCaps *caps;<br> GstStructure *str;<br><br> caps = gst_pad_get_caps (pad);<br> g_assert (caps != NULL);<br> str = gst_caps_get_structure (caps, 0);<br>
g_assert (str != NULL);<br><br> if (g_strrstr (gst_structure_get_name (str), "video")) {<br> g_debug ("Linking video pad to dec_vd");<br> // Link it actually<br>
GstPad *targetsink = gst_element_get_pad (dec, "sink");<br> g_assert (targetsink != NULL);<br> gst_pad_link (pad, targetsink);<br> gst_object_unref (targetsink);<br>
}<br><br> if (g_strrstr (gst_structure_get_name (str), "audio")) {<br> g_debug ("Linking audio pad to dec_ad");<br> // Link it actually<br> GstPad *targetsink = gst_element_get_pad (dec, "sink");<br>
g_assert (targetsink != NULL);<br> gst_pad_link (pad, targetsink);<br> gst_object_unref (targetsink);<br> }<br><br> gst_caps_unref (caps);<br>}<br><br>GstElement * getBin(const gchar * nomBin, GstElement * &alfa1, GstElement *&smpte, GstElement * &color, gint transicion = 1)<br>
{<br><br> GstElement * bin = gst_bin_new(nomBin);<br><br> if (!bin)<br> {<br> g_printerr ("No se pudo crear el bin. Saliendo\n");<br> return NULL;<br> }<br><br> alfa1 = gst_element_factory_make ("alpha","alfa1");<br>
smpte = gst_element_factory_make ("smptealpha","smpte");<br> color = gst_element_factory_make ("ffmpegcolorspace", "color");<br> GstElement * mixer = gst_element_factory_make("videomixer", "mixer");<br>
<br><br> if ((!alfa1) || (!smpte) || (!color) || (!mixer))<br> {<br> g_printerr ("Alguno de los elementos del Bin no pudo ser creado. Saliendo\n");<br> return NULL;<br> }<br><br> // Anexamos al bin<br>
gst_bin_add_many(GST_BIN (bin),alfa1,smpte,mixer,color,NULL);<br> <br> gst_element_link (alfa1, mixer);<br> gst_element_link (smpte, mixer);<br> gst_element_link (mixer,color);<br><br> g_object_set(smpte,"type", transicion, NULL);<br>
<br> return bin;<br>}<br><br>void getAndSetController(GstElement * smpte, gdouble duracion)<br>{<br> GstController * ctrl = NULL;<br> if (!(ctrl = gst_controller_new (G_OBJECT (smpte), "alpha",NULL))) {<br>
GST_WARNING ("No puede controlar el elemento fuente\n");<br> return;<br> }<br><br> GValue val_double = { 0, };<br> g_value_init (&val_double, G_TYPE_DOUBLE);<br><br> GstInterpolationControlSource * csource = gst_interpolation_control_source_new();<br>
gst_controller_set_control_source (ctrl, "alpha", GST_CONTROL_SOURCE (csource));<br><br> gst_interpolation_control_source_set_interpolation_mode(csource,GST_INTERPOLATE_LINEAR);<br><br> // Seteo primer valor<br>
g_value_set_double(&val_double, 0.0);<br> gst_interpolation_control_source_set(csource,(0 * GST_MSECOND),&val_double);<br><br> // Seteo segundo valor<br> g_value_set_double (&val_double, duracion);<br> gst_interpolation_control_source_set(csource,(1 * GST_MSECOND),&val_double);<br>
<br><br> g_object_unref (csource);<br><br>}<br><br>void addGhostPadsToBin(GstElement *alfa1, GstElement * smpte, GstElement * color, GstElement* bin)<br>{<br> /* add ghostpad */<br> GstPad * pad1 = gst_element_get_static_pad (alfa1, "sink");<br>
gst_element_add_pad(bin, gst_ghost_pad_new("alfasink1", pad1));<br> gst_object_unref (GST_OBJECT (pad1));<br><br> GstPad * pad2 = gst_element_get_static_pad (smpte, "sink");<br> gst_element_add_pad(bin, gst_ghost_pad_new("alfasink2", pad2));<br>
gst_object_unref(GST_OBJECT(pad2));<br><br> GstPad * pad3 = gst_element_get_static_pad (color, "src");<br> gst_element_add_pad(bin, gst_ghost_pad_new("colorsrc", pad3));<br> gst_object_unref(GST_OBJECT(pad3));<br>
<br>}<br><br>void crossTransicion(gdouble duracion, GstElement * & bin,gint transicion = 1)<br>{<br> // devuelve el bin<br> GstElement * alfa1, *smpte, *color;<br> alfa1 = 0;<br> smpte = 0;<br> color = 0;<br>
<br> bin = getBin("bin",alfa1, smpte,color,transicion); // Crea el bin y los elementos<br><br> getAndSetController(smpte,duracion);<br><br> addGhostPadsToBin(alfa1, smpte, color, bin);<br><br>}<br><br>
GstElement * crearVideo(const gchar *nomVideo, GstElement *&comp)<br>{<br> GstElement* video = NULL;<br> if ((video = gst_element_factory_make("gnlfilesource", nomVideo)) == NULL)<br> {<br> printf ("\n Falló la creacion del gnlfilesource \n");<br>
return NULL;<br> }<br><br><br> if (gst_bin_add (GST_BIN (comp), video) == FALSE)<br> {<br> printf ("\n No pudo agregar video %s a comp \n", nomVideo);<br> return NULL;<br> }<br><br> return video;<br>
}<br><br>void crearBinyCrossfade(GstElement *&op, GstElement *&bin2)<br>{<br> crossTransicion(dur_crossfade, bin2,1);<br><br> op = gst_element_factory_make("gnloperation", "op");<br><br> if (gst_bin_add (GST_BIN (op), bin2) == FALSE)<br>
{<br> printf ("\n No pudo agregar el bin a la gnloperacion op \n");<br> return;<br> }<br><br> // comp es Global<br> if (gst_bin_add (GST_BIN (comp), op) == FALSE)<br> {<br> printf ("\n No pudo agregar la gnloperacion a la gnlcomposition \n");<br>
return;<br> }<br>}<br><br>void crearCompYoper(GstElement*& compo, GstElement *&op, GstElement*& bin2)<br>{<br><br> if ((compo = gst_element_factory_make("gnlcomposition", "micomposicion")) == NULL)<br>
{<br> printf ("\n Fallo al crear gnlcomposition \n");<br> return;<br> }<br><br> //Aqui se crea el bin<br> crossTransicion(dur_crossfade, bin2,1);<br><br> op = gst_element_factory_make("gnloperation", "op");<br>
<br> if (gst_bin_add (GST_BIN (op), bin2) == FALSE)<br> {<br> printf ("\n No pudo agregar el bin a la gnloperacion op \n");<br> return;<br> }<br><br> if (gst_bin_add (GST_BIN (compo), op) == FALSE)<br>
{<br> printf ("\n No pudo agregar la gnloperacion a la gnlcomposition \n");<br> return;<br> }<br><br>}<br><br>/// Aqui pipeline3<br><br>GstElement * getPipeline3(gchar *argv[],GstElement *&video1, gint dur1, GstElement *& video2,GstElement *& comp, GstElement *&op)<br>
{<br> queueA, *sinkV,*sinkA, *decA, *decV, *demux, *pipeline, *aconvert,*bin;<br><br> crearCompYoper(comp, op,bin);<br><br> video1 = crearVideo("video1",comp);<br> video2 = crearVideo("video2",comp);<br>
<br> g_object_set (video1, "location", argv[1], NULL);<br> g_object_set(video1, "uri", argv[1],NULL);<br> g_object_set (video1, "start", 0 * GST_MSECOND, NULL);<br> g_object_set (video1, "duration", dur1 * GST_MSECOND, NULL);<br>
g_object_set (video1, "media-start", 0* GST_MSECOND, NULL);<br> g_object_set (video1, "media-duration", dur1 * GST_MSECOND, NULL);<br> g_object_set (video1, "priority", 1,NULL);<br>
<br> // setup the backend viewer<br> queueA = gst_element_factory_make("queue", "queueA");<br> queueV = gst_element_factory_make("queue", "queueV");<br> sinkV = gst_element_factory_make("autovideosink", "sink1");<br>
sinkA = gst_element_factory_make("alsasink", "sink2"); <br> demux = gst_element_factory_make("avidemux", "demux"); <br><br> pipeline = gst_pipeline_new ("video-player");<br>
<br> /* Agrego elementos al pipeline */<br><br> gst_bin_add_many (GST_BIN (pipeline),comp, demux, queueV, sinkV, queueA, sinkA, decA, NULL);<br><br> g_signal_connect (comp, "pad-added", G_CALLBACK (on_pad_added),demux);<br>
g_signal_connect (demux, "pad-added", G_CALLBACK (on_pad_added2),queueA);<br> g_signal_connect (demux, "pad-added", G_CALLBACK (on_pad_added2),queueV);<br><br> gst_element_link (comp, demux);<br>
gst_element_link (queueV, sinkV); <br> gst_element_link (queueA, sinkA); <br><br> return pipeline;<br>}<br><br><br>void playSigVideo(gchar *argv[], GstElement *& video1, gint dur1,GstElement *& video2, gint dur2,GstElement *&op, GstElement *pip)<br>
{<br><br> g_object_set (op,"start", (dur1 - dur_crossfade) * GST_MSECOND,NULL);<br> g_object_set (op,"duration", dur_crossfade * GST_MSECOND,NULL);<br> g_object_set (op,"media-start", 0 * GST_MSECOND,NULL);<br>
g_object_set(op,"media-duration", dur_crossfade * GST_MSECOND,NULL);<br> g_object_set(op,"priority",0,NULL);<br><br> g_object_set (video2, "location", argv[2], NULL);<br> g_object_set (video2,"uri",argv[2],NULL);<br>
g_object_set (video2, "start", (dur1 - dur_crossfade) * GST_MSECOND, NULL);<br> g_object_set (video2, "duration", dur2 * GST_MSECOND, NULL);<br> g_object_set (video2, "media-start", 0 * GST_MSECOND, NULL);<br>
g_object_set (video2, "media-duration", dur2 * GST_MSECOND, NULL);<br> g_object_set (video2, "priority", 2,NULL);<br> //g_object_set(video2,"caps",gst_caps_from_string("video/x-raw-yuv;video/x-raw-rgb"),NULL);<br>
//g_object_set(video2,"caps",gst_caps_from_string("audio/x-dv"),NULL);<br><br><br>}<br><br><br>void startPlay(GstElement * pip)<br>{<br> /* Set the pipeline to "playing" state*/<br> gst_element_set_state (pip, GST_STATE_PLAYING);<br>
<br>}<br><br><br>int main(gint argc, gchar *argv[])<br>{<br> gint dur1 = 9000; // d uration (in ms) to play of first clip<br> gint dur2 = 8000; // duration (in ms) to play of second clip<br> <br> GMainLoop *loop = NULL;<br>
<br> /* init GStreamer */<br> gst_init (&argc, &argv);<br> gst_controller_init (&argc, &argv);<br><br> loop = g_main_loop_new (NULL, FALSE);<br><br> /* chequeamos sintaxis */<br> if (argc != 3)<br>
{<br> g_print ("Uso: %s <URI1> <URI2>\n", argv[0]);<br> return -1;<br> }<br><br><br> play = getPipeline3(argv,video1, dur1,video2,comp, op);<br><br> playSigVideo(argv,video1,dur1,video2,dur2,op,play);<br>
<br> GstBus *bus2 = gst_pipeline_get_bus (GST_PIPELINE (play));<br> gst_bus_add_watch (bus2, bus_call, loop);<br> gst_object_unref (bus2);<br><br><br><br> cout << "...PLAY" << endl;<br><br>
startPlay(play);<br><br> /* now run */<br> g_main_loop_run (loop);<br><br> /* also clean up */<br> gst_element_set_state (play, GST_STATE_NULL);<br> gst_object_unref (GST_OBJECT (play));<br><br> return 0;<br>
}<br><br><br><pre>bin
-----------------------------------------------------------------------------------------------
alpha --------------------
|----------videomixer ------------fmpegcolorspace
smptealpha ----------
^
|
-----------------------------------------------------------------------------------------------
|
Controller // it controls the start-duration property of smptealpha
composition
--------------------------------------------------------------------------------------------------------
gnlfilesource
| gnloperation // contains the *bin*
described above
|
gnlfilesource
--------------------------------------------------------------------------------------------------------
gnlfilesource is for each video
pipeline
____________________
|
|
composition operation |___________ avidemux ____________ queueV ___________ sinkV
___________________ |
____________ queueA ___________ sinkA </pre><br>