Skip to content

Commit d8b2739

Browse files
committed
fix(v4l2): select viewer decoders for sink output
1 parent bd81178 commit d8b2739

1 file changed

Lines changed: 79 additions & 20 deletions

File tree

publish.py

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3396,6 +3396,38 @@ def _get_decoder_description(self, codec: str, fallback: str) -> Tuple[str, bool
33963396
parts.append(f"{key}={value}")
33973397

33983398
return " ".join(parts), using_hw
3399+
3400+
def _get_v4l2sink_decoder_description(
3401+
self,
3402+
codec: str,
3403+
fallbacks: Tuple[str, ...],
3404+
allow_hw: bool = True,
3405+
) -> Tuple[str, bool]:
3406+
"""Return a decoder fragment for viewer V4L2 output."""
3407+
primary_fallback = fallbacks[0]
3408+
disable_hw = getattr(self, "disable_hw_decoder", False) or not allow_hw
3409+
force_hw = getattr(self, "_force_hw_decoder", False) and allow_hw
3410+
factory_name, properties, using_hw = select_preferred_decoder(
3411+
codec,
3412+
primary_fallback,
3413+
disable_hw=disable_hw,
3414+
force_hw=force_hw,
3415+
)
3416+
3417+
if not using_hw:
3418+
for candidate in fallbacks:
3419+
if gst_element_available(candidate):
3420+
factory_name = candidate
3421+
properties = {}
3422+
break
3423+
3424+
parts = [factory_name]
3425+
for key, value in properties.items():
3426+
if isinstance(value, bool):
3427+
value = "true" if value else "false"
3428+
parts.append(f"{key}={value}")
3429+
3430+
return " ".join(parts), using_hw
33993431

34003432
def setup_ice_servers(self, webrtc):
34013433
"""Configure ICE servers including default VDO.Ninja TURN servers"""
@@ -6628,28 +6660,55 @@ def _attach_v4l2sink_video_stream(self, pad: Gst.Pad, caps_name: str) -> Optiona
66286660
elif "AV1" in caps_upper:
66296661
codec_type = "AV1"
66306662

6663+
def build_v4l2sink_output_chain(using_hw_decoder: bool = False) -> str:
6664+
if using_hw_decoder and gst_element_available("nvvidconv"):
6665+
return (
6666+
"nvvidconv ! video/x-raw,format=NV12 ! "
6667+
"videoconvert ! videoscale ! videorate ! "
6668+
f"video/x-raw,format={self.v4l2sink_format},width=(int){self.v4l2sink_width},"
6669+
f"height=(int){self.v4l2sink_height},framerate=(fraction){self.v4l2sink_fps}/1 ! "
6670+
f"identity name=v4l2sink_identity_{pad.get_name()}"
6671+
)
6672+
return (
6673+
"videoconvert ! videoscale ! videorate ! "
6674+
f"video/x-raw,format={self.v4l2sink_format},width=(int){self.v4l2sink_width},"
6675+
f"height=(int){self.v4l2sink_height},framerate=(fraction){self.v4l2sink_fps}/1 ! "
6676+
f"identity name=v4l2sink_identity_{pad.get_name()}"
6677+
)
6678+
6679+
def get_v4l2sink_decoder(codec: str, fallbacks: Tuple[str, ...]) -> Tuple[str, bool]:
6680+
decoder_desc, using_hw_decoder = self._get_v4l2sink_decoder_description(codec, fallbacks)
6681+
if using_hw_decoder and not gst_element_available("nvvidconv"):
6682+
printwarn(
6683+
f"V4L2 sink hardware {codec} decoder requires `nvvidconv`; "
6684+
"falling back to software decoding."
6685+
)
6686+
decoder_desc, using_hw_decoder = self._get_v4l2sink_decoder_description(
6687+
codec,
6688+
fallbacks,
6689+
allow_hw=False,
6690+
)
6691+
return decoder_desc, using_hw_decoder
6692+
66316693
fallback_pipeline = (
66326694
"queue ! decodebin ! "
6633-
"videoconvert ! videoscale ! videorate ! "
6634-
f"video/x-raw,format={self.v4l2sink_format},width=(int){self.v4l2sink_width},"
6635-
f"height=(int){self.v4l2sink_height},framerate=(fraction){self.v4l2sink_fps}/1 ! "
6636-
f"identity name=v4l2sink_identity_{pad.get_name()}"
6695+
f"{build_v4l2sink_output_chain()}"
66376696
)
66386697

66396698
pipeline_desc = None
66406699
if codec_type == "VP8":
6700+
decoder_desc, using_hw_decoder = get_v4l2sink_decoder("VP8", ("vp8dec",))
66416701
pipeline_desc = (
6642-
"queue ! rtpvp8depay ! vp8dec ! videoconvert ! videoscale ! videorate ! "
6643-
f"video/x-raw,format={self.v4l2sink_format},width=(int){self.v4l2sink_width},"
6644-
f"height=(int){self.v4l2sink_height},framerate=(fraction){self.v4l2sink_fps}/1 ! "
6645-
f"identity name=v4l2sink_identity_{pad.get_name()}"
6702+
"queue ! rtpvp8depay ! "
6703+
f"{decoder_desc} ! "
6704+
f"{build_v4l2sink_output_chain(using_hw_decoder)}"
66466705
)
66476706
elif codec_type == "H264":
6707+
decoder_desc, using_hw_decoder = get_v4l2sink_decoder("H264", ("openh264dec", "avdec_h264"))
66486708
pipeline_desc = (
6649-
"queue ! rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! videoscale ! videorate ! "
6650-
f"video/x-raw,format={self.v4l2sink_format},width=(int){self.v4l2sink_width},"
6651-
f"height=(int){self.v4l2sink_height},framerate=(fraction){self.v4l2sink_fps}/1 ! "
6652-
f"identity name=v4l2sink_identity_{pad.get_name()}"
6709+
"queue ! rtph264depay ! h264parse ! "
6710+
f"{decoder_desc} ! "
6711+
f"{build_v4l2sink_output_chain(using_hw_decoder)}"
66536712
)
66546713
elif codec_type == "VP9":
66556714
if not gst_element_available("rtpvp9depay"):
@@ -6658,11 +6717,11 @@ def _attach_v4l2sink_video_stream(self, pad: Gst.Pad, caps_name: str) -> Optiona
66586717
)
66596718
pipeline_desc = fallback_pipeline
66606719
else:
6720+
decoder_desc, using_hw_decoder = get_v4l2sink_decoder("VP9", ("vp9dec",))
66616721
pipeline_desc = (
6662-
"queue ! rtpvp9depay ! vp9dec ! videoconvert ! videoscale ! videorate ! "
6663-
f"video/x-raw,format={self.v4l2sink_format},width=(int){self.v4l2sink_width},"
6664-
f"height=(int){self.v4l2sink_height},framerate=(fraction){self.v4l2sink_fps}/1 ! "
6665-
f"identity name=v4l2sink_identity_{pad.get_name()}"
6722+
"queue ! rtpvp9depay ! "
6723+
f"{decoder_desc} ! "
6724+
f"{build_v4l2sink_output_chain(using_hw_decoder)}"
66666725
)
66676726
elif codec_type == "AV1":
66686727
if not gst_element_available("rtpav1depay") or not gst_element_available("av1parse"):
@@ -6671,11 +6730,11 @@ def _attach_v4l2sink_video_stream(self, pad: Gst.Pad, caps_name: str) -> Optiona
66716730
)
66726731
pipeline_desc = fallback_pipeline
66736732
else:
6733+
decoder_desc, using_hw_decoder = get_v4l2sink_decoder("AV1", ("av1dec",))
66746734
pipeline_desc = (
6675-
"queue ! rtpav1depay ! av1parse ! av1dec ! videoconvert ! videoscale ! videorate ! "
6676-
f"video/x-raw,format={self.v4l2sink_format},width=(int){self.v4l2sink_width},"
6677-
f"height=(int){self.v4l2sink_height},framerate=(fraction){self.v4l2sink_fps}/1 ! "
6678-
f"identity name=v4l2sink_identity_{pad.get_name()}"
6735+
"queue ! rtpav1depay ! av1parse ! "
6736+
f"{decoder_desc} ! "
6737+
f"{build_v4l2sink_output_chain(using_hw_decoder)}"
66796738
)
66806739
else:
66816740
printc(f"Unsupported video codec for V4L2 sink: {caps_name}", "F70")

0 commit comments

Comments
 (0)