Skip to content

Video: Replace OpenGL qml6glsink with appsink Metal path on macOS#14228

Open
DonLakeFlyer wants to merge 1 commit intomavlink:masterfrom
DonLakeFlyer:feature/macos-metal-video
Open

Video: Replace OpenGL qml6glsink with appsink Metal path on macOS#14228
DonLakeFlyer wants to merge 1 commit intomavlink:masterfrom
DonLakeFlyer:feature/macos-metal-video

Conversation

@DonLakeFlyer
Copy link
Copy Markdown
Collaborator

@DonLakeFlyer DonLakeFlyer commented Mar 27, 2026

Summary

Replace the OpenGL-dependent qml6glsink GStreamer video rendering path on macOS with a new appsink -> QVideoSink -> VideoOutput path that uses Qt's native Metal RHI backend.

Motivation

On macOS, Qt 6 defaults to Metal for rendering. The existing GStreamer video path uses qml6glsink, which requires an OpenGL context. This forced QGC to override Qt's default and use the deprecated OpenGL API on macOS. This PR eliminates that dependency by extracting decoded frames via GStreamer's appsink and delivering them to Qt's QVideoSink, which renders natively through Metal.

Architecture

GStreamer pipeline -> appsink -> GstAppSinkAdapter -> QVideoSink -> VideoOutput (Metal)

The new path sits alongside the existing D3D11 (Windows) and GL (Linux) paths inside qgcvideosinkbin, selected at compile time via Q_OS_MACOS.

Changes

  • gstqgcvideosinkbin.h/cc: Add videoconvert -> appsink path with fallback to GL
  • GstAppSinkAdapter.h/cc (new): Bridges GStreamer appsink to Qt QVideoSink with BGRA frame copy, stride handling, and buffer bounds validation
  • FlightDisplayViewMetal.qml (new): Qt VideoOutput component for Metal rendering
  • FlightDisplayViewVideo.qml: 3-way component selection (D3D11/Metal/GL) for main and thermal video
  • QGCApplication.cc: Let Qt use default Metal RHI on macOS instead of forcing OpenGL
  • VideoManager.h/cc: Expose gstreamerAppleSink property, wire adapter to VideoOutput QVideoSink
  • GStreamer.h/cc: setupAppleSinkAdapter() factory function
  • GStreamer/CMakeLists.txt: Add GstApp component, Apple-gated sources and Qt Multimedia links
  • GStreamerTest.h/cc: End-to-end unit test for the appsink frame delivery pipeline (see below)

Unit Test: End-to-End Appsink Validation

This PR includes _testAppsinkFrameDelivery, a new unit test that exercises the entire appsink rendering pipeline end-to-end on macOS (QSKIP on other platforms). The test builds a real GStreamer pipeline (videotestsrc -> videoconvert -> qgcvideosinkbin) with the appsink path active, wires a GstAppSinkAdapter to a QVideoSink, runs the pipeline to EOS, and verifies that:

  • Frames are successfully delivered through the appsink -> GstAppSinkAdapter -> QVideoSink chain
  • Frame dimensions match the expected 320x240 resolution
  • The pipeline completes without errors

This validates that the entire new code path -- from GStreamer's appsink element through the adapter's BGRA frame copy to Qt's video sink -- functions correctly as a unit, catching regressions in the frame bridge that manual testing alone would miss.

Platform Safety

All changes are gated behind Q_OS_MACOS / if(APPLE). No impact on Windows, Linux, Android, or iOS builds.

Testing

  • Verified Metal RHI active via QSG_INFO=1 logs (Creating QRhi with backend Metal)
  • Confirmed live video rendering with UDP H.264 test stream (hardware decoded via vtdec_hw)
  • Screenshot capture (grabToImage) works correctly
  • All 15 GStreamerTest slots pass including _testAppsinkFrameDelivery

This comment was marked as resolved.

This comment was marked as resolved.

@DonLakeFlyer DonLakeFlyer force-pushed the feature/macos-metal-video branch from 0e37d62 to 702f155 Compare March 27, 2026 18:33
On macOS, the GStreamer qml6glsink element requires an OpenGL context, but Qt 6 defaults to Metal RHI. Rather than forcing OpenGL (deprecated on macOS), this adds a new appsink-based rendering path: GStreamer pipeline -> appsink -> GstAppSinkAdapter -> QVideoSink -> VideoOutput (Metal) Changes: - gstqgcvideosinkbin: Add macOS appsink path (videoconvert -> appsink) alongside existing D3D11 (Windows) and GL (Linux) paths - GstAppSinkAdapter: New class bridging GStreamer appsink to Qt QVideoSink, copies BGRA frames with stride-aware memcpy and buffer bounds validation - FlightDisplayViewMetal.qml: Qt VideoOutput component for Metal rendering - FlightDisplayViewVideo.qml: 3-way component selection (D3D11/Metal/GL) for both main and thermal video - QGCApplication: Let Qt use default Metal RHI on macOS instead of forcing OpenGL - VideoManager: Expose gstreamerAppleSink property, wire appsink adapter to QML VideoOutput's QVideoSink - GStreamer CMakeLists: Add GstApp dependency, Apple-gated sources and Qt Multimedia links - Unit test: _testAppsinkFrameDelivery validates end-to-end frame delivery through the appsink pipeline (macOS-only, QSKIP elsewhere) All changes are gated behind Q_OS_MACOS / if(APPLE) -- no impact on Windows, Linux, Android, or iOS builds.
@DonLakeFlyer DonLakeFlyer force-pushed the feature/macos-metal-video branch from 702f155 to 1cc279e Compare March 27, 2026 18:34
@github-actions
Copy link
Copy Markdown
Contributor

Build Results

Platform Status

Platform Status Details
Linux Passed View
Windows Passed View
MacOS Passed View
Android Passed View

All builds passed.

Pre-commit

Check Status Details
pre-commit Failed (non-blocking) View

Pre-commit hooks: 4 passed, 33 failed, 7 skipped.

Test Results

linux-sanitizers: 67 passed, 0 skipped
linux_gcc_64: 67 passed, 0 skipped
Total: 134 passed, 0 skipped

Artifact Sizes

Artifact Size
QGroundControl 247.51 MB
QGroundControl 337.71 MB
QGroundControl-aarch64 176.94 MB
QGroundControl-installer-AMD64 134.76 MB
QGroundControl-installer-AMD64-ARM64 77.37 MB
QGroundControl-installer-ARM64 106.10 MB
QGroundControl-mac 188.42 MB
QGroundControl-windows 188.46 MB
QGroundControl-x86_64 163.15 MB
No baseline available for comparison---
Updated: 2026-03-27 19:30:44 UTC • Triggered by: Android
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment