본문 바로가기
IT와 개발/GStreamer Study

Bus

by 도서 임보자 2024. 4. 19.

Bus는 스트리밍 스레드에서 자체 스레드 컨텍스트의 애플리케이션으로 메시지를 전달하는 간단한 시스템입니다. Bus의 장점은 GStreamer 자체가 많은 스레드를 사용하더라도 GStreamer를 사용하기 위해 애플리케이션이 스레드를 인식할 필요가 없다는 것입니다.

 

모든 파이프라인에는 기본적으로 bus가 포함되어 있으므로 애플리케이션은 bus 등을 생성할 필요가 없습니다. 애플리케이션이 해야 할 유일한 일은 bus에 메시지 핸들러를 설정하는 것인데, 이는 객체에 대한 시그널 핸들러와 유사합니다. 메인 루프가 실행 중일 때 bus는 주기적으로 새 메시지를 확인하고 메시지가 있으면 콜백이 호출됩니다.

 

Bus 사용법

Bus를 사용하는 방법에는 두 가지가 있습니다.

  • GLib/Gtk+ 메인 루프를 실행하고 (또는 기본 GLib 메인 컨텍스트를 정기적으로 반복) bus에 일종의 watch를 연결하십시오. 이런 방식으로 GLib 메인 루프는 bus에서 새 메시지를 확인하고 메시지가 있을 때마다 알려줍니다.

    일반적으로 이 경우 gst_bus_add_watch() 또는 gst_bus_add_signal_watch()를 사용합니다.

    Bus를 사용하려면 gst_bus_add_watch()를 사용하여 파이프라인의 bus에 메시지 핸들러를 연결합니다. 이 핸들러는 파이프라인이 버스에 메시지를 내보낼 때마다 호출됩니다. 이 핸들러에서 시그널 유형 (다음 섹션 참조)을 확인하고 그에 따라 작업을 수행합니다. 핸들러를 bus에 계속 연결하려면 핸들러의 반환 값이 TRUE여야 하고, 핸들러를 제거하려면 FALSE를 반환해야 합니다.
  • Bus에서 직접 메시지를 확인하세요. 이는 gst_bus_peek() 및/또는 gst_bus_poll()을 사용하여 수행할 수 있습니다.
#include <gst/gst.h>

static GMainLoop *loop;

static gboolean
my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
{
  g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));

  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:
      /* end-of-stream */
      g_main_loop_quit (loop);
      break;
    default:
      /* unhandled message */
      break;
  }

  /* 다음에 bus에 메시지가 있을 때 다시 알림을 받고 싶기 때문에
   * TRUE를 반환합니다 (FALSE는 버스에서 메시지 감시를 중지하고
   * 콜백을 다시 호출해서는 안 된다는 의미입니다).
   */
  return TRUE;
}

gint
main (gint argc, gchar * argv[])
{
  GstElement *pipeline;
  GstBus *bus;
  guint bus_watch_id;

  /* init */
  gst_init (&argc, &argv);

  /* create pipeline, add handler */
  pipeline = gst_pipeline_new ("my_pipeline");

  /* 파이프라인의 메시지 bus에 있는 새 메시지에 대한 감시를
   * default GLib main context에 추가합니다.
   * 이는 GLib 메인 루프가 아래에 연결된 main context입니다.
   */
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  bus_watch_id = gst_bus_add_watch (bus, my_bus_callback, NULL);
  gst_object_unref (bus);

  /* [...] */

  /* Default GLib main context (context NULL)를 실행/반복하는
   * 메인 루프를 생성합니다. 즉, context가 감시하는 것이 발생했는지
   * 확인하도록 만듭니다. 메시지가 bus에 게시되면 default main context는
   * 자동으로 my_bus_callback() 함수를 호출하여 해당 메시지를 알려줍니다.
   * 메인 루프는 누군가 g_main_loop_quit()을 호출할 때까지 실행됩니다.
   */
  loop = g_main_loop_new (NULL, FALSE);
  g_main_loop_run (loop);

  /* clean up */
  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;
}

 

메인 루프의 스레드 컨텍스트에서 핸들러가 호출된다는 사실을 아는 것이 중요합니다. 이는 bus를 통한 파이프라인과 애플리케이션 간의 상호 작용이 비동기식이므로 오디오 트랙 간의 크로스 페이딩, (이론적으로) 간격 없는 재생 또는 비디오 이팩트와 같은 일부 실시간 목적에는 적합하지 않음을 의미합니다. 이러한 모든 작업은 파이프라인 컨텍스트에서 수행되어야 하며 GStreamer 플러그인을 작성하면 가장 쉽습니다. 그러나 이는 파이프라인에서 애플리케이션으로 메시지를 전달하는 원래 목적에는 매우 유용합니다. 이 접근 방식의 장점은 GStreamer가 내부적으로 수행하는 모든 스레딩이 애플리케이션에서 숨겨지고 애플리케이션 개발자가 스레드 문제에 대해 전혀 걱정할 필요가 없다는 것입니다.

 

Default GLib 메인 루프 통합을 사용하는 경우 watch를 연결하는 대신 bus의 "메시지" 시그널에 연결할 수 있습니다. 이렇게 하면 가능한 모든 메시지 유형에 대해 switch()를 수행할 필요가 없습니다. message::<type> 형식으로 관심있는 시그널에 연결하기만 하면 됩니다. 여기서 <type>은 특정 메시지 유형입니다 (메시지 유형에 대한 설명은 다음 섹션 참조).

 

위의 내용은 다음과 같이 작성할 수도 있습니다.

GstBus *bus;

[..]

bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_signal_watch (bus);
g_signal_connect (bus, "message::error", G_CALLBACK (cb_message_error), NULL);
g_signal_connect (bus, "message::eos", G_CALLBACK (cb_message_eos), NULL);

