x-linux-ai: recipes-samples: fix USB camera support on X-LINUX-AI v6.2.0

Restore the V4L2SRC based pipeline for USB webcams that was dropped in newer
X-LINUX-AI releases, fixing USB camera support on the v6.2.0 baseline.

https://onedigi.atlassian.net/browse/DEL-10040

Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
This commit is contained in:
Arturo Buzarra 2026-05-12 14:53:35 +02:00
parent 599fa04a01
commit cb70c15394
7 changed files with 542 additions and 4 deletions

View File

@ -0,0 +1,233 @@
From: Arturo Buzarra <arturo.buzarra@digi.com>
Date: Tue, 12 May 2026 11:23:56 +0200
Subject: [PATCH] pose-estimation: restore V4L2SRC pipeline for USB Web cameras
Backport the previous V4L2SRC-based capture path so MP2x platforms can use USB
webcams again.
https://onedigi.atlassian.net/browse/DEL-10040
Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
---
stai-mpu/stai_mpu_pose_estimation.py | 157 ++++++++++++++++++++++++++-
1 file changed, 154 insertions(+), 3 deletions(-)
diff --git a/stai-mpu/stai_mpu_pose_estimation.py b/stai-mpu/stai_mpu_pose_estimation.py
index fbbcfa7..94dde53 100644
--- a/stai-mpu/stai_mpu_pose_estimation.py
+++ b/stai-mpu/stai_mpu_pose_estimation.py
@@ -57,12 +57,125 @@ class GstWidget(Gtk.Box):
def _on_realize(self, widget):
if(args.camera_src == "LIBCAMERA"):
self.camera_dual_pipeline_creation()
self.pipeline_preview.set_state(Gst.State.PLAYING)
+ elif(args.camera_src == "V4L2SRC"):
+ self.camera_pipeline_creation()
else:
- print("Camera source used not supported use LIBCAMERA \n")
+ print("Camera source used not supported use LIBCAMERA or V4L2SRC\n")
+
+ def camera_pipeline_creation(self):
+ """
+ Creation of the gstreamer pipeline when gstwidget is created dedicated to handle
+ camera stream and NN inference (mode single pipeline)
+ """
+ # gstreamer pipeline creation
+ self.pipeline_preview = Gst.Pipeline()
+
+ # creation of the source v4l2src
+ self.v4lsrc1 = Gst.ElementFactory.make("v4l2src", "source")
+ video_device = "/dev/" + str(self.app.video_device_prev)
+ self.v4lsrc1.set_property("device", video_device)
+
+ #creation of the v4l2src caps
+ caps = "video/x-raw,width=" + str(self.app.frame_width) + ",height=" + str(self.app.frame_height) + ", framerate=" + str(args.framerate)+ "/1"
+ print("Camera pipeline configuration : ",caps)
+ camera1caps = Gst.Caps.from_string(caps)
+ self.camerafilter1 = Gst.ElementFactory.make("capsfilter", "filter1")
+ self.camerafilter1.set_property("caps", camera1caps)
+
+ # creation of capsfilter to force RGB16 on preview branch
+ self.rgb16_filter = Gst.ElementFactory.make("capsfilter", "rgb16-filter")
+ rgb16_caps = Gst.Caps.from_string("video/x-raw,format=RGB16")
+ self.rgb16_filter.set_property("caps", rgb16_caps)
+
+ # creation of the videoconvert elements
+ self.videoformatconverter1 = Gst.ElementFactory.make("videoconvert", "video_convert1")
+ self.videoformatconverter2 = Gst.ElementFactory.make("videoconvert", "video_convert2")
+
+ self.tee = Gst.ElementFactory.make("tee", "tee")
+
+ # creation and configuration of the queue elements
+ self.queue1 = Gst.ElementFactory.make("queue", "queue-1")
+ self.queue2 = Gst.ElementFactory.make("queue", "queue-2")
+ self.queue1.set_property("max-size-buffers", 1)
+ self.queue1.set_property("leaky", 2)
+ self.queue2.set_property("max-size-buffers", 1)
+ self.queue2.set_property("leaky", 2)
+
+ # creation and configuration of the appsink element
+ self.appsink = Gst.ElementFactory.make("appsink", "appsink")
+ nn_caps = "video/x-raw,width=" + str(self.app.nn_input_width) + ",height=" + str(self.app.nn_input_height) + ",format=RGB, framerate=" + str(args.framerate)+ "/1"
+ print("Aux pipe configuration: ", nn_caps)
+ nncaps = Gst.Caps.from_string(nn_caps)
+ self.appsink.set_property("caps", nncaps)
+ self.appsink.set_property("emit-signals", True)
+ self.appsink.set_property("sync", False)
+ self.appsink.set_property("max-buffers", 1)
+ self.appsink.set_property("drop", True)
+ self.appsink.connect("new-sample", self.new_sample)
+
+ # creation of the gtkwaylandsink element to handle the gestreamer video stream
+ self.gtkwaylandsink = Gst.ElementFactory.make("gtkwaylandsink")
+ self.pack_start(self.gtkwaylandsink.props.widget, True, True, 0)
+ self.gtkwaylandsink.props.widget.show()
+
+ # creation and configuration of the fpsdisplaysink element to measure display fps
+ self.fps_disp_sink = Gst.ElementFactory.make("fpsdisplaysink", "fpsmeasure1")
+ self.fps_disp_sink.set_property("signal-fps-measurements", True)
+ self.fps_disp_sink.set_property("fps-update-interval", 2000)
+ self.fps_disp_sink.set_property("text-overlay", False)
+ self.fps_disp_sink.set_property("video-sink", self.gtkwaylandsink)
+ self.fps_disp_sink.connect("fps-measurements",self.get_fps_display)
+
+ # creation of the video rate and video scale elements
+ self.video_rate = Gst.ElementFactory.make("videorate", "video-rate")
+ self.video_scale = Gst.ElementFactory.make("videoscale", "video-scale")
+
+ # Add all elements to the pipeline
+ self.pipeline_preview.add(self.v4lsrc1)
+ self.pipeline_preview.add(self.camerafilter1)
+ self.pipeline_preview.add(self.videoformatconverter1)
+ self.pipeline_preview.add(self.videoformatconverter2)
+ self.pipeline_preview.add(self.rgb16_filter)
+ self.pipeline_preview.add(self.tee)
+ self.pipeline_preview.add(self.queue1)
+ self.pipeline_preview.add(self.queue2)
+ self.pipeline_preview.add(self.appsink)
+ self.pipeline_preview.add(self.fps_disp_sink)
+ self.pipeline_preview.add(self.video_rate)
+ self.pipeline_preview.add(self.video_scale)
+
+ # linking elements together
+ # -> queue 1 -> videoconvert -> fpsdisplaysink
+ # v4l2src -> video rate -> tee
+ # -> queue 2 -> videoconvert -> video scale -> appsink
+ self.v4lsrc1.link(self.video_rate)
+ self.video_rate.link(self.camerafilter1)
+ self.camerafilter1.link(self.tee)
+ self.queue1.link(self.videoformatconverter1)
+ self.videoformatconverter1.link(self.rgb16_filter)
+ self.rgb16_filter.link(self.fps_disp_sink)
+ self.queue2.link(self.videoformatconverter2)
+ self.videoformatconverter2.link(self.video_scale)
+ self.video_scale.link(self.appsink)
+ self.tee.link(self.queue1)
+ self.tee.link(self.queue2)
+
+ # set pipeline playing mode
+ self.pipeline_preview.set_state(Gst.State.PLAYING)
+ # getting pipeline bus
+ self.bus_preview = self.pipeline_preview.get_bus()
+ self.bus_preview.add_signal_watch()
+ self.bus_preview.connect('message::error', self.msg_error_cb)
+ self.bus_preview.connect('message::eos', self.msg_eos_cb)
+ self.bus_preview.connect('message::info', self.msg_info_cb)
+ self.bus_preview.connect('message::application', self.msg_application_cb)
+ self.bus_preview.connect('message::state-changed', self.msg_state_changed_cb)
+
+ return True
def camera_dual_pipeline_creation(self):
"""
creation of the gstreamer pipeline when gstwidget is created dedicated to camera stream
(in dual camera pipeline mode)
@@ -270,11 +383,14 @@ class GstWidget(Gtk.Box):
self.app.nn_inference_time = stop_time - start_time
self.app.nn_inference_fps = (1000/(self.app.nn_inference_time*1000))
self.app.keypoint_loc, self.app.keypoint_edges, self.app.edge_colors = self.app.nn.get_results()
struc = Gst.Structure.new_empty("inference-done")
msg = Gst.Message.new_application(None, struc)
- self.bus_pipeline.post(msg)
+ if (args.camera_src == "LIBCAMERA"):
+ self.bus_pipeline.post(msg)
+ elif(args.camera_src == "V4L2SRC"):
+ self.bus_preview.post(msg)
return Gst.FlowReturn.OK
def get_fps_display(self,fpsdisplaysink,fps,droprate,avgfps):
"""
measure and recover display fps
@@ -733,10 +849,12 @@ class Application:
check_camera_cmd = RESOURCES_DIRECTORY + "check_camera_preview.sh"
check_camera = subprocess.run(check_camera_cmd)
if check_camera.returncode==1:
print("no camera connected")
exit(1)
+ if (args.camera_src == "V4L2SRC"):
+ self.video_device_prev,self.camera_caps_prev,self.dcmipp_sensor, self.main_postproc = self.setup_camera()
else:
print("still picture mode activate")
self.enable_camera_preview = False
self.still_picture_next = False
# initialize the list of the file to be processed (used with the
@@ -785,10 +903,43 @@ class Application:
print("display resolution is : ",display_width, " x ", display_height)
self.window_width = int(display_width)
self.window_height = int(display_height)
return 0
+
+ def setup_camera(self):
+ """
+ Used to configure the camera based on resolution passed as application arguments
+ """
+ width = str(args.frame_width)
+ height = str(args.frame_height)
+ framerate = str(args.framerate)
+ device = str(args.video_device)
+ nn_input_width = str(self.nn_input_width)
+ nn_input_height = str(self.nn_input_height)
+ config_camera = RESOURCES_DIRECTORY + "setup_camera.sh " + width + " " + height + " " + framerate + " " + device
+ x = subprocess.check_output(config_camera,shell=True)
+ x = x.decode("utf-8")
+ x = x.split("\n")
+ for i in x :
+ if "V4L_DEVICE_PREV" in i:
+ video_device_prev = i.lstrip('V4L_DEVICE_PREV=')
+ if "V4L2_CAPS_PREV" in i:
+ camera_caps_prev = i.lstrip('V4L2_CAPS_PREV=')
+ if "V4L_DEVICE_NN" in i:
+ video_device_nn = i.lstrip('V4L_DEVICE_NN=')
+ if "V4L2_CAPS_NN" in i:
+ camera_caps_nn = i.lstrip('V4L2_CAPS_NN=')
+ if "DCMIPP_SENSOR" in i:
+ dcmipp_sensor = i.lstrip('DCMIPP_SENSOR=')
+ if "MAIN_POSTPROC" in i:
+ main_postproc = i.lstrip('MAIN_POSTPROC=')
+ if "AUX_POSTPROC" in i:
+ aux_postproc = i.lstrip('AUX_POSTPROC=')
+ return video_device_prev, camera_caps_prev, dcmipp_sensor, main_postproc
+
+
def valid_timeout_callback(self):
"""
if timeout occurs that means that camera preview and the gtk is not
behaving as expected
"""
@@ -1059,11 +1210,11 @@ if __name__ == '__main__':
parser.add_argument("--input_mean", default=255, help="input mean")
parser.add_argument("--input_std", default=0, help="input standard deviation")
parser.add_argument("--normalize", default=False, help="input standard deviation")
parser.add_argument("--validation", action='store_true', help="enable the validation mode")
parser.add_argument("--val_run", default=50, help="set the number of draws in the validation mode")
- parser.add_argument("--camera_src", default="LIBCAMERA", help="use V4L2SRC for MP1x and LIBCAMERA for MP2x")
+ parser.add_argument("--camera_src", default="LIBCAMERA", help="use V4L2SRC for MP1x or USB camera and LIBCAMERA for MP2x")
parser.add_argument("--debug", default=False, action='store_true', help=argparse.SUPPRESS)
args = parser.parse_args()
try:
application = Application(args)
--
2.34.1

