[libcamera-devel,v1] test: gstreamer: Add a test for gstreamer multi stream
diff mbox series

Message ID 20210923110518.1556973-1-vedantparanjape160201@gmail.com
State Accepted
Headers show
Series
  • [libcamera-devel,v1] test: gstreamer: Add a test for gstreamer multi stream
Related show

Commit Message

Vedant Paranjape Sept. 23, 2021, 11:05 a.m. UTC
This patch adds a test to test if multi stream using libcamera's
gstreamer element works.

Test will run only on devices that support multistream output, i.e.,
devices that use IPU3 and raspberrypi pipeline. This was tested on
a Raspberry Pi 4B+.

Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
---

I am unable to run Valgrind on my RPI4B+, please check for memory
leaks on RPI4B+ as well. I used the following steps to test on amd64
system using the suppression files.

<snip>
cd libcamera
wget https://cgit.freedesktop.org/gstreamer/common/plain/gst.supp -P /tmp
ninja -C build test
valgrind --leak-check=full --suppressions=/usr/share/glib-2.0/valgrind/glib.supp --suppressions=/tmp/gst.supp ./build/test/gstreamer/single_stream_test
valgrind --leak-check=full --suppressions=/usr/share/glib-2.0/valgrind/glib.supp --suppressions=/tmp/gst.supp ./build/test/gstreamer/multi_stream_test
<snip>

Also please test this test on IPU3 enabled devices too, as I don't have
access to the same.

---
 .../gstreamer/gstreamer_multi_stream_test.cpp | 118 ++++++++++++++++++
 test/gstreamer/meson.build                    |   1 +
 2 files changed, 119 insertions(+)
 create mode 100644 test/gstreamer/gstreamer_multi_stream_test.cpp

Comments

