Crossfading-transition between more than 2 videos.

Rossana Guerra guerra.rossana at gmail.com
Sat Sep 24 23:29:21 PDT 2011


Hello everyone, I am trying to do crossfade between 3 videos. It works fine
when I do the same with 2, but when I put the 3rd something happens and the
player displays only the first.
Actually I use 2 videos, and I did a playlist such video1 -> video2 ->
video2, where the 3rd time, I set the new starting time of the video2
object.

video1 starts at 0, and its durations is dur1
I use an operator to handle the alpha channel, it starts at dur1 -
dur_crossfade
video2, starts at dur1 - dur_crossfade
And the starting time of video 2 the third time is dur1 + dur2 -
dur_crossfade.

Maybe it's something wrong with the priority or start properties values, I
am very new with GStreamer, I could make several mistakes.

Thanks and regards,

Rossana


Here's the code:


const gint dur_crossfade = 500;

// Error handler
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
{

  :::::::::::::::::::::::::::::::::
    return TRUE;
}

static void on_pad_added (GstElement *element, GstPad *pad, gpointer  data)
{
  GstPad *sinkpad = NULL;
  GstElement * queue = (GstElement *) data;

  /* Ahora linkeo el pad de comp con sink pad */
  g_print ("Dynamic pad created, linking queue\n");
  sinkpad = gst_element_get_static_pad (queue, "sink");

  gst_pad_link (pad, sinkpad);

  gst_object_unref (sinkpad);

}