View File

@ -8,6 +8,7 @@ SRC_URI += " \
file://patches/0002-pose-estimation-reduce-font-size-for-big-screens.patch \ file://patches/0002-pose-estimation-reduce-font-size-for-big-screens.patch \
file://patches/0003-pose-estimation-set-camera-preview-to-640x480.patch \ file://patches/0003-pose-estimation-set-camera-preview-to-640x480.patch \
${@bb.utils.contains("BBFILE_COLLECTIONS", "x-linux-isp", "file://patches/0004-pose-estimation-fix-initialization-issue-with-x-linu.patch", "", d)} \ ${@bb.utils.contains("BBFILE_COLLECTIONS", "x-linux-isp", "file://patches/0004-pose-estimation-fix-initialization-issue-with-x-linu.patch", "", d)} \
file://patches/0005-pose-estimation-restore-V4L2SRC-pipeline-for-USB-Web.patch \
" "
do_install:append () { do_install:append () {

View File

@ -0,0 +1,7 @@
# Copyright (C) 2026, Digi International Inc.
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += " \
file://patches/0001-setup_camera-fix-support-for-web-camera-with-STM32MP.patch \
"

View File

@ -6,13 +6,15 @@ Subject: [PATCH] config_board: fix support for web camera with STM32MP255
This commit disables the dual camera pipeline support for USB cameras, as it is This commit disables the dual camera pipeline support for USB cameras, as it is
exclusive to cameras using the DCMIPP peripheral. exclusive to cameras using the DCMIPP peripheral.
https://onedigi.atlassian.net/browse/DEL-10040
Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com> Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
--- ---
.../files/resources-files/config_board_npu.sh | 31 ++++++++++++++++++- resources-files/config_board_npu.sh | 32 ++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-) 1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/resources-files/config_board_npu.sh b/resources-files/config_board_npu.sh diff --git a/resources-files/config_board_npu.sh b/resources-files/config_board_npu.sh
index c89b5ca..af95558 100644 index dce3e68..65717f5 100644
--- a/resources-files/config_board_npu.sh --- a/resources-files/config_board_npu.sh
+++ b/resources-files/config_board_npu.sh +++ b/resources-files/config_board_npu.sh
@@ -16,10 +16,28 @@ STM32MP251="stm32mp251" @@ -16,10 +16,28 @@ STM32MP251="stm32mp251"
@ -44,7 +46,7 @@ index c89b5ca..af95558 100644
echo "Software X-LINUX-AI installed is not compatible with the board, please install X-LINUX-AI CPU version for plateform without hardware accelerator" echo "Software X-LINUX-AI installed is not compatible with the board, please install X-LINUX-AI CPU version for plateform without hardware accelerator"
exit 1 exit 1
fi fi
@@ -54,11 +72,22 @@ if [[ "$COMPATIBLE" == *"$STM32MP257"* ]] || [[ "$COMPATIBLE" == *"$STM32MP255"* @@ -56,11 +74,23 @@ if [[ "$COMPATIBLE" == *"$STM32MP257"* ]] || [[ "$COMPATIBLE" == *"$STM32MP255"*
MACHINE=$STM32MP2_NPU MACHINE=$STM32MP2_NPU
DWIDTH=760 DWIDTH=760
DHEIGHT=568 DHEIGHT=568
@ -58,6 +60,7 @@ index c89b5ca..af95558 100644
+ OPTIONS="--dual_camera_pipeline" + OPTIONS="--dual_camera_pipeline"
+ else + else
+ # Web camera + # Web camera
+ CAMERA_SRC="V4L2SRC"
+ OPTIONS="" + OPTIONS=""
+ DWIDTH=640 + DWIDTH=640
+ DHEIGHT=480 + DHEIGHT=480

View File

@ -0,0 +1,43 @@
From: Arturo Buzarra <arturo.buzarra@digi.com>
Date: Tue, 12 May 2026 10:07:34 +0200
Subject: [PATCH] setup_camera: fix support for web camera with STM32MP255
processor
This commit fixes the function to obtain the video node for USB cameras.
https://onedigi.atlassian.net/browse/DEL-10040
Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
---
resources-files/setup_camera.sh | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/resources-files/setup_camera.sh b/resources-files/setup_camera.sh
index 9d460a1..6f039e4 100644
--- a/resources-files/setup_camera.sh
+++ b/resources-files/setup_camera.sh
@@ -47,15 +47,16 @@ is_dcmipp_present() {
get_webcam_device() {
echo "get_webcam_device function"
found="NOTFOUND"
for video in $(find /sys/class/video4linux -name "video*" -type l | sort);
do
- if [ "$(cat $video/name)" = "dcmipp_dump_capture" ]; then
- found="FOUND"
- else
- V4L_DEVICE="$(basename $video)"
- break;
+ if ! $(cat "$video/name" | grep -q "dcmi") ; then
+ if ! $(cat "$video/name" | grep -q "stm32mp") ; then
+ V4L_DEVICE="$(basename "$video")"
+ found="FOUND"
+ break;
+ fi
fi
done
}
# ------------------------------
--
2.34.1

View File

@ -0,0 +1,250 @@
From: Arturo Buzarra <arturo.buzarra@digi.com>
Date: Tue, 12 May 2026 13:25:04 +0200
Subject: [PATCH] semantic-segmentation: restore V4L2SRC pipeline for USB Web
cameras
Backport the previous V4L2SRC-based capture path so MP2x platforms can use USB
webcams again.
https://onedigi.atlassian.net/browse/DEL-10040
Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
---
stai-mpu/stai_mpu_semantic_segmentation.py | 167 ++++++++++++++++++++-
1 file changed, 164 insertions(+), 3 deletions(-)
diff --git a/stai-mpu/stai_mpu_semantic_segmentation.py b/stai-mpu/stai_mpu_semantic_segmentation.py
index a4c65c2..e3601ba 100644
--- a/stai-mpu/stai_mpu_semantic_segmentation.py
+++ b/stai-mpu/stai_mpu_semantic_segmentation.py
@@ -62,12 +62,125 @@ class GstWidget(Gtk.Box):
def _on_realize(self, widget):
if(args.camera_src == "LIBCAMERA"):
self.camera_dual_pipeline_creation()
self.pipeline_preview.set_state(Gst.State.PLAYING)
+ elif(args.camera_src == "V4L2SRC"):
+ self.camera_pipeline_creation()
else:
- print("Camera source used not supported use LIBCAMERA \n")
+ print("Camera source used not supported use LIBCAMERA or V4L2SRC\n")
+
+ def camera_pipeline_creation(self):
+ """
+ Creation of the gstreamer pipeline when gstwidget is created dedicated to handle
+ camera stream and NN inference (mode single pipeline)
+ """
+ # gstreamer pipeline creation
+ self.pipeline_preview = Gst.Pipeline()
+
+ # creation of the source v4l2src
+ self.v4lsrc1 = Gst.ElementFactory.make("v4l2src", "source")
+ video_device = "/dev/" + str(self.app.video_device_prev)
+ self.v4lsrc1.set_property("device", video_device)
+
+ #creation of the v4l2src caps
+ caps = "video/x-raw,width=" + str(self.app.frame_width) + ",height=" + str(self.app.frame_height) + ", framerate=" + str(args.framerate)+ "/1"
+ print("Camera pipeline configuration : ",caps)
+ camera1caps = Gst.Caps.from_string(caps)
+ self.camerafilter1 = Gst.ElementFactory.make("capsfilter", "filter1")
+ self.camerafilter1.set_property("caps", camera1caps)
+
+ # creation of capsfilter to force RGB16 on preview branch
+ self.rgb16_filter = Gst.ElementFactory.make("capsfilter", "rgb16-filter")
+ rgb16_caps = Gst.Caps.from_string("video/x-raw,format=RGB16")
+ self.rgb16_filter.set_property("caps", rgb16_caps)
+
+ # creation of the videoconvert elements
+ self.videoformatconverter1 = Gst.ElementFactory.make("videoconvert", "video_convert1")
+ self.videoformatconverter2 = Gst.ElementFactory.make("videoconvert", "video_convert2")
+
+ self.tee = Gst.ElementFactory.make("tee", "tee")
+
+ # creation and configuration of the queue elements
+ self.queue1 = Gst.ElementFactory.make("queue", "queue-1")
+ self.queue2 = Gst.ElementFactory.make("queue", "queue-2")
+ self.queue1.set_property("max-size-buffers", 1)
+ self.queue1.set_property("leaky", 2)
+ self.queue2.set_property("max-size-buffers", 1)
+ self.queue2.set_property("leaky", 2)
+
+ # creation and configuration of the appsink element
+ self.appsink = Gst.ElementFactory.make("appsink", "appsink")
+ nn_caps = "video/x-raw,width=" + str(self.app.nn_input_width) + ",height=" + str(self.app.nn_input_height) + ",format=RGB, framerate=" + str(args.framerate)+ "/1"
+ print("Aux pipe configuration: ", nn_caps)
+ nncaps = Gst.Caps.from_string(nn_caps)
+ self.appsink.set_property("caps", nncaps)
+ self.appsink.set_property("emit-signals", True)
+ self.appsink.set_property("sync", False)
+ self.appsink.set_property("max-buffers", 1)
+ self.appsink.set_property("drop", True)
+ self.appsink.connect("new-sample", self.new_sample)
+
+ # creation of the gtkwaylandsink element to handle the gestreamer video stream
+ self.gtkwaylandsink = Gst.ElementFactory.make("gtkwaylandsink")
+ self.pack_start(self.gtkwaylandsink.props.widget, True, True, 0)
+ self.gtkwaylandsink.props.widget.show()
+
+ # creation and configuration of the fpsdisplaysink element to measure display fps
+ self.fps_disp_sink = Gst.ElementFactory.make("fpsdisplaysink", "fpsmeasure1")
+ self.fps_disp_sink.set_property("signal-fps-measurements", True)
+ self.fps_disp_sink.set_property("fps-update-interval", 2000)
+ self.fps_disp_sink.set_property("text-overlay", False)
+ self.fps_disp_sink.set_property("video-sink", self.gtkwaylandsink)
+ self.fps_disp_sink.connect("fps-measurements",self.get_fps_display)
+
+ # creation of the video rate and video scale elements
+ self.video_rate = Gst.ElementFactory.make("videorate", "video-rate")
+ self.video_scale = Gst.ElementFactory.make("videoscale", "video-scale")
+
+ # Add all elements to the pipeline
+ self.pipeline_preview.add(self.v4lsrc1)
+ self.pipeline_preview.add(self.camerafilter1)
+ self.pipeline_preview.add(self.videoformatconverter1)
+ self.pipeline_preview.add(self.videoformatconverter2)
+ self.pipeline_preview.add(self.rgb16_filter)
+ self.pipeline_preview.add(self.tee)
+ self.pipeline_preview.add(self.queue1)
+ self.pipeline_preview.add(self.queue2)
+ self.pipeline_preview.add(self.appsink)
+ self.pipeline_preview.add(self.fps_disp_sink)
+ self.pipeline_preview.add(self.video_rate)
+ self.pipeline_preview.add(self.video_scale)
+
+ # linking elements together
+ # -> queue 1 -> videoconvert -> fpsdisplaysink
+ # v4l2src -> video rate -> tee
+ # -> queue 2 -> videoconvert -> video scale -> appsink
+ self.v4lsrc1.link(self.video_rate)
+ self.video_rate.link(self.camerafilter1)
+ self.camerafilter1.link(self.tee)
+ self.queue1.link(self.videoformatconverter1)
+ self.videoformatconverter1.link(self.rgb16_filter)
+ self.rgb16_filter.link(self.fps_disp_sink)
+ self.queue2.link(self.videoformatconverter2)
+ self.videoformatconverter2.link(self.video_scale)
+ self.video_scale.link(self.appsink)
+ self.tee.link(self.queue1)
+ self.tee.link(self.queue2)
+
+ # set pipeline playing mode
+ self.pipeline_preview.set_state(Gst.State.PLAYING)
+ # getting pipeline bus
+ self.bus_preview = self.pipeline_preview.get_bus()
+ self.bus_preview.add_signal_watch()
+ self.bus_preview.connect('message::error', self.msg_error_cb)
+ self.bus_preview.connect('message::eos', self.msg_eos_cb)
+ self.bus_preview.connect('message::info', self.msg_info_cb)
+ self.bus_preview.connect('message::application', self.msg_application_cb)
+ self.bus_preview.connect('message::state-changed', self.msg_state_changed_cb)
+
+ return True
def camera_dual_pipeline_creation(self):
"""
creation of the gstreamer pipeline when gstwidget is created dedicated to camera stream
(in dual camera pipeline mode)
@@ -230,17 +343,29 @@ class GstWidget(Gtk.Box):
buffer_size = buf.get_size()
#determine the shape of the numpy array
number_of_column = caps.get_structure(0).get_value('width')
number_of_lines = caps.get_structure(0).get_value('height')
channels = 3
+
+ if (args.camera_src == "V4L2SRC"):
+ # Convert buffer, compute stride dynamically
+ # from the actual buffer size and frame height.
+ row_stride = buffer_size // number_of_lines
+ arr = np.ndarray(
+ (number_of_lines, number_of_column, channels),
+ strides=(row_stride, channels, 1),
+ buffer=buf.extract_dup(0, buffer_size),
+ dtype=np.uint8)
+ return arr
+
buffer = np.frombuffer(buf.extract_dup(0, buf.get_size()), dtype=np.uint8)
#DCMIPP pixelpacker has a constraint on the output resolution that should be multiple of 16.
# the allocated buffer may contains stride to handle the DCMIPP Hw constraints/
#The following code allow to handle both cases by anticipating the size of the
#allocated buffer according to the NN resolution
- if (self.app.nn_input_width % 16 != 0):
+ if (self.app.nn_input_width % 16 != 0) and (args.camera_src == "LIBCAMERA"):
# Calculate the nearest upper multiple of 16
upper_multiple = ((self.app.nn_input_width // 16) + 1) * 16
# Calculate the stride and offset
stride = upper_multiple * channels
offset = stride - (number_of_column * channels)
@@ -276,11 +401,14 @@ class GstWidget(Gtk.Box):
self.app.nn_inference_time = stop_time - start_time
self.app.nn_inference_fps = (1000/(self.app.nn_inference_time*1000))
self.app.unique_label, self.app.nn_seg_map = self.app.nn.get_results()
struc = Gst.Structure.new_empty("inference-done")
msg = Gst.Message.new_application(None, struc)
- self.bus_pipeline.post(msg)
+ if (args.camera_src == "LIBCAMERA"):
+ self.bus_pipeline.post(msg)
+ elif(args.camera_src == "V4L2SRC"):
+ self.bus_preview.post(msg)
return Gst.FlowReturn.OK
def get_fps_display(self,fpsdisplaysink,fps,droprate,avgfps):
"""
measure and recover display fps
@@ -863,10 +991,12 @@ class Application:
check_camera_cmd = RESOURCES_DIRECTORY + "check_camera_preview.sh"
check_camera = subprocess.run(check_camera_cmd)
if check_camera.returncode==1:
print("no camera connected")
exit(1)
+ if (args.camera_src == "V4L2SRC"):
+ self.video_device_prev,self.camera_caps_prev,self.dcmipp_sensor, self.main_postproc = self.setup_camera()
else:
print("still picture mode activate")
self.enable_camera_preview = False
self.still_picture_next = False
@@ -916,10 +1046,41 @@ class Application:
print("display resolution is : ",display_width, " x ", display_height)
self.window_width = int(display_width)
self.window_height = int(display_height)
return 0
+ def setup_camera(self):
+ """
+ Used to configure the camera based on resolution passed as application arguments
+ """
+ width = str(args.frame_width)
+ height = str(args.frame_height)
+ framerate = str(args.framerate)
+ device = str(args.video_device)
+ nn_input_width = str(self.nn_input_width)
+ nn_input_height = str(self.nn_input_height)
+ config_camera = RESOURCES_DIRECTORY + "setup_camera.sh " + width + " " + height + " " + framerate + " " + device
+ x = subprocess.check_output(config_camera,shell=True)
+ x = x.decode("utf-8")
+ x = x.split("\n")
+ for i in x :
+ if "V4L_DEVICE_PREV" in i:
+ video_device_prev = i.lstrip('V4L_DEVICE_PREV=')
+ if "V4L2_CAPS_PREV" in i:
+ camera_caps_prev = i.lstrip('V4L2_CAPS_PREV=')
+ if "V4L_DEVICE_NN" in i:
+ video_device_nn = i.lstrip('V4L_DEVICE_NN=')
+ if "V4L2_CAPS_NN" in i:
+ camera_caps_nn = i.lstrip('V4L2_CAPS_NN=')
+ if "DCMIPP_SENSOR" in i:
+ dcmipp_sensor = i.lstrip('DCMIPP_SENSOR=')
+ if "MAIN_POSTPROC" in i:
+ main_postproc = i.lstrip('MAIN_POSTPROC=')
+ if "AUX_POSTPROC" in i:
+ aux_postproc = i.lstrip('AUX_POSTPROC=')
+ return video_device_prev, camera_caps_prev, dcmipp_sensor, main_postproc
+
def valid_timeout_callback(self):
"""
if timeout occurs that means that camera preview and the gtk is not
behaving as expected */
"""
--
2.34.1

View File

@ -9,6 +9,7 @@ SRC_URI += " \
file://patches/0003-semantic-segmentation-adapt-sample-for-root-user.patch \ file://patches/0003-semantic-segmentation-adapt-sample-for-root-user.patch \
file://patches/0004-semantic-segmentation-set-camera-preview-to-640x480.patch \ file://patches/0004-semantic-segmentation-set-camera-preview-to-640x480.patch \
${@bb.utils.contains("BBFILE_COLLECTIONS", "x-linux-isp", "file://patches/0005-semantic-segmentation-fix-initialization-issue-with-.patch", "", d)} \ ${@bb.utils.contains("BBFILE_COLLECTIONS", "x-linux-isp", "file://patches/0005-semantic-segmentation-fix-initialization-issue-with-.patch", "", d)} \
file://patches/0006-semantic-segmentation-restore-V4L2SRC-pipeline-for-U.patch \
" "
do_install:append () { do_install:append () {