GStreamer & Multimedya
TEKNİK REHBER GSTREAMER TEMELLER 2026

GStreamer Temelleri —
Pipeline & Element.

GStreamer mimarisini sıfırdan öğren: element, pad, bus ve caps kavramlarından C API'ye, state machine'den canlı kamera pipeline'ına — gömülü sistemlerde multimedya işlemenin temeli.

00 GStreamer nedir — mimari ve temel kavramlar

GStreamer, LGPL lisanslı, açık kaynaklı bir multimedya framework'üdür. Video ve audio işleme pipeline'larını modüler plugin'lerle inşa etmeye olanak tanır. Gömülü Linux'tan masaüstüne, kameradan RTSP sunucusuna geniş bir kullanım alanına sahiptir.

Temel fikir: veri akışı, birbirine bağlı element'ler zincirinden (pipeline) geçer. Her element belirli bir işlevi yerine getirir: veri üretmek (source), dönüştürmek (filter) veya tüketmek (sink).

Mimari katmanları

GStreamer Mimari
┌──────────────────────────────────────────────────────────┐
│                  Uygulama Katmanı                         │
│    gst-launch-1.0  ·  Python/C/C++ GStreamer API          │
├──────────────────────────────────────────────────────────┤
│                  GStreamer Core                           │
│   GstPipeline · GstBin · GstElement · GstPad · GstBus    │
├──────────────────────────────────────────────────────────┤
│                  Plugin Sistemi                           │
│  gstreamer-plugins-base   (temel dönüşüm, audio/video)   │
│  gstreamer-plugins-good   (V4L2, RTP, FLAC, WebM...)     │
│  gstreamer-plugins-bad    (HLS, DASH, MSDK, NVCODEC...)   │
│  gstreamer-plugins-ugly   (x264, x265, MP3...)            │
├──────────────────────────────────────────────────────────┤
│              Platform / Donanım                          │
│   V4L2 · ALSA · DRM/KMS · DMA-BUF · OpenGL/Vulkan        │
└──────────────────────────────────────────────────────────┘

Temel kavramlar

GstElement
Pipeline'ın temel yapı taşı. Her element bir işlev uygular: decode, encode, mix, display vb. gst_element_factory_make() ile oluşturulur.
GstPad
Element'in giriş (sink pad) veya çıkış (source pad) noktası. Pad'ler birbirine link edildiğinde veri akar.
GstCaps
Capabilities — pad'in desteklediği medya formatını tanımlar. video/x-raw, audio/x-raw, video/x-h264 gibi. Caps müzakeresi, iki element arasında ortak formatı belirler.
GstBus
Pipeline'dan uygulamaya mesaj iletim kanalı. EOS, ERROR, WARNING, STATE_CHANGED mesajları bu kanal üzerinden gelir.
GstBuffer
Veri taşıyıcısı. Timestamp, duration ve flag bilgileriyle birlikte ham veri içerir.
GstPipeline
En üst düzey GstBin. Tüm element'leri barındırır, global saat yönetimi sağlar.

Basit pipeline grafiği

videotestsrc
source pad
videoconvert
sink/src pad
autovideosink
sink pad
NOT

GStreamer 1.x (1.0+) ve 0.10 arasında API uyumsuzluğu vardır. Gömülü Linux dağıtımlarında genellikle 1.18+ kullanılır. Bu rehber boyunca GStreamer 1.x API'si kullanılmaktadır.

01 Kurulum — araçlar ve plugin paketleri

GStreamer kurulumu dağıtıma göre değişir. Yocto/Buildroot gibi gömülü sistemlerde recipe/package seçimi kritiktir; masaüstü geliştirme ortamlarında apt/dnf ile hızlıca başlanabilir.

Debian/Ubuntu (geliştirme ortamı)

