Zurück zum Wiki
Video Pipeline

GStreamer Zero-Copy Pipeline: NVMM Bellek ve DMA Buffer Yönetimi

Jetson üzerinde kameradan encoder'a CPU kopyası olmadan giden bir GStreamer hattının kurulumu: NVMM caps müzakeresi, DMA-BUF, appsink'te NvBufSurface erişimi ve encode gecikmesinin ölçümü. Referans pipeline, C kod örneği ve saha kontrol listesiyle.

Spikedge Mühendislik26. Juli 20267 dk okuma

Gömülü bir vision sisteminde 1080p60 NV12 akışı yaklaşık 190 MB/s, 4K30 ise 373 MB/s ham veri üretir. Bu akışı hat boyunca bir kez bile gereksiz yere kopyalarsanız hem DDR bant genişliğini hem de bir CPU çekirdeğinin ciddi bölümünü memcpy'ye harcarsınız — Jetson gibi unified memory mimarilerinde bu bant genişliği aynı zamanda TensorRT inference'ın kullandığı kaynaktır. Bu yazıda kameradan encoder'a kadar CPU'ya hiç uğramayan bir GStreamer hattının nasıl kurulduğunu, appsink üzerinden NVMM buffer'lara güvenli erişimi ve encode gecikmesinin nasıl ölçüleceğini ele alıyoruz. Örnekler Jetson (JetPack 6) üzerinedir; kavramlar i.MX8M Plus gibi VPU'lu platformlara da büyük ölçüde taşınır.

Bellek alanları: system memory, NVMM ve DMA-BUF

GStreamer'da zero-copy, caps müzakeresinde kazanılır ya da kaybedilir. Jetson'da üç bellek alanıyla çalışırsınız:

  • video/x-raw — klasik system memory. CPU erişimi ucuzdur ama ISP, VIC ve NVENC bu belleğe doğrudan erişemez; donanıma giden her frame kopyalanır.
  • video/x-raw(memory:NVMM) — NvBufSurface destekli buffer. GstBuffer piksel verisi değil, DMA-BUF fd'sine bağlı küçük bir tanımlayıcı taşır. ISP, VIC, NVENC ve GPU aynı fiziksel sayfaları görür; elementler arasında yalnızca fd dolaşır.
  • DMA-BUF — çekirdek tarafında buffer paylaşımının ortak dili. NVMM bunun üzerine kuruludur; v4l2src io-mode=dmabuf da aynı mekanizmayı kullanır.

Domain geçişlerini nvvidconv (donanımdaki VIC bloğu) yapar ve iki yönde de çalışır. Caps'i açık yazmazsanız müzakere bazen sessizce system memory'de anlaşır; elinizde “çalışan ama yavaş” bir hat kalır.

Element Giriş Çıkış Not
nvarguscamerasrc CSI sensör NVMM Debayer, 3A ve lens shading ISP donanımında
v4l2src io-mode=dmabuf UVC/V4L2 DMA-BUF ISP yok; ilk nvvidconv tek DMA geçişiyle NVMM'e alır
nvvidconv NVMM veya CPU NVMM veya CPU Caps'e göre; iki taraf da CPU ise düz memcpy'ye dönüşür
nvv4l2h264enc NVMM byte-stream NVENC; CPU caps verirseniz girişte kopya oluşur
videoconvert CPU CPU Zero-copy hatta hiç görünmemeli — görünüyorsa müzakere kaybedilmiştir

Referans hat: kamera → ISP → NVENC

gst-launch-1.0 -v \
  nvarguscamerasrc sensor-id=0 ! \
  'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=60/1,format=NV12' ! \
  nvvidconv ! 'video/x-raw(memory:NVMM),format=NV12' ! \
  nvv4l2h264enc maxperf-enable=1 insert-sps-pps=true \
    control-rate=1 bitrate=8000000 iframeinterval=60 vbv-size=400000 ! \
  h264parse ! rtph264pay config-interval=-1 pt=96 ! \
  udpsink host=192.168.1.10 port=5600 sync=false

Buradaki kritik disiplin, her aşamada (memory:NVMM) caps'ini açıkça yazmaktır. -v çıktısındaki negotiated caps'lerde tek bir pad bile NVMM'siz video/x-raw gösteriyorsa o noktada kopya vardır. videoconvert eklemek ya da caps'i eksik yazmak gibi masum görünen değişiklikler müzakereyi CPU'ya düşürür; hat çalışmaya devam eder, sadece yavaşlar. USB kamera kullanıyorsanız ISP devrede olmaz; v4l2src io-mode=dmabuf ! nvvidconv ile frame tek DMA geçişiyle NVMM'e taşınır, hattın gerisi aynıdır.

appsink tuzakları

