Cela faisait un moment que je n’avais plus posté sur iMotion, en août dernier apparemment !
J’ai repris le code pour y ajouter le support des fichiers vidéos. Je butais depuis un moment sur un problème de fige de la vidéo lors du changement d’un effet pendant la lecture, problème que je n’ai pas avec la webcam. Cette technique de changement dynamique d’un élément lors de la lecture dans le pipeline est uniquement documenté ici : cgit.freedesktop.org/gstreamer/gstreamer/tree/docs/design/part-block.txt#n112 mais je n’ai pas trouvé de soft qui l’implémente …
Premièrement j’avais oublié l’indication 8 :
8) make sure element4 is in the same state as the rest of the elements. The element should at least be PAUSED.
Mon pipeline est en statut PLAYING donc en passant l’élément effect dans ce statut le problème de fige de la vidéo a été résolu.
Deuxièmement le schéma de la documentation montre un pipeline de 3 éléments (plus un 4 ème qui remplace dynamiquement le 2ème). Or cela m’a induis en erreur car le mien en possède 6 :
- filesrc
- decodebin2
- ffmpegcolorspace
- videoscale
- effectv
- ximagesink
Lorsque la documentation indique de bloquer l’élément 1 il s’agit en fait de l’élément qui précède celui que l’on veut remplacer. Dans iMotion je souhaite changer dynamiquement d’effet donc c’est l’élément 4 qui doit être bloqué.
Pour ceux qui débutent avec GStreamer voici une excellente présentation : blog.nicolargo.com/2009/03/gstreamer-la-theorie.html
Voici une capture d’écran avec l’effet edgetv suivie de l’implémentation correcte du code :
voidVideoManager::switch_effect (Glib::ustring a_name){ m_effect_name = a_name; bool res = false; GstEvent *event;
// replay pipeline if it paused
gst_element_get_state(m_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); gst_element_set_state (m_pipeline, GST_STATE_PLAYING);
// wait until pipeline playing if (gst_element_get_state (m_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE) == GST_STATE_CHANGE_FAILURE) {std::cout << "Failed to go into PLAYING state" << std::endl;exit(1);}
std::cout << "PLAYING state" << std::endl;
GstPad *videoscale_sink_pad = gst_element_get_static_pad (m_videoscale, "sink");GstPad *videoscale_src_pad = gst_element_get_static_pad (m_videoscale, "src");
if (videoscale_src_pad) {res = gst_pad_set_blocked_async (videoscale_src_pad, TRUE, (GstPadBlockCallback) block_callback, m_pipeline);std::cout << "blocked pad : " << res << std::endl;
if (!res) {std::cout << "can not block source pad : " << res << std::endl;exit (1);} else {std::cout << "blocked source pad : " << res << std::endl;}
}else {std::cout << "can not get source pad : " << res << std::endl;exit (1);}
if (m_effect){GstPad *effect_sink_pad = gst_element_get_static_pad (m_effect, "sink");GstPad *effect_src_pad = gst_element_get_static_pad (m_effect, "src");
// remove effect elementgst_element_get_state(m_effect, NULL, NULL, GST_CLOCK_TIME_NONE);gst_element_set_state (m_effect, GST_STATE_NULL);gst_element_get_state(m_effect, NULL, NULL, GST_CLOCK_TIME_NONE);
if (gst_element_get_state (m_effect, NULL, NULL, GST_CLOCK_TIME_NONE) == GST_STATE_CHANGE_FAILURE) {std::cout << "Failed to state null on m_effect" << std::endl;exit(1);}
gst_element_unlink_pads (m_videoscale,"src",m_effect,"sink");
std::cout << "UNLINK PAD" << std::endl;
/************ seems to not be usefull ************/gst_pad_add_event_probe (effect_src_pad, G_CALLBACK (source_pad_event_probe), effect_src_pad);event = gst_event_new_eos ();gst_pad_send_event (effect_sink_pad, event);gst_object_unref (effect_sink_pad);std::cout << "SEND EOS" << std::endl;/**************************************************/
gst_element_unlink_pads (m_effect,"src",m_sink,"sink");
std::cout << "UNLINK PAD 2" << std::endl;gst_element_get_state(m_effect, NULL, NULL, GST_CLOCK_TIME_NONE);
gst_bin_remove (GST_BIN (m_bin), m_effect);
std::cout << "GST BIN REMOVED" << std::endl;
}else{gst_element_unlink_pads (m_videoscale,"src",m_sink,"sink");}
if ( m_effect_name != "none"){m_effect = gst_element_factory_make (m_effect_name.c_str(), "effect");gst_bin_add (GST_BIN (m_bin), m_effect);gst_element_link_pads (m_videoscale,"src",m_effect,"sink");gst_element_link_pads (m_effect,"src",m_sink,"sink");
// Indication 8gst_element_set_state (m_effect, GST_STATE_PLAYING); std::cout << "new effect and linked in" << std::endl; } else { gst_element_link_pads (m_videoscale, "src", m_sink, "sink");
m_effect = 0; std::cout << "no effect" << std::endl;
}
if (videoscale_src_pad) { res = gst_pad_set_blocked_async (videoscale_src_pad, FALSE,(GstPadBlockCallback) block_callback, m_pipeline); gst_object_unref (videoscale_src_pad); } std::cout << "unblocked source pad : " << res << std::endl; std::cout << m_effect_name << std::endl;}