bash
# Temel araçlar ve çekirdek kütüphane
sudo apt install \
  gstreamer1.0-tools \
  gstreamer1.0-plugins-base \
  gstreamer1.0-plugins-good \
  gstreamer1.0-plugins-bad \
  gstreamer1.0-plugins-ugly \
  libgstreamer1.0-dev \
  libgstreamer-plugins-base1.0-dev

# V4L2 ve video desteği
sudo apt install \
  gstreamer1.0-v4l2 \
  v4l-utils

# Python bağlamları
sudo apt install python3-gst-1.0

# Doğrulama
gst-launch-1.0 --version
# GStreamer command line tool 1.20.3

Yocto — IMAGE_INSTALL

local.conf / image recipe
IMAGE_INSTALL:append = " \
    gstreamer1.0 \
    gstreamer1.0-plugins-base \
    gstreamer1.0-plugins-good \
    gstreamer1.0-plugins-bad \
    gstreamer1.0-plugins-ugly \
    gstreamer1.0-libav \
    gstreamer1.0-meta-video \
"

gst-inspect-1.0 — element keşfi

bash
# Yüklü tüm plugin'leri listele
gst-inspect-1.0

# Belirli bir element hakkında bilgi
gst-inspect-1.0 v4l2src
# Plugin Details:
#   Name        v4l2src
#   Description Video (video4linux2) Source element
#   ...
# Pad Templates:
#   SRC template: 'src'
#     Availability: Always
#     Capabilities:
#       video/x-raw ...

# Plugin içindeki tüm element'leri listele
gst-inspect-1.0 videotestsrc

# Belirli bir özelliği ara
gst-inspect-1.0 --exists v4l2h264enc && echo "donanım encode var"
plugins-base
videotestsrc, audiotestsrc, videoconvert, audioconvert, alsasrc/sink, ogg, vorbis, theora. Temel ve zorunlu.
plugins-good
v4l2src, rtpbin, rtph264pay/depay, flac, wavenc, matroska, udpsink. LGPL uyumlu kaliteli plugin'ler.
plugins-bad
HLS, DASH, nvcodec, msdk (Intel Media SDK), wayland, webrtc. Patent belirsizliği veya test eksikliği olan plugin'ler.
plugins-ugly
x264enc, x265enc, lame (MP3). Patent sorunu olan fakat yaygın kullanılan codec'ler.
İPUCU

GST_PLUGIN_PATH ortam değişkeni ile özel plugin dizini eklenebilir. Gömülü sistemlerde /usr/lib/gstreamer-1.0/ dizini standart konumdur.

02 gst-launch-1.0 ile ilk pipeline

gst-launch-1.0, komut satırından GStreamer pipeline'ı çalıştırmak için kullanılan temel araçtır. Hızlı prototipleme ve test için vazgeçilmezdir.

Temel syntax

gst-launch syntax
# Genel form:
# gst-launch-1.0 [OPTIONS] ELEMENT [PROPERTY=VALUE ...] ! ELEMENT ...

# ! işareti iki element'i birleştirir (pipe benzeri)
# Özellikler KEY=VALUE biçiminde element'ten hemen sonra gelir

# Ekrana test videosu oynat
gst-launch-1.0 videotestsrc ! autovideosink

# Test sesi çal (hoparlör gerekli)
gst-launch-1.0 audiotestsrc ! autoaudiosink

# Test görüntüsü + belirli caps (format zorla)
gst-launch-1.0 videotestsrc ! \
  video/x-raw,width=1280,height=720,framerate=30/1 ! \
  autovideosink

# Dönen küpler ile farklı pattern (pattern=18 = ball)
gst-launch-1.0 videotestsrc pattern=ball ! autovideosink

Önemli gst-launch seçenekleri