Nicolas Dufresne Sept. 23, 2021, 1:07 p.m. UTC | #1
Le jeudi 23 septembre 2021 à 16:35 +0530, Vedant Paranjape a écrit :
> This patch adds a test to test if multi stream using libcamera's
> gstreamer element works.
> 
> Test will run only on devices that support multistream output, i.e.,
> devices that use IPU3 and raspberrypi pipeline. This was tested on
> a Raspberry Pi 4B+.
> 
> Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> ---
> 
> I am unable to run Valgrind on my RPI4B+, please check for memory
> leaks on RPI4B+ as well. I used the following steps to test on amd64
> system using the suppression files.
> 
> <snip>
> cd libcamera
> wget https://cgit.freedesktop.org/gstreamer/common/plain/gst.supp -P /tmp
> ninja -C build test
> valgrind --leak-check=full --suppressions=/usr/share/glib-2.0/valgrind/glib.supp --suppressions=/tmp/gst.supp ./build/test/gstreamer/single_stream_test
> valgrind --leak-check=full --suppressions=/usr/share/glib-2.0/valgrind/glib.supp --suppressions=/tmp/gst.supp ./build/test/gstreamer/multi_stream_test
> <snip>
> 
> Also please test this test on IPU3 enabled devices too, as I don't have
> access to the same.
> 
> ---
>  .../gstreamer/gstreamer_multi_stream_test.cpp | 118 ++++++++++++++++++
>  test/gstreamer/meson.build                    |   1 +
>  2 files changed, 119 insertions(+)
>  create mode 100644 test/gstreamer/gstreamer_multi_stream_test.cpp
> 
> diff --git a/test/gstreamer/gstreamer_multi_stream_test.cpp b/test/gstreamer/gstreamer_multi_stream_test.cpp
> new file mode 100644
> index 000000000000..76cf5a3418a1
> --- /dev/null
> +++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
> @@ -0,0 +1,118 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2021, Vedant Paranjape
> + *
> + * gstreamer_multi_stream_test.cpp - GStreamer multi stream capture test
> + */
> +
> +#include <iostream>
> +#include <unistd.h>
> +
> +#include <libcamera/base/utils.h>
> +
> +#include <libcamera/libcamera.h>
> +
> +#include "libcamera/internal/source_paths.h"
> +
> +#include <gst/gst.h>
> +
> +#include "gstreamer_test.h"
> +#include "test.h"
> +
> +using namespace std;
> +
> +class GstreamerMultiStreamTest : public GstreamerTest, public Test
> +{
> +public:
> +	GstreamerMultiStreamTest()
> +		: GstreamerTest()
> +	{
> +	}
> +
> +protected:
> +	int init() override
> +	{
> +		if (status_ != TestPass)
> +			return status_;
> +
> +		/* Check if platform support multistream output */
> +		libcamera::CameraManager cm;
> +		cm.start();
> +		bool cameraFound = false;
> +		for (auto &camera : cm.cameras()) {
> +			if (camera->streams().size() > 1) {
> +				cameraName = camera->id();
> +				cameraFound = true;
> +				cm.stop();
> +				break;
> +			}
> +		}
> +
> +		if (!cameraFound) {
> +			cm.stop();
> +			return TestSkip;
> +		}
> +
> +		const gchar *streamDescription = "queue ! videoconvert ! fakesink";

Converter could be removed, it will always passthrough.

> +		g_autoptr(GError) error0 = NULL;
> +		g_autoptr(GError) error1 = NULL;
> +		stream0_ = gst_parse_bin_from_description_full(streamDescription, TRUE, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error0);
> +		stream1_ = gst_parse_bin_from_description_full(streamDescription, TRUE, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error1);
> +
> +		if (!stream0_ || !stream1_) {
> +			g_printerr("Not all bins could be created. %p.%p\n",
> +						stream0_, stream1_);

Please, split this in two checks, so you can dump the appropriate error message.

> +			return TestFail;
> +		}
> +		g_object_ref_sink(stream0_);
> +		g_object_ref_sink(stream1_);
> +
> +		if (createPipeline() != TestPass)
> +			return TestFail;
> +
> +		return TestPass;
> +	}
> +
> +	int run() override
> +	{
> +		g_object_set(libcameraSrc_, "camera-name", cameraName.c_str(), NULL);
> +
> +		/* Build the pipeline */
> +		gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
> +							stream0_, stream1_, NULL);
> +
> +		g_autoptr(GstPad) src_pad = gst_element_get_static_pad(libcameraSrc_, "src");
> +		g_autoptr(GstPad) request_pad = gst_element_get_request_pad(libcameraSrc_, "src_%u");
> +
> +		{
> +			g_autoptr(GstPad) queue0_sink_pad = gst_element_get_static_pad(stream0_, "sink");
> +			g_autoptr(GstPad) queue1_sink_pad = gst_element_get_static_pad(stream1_, "sink");
> +
> +			if (gst_pad_link(src_pad, queue0_sink_pad) != GST_PAD_LINK_OK
> +				|| gst_pad_link(request_pad, queue1_sink_pad) != GST_PAD_LINK_OK) {
> +				g_printerr("Pads could not be linked.\n");
> +				return TestFail;
> +			}
> +		}
> +
> +		if (startPipeline() != TestPass)
> +			return TestFail;
> +
> +		if (processEvent() != TestPass)
> +			return TestFail;
> +
> +		return TestPass;
> +	}
> +
> +	void cleanup() override
> +	{
> +		g_clear_object(&stream0_);
> +		g_clear_object(&stream1_);
> +	}
> +private:
> +	std::string cameraName;
> +	GstElement *stream0_;
> +	GstElement *stream1_;
> +};
> +
> +TEST_REGISTER(GstreamerMultiStreamTest)
> diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> index aca53b920365..13652e87d05c 100644
> --- a/test/gstreamer/meson.build
> +++ b/test/gstreamer/meson.build
> @@ -6,6 +6,7 @@ endif
>  
>  gstreamer_tests = [
>      ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> +    ['multi_stream_test',   'gstreamer_multi_stream_test.cpp'],
>  ]
>  gstreamer_dep = dependency('gstreamer-1.0', required: true)


Looks good with that minor change.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>

>

Patch
diff mbox series