Analiz veya inference için frame'i uygulamaya çekmenin standart yolu appsink'tir; zero-copy'nin en sık bozulduğu yer de burasıdır:

  1. Caps vermezseniz kopya alırsınız. appsink'in caps'ini video/x-raw(memory:NVMM),format=NV12 olarak sabitleyin; aksi halde upstream frame'i sizin için system memory'e çevirir ve hat sessizce zero-copy olmaktan çıkar.
  2. gst_buffer_map piksel vermez. NVMM buffer'da map.data bir NvBufSurface işaretçisidir. Piksele CPU'dan erişecekseniz NvBufSurfaceMap ve ardından NvBufSurfaceSyncForCpu gerekir; sync çağrısı cache invalidation yapar, atlarsanız bayat veri okursunuz.
  3. Kuyruk gecikmesi. Canlı hatta max-buffers=1 drop=true sync=false kullanın; yoksa tüketici yavaşladığı anda gecikme sessizce yüzlerce milisaniyeye birikir.
  4. Pool küçüktür. NVMM buffer pool tipik olarak birkaç buffer derinliğindedir; gst_sample_unref çağrısını geciktirirseniz kamera tarafı stall eder.
static GstFlowReturn on_new_sample(GstAppSink *sink, gpointer data) {
  GstSample *sample = gst_app_sink_pull_sample(sink);
  GstBuffer *buf = gst_sample_get_buffer(sample);
  GstMapInfo map;

  gst_buffer_map(buf, &map, GST_MAP_READ);
  NvBufSurface *surf = (NvBufSurface *)map.data;  /* piksel DEĞİL */

  NvBufSurfaceMap(surf, 0, 0, NVBUF_MAP_READ);
  NvBufSurfaceSyncForCpu(surf, 0, 0);             /* cache invalidate */
  /* surf->surfaceList[0].mappedAddr.addr[0] -> Y düzlemi (NV12) */
  NvBufSurfaceUnMap(surf, 0, 0);

  gst_buffer_unmap(buf, &map);
  gst_sample_unref(sample);                        /* pool'u bekletme */
  return GST_FLOW_OK;
}

GPU'da işlem yapacaksanız CPU map'e hiç girmeyin: NvBufSurfaceMapEglImage ile buffer'ı EGLImage olarak kaydedip cuGraphicsEGLRegisterImage üzerinden doğrudan CUDA'ya verin. Frame'in TensorRT'ye CPU'ya hiç inmeden ulaştığı bu kurulum, edge AI pipeline işlerimizdeki varsayılan yoldur.

Encode gecikmesini ölçmek

Gecikmeyi iki ayrı seviyede ölçün; ikisi farklı soruları yanıtlar. Element seviyesinde GStreamer'ın latency tracer'ı yeterlidir:

GST_TRACERS="latency(flags=pipeline+element)" \
GST_DEBUG="GST_TRACER:7" GST_DEBUG_FILE=/tmp/trace.log \
gst-launch-1.0 <hattınız>

grep element-latency /tmp/trace.log | tail -n 50

Tracer, nvv4l2h264enc girişindeki buffer ile çıkışı arasındaki farkı verir — encode gecikmesinin kendisi budur. Düşük gecikme ayarlarının etkisini de burada görürsünüz: küçük vbv-size, CBR (control-rate=1), maxperf-enable=1 ve B-frame'siz profil. Küçük VBV gecikmeyi düşürür ama ani sahne değişimlerinde kaliteyi dalgalandırır; bütçeyi bit hızıyla birlikte ayarlamak gerekir.

Glass-to-glass için tracer yetmez, çünkü sensör pozlaması, ISP ve görüntüleme tarafı hattın dışındadır. Pratik yöntem fizikseldir: kameranın gördüğü bir LED'i GPIO ile yakıp LED'in uzak ekranda belirdiği anı fotodiyotla ya da yüksek hızlı kayıtla yakalamak. Bu düzenekle, burada anlatılan hattın WebRTC ile birleştirilmiş halinde encode gecikmesini 80 ms'nin, glass-to-glass gecikmeyi 200 ms'nin altında ölçtük; düzenek ve sonuçlar WebRTC komuta-kontrol vaka analizinde ayrıntılı anlatılıyor.

Kontrol listesi

  • -v ile her pad'de (memory:NVMM) doğrulandı mı?
  • Hatta videoconvert var mı? Varsa müzakere bir yerde kaybedilmiş demektir.
  • appsink: NVMM caps + max-buffers=1 drop=true sync=false + hızlı unref.
  • CPU erişiminde NvBufSurfaceSyncForCpu çağrılıyor mu?
  • Encode gecikmesi tracer ile, glass-to-glass LED düzeneğiyle ayrı ayrı ölçüldü mü?

Gecikme bütçesi kağıt üzerinde tutuyor ama cihazda tutmuyorsa, hattı caps müzakeresinden encoder ayarlarına kadar ölçüm verisiyle incelediğimiz video pipeline mimari denetimi darboğazı sistematik biçimde bulmak için doğru başlangıç noktasıdır.

#GStreamer#NVMM#zero-copy#DMA-BUF#Jetson

Setzen Sie diese Technologie in Ihrem Projekt ein?

Planen Sie ein Architektur-Audit mit Spikedge-Ingenieuren.

Architektur-Audit planen