GStreamer 실전 가이드 | 파이프라인·C/Python·gst-launch로 멀티미디어 다루기
이 글의 핵심
GStreamer 1.x 파이프라인(Element·Pad·Caps), gst-launch-1.0 CLI, C gst_parse_launch·Bus 처리, Python PyGObject 재생 예제와 GST_DEBUG 디버깅을 한 흐름으로 정리합니다.
들어가며
GStreamer는 오디오·영상을 처리하는 오픈소스 멀티미디어 프레임워크입니다. 재생·녹화·인코딩·스트리밍·효과 처리까지 파이프라인이라는 그래프로 조립해 동작합니다.
이 글에서 다루는 것
- 파이프라인·Element·Pad·Caps의 최소 개념
gst-launch-1.0으로 빠르게 검증하는 방법- C와 Python에서 파이프라인을 돌리는 기본 패턴
- 에러 확인·디버그 로그(
GST_DEBUG)로 삽질 줄이기
GStreamer 1.x 기준으로 설명합니다.
목차
핵심 개념
파이프라인(Pipeline)
파이프라인은 연결된 Element들의 집합입니다. 데이터가 소스 → 필터 → 싱크 방향으로 흐릅니다.
[ filesrc ] → [ decodebin ] → [ audioconvert ] → [ autoaudiosink ]
(파일) (디코딩) (포맷 맞춤) (스피커)
- Element: 실제 동작 단위(읽기, 디코딩, 변환, 출력).
- Pad: Element의 입·출력 포트. Src pad는 데이터를 보내고 Sink pad는 받습니다.
- Caps(Capabilities): 포맷 협상에 쓰이는 설명(예:
video/x-raw, 샘플레이트, 픽셀 포맷). Pad가 연결될 때 호환 가능한 caps가 맞아야 합니다.
decodebin, playbin, uridecodebin 같은 빈(bin)은 내부에 여러 Element를 넣고 Pad를 동적으로 만들어 줍니다. 그래서 초보자는 이 셋부터 쓰면 삽질이 줄어듭니다.
gst-launch-1.0으로 시작하기
CLI로 파이프라인 문자열을 바로 실행해 플러그인·URI· caps를 검증합니다.
간단 재생
# 파일 재생(자동 디코딩·출력 선택)
gst-launch-1.0 playbin uri=file:///C:/Videos/sample.mp4
# HTTP 스트림
gst-launch-1.0 playbin uri=https://example.com/stream.mp4
명시적 체인 예시
오디오만 wav로 디코딩해 스피커로:
gst-launch-1.0 filesrc location=music.wav ! wavparse ! audioconvert ! audioresample ! autoaudiosink
!: Pad를 링크한다는 뜻(문자열 파싱 시).- 쉘에서
!가 특수 문자면 따옴표로 파이프라인 전체를 감싸세요.
gst-launch-1.0 "filesrc location=test.wav ! wavparse ! audioconvert ! audioresample ! autoaudiosink"
테스트 소스
설치가 됐는지 확인할 때 유용합니다.
gst-launch-1.0 videotestsrc ! autovideosink
gst-launch-1.0 audiotestsrc ! autoaudiosink
C 예제
playbin에 URI를 넣고 Bus에서 EOS/ERROR를 기다리는 최소 재생 예제입니다.
#include <gst/gst.h>
int main(int argc, char *argv[]) {
GstElement *pipeline;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
if (argc < 2) {
g_printerr("Usage: %s <file path or URI>\n", argv[0]);
return -1;
}
gst_init(&argc, &argv);
pipeline = gst_element_factory_make("playbin", "play");
if (!pipeline) {
g_printerr("playbin 생성 실패. 플러그인·PKG_CONFIG_PATH 확인.\n");
return -1;
}
g_object_set(pipeline, "uri", argv[1], NULL);
ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr("PLAYING 상태 전환 실패.\n");
gst_object_unref(pipeline);
return -1;
}
bus = gst_element_get_bus(pipeline);
msg = gst_bus_timed_pop_filtered(
bus,
GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
GError *e = NULL;
gchar *dbg = NULL;
gst_message_parse_error(msg, &e, &dbg);
g_printerr("에러: %s\n", e->message);
if (dbg) g_printerr("Debug: %s\n", dbg);
g_clear_error(&e);
g_free(dbg);
}
gst_message_unref(msg);
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
return 0;
}
빌드 예 (Linux, pkg-config 사용):
gcc -o play play.c $(pkg-config --cflags --libs gstreamer-1.0)
Python(PyGObject) 예제
GStreamer는 GObject Introspection으로 Python에서도 동일한 개념을 씁니다.
import sys
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GLib
def main():
Gst.init(None)
if len(sys.argv) < 2:
print("Usage: python play.py <URI>")
sys.exit(1)
playbin = Gst.ElementFactory.make("playbin", None)
playbin.set_property("uri", sys.argv[1])
loop = GLib.MainLoop()
bus = playbin.get_bus()
bus.add_signal_watch()
def on_message(bus, message):
t = message.type
if t == Gst.MessageType.EOS:
loop.quit()
elif t == Gst.MessageType.ERROR:
err, dbg = message.parse_error()
print(f"Error: {err.message}", file=sys.stderr)
loop.quit()
bus.connect("message", on_message)
playbin.set_state(Gst.State.PLAYING)
loop.run()
playbin.set_state(Gst.State.NULL)
if __name__ == "__main__":
main()
주의: 시스템에 python-gi와 GStreamer 1.0 typelib가 맞게 설치되어 있어야 합니다.
Bus 메시지와 종료 처리
앱에서 빠지기 쉬운 부분이 Bus 루프입니다.
- EOS: 스트림 끝. 재생 완료 시 정상 종료 신호.
- ERROR: 파이프라인이 복구 불가일 때 많이 옵니다.
parse_error로 문자열을 꼭 출력하세요. - STATE_CHANGED: 디버깅·UI 연동에 사용.
메인 스레드를 막지 않으려면 add_signal_watch + GLib 메인 루프 또는 별도 스레드에서 pop 패턴을 선택합니다.
디버깅과 자주 나는 실수
GST_DEBUG
로그 레벨과 카테고리를 지정하면 Pad 링크 실패 원인을 빠르게 좁힐 수 있습니다.
GST_DEBUG=3 gst-launch-1.0 playbin uri=file:///path/to/file.mp4
자주 쓰는 패턴:
GST_DEBUG=*:2,*decode*:5
흔한 실수
- Pad 미연결:
decodebin뒤는 동적 Pad가 생깁니다.pad-added시그널에서 다음 Element와 링크해야 하는 경우가 많습니다(직선!체인만으로 안 될 때). - Caps 불일치: 샘플레이트·채널·픽셀 포맷이 안 맞으면
audioconvert/videoscale/videoconvert등으로 중간에 맞춰 줍니다. - 잘못된 URI:
file://는 절대 경로 3슬래시(file:///home/...) 형태에 익숙해지세요. - 플러그인 누락:
gst-inspect-1.0 요소이름으로 존재 여부를 확인합니다.
gst-inspect-1.0 playbin
마무리
GStreamer는 “Element를 조립해 데이터가 흐르게 만든다”는 한 가지 원리만 잡아도 입문이 쉬워집니다. 실무에서는 playbin / uridecodebin으로 먼저 성공 경로를 만든 뒤, 필요한 지점만 수동 파이프라인으로 바꿔 가는 방식이 안전합니다.
더 나아가려면 Pad 템플릿, 요소 상태 머신, 시각/클럭 동기화, appsrc/appsink로 애플리케이션 버퍼를 직접 붙이는 패턴을 문서와 튜토리얼로 확장해 보세요.
참고
- GStreamer 공식 문서
gst-launch-1.0,gst-inspect-1.0,gst-discoverer-1.0매뉴얼