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

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

Commit Message

Vedant Paranjape Sept. 24, 2021, 8:38 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 capture, eg.,
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 | 124 ++++++++++++++++++
 test/gstreamer/meson.build                    |   1 +
 2 files changed, 125 insertions(+)
 create mode 100644 test/gstreamer/gstreamer_multi_stream_test.cpp

Comments

Paul Elder Sept. 24, 2021, 8:50 a.m. UTC | #1
Hi Vedant,

On Fri, Sep 24, 2021 at 02:08:21PM +0530, Vedant Paranjape wrote:
> 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 capture, eg.,
> 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 | 124 ++++++++++++++++++
>  test/gstreamer/meson.build                    |   1 +
>  2 files changed, 125 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..6a9a6f2509cb
> --- /dev/null
> +++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
> @@ -0,0 +1,124 @@
> +/* 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/libcamera.h>
> +
> +#include <gst/gst.h>
> +
> +#include "gstreamer_test.h"
> +#include "test.h"

Could you please later send a patch to remove the unnecessary includes
from the single stream test?

> +
> +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 */

s/support/supports/

s/output/capture/

I'll do these changes when applying.


Looks good!

Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>

> +		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) error = NULL;
> +
> +		stream0_ = gst_parse_bin_from_description_full(streamDescription, TRUE,
> +							       NULL,
> +							       GST_PARSE_FLAG_FATAL_ERRORS,
> +							       &error);
> +		if (!stream0_) {
> +			g_printerr("Stream0 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("Stream1 could not be created (%s)\n", error->message);
> +			return TestFail;
> +		}
> +		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..10058fc5206f 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)
>  
> -- 
> 2.25.1
>
Vedant Paranjape Sept. 24, 2021, 8:54 a.m. UTC | #2
On Fri, Sep 24, 2021 at 2:21 PM <paul.elder@ideasonboard.com> wrote:
>
> Hi Vedant,
>
> On Fri, Sep 24, 2021 at 02:08:21PM +0530, Vedant Paranjape wrote:
> > 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 capture, eg.,
> > 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 | 124 ++++++++++++++++++
> >  test/gstreamer/meson.build                    |   1 +
> >  2 files changed, 125 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..6a9a6f2509cb
> > --- /dev/null
> > +++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
> > @@ -0,0 +1,124 @@
> > +/* 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/libcamera.h>
> > +
> > +#include <gst/gst.h>
> > +
> > +#include "gstreamer_test.h"
> > +#include "test.h"
>
> Could you please later send a patch to remove the unnecessary includes
> from the single stream test?
>
Yes, I will send a patch.
> > +
> > +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 */
>
> s/support/supports/
>
> s/output/capture/
>
> I'll do these changes when applying.
>
>
> Looks good!
>
> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
>
> > +             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) error = NULL;
> > +
> > +             stream0_ = gst_parse_bin_from_description_full(streamDescription, TRUE,
> > +                                                            NULL,
> > +                                                            GST_PARSE_FLAG_FATAL_ERRORS,
> > +                                                            &error);
> > +             if (!stream0_) {
> > +                     g_printerr("Stream0 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("Stream1 could not be created (%s)\n", error->message);
> > +                     return TestFail;
> > +             }
> > +             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..10058fc5206f 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)
> >
> > --
> > 2.25.1
> >

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..6a9a6f2509cb
--- /dev/null
+++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
@@ -0,0 +1,124 @@ 
+/* 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/libcamera.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) error = NULL;
+
+		stream0_ = gst_parse_bin_from_description_full(streamDescription, TRUE,
+							       NULL,
+							       GST_PARSE_FLAG_FATAL_ERRORS,
+							       &error);
+		if (!stream0_) {
+			g_printerr("Stream0 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("Stream1 could not be created (%s)\n", error->message);
+			return TestFail;
+		}
+		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..10058fc5206f 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)