-> 원문

Basic tutorials 1: Hello world!

l 목표

소프트웨어 라이브러리를 이해하는데 화면에 “Hello World”를 출력하는 것 보다 좋은 예제는 없다. 하지만 우리는 멀티미디어 프레임워크를 다루기 때문에 Hello World를 출력하는 대신 샘플 비디오 하나를 재생할 것이다.

아래 코드의 양만 보고 지레 겁먹지 않기를 바란다: 동작과 관련한 코드는 단 4줄이며 나머지는 정리 코드이다. C언어에서는 항상 코드가 길어진다.

l Hello World

basic-tutorial-1.c 파일을 만들고 아래 코드를 복사 붙여넣기 한다.

#include <gst/gst.h>
 
int
main (int argc, char *argv[])
{
  GstElement *pipeline;
  GstBus *bus;
  GstMessage *msg;
 
  /* Initialize GStreamer */
  gst_init (&argc, &argv);
 
  /* Build the pipeline */
  pipeline =
      gst_parse_launch
      ("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm",
      NULL);
 
  /* Start playing */
  gst_element_set_state (pipeline, GST_STATE_PLAYING);
 
  /* Wait until error or EOS */
  bus = gst_element_get_bus (pipeline);
  msg =
      gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
      GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
 
  /* See next tutorial for proper error message handling/parsing */
  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
    g_error ("An error occurred! Re-run with the GST_DEBUG=*:WARN environment "
        "variable set for more details.");
  }
 
  /* Free resources */
  gst_message_unref (msg);
  gst_object_unref (bus);
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  return 0;
}

코드 파일을 컴파일한다. 성공적으로 빌드가 되면 실행파일을 실행한다. 팝업 윈도우가 뜨고 인터넷으로부터 전송되는 비디오가 오디오와 함께 출력될 것이다.

-       필요한 라이브러리: gstreamer-1.0

tutorial은 윈도우 하나를 열고 영상을 출력한다. 미디어는 인터넷에서 가져온다. 그래서 인터넷 연결 상태에 따라 윈도우가 늦게 나타날 수 있다. 또한, 예제 코드에서는 지연 시간을(latency) 관리(buffering)하지 않는다. 때문에 연결상태가 안 좋은 경우 영상이 멈출 수 있다. issue를 해결하려면 Basic tutorial 12: Streaming을 확인한다.

l 상세 설명

예제 코드의 각 구문을 해석해본다.

/* Initialize GStreamer */
gst_init (&argc, &argv);
 

gst_init()함수는 반드시 GStreamer 관련한 어떤 코드 보다 앞서서 첫 번째로 호출되어야 한다.

-       모든 내부 structure를 초기화한다.

-       사용 가능한 Plug-in을 확인한다.

-       GStreamer 관련한 명령줄 옵션을 수행한다.

명령줄 인자 argc, argvgst_init()함수에 전달하면 애플리케이션은 자동으로 GStreamer 표준 명령줄 옵션을 수행한다. (상세 정보는 Basic tutorial 10: GStreamer tools를 참조한다.)

/* Build the pipeline */
  pipeline =
      gst_parse_launch
      ("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm",
      NULL);
 

위 구문은 이번 튜토리얼의 핵심이자 키포인트 두 가지를 제시한다: gst_parse_launch(), playbin.

l gst_parse_launch

GStreamer는 멀티 미디어의 흐름을 다루는 프레임워크이다. 미디어는 “source” 엘리먼트에서(생산자) “sink” 엘리먼트로(소비자) 이동한다(to down). 그 과정에서 여러가지 중간 엘리먼트를 지나오며 각 엘리먼트에서는 데이터를 조작할 수 있다. 연결된 엘리먼트의 묶음을 “pipeline”이라고 한다.

보통은 여러 개의 엘리먼트를 수동으로 붙여서 파이프라인을 만들지만 고급 기능이 필요 없고 파이프라인이 간단하다면 shortcut으로 “gst_parse_launch()”함수를 사용할 수 있다.

이 함수는 파이프라인을 표현한 문자열을 입력으로 받아서 실제 파이프라인을 생성하며 굉장히 유용하다. 사실, 이 함수는 너무 유용해서 관련하여 만들어진 tool도 있다. 계속해서 튜토리얼을 진행함에 따라 이 tool을 매우 잘 알게 될 것이다. (gst-launch-1.0 도구와 그 문법에 대한 상세 설명은 Basic tutorial 10: GStreamer tools를 참조한다.)

l playbin

그래서, 예제에선 어떤 종류의 파이프라인이 gst_parse_launch()을 통해 만들어질까? 여기서 두 번째 키포인트를 살펴본다: 우리는 playbin이라고 불리는 엘리먼트 하나로 구성된 파이프라인을 만들고 있다.

