본문 바로가기
Study/Gstreamer

[Gstreamer] Gstreamer 기본 튜토리얼 2

by 스테디코디스트 2024. 3. 21.
반응형
전체 소스코드
#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 : 요소들을 서로 연결

 

참고자료
 

Basic tutorial 2: GStreamer concepts

Please port this tutorial to javascript! Basic tutorial 2: GStreamer concepts Goal The previous tutorial showed how to build a pipeline automatically. Now we are going to build a pipeline manually by instantiating each element and linking them all together

gstreamer.freedesktop.org