GstElement * getBin(const gchar * nomBin, GstElement * &alfa1, GstElement
*&smpte, GstElement * &color, gint transicion = 1)
{

  GstElement * bin = gst_bin_new(nomBin);

  if (!bin)
  {
      g_printerr ("No se pudo crear el bin. Saliendo\n");
     return NULL;
  }

  alfa1   = gst_element_factory_make ("alpha","alfa1");
  smpte  = gst_element_factory_make ("smptealpha","smpte");
  color  = gst_element_factory_make ("ffmpegcolorspace", "color");
  GstElement * mixer  = gst_element_factory_make("videomixer", "mixer");


  if ((!alfa1) || (!smpte) || (!color) || (!mixer))
  {
      g_printerr ("Alguno de los elementos del Bin no pudo ser creado.
Saliendo\n");
     return NULL;
  }

  // Anexamos al bin
  gst_bin_add_many(GST_BIN (bin),alfa1,smpte,mixer,color,NULL);

  // Enlazamos elementos
  gst_element_link (alfa1, mixer);
  gst_element_link (smpte, mixer);
  gst_element_link (mixer,color);

  g_object_set(smpte,"type", transicion, NULL);

  return bin;
}

void getAndSetController(GstElement * smpte, gdouble duracion)
{
    GstController * ctrl = NULL;
    if (!(ctrl = gst_controller_new (G_OBJECT (smpte), "alpha",NULL))) {
        GST_WARNING ("No puede controlar el elemento fuente\n");
        return;
   }

  // Todo valor GValue debe inicializarse en 0
  GValue val_double = { 0, };
  g_value_init (&val_double, G_TYPE_DOUBLE);


  // Create de controller, source and set the interpolation mode

  GstInterpolationControlSource * csource =
gst_interpolation_control_source_new();
  gst_controller_set_control_source (ctrl, "alpha", GST_CONTROL_SOURCE
(csource));


gst_interpolation_control_source_set_interpolation_mode(csource,GST_INTERPOLATE_LINEAR);

  // Set first value
  g_value_set_double(&val_double, 0.0);
  gst_interpolation_control_source_set(csource,(0 *
GST_MSECOND),&val_double);

  // Ser 2nd value
  g_value_set_double (&val_double, duracion);
  gst_interpolation_control_source_set(csource,(1 *
GST_MSECOND),&val_double);


  g_object_unref (csource);

}

void addGhostPadsToBin(GstElement *alfa1, GstElement * smpte, GstElement *
color, GstElement* bin)
{
    /* add ghostpad */
  GstPad * pad1 = gst_element_get_static_pad (alfa1, "sink");
  gst_element_add_pad(bin, gst_ghost_pad_new("alfasink1", pad1));
  gst_object_unref (GST_OBJECT (pad1));

  GstPad * pad2 = gst_element_get_static_pad (smpte, "sink");
  gst_element_add_pad(bin, gst_ghost_pad_new("alfasink2", pad2));
  gst_object_unref(GST_OBJECT(pad2));

  GstPad * pad3 = gst_element_get_static_pad (color, "src");
  gst_element_add_pad(bin, gst_ghost_pad_new("colorsrc", pad3));
  gst_object_unref(GST_OBJECT(pad3));

}

void crossTransicion(gdouble duracion, GstElement * & bin,gint transicion =
1)
{
    // devuelve el bin
    GstElement * alfa1, *smpte, *color;
    alfa1 = 0;
    smpte = 0;
    color = 0;

    bin = getBin("bin",alfa1, smpte,color,transicion);  // Crea el bin y los
elementos

    getAndSetController(smpte,duracion);

    addGhostPadsToBin(alfa1, smpte, color, bin);

}

GstElement * crearVideo(const gchar *nomVideo, GstElement *&comp)
{
  GstElement* video = NULL;
  if ((video = gst_element_factory_make("gnlfilesource", nomVideo)) == NULL)
    {
      printf ("\n Falló la creacion del gnlfilesource \n");
      return NULL;
    }


    if (gst_bin_add (GST_BIN (comp), video) == FALSE)
    {
      printf ("\n No pudo agregar video %s a comp \n", nomVideo);
      return NULL;
    }

    return video;
}

void crearCompYoper(GstElement*& compo, GstElement *&op, GstElement*& bin2)
{

    if ((compo = gst_element_factory_make("gnlcomposition",
"micomposicion")) == NULL)
    {
      printf ("\n Fallo al crear gnlcomposition \n");
      return;
    }

    //Aqui se crea el bin
    crossTransicion(dur_crossfade, bin2,1);

    op = gst_element_factory_make("gnloperation", "op");

    if (gst_bin_add (GST_BIN (op), bin2) == FALSE)
    {
      printf ("\n No pudo agregar el bin a la gnloperacion op \n");
      return;
    }

    if (gst_bin_add (GST_BIN (compo), op) == FALSE)
    {
      printf ("\n No pudo agregar la gnloperacion a la gnlcomposition \n");
      return;
    }

}


/// Aqui pipeline3

GstElement * getPipeline3(gchar *argv[],GstElement *&video1, gint dur1,
GstElement *& video2,GstElement *& comp, GstElement *&op)
{

    GstElement *queue, *sink, *pipeline, *bin;

    crearCompYoper(comp, op,bin);

    video1 = crearVideo("video1",comp);
    video2 = crearVideo("video2",comp);

    g_object_set (video1, "location", argv[1], NULL);
    g_object_set(video1, "uri", argv[1],NULL);
    g_object_set (video1, "start", 0 * GST_MSECOND, NULL);
    g_object_set (video1, "duration", dur1 * GST_MSECOND, NULL);
    g_object_set (video1, "media-start", 0* GST_MSECOND, NULL);
    g_object_set (video1, "media-duration", dur1 * GST_MSECOND, NULL);
    g_object_set (video1, "priority", 1,NULL);

    // setup the backend viewer
    queue = gst_element_factory_make("queue", "queue");
    sink  = gst_element_factory_make("autovideosink", "sink");

    pipeline = gst_pipeline_new ("video-player");

    /* Agrego elementos al pipeline */

    gst_bin_add_many (GST_BIN (pipeline),comp, queue, sink, NULL);

    g_signal_connect (comp, "pad-added", G_CALLBACK (on_pad_added),queue);

    gst_element_link (queue, sink);

    cout << "...PLAY" << endl;

    gst_element_set_state (pipeline, GST_STATE_PLAYING);

    return pipeline;
}


void playSigVideo(gchar *argv[], GstElement *& video2, gint dur1, gint
dur2,GstElement *&op, GstElement *pip)
{
    g_object_set (op,"start", (dur1-dur_crossfade) * GST_MSECOND,NULL);
    g_object_set (op,"duration", dur_crossfade *  GST_MSECOND,NULL);
    g_object_set (op,"media-start", 0 *  GST_MSECOND,NULL);
    g_object_set(op,"media-duration", dur_crossfade * GST_MSECOND,NULL);
    g_object_set(op,"priority",0,NULL);

    gst_element_set_state (pip, GST_STATE_PLAYING);

    g_object_set (video2, "location", argv[2], NULL);
    g_object_set (video2,"uri",argv[2],NULL);
    g_object_set (video2, "start", (dur1-dur_crossfade) * GST_MSECOND,
NULL);
    g_object_set (video2, "duration", dur2 * GST_MSECOND, NULL);
    g_object_set (video2, "media-start", 0 * GST_MSECOND, NULL);
    g_object_set (video2, "media-duration", dur2 * GST_MSECOND, NULL);
    g_object_set (video2, "priority", 2,NULL);

    g_object_set (op,"start", ((dur2+dur1)- 2*dur_crossfade) *
GST_MSECOND,NULL);
    g_object_set (op,"duration", dur_crossfade *  GST_MSECOND,NULL);
    g_object_set (op,"media-start", 0 *  GST_MSECOND,NULL);
    g_object_set(op,"media-duration", dur_crossfade * GST_MSECOND,NULL);
    g_object_set(op,"priority",3,NULL);

    g_object_set (video2, "location", argv[1], NULL);
    g_object_set (video2,"uri",argv[1],NULL);
    g_object_set (video2, "start", ((dur2 + dur1) - 2*dur_crossfade) *
GST_MSECOND, NULL);
    g_object_set (video2, "duration", dur1 * GST_MSECOND, NULL);
    g_object_set (video2, "media-start", 0 * GST_MSECOND, NULL);
    g_object_set (video2, "media-duration", dur1 * GST_MSECOND, NULL);
    g_object_set (video2, "priority", 4,NULL);

}


int main(gint argc, gchar *argv[])
{
    gint dur1 = 9000; // d uration (in ms) to play of first clip
    gint dur2 = 8000; // duration (in ms) to play of second clip
    //gint dur_crossfade = 500; //number of milliseconds to crossfade for
    GMainLoop *loop = NULL;

    /* init GStreamer */
    gst_init (&argc, &argv);
    gst_controller_init (&argc, &argv);

    loop = g_main_loop_new (NULL, FALSE);

    /* chequeamos sintaxis */
    if (argc != 3)
    {
        g_print ("Uso: %s <URI1>  <URI2>\n", argv[0]);
        return -1;
    }

    GstElement *comp = NULL;
    GstElement *op = NULL;
    GstElement *video1,*video2;

    GstElement *play = getPipeline3(argv,video1, dur1,video2,comp, op);

    playSigVideo(argv,video2, dur1, dur2,op,play);

    GstBus *bus2 = gst_pipeline_get_bus (GST_PIPELINE (play));
    gst_bus_add_watch (bus2, bus_call, loop);
    gst_object_unref (bus2);

    //cout << "...PLAY" << endl;


    /* now run */
    g_main_loop_run (loop);

    /* also clean up */
    gst_element_set_state (play, GST_STATE_NULL);
    gst_object_unref (GST_OBJECT (play));
    return 0;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/gstreamer-devel/attachments/20110925/c4e519c5/attachment.html>


More information about the gstreamer-devel mailing list