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 |
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. _______________________________________________ gstreamer-devel mailing list [hidden email] http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
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, _______________________________________________ gstreamer-devel mailing list [hidden email] http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
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). _______________________________________________ gstreamer-devel mailing list [hidden email] http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
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. _______________________________________________ gstreamer-devel mailing list [hidden email] http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
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, _______________________________________________ gstreamer-devel mailing list [hidden email] http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
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. _______________________________________________ gstreamer-devel mailing list [hidden email] http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
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). _______________________________________________ gstreamer-devel mailing list [hidden email] http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Free forum by Nabble | Edit this page |