소스 원소
필터 원소
싱크 원소
디먹서 원소
각 원소에는 pad라는 구성 요소를 가지고 있다.
소스에는 src pad, 싱크에는 sink pad, 필터의 경우에는 src 와 sink pad를 동시에 가지고 있는 경우이다.
demuxer의 경우에는 여러 미디어를 분리해내서 출력하기 때문에 여러 개의 src pad가 존재할 수 있다. 그리고, 입력을 파싱하는 과정에서 몇 개의 pad가 존재하는지 알 수 있기 때문에 생성할 때 pad를 결정할 수 없다.
결정할 수 있는 시점에서 동적으로 파이프라인을 구성하는 방법이 필요하다.
/* Create the elements */
data.source = gst_element_factory_make ("uridecodebin", "source");
data.convert = gst_element_factory_make ("audioconvert", "convert");
data.resample = gst_element_factory_make ("audioresample", "resample");
data.sink = gst_element_factory_make ("autoaudiosink", "sink");
uridecodebin
은 디벅서를 포함하고 있기 때문에 source pad를 바로 사용할 수는 없다.
if (!gst_element_link_many (data.convert, data.resample, data.sink, NULL)) {
g_printerr ("Elements could not be linked.\n");
gst_object_unref (data.pipeline);
return -1;
}
원소들을 연결하지만, 소스와는 연결하지 않는다.
/* Set the URI to play */
g_object_set (data.source, "uri", "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL);
소스의 프로퍼티를 지정한다.
/* Connect to the pad-added signal */
g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler), &data);
uridecodebin
은 pad-added
신호를 발생시킨다. 이 신호에 대해 pad_added_handler 라는 콜백 함수를 등록하여 처리한다.
static void pad_added_handler (GstElement *src, GstPad *new_pad, CustomData *data) {
new_pad
는 소스 원소에 추가되는 pad이다. 콜백 함수 등록할 때 함께 설정해준 데이터(포인터)가 함께 인자로 넘어온다.
GstPad *sink_pad = gst_element_get_static_pad (data->convert, "sink");
소스 원소의 pad와 연결할 싱크 pad를 얻어와야 한다. 연결될 싱크 pad는 audioconvert 원소에 포함되어 있다.
/* If our converter is already linked, we have nothing to do here */
if (gst_pad_is_linked (sink_pad)) {
g_print ("We are already linked. Ignoring.\n");
goto exit;
}
이미 연결되어 있는 경우는 연결하지 않는다.
/* Check the new pad's type */
new_pad_caps = gst_pad_get_current_caps (new_pad, NULL);
new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
new_pad_type = gst_structure_get_name (new_pad_struct);
if (!g_str_has_prefix (new_pad_type, "audio/x-raw")) {
g_print ("It has type '%s' which is not raw audio. Ignoring.\n", new_pad_type);
goto exit;
}
uridecodebin
은 여러 pad를 생성할 수 있으며, 각각에 대해 콜백 함수가 호출된다. pad의 정보를 통해 한 번만 연결한다.
최종적으로 얻게 되는 prefix가 audio/x-raw
가 아니라면 오디오가 아니므로, 처리하지 않는다.
/* Attempt the link */
ret = gst_pad_link (new_pad, sink_pad);
if (GST_PAD_LINK_FAILED (ret)) {
g_print ("Type is '%s' but link failed.\n", new_pad_type);
} else {
g_print ("Link succeeded (type '%s').\n", new_pad_type);
}
gst_element_link()
와 유사하게 두 개의 pad를 연결한다.
NULL, READY, PAUSED, PLAYING, 4가지의 상태가 있다.
상태 변경은 뛰어 넘어서 이동할 수 없다. 즉, NULL에서 PLAYING으로 넘어갈 수는 없다.
case GST_MESSAGE_STATE_CHANGED:
/* We are only interested in state-changed messages from the pipeline */
if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data.pipeline)) {
GstState old_state, new_state, pending_state;
gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
g_print ("Pipeline state changed from %s to %s:\n",
gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
}
break;
상태가 변경될 때, 확인할 수 있는 메시지를 남긴다.