GStreamer 튜토리얼 - 1 : Hello World!
목표 모든 프로그래밍의 시작은 Hello World!를 출력하는 것에서 출발한다. GStreamer는 멀티미디어 프레임워크이므로 대신에 간단한 비디오를 출력해보는 것으로 시작한다. 하단에 매우 긴 소스코드가 있지만 실제 동작에 관여하는 코드는 4줄이며 나머지 부분은 메모리 관리와 같은 cleanup code 부분으로, 기본적으로 튜토리얼이 C로 쓰여져있기 때문에 사용되는 verbose한 부분이다. 소스 코드 다음은 웹상에 존재하는 비디오 리소스를 받아 실행하는 코드이다. #include <gst/gst.h> int main(int argc, char *argv[]) { GstElement *pipeline; GstBus *bus; GstMessage *msg; gst_init(&argc, &argv); pipeline = gst_parse_launch("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL); gst_element_set_state(pipeline, GST_STATE_PLAYING); bus = gst_element_get_bus(pipeline); msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); if (msg != NULL) { gst_message_unref(msg); } gst_object_unref(bus); gst_element_set_state(pipeline, GST_STATE_NULL); gst_object_unref(pipeline); return 0; } 소스코드를 빌드 후 실행하면 화면에 동영상이 실행된다. 다만, 비디오 리소스가 인터넷 상에 존재하므로 인터넷 속도에 따라 불러오는 데 시간이 조금 걸릴 수 있으며, 버퍼링과 같은 latency management는 이루어지지 않으므로 실행 도중에 멈출 수도 있다. 코드의 의미 /* Initialize GStreamer */ gst_init(&argc, &argv) 모든 GStreamer 코드는 gst_init()으로 시작하며 다음 역할을 수행한다. 모든 내부 구조 초기화 사용 가능한 플러그인 체크 Gstreamer에 의도된 모든 커맨드라인 옵션을 실행 (gst_init()에 인자로 &argc와 &argv를 전달하는 이유) pipeline = gst_parse_launch("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL); 해당 코드는 이번 튜토리얼의 핵심이 되는 부분이며 두가지 부분을 주목해야 한다. gst_parse_launch GStreamer은 멀티미디어(동영상, 음성 등)의 흐름을 제어하는 프레임워크이며, 이 흐름은 Source(the producer)에서 Sink(the consumer)로 향하게 된다. 이 과정에서 중간에 여러 중간 요소를 거치게 되는데 이 요소들은 다양한 작업을 수행하게 된다. 이러한 요소들이 연결된 것을 Pipeline이라 부른다. GStreamer에서 이러한 pipeline을 수동으로 구성할 수도 있지만, 이번 튜토리얼과 같은 단순한 작업에 대해서는 복잡한 과정을 거칠 필요 없이 pipeline 구성을 자동으로 해주는 함수를 호출하여 해결 가능하다. 이러한 역할을 하는 함수가 바로 gst_parse_launch()이다. gst_parse_launch()는 텍스트로 이루어진 파이프라인 표현식을 실제 파이프라인으로 반환하는 간편한 함수이다. 위의 코드는 텍스트 형태로 playbin이라는 녀석과 파이프라인에 입력될 비디오를 URI라고 하는 주소의 형태로 전해주고 있다. playbin 그렇다면 우리는 이 playbin이라는 것이 무엇인지에 대해 알 필요가 있다. 앞서 설명하기를 멀티미디어의 흐름은 source에서 sink로 향하며 그 사이의 중간 과정들을 묶은 것을 pipeline이라고 하였다. 여기서 playbin은 그 자체로 source 및 sink의 역할을 하며 또한 완전한 파이프라인이다. 즉, 내부적으로 playbin은 멀티미디어를 실행할 수 있도록 해주는 요소를 생성하고 연결해주는 역할을 한다. 이번 튜토리얼은 playbin에 단 하나의 인자를 전달하고 있는데, 바로 우리가 실행하고자 하는 미디어의 URI이다. 해당 미디어가 https:// 프로토콜로 전달되는데, http:// 혹은 file:// 형식으로 전달되도 상관 없으며, 이에 따라 playbin은 적절한 GStreamer source를 인스턴스화하게 된다. playbin은 그 사용법이 간단하다는 장점이 있으나 원래대로라면 수동으로 pipeline을 구성해주는 과정을 자동화해주므로 우리는 세세한 과정에 대한 컨트롤이 불가하다는 단점이 있다. 그럼에도 다양한 방면에서 활용이 가능하도록 충분한 커스터마이징이 가능하므로 이번 튜토리얼과 같은 경우에 대해서는 충분히 사용 가능하다. /* Start Playing */ gst_element_set_state(pipeline, GST_STATE_PLAYING); 모든 GStreamer의 요소는 연관된 state를 가지고 있다. 예를 들어 DVD 플레이어의 Play/Pause가 대표적인 state의 예이며 이외에도 다양한 state가 존재한다. 현재로서는 pipeline을 PLAYING state로 세팅하지 않으면 재생을 시작하지 않는 경우로 충분하다. 따라서 해당 코드는 함수 gst_element_set_state()를 통해 pipeline을 PLAYING state로 세팅해 재생을 시작하는 의미이다. /* 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); 해당 코드에는 Bus와 Message라는 것이 등장한다. 두 단어의 의미는 통상적인 의미와 비슷한데, message는 둘 이상의 객체간에 상호작용을 위한 메시지이고 bus는 이 메시지를 옮기는 데 사용되는 수단이다. 해당 pipeline에서 사용될 bus를 인스턴스화하기 위해 함수 gst_element_get_bus() 함수가 사용되었다. 또한 메시지를 만드는 데 사용한 함수 gst_bus_timed_pop_filtered()는 bus로 부터 message를 얻을 때 사용되며 받고자 하는 message type을 세번째 인자로 지정해 주었다 (Error 혹은 EOS, End-Of-Stream). 두번째 인자는 timeout을 지정해줄 수 있는데, GST_CLOCK_TIME_NONE은 timeout을 지정해주지 않고 영원히 기다리겠다는 의미이다. Cleanup 어플리케이션을 종료하기 전에 약간의 사후 처리 작업이 필요하다. /* Free Resources */ if (msg != NULL) { gst_message_unref(msg); } gst_object_unref(bus); gst_element_set_state(pipeline, GST_STATE_NULL); gst_object_unref(pipeline); 인스턴스화한 pipeline과 bus 및 message는 작업이 끝나면 메모리 상에서 해제해주어야 한다. 이때 사용하는 함수가 gst_object_unref()와 gst_message_unref()이다. 다만 pipeline은 해제해주기 전에 함수 gst_element_set_state() 함수를 통해 NULL state로 만들어주는데 이는 pipeline을 통해 메모리에 할당된 어느 리소스라도 메모리 상에서 해제할 수 있도록 함이다. 최종적으로 pipeline까지 unreferencing을 함으로써 모든 객체가 메모리상에서 해제되고 프로그램이 종료된다. 요약 GStreamer Initialization : gst_init() Quick building pipeline from a textual description : gst_parse_launch() Creating an automatic playback pipeline : playbin Signaling Gstreamer to start playback : gst_element_set_state() Leaving the left process up to GStreamer : gst_element_get_bus() & gst_bus_timed_pop_filtered() 출처 Gstreamer Basic Tutorial 1: Hello World!