-v / --verbose
Caps negotiation ve state değişimlerini ayrıntılı gösterir. Hata ayıklamada kritik.
-e / --eos-on-shutdown
Ctrl+C'de pipeline'ı EOS ile düzgün kapatır. Dosya yazarken mutlaka kullan.
--gst-debug=CATEGORY:LEVEL
Debug log seviyesi. Örn: --gst-debug=v4l2src:5 sadece v4l2src için verbose log açar.
GST_DEBUG
Ortam değişkeni. GST_DEBUG=*:3 tüm kategorileri WARNING seviyesinde loglar.

Pratik pipeline örnekleri

bash
# Test videosu → MP4 dosyasına yaz (5 saniye)
gst-launch-1.0 -e videotestsrc num-buffers=150 ! \
  videoconvert ! \
  x264enc ! \
  mp4mux ! \
  filesink location=test.mp4

# Kamera görüntüsünü ekranda göster
gst-launch-1.0 v4l2src device=/dev/video0 ! \
  videoconvert ! \
  autovideosink

# Mikrofon sesini WAV dosyasına kaydet
gst-launch-1.0 -e alsasrc device=hw:0 ! \
  audioconvert ! \
  wavenc ! \
  filesink location=ses.wav

# UDP üzerinden video gönder (gönderici taraf)
gst-launch-1.0 videotestsrc ! \
  videoconvert ! \
  x264enc tune=zerolatency ! \
  rtph264pay ! \
  udpsink host=192.168.1.100 port=5000

# UDP'den video al ve göster (alıcı taraf)
gst-launch-1.0 udpsrc port=5000 ! \
  application/x-rtp,encoding-name=H264 ! \
  rtph264depay ! \
  avdec_h264 ! \
  autovideosink
UYARI

Gömülü sistemlerde autovideosink her zaman çalışmayabilir. Wayland için waylandsink, framebuffer için fbdevsink, KMS/DRM için kmssink tercih edilmelidir.

03 Element türleri — source, filter, sink

GStreamer element'leri pad yapılarına göre üç ana kategoriye ayrılır. Hangi türde element kullandığınızı anlamak, pipeline tasarımının temelidir.

Source Element
Sadece source pad'e sahiptir. Dışarıdan veri üretir: v4l2src, filesrc, audiotestsrc, rtspsrc, appsrc. Pipeline'ın başında yer alır.
Filter / Transform Element
Hem sink hem source pad'i vardır. Veriyi alır, işler, gönderir: videoconvert, x264enc, avdec_h264, volume, queue. Zincirin ortasında yer alır.
Sink Element
Sadece sink pad'e sahiptir. Veriyi tüketir: filesink, autovideosink, appsink, udpsink, alsasink. Pipeline'ın sonunda yer alır.
Demuxer / Muxer
Birden fazla pad'i olan özel element'ler. qtdemux H.264+AAC stream'ini ayırır; mp4mux video+audio'yu birleştirir.
Tee Element
Tek girişi birden fazla çıkışa kopyalar. Aynı kaynaktan hem dosya yazıp hem stream etmek için kullanılır.

Caps negotiation

İki element birbirine link edildiğinde, GStreamer aralarında ortak bir format (caps) belirler. Bu süreç caps negotiation olarak adlandırılır:

Caps Negotiation Akışı
1. Element A'nın src pad'i desteklenen caps'i ilan eder:
   video/x-raw, format=(string){NV12, I420, YUY2}, width=[1,MAX], ...

2. Element B'nin sink pad'i kendi desteklediği caps'i ilan eder:
   video/x-raw, format=(string){I420, YV12}, width=[320,1920], ...

3. GStreamer kesişim kümesini bulur:
   video/x-raw, format=I420, width=[320,1920], ...

4. Gerekirse videoconvert gibi dönüştürücü otomatik eklenir (auto-plugging)
   veya caps uyuşmazsa pipeline HATA verir.

GST_CAPS örneği

bash — caps string formatı
# Caps string yapısı:
# media-type, field1=value1, field2=value2, ...

# Video raw caps
video/x-raw,format=NV12,width=1920,height=1080,framerate=30/1

