Crossfading-transition between more than 2 videos.

Rossana Guerra guerra.rossana at gmail.com
Wed Sep 28 12:11:49 PDT 2011


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 <amartin at vicomtech.org>

> 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
>>
>>
>
>
>
> _______________________________________________
> 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/f764e55e/attachment-0001.htm>


More information about the gstreamer-devel mailing list