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&#39;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&#39;t work for me. <br>
<br>This is the runtime error I got:<br><br>&quot;GStreamer-CRITICAL **: gst_pad_link_full: assertion `GST_IS_PAD (sinkpad)&#39; failed&quot;<br><br>it seems it couldn&#39;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 (&quot;Dynamic pad created, linking queue\n&quot;);<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 (&quot;Signal: pad-added&quot;);<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), &quot;video&quot;)) {<br>                g_debug (&quot;Linking video pad to dec_vd&quot;);<br>                // Link it actually<br>
                GstPad *targetsink = gst_element_get_pad (dec, &quot;sink&quot;);<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), &quot;audio&quot;)) {<br>                g_debug (&quot;Linking audio pad to dec_ad&quot;);<br>                // Link it actually<br>                GstPad *targetsink = gst_element_get_pad (dec, &quot;sink&quot;);<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 * &amp;alfa1, GstElement *&amp;smpte, GstElement * &amp;color, gint transicion = 1)<br>
{<br><br>  GstElement * bin = gst_bin_new(nomBin);<br><br>  if (!bin)<br>  {<br>      g_printerr (&quot;No se pudo crear el bin. Saliendo\n&quot;);<br>     return NULL;<br>  }<br><br>  alfa1   = gst_element_factory_make (&quot;alpha&quot;,&quot;alfa1&quot;);<br>
  smpte  = gst_element_factory_make (&quot;smptealpha&quot;,&quot;smpte&quot;);<br>  color  = gst_element_factory_make (&quot;ffmpegcolorspace&quot;, &quot;color&quot;);<br>  GstElement * mixer  = gst_element_factory_make(&quot;videomixer&quot;, &quot;mixer&quot;);<br>
<br><br>  if ((!alfa1) || (!smpte) || (!color) || (!mixer))<br>  {<br>      g_printerr (&quot;Alguno de los elementos del Bin no pudo ser creado. Saliendo\n&quot;);<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,&quot;type&quot;, 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), &quot;alpha&quot;,NULL))) {<br>
        GST_WARNING (&quot;No puede controlar el elemento fuente\n&quot;);<br>        return;<br>   }<br><br>  GValue val_double = { 0, };<br>  g_value_init (&amp;val_double, G_TYPE_DOUBLE);<br><br>  GstInterpolationControlSource * csource = gst_interpolation_control_source_new();<br>
  gst_controller_set_control_source (ctrl, &quot;alpha&quot;, 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(&amp;val_double, 0.0);<br>  gst_interpolation_control_source_set(csource,(0 * GST_MSECOND),&amp;val_double);<br><br>  // Seteo segundo valor<br>  g_value_set_double (&amp;val_double, duracion);<br>  gst_interpolation_control_source_set(csource,(1 * GST_MSECOND),&amp;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, &quot;sink&quot;);<br>
  gst_element_add_pad(bin, gst_ghost_pad_new(&quot;alfasink1&quot;, pad1));<br>  gst_object_unref (GST_OBJECT (pad1));<br><br>  GstPad * pad2 = gst_element_get_static_pad (smpte, &quot;sink&quot;);<br>  gst_element_add_pad(bin, gst_ghost_pad_new(&quot;alfasink2&quot;, pad2));<br>
  gst_object_unref(GST_OBJECT(pad2));<br><br>  GstPad * pad3 = gst_element_get_static_pad (color, &quot;src&quot;);<br>  gst_element_add_pad(bin, gst_ghost_pad_new(&quot;colorsrc&quot;, pad3));<br>  gst_object_unref(GST_OBJECT(pad3));<br>
<br>}<br><br>void crossTransicion(gdouble duracion, GstElement * &amp; 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(&quot;bin&quot;,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 *&amp;comp)<br>{<br>  GstElement* video = NULL;<br>  if ((video = gst_element_factory_make(&quot;gnlfilesource&quot;, nomVideo)) == NULL)<br>    {<br>      printf (&quot;\n Falló la creacion del gnlfilesource \n&quot;);<br>
      return NULL;<br>    }<br><br><br>    if (gst_bin_add (GST_BIN (comp), video) == FALSE)<br>    {<br>      printf (&quot;\n No pudo agregar video %s a comp \n&quot;, nomVideo);<br>      return NULL;<br>    }<br><br>    return video;<br>
}<br><br>void crearBinyCrossfade(GstElement *&amp;op, GstElement *&amp;bin2)<br>{<br>    crossTransicion(dur_crossfade, bin2,1);<br><br>    op = gst_element_factory_make(&quot;gnloperation&quot;, &quot;op&quot;);<br><br>    if (gst_bin_add (GST_BIN (op), bin2) == FALSE)<br>
    {<br>      printf (&quot;\n No pudo agregar el bin a la gnloperacion op \n&quot;);<br>      return;<br>    }<br><br>    // comp es Global<br>    if (gst_bin_add (GST_BIN (comp), op) == FALSE)<br>    {<br>      printf (&quot;\n No pudo agregar la gnloperacion a la gnlcomposition \n&quot;);<br>
      return;<br>    }<br>}<br><br>void crearCompYoper(GstElement*&amp; compo, GstElement *&amp;op, GstElement*&amp; bin2)<br>{<br><br>    if ((compo = gst_element_factory_make(&quot;gnlcomposition&quot;, &quot;micomposicion&quot;)) == NULL)<br>
    {<br>      printf (&quot;\n Fallo al crear gnlcomposition \n&quot;);<br>      return;<br>    }<br><br>    //Aqui se crea el bin<br>    crossTransicion(dur_crossfade, bin2,1);<br><br>    op = gst_element_factory_make(&quot;gnloperation&quot;, &quot;op&quot;);<br>
<br>    if (gst_bin_add (GST_BIN (op), bin2) == FALSE)<br>    {<br>      printf (&quot;\n No pudo agregar el bin a la gnloperacion op \n&quot;);<br>      return;<br>    }<br><br>    if (gst_bin_add (GST_BIN (compo), op) == FALSE)<br>
    {<br>      printf (&quot;\n No pudo agregar la gnloperacion a la gnlcomposition \n&quot;);<br>      return;<br>    }<br><br>}<br><br>/// Aqui pipeline3<br><br>GstElement * getPipeline3(gchar *argv[],GstElement *&amp;video1, gint dur1, GstElement *&amp; video2,GstElement *&amp; comp, GstElement *&amp;op)<br>
{<br>    queueA, *sinkV,*sinkA, *decA, *decV, *demux, *pipeline, *aconvert,*bin;<br><br>    crearCompYoper(comp, op,bin);<br><br>    video1 = crearVideo(&quot;video1&quot;,comp);<br>    video2 = crearVideo(&quot;video2&quot;,comp);<br>
<br>    g_object_set (video1, &quot;location&quot;, argv[1], NULL);<br>    g_object_set(video1, &quot;uri&quot;, argv[1],NULL);<br>    g_object_set (video1, &quot;start&quot;, 0 * GST_MSECOND, NULL);<br>    g_object_set (video1, &quot;duration&quot;, dur1 * GST_MSECOND, NULL);<br>
    g_object_set (video1, &quot;media-start&quot;, 0* GST_MSECOND, NULL);<br>    g_object_set (video1, &quot;media-duration&quot;, dur1 * GST_MSECOND, NULL);<br>    g_object_set (video1, &quot;priority&quot;, 1,NULL);<br>
   <br>    // setup the backend viewer<br>    queueA = gst_element_factory_make(&quot;queue&quot;, &quot;queueA&quot;);<br>    queueV = gst_element_factory_make(&quot;queue&quot;, &quot;queueV&quot;);<br>    sinkV  = gst_element_factory_make(&quot;autovideosink&quot;, &quot;sink1&quot;);<br>
    sinkA  = gst_element_factory_make(&quot;alsasink&quot;, &quot;sink2&quot;);    <br>    demux = gst_element_factory_make(&quot;avidemux&quot;, &quot;demux&quot;);    <br><br>    pipeline = gst_pipeline_new (&quot;video-player&quot;);<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, &quot;pad-added&quot;, G_CALLBACK (on_pad_added),demux);<br>
    g_signal_connect (demux, &quot;pad-added&quot;, G_CALLBACK (on_pad_added2),queueA);<br>    g_signal_connect (demux, &quot;pad-added&quot;, 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 *&amp; video1, gint dur1,GstElement *&amp; video2, gint dur2,GstElement *&amp;op, GstElement *pip)<br>
{<br><br>    g_object_set (op,&quot;start&quot;, (dur1 - dur_crossfade) * GST_MSECOND,NULL);<br>    g_object_set (op,&quot;duration&quot;, dur_crossfade *  GST_MSECOND,NULL);<br>    g_object_set (op,&quot;media-start&quot;, 0 *  GST_MSECOND,NULL);<br>
    g_object_set(op,&quot;media-duration&quot;, dur_crossfade * GST_MSECOND,NULL);<br>    g_object_set(op,&quot;priority&quot;,0,NULL);<br><br>    g_object_set (video2, &quot;location&quot;, argv[2], NULL);<br>    g_object_set (video2,&quot;uri&quot;,argv[2],NULL);<br>
    g_object_set (video2, &quot;start&quot;, (dur1  - dur_crossfade) * GST_MSECOND, NULL);<br>    g_object_set (video2, &quot;duration&quot;, dur2 * GST_MSECOND, NULL);<br>    g_object_set (video2, &quot;media-start&quot;, 0 * GST_MSECOND, NULL);<br>
    g_object_set (video2, &quot;media-duration&quot;, dur2 * GST_MSECOND, NULL);<br>    g_object_set (video2, &quot;priority&quot;, 2,NULL);<br>    //g_object_set(video2,&quot;caps&quot;,gst_caps_from_string(&quot;video/x-raw-yuv;video/x-raw-rgb&quot;),NULL);<br>
    //g_object_set(video2,&quot;caps&quot;,gst_caps_from_string(&quot;audio/x-dv&quot;),NULL);<br><br><br>}<br><br><br>void startPlay(GstElement * pip)<br>{<br>    /* Set the pipeline to &quot;playing&quot; 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 (&amp;argc, &amp;argv);<br>    gst_controller_init (&amp;argc, &amp;argv);<br><br>    loop = g_main_loop_new (NULL, FALSE);<br><br>    /* chequeamos sintaxis */<br>    if (argc != 3)<br>
    {<br>        g_print (&quot;Uso: %s &lt;URI1&gt;  &lt;URI2&gt;\n&quot;, 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 &lt;&lt; &quot;...PLAY&quot; &lt;&lt; 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>