# H.264 caps (encode sonrası)
video/x-h264,stream-format=byte-stream,alignment=au,profile=high

# Pipeline'da capsfilter olarak kullan
gst-launch-1.0 v4l2src device=/dev/video0 ! \
  video/x-raw,format=YUYV,width=1280,height=720 ! \
  videoconvert ! \
  video/x-raw,format=I420 ! \
  x264enc ! \
  filesink location=cikti.h264

# caps durumunu verbose modda incele
gst-launch-1.0 -v videotestsrc ! videoconvert ! autovideosink 2>&1 | grep caps
NOT

Gömülü platformlarda hardware encoder/decoder genellikle sadece NV12 formatını kabul eder. videoconvert ile I420 → NV12 dönüşümü yapılabilir; ancak bu CPU kullanımı demektir. DMA-BUF ile zero-copy aktarım için pad caps'lerini aynı tutmak gerekir.

04 C API ile pipeline oluşturma

Gerçek uygulamalarda gst-launch yeterli değildir. C API ile pipeline'ı programatik olarak oluşturmak; hata yönetimi, dinamik değişiklik ve uygulama entegrasyonu sağlar.

Temel C pipeline örneği

basic_pipeline.c
#include <gst/gst.h>

int main(int argc, char *argv[])
{
    GstElement *pipeline, *source, *convert, *sink;
    GstBus     *bus;
    GstMessage *msg;
    GstStateChangeReturn ret;

    /* GStreamer'ı başlat */
    gst_init(&argc, &argv);

    /* Element'leri oluştur */
    source  = gst_element_factory_make("videotestsrc",  "source");
    convert = gst_element_factory_make("videoconvert",  "convert");
    sink    = gst_element_factory_make("autovideosink", "sink");

    /* Pipeline (bin) oluştur */
    pipeline = gst_pipeline_new("test-pipeline");

    if (!pipeline || !source || !convert || !sink) {
        g_printerr("Element oluşturulamadı.\n");
        return -1;
    }

    /* Element'leri pipeline'a ekle */
    gst_bin_add_many(GST_BIN(pipeline), source, convert, sink, NULL);

    /* Element'leri birbirine bağla */
    if (!gst_element_link_many(source, convert, sink, NULL)) {
        g_printerr("Element'ler bağlanamadı.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    /* Element özelliği ayarla */
    g_object_set(source, "pattern", 0, NULL);  /* 0 = SMPTE renk çubukları */

    /* Pipeline'ı PLAYING durumuna geçir */
    ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Pipeline PLAYING durumuna geçemedi.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    /* Bus mesajlarını bekle */
    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) {
        GError *err;
        gchar  *debug_info;

        switch (GST_MESSAGE_TYPE(msg)) {
        case GST_MESSAGE_ERROR:
            gst_message_parse_error(msg, &err, &debug_info);
            g_printerr("Hata: %s\n", err->message);
            g_printerr("Debug: %s\n", debug_info ? debug_info : "yok");
            g_clear_error(&err);
            g_free(debug_info);
            break;
        case GST_MESSAGE_EOS:
            g_print("Akış sona erdi.\n");
            break;
        default:
            break;
        }
        gst_message_unref(msg);
    }

    /* Temizlik */
    gst_object_unref(bus);
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);

    return 0;
}

Derleme

Makefile
CC      = gcc
CFLAGS  = $(shell pkg-config --cflags gstreamer-1.0)
LDFLAGS = $(shell pkg-config --libs gstreamer-1.0)

basic_pipeline: basic_pipeline.c
	$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)

clean:
	rm -f basic_pipeline