[..]

 

GLib 메인 루프를 사용하지 않는 경우 기본적으로 비동기 메시지 시그널을 사용할 수 없습니다. 그러나 사용자 정의 동기 핸들러를 설치하여 사용자 정의 메인 루프를 깨우고 gst_bus_async_signal_func()를 사용하여 시그널을 발생시킬 수 있습니다. (자세한 내용은 설명서도 참조하세요)

 

Message types

GStreamer에는 bus를 통해 전달될 수 있는 몇 가지 사전 정의된 메시지 유형이 있습니다. 그러나 메시지는 확장 가능합니다. 플러그인은 추가 메시지를 정의할 수 있으며, 애플리케이션은 해당 메시지에 대한 특정 코드를 갖거나 무시하도록 결정할 수 있습니다. 모든 애플리케이션은 최소한 사용자에게 시각적 피드백을 제공하여 오류 메시지를 처리하는 것이 좋습니다.

 

모든 메시지에는 메시지 소스, 유형 및 타임스탬프가 있습니다. 메시지 소스를 사용하여 메시지를 생성한 요소를 확인할 수 있습니다. 예를 들어 일부 메시지의 경우 대부분의 애플리케이션에서는 최상위 파이프라인에서 생성된 메시지만 관심을 가질 것입니다 (예: 상태 변경 알림). 다음은 모든 메시지 목록과 해당 메시지가 수행하는 작업, 메시지 별 콘텐츠를 구문 분석하는 방법에 대한 간단한 설명입니다.

 

  • 오류, 경고 및 정보 알림
    • 파이프라인 상태에 대한 메시지를 사용자에게 표시해야 하는 경우 element에서 사용됩니다. Fatal 메시지는 치명적이며 데이터 전달을 종료합니다. 파이프라인 활동을 재개하려면 오류를 수정해야 합니다. Warning는 치명적이지는 않지만 문제가 있음을 암시합니다. Information 메시지는 문제가 없는 알림을 위한 것입니다. 모든 메시지에는 주요 오류 유형과 메시지가 포함된 GError가 포함되어 있으며 선택적으로 디버그 문자열도 포함되어 있습니다. 둘 다 gst_message_parse_error(), _parse_warning() 및 _parse_info()를 사용하여 추출할 수 있습니다. 사용 후에는 오류 문자열과 디버그 문자열을 모두 해제해야 합니다.
  • 스트림 종료 알림
    • 스트림이 종료되면 표시됩니다. 파이프라인 상태는 변경되지 않지만 추가 미디어 처리가 중단됩니다. 애플리케이션은 이를 사용하여 재생 목록의 다음 노래로 건너뛸 수 있습니다. 스트림이 종료된 후에 스트림의 특정 시점으로 돌아가는 것도 가능합니다. 그러면 자동으로 재생이 계속됩니다. 이 메시지에는 특정 인수가 없습니다.
  • 태그
    • 스트림에서 메타 데이터가 발견되면 생성됩니다. 파이프라인에 대해 여러 번 내보낼 수 있습니다 (예: 아티스트 이름이나 노래 제목과 같은 정보를 설명하는 메타 데이터에 대해 한 번, 샘플 속도 및 비트 전송률과 같은 스트림 정보에 대해 한 번). 애플리케이션은 메타 데이터를 내부적으로 캐시해야 합니다. gst_message_parse_tag()는 태그 목록을 구문 분석하는 데 사용되며, 이 태그 목록이 더 이상 필요하지 않을 때 gst_tag_list_unref()가 사용 됩니다.
  • 상태 변경
    • 성공적인 상태 변경 후에 발생합니다. gst_message_parse_state_changed()를 사용하여 이 전환의 이전 상태와 새 상태를 구문 분석할 수 있습니다.
  • 버퍼링
    • 네트워크 스트림을 캐싱하는 동안 발생합니다. gst_message_get_structure()에 의해 반환된 구조체에서 "buffer-percent" 속성을 추출하여 메시지에서 진행률(%)을 수동으로 추출할 수 있습니다. Buffering도 참조하세요.
  • Element 메시지
    • 이들은 특정 element에만 해당되며 일반적으로 추가 기능을 나타내는 특별한 메시지입니다. Element의 문서에서는 특정 element가 어떤 element 메시지를 전송할 수 있는지에 대해 자세히 언급해야 합니다. 예를 들어 'qtdemux' QuickTime demuxer element는 스트림에 리디렉션 지시가 포함되어 있는 경우에는 'redirect' element 메시지를 전송할 수 있습니다.
  • 응용 프로그램별 메시지
    • 이러한 메시지에 대한 정보는 메시지 구조체를 가져와서 해당 필드를 읽으면 추출할 수 있습니다(위 참조). 보통 이러한 메시지는 안전하게 무시할 수 있습니다.
    • 응용 프로그램 메시지는 주로 애플리케이션에서 어떤 스레드의 정보를 메인 스레드로 전달 할 때 내부적으로 사용됩니다. 이것은 특히 애플리케이션이 element 시그널을 사용할 때 유용합니다 (이러한 시그널은 스트리밍 스레드의 context에서 발생합니다).

 

 

원문: Bus (gstreamer.freedesktop.org)

 

Bus

Bus A bus is a simple system that takes care of forwarding messages from the streaming threads to an application in its own thread context. The advantage of a bus is that an application does not need to be thread-aware in order to use GStreamer, even thoug

gstreamer.freedesktop.org

 

반응형

'IT와 개발 > GStreamer Study' 카테고리의 다른 글

Buffers and Events  (0) 2024.05.03
Pads and capabilities  (1) 2024.04.26
Bins  (1) 2024.04.12
Elements  (0) 2024.04.05
GStreamer 초기화  (0) 2024.03.29