Crossfading-transition between more than 2 videos.

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Crossfading-transition between more than 2 videos.

rossana
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;
}




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Crossfading-transition between more than 2 videos.

amartin
Hello,

I suggest you to remove variable start and duration attributes and put fixed values instead in order to have a clear schedule of the different elements involved.

Moreover, the priority of the operation should be always minor that the videos involved, I suggest you to put a 0 always in the transition operation priority.

Best Regards,

Angel

2011/9/25 Rossana Guerra <[hidden email]>
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;
}




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Crossfading-transition between more than 2 videos.

rossana
Hi Angel, thanks for your suggest, I did what you suggested but it didn't work. It only play the 1st vido. So I put back the variables. In fact, I want to have a play list, so I need to calculate the next start/duration attribute (I need variables for that).
As I said if I test with 2 videos it works fine, the problems is when a 3rd one comes to the scenario.

This is the situation. I want to play a playlist with crossfade between videos. The crossfade time is fixed: 500ms.
The first video lasts 9000ms
The 2nd lasts 8000ms.
The 3rd lasts 9000ms.

2nd video, start duration: 9000 - 500 // video1 duration - crossfade duration
3rd video start duration: 9000 + 8000 - 2*500  // video1 duration + video 2 duration - 2 * crossfade duration

According some test I did, it has to do with starting time of both, operation and 3rd video.

Thanks and any suggestion is welcome.

Here's the problematic part (start and duration with fixed attributes, didn't work)

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);

    // Playing 2nd video
    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", (dur1 + dur2 - 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",0,NULL);

   // Playin 3rd video, which is the first one played
    g_object_set (video2, "location", argv[1], NULL);
    g_object_set (video2,"uri",argv[1],NULL);
    g_object_set (video2, "start", (dur1 + dur2 - 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", 3,NULL);

}



2011/9/26 Angel Martin <[hidden email]>
Hello,

I suggest you to remove variable start and duration attributes and put fixed values instead in order to have a clear schedule of the different elements involved.

Moreover, the priority of the operation should be always minor that the videos involved, I suggest you to put a 0 always in the transition operation priority.

Best Regards,

Angel

2011/9/25 Rossana Guerra <[hidden email]>
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;
}




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel



_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Crossfading-transition between more than 2 videos.

rossana
Hi another thing I noticed is that it takes the last properties I set to video2.
I meant, I execute video2 twice with differents properties, first for those corresponding to argv[2], and the second to argv[1].
Whatever were the values at argv[2] it doesn't matter if argv[1] are the correct ones.

I mean this:

video1
video2, argv[2] to play at x time
video2 argv[1] to play after video1
It skips argv[2], so it keeps with the las values set. So, how I do to play a playlist with crossfade?.

I wish I were clear.

Thanks,

Ro

2011/9/26 Rossana Guerra <[hidden email]>
Hi Angel, thanks for your suggest, I did what you suggested but it didn't work. It only play the 1st vido. So I put back the variables. In fact, I want to have a play list, so I need to calculate the next start/duration attribute (I need variables for that).
As I said if I test with 2 videos it works fine, the problems is when a 3rd one comes to the scenario.

This is the situation. I want to play a playlist with crossfade between videos. The crossfade time is fixed: 500ms.
The first video lasts 9000ms
The 2nd lasts 8000ms.
The 3rd lasts 9000ms.

2nd video, start duration: 9000 - 500 // video1 duration - crossfade duration
3rd video start duration: 9000 + 8000 - 2*500  // video1 duration + video 2 duration - 2 * crossfade duration

According some test I did, it has to do with starting time of both, operation and 3rd video.

Thanks and any suggestion is welcome.

Here's the problematic part (start and duration with fixed attributes, didn't work)


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);

    // Playing 2nd video

    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", (dur1 + dur2 - 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",0,NULL);

   // Playin 3rd video, which is the first one played

    g_object_set (video2, "location", argv[1], NULL);
    g_object_set (video2,"uri",argv[1],NULL);
    g_object_set (video2, "start", (dur1 + dur2 - 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", 3,NULL);


}



2011/9/26 Angel Martin <[hidden email]>
Hello,

I suggest you to remove variable start and duration attributes and put fixed values instead in order to have a clear schedule of the different elements involved.

Moreover, the priority of the operation should be always minor that the videos involved, I suggest you to put a 0 always in the transition operation priority.

Best Regards,

Angel

2011/9/25 Rossana Guerra <[hidden email]>
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;
}




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Crossfading-transition between more than 2 videos.

