GStreamerで隣人またはカラオケを取得する方法

GStreamerフレームワークの開発を続けています。 約束どおり、今日はバスの操作とさまざまな種類のメッセージの処理について詳しく見ていきます。 実際のセクションでは、小さなコンソールカラオケを作成します。 それでは始めましょう。



画像



タイヤ



GStreamerのアプリケーションは、パイプラインに配置され相互接続されたさまざまな要素で構成されていることを思い出させてください。 作業プロセスの各要素は、さまざまなタイプのメッセージを生成できます(以下で説明します)。 これらのメッセージを収集し、優先順位に従ってメインアプリケーションストリームに配信するために、バスが使用されます。



各パイプラインにはデフォルトで組み込みのバスがあります。 作成またはカスタマイズする必要はありません。 タイヤは、次の機能によってコンベヤから取り外されます。



GstBus * gst_pipeline_get_bus (GstPipeline *pipeline)
      
      





バス上のメッセージを処理するには、非同期と同期の2つの方法があります。 最初の方法は、ハンドラーがバスに接続され、メッセージを受信すると何らかのアクションを実行することです。 これは、関数を使用して行われます。



 guint gst_bus_add_watch (GstBus *bus, GstBusFunc func, gpointer user_data) void gst_bus_add_signal_watch (GstBus *bus)
      
      





これらの関数の両方に高度なオプション(* _full)があり、その助けを借りてハンドラーをさらに微調整できることに注意してください。

2番目の方法は、メッセージを求めてバスを常にポーリングすることです。 これは、関数を使用して行われます。



 GstMessage *gst_bus_poll (GstBus *bus, GstMessageType events, GstClockTime timeout)
      
      





同時に、調査の期間を調整するだけでなく、キューから特定のタイプのメッセージのみを取得することもできます。



メッセージ



各メッセージは、ソース、タイプ、およびタイムスタンプによって特徴付けられます。 ほとんどの場合、各タイプのメッセージに応答する必要はありませんが、少なくともエラーメッセージを処理することを強くお勧めします。 かなり多くの種類がありますが、最も一般的なものは次のとおりです。





一方、メッセージ処理の問題にアプローチすることもできます。つまり、次の形式で対象の信号のみに接続します。



 g_signal_connect (bus, "message::error", G_CALLBACK (cb_message_error), NULL)
      
      





重要! ハンドラーがメッセージに応答し続けるようにするには、TRUEを返す必要があります。 FALSEの戻り値を登録すると、処理後、このハンドラーによるメッセージ追跡が停止します。



練習する



次に、mp3ファイルを再生し、audiokaraoke要素を使用して特定の周波数範囲(ボーカル範囲を含む)を抑制するアプリケーションを作成します。 同時に、出力ではボーカルのないトラックを取得します。 コンソールには、ファイルの曲の歌詞も(UTF-8エンコードで)表示されます。



コンベアは次のようになります。



画像



Mad mp3デコーダーが含まれているため、Uglyプラグインセット(gst-plugins-ugly)がインストールされていることを確認してください。



そして、プログラム自体は次のとおりです。

 #include <gst/gst.h> #define SUPRESS_LEVEL 1.0 //  0.0  1.0 #define MONO_LEVEL 1.0 //  0.0  1.0 #define FILTER_BAND 220.0 //  0.0  441.0 #define FILTER_WIDTH 100.0 //  0.0  100.0 static GMainLoop *loop; static gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data) { switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { GError *err; gchar *debug; gst_message_parse_error (message, &err, &debug); g_print ("Error: %s\n", err->message); g_error_free (err); g_free (debug); g_main_loop_quit (loop); break; } case GST_MESSAGE_EOS: { g_print ("\n\nYou've got 100 points!\n"); g_main_loop_quit (loop); break; } default: break; } /*  TRUE,   ,       */ return TRUE; } int main (int argc, char * argv[]) { if (argc != 3) { g_printerr("Usage: %s audiofile.mp3 lyricsfile.txt\n", argv[0]); return -1; } GstElement *pipeline, *audiosrc, *parser, *decoder, *converter, *karaoke, *audiosink; GstElement *textsrc, *textsink; GstStateChangeReturn ret; GstBus *bus; guint bus_watch_id; /*  */ gst_init(NULL, NULL); /*   */ pipeline = gst_element_factory_make ("pipeline", "pipe"); audiosrc = gst_element_factory_make ("filesrc", "audiosrc"); parser = gst_element_factory_make ("mpegaudioparse", "parser"); decoder = gst_element_factory_make ("mad", "decoder"); converter = gst_element_factory_make ("audioconvert", "converter"); karaoke = gst_element_factory_make ("audiokaraoke", "karaoke"); audiosink = gst_element_factory_make ("autoaudiosink", "audiosink"); textsrc = gst_element_factory_make ("filesrc", "textsrc"); textsink = gst_element_factory_make ("fdsink", "textsink"); if (!pipeline || !audiosrc || !parser || !decoder || !converter || !karaoke || !audiosink || !textsrc || !textsink) { g_printerr ("Unable to create some elements\n"); return -1; } /*     */ gst_bin_add_many (GST_BIN(pipeline), audiosrc, parser, decoder, converter, karaoke, audiosink, textsrc, textsink, NULL); /*    */ if (gst_element_link_many (audiosrc, parser, decoder, converter, karaoke, audiosink, NULL) != TRUE) { g_printerr ("Unable to link some elements\n"); gst_object_unref(pipeline); return -1; } if (gst_element_link (textsrc, textsink) != TRUE) { g_printerr ("Unable to link text with textsink\n"); gst_object_unref(pipeline); return -1; } /*    */ g_object_set (audiosrc, "location", argv[1], NULL); g_object_set (textsrc, "location", argv[2], NULL); g_object_set (karaoke, "level", SUPRESS_LEVEL, "mono-level", MONO_LEVEL, "filter-band", FILTER_BAND, "filter-width", FILTER_WIDTH, NULL); /*   */ ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); if ( ret == GST_STATE_CHANGE_FAILURE ) { g_printerr ("Unable to set pipeline to the playing state\n"); gst_object_unref (pipeline); return -1; } /*          */ bus = gst_element_get_bus (pipeline); bus_watch_id = gst_bus_add_watch (bus, my_bus_callback, NULL); gst_object_unref (bus); /*     */ loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); /*   */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); g_source_remove (bus_watch_id); g_main_loop_unref (loop); return 0; }
      
      





通常通りコンパイルする

 $ gcc -Wall -o karaoke karaoke.c $(pkg-config --libs --cflags gstreamer-1.0)
      
      





そして走る

 $ ./karaoke audiofile.mp3 lyricsfile.txt
      
      





結果



次の曲でアプリケーションを(デフォルトのフィルター設定で)実行しようとしました:

効果
ツール-放物線 ボーカルは非常にうまくカットされましたが、多くのインストゥルメンタルを抑制しました(特にソロのフラオレット)
ドライブインで-ロロデックスプロパガンダ インストゥルメンタルはよく保存されていますが、ボーカルは非常に強く突破します(明らかに、その高さのため)
レディオヘッド-ジグソーフォールフォープレース ここでは非常に興味深い結果が出ました。メインボーカルが粉砕され、バックが残っています
U2-オオカミによって発生 ギターはほぼ完璧に保たれています


結果がフィルター設定と曲自体に強く依存することは明らかであるため、#defineで指定されたパラメーターで再生して何が起こるかを確認できます。



All Articles