gst_init()
GStreamer çalışma zamanını başlatır. argc/argv argüman parse eder. main() başında çağrılmalı.
gst_element_factory_make(type, name)
İsimlendirilmiş element oluşturur. NULL dönerse plugin yüklü değildir.
gst_bin_add_many()
Birden fazla element'i pipeline'a ekler. Sahiplik pipeline'a geçer.
gst_element_link_many()
Element zincirini sırayla bağlar. Caps uyuşmazsa FALSE döner.
g_object_set()
GObject özelliklerini değiştirir. NULL ile sonlandırılmış key-value çiftleri alır.

05 Bus ve mesaj yönetimi

GstBus, pipeline içindeki element'lerden uygulamaya asenkron mesaj iletmek için kullanılan thread-safe bir kuyruk mekanizmasıdır. Hata, EOS, state değişimi gibi olayları yakalamak için kritiktir.

GMainLoop ile asenkron mesaj izleme

bus_watch.c
#include <gst/gst.h>

typedef struct {
    GstElement *pipeline;
    GMainLoop  *loop;
} AppData;

static gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data)
{
    AppData *app = (AppData *)data;

    switch (GST_MESSAGE_TYPE(msg)) {

    case GST_MESSAGE_EOS:
        g_print("[BUS] Akış sona erdi (EOS).\n");
        g_main_loop_quit(app->loop);
        break;

    case GST_MESSAGE_ERROR: {
        GError *err = NULL;
        gchar  *dbg = NULL;
        gst_message_parse_error(msg, &err, &dbg);
        g_printerr("[BUS] HATA: %s\n", err->message);
        if (dbg) g_printerr("[BUS] DEBUG: %s\n", dbg);
        g_error_free(err);
        g_free(dbg);
        g_main_loop_quit(app->loop);
        break;
    }

    case GST_MESSAGE_WARNING: {
        GError *err = NULL;
        gchar  *dbg = NULL;
        gst_message_parse_warning(msg, &err, &dbg);
        g_print("[BUS] UYARI: %s\n", err->message);
        g_error_free(err);
        g_free(dbg);
        break;
    }

    case GST_MESSAGE_STATE_CHANGED:
        if (GST_MESSAGE_SRC(msg) == GST_OBJECT(app->pipeline)) {
            GstState old_state, new_state, pending;
            gst_message_parse_state_changed(msg, &old_state, &new_state, &pending);
            g_print("[BUS] State: %s → %s\n",
                    gst_element_state_get_name(old_state),
                    gst_element_state_get_name(new_state));
        }
        break;

    default:
        break;
    }

    return TRUE;  /* mesaj izlemeye devam et */
}

int main(int argc, char *argv[])
{
    AppData app = {0};
    GstBus *bus;
    guint   watch_id;

    gst_init(&argc, &argv);

    app.pipeline = gst_parse_launch(
        "videotestsrc num-buffers=100 ! videoconvert ! autovideosink",
        NULL);
    app.loop = g_main_loop_new(NULL, FALSE);

    bus = gst_element_get_bus(app.pipeline);
    watch_id = gst_bus_add_watch(bus, bus_callback, &app);
    gst_object_unref(bus);

    gst_element_set_state(app.pipeline, GST_STATE_PLAYING);
    g_main_loop_run(app.loop);  /* bloklar, bus event'leri işler */

    gst_element_set_state(app.pipeline, GST_STATE_NULL);
    g_source_remove(watch_id);
    g_main_loop_unref(app.loop);
    gst_object_unref(app.pipeline);
    return 0;
}
GST_MESSAGE_EOS
Tüm source'lar veri üretmeyi bitirdiğinde gönderilir. Pipeline'ı durdurmak için uygun zaman.
GST_MESSAGE_ERROR
Kurtarılamaz hata. GError ve debug string içerir. Pipeline'ı NULL'a almak gerekir.
GST_MESSAGE_WARNING
Kurtarılabilir uyarı. Devam edilebilir ama log edilmeli.
GST_MESSAGE_STATE_CHANGED
Element state değişimini bildirir. Sadece pipeline seviyesinden izlemek için src filtrele.
gst_bus_add_watch()
GMainLoop'a bus callback ekler. GLib event loop gerektirir.