diff --git a/test/gstreamer/gstreamer_multi_stream_test.cpp b/test/gstreamer/gstreamer_multi_stream_test.cpp
new file mode 100644
index 000000000000..76cf5a3418a1
--- /dev/null
+++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
@@ -0,0 +1,118 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2021, Vedant Paranjape
+ *
+ * gstreamer_multi_stream_test.cpp - GStreamer multi stream capture test
+ */
+
+#include <iostream>
+#include <unistd.h>
+
+#include <libcamera/base/utils.h>
+
+#include <libcamera/libcamera.h>
+
+#include "libcamera/internal/source_paths.h"
+
+#include <gst/gst.h>
+
+#include "gstreamer_test.h"
+#include "test.h"
+
+using namespace std;
+
+class GstreamerMultiStreamTest : public GstreamerTest, public Test
+{
+public:
+	GstreamerMultiStreamTest()
+		: GstreamerTest()
+	{
+	}
+
+protected:
+	int init() override
+	{
+		if (status_ != TestPass)
+			return status_;
+
+		/* Check if platform support multistream output */
+		libcamera::CameraManager cm;
+		cm.start();
+		bool cameraFound = false;
+		for (auto &camera : cm.cameras()) {
+			if (camera->streams().size() > 1) {
+				cameraName = camera->id();
+				cameraFound = true;
+				cm.stop();
+				break;
+			}
+		}
+
+		if (!cameraFound) {
+			cm.stop();
+			return TestSkip;
+		}
+
+		const gchar *streamDescription = "queue ! videoconvert ! fakesink";
+		g_autoptr(GError) error0 = NULL;
+		g_autoptr(GError) error1 = NULL;
+		stream0_ = gst_parse_bin_from_description_full(streamDescription, TRUE, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error0);
+		stream1_ = gst_parse_bin_from_description_full(streamDescription, TRUE, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error1);
+
+		if (!stream0_ || !stream1_) {
+			g_printerr("Not all bins could be created. %p.%p\n",
+						stream0_, stream1_);
+			return TestFail;
+		}
+		g_object_ref_sink(stream0_);
+		g_object_ref_sink(stream1_);
+
+		if (createPipeline() != TestPass)
+			return TestFail;
+
+		return TestPass;
+	}
+
+	int run() override
+	{
+		g_object_set(libcameraSrc_, "camera-name", cameraName.c_str(), NULL);
+
+		/* Build the pipeline */
+		gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
+							stream0_, stream1_, NULL);
+
+		g_autoptr(GstPad) src_pad = gst_element_get_static_pad(libcameraSrc_, "src");
+		g_autoptr(GstPad) request_pad = gst_element_get_request_pad(libcameraSrc_, "src_%u");
+
+		{
+			g_autoptr(GstPad) queue0_sink_pad = gst_element_get_static_pad(stream0_, "sink");
+			g_autoptr(GstPad) queue1_sink_pad = gst_element_get_static_pad(stream1_, "sink");
+
+			if (gst_pad_link(src_pad, queue0_sink_pad) != GST_PAD_LINK_OK
+				|| gst_pad_link(request_pad, queue1_sink_pad) != GST_PAD_LINK_OK) {
+				g_printerr("Pads could not be linked.\n");
+				return TestFail;
+			}
+		}
+
+		if (startPipeline() != TestPass)
+			return TestFail;
+
+		if (processEvent() != TestPass)
+			return TestFail;
+
+		return TestPass;
+	}
+
+	void cleanup() override
+	{
+		g_clear_object(&stream0_);
+		g_clear_object(&stream1_);
+	}
+private:
+	std::string cameraName;
+	GstElement *stream0_;
+	GstElement *stream1_;
+};
+
+TEST_REGISTER(GstreamerMultiStreamTest)
diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
index aca53b920365..13652e87d05c 100644
--- a/test/gstreamer/meson.build
+++ b/test/gstreamer/meson.build
@@ -6,6 +6,7 @@  endif
 
 gstreamer_tests = [
     ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
+    ['multi_stream_test',   'gstreamer_multi_stream_test.cpp'],
 ]
 gstreamer_dep = dependency('gstreamer-1.0', required: true)