[libcamera-devel] [PATCH v4] test: gstreamer: Add a test for gstreamer multi stream

Jean-Michel Hautbois jeanmichel.hautbois at ideasonboard.com
Tue Sep 14 12:24:37 CEST 2021



On 14/09/2021 12:23, Jean-Michel Hautbois wrote:
> Hi Vedant,
> 
> On 14/09/2021 10:46, Vedant Paranjape wrote:
>> This patch adds a test to test if multi stream using libcamera's
>> gstreamer element works.
> 
> A test to test :-) ?
> A proposal (I am not good at writing commit messages though so, please
> use it with care :-)):

I obviously forgot to paste it... :-/ and now I lost it...
Basically, introduce the fact we are not testing it and just say what
this test does (outputs two streams in fakesink if multi-stream is
supported by the device).

> 
>>
>> Test will run only on devices that support multistream output, i.e.,
>> devices that use IPU3 and RPI pipeline. This was tested on a Raspberry
>> Pi 4B+
>>
>> Signed-off-by: Vedant Paranjape <vedantparanjape160201 at gmail.com>
>> Reviewed-by: Paul Elder <paul.elder at ideasonboard.com>
>> Tested-by: Paul Elder <paul.elder at ideasonboard.com>
>> ---
>>  .../gstreamer/gstreamer_multi_stream_test.cpp | 138 ++++++++++++++++++
>>  test/gstreamer/meson.build                    |   1 +
>>  2 files changed, 139 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..aea9a1dcb211
>> --- /dev/null
>> +++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
>> @@ -0,0 +1,138 @@
>> +/* 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;
>> +		}
>> +
>> +		g_autoptr(GstElement) convert0 = gst_element_factory_make("videoconvert", "convert0");
>> +		g_autoptr(GstElement) convert1 = gst_element_factory_make("videoconvert", "convert1");
> 
> Why do you need a convert element ? AFAIK you are outputting into a
> fakesink it should not be an issue ?
> 
>> +		g_autoptr(GstElement) sink0 = gst_element_factory_make("fakesink", "sink0");
>> +		g_autoptr(GstElement) sink1 = gst_element_factory_make("fakesink", "sink1");
>> +		g_autoptr(GstElement) queue0 = gst_element_factory_make("queue", "queue0");
>> +		g_autoptr(GstElement) queue1 = gst_element_factory_make("queue", "queue1");
>> +		g_object_ref_sink(convert0);
>> +		g_object_ref_sink(convert1);
>> +		g_object_ref_sink(sink0);
>> +		g_object_ref_sink(sink1);
>> +		g_object_ref_sink(queue0);
>> +		g_object_ref_sink(queue1);
> 
> I don't really like that, why can't you use
> gst_parse_bin_from_description() for instance ?
> That way you would get a bin you could link to libcamerasrc.
> 
> Note: it is a long time since I really use GStreamer so I may not be
> up-to-date, Nicolas may a different comment, and he would be the one to
> follow ;-).
> 
>> +
>> +		if (!convert0 || !convert1 || !sink0 || !sink1 || !queue0 || !queue1) {
>> +			g_printerr("Not all elements could be created. %p.%p.%p.%p.%p.%p\n",
>> +				   convert0, convert1, sink0, sink1, queue0, queue1);
>> +
>> +			return TestFail;
>> +		}
>> +
>> +		if (createPipeline() != TestPass)
>> +			return TestFail;
>> +
>> +		convert0_ = reinterpret_cast<GstElement *>(g_steal_pointer(&convert0));
>> +		convert1_ = reinterpret_cast<GstElement *>(g_steal_pointer(&convert1));
>> +		sink0_ = reinterpret_cast<GstElement *>(g_steal_pointer(&sink0));
>> +		sink1_ = reinterpret_cast<GstElement *>(g_steal_pointer(&sink1));
>> +		queue0_ = reinterpret_cast<GstElement *>(g_steal_pointer(&queue0));
>> +		queue1_ = reinterpret_cast<GstElement *>(g_steal_pointer(&queue1));
>> +
>> +		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_, queue0_, queue1_,
>> +				 convert0_, convert1_, sink0_, sink1_, NULL);
>> +		if (gst_element_link_many(queue0_, convert0_, sink0_, NULL) != TRUE ||
>> +		    gst_element_link_many(queue1_, convert1_, sink1_, NULL) != TRUE) {
>> +			g_printerr("Elements could not be linked.\n");
>> +			return TestFail;
>> +		}
>> +
>> +		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");
>> +		GstPad *queue0_sink_pad = gst_element_get_static_pad(queue0_, "sink");
>> +		GstPad *queue1_sink_pad = gst_element_get_static_pad(queue1_, "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) {
>> +			if (queue0_sink_pad)
>> +				gst_object_unref(queue0_sink_pad);
>> +			if (queue1_sink_pad)
>> +				gst_object_unref(queue1_sink_pad);
>> +			g_printerr("Pads could not be linked.\n");
>> +			return TestFail;
>> +		}
>> +		gst_object_unref(queue0_sink_pad);
>> +		gst_object_unref(queue1_sink_pad);
>> +
>> +		if (startPipeline() != TestPass)
>> +			return TestFail;
>> +
>> +		if (processEvent() != TestPass)
>> +			return TestFail;
>> +
>> +		return TestPass;
>> +	}
>> +
>> +private:
>> +	std::string cameraName;
>> +	GstElement *convert0_;
>> +	GstElement *convert1_;
>> +	GstElement *sink0_;
>> +	GstElement *sink1_;
>> +	GstElement *queue0_;
>> +	GstElement *queue1_;
>> +};
>> +
>> +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)
>>  
>>


More information about the libcamera-devel mailing list