player: probe Rockchip MPP/V4L2 HW decoders at pipeline init, add setup_hw_decode.sh

This commit is contained in:
Matteo Benedetto
2026-03-23 21:42:25 +01:00
parent 544ed8bc6d
commit ddbe31dc02
2 changed files with 159 additions and 0 deletions
@@ -25,6 +25,72 @@ log = logging.getLogger(__name__)
Gst.init(None)
# GStreamer element names for hardware video decoders, in priority order.
# mppvideodec: Rockchip MPP plugin (gst-mpp), uses /dev/vpu_service on kernel 4.4 BSP.
# v4l2*dec: Linux V4L2 stateful decoders, available on kernel 5.4+ (rkvdec/hantro).
_HW_DECODER_ELEMENTS = [
"mppvideodec",
"v4l2h264dec",
"v4l2h265dec",
"v4l2vp8dec",
"v4l2vp9dec",
]
# VPU device nodes that must be accessible for hardware decode on RK3326.
_HW_VPU_DEVICES = [
"/dev/vpu_service", # kernel 4.4 BSP (RK3326 / PX30)
"/dev/mpp_service", # newer BSP variants
"/dev/video10", # V4L2 vcodec on mainline/5.10+ kernels
"/dev/video11",
]
def _vpu_device_accessible() -> bool:
"""Return True if at least one VPU device node can be opened by this process."""
for path in _HW_VPU_DEVICES:
try:
fd = os.open(path, os.O_RDWR | os.O_NONBLOCK)
os.close(fd)
log.info("HW decode: VPU device accessible: %s", path)
return True
except OSError:
pass
return False
def _probe_hw_decoders(gst_module) -> list:
"""
Probe for available hardware video decoder GStreamer elements and boost
their rank so that playbin's internal decodebin prefers them over software
decoders. Returns the list of element names that were found and boosted.
If no VPU device node is accessible the probe is skipped entirely so that
a half-initialised hardware element cannot stall the pipeline.
"""
if not _vpu_device_accessible():
log.info(
"HW decode: no accessible VPU device node — using software decode. "
"Run deploy/arkos/setup_hw_decode.sh as root to fix permissions."
)
return []
found = []
for name in _HW_DECODER_ELEMENTS:
factory = gst_module.ElementFactory.find(name)
if factory is not None:
try:
factory.set_rank(gst_module.Rank.PRIMARY + 1)
found.append(name)
log.info("HW decode: boosted rank of %s", name)
except Exception as exc: # pragma: no cover
log.warning("HW decode: could not boost rank of %s: %s", name, exc)
if not found:
log.info(
"HW decode: VPU device is accessible but no gst-mpp / V4L2 plugin found. "
"Run deploy/arkos/setup_hw_decode.sh to install gstreamer1.0-rockchip-mpp."
)
return found
def _wm_subsystem_name(subsystem: int) -> str:
mapping = {
@@ -116,6 +182,7 @@ class GStreamerBackend(PlayerBackend):
self._texture_renderer = None
self._texture_size = (0, 0)
self._resolution = ""
self._hw_decoders: list | None = None # None = not yet probed
def attach_window(self, window: object) -> None:
self._window = window
@@ -259,6 +326,9 @@ class GStreamerBackend(PlayerBackend):
if self._pipeline is not None:
return self._pipeline
if self._hw_decoders is None:
self._hw_decoders = _probe_hw_decoders(self._gst)
self._pipeline = self._playbin_factory()
self._configure_playbin_flags(self._pipeline)
self._video_sink = self._create_appsink()