-> 원문
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, argv를 gst_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 관련 설치 후 단순히 복붙해서 돌려봤던 예제입니다. 아직 잘 모르지만 일단 예제 분석한 것만으로 판단했을 때 확실히 튜토리얼에서 말하는 것처럼 고수준으로 구현되어 있는 것 같습니다. 몇 줄 끄적이니 영상이 나오네요... 이런 걸 어떻게 만들었는지.. 대단합니다.
'개발 > c' 카테고리의 다른 글
[번역][gstreamer] basic tutorial 3: Dynamic pipelines (0) | 2022.01.28 |
---|---|
[번역][gstreamer] basic tutorial 2: Manual Hello world! (0) | 2022.01.18 |
[번역][gstreamer] Tutorials을 시작하며... (0) | 2022.01.10 |
[gstreamer] windows에서 설치 및 예제 빌드 (0) | 2022.01.04 |
[백준] 15683 감시 (0) | 2020.05.09 |