버스는 메시지를 스레드 컨텍스트에서 스트리밍 스레드에서 애플리케이션으로 전달하는 것을 관리하는 시스템입니다. 버스의 이점은 애플리케이션이 GStreamer가 많은 스레드로 동작함에도 GStreamer를 사용하는데 스레드 회피가 필요 없다는 것입니다.

모든 파이프라인은 기본적으로 버스를 가집니다. 그래서 애플리케이션은 버스를 만들거나 다른 일을 할 필요가 없습니다. 애플리케이션에서 해야하는 단 하나의 일은 버스에 메시지 핸들러를 설정하는 것입니다. 이 메시지 핸들러는 오브젝트에 있는 메시지 핸들러와 비슷합니다. 메인 루프가 동작하는 중에는 버스는 주기적으로 메시지를 확인하고, 메시지가 있을 경우 콜백 함수를 호출합니다.

 

7.1. 버스 사용법

버스를 사용하는데는 두 가지 방법이 있습니다.

  • GLib/GTK+의 메인 루프를 실행하고, 버스를 확인하는 시나리오를 추가합니다. GLib 메인 루프가 버스의 새로운 메시지를 확인하고, 새로운 메시지가 도착하면 바로 알려줍니다.
    • 이러한 경우, gst_bus_add_watch ()나 gst_bus_add_signal_watch () 함수를 사용합니다.
    • 버스를 사용하기 위해 gst_bus_add_watch () 함수를 사용해 파이프라인에 버스 메시지 핸들러를 추가할 수 있습니다. 이 핸들러는 파이프라인이 버스에 메시지를 보내면 호출됩니다. 이 핸들러는 시그널의 타입(다음 절 참조)을 확인하고, 이에 따르는 동작을 수행해야 합니다. 핸들러를 버스에 계속 붙어 있게 하려면 핸들러의 리턴값은 TRUE여야 합니다. 핸들러 제거를 위해 FALSE를 리턴합니다.
  • 버스에서 메시지를 직접 처리할 수 있습니다. 이 경우 gst_bus_peek ()나 gst_bus_poll () 함수를 이용합니다.

메인 루프의 스레드 컨텍스트에서 핸들러를 호출한다는 것이 중요합니다. 이것의 의미는 버스를 통한 애플리케이션과 파이프라인간 상호작용은 비동기적으로 수행되어 오디오 트랙 간 크로스 페이딩, 끊김 없는(이론적으로) 미디어 플레이, 비디오 이펙트 같은 일부 실시간 처리에 맞지 않다는 것입니다. 이런 모든 것은 파이프라인 컨텍스트에서 수행되어야 합니다. 이것은 플러그인을 작성하는 것으로 가장 쉽게 달성할 수 있습니다. 이런 것이 파이프라인에서 애플리케이션으로 메시지를 전달한다는 버스의 첫 번째 목적에 상당히 유용합니다. 이러한 접근 방법의 장점은 애플리케이션으로부터 GStreamer 내부의 스레드를 숨겨 애플리케이션 개발자는 스레드 관련 이슈를 걱정할 필요가 없게 된다는 점입니다.

기본 GLib의 메일 루트를 사용한다면, 버스에 감시(watch)를 붙이는 대신 버스에 시그널을 연결시킬 수 있습니다. 이 경우 switch문으로 메시지 타입을 구별할 필요가 없고,  관심있는 시그널을 “message::<타입>”의 형태로 추가해주면 됩니다. <타입>에 특정한 메시지 타입을 적어주면 됩니다(다음 절의 메시지 타입 부분 참고).

위에서 설명한 것은 아래와 같이 작성될 수 있습니다.

GLib 메인 루프를 사용하지 않는다면, 기본으로 비동기적 메시지 시그널을 사용할 수 없습니다. 커스턴 메인 루프를 깨워 줄 커스텀 싱크 핸들러를 설치해야 하고, gst_bus_async_signal_func () 함수를 사용하여 시그널을 보내줘야 합니다(자세한 내용은 http://gstreamer.freedesktop.org/data/doc/gstreamer/stable/gstreamer/html/GstBus.html 문서에서 확인할 수 있습니다).


7.2. 메시지 타입

GStreamer에는 버스에서 전달해줄 수 있는 이미 정의된 메시지 타입이 존재합니다. 하지만 메시지 타입은 확장이 가능합니다. 플러그인은 추가 메시지를 정의할 수 있고, 애플리케이션은 이 메시지 처리 여부를 선택할 수 있습니다. 모든 애플리케이션은 최소한 에러 메시지를 처리하여, 사용자에게 시각적인 피드백을 주는 것을 강력하게 권장합니다.

모든 메시지는 메시지 소스와 타임 스탬프, 타입을 가지고 있습니다. 메세지 소스는 어떤 엘리먼트가 메시지를 보냈는지 확인하는데 사용할 수 있습니다. 예를 들어, 최상위 파이프 라인에서 보내는 어떤 메시지는 대부분의 애플리케이션이 관심을 가질 것 입니다(예, 상태 변화 알림). 아래에 모든 메시지와 메시지가 어떤일을 하기 위한것인지, 메시지에 특정한 내용을 어떻게 파싱할 것인지에 대한 간단한 설명이 담긴 리스트가 있습니다.

  • 에러, 경고, 정보 알림 : 이런 메시지는 파이프라인 상태에 관한 메시지를 유저에게 보여주기 위해 사용됩니다. 에러 메시지는 치명적이고, 데이터 전달을 종료시킵니다. 파이프라인을 동작하려면 에러를 해결해야 합니다. 경고는 치명적이지는 않지만 문제를 내포하고 있음을 의미합니다. 정보는 문제가 없는 알림을 의미합니다. 모든 메시지는 메인 에러 형태와 메시지와 디버그 스트링을 포함하는 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” 프로퍼티를 이용해 버퍼링의 진행 상태를 퍼센트 형태로 추출할 수 있습니다. 15장을 참고하세요.
  • 엘리먼트 메시지 : 특정 엘리먼트의 독특한 메시지이고, 일반적으로 추가기능을 나타냅니다. 엘리먼트 문서는 어떤 엘리먼트가 어떤 메시지를 보내는지 상세히 설명해야 합니다. 이 예로,  Quick Time Demuxer(qtdemux) 엘리먼트는 스트림이 리다이렉트 명령을 가지고 있으면 ‘redirect’ 엘리먼트 메시지를 보냅니다.
  • 애플리케이션 특정 메시지 : 이런 메시지의 정보는 메시지 구조체(위를 참고)에서 추출할 수 있고, 구조체의 필드로 읽을 수 있습니다. 보통 이런 메시지는 무시해도 안전합니다.
    • 애플리케이션 메시지는 주로 응용 프로그램이 어떤 스레드에서 메인 스레드로 스레드 관리에 관한 정보를 전달하기 위해 내부적으로 사용합니다. 특히 이것은 애플리케이션이 엘리먼트 시그널을 만들어 사용할 때 특히 유용합니다(이런 시그널이 스트리밍 스레드 컨텍스트에서 발생할 때).


Posted by _유부남J군_