目标

      GStreamer有一系列把音频转换成视频的element。他们可以用于科学的目的或者增加音乐播放器的趣味性。本教程展示:

      如何允许音频的可视化

      如何选择可视化element


介绍

      在playbin2里面运行音频可视化是非常容易的。当遇到一个只有音频的流时,只需要正确地设置playbin2的一些标志就行了。它会自己创建必要的element然后显示的。

      如果你想要增加实际的element的趣味性,你要自己实例化它然后通过vis-plug属性来告诉playbin2。

      本教程GStreamer注册的所有关于可视化的element,选择了goom并传给了playbin2


一个有趣的音乐播放器




[objc] ​​view plain​ ​ ​​copy​



  1. <span style="font-size:14px;">#include <gst/gst.h>  
  2.     
  3. /* playbin2 flags */  
  4. typedef enum {  
  5.   GST_PLAY_FLAG_VIS           = (1 << 3) /* Enable rendering of visualizations when there is no video stream. */  
  6. } GstPlayFlags;  
  7.     
  8. /* Return TRUE if this is a Visualization element */  
  9. static gboolean filter_vis_features (GstPluginFeature *feature, gpointer data) {  
  10.   GstElementFactory *factory;  
  11.     
  12.   if (!GST_IS_ELEMENT_FACTORY (feature))  
  13.     return FALSE;  
  14.   factory = GST_ELEMENT_FACTORY (feature);  
  15.   if (!g_strrstr (gst_element_factory_get_klass (factory), "Visualization"))  
  16.     return FALSE;  
  17.     
  18.   return TRUE;  
  19. }  
  20.     
  21. int main(int argc, charchar *argv[]) {  
  22.   GstElement *pipeline, *vis_plugin;  
  23.   GstBus *bus;  
  24.   GstMessage *msg;  
  25.   GList *list, *walk;  
  26.   GstElementFactory *selected_factory = NULL;  
  27.   guint flags;  
  28.     
  29.   /* Initialize GStreamer */  
  30.   gst_init (&argc, &argv);  
  31.     
  32.   /* Get a list of all visualization plugins */  
  33.   list = gst_registry_feature_filter (gst_registry_get_default (), filter_vis_features, FALSE, NULL);  
  34.     
  35.   /* Print their names */  
  36.   g_print("Available visualization plugins:\n");  
  37.   for (walk = list; walk != NULL; walk = g_list_next (walk)) {  
  38.     const gchar *name;  
  39.     GstElementFactory *factory;  
  40.       
  41.     factory = GST_ELEMENT_FACTORY (walk->data);  
  42.     name = gst_element_factory_get_longname (factory);  
  43.     g_print("  %s\n", name);  
  44.       
  45.     if (selected_factory == NULL || g_str_has_prefix (name, "GOOM")) {  
  46.       selected_factory = factory;  
  47.     }  
  48.   }  
  49.     
  50.   /* Don't use the factory if it's still empty */  
  51.   /* e.g. no visualization plugins found */  
  52.   if (!selected_factory) {  
  53.     g_print ("No visualization plugins found!\n");  
  54.     return -1;  
  55.   }  
  56.     
  57.   /* We have now selected a factory for the visualization element */  
  58.   g_print ("Selected '%s'\n", gst_element_factory_get_longname (selected_factory));  
  59.   vis_plugin = gst_element_factory_create (selected_factory, NULL);  
  60.   if (!vis_plugin)  
  61.     return -1;  
  62.     
  63.   /* Build the pipeline */  
  64.   pipeline = gst_parse_launch ("playbin2 uri=http://radio.hbr1.com:19800/ambient.ogg", NULL);  
  65.     
  66.   /* Set the visualization flag */  
  67.   g_object_get (pipeline, "flags", &flags, NULL);  
  68.   flags |= GST_PLAY_FLAG_VIS;  
  69.   g_object_set (pipeline, "flags", flags, NULL);  
  70.     
  71.   /* set vis plugin for playbin2 */  
  72.   g_object_set (pipeline, "vis-plugin", vis_plugin, NULL);  
  73.     
  74.   /* Start playing */  
  75.   gst_element_set_state (pipeline, GST_STATE_PLAYING);  
  76.     
  77.   /* Wait until error or EOS */  
  78.   bus = gst_element_get_bus (pipeline);  
  79.   msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);  
  80.     
  81.   /* Free resources */  
  82.   if (msg != NULL)  
  83.     gst_message_unref (msg);  
  84.   gst_plugin_feature_list_free (list);  
  85.   gst_object_unref (bus);  
  86.   gst_element_set_state (pipeline, GST_STATE_NULL);  
  87.   gst_object_unref (pipeline);  
  88.   return 0;  
  89. }  
  90. </span>  


