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

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

Commit Message

Vedant Paranjape Sept. 23, 2021, 1:46 p.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>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
 .../gstreamer/gstreamer_multi_stream_test.cpp | 121 ++++++++++++++++++
 test/gstreamer/meson.build                    |   1 +
 2 files changed, 122 insertions(+)
 create mode 100644 test/gstreamer/gstreamer_multi_stream_test.cpp

Comments

Nicolas Dufresne Sept. 23, 2021, 2:05 p.m. UTC | #1
Le jeudi 23 septembre 2021 à 19:16 +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>
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> ---
>  .../gstreamer/gstreamer_multi_stream_test.cpp | 121 ++++++++++++++++++
>  test/gstreamer/meson.build                    |   1 +
>  2 files changed, 122 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..5df1dd40388a
> --- /dev/null
> +++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
> @@ -0,0 +1,121 @@
> +/* 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 ! 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_) {
> +			g_printerr("Bin 0 could not be created (%s)\n", error0->message);
> +			return TestFail;
> +		}
> +		if (!stream1_) {
> +			g_printerr("Bin 1 could not be created (%s)\n", error1->message);
> +			return TestFail;
> +		}
> +		g_object_ref_sink(stream0_);
> +		g_object_ref_sink(stream1_);

In general, I refer when things are slightly more grouped together, what do you
think of:

+		g_autoptr(GError) error = NULL;
+
+		stream0_ = gst_parse_bin_from_description_full(streamDescription, TRUE, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error);
+		if (!stream0_) {
+			g_printerr("Stream 0 could not be created (%s)\n", error->message);
+			return TestFail;
+		}
+		g_object_ref_sink(stream0_);
+
+		stream1_ = gst_parse_bin_from_description_full(streamDescription, TRUE, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error);
+		if (!stream1_) {
+			g_printerr("Stream 1 could not be created (%s)\n", error->message);
+			return TestFail;
+		}
+		g_object_ref_sink(stream1_);

p.s. Changed Bin into Stream, I would not get what that means if I saw an error
about bin0/1, as the member is named streamX.

> +
> +		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)
>
Vedant Paranjape Sept. 23, 2021, 2:50 p.m. UTC | #2
On Thu, Sep 23, 2021 at 7:35 PM Nicolas Dufresne <
nicolas.dufresne@collabora.com> wrote:

> Le jeudi 23 septembre 2021 à 19:16 +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>
> > Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> > ---
> >  .../gstreamer/gstreamer_multi_stream_test.cpp | 121 ++++++++++++++++++
> >  test/gstreamer/meson.build                    |   1 +
> >  2 files changed, 122 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..5df1dd40388a
> > --- /dev/null
> > +++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
> > @@ -0,0 +1,121 @@
> > +/* 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 ! 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_) {
> > +                     g_printerr("Bin 0 could not be created (%s)\n",
> error0->message);
> > +                     return TestFail;
> > +             }
> > +             if (!stream1_) {
> > +                     g_printerr("Bin 1 could not be created (%s)\n",
> error1->message);
> > +                     return TestFail;
> > +             }
> > +             g_object_ref_sink(stream0_);
> > +             g_object_ref_sink(stream1_);
>
> In general, I refer when things are slightly more grouped together, what
> do you
> think of:
>
> +               g_autoptr(GError) error = NULL;
> +
> +               stream0_ =
> gst_parse_bin_from_description_full(streamDescription, TRUE, NULL,
> GST_PARSE_FLAG_FATAL_ERRORS, &error);
> +               if (!stream0_) {
> +                       g_printerr("Stream 0 could not be created (%s)\n",
> error->message);
> +                       return TestFail;
> +               }
> +               g_object_ref_sink(stream0_);
> +
> +               stream1_ =
> gst_parse_bin_from_description_full(streamDescription, TRUE, NULL,
> GST_PARSE_FLAG_FATAL_ERRORS, &error);
> +               if (!stream1_) {
> +                       g_printerr("Stream 1 could not be created (%s)\n",
> error->message);
> +                       return TestFail;
> +               }
> +               g_object_ref_sink(stream1_);
>
> p.s. Changed Bin into Stream, I would not get what that means if I saw an
> error
> about bin0/1, as the member is named streamX.
>

This looks much better. Sending a v3.

> +
> > +             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)
> >
>
>
>

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..5df1dd40388a
--- /dev/null
+++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
@@ -0,0 +1,121 @@ 
+/* 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 ! 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_) {
+			g_printerr("Bin 0 could not be created (%s)\n", error0->message);
+			return TestFail;
+		}
+		if (!stream1_) {
+			g_printerr("Bin 1 could not be created (%s)\n", error1->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)