amartin
Hi again,

I think that the problem is that you should create a completely different GstElement for each video or operation for each transition.

You want 3 videos, so 3 gst_element_factory_make should appear.

I think that you are reusing the same variable for different multimedia objects. Moreover, it is important that the name associated to each GstElement shouldn't be repeated, specially for concurrent objects.

Best,

Angel

2011/9/27 Rossana Guerra <[hidden email]>
Hi another thing I noticed is that it takes the last properties I set to video2.
I meant, I execute video2 twice with differents properties, first for those corresponding to argv[2], and the second to argv[1].
Whatever were the values at argv[2] it doesn't matter if argv[1] are the correct ones.

I mean this:

video1
video2, argv[2] to play at x time
video2 argv[1] to play after video1
It skips argv[2], so it keeps with the las values set. So, how I do to play a playlist with crossfade?.

I wish I were clear.

Thanks,

Ro


2011/9/26 Rossana Guerra <[hidden email]>
Hi Angel, thanks for your suggest, I did what you suggested but it didn't work. It only play the 1st vido. So I put back the variables. In fact, I want to have a play list, so I need to calculate the next start/duration attribute (I need variables for that).
As I said if I test with 2 videos it works fine, the problems is when a 3rd one comes to the scenario.

This is the situation. I want to play a playlist with crossfade between videos. The crossfade time is fixed: 500ms.
The first video lasts 9000ms
The 2nd lasts 8000ms.
The 3rd lasts 9000ms.

2nd video, start duration: 9000 - 500 // video1 duration - crossfade duration
3rd video start duration: 9000 + 8000 - 2*500  // video1 duration + video 2 duration - 2 * crossfade duration

According some test I did, it has to do with starting time of both, operation and 3rd video.

Thanks and any suggestion is welcome.

Here's the problematic part (start and duration with fixed attributes, didn't work)


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);

    // Playing 2nd video

    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", (dur1 + dur2 - 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",0,NULL);

   // Playin 3rd video, which is the first one played

    g_object_set (video2, "location", argv[1], NULL);
    g_object_set (video2,"uri",argv[1],NULL);
    g_object_set (video2, "start", (dur1 + dur2 - 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", 3,NULL);


}



2011/9/26 Angel Martin <[hidden email]>
Hello,

I suggest you to remove variable start and duration attributes and put fixed values instead in order to have a clear schedule of the different elements involved.

Moreover, the priority of the operation should be always minor that the videos involved, I suggest you to put a 0 always in the transition operation priority.

Best Regards,

Angel

2011/9/25 Rossana Guerra <[hidden email]>
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;
}




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel





_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Crossfading-transition between more than 2 videos.

rossana
Hi Angel, thanks again for your suggestion, I was suspecting something of what you sad. 
Let's see if I understand. The video and operator variable are within a pipeline, bin, so I need to re create the same "artfact" or pipeline. 
Do I need to unref video or op referecne and then create and re -add  them into the corresponding bin/pipeline?.
Or I delete the whole pipeline?
Anf if it is so, where?.

Thanks for your responde

Rossana



2011/9/28 Angel Martin <[hidden email]>
Hi again,

I think that the problem is that you should create a completely different GstElement for each video or operation for each transition.

You want 3 videos, so 3 gst_element_factory_make should appear.

I think that you are reusing the same variable for different multimedia objects. Moreover, it is important that the name associated to each GstElement shouldn't be repeated, specially for concurrent objects.

Best,

Angel


2011/9/27 Rossana Guerra <[hidden email]>
Hi another thing I noticed is that it takes the last properties I set to video2.
I meant, I execute video2 twice with differents properties, first for those corresponding to argv[2], and the second to argv[1].
Whatever were the values at argv[2] it doesn't matter if argv[1] are the correct ones.

I mean this:

video1
video2, argv[2] to play at x time
video2 argv[1] to play after video1
It skips argv[2], so it keeps with the las values set. So, how I do to play a playlist with crossfade?.

I wish I were clear.

Thanks,

Ro


2011/9/26 Rossana Guerra <[hidden email]>
Hi Angel, thanks for your suggest, I did what you suggested but it didn't work. It only play the 1st vido. So I put back the variables. In fact, I want to have a play list, so I need to calculate the next start/duration attribute (I need variables for that).
As I said if I test with 2 videos it works fine, the problems is when a 3rd one comes to the scenario.