06 State machine — NULL'dan PLAYING'e

Her GStreamer element bir state machine ile yönetilir. Doğru state geçişlerini anlamak; pipeline başlatma süresini optimize etmek, kaynak yönetimi ve hata kurtarma için gereklidir.

GST_STATE_NULL
Başlangıç durumu. Element henüz hazır değil, hiçbir kaynak tahsis edilmedi. gst_object_unref() öncesi bu state'e dönülmeli.
GST_STATE_READY
Element global kaynakları tahsis etti (donanım aygıt açıldı). Henüz veri akmıyor. NULL↔READY geçişi yavaştır.
GST_STATE_PAUSED
Veri akışı hazır, pipeline senkronize edildi; ancak saat ilerlemez. Buffer'lar doldu, ilk kare render edildi.
GST_STATE_PLAYING
Saat ilerliyor, veri gerçek zamanlı akıyor. Normal çalışma durumu.
State Geçiş Diyagramı
NULL ──→ READY ──→ PAUSED ──→ PLAYING
         ↑             ↑           ↑
         └─────────────┴───────────┘
              (geri geçiş de mümkün)

Geçiş sırası zorunludur: NULL→PLAYING doğrudan olmaz,
kernel ara adımları otomatik gerçekleştirir.

Async state change yönetimi

state_change.c
GstStateChangeReturn ret;

/* State geçişini başlat */
ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);

switch (ret) {
case GST_STATE_CHANGE_SUCCESS:
    g_print("Anlık state geçişi başarılı.\n");
    break;

case GST_STATE_CHANGE_ASYNC:
    /* Async geçiş — tamamlanmasını bekle (en fazla 5 sn) */
    g_print("Async geçiş bekleniyor...\n");
    ret = gst_element_get_state(pipeline, NULL, NULL, 5 * GST_SECOND);
    if (ret == GST_STATE_CHANGE_SUCCESS)
        g_print("Geçiş tamamlandı.\n");
    else
        g_printerr("Geçiş zaman aşımı!\n");
    break;

case GST_STATE_CHANGE_FAILURE:
    g_printerr("State geçişi başarısız!\n");
    break;

case GST_STATE_CHANGE_NO_PREROLL:
    /* Live kaynak (kamera) PAUSED'da veri üretmez — normal */
    g_print("Live kaynak: NO_PREROLL (normal).\n");
    break;
}

/* Mevcut state'i sorgula */
GstState current, pending;
gst_element_get_state(pipeline, &current, &pending, 0);
g_print("Mevcut: %s, Bekleyen: %s\n",
    gst_element_state_get_name(current),
    gst_element_state_get_name(pending));
ÖNEMLİ

v4l2src gibi live source'lar PAUSED durumunda GST_STATE_CHANGE_NO_PREROLL döner. Bu bir hata değildir; live kaynaklar buffer dolduramaz. Bu durumu doğru ele almak gerekir.

07 Pad ve caps — format müzakeresi

Pad'ler element'lerin bağlantı noktalarıdır. Static pad'ler her zaman mevcuttur; dynamic pad'ler ise çalışma zamanında (örneğin demux sırasında) oluşur. Caps negotiation bu pad'ler üzerinden yürütülür.

Dynamic pad — pad-added sinyali

dynamic_pad.c
#include <gst/gst.h>