playbin은 특별한 엘리먼트로 source, sink 둘의 역할을 모두 한다. 자체로 하나의 파이프라인을 구성할 수 있다. 내부적으로 필요한 모든 엘리먼트를 생성하고 연결하여 미디어를 재생시킨다.

수동 파이프라인과 다르게 매우 자세한 제어는 할 수 없지만 충분한 customization도 제공한다.

이 예제에서 우리는 오직 하나의 파라미터만 playbin에 전달하고 있다. 재생시키고자 하는 미디어의 URI이다. URI을 바꿔보자. “https://”인지 “file://”인지에 따라 playbin이 적절한 source를 만들 것이다.

URI를 잘못 입력했거나 파일이 존재하지 않거나 plug-in을 빠뜨리는 등 실수할 수 있는데 GStreamer는 이에 대해 몇 가지 알림 시스템도 제공한다.

/* Start playing */
  gst_element_set_state (pipeline, GST_STATE_PLAYING);
 

구문에는 또 다른 개념이 숨어있다. “state”이다. 모든 GStreamer 엘리먼트는 상태와 관련이 있다. DVD 플레이어에서 재생/중지 버튼을 생각해보면 어느 정도 알 수 있다. 아직까지는 이것만 알아도 충분하다. 생성한 파이프라인의 상태를 PLAYING으로 설정하지 않는 한 미디어는 재생되지 않는다.

위 구문에서 gst_element_set_state()함수는 파이프라인을 PLAYING 상태로 설정하여 미디어를 재생한다.

/* Wait until error or EOS */
  bus = gst_element_get_bus (pipeline);
  msg =
      gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
      GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
 

구문은 에러가 발생하거나 미디어가 끝날 때까지 대기한다. gst_element_get_bus()함수는 파이프라인의 버스를 찾는다. gst_bus_timed_pop_filtered()함수는 버스를 통해 에러나 EOS가 반환될 때까지 block된다. Bus에 관해서는 Basic tutorial 2: GStreamer concepts를 참조한다.

이제 끝났다. 앞으로는 GStreamer가 모든 것을 관리한다. 미디어가 끝나거나 에러가 발생할 때(윈도우를 닫거나 인터넷이 끊겼을 때) 실행이 끝난다. 앱은 콘솔창에서 Ctrl+C를 눌러서 언제든지 끌 수 있다.

l 정리

앱이 끝나기 전에 몇 가지 정리해야 할 것이 있다.

/* See next tutorial for proper error message handling/parsing */
  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
    g_error ("An error occurred! Re-run with the GST_DEBUG=*:WARN environment "
        "variable set for more details.");
  }
 

항상 사용하는 함수에 대한 문서를 읽어라. 이를 통해 objects를 사용한 후 자원 해제를 해야 하는지 알 수 있다.

예제의 경우 gst_bus_timed_pop_filtered()함수는 message를 반환한다. 이는 gst_message_unref()함수로 자원 해제되어야 한다.

 

gst_element_get_bus()함수는 bus 객체에 대한 참조를 가져왔다. 이 역시 gst_object_unref()함수로 자원을 해제해야 한다. 파이프라인을 NULL 상태로 설정하기 전에 모든 할당한 자원을 해제해야 한다. 마지막으로 파이프라인을 해제한다.

l 결론

첫 번째 예제가 끝났다. 이 예제의 간결성으로 이 프레임워크가 얼마나 강력한지 알 수 있었기를 바란다.

간단히 이번 예제에서 배운 것을 요약한다.

-       어떻게 GStreamer를 초기화 하는가? gst_init()

-       어떻게 빠르게 문자 표현으로 파이프라인을 만들 수 있나? gst_parse_launch()

-       어떻게 playbin을 사용해서 자동으로 재생하는 파이프라인을 만들 수 있나?

-       어떻게 GStreamer가 재생을 시작하도록 만들 수 있나? gst_element_set_state()

-       어떻게 GStreamer가 모든 것을 진행하는 동안 프로그램을 유지시킬 수 있나? gst_element_get_bus() & gst_bus_timed_pop_filtered()

다음 튜토리얼은 계속해서 더 많은 기본 GStreamer 엘리먼트를 소개한다. 그리고 어떻게 수동으로 파이프라인을 구성하는지 배울 것이다.

 

이 전 글에서 gstreamer 관련 설치 후 단순히 복붙해서 돌려봤던 예제입니다. 아직 잘 모르지만 일단 예제 분석한 것만으로 판단했을 때 확실히 튜토리얼에서 말하는 것처럼 고수준으로 구현되어 있는 것 같습니다. 몇 줄 끄적이니 영상이 나오네요... 이런 걸 어떻게 만들었는지.. 대단합니다.

+ Recent posts