工作流程

      首先,我们都知道通过设置GST_PLAY_FLAG_VIS标志可以让playbin2的音频可视化。如果媒体文件里面已经包含了视频,那么这个标志就不起作用。



  1. /* Set the visualization flag */  
  2. g_object_get (pipeline, "flags", &flags, NULL);  
  3. flags |= GST_PLAY_FLAG_VIS;  
  4. g_object_set (pipeline, "flags", flags, NULL);  


      如果用户没有指定可视化插件,playbin2会使用goom来做(如果没有这个element就不能进行音频可视化)。本教程剩下的部分会显示如何来发现一个可用的可视化element并指定playbin2使用。




  1. /* Get a list of all visualization plugins */  
  2. list = gst_registry_feature_filter (gst_registry_get_default (), filter_vis_features, FALSE, NULL);  


      gst_registry_feature_filter()检查GStreamer当前所有注册的element并选择那些filter_vis_features函数返回TRUE的element。




[objc] ​​view plain​ ​ ​​copy​


 ​​​​​​​

  1. /* Return TRUE if this is a Visualization element */  
  2. static gboolean filter_vis_features (GstPluginFeature *feature, gpointer data) {  
  3.   GstElementFactory *factory;  
  4.     
  5.   if (!GST_IS_ELEMENT_FACTORY (feature))  
  6.     return FALSE;  
  7.   factory = GST_ELEMENT_FACTORY (feature);  
  8.   if (!g_strrstr (gst_element_factory_get_klass (factory), "Visualization"))  
  9.     return FALSE;  
  10.     
  11.   return TRUE;  
  12. }  


      这里牵涉到一点关于GStreamer element的理论:每一个GStreamer在运行时加载的文件都被认为是插件。一个插件可以有多个功能,不同种类的功能。

      这个函数简单的丢弃了所有不能批量复现的功能以及不包含“可视化”这个功能的插件。




  1. /* Print their names */  
  2. g_print("Available visualization plugins:\n");  
  3. for (walk = list; walk != NULL; walk = g_list_next (walk)) {  
  4.   const gchar *name;  
  5.   GstElementFactory *factory;  
  6.     
  7.   factory = GST_ELEMENT_FACTORY (walk->data);  
  8.   name = gst_element_factory_get_longname (factory);  
  9.   g_print("  %s\n", name);  
  10.     
  11.   if (selected_factory == NULL || g_str_has_prefix (name, "GOOM")) {  
  12.     selected_factory = factory;  
  13.   }  
  14. }  


      一旦我们有了可视化插件的列表,我们会打印出它们的名字(gst_element_factory_get_longname())并选择一个(比如:GOOM)。




  1. /* We have now selected a factory for the visualization element */  
  2. g_print ("Selected '%s'\n", gst_element_factory_get_longname (selected_factory));  
  3. vis_plugin = gst_element_factory_create (selected_factory, NULL);  
  4. if (!vis_plugin)  
  5.   return -1;  


      选中的工厂用来生成一个GstElement,通过vis-plugin属性来传给playbin2。




  1. /* set vis plugin for playbin2 */  
  2. g_object_set (pipeline, "vis-plugin", vis_plugin, NULL);  


      Bingo,就这么简单。