/* qtdemux yeni pad açtığında çağrılır */
static void on_pad_added(GstElement *element, GstPad *pad, gpointer data)
{
    GstElement *decoder = (GstElement *)data;
    GstPad     *sink_pad;
    GstCaps    *caps;
    GstStructure *str;
    const gchar *name;

    /* Açılan pad'in caps'ini al */
    caps = gst_pad_get_current_caps(pad);
    str  = gst_caps_get_structure(caps, 0);
    name = gst_structure_get_name(str);

    g_print("Yeni pad: %s, caps: %s\n", GST_PAD_NAME(pad), name);

    /* Sadece video pad'ini bağla */
    if (g_str_has_prefix(name, "video/x-h264")) {
        sink_pad = gst_element_get_static_pad(decoder, "sink");
        if (!gst_pad_is_linked(sink_pad)) {
            if (gst_pad_link(pad, sink_pad) != GST_PAD_LINK_OK)
                g_printerr("Pad link başarısız!\n");
            else
                g_print("Video pad bağlandı.\n");
        }
        gst_object_unref(sink_pad);
    }

    gst_caps_unref(caps);
}

int main(int argc, char *argv[])
{
    GstElement *pipeline, *src, *demux, *decoder, *convert, *sink;

    gst_init(&argc, &argv);

    src     = gst_element_factory_make("filesrc",     "src");
    demux   = gst_element_factory_make("qtdemux",     "demux");
    decoder = gst_element_factory_make("avdec_h264",  "decoder");
    convert = gst_element_factory_make("videoconvert","convert");
    sink    = gst_element_factory_make("autovideosink","sink");

    pipeline = gst_pipeline_new("file-pipeline");
    gst_bin_add_many(GST_BIN(pipeline), src, demux, decoder, convert, sink, NULL);

    g_object_set(src, "location", "video.mp4", NULL);

    /* src → demux statik bağlantı */
    gst_element_link(src, demux);

    /* demux → decoder dinamik bağlantı */
    g_signal_connect(demux, "pad-added", G_CALLBACK(on_pad_added), decoder);

    /* decoder → convert → sink statik */
    gst_element_link_many(decoder, convert, sink, NULL);

    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    /* ... mesaj döngüsü ... */
    return 0;
}

Caps filtreleme — capsfilter element

bash
# capsfilter ile format zorla
gst-launch-1.0 v4l2src device=/dev/video0 ! \
  video/x-raw,format=NV12,width=1920,height=1080,framerate=30/1 ! \
  videoconvert ! \
  video/x-raw,format=I420 ! \
  x264enc bitrate=4000 ! \
  filesink location=output.h264

# C API'de capsfilter
capsfilter_api.c
GstElement *capsfilter;
GstCaps    *caps;

capsfilter = gst_element_factory_make("capsfilter", "filter");

caps = gst_caps_from_string(
    "video/x-raw,format=NV12,width=1920,height=1080,framerate=30/1");

g_object_set(capsfilter, "caps", caps, NULL);
gst_caps_unref(caps);

gst_bin_add(GST_BIN(pipeline), capsfilter);
gst_element_link_many(v4l2src, capsfilter, videoconvert, NULL);

08 Pratik: v4l2src → videoconvert → autovideosink canlı kamera pipeline

Raspberry Pi veya i.MX8 üzerinde V4L2 kamerasından canlı görüntü alan, hem ekranda gösteren hem dosyaya yazan tam çalışan bir pipeline uygulaması.

Kamera bilgilerini keşfet

bash
# Mevcut video aygıtları
v4l2-ctl --list-devices

# Kameranın desteklediği formatları listele
v4l2-ctl -d /dev/video0 --list-formats-ext
# ioctl: VIDIOC_ENUM_FMT
#     Index       : 0
#     Type        : Video Capture
#     Pixel Format: 'YUYV'
#     Name        : YUYV 4:2:2
#         Size: Discrete 1920x1080
#             Interval: Discrete 0.033s (30.000 fps)
#         Size: Discrete 1280x720
#             Interval: Discrete 0.033s (30.000 fps)

# GStreamer ile kamera caps'lerini keşfet
gst-device-monitor-1.0 Video/Source

Canlı görüntü + eş zamanlı kayıt

