00 RTSP protokolü — RFC 2326 ve SDP
RTSP (Real-Time Streaming Protocol), RFC 2326 ile tanımlanan uygulama katmanı protokolüdür. HTTP'ye benzer komut-yanıt yapısıyla medya oturumlarını kontrol eder; gerçek medya verisi RTP üzerinden taşınır.
RTSP komutları
Örnek RTSP oturumu
→ DESCRIBE rtsp://192.168.1.10:8554/kamera RTSP/1.0
CSeq: 1
← RTSP/1.0 200 OK
CSeq: 1
Content-Type: application/sdp
Content-Length: 142
v=0
o=- 0 0 IN IP4 192.168.1.10
s=GStreamer RTSP Server
c=IN IP4 0.0.0.0
t=0 0
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; profile-level-id=42c028
→ SETUP rtsp://192.168.1.10:8554/kamera RTSP/1.0
CSeq: 2
Transport: RTP/AVP;unicast;client_port=4588-4589
← RTSP/1.0 200 OK
CSeq: 2
Session: 12345678
Transport: RTP/AVP;unicast;client_port=4588-4589;server_port=6970-6971
→ PLAY rtsp://192.168.1.10:8554/kamera RTSP/1.0
CSeq: 3
Session: 12345678
Range: npt=0.000-
← RTSP/1.0 200 OK
CSeq: 3
(RTP veri akışı başlar)
SDP dosyası yapısı
v=0 # Versiyon
o=- 0 0 IN IP4 127.0.0.1 # Kaynak
s=Gömülü Kamera Stream # Oturum adı
c=IN IP4 192.168.1.100 # Bağlantı adresi
t=0 0 # Zaman (0=belirsiz)
m=video 5000 RTP/AVP 96 # Medya: video, port 5000, payload 96
a=rtpmap:96 H264/90000 # PT 96 → H.264, 90kHz saat
a=fmtp:96 packetization-mode=1
a=control:streamid=0
01 gst-rtsp-server kurulum ve API
gst-rtsp-server, GStreamer üzerine inşa edilmiş RTSP sunucu kütüphanesidir. GstRTSPServer, GstRTSPMediaFactory ve GstRTSPMedia sınıflarıyla esnek RTSP altyapısı kurulur.
Kurulum
# Debian/Ubuntu
sudo apt install \
libgstrtspserver-1.0-dev \
gstreamer1.0-rtsp
# Yocto
IMAGE_INSTALL:append = " gst-rtsp-server"
# Derleme için pkg-config
pkg-config --libs --cflags gstreamer-rtsp-server-1.0
Temel API sınıfları
Temel kullanım yapısı
#include <gst/rtsp-server/rtsp-server.h>
int main(int argc, char *argv[])
{
GstRTSPServer *server;
GstRTSPMountPoints *mounts;
GstRTSPMediaFactory *factory;
GMainLoop *loop;
gst_init(&argc, &argv);
/* Sunucu oluştur */
server = gst_rtsp_server_new();
g_object_set(server, "service", "8554", NULL); /* port */
/* Mount points */
mounts = gst_rtsp_server_get_mount_points(server);
factory = gst_rtsp_media_factory_new();
/* Pipeline string'i — ( ... ) içinde stream pipeline */
gst_rtsp_media_factory_set_launch(factory,
"( videotestsrc ! videoconvert ! x264enc ! rtph264pay name=pay0 pt=96 )");
/* Tüm istemciler aynı pipeline paylaşsın */
gst_rtsp_media_factory_set_shared(factory, TRUE);
/* /test yoluna bağla */
gst_rtsp_mount_points_add_factory(mounts, "/test", factory);
g_object_unref(mounts);
/* Sunucuyu GMainLoop'a ekle */
gst_rtsp_server_attach(server, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_print("RTSP sunucu hazır: rtsp://127.0.0.1:8554/test\n");
g_main_loop_run(loop);
return 0;
}
Factory launch string'indeki pipeline ( ... ) parantez içinde yazılmalıdır. RTP payload element'i name=pay0 olarak adlandırılmalıdır; sunucu bu ismi SDP oluşturmak için kullanır.
02 Basit RTSP server — test kaynağı
videotestsrc ile gerçek donanım gerekmeden RTSP sunucusunu test edin. VLC veya ffplay ile doğrulayın.
gst-rtsp-server örnek araçları
# Paket içindeki örnek server (test ortamı)
# Kurulum: apt install gstreamer1.0-rtsp
# Basit test server (kaynak koddan derlenmiş örnek)
test-launch "( videotestsrc ! video/x-raw,width=1280,height=720,framerate=30/1 \
! videoconvert ! x264enc tune=zerolatency ! rtph264pay name=pay0 pt=96 )"
# Başka terminalde test et
gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/test ! \
rtph264depay ! avdec_h264 ! videoconvert ! autovideosink
# VLC ile izle
vlc rtsp://127.0.0.1:8554/test
# ffplay ile izle (FFmpeg)
ffplay -rtsp_transport tcp rtsp://127.0.0.1:8554/test
Tam çalışan C sunucusu
#include <gst/rtsp-server/rtsp-server.h>
int main(int argc, char *argv[])
{
GstRTSPServer *server;
GstRTSPMountPoints *mounts;
GstRTSPMediaFactory *factory;
GMainLoop *loop;
guint id;
gst_init(&argc, &argv);
server = gst_rtsp_server_new();
g_object_set(server, "service", "8554", NULL);
g_object_set(server, "address", "0.0.0.0", NULL);
mounts = gst_rtsp_server_get_mount_points(server);
factory = gst_rtsp_media_factory_new();
gst_rtsp_media_factory_set_launch(factory,
"( videotestsrc pattern=ball is-live=true ! "
" video/x-raw,width=1280,height=720,framerate=30/1 ! "
" videoconvert ! "
" x264enc tune=zerolatency speed-preset=ultrafast bitrate=2000 "
" key-int-max=30 ! "
" rtph264pay name=pay0 pt=96 config-interval=1 )");
gst_rtsp_media_factory_set_shared(factory, TRUE);
gst_rtsp_mount_points_add_factory(mounts, "/live", factory);
g_object_unref(mounts);
id = gst_rtsp_server_attach(server, NULL);
if (id == 0) {
g_printerr("Sunucu başlatılamadı.\n");
return 1;
}
loop = g_main_loop_new(NULL, FALSE);
g_print("RTSP sunucu başladı:\n");
g_print(" rtsp://0.0.0.0:8554/live\n");
g_print("VLC: vlc rtsp://SUNUCU_IP:8554/live\n");
g_main_loop_run(loop);
return 0;
}
03 Kamera RTSP server — çok istemcili
V4L2 kamerasını RTSP üzerinden birden fazla istemciye yayınlamak için shared media factory kullanılır. Tek pipeline, tüm istemcilere aynı stream'i verir.
V4L2 kaynaklı RTSP server
#include <gst/rtsp-server/rtsp-server.h>
typedef struct {
gchar *device;
gchar *path;
gchar *port;
gint width;
gint height;
gint fps;
gint bitrate;
} ServerConfig;
static void client_connected_cb(GstRTSPServer *server,
GstRTSPClient *client,
gpointer data)
{
GstRTSPConnection *conn = gst_rtsp_client_get_connection(client);
const GstRTSPUrl *url = gst_rtsp_connection_get_url(conn);
g_print("[RTSP] İstemci bağlandı: %s\n", url ? url->host : "bilinmiyor");
}
int main(int argc, char *argv[])
{
ServerConfig cfg = {
.device = "/dev/video0",
.path = "/kamera",
.port = "8554",
.width = 1280,
.height = 720,
.fps = 30,
.bitrate = 2000
};
gchar *launch_str;
GstRTSPServer *server;
GstRTSPMountPoints *mounts;
GstRTSPMediaFactory *factory;
GMainLoop *loop;
gst_init(&argc, &argv);
launch_str = g_strdup_printf(
"( v4l2src device=%s ! "
" video/x-raw,format=YUYV,width=%d,height=%d,framerate=%d/1 ! "
" videoconvert ! "
" video/x-raw,format=I420 ! "
" x264enc tune=zerolatency speed-preset=ultrafast "
" bitrate=%d key-int-max=%d ! "
" rtph264pay name=pay0 pt=96 config-interval=1 )",
cfg.device, cfg.width, cfg.height, cfg.fps,
cfg.bitrate, cfg.fps);
server = gst_rtsp_server_new();
g_object_set(server, "service", cfg.port, NULL);
g_signal_connect(server, "client-connected",
G_CALLBACK(client_connected_cb), NULL);
mounts = gst_rtsp_server_get_mount_points(server);
factory = gst_rtsp_media_factory_new();
gst_rtsp_media_factory_set_launch(factory, launch_str);
gst_rtsp_media_factory_set_shared(factory, TRUE);
gst_rtsp_mount_points_add_factory(mounts, cfg.path, factory);
g_object_unref(mounts);
g_free(launch_str);
gst_rtsp_server_attach(server, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_print("Kamera RTSP yayını başladı:\n");
g_print(" rtsp://0.0.0.0:%s%s\n", cfg.port, cfg.path);
g_main_loop_run(loop);
return 0;
}
set_shared(TRUE) tüm istemcilere tek pipeline stream eder (multicast benzeri). FALSE durumunda her istemci için yeni pipeline başlatılır: her istemci farklı seek pozisyonu kullanabilir ama CPU/kamera kaynağı katlanır. Canlı kamera için daima TRUE kullanın.
04 RTP paket yapısı — header ve parametreler
RTP (Real-time Transport Protocol), medya verisi taşımak için kullanılan UDP tabanlı protokoldür. Sıra numarası ve timestamp ile alıcı sırayı ve senkronizasyonu yönetir.
RTP header yapısı
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Synchronization Source (SSRC) identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
rtph264pay parametreleri
# rtph264pay önemli parametreler
gst-launch-1.0 \
videotestsrc ! videoconvert ! x264enc ! \
rtph264pay \
pt=96 \
config-interval=1 \ # Her I-frame'de SPS/PPS gönder
mtu=1400 \ # Maksimum paket boyutu (MTU-28)
aggregate-mode=zero-latency ! \
udpsink host=192.168.1.100 port=5000
# Alıcı tarafında paket istatistikleri (tcpdump)
tcpdump -i eth0 udp port 5000 -v | head -50
05 RTCP — kalite geri bildirimi
RTCP (RTP Control Protocol), RTP ile birlikte çalışır ve ağ kalitesi geri bildirimlerini (jitter, paket kaybı, gecikme) sağlar. Lip-sync ve adaptif bitrate için gereklidir.
GStreamer RTCP entegrasyonu
# rtpbin: RTP session yönetimi, RTCP destekli
# Gönderici taraf
gst-launch-1.0 \
videotestsrc ! videoconvert ! x264enc ! rtph264pay pt=96 ! \
rtpbin name=rtpbin \
rtpbin.send_rtp_src_0 ! \
udpsink host=192.168.1.100 port=5000 \
rtpbin.send_rtcp_src_0 ! \
udpsink host=192.168.1.100 port=5001 sync=false async=false \
udpsrc port=5002 ! rtpbin.recv_rtcp_sink_0
# Alıcı taraf
gst-launch-1.0 \
udpsrc port=5000 caps="application/x-rtp,payload=96" ! \
rtpbin name=rtpbin \
rtpbin.recv_rtp_sink_0 ! \
rtph264depay ! avdec_h264 ! videoconvert ! autovideosink \
udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0 \
rtpbin.send_rtcp_src_0 ! \
udpsink host=192.168.1.100 port=5002 sync=false async=false
Jitter ve paket kaybı izleme
# rtpbin istatistiklerini sysfs'ten oku
# GST_DEBUG ile RTCP mesajlarını izle
GST_DEBUG="rtpjitterbuffer:4,rtpsession:4" \
gst-launch-1.0 udpsrc port=5000 ! \
application/x-rtp,payload=96 ! \
rtpjitterbuffer latency=200 ! \
rtph264depay ! avdec_h264 ! autovideosink 2>&1 | grep -i jitter
06 Multi-stream ve tee — kayıt + canlı stream
Gerçek dünya senaryolarında kamera görüntüsü hem yerel olarak kaydedilmeli hem de canlı RTSP üzerinden yayınlanmalıdır. tee element bu iki dalı aynı anda yönetir.
RTSP + yerel kayıt pipeline
#include <gst/rtsp-server/rtsp-server.h>
/* appsrc → encode → rtsp için ayrı pipeline mimarisi */
/* Bu örnekte: kamera → tee → (RTSP) + (dosya) */
int main(int argc, char *argv[])
{
GstElement *pipeline, *v4l2src, *conv, *tee,
*q1, *enc1, *mux, *fsink,
*q2, *enc2, *pay;
GstRTSPServer *server;
GstRTSPMountPoints *mounts;
GstRTSPMediaFactory *factory;
GMainLoop *loop;
GstPad *tee_src1, *tee_src2, *q1_sink, *q2_sink;
gst_init(&argc, &argv);
/* Kayıt pipeline'ı (kamera → dosya) */
pipeline = gst_pipeline_new("record");
v4l2src = gst_element_factory_make("v4l2src", "src");
conv = gst_element_factory_make("videoconvert", "conv");
tee = gst_element_factory_make("tee", "tee");
q1 = gst_element_factory_make("queue", "q1");
enc1 = gst_element_factory_make("x264enc", "enc1");
mux = gst_element_factory_make("mp4mux", "mux");
fsink = gst_element_factory_make("filesink", "fsink");
q2 = gst_element_factory_make("queue", "q2");
enc2 = gst_element_factory_make("x264enc", "enc2");
g_object_set(v4l2src, "device", "/dev/video0", NULL);
g_object_set(fsink, "location", "kayit.mp4", NULL);
g_object_set(enc1, "bitrate", 4000, "speed-preset", 4, NULL);
g_object_set(enc2, "tune", 4 /* zerolatency */, "bitrate", 2000,
"speed-preset", 1 /* ultrafast */, NULL);
gst_bin_add_many(GST_BIN(pipeline),
v4l2src, conv, tee,
q1, enc1, mux, fsink,
q2, enc2, NULL);
gst_element_link_many(v4l2src, conv, tee, NULL);
gst_element_link_many(q1, enc1, mux, fsink, NULL);
gst_element_link(q2, enc2);
/* tee → q1 ve tee → q2 pad bağlantıları */
tee_src1 = gst_element_get_request_pad(tee, "src_%u");
q1_sink = gst_element_get_static_pad(q1, "sink");
gst_pad_link(tee_src1, q1_sink);
tee_src2 = gst_element_get_request_pad(tee, "src_%u");
q2_sink = gst_element_get_static_pad(q2, "sink");
gst_pad_link(tee_src2, q2_sink);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
/* RTSP sunucu enc2 çıkışını yayınlayacak — appsink/src köprüsü gerekir
* Basit alternatif: tüm pipeline RTSP factory içinde tanımla */
/* Basit yol: factory launch string'i kullan */
server = gst_rtsp_server_new();
g_object_set(server, "service", "8554", NULL);
mounts = gst_rtsp_server_get_mount_points(server);
factory = gst_rtsp_media_factory_new();
gst_rtsp_media_factory_set_launch(factory,
"( v4l2src device=/dev/video0 ! "
" video/x-raw,format=YUYV,width=1280,height=720 ! "
" videoconvert ! x264enc tune=zerolatency bitrate=2000 ! "
" rtph264pay name=pay0 pt=96 )");
gst_rtsp_media_factory_set_shared(factory, TRUE);
gst_rtsp_mount_points_add_factory(mounts, "/live", factory);
g_object_unref(mounts);
gst_rtsp_server_attach(server, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_print("Kayıt + RTSP aktif:\n");
g_print(" Dosya: kayit.mp4\n");
g_print(" RTSP: rtsp://0.0.0.0:8554/live\n");
g_main_loop_run(loop);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
return 0;
}
07 Adaptif streaming — HLS ve DASH
HLS (HTTP Live Streaming) ve DASH (Dynamic Adaptive Streaming over HTTP), ağ koşullarına göre otomatik kalite değiştiren adaptif streaming protokolleridir. Düşük gecikme yerine yüksek güvenilirlik sunarlar.
HLS ile GStreamer
# hlssink2 ile HLS çıktısı
gst-launch-1.0 -e \
v4l2src device=/dev/video0 ! \
video/x-raw,format=YUYV,width=1280,height=720,framerate=30/1 ! \
videoconvert ! \
x264enc tune=zerolatency bitrate=2000 key-int-max=30 ! \
h264parse ! \
hlssink2 \
playlist-root="http://192.168.1.10:8080" \
playlist-location=/var/www/html/hls/stream.m3u8 \
location=/var/www/html/hls/segment%05d.ts \
target-duration=2 \
playlist-length=5 \
send-keyframe-requests=true
# Basit HTTP sunucu (segment yayını için)
cd /var/www/html/hls
python3 -m http.server 8080
# Tarayıcıda veya VLC ile izle
# http://192.168.1.10:8080/stream.m3u8
Çok bitrate HLS (multi-bitrate)
# 3 farklı kalite seviyesi: 360p, 720p, 1080p
gst-launch-1.0 -e \
v4l2src device=/dev/video0 ! \
video/x-raw,format=YUYV,width=1920,height=1080,framerate=30/1 ! \
videoconvert ! tee name=t \
\
t. ! queue ! videoscale ! video/x-raw,width=640,height=360 ! \
x264enc bitrate=500 tune=zerolatency key-int-max=30 ! h264parse ! \
mpegtsmux ! filesink location=/tmp/hls/360p/segment%05d.ts \
\
t. ! queue ! videoscale ! video/x-raw,width=1280,height=720 ! \
x264enc bitrate=2000 tune=zerolatency key-int-max=30 ! h264parse ! \
mpegtsmux ! filesink location=/tmp/hls/720p/segment%05d.ts \
\
t. ! queue ! x264enc bitrate=5000 tune=zerolatency key-int-max=30 ! \
h264parse ! mpegtsmux ! filesink location=/tmp/hls/1080p/segment%05d.ts
DASH ile GStreamer
# dashsink ile MPEG-DASH üretimi
gst-launch-1.0 -e \
videotestsrc is-live=true ! \
video/x-raw,width=1280,height=720,framerate=30/1 ! \
videoconvert ! x264enc key-int-max=30 ! h264parse ! \
dashsink \
mpd-root-path=/var/www/html/dash \
mpd-filename=stream.mpd \
target-duration=2
08 Pratik: RPi kamera → RTSP → VLC izleme ve latency ölçümü
Raspberry Pi kamera modülü (V2 veya HQ) ile tam çalışan RTSP sunucu, VLC ile izleme ve uçtan uca gecikme ölçümü.
RPi kamera kurulumu
# Kamera modülünü etkinleştir (raspi-config veya config.txt)
echo "camera_auto_detect=1" | sudo tee -a /boot/firmware/config.txt
# libcamera araçları kur
sudo apt install libcamera-apps libcamera-dev gstreamer1.0-libcamera
# Kamera doğrula
libcamera-hello --timeout 5000
rpicam-hello --timeout 5000
# V4L2 cihaz listesi
v4l2-ctl --list-devices
# bcm2835-codec-decode (platform:bcm2835-codec):
# /dev/video10
# /dev/video11
# unicam (platform:3f801000.csi):
# /dev/video0 ← kamera
libcamerasrc ile RTSP sunucu
# libcamerasrc → hardware encode → RTSP
# RPi 4/5'te v4l2h264enc donanım encoder kullanır
gst-launch-1.0 \
libcamerasrc ! \
video/x-raw,width=1920,height=1080,framerate=30/1,format=NV12 ! \
v4l2h264enc \
extra-controls="controls,repeat_sequence_header=1,h264_profile=4" ! \
video/x-h264,level=\(string\)4 ! \
h264parse ! \
rtph264pay config-interval=1 pt=96 ! \
udpsink host=0.0.0.0 port=5000 auto-multicast=true
# Daha basit: test-launch ile (gst-rtsp-server example)
test-launch \
"( libcamerasrc ! video/x-raw,width=1280,height=720,framerate=30/1 ! \
videoconvert ! x264enc tune=zerolatency bitrate=2000 ! \
rtph264pay name=pay0 pt=96 )"
Latency ölçümü
# Yöntem 1: dijital saat veya kronometreyi kameraya tut
# VLC ekranı yanında gerçek süreç ekranı karşılaştırılır (görsel)
# Yöntem 2: GStreamer probe ile timestamp farkı
GST_DEBUG="GST_PERFORMANCE:4" gst-launch-1.0 \
rtspsrc location=rtsp://127.0.0.1:8554/live latency=50 ! \
rtph264depay ! h264parse ! avdec_h264 ! \
fpsdisplaysink sync=false 2>&1 | grep latency
# Yöntem 3: Pipeline latency profil
gst-launch-1.0 \
libcamerasrc ! \
video/x-raw,width=1280,height=720,framerate=30/1 ! \
videoconvert ! \
x264enc tune=zerolatency ! \
rtph264pay ! \
udpsink host=127.0.0.1 port=5000 &
gst-launch-1.0 \
udpsrc port=5000 ! \
application/x-rtp,encoding-name=H264 ! \
rtph264depay ! h264parse ! \
avdec_h264 ! \
videoconvert ! \
fpsdisplaysink sync=false text-overlay=true
Gecikmeyi minimize etmek için: tune=zerolatency, speed-preset=ultrafast, rtpjitterbuffer latency=50, sync=false kullanın. rtspsrc yerine doğrudan udpsrc kullanmak da 10-30ms kazandırır.