This is the situation. I want to play a playlist with crossfade between videos. The crossfade time is fixed: 500ms.
The first video lasts 9000ms
The 2nd lasts 8000ms.
The 3rd lasts 9000ms.

2nd video, start duration: 9000 - 500 // video1 duration - crossfade duration
3rd video start duration: 9000 + 8000 - 2*500  // video1 duration + video 2 duration - 2 * crossfade duration

According some test I did, it has to do with starting time of both, operation and 3rd video.

Thanks and any suggestion is welcome.

Here's the problematic part (start and duration with fixed attributes, didn't work)


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);

    // Playing 2nd video

    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", (dur1 + dur2 - 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",0,NULL);

   // Playin 3rd video, which is the first one played

    g_object_set (video2, "location", argv[1], NULL);
    g_object_set (video2,"uri",argv[1],NULL);
    g_object_set (video2, "start", (dur1 + dur2 - 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", 3,NULL);


}



2011/9/26 Angel Martin <[hidden email]>
Hello,

I suggest you to remove variable start and duration attributes and put fixed values instead in order to have a clear schedule of the different elements involved.

Moreover, the priority of the operation should be always minor that the videos involved, I suggest you to put a 0 always in the transition operation priority.

Best Regards,

Angel

2011/9/25 Rossana Guerra <[hidden email]>
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;
}




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel





_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel



_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Crossfading-transition between more than 2 videos.

rossana
Hi, well in this way it seems to work. I put the following code in a loop (a while-cond).

while (cond)
{
    loop = g_main_loop_new (NULL, FALSE);

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

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

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

    g_main_loop_run (loop);

    gst_element_set_state (play, GST_STATE_NULL);
    gst_object_unref (GST_OBJECT (play));
]

I need to recreate the pipeline and loop. Is there another way? since I learning I'd like to know.
Thanks



2011/9/28 Rossana Guerra <[hidden email]>
Hi Angel, thanks again for your suggestion, I was suspecting something of what you sad. 
Let's see if I understand. The video and operator variable are within a pipeline, bin, so I need to re create the same "artfact" or pipeline. 
Do I need to unref video or op referecne and then create and re -add  them into the corresponding bin/pipeline?.
Or I delete the whole pipeline?
Anf if it is so, where?.

Thanks for your responde

Rossana



2011/9/28 Angel Martin <[hidden email]>
Hi again,

I think that the problem is that you should create a completely different GstElement for each video or operation for each transition.

You want 3 videos, so 3 gst_element_factory_make should appear.

I think that you are reusing the same variable for different multimedia objects. Moreover, it is important that the name associated to each GstElement shouldn't be repeated, specially for concurrent objects.

Best,

Angel


2011/9/27 Rossana Guerra <[hidden email]>
Hi another thing I noticed is that it takes the last properties I set to video2.
I meant, I execute video2 twice with differents properties, first for those corresponding to argv[2], and the second to argv[1].
Whatever were the values at argv[2] it doesn't matter if argv[1] are the correct ones.

I mean this:

video1
video2, argv[2] to play at x time
video2 argv[1] to play after video1
It skips argv[2], so it keeps with the las values set. So, how I do to play a playlist with crossfade?.

I wish I were clear.

Thanks,

Ro


2011/9/26 Rossana Guerra <[hidden email]>
Hi Angel, thanks for your suggest, I did what you suggested but it didn't work. It only play the 1st vido. So I put back the variables. In fact, I want to have a play list, so I need to calculate the next start/duration attribute (I need variables for that).
As I said if I test with 2 videos it works fine, the problems is when a 3rd one comes to the scenario.

This is the situation. I want to play a playlist with crossfade between videos. The crossfade time is fixed: 500ms.
The first video lasts 9000ms
The 2nd lasts 8000ms.
The 3rd lasts 9000ms.

2nd video, start duration: 9000 - 500 // video1 duration - crossfade duration
3rd video start duration: 9000 + 8000 - 2*500  // video1 duration + video 2 duration - 2 * crossfade duration

According some test I did, it has to do with starting time of both, operation and 3rd video.

Thanks and any suggestion is welcome.