bash — gst-launch
# Sadece ekran gösterimi
gst-launch-1.0 \
  v4l2src device=/dev/video0 ! \
  video/x-raw,format=YUYV,width=1280,height=720,framerate=30/1 ! \
  videoconvert ! \
  autovideosink sync=false

# tee ile hem ekran hem H.264 dosya kaydı
gst-launch-1.0 -e \
  v4l2src device=/dev/video0 ! \
  video/x-raw,format=YUYV,width=1280,height=720,framerate=30/1 ! \
  videoconvert ! \
  tee name=t \
    t. ! queue ! autovideosink sync=false \
    t. ! queue ! x264enc bitrate=2000 ! mp4mux ! filesink location=kayit.mp4

C uygulaması — tam örnek

camera_pipeline.c
#include <gst/gst.h>
#include <signal.h>

static GMainLoop *main_loop = NULL;

static void sigint_handler(int sig)
{
    g_print("\nCtrl+C yakalandı — EOS gönderiliyor...\n");
    /* Pipeline'a EOS gönder — dosya düzgün kapansın */
    if (main_loop) g_main_loop_quit(main_loop);
}

static gboolean bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
{
    GMainLoop *loop = (GMainLoop *)data;
    switch (GST_MESSAGE_TYPE(msg)) {
    case GST_MESSAGE_EOS:
        g_print("EOS alındı.\n");
        g_main_loop_quit(loop);
        break;
    case GST_MESSAGE_ERROR: {
        GError *err; gchar *dbg;
        gst_message_parse_error(msg, &err, &dbg);
        g_printerr("HATA: %s (%s)\n", err->message, dbg ? dbg : "-");
        g_error_free(err); g_free(dbg);
        g_main_loop_quit(loop);
        break;
    }
    default: break;
    }
    return TRUE;
}

int main(int argc, char *argv[])
{
    GstElement *pipeline;
    GstBus     *bus;
    GError     *err = NULL;
    const gchar *pipe_desc =
        "v4l2src device=/dev/video0 ! "
        "video/x-raw,format=YUYV,width=1280,height=720,framerate=30/1 ! "
        "videoconvert ! "
        "tee name=t "
        "t. ! queue leaky=2 max-size-buffers=3 ! autovideosink sync=false "
        "t. ! queue ! x264enc bitrate=2000 speed-preset=ultrafast ! "
        "   mp4mux ! filesink location=kayit.mp4";

    gst_init(&argc, &argv);
    signal(SIGINT, sigint_handler);

    pipeline = gst_parse_launch(pipe_desc, &err);
    if (err) {
        g_printerr("Pipeline hatası: %s\n", err->message);
        g_error_free(err);
        return 1;
    }

    main_loop = g_main_loop_new(NULL, FALSE);
    bus = gst_element_get_bus(pipeline);
    gst_bus_add_watch(bus, bus_cb, main_loop);
    gst_object_unref(bus);

    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    g_print("Pipeline başladı. Ctrl+C ile dur.\n");

    g_main_loop_run(main_loop);

    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);
    g_main_loop_unref(main_loop);

    g_print("Temizlik tamamlandı.\n");
    return 0;
}
Element
Görev
Önemli Parametre
v4l2src
Kamera ham frame'i al
device, io-mode
videoconvert
YUYV → I420/NV12 dönüştür
-
tee
Akışı çoğalt
name=t
queue
Thread sınırı, buffer yönetimi
leaky, max-size-buffers
x264enc
Yazılım H.264 encode
bitrate, speed-preset
mp4mux
H.264 → MP4 konteyner
-
filesink
Dosyaya yaz
location
PERFORMANS

Raspberry Pi 4'te YUYV → I420 dönüşümü CPU'ya yük bindirdirir. RPi kamera modülünü libcamerasrc ile kullanarak NV12 natif çıkış alabilir, videoconvert'ten kaçınabilirsiniz. i.MX8MP üzerinde ise v4l2h264enc hardware encoder, CPU kullanımını %5'in altına indirir.