전체 소스코드
#include <gst/gst.h>
#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
int
tutorial_main (int argc, char *argv[])
{
GstElement *pipeline, *source, *sink;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
/* Initialize GStreamer */
gst_init (&argc, &argv);
/* Create the elements */
source = gst_element_factory_make ("videotestsrc", "source");
sink = gst_element_factory_make ("autovideosink", "sink");
/* Create the empty pipeline */
pipeline = gst_pipeline_new ("test-pipeline");
if (!pipeline || !source || !sink) {
g_printerr ("Not all elements could be created.\n");
return -1;
}
/* Build the pipeline */
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
if (gst_element_link (source, sink) != TRUE) {
g_printerr ("Elements could not be linked.\n");
gst_object_unref (pipeline);
return -1;
}
/* Modify the source's properties */
g_object_set (source, "pattern", 0, NULL);
/* Start playing */
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr ("Unable to set the pipeline to the playing state.\n");
gst_object_unref (pipeline);
return -1;
}
/* 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);
/* Parse message */
if (msg != NULL) {
GError *err;
gchar *debug_info;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error (msg, &err, &debug_info);
g_printerr ("Error received from element %s: %s\n",
GST_OBJECT_NAME (msg->src), err->message);
g_printerr ("Debugging information: %s\n",
debug_info ? debug_info : "none");
g_clear_error (&err);
g_free (debug_info);
break;
case GST_MESSAGE_EOS:
g_print ("End-Of-Stream reached.\n");
break;
default:
/* We should not reach here because we only asked for ERRORs and EOS */
g_printerr ("Unexpected message received.\n");
break;
}
gst_message_unref (msg);
}
/* Free resources */
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}
int
main (int argc, char *argv[])
{
#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE
return gst_macos_main ((GstMainFunc) tutorial_main, argc, argv, NULL);
#else
return tutorial_main (argc, argv);
#endif
}
코드 설명
// 요소 생성
source = gst_element_factory_make ("videotestsrc", "source");
sink = gst_element_factory_make ("autovideosink", "sink");
gst_element_factory_make(value1, value2)
- 새로운 요소(element) 생성
- value1은 생성할 요소의 type
- value2는 특정 인스턴스에 부여하려는 이름 -> 요소 검색에 유용함.
videotestsrc
- 테스트 비디오 패턴을 생성하는 소스(학습용 데이터 생성)
autovideosink
- 이미지를 창에 표시(데이터 사용)
- 운영체제에 따라 여러개의 videosink가 있는데 autovideosink로 설정하면 자동으로 가장 좋은 것을 선택해줌.
// 파이프라인 생성
pipeline = gst_pipeline_new("test-pipeline");
// 파이프라인 구축
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
if (gst_element_link (source, sink) != TRUE)
{
gst_printerr ("요소가 연결되어 있지 않음.\n");
gst_object_unref (pipeline);
return -1;
}
gst_pipeline_new
- 새로운 파이프라인 생성
gst_bin_add_many
- 파이프라인에 요소를 추가
- 추가할 요소들을 나열한 후 NULL로 끝남.
- 요소들을 하나씩 추가하려면 gst_bin_add를 사용
gst_element_link(value1, value2)
- 각 요소들을 서로 연결시켜줌.
- value1은 소스, value2는 대상
- link는 데이터의 흐름에 따라 소스요소에서 싱크요소로 설정되어야 하기 때문에 순서가 중요함.
- 동일한 저장소에 있는 요소만 연결이 가능하기 때문에 연결을 시도하기 전, 파이프라인에 요소들을 추가해 두어야함.
// Source의 속성 수정
g_object_set (source, "pattern", 0, NULL);
속성
- Gstreamer의 요소들은 모두 속성을 가진 GObject이다.
- g_object_get으로 읽고 g_object_set으로 사용(변경)함.
g_object_set
- 속성-이름, 속성-값 쌍의 NULL로 끝나는 목록들을 나열하여 한 번에 변경할 수 있음.
- 위의 코드는 source인 "videotestsrc"의 "pattern" 속성을 변경한다.
// 플레이 시작
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
// 오류 확인
if(ret == GST_STATE_CHANGE_FAILURE)
{
g_printerr ("파이프라인을 플레이 상태로 바꿀 수 없습니다.\n");
gst_object_unref (pipeline);
return -1;
}
gst_element_set_state
- playing 상태로 변경한 결과를 ret에 저장
- 반환 값 ret을 이용해 오류확인
// 에러가 발생하거나 EOS에 도달할 때까지 대기
bus = gst_element_get_bus (pipeline);
msg =
gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
// 메세지 parse(분석)
if (msg != NULL)
{
GError *err;
gchar *debug_info;
switch (GST_MESSAGE_TYPE (msg))
{
case GST_MESSAGE_ERROR:
gst_message_parse_error (msg, &err, &debug_info);
g_printerr ("요소로부터 에러 발생 %s : %s\n", GST_OBJECT_NAME (msg->src), err->message);
g_printerr ("정보 디버깅 : %s\n", debug_info ? debug_info : "none");
g_clear_error (&err);
g_free (debug_info);
break;
case GST_MESSAGE_EOS:
g_print ("End-Of-Stream 도달.\n");
break;
default:
g_printerr("예기치 못한 메세지를 받음.\n");
break;
}
gst_message_unref (msg);
}
gst_bus_timed_pop_filtered
- 실행이 끝날 때까지 기다렸다가 이전에 무시했던 GstMessage를 반환.
- 어떤 일이 발생했는지 확인을 마친 후 만약 오류나 EOS를 만났다면 메세지 반환.
gst_message_parse_error
- 메세지에 오류가 포함되어 있다면, GError 오류 구조와 디버깅에 유효한 문자열을 반환.
Gstreamer 버스
- 요소에 의해 생성된 GstMessage를 순서대로 애플리케이션의 Thread에 전달하는 역할을 하는 객체
- 하지만 실제 미디어 스트리밍은 애플리케이션의 Thread가 아닌 다른 Thread에서 수행된다는 점이 중요함.
- 메세지는 gst_bus_timed_pop_filtered와 비슷한 함수들을 이용해 버스에서 동기적으로 추출되거나, 신호를 사용하여 비동기적으로 추출될 수 있음.
결과
정리
gst_element_factory_make : 요소를 생성
gst_pipeline_new : 빈 파이프라인 생성
gst_bin_add_many : 파이프라인에 요소를 추가
gst_element_link : 요소들을 서로 연결
참고자료