Crossfading-transition between more than 2 videos.

Angel Martin amartin at vicomtech.org
Wed Sep 28 02:09:01 PDT 2011


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 <guerra.rossana at gmail.com>

> 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 <guerra.rossana at gmail.com>
>
>> 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 <amartin at vicomtech.org>
>>
>>> 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 <guerra.rossana at gmail.com>
>>>
>>>> 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
>>>> gstreamer-devel at lists.freedesktop.org
>>>> http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>>>>
>>>>
>>>
>>>
>>> _______________________________________________
>>> gstreamer-devel mailing list
>>> gstreamer-devel at lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>>>
>>>
>>
>
> _______________________________________________
> gstreamer-devel mailing list
> gstreamer-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/gstreamer-devel/attachments/20110928/2bf0ea91/attachment-0001.htm>


More information about the gstreamer-devel mailing list