Here's the problematic part (start and duration with fixed attributes, didn't work)


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);

    // Playing 2nd video

    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", (dur1 + dur2 - 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",0,NULL);

   // Playin 3rd video, which is the first one played

    g_object_set (video2, "location", argv[1], NULL);
    g_object_set (video2,"uri",argv[1],NULL);
    g_object_set (video2, "start", (dur1 + dur2 - 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", 3,NULL);


}



2011/9/26 Angel Martin <[hidden email]>
Hello,

I suggest you to remove variable start and duration attributes and put fixed values instead in order to have a clear schedule of the different elements involved.

Moreover, the priority of the operation should be always minor that the videos involved, I suggest you to put a 0 always in the transition operation priority.

Best Regards,

Angel

2011/9/25 Rossana Guerra <[hidden email]>
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;
}




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel





_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Crossfading-transition between more than 2 videos.

rossana
I have to say I don't know if memory the leaks grow with this method. I appreciate any improvement to this approach.
Thanks

Rossana

2011/9/28 Rossana Guerra <[hidden email]>
Hi, well in this way it seems to work. I put the following code in a loop (a while-cond).

while (cond)

{
    loop = g_main_loop_new (NULL, FALSE);

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

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


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

    g_main_loop_run (loop);

    gst_element_set_state (play, GST_STATE_NULL);
    gst_object_unref (GST_OBJECT (play));
]

I need to recreate the pipeline and loop. Is there another way? since I learning I'd like to know.
Thanks




2011/9/28 Rossana Guerra <[hidden email]>
Hi Angel, thanks again for your suggestion, I was suspecting something of what you sad. 
Let's see if I understand. The video and operator variable are within a pipeline, bin, so I need to re create the same "artfact" or pipeline. 
Do I need to unref video or op referecne and then create and re -add  them into the corresponding bin/pipeline?.
Or I delete the whole pipeline?
Anf if it is so, where?.

Thanks for your responde

Rossana



2011/9/28 Angel Martin <[hidden email]>
Hi again,

I think that the problem is that you should create a completely different GstElement for each video or operation for each transition.

You want 3 videos, so 3 gst_element_factory_make should appear.

I think that you are reusing the same variable for different multimedia objects. Moreover, it is important that the name associated to each GstElement shouldn't be repeated, specially for concurrent objects.

Best,

Angel


2011/9/27 Rossana Guerra <[hidden email]>
Hi another thing I noticed is that it takes the last properties I set to video2.
I meant, I execute video2 twice with differents properties, first for those corresponding to argv[2], and the second to argv[1].
Whatever were the values at argv[2] it doesn't matter if argv[1] are the correct ones.

I mean this:

video1
video2, argv[2] to play at x time
video2 argv[1] to play after video1
It skips argv[2], so it keeps with the las values set. So, how I do to play a playlist with crossfade?.

I wish I were clear.

Thanks,

Ro


2011/9/26 Rossana Guerra <[hidden email]>
Hi Angel, thanks for your suggest, I did what you suggested but it didn't work. It only play the 1st vido. So I put back the variables. In fact, I want to have a play list, so I need to calculate the next start/duration attribute (I need variables for that).
As I said if I test with 2 videos it works fine, the problems is when a 3rd one comes to the scenario.

This is the situation. I want to play a playlist with crossfade between videos. The crossfade time is fixed: 500ms.
The first video lasts 9000ms
The 2nd lasts 8000ms.
The 3rd lasts 9000ms.

2nd video, start duration: 9000 - 500 // video1 duration - crossfade duration
3rd video start duration: 9000 + 8000 - 2*500  // video1 duration + video 2 duration - 2 * crossfade duration

According some test I did, it has to do with starting time of both, operation and 3rd video.

Thanks and any suggestion is welcome.

Here's the problematic part (start and duration with fixed attributes, didn't work)


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);

    // Playing 2nd video

    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", (dur1 + dur2 - 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",0,NULL);

   // Playin 3rd video, which is the first one played

    g_object_set (video2, "location", argv[1], NULL);
    g_object_set (video2,"uri",argv[1],NULL);
    g_object_set (video2, "start", (dur1 + dur2 - 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", 3,NULL);


}



2011/9/26 Angel Martin <[hidden email]>
Hello,

I suggest you to remove variable start and duration attributes and put fixed values instead in order to have a clear schedule of the different elements involved.

Moreover, the priority of the operation should be always minor that the videos involved, I suggest you to put a 0 always in the transition operation priority.

Best Regards,

Angel

2011/9/25 Rossana Guerra <[hidden email]>
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;
}




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel





_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel





_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel