[libcamera-devel,v10] test: gstreamer: Add test for gstreamer single stream
diff mbox series

Message ID 20210813104302.200994-1-vedantparanjape160201@gmail.com
State Superseded
Headers show
Series
  • [libcamera-devel,v10] test: gstreamer: Add test for gstreamer single stream
Related show

Commit Message

Vedant Paranjape Aug. 13, 2021, 10:43 a.m. UTC
This patch adds a test to test if single stream using
libcamera's gstreamer element works.

Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
 test/gstreamer/meson.build                    |  19 +++
 test/meson.build                              |   1 +
 3 files changed, 173 insertions(+)
 create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
 create mode 100644 test/gstreamer/meson.build

Comments

Laurent Pinchart Aug. 13, 2021, 12:57 p.m. UTC | #1
Hi Vedant,

Thank you for the patch.

On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> This patch adds a test to test if single stream using
> libcamera's gstreamer element works.
> 
> Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> ---
>  .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
>  test/gstreamer/meson.build                    |  19 +++
>  test/meson.build                              |   1 +
>  3 files changed, 173 insertions(+)
>  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
>  create mode 100644 test/gstreamer/meson.build
> 
> diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp
> new file mode 100644
> index 00000000..eecd3274
> --- /dev/null
> +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> @@ -0,0 +1,153 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2021, Vedant Paranjape
> + *
> + * ipa_interface_test.cpp - Test the IPA interface
> + */
> +
> +#include <iostream>
> +
> +#include <libcamera/base/utils.h>
> +
> +#include <gst/gst.h>
> +
> +#include "test.h"
> +
> +using namespace std;
> +
> +class GstreamerSingleStreamTest : public Test
> +{
> +protected:
> +	int init() override
> +	{
> +		/* Initialize GStreamer */
> +		GError *errInit = nullptr;
> +		if (!gst_init_check(nullptr, nullptr, &errInit)) {
> +			g_printerr("Could not initialize GStreamer: %s\n",
> +				   errInit ? errInit->message : "unknown error");
> +			if (errInit)
> +				g_error_free(errInit);
> +
> +			return TestFail;
> +		}
> +
> +		/*
> +		* Remove the system libcamera plugin, if any, and add the
> +		* plugin from the build directory.
> +		*/

Missing space before *

> +		GstRegistry *registry = gst_registry_get();
> +		GstPlugin *plugin = gst_registry_lookup(registry, "libgstlibcamera.so");
> +		if (plugin) {
> +			gst_registry_remove_plugin(registry, plugin);
> +			gst_object_unref(plugin);
> +		}
> +		

Extra blank spaces at the end of the line.

> +		std::string path = std::string(libcamera::utils::libcameraBuildPath()
> +					+ "src/gstreamer");

No need for calling the std::string constructor explictly,
libcamera::utils::libcameraBuildPath() returns an std::string and the
result of the operator+() call is also an std::string.

You should #include "libcamera/internal/source_paths.h"" for
libcamera::utils::libcameraBuildPath().

I'll fix these small issues when applying.

> +		if (!gst_registry_scan_path(registry, path.c_str())) {
> +			g_printerr("Failed to add plugin to registry\n");
> +			gst_deinit();
> +			return TestFail;
> +		}
> +
> +		/* Create the elements */
> +		libcameraSrc_ = gst_element_factory_make("libcamerasrc", "libcamera");
> +		convert0_ = gst_element_factory_make("videoconvert", "convert0");
> +		sink0_ = gst_element_factory_make("fakesink", "sink0");
> +
> +		/* Create the empty pipeline_ */
> +		pipeline_ = gst_pipeline_new("test-pipeline");
> +
> +		if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) {
> +			g_printerr("Not all elements could be created. %p.%p.%p.%p\n",
> +				   pipeline_, convert0_, sink0_, libcameraSrc_);
> +			if (pipeline_)
> +				gst_object_unref(pipeline_);
> +			if (convert0_)
> +				gst_object_unref(convert0_);
> +			if (sink0_)
> +				gst_object_unref(sink0_);
> +			if (libcameraSrc_)
> +				gst_object_unref(libcameraSrc_);
> +			gst_deinit();
> +
> +			return TestFail;
> +		}
> +
> +		return TestPass;
> +	}
> +
> +	void cleanup() override
> +	{
> +		gst_object_unref(pipeline_);
> +		gst_deinit();
> +	}
> +
> +	int run() override
> +	{
> +		GstStateChangeReturn ret;
> +		g_autoptr(GstBus) bus;
> +		g_autoptr(GstMessage) msg;
> +
> +		/* Build the pipeline */
> +		gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL);
> +		if (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) {
> +			g_printerr("Elements could not be linked.\n");
> +			return TestFail;
> +		}
> +
> +		/* Start playing */
> +		ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> +		if (ret == GST_STATE_CHANGE_FAILURE) {
> +			g_printerr("Unable to set the pipeline to the playing state.\n");
> +			return TestFail;
> +		}
> +
> +		/* Wait until error or EOS or timeout after 2 seconds */
> +		GstClockTime timeout = 2000000000;
> +		bus = gst_element_get_bus(pipeline_);
> +		msg = gst_bus_timed_pop_filtered(bus, timeout,
> +						 GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> +		gst_element_set_state(pipeline_, GST_STATE_NULL);
> +
> +		/* Parse error message */
> +		if (msg == NULL)
> +			return TestPass;
> +
> +		switch (GST_MESSAGE_TYPE(msg)) {
> +		case GST_MESSAGE_ERROR:
> +			gstreamer_print_error(msg);
> +			break;
> +		case GST_MESSAGE_EOS:
> +			g_print("End-Of-Stream reached.\n");
> +			break;
> +		default:
> +			g_printerr("Unexpected message received.\n");
> +			break;
> +		}
> +
> +		return TestFail;
> +	}
> +
> +private:
> +	void gstreamer_print_error(GstMessage *msg)
> +	{
> +		GError *err;
> +		gchar *debug_info;
> +
> +		gst_message_parse_error(msg, &err, &debug_info);
> +		g_printerr("Error received from element %s: %s\n",
> +			   GST_OBJECT_NAME(msg->src), err->message);
> +		g_printerr("Debugging information: %s\n",
> +			   debug_info ? debug_info : "none");
> +		g_clear_error(&err);
> +		g_free(debug_info);
> +	}
> +
> +	GstElement *pipeline_;
> +	GstElement *libcameraSrc_;
> +	GstElement *convert0_;
> +	GstElement *sink0_;
> +};
> +
> +TEST_REGISTER(GstreamerSingleStreamTest)
> diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> new file mode 100644
> index 00000000..b99aa0da
> --- /dev/null
> +++ b/test/gstreamer/meson.build
> @@ -0,0 +1,19 @@
> +# SPDX-License-Identifier: CC0-1.0
> +
> +if not gst_enabled
> +    subdir_done()
> +endif
> +
> +gstreamer_tests = [
> +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> +]
> +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> +
> +foreach t : gstreamer_tests
> +    exe = executable(t[0], t[1],
> +                     dependencies : [libcamera_private, gstreamer_dep],
> +                     link_with : test_libraries,
> +                     include_directories : test_includes_internal)
> +
> +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> +endforeach
> diff --git a/test/meson.build b/test/meson.build
> index 3bceb5df..d0466f17 100644
> --- a/test/meson.build
> +++ b/test/meson.build
> @@ -11,6 +11,7 @@ subdir('libtest')
>  
>  subdir('camera')
>  subdir('controls')
> +subdir('gstreamer')
>  subdir('ipa')
>  subdir('ipc')
>  subdir('log')
Vedant Paranjape Aug. 13, 2021, 1:11 p.m. UTC | #2
Thanks

On Fri, 13 Aug, 2021, 18:27 Laurent Pinchart, <
laurent.pinchart@ideasonboard.com> wrote:

> Hi Vedant,
>
> Thank you for the patch.
>
> On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > This patch adds a test to test if single stream using
> > libcamera's gstreamer element works.
> >
> > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > ---
> >  .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
> >  test/gstreamer/meson.build                    |  19 +++
> >  test/meson.build                              |   1 +
> >  3 files changed, 173 insertions(+)
> >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
> >  create mode 100644 test/gstreamer/meson.build
> >
> > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp
> b/test/gstreamer/gstreamer_single_stream_test.cpp
> > new file mode 100644
> > index 00000000..eecd3274
> > --- /dev/null
> > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > @@ -0,0 +1,153 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + * Copyright (C) 2021, Vedant Paranjape
> > + *
> > + * ipa_interface_test.cpp - Test the IPA interface
> > + */
> > +
> > +#include <iostream>
> > +
> > +#include <libcamera/base/utils.h>
> > +
> > +#include <gst/gst.h>
> > +
> > +#include "test.h"
> > +
> > +using namespace std;
> > +
> > +class GstreamerSingleStreamTest : public Test
> > +{
> > +protected:
> > +     int init() override
> > +     {
> > +             /* Initialize GStreamer */
> > +             GError *errInit = nullptr;
> > +             if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > +                     g_printerr("Could not initialize GStreamer: %s\n",
> > +                                errInit ? errInit->message : "unknown
> error");
> > +                     if (errInit)
> > +                             g_error_free(errInit);
> > +
> > +                     return TestFail;
> > +             }
> > +
> > +             /*
> > +             * Remove the system libcamera plugin, if any, and add the
> > +             * plugin from the build directory.
> > +             */
>
> Missing space before *
>
> > +             GstRegistry *registry = gst_registry_get();
> > +             GstPlugin *plugin = gst_registry_lookup(registry,
> "libgstlibcamera.so");
> > +             if (plugin) {
> > +                     gst_registry_remove_plugin(registry, plugin);
> > +                     gst_object_unref(plugin);
> > +             }
> > +
>
> Extra blank spaces at the end of the line.
>
> > +             std::string path =
> std::string(libcamera::utils::libcameraBuildPath()
> > +                                     + "src/gstreamer");
>
> No need for calling the std::string constructor explictly,
> libcamera::utils::libcameraBuildPath() returns an std::string and the
> result of the operator+() call is also an std::string.
>
> You should #include "libcamera/internal/source_paths.h"" for
> libcamera::utils::libcameraBuildPath().
>

I thought, It's "internal" so shouldn't be used in a public library. :D

I'll fix these small issues when applying.
>
> > +             if (!gst_registry_scan_path(registry, path.c_str())) {
> > +                     g_printerr("Failed to add plugin to registry\n");
> > +                     gst_deinit();
> > +                     return TestFail;
> > +             }
> > +
> > +             /* Create the elements */
> > +             libcameraSrc_ = gst_element_factory_make("libcamerasrc",
> "libcamera");
> > +             convert0_ = gst_element_factory_make("videoconvert",
> "convert0");
> > +             sink0_ = gst_element_factory_make("fakesink", "sink0");
> > +
> > +             /* Create the empty pipeline_ */
> > +             pipeline_ = gst_pipeline_new("test-pipeline");
> > +
> > +             if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_)
> {
> > +                     g_printerr("Not all elements could be created.
> %p.%p.%p.%p\n",
> > +                                pipeline_, convert0_, sink0_,
> libcameraSrc_);
> > +                     if (pipeline_)
> > +                             gst_object_unref(pipeline_);
> > +                     if (convert0_)
> > +                             gst_object_unref(convert0_);
> > +                     if (sink0_)
> > +                             gst_object_unref(sink0_);
> > +                     if (libcameraSrc_)
> > +                             gst_object_unref(libcameraSrc_);
> > +                     gst_deinit();
> > +
> > +                     return TestFail;
> > +             }
> > +
> > +             return TestPass;
> > +     }
> > +
> > +     void cleanup() override
> > +     {
> > +             gst_object_unref(pipeline_);
> > +             gst_deinit();
> > +     }
> > +
> > +     int run() override
> > +     {
> > +             GstStateChangeReturn ret;
> > +             g_autoptr(GstBus) bus;
> > +             g_autoptr(GstMessage) msg;
> > +
> > +             /* Build the pipeline */
> > +             gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
> convert0_, sink0_, NULL);
> > +             if (gst_element_link_many(libcameraSrc_, convert0_,
> sink0_, NULL) != TRUE) {
> > +                     g_printerr("Elements could not be linked.\n");
> > +                     return TestFail;
> > +             }
> > +
> > +             /* Start playing */
> > +             ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> > +             if (ret == GST_STATE_CHANGE_FAILURE) {
> > +                     g_printerr("Unable to set the pipeline to the
> playing state.\n");
> > +                     return TestFail;
> > +             }
> > +
> > +             /* Wait until error or EOS or timeout after 2 seconds */
> > +             GstClockTime timeout = 2000000000;
> > +             bus = gst_element_get_bus(pipeline_);
> > +             msg = gst_bus_timed_pop_filtered(bus, timeout,
> > +
> GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > +             gst_element_set_state(pipeline_, GST_STATE_NULL);
> > +
> > +             /* Parse error message */
> > +             if (msg == NULL)
> > +                     return TestPass;
> > +
> > +             switch (GST_MESSAGE_TYPE(msg)) {
> > +             case GST_MESSAGE_ERROR:
> > +                     gstreamer_print_error(msg);
> > +                     break;
> > +             case GST_MESSAGE_EOS:
> > +                     g_print("End-Of-Stream reached.\n");
> > +                     break;
> > +             default:
> > +                     g_printerr("Unexpected message received.\n");
> > +                     break;
> > +             }
> > +
> > +             return TestFail;
> > +     }
> > +
> > +private:
> > +     void gstreamer_print_error(GstMessage *msg)
> > +     {
> > +             GError *err;
> > +             gchar *debug_info;
> > +
> > +             gst_message_parse_error(msg, &err, &debug_info);
> > +             g_printerr("Error received from element %s: %s\n",
> > +                        GST_OBJECT_NAME(msg->src), err->message);
> > +             g_printerr("Debugging information: %s\n",
> > +                        debug_info ? debug_info : "none");
> > +             g_clear_error(&err);
> > +             g_free(debug_info);
> > +     }
> > +
> > +     GstElement *pipeline_;
> > +     GstElement *libcameraSrc_;
> > +     GstElement *convert0_;
> > +     GstElement *sink0_;
> > +};
> > +
> > +TEST_REGISTER(GstreamerSingleStreamTest)
> > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > new file mode 100644
> > index 00000000..b99aa0da
> > --- /dev/null
> > +++ b/test/gstreamer/meson.build
> > @@ -0,0 +1,19 @@
> > +# SPDX-License-Identifier: CC0-1.0
> > +
> > +if not gst_enabled
> > +    subdir_done()
> > +endif
> > +
> > +gstreamer_tests = [
> > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> > +]
> > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > +
> > +foreach t : gstreamer_tests
> > +    exe = executable(t[0], t[1],
> > +                     dependencies : [libcamera_private, gstreamer_dep],
> > +                     link_with : test_libraries,
> > +                     include_directories : test_includes_internal)
> > +
> > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > +endforeach
> > diff --git a/test/meson.build b/test/meson.build
> > index 3bceb5df..d0466f17 100644
> > --- a/test/meson.build
> > +++ b/test/meson.build
> > @@ -11,6 +11,7 @@ subdir('libtest')
> >
> >  subdir('camera')
> >  subdir('controls')
> > +subdir('gstreamer')
> >  subdir('ipa')
> >  subdir('ipc')
> >  subdir('log')
>
> --
> Regards,
>
> Laurent Pinchart



Regards

Vedant Paranjape
Kieran Bingham Aug. 13, 2021, 1:13 p.m. UTC | #3
Hi Vedant,

On 13/08/2021 11:43, Vedant Paranjape wrote:
> This patch adds a test to test if single stream using
> libcamera's gstreamer element works.
> 
> Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>


This works on my machine now, thanks.

Tested-by: Kieran Bingham <kieran.bingham@@ideasonboard.com>

> ---
>  .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
>  test/gstreamer/meson.build                    |  19 +++
>  test/meson.build                              |   1 +
>  3 files changed, 173 insertions(+)
>  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
>  create mode 100644 test/gstreamer/meson.build
> 
> diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp
> new file mode 100644
> index 00000000..eecd3274
> --- /dev/null
> +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> @@ -0,0 +1,153 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2021, Vedant Paranjape
> + *
> + * ipa_interface_test.cpp - Test the IPA interface
> + */
> +
> +#include <iostream>
> +
> +#include <libcamera/base/utils.h>
> +
> +#include <gst/gst.h>
> +
> +#include "test.h"
> +
> +using namespace std;
> +
> +class GstreamerSingleStreamTest : public Test
> +{
> +protected:
> +	int init() override
> +	{
> +		/* Initialize GStreamer */
> +		GError *errInit = nullptr;
> +		if (!gst_init_check(nullptr, nullptr, &errInit)) {
> +			g_printerr("Could not initialize GStreamer: %s\n",
> +				   errInit ? errInit->message : "unknown error");
> +			if (errInit)
> +				g_error_free(errInit);
> +
> +			return TestFail;
> +		}
> +
> +		/*
> +		* Remove the system libcamera plugin, if any, and add the
> +		* plugin from the build directory.
> +		*/
> +		GstRegistry *registry = gst_registry_get();
> +		GstPlugin *plugin = gst_registry_lookup(registry, "libgstlibcamera.so");
> +		if (plugin) {
> +			gst_registry_remove_plugin(registry, plugin);
> +			gst_object_unref(plugin);
> +		}
> +		
> +		std::string path = std::string(libcamera::utils::libcameraBuildPath()
> +					+ "src/gstreamer");
> +		if (!gst_registry_scan_path(registry, path.c_str())) {
> +			g_printerr("Failed to add plugin to registry\n");
> +			gst_deinit();
> +			return TestFail;
> +		}
> +
> +		/* Create the elements */
> +		libcameraSrc_ = gst_element_factory_make("libcamerasrc", "libcamera");
> +		convert0_ = gst_element_factory_make("videoconvert", "convert0");
> +		sink0_ = gst_element_factory_make("fakesink", "sink0");
> +
> +		/* Create the empty pipeline_ */
> +		pipeline_ = gst_pipeline_new("test-pipeline");
> +
> +		if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) {
> +			g_printerr("Not all elements could be created. %p.%p.%p.%p\n",
> +				   pipeline_, convert0_, sink0_, libcameraSrc_);
> +			if (pipeline_)
> +				gst_object_unref(pipeline_);
> +			if (convert0_)
> +				gst_object_unref(convert0_);
> +			if (sink0_)
> +				gst_object_unref(sink0_);
> +			if (libcameraSrc_)
> +				gst_object_unref(libcameraSrc_);
> +			gst_deinit();
> +
> +			return TestFail;
> +		}
> +
> +		return TestPass;
> +	}
> +
> +	void cleanup() override
> +	{
> +		gst_object_unref(pipeline_);
> +		gst_deinit();
> +	}
> +
> +	int run() override
> +	{
> +		GstStateChangeReturn ret;
> +		g_autoptr(GstBus) bus;
> +		g_autoptr(GstMessage) msg;
> +
> +		/* Build the pipeline */
> +		gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL);
> +		if (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) {
> +			g_printerr("Elements could not be linked.\n");
> +			return TestFail;
> +		}
> +
> +		/* Start playing */
> +		ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> +		if (ret == GST_STATE_CHANGE_FAILURE) {
> +			g_printerr("Unable to set the pipeline to the playing state.\n");
> +			return TestFail;
> +		}
> +
> +		/* Wait until error or EOS or timeout after 2 seconds */
> +		GstClockTime timeout = 2000000000;
> +		bus = gst_element_get_bus(pipeline_);
> +		msg = gst_bus_timed_pop_filtered(bus, timeout,
> +						 GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> +		gst_element_set_state(pipeline_, GST_STATE_NULL);
> +
> +		/* Parse error message */
> +		if (msg == NULL)
> +			return TestPass;
> +
> +		switch (GST_MESSAGE_TYPE(msg)) {
> +		case GST_MESSAGE_ERROR:
> +			gstreamer_print_error(msg);
> +			break;
> +		case GST_MESSAGE_EOS:
> +			g_print("End-Of-Stream reached.\n");
> +			break;
> +		default:
> +			g_printerr("Unexpected message received.\n");
> +			break;
> +		}
> +
> +		return TestFail;
> +	}
> +
> +private:
> +	void gstreamer_print_error(GstMessage *msg)
> +	{
> +		GError *err;
> +		gchar *debug_info;
> +
> +		gst_message_parse_error(msg, &err, &debug_info);
> +		g_printerr("Error received from element %s: %s\n",
> +			   GST_OBJECT_NAME(msg->src), err->message);
> +		g_printerr("Debugging information: %s\n",
> +			   debug_info ? debug_info : "none");
> +		g_clear_error(&err);
> +		g_free(debug_info);
> +	}
> +
> +	GstElement *pipeline_;
> +	GstElement *libcameraSrc_;
> +	GstElement *convert0_;
> +	GstElement *sink0_;
> +};
> +
> +TEST_REGISTER(GstreamerSingleStreamTest)
> diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> new file mode 100644
> index 00000000..b99aa0da
> --- /dev/null
> +++ b/test/gstreamer/meson.build
> @@ -0,0 +1,19 @@
> +# SPDX-License-Identifier: CC0-1.0
> +
> +if not gst_enabled
> +    subdir_done()
> +endif
> +
> +gstreamer_tests = [
> +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> +]
> +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> +
> +foreach t : gstreamer_tests
> +    exe = executable(t[0], t[1],
> +                     dependencies : [libcamera_private, gstreamer_dep],
> +                     link_with : test_libraries,
> +                     include_directories : test_includes_internal)
> +
> +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> +endforeach
> diff --git a/test/meson.build b/test/meson.build
> index 3bceb5df..d0466f17 100644
> --- a/test/meson.build
> +++ b/test/meson.build
> @@ -11,6 +11,7 @@ subdir('libtest')
>  
>  subdir('camera')
>  subdir('controls')
> +subdir('gstreamer')
>  subdir('ipa')
>  subdir('ipc')
>  subdir('log')
>
Laurent Pinchart Aug. 13, 2021, 2:04 p.m. UTC | #4
On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> Hi Vedant,
> 
> Thank you for the patch.
> 
> On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > This patch adds a test to test if single stream using
> > libcamera's gstreamer element works.
> > 
> > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > ---
> >  .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
> >  test/gstreamer/meson.build                    |  19 +++
> >  test/meson.build                              |   1 +
> >  3 files changed, 173 insertions(+)
> >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
> >  create mode 100644 test/gstreamer/meson.build
> > 
> > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp
> > new file mode 100644
> > index 00000000..eecd3274
> > --- /dev/null
> > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > @@ -0,0 +1,153 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + * Copyright (C) 2021, Vedant Paranjape
> > + *
> > + * ipa_interface_test.cpp - Test the IPA interface
> > + */
> > +
> > +#include <iostream>
> > +
> > +#include <libcamera/base/utils.h>
> > +
> > +#include <gst/gst.h>
> > +
> > +#include "test.h"
> > +
> > +using namespace std;
> > +
> > +class GstreamerSingleStreamTest : public Test
> > +{
> > +protected:
> > +	int init() override
> > +	{
> > +		/* Initialize GStreamer */
> > +		GError *errInit = nullptr;
> > +		if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > +			g_printerr("Could not initialize GStreamer: %s\n",
> > +				   errInit ? errInit->message : "unknown error");
> > +			if (errInit)
> > +				g_error_free(errInit);
> > +
> > +			return TestFail;
> > +		}
> > +
> > +		/*
> > +		* Remove the system libcamera plugin, if any, and add the
> > +		* plugin from the build directory.
> > +		*/
> 
> Missing space before *
> 
> > +		GstRegistry *registry = gst_registry_get();
> > +		GstPlugin *plugin = gst_registry_lookup(registry, "libgstlibcamera.so");
> > +		if (plugin) {
> > +			gst_registry_remove_plugin(registry, plugin);
> > +			gst_object_unref(plugin);
> > +		}
> > +		
> 
> Extra blank spaces at the end of the line.
> 
> > +		std::string path = std::string(libcamera::utils::libcameraBuildPath()
> > +					+ "src/gstreamer");
> 
> No need for calling the std::string constructor explictly,
> libcamera::utils::libcameraBuildPath() returns an std::string and the
> result of the operator+() call is also an std::string.
> 
> You should #include "libcamera/internal/source_paths.h"" for
> libcamera::utils::libcameraBuildPath().
> 
> I'll fix these small issues when applying.
> 
> > +		if (!gst_registry_scan_path(registry, path.c_str())) {
> > +			g_printerr("Failed to add plugin to registry\n");
> > +			gst_deinit();
> > +			return TestFail;
> > +		}
> > +
> > +		/* Create the elements */
> > +		libcameraSrc_ = gst_element_factory_make("libcamerasrc", "libcamera");
> > +		convert0_ = gst_element_factory_make("videoconvert", "convert0");
> > +		sink0_ = gst_element_factory_make("fakesink", "sink0");
> > +
> > +		/* Create the empty pipeline_ */
> > +		pipeline_ = gst_pipeline_new("test-pipeline");
> > +
> > +		if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) {
> > +			g_printerr("Not all elements could be created. %p.%p.%p.%p\n",
> > +				   pipeline_, convert0_, sink0_, libcameraSrc_);
> > +			if (pipeline_)
> > +				gst_object_unref(pipeline_);
> > +			if (convert0_)
> > +				gst_object_unref(convert0_);
> > +			if (sink0_)
> > +				gst_object_unref(sink0_);
> > +			if (libcameraSrc_)
> > +				gst_object_unref(libcameraSrc_);
> > +			gst_deinit();
> > +
> > +			return TestFail;
> > +		}
> > +
> > +		return TestPass;
> > +	}
> > +
> > +	void cleanup() override
> > +	{
> > +		gst_object_unref(pipeline_);
> > +		gst_deinit();
> > +	}
> > +
> > +	int run() override
> > +	{
> > +		GstStateChangeReturn ret;
> > +		g_autoptr(GstBus) bus;
> > +		g_autoptr(GstMessage) msg;

I've also had to initialize those two variables to nullptr, to fix

In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:32,
                 from /usr/include/glib-2.0/glib/galloca.h:32,
                 from /usr/include/glib-2.0/glib.h:30,
                 from /usr/include/gstreamer-1.0/gst/gst.h:27,
                 from ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
/usr/include/glib-2.0/glib/gmacros.h: In member function ‘virtual int GstreamerSingleStreamTest::run()’:
/usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
 1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }                                                              \
      |       ^~
../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25: note: ‘msg’ was declared here
  108 |   g_autoptr(GstMessage) msg;
      |                         ^~~

when cross-compiling for ARM.

> > +
> > +		/* Build the pipeline */
> > +		gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL);
> > +		if (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) {
> > +			g_printerr("Elements could not be linked.\n");
> > +			return TestFail;
> > +		}
> > +
> > +		/* Start playing */
> > +		ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> > +		if (ret == GST_STATE_CHANGE_FAILURE) {
> > +			g_printerr("Unable to set the pipeline to the playing state.\n");
> > +			return TestFail;
> > +		}
> > +
> > +		/* Wait until error or EOS or timeout after 2 seconds */
> > +		GstClockTime timeout = 2000000000;
> > +		bus = gst_element_get_bus(pipeline_);
> > +		msg = gst_bus_timed_pop_filtered(bus, timeout,
> > +						 GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > +		gst_element_set_state(pipeline_, GST_STATE_NULL);
> > +
> > +		/* Parse error message */
> > +		if (msg == NULL)
> > +			return TestPass;
> > +
> > +		switch (GST_MESSAGE_TYPE(msg)) {
> > +		case GST_MESSAGE_ERROR:
> > +			gstreamer_print_error(msg);
> > +			break;
> > +		case GST_MESSAGE_EOS:
> > +			g_print("End-Of-Stream reached.\n");
> > +			break;
> > +		default:
> > +			g_printerr("Unexpected message received.\n");
> > +			break;
> > +		}
> > +
> > +		return TestFail;
> > +	}
> > +
> > +private:
> > +	void gstreamer_print_error(GstMessage *msg)
> > +	{
> > +		GError *err;
> > +		gchar *debug_info;
> > +
> > +		gst_message_parse_error(msg, &err, &debug_info);
> > +		g_printerr("Error received from element %s: %s\n",
> > +			   GST_OBJECT_NAME(msg->src), err->message);
> > +		g_printerr("Debugging information: %s\n",
> > +			   debug_info ? debug_info : "none");
> > +		g_clear_error(&err);
> > +		g_free(debug_info);
> > +	}
> > +
> > +	GstElement *pipeline_;
> > +	GstElement *libcameraSrc_;
> > +	GstElement *convert0_;
> > +	GstElement *sink0_;
> > +};
> > +
> > +TEST_REGISTER(GstreamerSingleStreamTest)
> > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > new file mode 100644
> > index 00000000..b99aa0da
> > --- /dev/null
> > +++ b/test/gstreamer/meson.build
> > @@ -0,0 +1,19 @@
> > +# SPDX-License-Identifier: CC0-1.0
> > +
> > +if not gst_enabled
> > +    subdir_done()
> > +endif
> > +
> > +gstreamer_tests = [
> > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> > +]
> > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > +
> > +foreach t : gstreamer_tests
> > +    exe = executable(t[0], t[1],
> > +                     dependencies : [libcamera_private, gstreamer_dep],
> > +                     link_with : test_libraries,
> > +                     include_directories : test_includes_internal)
> > +
> > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > +endforeach
> > diff --git a/test/meson.build b/test/meson.build
> > index 3bceb5df..d0466f17 100644
> > --- a/test/meson.build
> > +++ b/test/meson.build
> > @@ -11,6 +11,7 @@ subdir('libtest')
> >  
> >  subdir('camera')
> >  subdir('controls')
> > +subdir('gstreamer')
> >  subdir('ipa')
> >  subdir('ipc')
> >  subdir('log')
Vedant Paranjape Aug. 13, 2021, 2:11 p.m. UTC | #5
Hi Laurent,
I'm just curious, what might be the reason that this error gets triggered
only on ARM and not on x86.

Regards,
*Vedant Paranjape*

On Fri, Aug 13, 2021 at 7:34 PM Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> > Hi Vedant,
> >
> > Thank you for the patch.
> >
> > On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > > This patch adds a test to test if single stream using
> > > libcamera's gstreamer element works.
> > >
> > > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > ---
> > >  .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
> > >  test/gstreamer/meson.build                    |  19 +++
> > >  test/meson.build                              |   1 +
> > >  3 files changed, 173 insertions(+)
> > >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
> > >  create mode 100644 test/gstreamer/meson.build
> > >
> > > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp
> b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > new file mode 100644
> > > index 00000000..eecd3274
> > > --- /dev/null
> > > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > @@ -0,0 +1,153 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > +/*
> > > + * Copyright (C) 2021, Vedant Paranjape
> > > + *
> > > + * ipa_interface_test.cpp - Test the IPA interface
> > > + */
> > > +
> > > +#include <iostream>
> > > +
> > > +#include <libcamera/base/utils.h>
> > > +
> > > +#include <gst/gst.h>
> > > +
> > > +#include "test.h"
> > > +
> > > +using namespace std;
> > > +
> > > +class GstreamerSingleStreamTest : public Test
> > > +{
> > > +protected:
> > > +   int init() override
> > > +   {
> > > +           /* Initialize GStreamer */
> > > +           GError *errInit = nullptr;
> > > +           if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > > +                   g_printerr("Could not initialize GStreamer: %s\n",
> > > +                              errInit ? errInit->message : "unknown
> error");
> > > +                   if (errInit)
> > > +                           g_error_free(errInit);
> > > +
> > > +                   return TestFail;
> > > +           }
> > > +
> > > +           /*
> > > +           * Remove the system libcamera plugin, if any, and add the
> > > +           * plugin from the build directory.
> > > +           */
> >
> > Missing space before *
> >
> > > +           GstRegistry *registry = gst_registry_get();
> > > +           GstPlugin *plugin = gst_registry_lookup(registry,
> "libgstlibcamera.so");
> > > +           if (plugin) {
> > > +                   gst_registry_remove_plugin(registry, plugin);
> > > +                   gst_object_unref(plugin);
> > > +           }
> > > +
> >
> > Extra blank spaces at the end of the line.
> >
> > > +           std::string path =
> std::string(libcamera::utils::libcameraBuildPath()
> > > +                                   + "src/gstreamer");
> >
> > No need for calling the std::string constructor explictly,
> > libcamera::utils::libcameraBuildPath() returns an std::string and the
> > result of the operator+() call is also an std::string.
> >
> > You should #include "libcamera/internal/source_paths.h"" for
> > libcamera::utils::libcameraBuildPath().
> >
> > I'll fix these small issues when applying.
> >
> > > +           if (!gst_registry_scan_path(registry, path.c_str())) {
> > > +                   g_printerr("Failed to add plugin to registry\n");
> > > +                   gst_deinit();
> > > +                   return TestFail;
> > > +           }
> > > +
> > > +           /* Create the elements */
> > > +           libcameraSrc_ = gst_element_factory_make("libcamerasrc",
> "libcamera");
> > > +           convert0_ = gst_element_factory_make("videoconvert",
> "convert0");
> > > +           sink0_ = gst_element_factory_make("fakesink", "sink0");
> > > +
> > > +           /* Create the empty pipeline_ */
> > > +           pipeline_ = gst_pipeline_new("test-pipeline");
> > > +
> > > +           if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_)
> {
> > > +                   g_printerr("Not all elements could be created.
> %p.%p.%p.%p\n",
> > > +                              pipeline_, convert0_, sink0_,
> libcameraSrc_);
> > > +                   if (pipeline_)
> > > +                           gst_object_unref(pipeline_);
> > > +                   if (convert0_)
> > > +                           gst_object_unref(convert0_);
> > > +                   if (sink0_)
> > > +                           gst_object_unref(sink0_);
> > > +                   if (libcameraSrc_)
> > > +                           gst_object_unref(libcameraSrc_);
> > > +                   gst_deinit();
> > > +
> > > +                   return TestFail;
> > > +           }
> > > +
> > > +           return TestPass;
> > > +   }
> > > +
> > > +   void cleanup() override
> > > +   {
> > > +           gst_object_unref(pipeline_);
> > > +           gst_deinit();
> > > +   }
> > > +
> > > +   int run() override
> > > +   {
> > > +           GstStateChangeReturn ret;
> > > +           g_autoptr(GstBus) bus;
> > > +           g_autoptr(GstMessage) msg;
>
> I've also had to initialize those two variables to nullptr, to fix
>
> In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
>                  from /usr/include/glib-2.0/glib/gtypes.h:32,
>                  from /usr/include/glib-2.0/glib/galloca.h:32,
>                  from /usr/include/glib-2.0/glib.h:30,
>                  from /usr/include/gstreamer-1.0/gst/gst.h:27,
>                  from
> ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
> /usr/include/glib-2.0/glib/gmacros.h: In member function ‘virtual int
> GstreamerSingleStreamTest::run()’:
> /usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be used
> uninitialized in this function [-Werror=maybe-uninitialized]
>  1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }
>                                               \
>       |       ^~
> ../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25: note: ‘msg’
> was declared here
>   108 |   g_autoptr(GstMessage) msg;
>       |                         ^~~
>
> when cross-compiling for ARM.
>
> > > +
> > > +           /* Build the pipeline */
> > > +           gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
> convert0_, sink0_, NULL);
> > > +           if (gst_element_link_many(libcameraSrc_, convert0_,
> sink0_, NULL) != TRUE) {
> > > +                   g_printerr("Elements could not be linked.\n");
> > > +                   return TestFail;
> > > +           }
> > > +
> > > +           /* Start playing */
> > > +           ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> > > +           if (ret == GST_STATE_CHANGE_FAILURE) {
> > > +                   g_printerr("Unable to set the pipeline to the
> playing state.\n");
> > > +                   return TestFail;
> > > +           }
> > > +
> > > +           /* Wait until error or EOS or timeout after 2 seconds */
> > > +           GstClockTime timeout = 2000000000;
> > > +           bus = gst_element_get_bus(pipeline_);
> > > +           msg = gst_bus_timed_pop_filtered(bus, timeout,
> > > +
> GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > > +           gst_element_set_state(pipeline_, GST_STATE_NULL);
> > > +
> > > +           /* Parse error message */
> > > +           if (msg == NULL)
> > > +                   return TestPass;
> > > +
> > > +           switch (GST_MESSAGE_TYPE(msg)) {
> > > +           case GST_MESSAGE_ERROR:
> > > +                   gstreamer_print_error(msg);
> > > +                   break;
> > > +           case GST_MESSAGE_EOS:
> > > +                   g_print("End-Of-Stream reached.\n");
> > > +                   break;
> > > +           default:
> > > +                   g_printerr("Unexpected message received.\n");
> > > +                   break;
> > > +           }
> > > +
> > > +           return TestFail;
> > > +   }
> > > +
> > > +private:
> > > +   void gstreamer_print_error(GstMessage *msg)
> > > +   {
> > > +           GError *err;
> > > +           gchar *debug_info;
> > > +
> > > +           gst_message_parse_error(msg, &err, &debug_info);
> > > +           g_printerr("Error received from element %s: %s\n",
> > > +                      GST_OBJECT_NAME(msg->src), err->message);
> > > +           g_printerr("Debugging information: %s\n",
> > > +                      debug_info ? debug_info : "none");
> > > +           g_clear_error(&err);
> > > +           g_free(debug_info);
> > > +   }
> > > +
> > > +   GstElement *pipeline_;
> > > +   GstElement *libcameraSrc_;
> > > +   GstElement *convert0_;
> > > +   GstElement *sink0_;
> > > +};
> > > +
> > > +TEST_REGISTER(GstreamerSingleStreamTest)
> > > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > > new file mode 100644
> > > index 00000000..b99aa0da
> > > --- /dev/null
> > > +++ b/test/gstreamer/meson.build
> > > @@ -0,0 +1,19 @@
> > > +# SPDX-License-Identifier: CC0-1.0
> > > +
> > > +if not gst_enabled
> > > +    subdir_done()
> > > +endif
> > > +
> > > +gstreamer_tests = [
> > > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> > > +]
> > > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > > +
> > > +foreach t : gstreamer_tests
> > > +    exe = executable(t[0], t[1],
> > > +                     dependencies : [libcamera_private,
> gstreamer_dep],
> > > +                     link_with : test_libraries,
> > > +                     include_directories : test_includes_internal)
> > > +
> > > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > > +endforeach
> > > diff --git a/test/meson.build b/test/meson.build
> > > index 3bceb5df..d0466f17 100644
> > > --- a/test/meson.build
> > > +++ b/test/meson.build
> > > @@ -11,6 +11,7 @@ subdir('libtest')
> > >
> > >  subdir('camera')
> > >  subdir('controls')
> > > +subdir('gstreamer')
> > >  subdir('ipa')
> > >  subdir('ipc')
> > >  subdir('log')
>
> --
> Regards,
>
> Laurent Pinchart
>
Laurent Pinchart Aug. 13, 2021, 2:37 p.m. UTC | #6
On Fri, Aug 13, 2021 at 05:04:01PM +0300, Laurent Pinchart wrote:
> On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> > Hi Vedant,
> > 
> > Thank you for the patch.
> > 
> > On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > > This patch adds a test to test if single stream using
> > > libcamera's gstreamer element works.
> > > 
> > > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > ---
> > >  .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
> > >  test/gstreamer/meson.build                    |  19 +++
> > >  test/meson.build                              |   1 +
> > >  3 files changed, 173 insertions(+)
> > >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
> > >  create mode 100644 test/gstreamer/meson.build
> > > 
> > > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > new file mode 100644
> > > index 00000000..eecd3274
> > > --- /dev/null
> > > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > @@ -0,0 +1,153 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > +/*
> > > + * Copyright (C) 2021, Vedant Paranjape
> > > + *
> > > + * ipa_interface_test.cpp - Test the IPA interface
> > > + */
> > > +
> > > +#include <iostream>
> > > +
> > > +#include <libcamera/base/utils.h>
> > > +
> > > +#include <gst/gst.h>
> > > +
> > > +#include "test.h"
> > > +
> > > +using namespace std;
> > > +
> > > +class GstreamerSingleStreamTest : public Test
> > > +{
> > > +protected:
> > > +	int init() override
> > > +	{
> > > +		/* Initialize GStreamer */
> > > +		GError *errInit = nullptr;
> > > +		if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > > +			g_printerr("Could not initialize GStreamer: %s\n",
> > > +				   errInit ? errInit->message : "unknown error");
> > > +			if (errInit)
> > > +				g_error_free(errInit);
> > > +
> > > +			return TestFail;
> > > +		}
> > > +
> > > +		/*
> > > +		* Remove the system libcamera plugin, if any, and add the
> > > +		* plugin from the build directory.
> > > +		*/
> > 
> > Missing space before *
> > 
> > > +		GstRegistry *registry = gst_registry_get();
> > > +		GstPlugin *plugin = gst_registry_lookup(registry, "libgstlibcamera.so");
> > > +		if (plugin) {
> > > +			gst_registry_remove_plugin(registry, plugin);
> > > +			gst_object_unref(plugin);
> > > +		}
> > > +		
> > 
> > Extra blank spaces at the end of the line.
> > 
> > > +		std::string path = std::string(libcamera::utils::libcameraBuildPath()
> > > +					+ "src/gstreamer");
> > 
> > No need for calling the std::string constructor explictly,
> > libcamera::utils::libcameraBuildPath() returns an std::string and the
> > result of the operator+() call is also an std::string.
> > 
> > You should #include "libcamera/internal/source_paths.h"" for
> > libcamera::utils::libcameraBuildPath().
> > 
> > I'll fix these small issues when applying.
> > 
> > > +		if (!gst_registry_scan_path(registry, path.c_str())) {
> > > +			g_printerr("Failed to add plugin to registry\n");
> > > +			gst_deinit();
> > > +			return TestFail;
> > > +		}
> > > +
> > > +		/* Create the elements */
> > > +		libcameraSrc_ = gst_element_factory_make("libcamerasrc", "libcamera");

And now I'm getting a failure here :-( When compiling with gcc, and with
the meson b_sanitize option set to 'address', this call returns null.

10/64 libcamera:gstreamer / single_stream_test                           FAIL            0.48s   exit status 1
>>> MALLOC_PERTURB_=101 build/x86-gcc-11.1.0/test/gstreamer/single_stream_test
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ✀  ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
stderr:
==14992==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
==14993==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
Not all elements could be created. 0x6290000241f0.0x61a000019950.0x61a00001a670.(nil)

=================================================================
==14990==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16384 byte(s) in 1 object(s) allocated from:
    #0 0x7f9daade1ac7 in __interceptor_malloc /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x7f9da776a938 in g_malloc ../glib-2.68.3/glib/gmem.c:106

SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

11/64 libcamera:ipa / ipa_module_test                                    OK              0.08s

Interestingly, if I run the test with

LD_PRELOAD=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/libasan.so.6 ./test/gstreamer/single_stream_test

then is runs fine:

[25:59:46.412146534] [18711]  INFO IPAManager ipa_manager.cpp:138 libcamera is not installed. Adding '[...]/build/x86-gcc-11.1.0/src/ipa' to the IPA search path
[25:59:46.413634330] [18711]  INFO Camera camera_manager.cpp:294 libcamera v0.0.0+2881-24c1e91b-dirty (2021-08-13T17:24:37+03:00)
[25:59:46.663097368] [18714]  WARN CameraSensorProperties camera_sensor_properties.cpp:123 No static properties available for 'Sensor B'
[25:59:46.663129122] [18714]  WARN CameraSensorProperties camera_sensor_properties.cpp:125 Please consider updating the camera sensor properties database
[25:59:46.663156409] [18714]  WARN CameraSensor camera_sensor.cpp:403 'Sensor B': Failed to retrieve the camera location
[25:59:46.664891182] [18714]  INFO IPAProxy ipa_proxy.cpp:130 libcamera is not installed. Loading IPA configuration from '[...]/src/ipa/vimc/data'
[25:59:46.680563655] [18715]  INFO Camera camera.cpp:870 configuring streams: (0) 160x120-YUYV

=================================================================
==18711==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16384 byte(s) in 1 object(s) allocated from:
    #0 0x7effa6393ac7 in __interceptor_malloc /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x7effa57be938 in g_malloc ../glib-2.68.3/glib/gmem.c:106

SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).

The leak is a known glib issue, caught by valgrind too, so I'm not
worried about it. The test failing to run is however a blocker.

Vedant, can you reproduce the failure with the address sanitizer ?

> > > +		convert0_ = gst_element_factory_make("videoconvert", "convert0");
> > > +		sink0_ = gst_element_factory_make("fakesink", "sink0");
> > > +
> > > +		/* Create the empty pipeline_ */
> > > +		pipeline_ = gst_pipeline_new("test-pipeline");
> > > +
> > > +		if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) {
> > > +			g_printerr("Not all elements could be created. %p.%p.%p.%p\n",
> > > +				   pipeline_, convert0_, sink0_, libcameraSrc_);
> > > +			if (pipeline_)
> > > +				gst_object_unref(pipeline_);
> > > +			if (convert0_)
> > > +				gst_object_unref(convert0_);
> > > +			if (sink0_)
> > > +				gst_object_unref(sink0_);
> > > +			if (libcameraSrc_)
> > > +				gst_object_unref(libcameraSrc_);
> > > +			gst_deinit();
> > > +
> > > +			return TestFail;
> > > +		}
> > > +
> > > +		return TestPass;
> > > +	}
> > > +
> > > +	void cleanup() override
> > > +	{
> > > +		gst_object_unref(pipeline_);
> > > +		gst_deinit();
> > > +	}
> > > +
> > > +	int run() override
> > > +	{
> > > +		GstStateChangeReturn ret;
> > > +		g_autoptr(GstBus) bus;
> > > +		g_autoptr(GstMessage) msg;
> 
> I've also had to initialize those two variables to nullptr, to fix
> 
> In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
>                  from /usr/include/glib-2.0/glib/gtypes.h:32,
>                  from /usr/include/glib-2.0/glib/galloca.h:32,
>                  from /usr/include/glib-2.0/glib.h:30,
>                  from /usr/include/gstreamer-1.0/gst/gst.h:27,
>                  from ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
> /usr/include/glib-2.0/glib/gmacros.h: In member function ‘virtual int GstreamerSingleStreamTest::run()’:
> /usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
>  1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }                                                              \
>       |       ^~
> ../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25: note: ‘msg’ was declared here
>   108 |   g_autoptr(GstMessage) msg;
>       |                         ^~~
> 
> when cross-compiling for ARM.
> 
> > > +
> > > +		/* Build the pipeline */
> > > +		gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL);
> > > +		if (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) {
> > > +			g_printerr("Elements could not be linked.\n");
> > > +			return TestFail;
> > > +		}
> > > +
> > > +		/* Start playing */
> > > +		ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> > > +		if (ret == GST_STATE_CHANGE_FAILURE) {
> > > +			g_printerr("Unable to set the pipeline to the playing state.\n");
> > > +			return TestFail;
> > > +		}
> > > +
> > > +		/* Wait until error or EOS or timeout after 2 seconds */
> > > +		GstClockTime timeout = 2000000000;
> > > +		bus = gst_element_get_bus(pipeline_);
> > > +		msg = gst_bus_timed_pop_filtered(bus, timeout,
> > > +						 GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > > +		gst_element_set_state(pipeline_, GST_STATE_NULL);
> > > +
> > > +		/* Parse error message */
> > > +		if (msg == NULL)
> > > +			return TestPass;
> > > +
> > > +		switch (GST_MESSAGE_TYPE(msg)) {
> > > +		case GST_MESSAGE_ERROR:
> > > +			gstreamer_print_error(msg);
> > > +			break;
> > > +		case GST_MESSAGE_EOS:
> > > +			g_print("End-Of-Stream reached.\n");
> > > +			break;
> > > +		default:
> > > +			g_printerr("Unexpected message received.\n");
> > > +			break;
> > > +		}
> > > +
> > > +		return TestFail;
> > > +	}
> > > +
> > > +private:
> > > +	void gstreamer_print_error(GstMessage *msg)
> > > +	{
> > > +		GError *err;
> > > +		gchar *debug_info;
> > > +
> > > +		gst_message_parse_error(msg, &err, &debug_info);
> > > +		g_printerr("Error received from element %s: %s\n",
> > > +			   GST_OBJECT_NAME(msg->src), err->message);
> > > +		g_printerr("Debugging information: %s\n",
> > > +			   debug_info ? debug_info : "none");
> > > +		g_clear_error(&err);
> > > +		g_free(debug_info);
> > > +	}
> > > +
> > > +	GstElement *pipeline_;
> > > +	GstElement *libcameraSrc_;
> > > +	GstElement *convert0_;
> > > +	GstElement *sink0_;
> > > +};
> > > +
> > > +TEST_REGISTER(GstreamerSingleStreamTest)
> > > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > > new file mode 100644
> > > index 00000000..b99aa0da
> > > --- /dev/null
> > > +++ b/test/gstreamer/meson.build
> > > @@ -0,0 +1,19 @@
> > > +# SPDX-License-Identifier: CC0-1.0
> > > +
> > > +if not gst_enabled
> > > +    subdir_done()
> > > +endif
> > > +
> > > +gstreamer_tests = [
> > > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> > > +]
> > > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > > +
> > > +foreach t : gstreamer_tests
> > > +    exe = executable(t[0], t[1],
> > > +                     dependencies : [libcamera_private, gstreamer_dep],
> > > +                     link_with : test_libraries,
> > > +                     include_directories : test_includes_internal)
> > > +
> > > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > > +endforeach
> > > diff --git a/test/meson.build b/test/meson.build
> > > index 3bceb5df..d0466f17 100644
> > > --- a/test/meson.build
> > > +++ b/test/meson.build
> > > @@ -11,6 +11,7 @@ subdir('libtest')
> > >  
> > >  subdir('camera')
> > >  subdir('controls')
> > > +subdir('gstreamer')
> > >  subdir('ipa')
> > >  subdir('ipc')
> > >  subdir('log')
Laurent Pinchart Aug. 13, 2021, 2:42 p.m. UTC | #7
On Fri, Aug 13, 2021 at 07:41:34PM +0530, Vedant Paranjape wrote:
> Hi Laurent,
> I'm just curious, what might be the reason that this error gets triggered
> only on ARM and not on x86.

I don't know, I haven't investigated. It may be that my ARM cross-build
environment uses a different glib version, not sure.

I'm actually a bit surprised that no other compiler warned about this,
it seems to be a legitimate issue.

> On Fri, Aug 13, 2021 at 7:34 PM Laurent Pinchart wrote:
> > On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> > > On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > > > This patch adds a test to test if single stream using
> > > > libcamera's gstreamer element works.
> > > >
> > > > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> > > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > ---
> > > >  .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
> > > >  test/gstreamer/meson.build                    |  19 +++
> > > >  test/meson.build                              |   1 +
> > > >  3 files changed, 173 insertions(+)
> > > >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
> > > >  create mode 100644 test/gstreamer/meson.build
> > > >
> > > > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp
> > b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > new file mode 100644
> > > > index 00000000..eecd3274
> > > > --- /dev/null
> > > > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > @@ -0,0 +1,153 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > > +/*
> > > > + * Copyright (C) 2021, Vedant Paranjape
> > > > + *
> > > > + * ipa_interface_test.cpp - Test the IPA interface
> > > > + */
> > > > +
> > > > +#include <iostream>
> > > > +
> > > > +#include <libcamera/base/utils.h>
> > > > +
> > > > +#include <gst/gst.h>
> > > > +
> > > > +#include "test.h"
> > > > +
> > > > +using namespace std;
> > > > +
> > > > +class GstreamerSingleStreamTest : public Test
> > > > +{
> > > > +protected:
> > > > +   int init() override
> > > > +   {
> > > > +           /* Initialize GStreamer */
> > > > +           GError *errInit = nullptr;
> > > > +           if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > > > +                   g_printerr("Could not initialize GStreamer: %s\n",
> > > > +                              errInit ? errInit->message : "unknown
> > error");
> > > > +                   if (errInit)
> > > > +                           g_error_free(errInit);
> > > > +
> > > > +                   return TestFail;
> > > > +           }
> > > > +
> > > > +           /*
> > > > +           * Remove the system libcamera plugin, if any, and add the
> > > > +           * plugin from the build directory.
> > > > +           */
> > >
> > > Missing space before *
> > >
> > > > +           GstRegistry *registry = gst_registry_get();
> > > > +           GstPlugin *plugin = gst_registry_lookup(registry,
> > "libgstlibcamera.so");
> > > > +           if (plugin) {
> > > > +                   gst_registry_remove_plugin(registry, plugin);
> > > > +                   gst_object_unref(plugin);
> > > > +           }
> > > > +
> > >
> > > Extra blank spaces at the end of the line.
> > >
> > > > +           std::string path =
> > std::string(libcamera::utils::libcameraBuildPath()
> > > > +                                   + "src/gstreamer");
> > >
> > > No need for calling the std::string constructor explictly,
> > > libcamera::utils::libcameraBuildPath() returns an std::string and the
> > > result of the operator+() call is also an std::string.
> > >
> > > You should #include "libcamera/internal/source_paths.h"" for
> > > libcamera::utils::libcameraBuildPath().
> > >
> > > I'll fix these small issues when applying.
> > >
> > > > +           if (!gst_registry_scan_path(registry, path.c_str())) {
> > > > +                   g_printerr("Failed to add plugin to registry\n");
> > > > +                   gst_deinit();
> > > > +                   return TestFail;
> > > > +           }
> > > > +
> > > > +           /* Create the elements */
> > > > +           libcameraSrc_ = gst_element_factory_make("libcamerasrc",
> > "libcamera");
> > > > +           convert0_ = gst_element_factory_make("videoconvert",
> > "convert0");
> > > > +           sink0_ = gst_element_factory_make("fakesink", "sink0");
> > > > +
> > > > +           /* Create the empty pipeline_ */
> > > > +           pipeline_ = gst_pipeline_new("test-pipeline");
> > > > +
> > > > +           if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_)
> > {
> > > > +                   g_printerr("Not all elements could be created.
> > %p.%p.%p.%p\n",
> > > > +                              pipeline_, convert0_, sink0_,
> > libcameraSrc_);
> > > > +                   if (pipeline_)
> > > > +                           gst_object_unref(pipeline_);
> > > > +                   if (convert0_)
> > > > +                           gst_object_unref(convert0_);
> > > > +                   if (sink0_)
> > > > +                           gst_object_unref(sink0_);
> > > > +                   if (libcameraSrc_)
> > > > +                           gst_object_unref(libcameraSrc_);
> > > > +                   gst_deinit();
> > > > +
> > > > +                   return TestFail;
> > > > +           }
> > > > +
> > > > +           return TestPass;
> > > > +   }
> > > > +
> > > > +   void cleanup() override
> > > > +   {
> > > > +           gst_object_unref(pipeline_);
> > > > +           gst_deinit();
> > > > +   }
> > > > +
> > > > +   int run() override
> > > > +   {
> > > > +           GstStateChangeReturn ret;
> > > > +           g_autoptr(GstBus) bus;
> > > > +           g_autoptr(GstMessage) msg;
> >
> > I've also had to initialize those two variables to nullptr, to fix
> >
> > In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
> >                  from /usr/include/glib-2.0/glib/gtypes.h:32,
> >                  from /usr/include/glib-2.0/glib/galloca.h:32,
> >                  from /usr/include/glib-2.0/glib.h:30,
> >                  from /usr/include/gstreamer-1.0/gst/gst.h:27,
> >                  from
> > ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
> > /usr/include/glib-2.0/glib/gmacros.h: In member function ‘virtual int
> > GstreamerSingleStreamTest::run()’:
> > /usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be used
> > uninitialized in this function [-Werror=maybe-uninitialized]
> >  1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }
> >                                               \
> >       |       ^~
> > ../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25: note: ‘msg’
> > was declared here
> >   108 |   g_autoptr(GstMessage) msg;
> >       |                         ^~~
> >
> > when cross-compiling for ARM.
> >
> > > > +
> > > > +           /* Build the pipeline */
> > > > +           gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
> > convert0_, sink0_, NULL);
> > > > +           if (gst_element_link_many(libcameraSrc_, convert0_,
> > sink0_, NULL) != TRUE) {
> > > > +                   g_printerr("Elements could not be linked.\n");
> > > > +                   return TestFail;
> > > > +           }
> > > > +
> > > > +           /* Start playing */
> > > > +           ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> > > > +           if (ret == GST_STATE_CHANGE_FAILURE) {
> > > > +                   g_printerr("Unable to set the pipeline to the
> > playing state.\n");
> > > > +                   return TestFail;
> > > > +           }
> > > > +
> > > > +           /* Wait until error or EOS or timeout after 2 seconds */
> > > > +           GstClockTime timeout = 2000000000;
> > > > +           bus = gst_element_get_bus(pipeline_);
> > > > +           msg = gst_bus_timed_pop_filtered(bus, timeout,
> > > > +
> > GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > > > +           gst_element_set_state(pipeline_, GST_STATE_NULL);
> > > > +
> > > > +           /* Parse error message */
> > > > +           if (msg == NULL)
> > > > +                   return TestPass;
> > > > +
> > > > +           switch (GST_MESSAGE_TYPE(msg)) {
> > > > +           case GST_MESSAGE_ERROR:
> > > > +                   gstreamer_print_error(msg);
> > > > +                   break;
> > > > +           case GST_MESSAGE_EOS:
> > > > +                   g_print("End-Of-Stream reached.\n");
> > > > +                   break;
> > > > +           default:
> > > > +                   g_printerr("Unexpected message received.\n");
> > > > +                   break;
> > > > +           }
> > > > +
> > > > +           return TestFail;
> > > > +   }
> > > > +
> > > > +private:
> > > > +   void gstreamer_print_error(GstMessage *msg)
> > > > +   {
> > > > +           GError *err;
> > > > +           gchar *debug_info;
> > > > +
> > > > +           gst_message_parse_error(msg, &err, &debug_info);
> > > > +           g_printerr("Error received from element %s: %s\n",
> > > > +                      GST_OBJECT_NAME(msg->src), err->message);
> > > > +           g_printerr("Debugging information: %s\n",
> > > > +                      debug_info ? debug_info : "none");
> > > > +           g_clear_error(&err);
> > > > +           g_free(debug_info);
> > > > +   }
> > > > +
> > > > +   GstElement *pipeline_;
> > > > +   GstElement *libcameraSrc_;
> > > > +   GstElement *convert0_;
> > > > +   GstElement *sink0_;
> > > > +};
> > > > +
> > > > +TEST_REGISTER(GstreamerSingleStreamTest)
> > > > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > > > new file mode 100644
> > > > index 00000000..b99aa0da
> > > > --- /dev/null
> > > > +++ b/test/gstreamer/meson.build
> > > > @@ -0,0 +1,19 @@
> > > > +# SPDX-License-Identifier: CC0-1.0
> > > > +
> > > > +if not gst_enabled
> > > > +    subdir_done()
> > > > +endif
> > > > +
> > > > +gstreamer_tests = [
> > > > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> > > > +]
> > > > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > > > +
> > > > +foreach t : gstreamer_tests
> > > > +    exe = executable(t[0], t[1],
> > > > +                     dependencies : [libcamera_private,
> > gstreamer_dep],
> > > > +                     link_with : test_libraries,
> > > > +                     include_directories : test_includes_internal)
> > > > +
> > > > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > > > +endforeach
> > > > diff --git a/test/meson.build b/test/meson.build
> > > > index 3bceb5df..d0466f17 100644
> > > > --- a/test/meson.build
> > > > +++ b/test/meson.build
> > > > @@ -11,6 +11,7 @@ subdir('libtest')
> > > >
> > > >  subdir('camera')
> > > >  subdir('controls')
> > > > +subdir('gstreamer')
> > > >  subdir('ipa')
> > > >  subdir('ipc')
> > > >  subdir('log')
Vedant Paranjape Aug. 13, 2021, 4:44 p.m. UTC | #8
Hi Laurent,
I was unable to reproduce the issue with address sanitizer.

Steps I followed:
1) meson --reconfigure build -Db_sanitize=address
2) ninja -C build test

Regards,
Vedant

On Fri, Aug 13, 2021 at 8:07 PM Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> On Fri, Aug 13, 2021 at 05:04:01PM +0300, Laurent Pinchart wrote:
> > On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> > > Hi Vedant,
> > >
> > > Thank you for the patch.
> > >
> > > On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > > > This patch adds a test to test if single stream using
> > > > libcamera's gstreamer element works.
> > > >
> > > > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> > > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > ---
> > > >  .../gstreamer_single_stream_test.cpp          | 153
> ++++++++++++++++++
> > > >  test/gstreamer/meson.build                    |  19 +++
> > > >  test/meson.build                              |   1 +
> > > >  3 files changed, 173 insertions(+)
> > > >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
> > > >  create mode 100644 test/gstreamer/meson.build
> > > >
> > > > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp
> b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > new file mode 100644
> > > > index 00000000..eecd3274
> > > > --- /dev/null
> > > > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > @@ -0,0 +1,153 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > > +/*
> > > > + * Copyright (C) 2021, Vedant Paranjape
> > > > + *
> > > > + * ipa_interface_test.cpp - Test the IPA interface
> > > > + */
> > > > +
> > > > +#include <iostream>
> > > > +
> > > > +#include <libcamera/base/utils.h>
> > > > +
> > > > +#include <gst/gst.h>
> > > > +
> > > > +#include "test.h"
> > > > +
> > > > +using namespace std;
> > > > +
> > > > +class GstreamerSingleStreamTest : public Test
> > > > +{
> > > > +protected:
> > > > + int init() override
> > > > + {
> > > > +         /* Initialize GStreamer */
> > > > +         GError *errInit = nullptr;
> > > > +         if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > > > +                 g_printerr("Could not initialize GStreamer: %s\n",
> > > > +                            errInit ? errInit->message : "unknown
> error");
> > > > +                 if (errInit)
> > > > +                         g_error_free(errInit);
> > > > +
> > > > +                 return TestFail;
> > > > +         }
> > > > +
> > > > +         /*
> > > > +         * Remove the system libcamera plugin, if any, and add the
> > > > +         * plugin from the build directory.
> > > > +         */
> > >
> > > Missing space before *
> > >
> > > > +         GstRegistry *registry = gst_registry_get();
> > > > +         GstPlugin *plugin = gst_registry_lookup(registry,
> "libgstlibcamera.so");
> > > > +         if (plugin) {
> > > > +                 gst_registry_remove_plugin(registry, plugin);
> > > > +                 gst_object_unref(plugin);
> > > > +         }
> > > > +
> > >
> > > Extra blank spaces at the end of the line.
> > >
> > > > +         std::string path =
> std::string(libcamera::utils::libcameraBuildPath()
> > > > +                                 + "src/gstreamer");
> > >
> > > No need for calling the std::string constructor explictly,
> > > libcamera::utils::libcameraBuildPath() returns an std::string and the
> > > result of the operator+() call is also an std::string.
> > >
> > > You should #include "libcamera/internal/source_paths.h"" for
> > > libcamera::utils::libcameraBuildPath().
> > >
> > > I'll fix these small issues when applying.
> > >
> > > > +         if (!gst_registry_scan_path(registry, path.c_str())) {
> > > > +                 g_printerr("Failed to add plugin to registry\n");
> > > > +                 gst_deinit();
> > > > +                 return TestFail;
> > > > +         }
> > > > +
> > > > +         /* Create the elements */
> > > > +         libcameraSrc_ = gst_element_factory_make("libcamerasrc",
> "libcamera");
>
> And now I'm getting a failure here :-( When compiling with gcc, and with
> the meson b_sanitize option set to 'address', this call returns null.
>
> 10/64 libcamera:gstreamer / single_stream_test
>  FAIL            0.48s   exit status 1
> >>> MALLOC_PERTURB_=101
> build/x86-gcc-11.1.0/test/gstreamer/single_stream_test
> ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> ✀
> ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> stderr:
> ==14992==ASan runtime does not come first in initial library list; you
> should either link runtime to your application or manually preload it with
> LD_PRELOAD.
> ==14993==ASan runtime does not come first in initial library list; you
> should either link runtime to your application or manually preload it with
> LD_PRELOAD.
> Not all elements could be created.
> 0x6290000241f0.0x61a000019950.0x61a00001a670.(nil)
>
> =================================================================
> ==14990==ERROR: LeakSanitizer: detected memory leaks
>
> Direct leak of 16384 byte(s) in 1 object(s) allocated from:
>     #0 0x7f9daade1ac7 in __interceptor_malloc
> /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
>     #1 0x7f9da776a938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
>
> SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
>
> ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
>
> 11/64 libcamera:ipa / ipa_module_test
> OK              0.08s
>
> Interestingly, if I run the test with
>
> LD_PRELOAD=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/libasan.so.6
> ./test/gstreamer/single_stream_test
>
> then is runs fine:
>
> [25:59:46.412146534] [18711]  INFO IPAManager ipa_manager.cpp:138
> libcamera is not installed. Adding '[...]/build/x86-gcc-11.1.0/src/ipa' to
> the IPA search path
> [25:59:46.413634330] [18711]  INFO Camera camera_manager.cpp:294 libcamera
> v0.0.0+2881-24c1e91b-dirty (2021-08-13T17:24:37+03:00)
> [25:59:46.663097368] [18714]  WARN CameraSensorProperties
> camera_sensor_properties.cpp:123 No static properties available for 'Sensor
> B'
> [25:59:46.663129122] [18714]  WARN CameraSensorProperties
> camera_sensor_properties.cpp:125 Please consider updating the camera sensor
> properties database
> [25:59:46.663156409] [18714]  WARN CameraSensor camera_sensor.cpp:403
> 'Sensor B': Failed to retrieve the camera location
> [25:59:46.664891182] [18714]  INFO IPAProxy ipa_proxy.cpp:130 libcamera is
> not installed. Loading IPA configuration from '[...]/src/ipa/vimc/data'
> [25:59:46.680563655] [18715]  INFO Camera camera.cpp:870 configuring
> streams: (0) 160x120-YUYV
>
> =================================================================
> ==18711==ERROR: LeakSanitizer: detected memory leaks
>
> Direct leak of 16384 byte(s) in 1 object(s) allocated from:
>     #0 0x7effa6393ac7 in __interceptor_malloc
> /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
>     #1 0x7effa57be938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
>
> SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
>
> The leak is a known glib issue, caught by valgrind too, so I'm not
> worried about it. The test failing to run is however a blocker.
>
> Vedant, can you reproduce the failure with the address sanitizer ?
>
> > > > +         convert0_ = gst_element_factory_make("videoconvert",
> "convert0");
> > > > +         sink0_ = gst_element_factory_make("fakesink", "sink0");
> > > > +
> > > > +         /* Create the empty pipeline_ */
> > > > +         pipeline_ = gst_pipeline_new("test-pipeline");
> > > > +
> > > > +         if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_)
> {
> > > > +                 g_printerr("Not all elements could be created.
> %p.%p.%p.%p\n",
> > > > +                            pipeline_, convert0_, sink0_,
> libcameraSrc_);
> > > > +                 if (pipeline_)
> > > > +                         gst_object_unref(pipeline_);
> > > > +                 if (convert0_)
> > > > +                         gst_object_unref(convert0_);
> > > > +                 if (sink0_)
> > > > +                         gst_object_unref(sink0_);
> > > > +                 if (libcameraSrc_)
> > > > +                         gst_object_unref(libcameraSrc_);
> > > > +                 gst_deinit();
> > > > +
> > > > +                 return TestFail;
> > > > +         }
> > > > +
> > > > +         return TestPass;
> > > > + }
> > > > +
> > > > + void cleanup() override
> > > > + {
> > > > +         gst_object_unref(pipeline_);
> > > > +         gst_deinit();
> > > > + }
> > > > +
> > > > + int run() override
> > > > + {
> > > > +         GstStateChangeReturn ret;
> > > > +         g_autoptr(GstBus) bus;
> > > > +         g_autoptr(GstMessage) msg;
> >
> > I've also had to initialize those two variables to nullptr, to fix
> >
> > In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
> >                  from /usr/include/glib-2.0/glib/gtypes.h:32,
> >                  from /usr/include/glib-2.0/glib/galloca.h:32,
> >                  from /usr/include/glib-2.0/glib.h:30,
> >                  from /usr/include/gstreamer-1.0/gst/gst.h:27,
> >                  from
> ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
> > /usr/include/glib-2.0/glib/gmacros.h: In member function ‘virtual int
> GstreamerSingleStreamTest::run()’:
> > /usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be used
> uninitialized in this function [-Werror=maybe-uninitialized]
> >  1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }
>                                                 \
> >       |       ^~
> > ../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25: note:
> ‘msg’ was declared here
> >   108 |   g_autoptr(GstMessage) msg;
> >       |                         ^~~
> >
> > when cross-compiling for ARM.
> >
> > > > +
> > > > +         /* Build the pipeline */
> > > > +         gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
> convert0_, sink0_, NULL);
> > > > +         if (gst_element_link_many(libcameraSrc_, convert0_,
> sink0_, NULL) != TRUE) {
> > > > +                 g_printerr("Elements could not be linked.\n");
> > > > +                 return TestFail;
> > > > +         }
> > > > +
> > > > +         /* Start playing */
> > > > +         ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> > > > +         if (ret == GST_STATE_CHANGE_FAILURE) {
> > > > +                 g_printerr("Unable to set the pipeline to the
> playing state.\n");
> > > > +                 return TestFail;
> > > > +         }
> > > > +
> > > > +         /* Wait until error or EOS or timeout after 2 seconds */
> > > > +         GstClockTime timeout = 2000000000;
> > > > +         bus = gst_element_get_bus(pipeline_);
> > > > +         msg = gst_bus_timed_pop_filtered(bus, timeout,
> > > > +
> GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > > > +         gst_element_set_state(pipeline_, GST_STATE_NULL);
> > > > +
> > > > +         /* Parse error message */
> > > > +         if (msg == NULL)
> > > > +                 return TestPass;
> > > > +
> > > > +         switch (GST_MESSAGE_TYPE(msg)) {
> > > > +         case GST_MESSAGE_ERROR:
> > > > +                 gstreamer_print_error(msg);
> > > > +                 break;
> > > > +         case GST_MESSAGE_EOS:
> > > > +                 g_print("End-Of-Stream reached.\n");
> > > > +                 break;
> > > > +         default:
> > > > +                 g_printerr("Unexpected message received.\n");
> > > > +                 break;
> > > > +         }
> > > > +
> > > > +         return TestFail;
> > > > + }
> > > > +
> > > > +private:
> > > > + void gstreamer_print_error(GstMessage *msg)
> > > > + {
> > > > +         GError *err;
> > > > +         gchar *debug_info;
> > > > +
> > > > +         gst_message_parse_error(msg, &err, &debug_info);
> > > > +         g_printerr("Error received from element %s: %s\n",
> > > > +                    GST_OBJECT_NAME(msg->src), err->message);
> > > > +         g_printerr("Debugging information: %s\n",
> > > > +                    debug_info ? debug_info : "none");
> > > > +         g_clear_error(&err);
> > > > +         g_free(debug_info);
> > > > + }
> > > > +
> > > > + GstElement *pipeline_;
> > > > + GstElement *libcameraSrc_;
> > > > + GstElement *convert0_;
> > > > + GstElement *sink0_;
> > > > +};
> > > > +
> > > > +TEST_REGISTER(GstreamerSingleStreamTest)
> > > > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > > > new file mode 100644
> > > > index 00000000..b99aa0da
> > > > --- /dev/null
> > > > +++ b/test/gstreamer/meson.build
> > > > @@ -0,0 +1,19 @@
> > > > +# SPDX-License-Identifier: CC0-1.0
> > > > +
> > > > +if not gst_enabled
> > > > +    subdir_done()
> > > > +endif
> > > > +
> > > > +gstreamer_tests = [
> > > > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> > > > +]
> > > > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > > > +
> > > > +foreach t : gstreamer_tests
> > > > +    exe = executable(t[0], t[1],
> > > > +                     dependencies : [libcamera_private,
> gstreamer_dep],
> > > > +                     link_with : test_libraries,
> > > > +                     include_directories : test_includes_internal)
> > > > +
> > > > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > > > +endforeach
> > > > diff --git a/test/meson.build b/test/meson.build
> > > > index 3bceb5df..d0466f17 100644
> > > > --- a/test/meson.build
> > > > +++ b/test/meson.build
> > > > @@ -11,6 +11,7 @@ subdir('libtest')
> > > >
> > > >  subdir('camera')
> > > >  subdir('controls')
> > > > +subdir('gstreamer')
> > > >  subdir('ipa')
> > > >  subdir('ipc')
> > > >  subdir('log')
>
> --
> Regards,
>
> Laurent Pinchart
>
Laurent Pinchart Aug. 13, 2021, 4:58 p.m. UTC | #9
Hi Vedant,

On Fri, Aug 13, 2021 at 10:14:09PM +0530, Vedant Paranjape wrote:
> Hi Laurent,
> I was unable to reproduce the issue with address sanitizer.
> 
> Steps I followed:
> 1) meson --reconfigure build -Db_sanitize=address
> 2) ninja -C build test

What's the full output of the gstreamer test when you run it manually ?

> On Fri, Aug 13, 2021 at 8:07 PM Laurent Pinchart wrote:
> > On Fri, Aug 13, 2021 at 05:04:01PM +0300, Laurent Pinchart wrote:
> > > On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> > > > Hi Vedant,
> > > >
> > > > Thank you for the patch.
> > > >
> > > > On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > > > > This patch adds a test to test if single stream using
> > > > > libcamera's gstreamer element works.
> > > > >
> > > > > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>
> > > > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > > ---
> > > > >  .../gstreamer_single_stream_test.cpp          | 153
> > ++++++++++++++++++
> > > > >  test/gstreamer/meson.build                    |  19 +++
> > > > >  test/meson.build                              |   1 +
> > > > >  3 files changed, 173 insertions(+)
> > > > >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
> > > > >  create mode 100644 test/gstreamer/meson.build
> > > > >
> > > > > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp
> > b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > new file mode 100644
> > > > > index 00000000..eecd3274
> > > > > --- /dev/null
> > > > > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > @@ -0,0 +1,153 @@
> > > > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > > > +/*
> > > > > + * Copyright (C) 2021, Vedant Paranjape
> > > > > + *
> > > > > + * ipa_interface_test.cpp - Test the IPA interface
> > > > > + */
> > > > > +
> > > > > +#include <iostream>
> > > > > +
> > > > > +#include <libcamera/base/utils.h>
> > > > > +
> > > > > +#include <gst/gst.h>
> > > > > +
> > > > > +#include "test.h"
> > > > > +
> > > > > +using namespace std;
> > > > > +
> > > > > +class GstreamerSingleStreamTest : public Test
> > > > > +{
> > > > > +protected:
> > > > > + int init() override
> > > > > + {
> > > > > +         /* Initialize GStreamer */
> > > > > +         GError *errInit = nullptr;
> > > > > +         if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > > > > +                 g_printerr("Could not initialize GStreamer: %s\n",
> > > > > +                            errInit ? errInit->message : "unknown
> > error");
> > > > > +                 if (errInit)
> > > > > +                         g_error_free(errInit);
> > > > > +
> > > > > +                 return TestFail;
> > > > > +         }
> > > > > +
> > > > > +         /*
> > > > > +         * Remove the system libcamera plugin, if any, and add the
> > > > > +         * plugin from the build directory.
> > > > > +         */
> > > >
> > > > Missing space before *
> > > >
> > > > > +         GstRegistry *registry = gst_registry_get();
> > > > > +         GstPlugin *plugin = gst_registry_lookup(registry,
> > "libgstlibcamera.so");
> > > > > +         if (plugin) {
> > > > > +                 gst_registry_remove_plugin(registry, plugin);
> > > > > +                 gst_object_unref(plugin);
> > > > > +         }
> > > > > +
> > > >
> > > > Extra blank spaces at the end of the line.
> > > >
> > > > > +         std::string path =
> > std::string(libcamera::utils::libcameraBuildPath()
> > > > > +                                 + "src/gstreamer");
> > > >
> > > > No need for calling the std::string constructor explictly,
> > > > libcamera::utils::libcameraBuildPath() returns an std::string and the
> > > > result of the operator+() call is also an std::string.
> > > >
> > > > You should #include "libcamera/internal/source_paths.h"" for
> > > > libcamera::utils::libcameraBuildPath().
> > > >
> > > > I'll fix these small issues when applying.
> > > >
> > > > > +         if (!gst_registry_scan_path(registry, path.c_str())) {
> > > > > +                 g_printerr("Failed to add plugin to registry\n");
> > > > > +                 gst_deinit();
> > > > > +                 return TestFail;
> > > > > +         }
> > > > > +
> > > > > +         /* Create the elements */
> > > > > +         libcameraSrc_ = gst_element_factory_make("libcamerasrc",
> > "libcamera");
> >
> > And now I'm getting a failure here :-( When compiling with gcc, and with
> > the meson b_sanitize option set to 'address', this call returns null.
> >
> > 10/64 libcamera:gstreamer / single_stream_test
> >  FAIL            0.48s   exit status 1
> > >>> MALLOC_PERTURB_=101
> > build/x86-gcc-11.1.0/test/gstreamer/single_stream_test
> > ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > ✀
> > ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > stderr:
> > ==14992==ASan runtime does not come first in initial library list; you
> > should either link runtime to your application or manually preload it with
> > LD_PRELOAD.
> > ==14993==ASan runtime does not come first in initial library list; you
> > should either link runtime to your application or manually preload it with
> > LD_PRELOAD.
> > Not all elements could be created.
> > 0x6290000241f0.0x61a000019950.0x61a00001a670.(nil)
> >
> > =================================================================
> > ==14990==ERROR: LeakSanitizer: detected memory leaks
> >
> > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> >     #0 0x7f9daade1ac7 in __interceptor_malloc
> > /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> >     #1 0x7f9da776a938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> >
> > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> >
> > ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> >
> > 11/64 libcamera:ipa / ipa_module_test
> > OK              0.08s
> >
> > Interestingly, if I run the test with
> >
> > LD_PRELOAD=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/libasan.so.6
> > ./test/gstreamer/single_stream_test
> >
> > then is runs fine:
> >
> > [25:59:46.412146534] [18711]  INFO IPAManager ipa_manager.cpp:138
> > libcamera is not installed. Adding '[...]/build/x86-gcc-11.1.0/src/ipa' to
> > the IPA search path
> > [25:59:46.413634330] [18711]  INFO Camera camera_manager.cpp:294 libcamera
> > v0.0.0+2881-24c1e91b-dirty (2021-08-13T17:24:37+03:00)
> > [25:59:46.663097368] [18714]  WARN CameraSensorProperties
> > camera_sensor_properties.cpp:123 No static properties available for 'Sensor
> > B'
> > [25:59:46.663129122] [18714]  WARN CameraSensorProperties
> > camera_sensor_properties.cpp:125 Please consider updating the camera sensor
> > properties database
> > [25:59:46.663156409] [18714]  WARN CameraSensor camera_sensor.cpp:403
> > 'Sensor B': Failed to retrieve the camera location
> > [25:59:46.664891182] [18714]  INFO IPAProxy ipa_proxy.cpp:130 libcamera is
> > not installed. Loading IPA configuration from '[...]/src/ipa/vimc/data'
> > [25:59:46.680563655] [18715]  INFO Camera camera.cpp:870 configuring
> > streams: (0) 160x120-YUYV
> >
> > =================================================================
> > ==18711==ERROR: LeakSanitizer: detected memory leaks
> >
> > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> >     #0 0x7effa6393ac7 in __interceptor_malloc
> > /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> >     #1 0x7effa57be938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> >
> > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> >
> > The leak is a known glib issue, caught by valgrind too, so I'm not
> > worried about it. The test failing to run is however a blocker.
> >
> > Vedant, can you reproduce the failure with the address sanitizer ?
> >
> > > > > +         convert0_ = gst_element_factory_make("videoconvert",
> > "convert0");
> > > > > +         sink0_ = gst_element_factory_make("fakesink", "sink0");
> > > > > +
> > > > > +         /* Create the empty pipeline_ */
> > > > > +         pipeline_ = gst_pipeline_new("test-pipeline");
> > > > > +
> > > > > +         if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_)
> > {
> > > > > +                 g_printerr("Not all elements could be created.
> > %p.%p.%p.%p\n",
> > > > > +                            pipeline_, convert0_, sink0_,
> > libcameraSrc_);
> > > > > +                 if (pipeline_)
> > > > > +                         gst_object_unref(pipeline_);
> > > > > +                 if (convert0_)
> > > > > +                         gst_object_unref(convert0_);
> > > > > +                 if (sink0_)
> > > > > +                         gst_object_unref(sink0_);
> > > > > +                 if (libcameraSrc_)
> > > > > +                         gst_object_unref(libcameraSrc_);
> > > > > +                 gst_deinit();
> > > > > +
> > > > > +                 return TestFail;
> > > > > +         }
> > > > > +
> > > > > +         return TestPass;
> > > > > + }
> > > > > +
> > > > > + void cleanup() override
> > > > > + {
> > > > > +         gst_object_unref(pipeline_);
> > > > > +         gst_deinit();
> > > > > + }
> > > > > +
> > > > > + int run() override
> > > > > + {
> > > > > +         GstStateChangeReturn ret;
> > > > > +         g_autoptr(GstBus) bus;
> > > > > +         g_autoptr(GstMessage) msg;
> > >
> > > I've also had to initialize those two variables to nullptr, to fix
> > >
> > > In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
> > >                  from /usr/include/glib-2.0/glib/gtypes.h:32,
> > >                  from /usr/include/glib-2.0/glib/galloca.h:32,
> > >                  from /usr/include/glib-2.0/glib.h:30,
> > >                  from /usr/include/gstreamer-1.0/gst/gst.h:27,
> > >                  from
> > ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
> > > /usr/include/glib-2.0/glib/gmacros.h: In member function ‘virtual int
> > GstreamerSingleStreamTest::run()’:
> > > /usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be used
> > uninitialized in this function [-Werror=maybe-uninitialized]
> > >  1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }
> >                                                 \
> > >       |       ^~
> > > ../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25: note:
> > ‘msg’ was declared here
> > >   108 |   g_autoptr(GstMessage) msg;
> > >       |                         ^~~
> > >
> > > when cross-compiling for ARM.
> > >
> > > > > +
> > > > > +         /* Build the pipeline */
> > > > > +         gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
> > convert0_, sink0_, NULL);
> > > > > +         if (gst_element_link_many(libcameraSrc_, convert0_,
> > sink0_, NULL) != TRUE) {
> > > > > +                 g_printerr("Elements could not be linked.\n");
> > > > > +                 return TestFail;
> > > > > +         }
> > > > > +
> > > > > +         /* Start playing */
> > > > > +         ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> > > > > +         if (ret == GST_STATE_CHANGE_FAILURE) {
> > > > > +                 g_printerr("Unable to set the pipeline to the
> > playing state.\n");
> > > > > +                 return TestFail;
> > > > > +         }
> > > > > +
> > > > > +         /* Wait until error or EOS or timeout after 2 seconds */
> > > > > +         GstClockTime timeout = 2000000000;
> > > > > +         bus = gst_element_get_bus(pipeline_);
> > > > > +         msg = gst_bus_timed_pop_filtered(bus, timeout,
> > > > > +
> > GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > > > > +         gst_element_set_state(pipeline_, GST_STATE_NULL);
> > > > > +
> > > > > +         /* Parse error message */
> > > > > +         if (msg == NULL)
> > > > > +                 return TestPass;
> > > > > +
> > > > > +         switch (GST_MESSAGE_TYPE(msg)) {
> > > > > +         case GST_MESSAGE_ERROR:
> > > > > +                 gstreamer_print_error(msg);
> > > > > +                 break;
> > > > > +         case GST_MESSAGE_EOS:
> > > > > +                 g_print("End-Of-Stream reached.\n");
> > > > > +                 break;
> > > > > +         default:
> > > > > +                 g_printerr("Unexpected message received.\n");
> > > > > +                 break;
> > > > > +         }
> > > > > +
> > > > > +         return TestFail;
> > > > > + }
> > > > > +
> > > > > +private:
> > > > > + void gstreamer_print_error(GstMessage *msg)
> > > > > + {
> > > > > +         GError *err;
> > > > > +         gchar *debug_info;
> > > > > +
> > > > > +         gst_message_parse_error(msg, &err, &debug_info);
> > > > > +         g_printerr("Error received from element %s: %s\n",
> > > > > +                    GST_OBJECT_NAME(msg->src), err->message);
> > > > > +         g_printerr("Debugging information: %s\n",
> > > > > +                    debug_info ? debug_info : "none");
> > > > > +         g_clear_error(&err);
> > > > > +         g_free(debug_info);
> > > > > + }
> > > > > +
> > > > > + GstElement *pipeline_;
> > > > > + GstElement *libcameraSrc_;
> > > > > + GstElement *convert0_;
> > > > > + GstElement *sink0_;
> > > > > +};
> > > > > +
> > > > > +TEST_REGISTER(GstreamerSingleStreamTest)
> > > > > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > > > > new file mode 100644
> > > > > index 00000000..b99aa0da
> > > > > --- /dev/null
> > > > > +++ b/test/gstreamer/meson.build
> > > > > @@ -0,0 +1,19 @@
> > > > > +# SPDX-License-Identifier: CC0-1.0
> > > > > +
> > > > > +if not gst_enabled
> > > > > +    subdir_done()
> > > > > +endif
> > > > > +
> > > > > +gstreamer_tests = [
> > > > > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> > > > > +]
> > > > > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > > > > +
> > > > > +foreach t : gstreamer_tests
> > > > > +    exe = executable(t[0], t[1],
> > > > > +                     dependencies : [libcamera_private,
> > gstreamer_dep],
> > > > > +                     link_with : test_libraries,
> > > > > +                     include_directories : test_includes_internal)
> > > > > +
> > > > > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > > > > +endforeach
> > > > > diff --git a/test/meson.build b/test/meson.build
> > > > > index 3bceb5df..d0466f17 100644
> > > > > --- a/test/meson.build
> > > > > +++ b/test/meson.build
> > > > > @@ -11,6 +11,7 @@ subdir('libtest')
> > > > >
> > > > >  subdir('camera')
> > > > >  subdir('controls')
> > > > > +subdir('gstreamer')
> > > > >  subdir('ipa')
> > > > >  subdir('ipc')
> > > > >  subdir('log')
Vedant Paranjape Aug. 13, 2021, 5:01 p.m. UTC | #10
Hi Laurent,

vedant@veware ~/Programming/contributing/libcamera$
./build/test/gstreamer/single_stream_test
                                           ✹ ✭wip-negotiation
[11:45:45.304648653] [243629]  INFO IPAManager ipa_manager.cpp:138
libcamera is not installed. Adding
'/home/vedant/Programming/contributing/libcamera/build/src/ipa' to the IPA
search path
[11:45:45.306046376] [243629]  INFO Camera camera_manager.cpp:294 libcamera
v0.0.0+2877-e3edb100-dirty (2021-08-13T22:11:47+05:30)
[11:45:45.319737506] [243632]  INFO Camera camera.cpp:870 configuring
streams: (0) 640x360-YUYV

On Fri, Aug 13, 2021 at 10:28 PM Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> Hi Vedant,
>
> On Fri, Aug 13, 2021 at 10:14:09PM +0530, Vedant Paranjape wrote:
> > Hi Laurent,
> > I was unable to reproduce the issue with address sanitizer.
> >
> > Steps I followed:
> > 1) meson --reconfigure build -Db_sanitize=address
> > 2) ninja -C build test
>
> What's the full output of the gstreamer test when you run it manually ?
>
> > On Fri, Aug 13, 2021 at 8:07 PM Laurent Pinchart wrote:
> > > On Fri, Aug 13, 2021 at 05:04:01PM +0300, Laurent Pinchart wrote:
> > > > On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> > > > > Hi Vedant,
> > > > >
> > > > > Thank you for the patch.
> > > > >
> > > > > On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > > > > > This patch adds a test to test if single stream using
> > > > > > libcamera's gstreamer element works.
> > > > > >
> > > > > > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com
> >
> > > > > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > > > ---
> > > > > >  .../gstreamer_single_stream_test.cpp          | 153
> > > ++++++++++++++++++
> > > > > >  test/gstreamer/meson.build                    |  19 +++
> > > > > >  test/meson.build                              |   1 +
> > > > > >  3 files changed, 173 insertions(+)
> > > > > >  create mode 100644
> test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > >  create mode 100644 test/gstreamer/meson.build
> > > > > >
> > > > > > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp
> > > b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > new file mode 100644
> > > > > > index 00000000..eecd3274
> > > > > > --- /dev/null
> > > > > > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > @@ -0,0 +1,153 @@
> > > > > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > > > > +/*
> > > > > > + * Copyright (C) 2021, Vedant Paranjape
> > > > > > + *
> > > > > > + * ipa_interface_test.cpp - Test the IPA interface
> > > > > > + */
> > > > > > +
> > > > > > +#include <iostream>
> > > > > > +
> > > > > > +#include <libcamera/base/utils.h>
> > > > > > +
> > > > > > +#include <gst/gst.h>
> > > > > > +
> > > > > > +#include "test.h"
> > > > > > +
> > > > > > +using namespace std;
> > > > > > +
> > > > > > +class GstreamerSingleStreamTest : public Test
> > > > > > +{
> > > > > > +protected:
> > > > > > + int init() override
> > > > > > + {
> > > > > > +         /* Initialize GStreamer */
> > > > > > +         GError *errInit = nullptr;
> > > > > > +         if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > > > > > +                 g_printerr("Could not initialize GStreamer:
> %s\n",
> > > > > > +                            errInit ? errInit->message :
> "unknown
> > > error");
> > > > > > +                 if (errInit)
> > > > > > +                         g_error_free(errInit);
> > > > > > +
> > > > > > +                 return TestFail;
> > > > > > +         }
> > > > > > +
> > > > > > +         /*
> > > > > > +         * Remove the system libcamera plugin, if any, and add
> the
> > > > > > +         * plugin from the build directory.
> > > > > > +         */
> > > > >
> > > > > Missing space before *
> > > > >
> > > > > > +         GstRegistry *registry = gst_registry_get();
> > > > > > +         GstPlugin *plugin = gst_registry_lookup(registry,
> > > "libgstlibcamera.so");
> > > > > > +         if (plugin) {
> > > > > > +                 gst_registry_remove_plugin(registry, plugin);
> > > > > > +                 gst_object_unref(plugin);
> > > > > > +         }
> > > > > > +
> > > > >
> > > > > Extra blank spaces at the end of the line.
> > > > >
> > > > > > +         std::string path =
> > > std::string(libcamera::utils::libcameraBuildPath()
> > > > > > +                                 + "src/gstreamer");
> > > > >
> > > > > No need for calling the std::string constructor explictly,
> > > > > libcamera::utils::libcameraBuildPath() returns an std::string and
> the
> > > > > result of the operator+() call is also an std::string.
> > > > >
> > > > > You should #include "libcamera/internal/source_paths.h"" for
> > > > > libcamera::utils::libcameraBuildPath().
> > > > >
> > > > > I'll fix these small issues when applying.
> > > > >
> > > > > > +         if (!gst_registry_scan_path(registry, path.c_str())) {
> > > > > > +                 g_printerr("Failed to add plugin to
> registry\n");
> > > > > > +                 gst_deinit();
> > > > > > +                 return TestFail;
> > > > > > +         }
> > > > > > +
> > > > > > +         /* Create the elements */
> > > > > > +         libcameraSrc_ =
> gst_element_factory_make("libcamerasrc",
> > > "libcamera");
> > >
> > > And now I'm getting a failure here :-( When compiling with gcc, and
> with
> > > the meson b_sanitize option set to 'address', this call returns null.
> > >
> > > 10/64 libcamera:gstreamer / single_stream_test
> > >  FAIL            0.48s   exit status 1
> > > >>> MALLOC_PERTURB_=101
> > > build/x86-gcc-11.1.0/test/gstreamer/single_stream_test
> > >
> ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > > ✀
> > >
> ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > > stderr:
> > > ==14992==ASan runtime does not come first in initial library list; you
> > > should either link runtime to your application or manually preload it
> with
> > > LD_PRELOAD.
> > > ==14993==ASan runtime does not come first in initial library list; you
> > > should either link runtime to your application or manually preload it
> with
> > > LD_PRELOAD.
> > > Not all elements could be created.
> > > 0x6290000241f0.0x61a000019950.0x61a00001a670.(nil)
> > >
> > > =================================================================
> > > ==14990==ERROR: LeakSanitizer: detected memory leaks
> > >
> > > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> > >     #0 0x7f9daade1ac7 in __interceptor_malloc
> > >
> /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> > >     #1 0x7f9da776a938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> > >
> > > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> > >
> > >
> ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > >
> > > 11/64 libcamera:ipa / ipa_module_test
> > > OK              0.08s
> > >
> > > Interestingly, if I run the test with
> > >
> > > LD_PRELOAD=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/libasan.so.6
> > > ./test/gstreamer/single_stream_test
> > >
> > > then is runs fine:
> > >
> > > [25:59:46.412146534] [18711]  INFO IPAManager ipa_manager.cpp:138
> > > libcamera is not installed. Adding
> '[...]/build/x86-gcc-11.1.0/src/ipa' to
> > > the IPA search path
> > > [25:59:46.413634330] [18711]  INFO Camera camera_manager.cpp:294
> libcamera
> > > v0.0.0+2881-24c1e91b-dirty (2021-08-13T17:24:37+03:00)
> > > [25:59:46.663097368] [18714]  WARN CameraSensorProperties
> > > camera_sensor_properties.cpp:123 No static properties available for
> 'Sensor
> > > B'
> > > [25:59:46.663129122] [18714]  WARN CameraSensorProperties
> > > camera_sensor_properties.cpp:125 Please consider updating the camera
> sensor
> > > properties database
> > > [25:59:46.663156409] [18714]  WARN CameraSensor camera_sensor.cpp:403
> > > 'Sensor B': Failed to retrieve the camera location
> > > [25:59:46.664891182] [18714]  INFO IPAProxy ipa_proxy.cpp:130
> libcamera is
> > > not installed. Loading IPA configuration from '[...]/src/ipa/vimc/data'
> > > [25:59:46.680563655] [18715]  INFO Camera camera.cpp:870 configuring
> > > streams: (0) 160x120-YUYV
> > >
> > > =================================================================
> > > ==18711==ERROR: LeakSanitizer: detected memory leaks
> > >
> > > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> > >     #0 0x7effa6393ac7 in __interceptor_malloc
> > >
> /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> > >     #1 0x7effa57be938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> > >
> > > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> > >
> > > The leak is a known glib issue, caught by valgrind too, so I'm not
> > > worried about it. The test failing to run is however a blocker.
> > >
> > > Vedant, can you reproduce the failure with the address sanitizer ?
> > >
> > > > > > +         convert0_ = gst_element_factory_make("videoconvert",
> > > "convert0");
> > > > > > +         sink0_ = gst_element_factory_make("fakesink", "sink0");
> > > > > > +
> > > > > > +         /* Create the empty pipeline_ */
> > > > > > +         pipeline_ = gst_pipeline_new("test-pipeline");
> > > > > > +
> > > > > > +         if (!pipeline_ || !convert0_ || !sink0_ ||
> !libcameraSrc_)
> > > {
> > > > > > +                 g_printerr("Not all elements could be created.
> > > %p.%p.%p.%p\n",
> > > > > > +                            pipeline_, convert0_, sink0_,
> > > libcameraSrc_);
> > > > > > +                 if (pipeline_)
> > > > > > +                         gst_object_unref(pipeline_);
> > > > > > +                 if (convert0_)
> > > > > > +                         gst_object_unref(convert0_);
> > > > > > +                 if (sink0_)
> > > > > > +                         gst_object_unref(sink0_);
> > > > > > +                 if (libcameraSrc_)
> > > > > > +                         gst_object_unref(libcameraSrc_);
> > > > > > +                 gst_deinit();
> > > > > > +
> > > > > > +                 return TestFail;
> > > > > > +         }
> > > > > > +
> > > > > > +         return TestPass;
> > > > > > + }
> > > > > > +
> > > > > > + void cleanup() override
> > > > > > + {
> > > > > > +         gst_object_unref(pipeline_);
> > > > > > +         gst_deinit();
> > > > > > + }
> > > > > > +
> > > > > > + int run() override
> > > > > > + {
> > > > > > +         GstStateChangeReturn ret;
> > > > > > +         g_autoptr(GstBus) bus;
> > > > > > +         g_autoptr(GstMessage) msg;
> > > >
> > > > I've also had to initialize those two variables to nullptr, to fix
> > > >
> > > > In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
> > > >                  from /usr/include/glib-2.0/glib/gtypes.h:32,
> > > >                  from /usr/include/glib-2.0/glib/galloca.h:32,
> > > >                  from /usr/include/glib-2.0/glib.h:30,
> > > >                  from /usr/include/gstreamer-1.0/gst/gst.h:27,
> > > >                  from
> > > ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
> > > > /usr/include/glib-2.0/glib/gmacros.h: In member function ‘virtual int
> > > GstreamerSingleStreamTest::run()’:
> > > > /usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be used
> > > uninitialized in this function [-Werror=maybe-uninitialized]
> > > >  1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }
> > >                                                 \
> > > >       |       ^~
> > > > ../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25: note:
> > > ‘msg’ was declared here
> > > >   108 |   g_autoptr(GstMessage) msg;
> > > >       |                         ^~~
> > > >
> > > > when cross-compiling for ARM.
> > > >
> > > > > > +
> > > > > > +         /* Build the pipeline */
> > > > > > +         gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
> > > convert0_, sink0_, NULL);
> > > > > > +         if (gst_element_link_many(libcameraSrc_, convert0_,
> > > sink0_, NULL) != TRUE) {
> > > > > > +                 g_printerr("Elements could not be linked.\n");
> > > > > > +                 return TestFail;
> > > > > > +         }
> > > > > > +
> > > > > > +         /* Start playing */
> > > > > > +         ret = gst_element_set_state(pipeline_,
> GST_STATE_PLAYING);
> > > > > > +         if (ret == GST_STATE_CHANGE_FAILURE) {
> > > > > > +                 g_printerr("Unable to set the pipeline to the
> > > playing state.\n");
> > > > > > +                 return TestFail;
> > > > > > +         }
> > > > > > +
> > > > > > +         /* Wait until error or EOS or timeout after 2 seconds
> */
> > > > > > +         GstClockTime timeout = 2000000000;
> > > > > > +         bus = gst_element_get_bus(pipeline_);
> > > > > > +         msg = gst_bus_timed_pop_filtered(bus, timeout,
> > > > > > +
> > > GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > > > > > +         gst_element_set_state(pipeline_, GST_STATE_NULL);
> > > > > > +
> > > > > > +         /* Parse error message */
> > > > > > +         if (msg == NULL)
> > > > > > +                 return TestPass;
> > > > > > +
> > > > > > +         switch (GST_MESSAGE_TYPE(msg)) {
> > > > > > +         case GST_MESSAGE_ERROR:
> > > > > > +                 gstreamer_print_error(msg);
> > > > > > +                 break;
> > > > > > +         case GST_MESSAGE_EOS:
> > > > > > +                 g_print("End-Of-Stream reached.\n");
> > > > > > +                 break;
> > > > > > +         default:
> > > > > > +                 g_printerr("Unexpected message received.\n");
> > > > > > +                 break;
> > > > > > +         }
> > > > > > +
> > > > > > +         return TestFail;
> > > > > > + }
> > > > > > +
> > > > > > +private:
> > > > > > + void gstreamer_print_error(GstMessage *msg)
> > > > > > + {
> > > > > > +         GError *err;
> > > > > > +         gchar *debug_info;
> > > > > > +
> > > > > > +         gst_message_parse_error(msg, &err, &debug_info);
> > > > > > +         g_printerr("Error received from element %s: %s\n",
> > > > > > +                    GST_OBJECT_NAME(msg->src), err->message);
> > > > > > +         g_printerr("Debugging information: %s\n",
> > > > > > +                    debug_info ? debug_info : "none");
> > > > > > +         g_clear_error(&err);
> > > > > > +         g_free(debug_info);
> > > > > > + }
> > > > > > +
> > > > > > + GstElement *pipeline_;
> > > > > > + GstElement *libcameraSrc_;
> > > > > > + GstElement *convert0_;
> > > > > > + GstElement *sink0_;
> > > > > > +};
> > > > > > +
> > > > > > +TEST_REGISTER(GstreamerSingleStreamTest)
> > > > > > diff --git a/test/gstreamer/meson.build
> b/test/gstreamer/meson.build
> > > > > > new file mode 100644
> > > > > > index 00000000..b99aa0da
> > > > > > --- /dev/null
> > > > > > +++ b/test/gstreamer/meson.build
> > > > > > @@ -0,0 +1,19 @@
> > > > > > +# SPDX-License-Identifier: CC0-1.0
> > > > > > +
> > > > > > +if not gst_enabled
> > > > > > +    subdir_done()
> > > > > > +endif
> > > > > > +
> > > > > > +gstreamer_tests = [
> > > > > > +    ['single_stream_test',
>  'gstreamer_single_stream_test.cpp'],
> > > > > > +]
> > > > > > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > > > > > +
> > > > > > +foreach t : gstreamer_tests
> > > > > > +    exe = executable(t[0], t[1],
> > > > > > +                     dependencies : [libcamera_private,
> > > gstreamer_dep],
> > > > > > +                     link_with : test_libraries,
> > > > > > +                     include_directories :
> test_includes_internal)
> > > > > > +
> > > > > > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > > > > > +endforeach
> > > > > > diff --git a/test/meson.build b/test/meson.build
> > > > > > index 3bceb5df..d0466f17 100644
> > > > > > --- a/test/meson.build
> > > > > > +++ b/test/meson.build
> > > > > > @@ -11,6 +11,7 @@ subdir('libtest')
> > > > > >
> > > > > >  subdir('camera')
> > > > > >  subdir('controls')
> > > > > > +subdir('gstreamer')
> > > > > >  subdir('ipa')
> > > > > >  subdir('ipc')
> > > > > >  subdir('log')
>
> --
> Regards,
>
> Laurent Pinchart
>
Laurent Pinchart Aug. 13, 2021, 6:39 p.m. UTC | #11
Hi Vedant,

On Fri, Aug 13, 2021 at 10:31:43PM +0530, Vedant Paranjape wrote:
> Hi Laurent,
> 
> vedant@veware ~/Programming/contributing/libcamera$
> ./build/test/gstreamer/single_stream_test
>                                            ✹ ✭wip-negotiation
> [11:45:45.304648653] [243629]  INFO IPAManager ipa_manager.cpp:138 libcamera is not installed. Adding '/home/vedant/Programming/contributing/libcamera/build/src/ipa' to the IPA search path
> [11:45:45.306046376] [243629]  INFO Camera camera_manager.cpp:294 libcamera v0.0.0+2877-e3edb100-dirty (2021-08-13T22:11:47+05:30)
> [11:45:45.319737506] [243632]  INFO Camera camera.cpp:870 configuring streams: (0) 640x360-YUYV

As discussed on IRC, that didn't have asan enabled.

Running

LD_DEBUG=libs ./test/gstreamer/single_stream_test

gives useful information. GStreamer spawns a new process,
gst-plugin-scanner, to locate the libcamerasrc plugin. As gstreamer is
compiled without asan, the gst-plugin-scanner process has lots of
libraries loaded when it dlopen()s the plugin .so, which results in a
failure in the asan library order sanity check, producing the messages

==24099==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
==24100==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.

I'm getting the exact same two messages when running gst-inspect or
gst-launch. However,

gst-launch-1.0 --gst-plugin-path=$(pwd)/src/gstreamer/ libcamerasrc ! videoconvert ! fakesink

doesn't fail. There may thus be something we're doing wrong, or at least
in a different way.

> On Fri, Aug 13, 2021 at 10:28 PM Laurent Pinchart wrote:
> > On Fri, Aug 13, 2021 at 10:14:09PM +0530, Vedant Paranjape wrote:
> > > Hi Laurent,
> > > I was unable to reproduce the issue with address sanitizer.
> > >
> > > Steps I followed:
> > > 1) meson --reconfigure build -Db_sanitize=address
> > > 2) ninja -C build test
> >
> > What's the full output of the gstreamer test when you run it manually ?
> >
> > > On Fri, Aug 13, 2021 at 8:07 PM Laurent Pinchart wrote:
> > > > On Fri, Aug 13, 2021 at 05:04:01PM +0300, Laurent Pinchart wrote:
> > > > > On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> > > > > > Hi Vedant,
> > > > > >
> > > > > > Thank you for the patch.
> > > > > >
> > > > > > On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > > > > > > This patch adds a test to test if single stream using
> > > > > > > libcamera's gstreamer element works.
> > > > > > >
> > > > > > > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com
> > > > > > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > > > > ---
> > > > > > >  .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
> > > > > > >  test/gstreamer/meson.build                    |  19 +++
> > > > > > >  test/meson.build                              |   1 +
> > > > > > >  3 files changed, 173 insertions(+)
> > > > > > >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > >  create mode 100644 test/gstreamer/meson.build
> > > > > > >
> > > > > > > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > > new file mode 100644
> > > > > > > index 00000000..eecd3274
> > > > > > > --- /dev/null
> > > > > > > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > > @@ -0,0 +1,153 @@
> > > > > > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > > > > > +/*
> > > > > > > + * Copyright (C) 2021, Vedant Paranjape
> > > > > > > + *
> > > > > > > + * ipa_interface_test.cpp - Test the IPA interface
> > > > > > > + */
> > > > > > > +
> > > > > > > +#include <iostream>
> > > > > > > +
> > > > > > > +#include <libcamera/base/utils.h>
> > > > > > > +
> > > > > > > +#include <gst/gst.h>
> > > > > > > +
> > > > > > > +#include "test.h"
> > > > > > > +
> > > > > > > +using namespace std;
> > > > > > > +
> > > > > > > +class GstreamerSingleStreamTest : public Test
> > > > > > > +{
> > > > > > > +protected:
> > > > > > > + int init() override
> > > > > > > + {
> > > > > > > +         /* Initialize GStreamer */
> > > > > > > +         GError *errInit = nullptr;
> > > > > > > +         if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > > > > > > +                 g_printerr("Could not initialize GStreamer: %s\n",
> > > > > > > +                            errInit ? errInit->message : "unknown error");
> > > > > > > +                 if (errInit)
> > > > > > > +                         g_error_free(errInit);
> > > > > > > +
> > > > > > > +                 return TestFail;
> > > > > > > +         }
> > > > > > > +
> > > > > > > +         /*
> > > > > > > +         * Remove the system libcamera plugin, if any, and add the
> > > > > > > +         * plugin from the build directory.
> > > > > > > +         */
> > > > > >
> > > > > > Missing space before *
> > > > > >
> > > > > > > +         GstRegistry *registry = gst_registry_get();
> > > > > > > +         GstPlugin *plugin = gst_registry_lookup(registry, "libgstlibcamera.so");
> > > > > > > +         if (plugin) {
> > > > > > > +                 gst_registry_remove_plugin(registry, plugin);
> > > > > > > +                 gst_object_unref(plugin);
> > > > > > > +         }
> > > > > > > +
> > > > > >
> > > > > > Extra blank spaces at the end of the line.
> > > > > >
> > > > > > > +         std::string path = std::string(libcamera::utils::libcameraBuildPath()
> > > > > > > +                                 + "src/gstreamer");
> > > > > >
> > > > > > No need for calling the std::string constructor explictly,
> > > > > > libcamera::utils::libcameraBuildPath() returns an std::string and the
> > > > > > result of the operator+() call is also an std::string.
> > > > > >
> > > > > > You should #include "libcamera/internal/source_paths.h"" for
> > > > > > libcamera::utils::libcameraBuildPath().
> > > > > >
> > > > > > I'll fix these small issues when applying.
> > > > > >
> > > > > > > +         if (!gst_registry_scan_path(registry, path.c_str())) {
> > > > > > > +                 g_printerr("Failed to add plugin to registry\n");
> > > > > > > +                 gst_deinit();
> > > > > > > +                 return TestFail;
> > > > > > > +         }
> > > > > > > +
> > > > > > > +         /* Create the elements */
> > > > > > > +         libcameraSrc_ = gst_element_factory_make("libcamerasrc", "libcamera");
> > > >
> > > > And now I'm getting a failure here :-( When compiling with gcc, and with
> > > > the meson b_sanitize option set to 'address', this call returns null.
> > > >
> > > > 10/64 libcamera:gstreamer / single_stream_test
> > > >  FAIL            0.48s   exit status 1
> > > > >>> MALLOC_PERTURB_=101
> > > > build/x86-gcc-11.1.0/test/gstreamer/single_stream_test
> > > > ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ✀ ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > > > stderr:
> > > > ==14992==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
> > > > ==14993==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
> > > > Not all elements could be created. 0x6290000241f0.0x61a000019950.0x61a00001a670.(nil)
> > > >
> > > > =================================================================
> > > > ==14990==ERROR: LeakSanitizer: detected memory leaks
> > > >
> > > > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> > > >     #0 0x7f9daade1ac7 in __interceptor_malloc
> > > > /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> > > >     #1 0x7f9da776a938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> > > >
> > > > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> > > >
> > > > ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > > >
> > > > 11/64 libcamera:ipa / ipa_module_test
> > > > OK              0.08s
> > > >
> > > > Interestingly, if I run the test with
> > > >
> > > > LD_PRELOAD=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/libasan.so.6
> > > > ./test/gstreamer/single_stream_test
> > > >
> > > > then is runs fine:
> > > >
> > > > [25:59:46.412146534] [18711]  INFO IPAManager ipa_manager.cpp:138 libcamera is not installed. Adding '[...]/build/x86-gcc-11.1.0/src/ipa' to the IPA search path
> > > > [25:59:46.413634330] [18711]  INFO Camera camera_manager.cpp:294 libcamera v0.0.0+2881-24c1e91b-dirty (2021-08-13T17:24:37+03:00)
> > > > [25:59:46.663097368] [18714]  WARN CameraSensorProperties camera_sensor_properties.cpp:123 No static properties available for 'Sensor B'
> > > > [25:59:46.663129122] [18714]  WARN CameraSensorProperties camera_sensor_properties.cpp:125 Please consider updating the camera sensor properties database
> > > > [25:59:46.663156409] [18714]  WARN CameraSensor camera_sensor.cpp:403 'Sensor B': Failed to retrieve the camera location
> > > > [25:59:46.664891182] [18714]  INFO IPAProxy ipa_proxy.cpp:130 libcamera is not installed. Loading IPA configuration from '[...]/src/ipa/vimc/data'
> > > > [25:59:46.680563655] [18715]  INFO Camera camera.cpp:870 configuring streams: (0) 160x120-YUYV
> > > >
> > > > =================================================================
> > > > ==18711==ERROR: LeakSanitizer: detected memory leaks
> > > >
> > > > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> > > >     #0 0x7effa6393ac7 in __interceptor_malloc
> > > > /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> > > >     #1 0x7effa57be938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> > > >
> > > > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> > > >
> > > > The leak is a known glib issue, caught by valgrind too, so I'm not
> > > > worried about it. The test failing to run is however a blocker.
> > > >
> > > > Vedant, can you reproduce the failure with the address sanitizer ?
> > > >
> > > > > > > +         convert0_ = gst_element_factory_make("videoconvert", "convert0");
> > > > > > > +         sink0_ = gst_element_factory_make("fakesink", "sink0");
> > > > > > > +
> > > > > > > +         /* Create the empty pipeline_ */
> > > > > > > +         pipeline_ = gst_pipeline_new("test-pipeline");
> > > > > > > +
> > > > > > > +         if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) {
> > > > > > > +                 g_printerr("Not all elements could be created. %p.%p.%p.%p\n",
> > > > > > > +                            pipeline_, convert0_, sink0_, libcameraSrc_);
> > > > > > > +                 if (pipeline_)
> > > > > > > +                         gst_object_unref(pipeline_);
> > > > > > > +                 if (convert0_)
> > > > > > > +                         gst_object_unref(convert0_);
> > > > > > > +                 if (sink0_)
> > > > > > > +                         gst_object_unref(sink0_);
> > > > > > > +                 if (libcameraSrc_)
> > > > > > > +                         gst_object_unref(libcameraSrc_);
> > > > > > > +                 gst_deinit();
> > > > > > > +
> > > > > > > +                 return TestFail;
> > > > > > > +         }
> > > > > > > +
> > > > > > > +         return TestPass;
> > > > > > > + }
> > > > > > > +
> > > > > > > + void cleanup() override
> > > > > > > + {
> > > > > > > +         gst_object_unref(pipeline_);
> > > > > > > +         gst_deinit();
> > > > > > > + }
> > > > > > > +
> > > > > > > + int run() override
> > > > > > > + {
> > > > > > > +         GstStateChangeReturn ret;
> > > > > > > +         g_autoptr(GstBus) bus;
> > > > > > > +         g_autoptr(GstMessage) msg;
> > > > >
> > > > > I've also had to initialize those two variables to nullptr, to fix
> > > > >
> > > > > In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
> > > > >                  from /usr/include/glib-2.0/glib/gtypes.h:32,
> > > > >                  from /usr/include/glib-2.0/glib/galloca.h:32,
> > > > >                  from /usr/include/glib-2.0/glib.h:30,
> > > > >                  from /usr/include/gstreamer-1.0/gst/gst.h:27,
> > > > >                  from
> > > > ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
> > > > > /usr/include/glib-2.0/glib/gmacros.h: In member function ‘virtual int GstreamerSingleStreamTest::run()’:
> > > > > /usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
> > > > >  1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }
> > > >                                                 \
> > > > >       |       ^~
> > > > > ../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25: note: ‘msg’ was declared here
> > > > >   108 |   g_autoptr(GstMessage) msg;
> > > > >       |                         ^~~
> > > > >
> > > > > when cross-compiling for ARM.
> > > > >
> > > > > > > +
> > > > > > > +         /* Build the pipeline */
> > > > > > > +         gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL);
> > > > > > > +         if (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) {
> > > > > > > +                 g_printerr("Elements could not be linked.\n");
> > > > > > > +                 return TestFail;
> > > > > > > +         }
> > > > > > > +
> > > > > > > +         /* Start playing */
> > > > > > > +         ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> > > > > > > +         if (ret == GST_STATE_CHANGE_FAILURE) {
> > > > > > > +                 g_printerr("Unable to set the pipeline to the playing state.\n");
> > > > > > > +                 return TestFail;
> > > > > > > +         }
> > > > > > > +
> > > > > > > +         /* Wait until error or EOS or timeout after 2 seconds */
> > > > > > > +         GstClockTime timeout = 2000000000;
> > > > > > > +         bus = gst_element_get_bus(pipeline_);
> > > > > > > +         msg = gst_bus_timed_pop_filtered(bus, timeout,
> > > > > > > +                                          GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > > > > > > +         gst_element_set_state(pipeline_, GST_STATE_NULL);
> > > > > > > +
> > > > > > > +         /* Parse error message */
> > > > > > > +         if (msg == NULL)
> > > > > > > +                 return TestPass;
> > > > > > > +
> > > > > > > +         switch (GST_MESSAGE_TYPE(msg)) {
> > > > > > > +         case GST_MESSAGE_ERROR:
> > > > > > > +                 gstreamer_print_error(msg);
> > > > > > > +                 break;
> > > > > > > +         case GST_MESSAGE_EOS:
> > > > > > > +                 g_print("End-Of-Stream reached.\n");
> > > > > > > +                 break;
> > > > > > > +         default:
> > > > > > > +                 g_printerr("Unexpected message received.\n");
> > > > > > > +                 break;
> > > > > > > +         }
> > > > > > > +
> > > > > > > +         return TestFail;
> > > > > > > + }
> > > > > > > +
> > > > > > > +private:
> > > > > > > + void gstreamer_print_error(GstMessage *msg)
> > > > > > > + {
> > > > > > > +         GError *err;
> > > > > > > +         gchar *debug_info;
> > > > > > > +
> > > > > > > +         gst_message_parse_error(msg, &err, &debug_info);
> > > > > > > +         g_printerr("Error received from element %s: %s\n",
> > > > > > > +                    GST_OBJECT_NAME(msg->src), err->message);
> > > > > > > +         g_printerr("Debugging information: %s\n",
> > > > > > > +                    debug_info ? debug_info : "none");
> > > > > > > +         g_clear_error(&err);
> > > > > > > +         g_free(debug_info);
> > > > > > > + }
> > > > > > > +
> > > > > > > + GstElement *pipeline_;
> > > > > > > + GstElement *libcameraSrc_;
> > > > > > > + GstElement *convert0_;
> > > > > > > + GstElement *sink0_;
> > > > > > > +};
> > > > > > > +
> > > > > > > +TEST_REGISTER(GstreamerSingleStreamTest)
> > > > > > > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > > > > > > new file mode 100644
> > > > > > > index 00000000..b99aa0da
> > > > > > > --- /dev/null
> > > > > > > +++ b/test/gstreamer/meson.build
> > > > > > > @@ -0,0 +1,19 @@
> > > > > > > +# SPDX-License-Identifier: CC0-1.0
> > > > > > > +
> > > > > > > +if not gst_enabled
> > > > > > > +    subdir_done()
> > > > > > > +endif
> > > > > > > +
> > > > > > > +gstreamer_tests = [
> > > > > > > +    ['single_stream_test',  'gstreamer_single_stream_test.cpp'],
> > > > > > > +]
> > > > > > > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > > > > > > +
> > > > > > > +foreach t : gstreamer_tests
> > > > > > > +    exe = executable(t[0], t[1],
> > > > > > > +                     dependencies : [libcamera_private, gstreamer_dep],
> > > > > > > +                     link_with : test_libraries,
> > > > > > > +                     include_directories : test_includes_internal)
> > > > > > > +
> > > > > > > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > > > > > > +endforeach
> > > > > > > diff --git a/test/meson.build b/test/meson.build
> > > > > > > index 3bceb5df..d0466f17 100644
> > > > > > > --- a/test/meson.build
> > > > > > > +++ b/test/meson.build
> > > > > > > @@ -11,6 +11,7 @@ subdir('libtest')
> > > > > > >
> > > > > > >  subdir('camera')
> > > > > > >  subdir('controls')
> > > > > > > +subdir('gstreamer')
> > > > > > >  subdir('ipa')
> > > > > > >  subdir('ipc')
> > > > > > >  subdir('log')
Laurent Pinchart Aug. 13, 2021, 6:42 p.m. UTC | #12
On Fri, Aug 13, 2021 at 09:39:36PM +0300, Laurent Pinchart wrote:
> Hi Vedant,
> 
> On Fri, Aug 13, 2021 at 10:31:43PM +0530, Vedant Paranjape wrote:
> > Hi Laurent,
> > 
> > vedant@veware ~/Programming/contributing/libcamera$
> > ./build/test/gstreamer/single_stream_test
> >                                            ✹ ✭wip-negotiation
> > [11:45:45.304648653] [243629]  INFO IPAManager ipa_manager.cpp:138 libcamera is not installed. Adding '/home/vedant/Programming/contributing/libcamera/build/src/ipa' to the IPA search path
> > [11:45:45.306046376] [243629]  INFO Camera camera_manager.cpp:294 libcamera v0.0.0+2877-e3edb100-dirty (2021-08-13T22:11:47+05:30)
> > [11:45:45.319737506] [243632]  INFO Camera camera.cpp:870 configuring streams: (0) 640x360-YUYV
> 
> As discussed on IRC, that didn't have asan enabled.
> 
> Running
> 
> LD_DEBUG=libs ./test/gstreamer/single_stream_test
> 
> gives useful information. GStreamer spawns a new process,
> gst-plugin-scanner, to locate the libcamerasrc plugin. As gstreamer is
> compiled without asan, the gst-plugin-scanner process has lots of
> libraries loaded when it dlopen()s the plugin .so, which results in a
> failure in the asan library order sanity check, producing the messages
> 
> ==24099==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
> ==24100==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
> 
> I'm getting the exact same two messages when running gst-inspect or
> gst-launch. However,
> 
> gst-launch-1.0 --gst-plugin-path=$(pwd)/src/gstreamer/ libcamerasrc ! videoconvert ! fakesink
> 
> doesn't fail. There may thus be something we're doing wrong, or at least
> in a different way.

And replying to myself, the thing we're doing differently is loading the
gstreamer plugin from the build directory instead of the system plugins
location. When running the above command, gst-launch was using the
system plugin.

> > On Fri, Aug 13, 2021 at 10:28 PM Laurent Pinchart wrote:
> > > On Fri, Aug 13, 2021 at 10:14:09PM +0530, Vedant Paranjape wrote:
> > > > Hi Laurent,
> > > > I was unable to reproduce the issue with address sanitizer.
> > > >
> > > > Steps I followed:
> > > > 1) meson --reconfigure build -Db_sanitize=address
> > > > 2) ninja -C build test
> > >
> > > What's the full output of the gstreamer test when you run it manually ?
> > >
> > > > On Fri, Aug 13, 2021 at 8:07 PM Laurent Pinchart wrote:
> > > > > On Fri, Aug 13, 2021 at 05:04:01PM +0300, Laurent Pinchart wrote:
> > > > > > On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> > > > > > > Hi Vedant,
> > > > > > >
> > > > > > > Thank you for the patch.
> > > > > > >
> > > > > > > On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape wrote:
> > > > > > > > This patch adds a test to test if single stream using
> > > > > > > > libcamera's gstreamer element works.
> > > > > > > >
> > > > > > > > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com
> > > > > > > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > > > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > > > > > ---
> > > > > > > >  .../gstreamer_single_stream_test.cpp          | 153 ++++++++++++++++++
> > > > > > > >  test/gstreamer/meson.build                    |  19 +++
> > > > > > > >  test/meson.build                              |   1 +
> > > > > > > >  3 files changed, 173 insertions(+)
> > > > > > > >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > > >  create mode 100644 test/gstreamer/meson.build
> > > > > > > >
> > > > > > > > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > > > new file mode 100644
> > > > > > > > index 00000000..eecd3274
> > > > > > > > --- /dev/null
> > > > > > > > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > > > @@ -0,0 +1,153 @@
> > > > > > > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > > > > > > +/*
> > > > > > > > + * Copyright (C) 2021, Vedant Paranjape
> > > > > > > > + *
> > > > > > > > + * ipa_interface_test.cpp - Test the IPA interface
> > > > > > > > + */
> > > > > > > > +
> > > > > > > > +#include <iostream>
> > > > > > > > +
> > > > > > > > +#include <libcamera/base/utils.h>
> > > > > > > > +
> > > > > > > > +#include <gst/gst.h>
> > > > > > > > +
> > > > > > > > +#include "test.h"
> > > > > > > > +
> > > > > > > > +using namespace std;
> > > > > > > > +
> > > > > > > > +class GstreamerSingleStreamTest : public Test
> > > > > > > > +{
> > > > > > > > +protected:
> > > > > > > > + int init() override
> > > > > > > > + {
> > > > > > > > +         /* Initialize GStreamer */
> > > > > > > > +         GError *errInit = nullptr;
> > > > > > > > +         if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > > > > > > > +                 g_printerr("Could not initialize GStreamer: %s\n",
> > > > > > > > +                            errInit ? errInit->message : "unknown error");
> > > > > > > > +                 if (errInit)
> > > > > > > > +                         g_error_free(errInit);
> > > > > > > > +
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         /*
> > > > > > > > +         * Remove the system libcamera plugin, if any, and add the
> > > > > > > > +         * plugin from the build directory.
> > > > > > > > +         */
> > > > > > >
> > > > > > > Missing space before *
> > > > > > >
> > > > > > > > +         GstRegistry *registry = gst_registry_get();
> > > > > > > > +         GstPlugin *plugin = gst_registry_lookup(registry, "libgstlibcamera.so");
> > > > > > > > +         if (plugin) {
> > > > > > > > +                 gst_registry_remove_plugin(registry, plugin);
> > > > > > > > +                 gst_object_unref(plugin);
> > > > > > > > +         }
> > > > > > > > +
> > > > > > >
> > > > > > > Extra blank spaces at the end of the line.
> > > > > > >
> > > > > > > > +         std::string path = std::string(libcamera::utils::libcameraBuildPath()
> > > > > > > > +                                 + "src/gstreamer");
> > > > > > >
> > > > > > > No need for calling the std::string constructor explictly,
> > > > > > > libcamera::utils::libcameraBuildPath() returns an std::string and the
> > > > > > > result of the operator+() call is also an std::string.
> > > > > > >
> > > > > > > You should #include "libcamera/internal/source_paths.h"" for
> > > > > > > libcamera::utils::libcameraBuildPath().
> > > > > > >
> > > > > > > I'll fix these small issues when applying.
> > > > > > >
> > > > > > > > +         if (!gst_registry_scan_path(registry, path.c_str())) {
> > > > > > > > +                 g_printerr("Failed to add plugin to registry\n");
> > > > > > > > +                 gst_deinit();
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         /* Create the elements */
> > > > > > > > +         libcameraSrc_ = gst_element_factory_make("libcamerasrc", "libcamera");
> > > > >
> > > > > And now I'm getting a failure here :-( When compiling with gcc, and with
> > > > > the meson b_sanitize option set to 'address', this call returns null.
> > > > >
> > > > > 10/64 libcamera:gstreamer / single_stream_test
> > > > >  FAIL            0.48s   exit status 1
> > > > > >>> MALLOC_PERTURB_=101
> > > > > build/x86-gcc-11.1.0/test/gstreamer/single_stream_test
> > > > > ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ✀ ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > > > > stderr:
> > > > > ==14992==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
> > > > > ==14993==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
> > > > > Not all elements could be created. 0x6290000241f0.0x61a000019950.0x61a00001a670.(nil)
> > > > >
> > > > > =================================================================
> > > > > ==14990==ERROR: LeakSanitizer: detected memory leaks
> > > > >
> > > > > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> > > > >     #0 0x7f9daade1ac7 in __interceptor_malloc
> > > > > /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> > > > >     #1 0x7f9da776a938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> > > > >
> > > > > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> > > > >
> > > > > ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > > > >
> > > > > 11/64 libcamera:ipa / ipa_module_test
> > > > > OK              0.08s
> > > > >
> > > > > Interestingly, if I run the test with
> > > > >
> > > > > LD_PRELOAD=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/libasan.so.6
> > > > > ./test/gstreamer/single_stream_test
> > > > >
> > > > > then is runs fine:
> > > > >
> > > > > [25:59:46.412146534] [18711]  INFO IPAManager ipa_manager.cpp:138 libcamera is not installed. Adding '[...]/build/x86-gcc-11.1.0/src/ipa' to the IPA search path
> > > > > [25:59:46.413634330] [18711]  INFO Camera camera_manager.cpp:294 libcamera v0.0.0+2881-24c1e91b-dirty (2021-08-13T17:24:37+03:00)
> > > > > [25:59:46.663097368] [18714]  WARN CameraSensorProperties camera_sensor_properties.cpp:123 No static properties available for 'Sensor B'
> > > > > [25:59:46.663129122] [18714]  WARN CameraSensorProperties camera_sensor_properties.cpp:125 Please consider updating the camera sensor properties database
> > > > > [25:59:46.663156409] [18714]  WARN CameraSensor camera_sensor.cpp:403 'Sensor B': Failed to retrieve the camera location
> > > > > [25:59:46.664891182] [18714]  INFO IPAProxy ipa_proxy.cpp:130 libcamera is not installed. Loading IPA configuration from '[...]/src/ipa/vimc/data'
> > > > > [25:59:46.680563655] [18715]  INFO Camera camera.cpp:870 configuring streams: (0) 160x120-YUYV
> > > > >
> > > > > =================================================================
> > > > > ==18711==ERROR: LeakSanitizer: detected memory leaks
> > > > >
> > > > > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> > > > >     #0 0x7effa6393ac7 in __interceptor_malloc
> > > > > /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> > > > >     #1 0x7effa57be938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> > > > >
> > > > > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> > > > >
> > > > > The leak is a known glib issue, caught by valgrind too, so I'm not
> > > > > worried about it. The test failing to run is however a blocker.
> > > > >
> > > > > Vedant, can you reproduce the failure with the address sanitizer ?
> > > > >
> > > > > > > > +         convert0_ = gst_element_factory_make("videoconvert", "convert0");
> > > > > > > > +         sink0_ = gst_element_factory_make("fakesink", "sink0");
> > > > > > > > +
> > > > > > > > +         /* Create the empty pipeline_ */
> > > > > > > > +         pipeline_ = gst_pipeline_new("test-pipeline");
> > > > > > > > +
> > > > > > > > +         if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) {
> > > > > > > > +                 g_printerr("Not all elements could be created. %p.%p.%p.%p\n",
> > > > > > > > +                            pipeline_, convert0_, sink0_, libcameraSrc_);
> > > > > > > > +                 if (pipeline_)
> > > > > > > > +                         gst_object_unref(pipeline_);
> > > > > > > > +                 if (convert0_)
> > > > > > > > +                         gst_object_unref(convert0_);
> > > > > > > > +                 if (sink0_)
> > > > > > > > +                         gst_object_unref(sink0_);
> > > > > > > > +                 if (libcameraSrc_)
> > > > > > > > +                         gst_object_unref(libcameraSrc_);
> > > > > > > > +                 gst_deinit();
> > > > > > > > +
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         return TestPass;
> > > > > > > > + }
> > > > > > > > +
> > > > > > > > + void cleanup() override
> > > > > > > > + {
> > > > > > > > +         gst_object_unref(pipeline_);
> > > > > > > > +         gst_deinit();
> > > > > > > > + }
> > > > > > > > +
> > > > > > > > + int run() override
> > > > > > > > + {
> > > > > > > > +         GstStateChangeReturn ret;
> > > > > > > > +         g_autoptr(GstBus) bus;
> > > > > > > > +         g_autoptr(GstMessage) msg;
> > > > > >
> > > > > > I've also had to initialize those two variables to nullptr, to fix
> > > > > >
> > > > > > In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
> > > > > >                  from /usr/include/glib-2.0/glib/gtypes.h:32,
> > > > > >                  from /usr/include/glib-2.0/glib/galloca.h:32,
> > > > > >                  from /usr/include/glib-2.0/glib.h:30,
> > > > > >                  from /usr/include/gstreamer-1.0/gst/gst.h:27,
> > > > > >                  from
> > > > > ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
> > > > > > /usr/include/glib-2.0/glib/gmacros.h: In member function ‘virtual int GstreamerSingleStreamTest::run()’:
> > > > > > /usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
> > > > > >  1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }
> > > > >                                                 \
> > > > > >       |       ^~
> > > > > > ../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25: note: ‘msg’ was declared here
> > > > > >   108 |   g_autoptr(GstMessage) msg;
> > > > > >       |                         ^~~
> > > > > >
> > > > > > when cross-compiling for ARM.
> > > > > >
> > > > > > > > +
> > > > > > > > +         /* Build the pipeline */
> > > > > > > > +         gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL);
> > > > > > > > +         if (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) {
> > > > > > > > +                 g_printerr("Elements could not be linked.\n");
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         /* Start playing */
> > > > > > > > +         ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
> > > > > > > > +         if (ret == GST_STATE_CHANGE_FAILURE) {
> > > > > > > > +                 g_printerr("Unable to set the pipeline to the playing state.\n");
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         /* Wait until error or EOS or timeout after 2 seconds */
> > > > > > > > +         GstClockTime timeout = 2000000000;
> > > > > > > > +         bus = gst_element_get_bus(pipeline_);
> > > > > > > > +         msg = gst_bus_timed_pop_filtered(bus, timeout,
> > > > > > > > +                                          GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > > > > > > > +         gst_element_set_state(pipeline_, GST_STATE_NULL);
> > > > > > > > +
> > > > > > > > +         /* Parse error message */
> > > > > > > > +         if (msg == NULL)
> > > > > > > > +                 return TestPass;
> > > > > > > > +
> > > > > > > > +         switch (GST_MESSAGE_TYPE(msg)) {
> > > > > > > > +         case GST_MESSAGE_ERROR:
> > > > > > > > +                 gstreamer_print_error(msg);
> > > > > > > > +                 break;
> > > > > > > > +         case GST_MESSAGE_EOS:
> > > > > > > > +                 g_print("End-Of-Stream reached.\n");
> > > > > > > > +                 break;
> > > > > > > > +         default:
> > > > > > > > +                 g_printerr("Unexpected message received.\n");
> > > > > > > > +                 break;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         return TestFail;
> > > > > > > > + }
> > > > > > > > +
> > > > > > > > +private:
> > > > > > > > + void gstreamer_print_error(GstMessage *msg)
> > > > > > > > + {
> > > > > > > > +         GError *err;
> > > > > > > > +         gchar *debug_info;
> > > > > > > > +
> > > > > > > > +         gst_message_parse_error(msg, &err, &debug_info);
> > > > > > > > +         g_printerr("Error received from element %s: %s\n",
> > > > > > > > +                    GST_OBJECT_NAME(msg->src), err->message);
> > > > > > > > +         g_printerr("Debugging information: %s\n",
> > > > > > > > +                    debug_info ? debug_info : "none");
> > > > > > > > +         g_clear_error(&err);
> > > > > > > > +         g_free(debug_info);
> > > > > > > > + }
> > > > > > > > +
> > > > > > > > + GstElement *pipeline_;
> > > > > > > > + GstElement *libcameraSrc_;
> > > > > > > > + GstElement *convert0_;
> > > > > > > > + GstElement *sink0_;
> > > > > > > > +};
> > > > > > > > +
> > > > > > > > +TEST_REGISTER(GstreamerSingleStreamTest)
> > > > > > > > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > > > > > > > new file mode 100644
> > > > > > > > index 00000000..b99aa0da
> > > > > > > > --- /dev/null
> > > > > > > > +++ b/test/gstreamer/meson.build
> > > > > > > > @@ -0,0 +1,19 @@
> > > > > > > > +# SPDX-License-Identifier: CC0-1.0
> > > > > > > > +
> > > > > > > > +if not gst_enabled
> > > > > > > > +    subdir_done()
> > > > > > > > +endif
> > > > > > > > +
> > > > > > > > +gstreamer_tests = [
> > > > > > > > +    ['single_stream_test',  'gstreamer_single_stream_test.cpp'],
> > > > > > > > +]
> > > > > > > > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > > > > > > > +
> > > > > > > > +foreach t : gstreamer_tests
> > > > > > > > +    exe = executable(t[0], t[1],
> > > > > > > > +                     dependencies : [libcamera_private, gstreamer_dep],
> > > > > > > > +                     link_with : test_libraries,
> > > > > > > > +                     include_directories : test_includes_internal)
> > > > > > > > +
> > > > > > > > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
> > > > > > > > +endforeach
> > > > > > > > diff --git a/test/meson.build b/test/meson.build
> > > > > > > > index 3bceb5df..d0466f17 100644
> > > > > > > > --- a/test/meson.build
> > > > > > > > +++ b/test/meson.build
> > > > > > > > @@ -11,6 +11,7 @@ subdir('libtest')
> > > > > > > >
> > > > > > > >  subdir('camera')
> > > > > > > >  subdir('controls')
> > > > > > > > +subdir('gstreamer')
> > > > > > > >  subdir('ipa')
> > > > > > > >  subdir('ipc')
> > > > > > > >  subdir('log')
Vedant Paranjape Aug. 13, 2021, 6:42 p.m. UTC | #13
Hi Laurent,


On Sat, Aug 14, 2021 at 12:09 AM Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> Hi Vedant,
>
> On Fri, Aug 13, 2021 at 10:31:43PM +0530, Vedant Paranjape wrote:
> > Hi Laurent,
> >
> > vedant@veware ~/Programming/contributing/libcamera$
> > ./build/test/gstreamer/single_stream_test
> >                                            ✹ ✭wip-negotiation
> > [11:45:45.304648653] [243629]  INFO IPAManager ipa_manager.cpp:138
> libcamera is not installed. Adding
> '/home/vedant/Programming/contributing/libcamera/build/src/ipa' to the IPA
> search path
> > [11:45:45.306046376] [243629]  INFO Camera camera_manager.cpp:294
> libcamera v0.0.0+2877-e3edb100-dirty (2021-08-13T22:11:47+05:30)
> > [11:45:45.319737506] [243632]  INFO Camera camera.cpp:870 configuring
> streams: (0) 640x360-YUYV
>
> As discussed on IRC, that didn't have asan enabled.
>
> Running
>
> LD_DEBUG=libs ./test/gstreamer/single_stream_test
>
> gives useful information. GStreamer spawns a new process,
> gst-plugin-scanner, to locate the libcamerasrc plugin. As gstreamer is
> compiled without asan, the gst-plugin-scanner process has lots of
> libraries loaded when it dlopen()s the plugin .so, which results in a
> failure in the asan library order sanity check, producing the messages
>
> ==24099==ASan runtime does not come first in initial library list; you
> should either link runtime to your application or manually preload it with
> LD_PRELOAD.
> ==24100==ASan runtime does not come first in initial library list; you
> should either link runtime to your application or manually preload it with
> LD_PRELOAD.
>
> I'm getting the exact same two messages when running gst-inspect or
> gst-launch. However,
>
> gst-launch-1.0 --gst-plugin-path=$(pwd)/src/gstreamer/ libcamerasrc !
> videoconvert ! fakesink
>
> doesn't fail. There may thus be something we're doing wrong, or at least
> in a different way.
>

I think somehow in this case libasan is loaded first then gstreamer looks
for plugins.

> On Fri, Aug 13, 2021 at 10:28 PM Laurent Pinchart wrote:
> > > On Fri, Aug 13, 2021 at 10:14:09PM +0530, Vedant Paranjape wrote:
> > > > Hi Laurent,
> > > > I was unable to reproduce the issue with address sanitizer.
> > > >
> > > > Steps I followed:
> > > > 1) meson --reconfigure build -Db_sanitize=address
> > > > 2) ninja -C build test
> > >
> > > What's the full output of the gstreamer test when you run it manually ?
> > >
> > > > On Fri, Aug 13, 2021 at 8:07 PM Laurent Pinchart wrote:
> > > > > On Fri, Aug 13, 2021 at 05:04:01PM +0300, Laurent Pinchart wrote:
> > > > > > On Fri, Aug 13, 2021 at 03:57:22PM +0300, Laurent Pinchart wrote:
> > > > > > > Hi Vedant,
> > > > > > >
> > > > > > > Thank you for the patch.
> > > > > > >
> > > > > > > On Fri, Aug 13, 2021 at 04:13:02PM +0530, Vedant Paranjape
> wrote:
> > > > > > > > This patch adds a test to test if single stream using
> > > > > > > > libcamera's gstreamer element works.
> > > > > > > >
> > > > > > > > Signed-off-by: Vedant Paranjape <
> vedantparanjape160201@gmail.com
> > > > > > > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
> > > > > > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com
> >
> > > > > > > > ---
> > > > > > > >  .../gstreamer_single_stream_test.cpp          | 153
> ++++++++++++++++++
> > > > > > > >  test/gstreamer/meson.build                    |  19 +++
> > > > > > > >  test/meson.build                              |   1 +
> > > > > > > >  3 files changed, 173 insertions(+)
> > > > > > > >  create mode 100644
> test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > > >  create mode 100644 test/gstreamer/meson.build
> > > > > > > >
> > > > > > > > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp
> b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > > > new file mode 100644
> > > > > > > > index 00000000..eecd3274
> > > > > > > > --- /dev/null
> > > > > > > > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp
> > > > > > > > @@ -0,0 +1,153 @@
> > > > > > > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > > > > > > +/*
> > > > > > > > + * Copyright (C) 2021, Vedant Paranjape
> > > > > > > > + *
> > > > > > > > + * ipa_interface_test.cpp - Test the IPA interface
> > > > > > > > + */
> > > > > > > > +
> > > > > > > > +#include <iostream>
> > > > > > > > +
> > > > > > > > +#include <libcamera/base/utils.h>
> > > > > > > > +
> > > > > > > > +#include <gst/gst.h>
> > > > > > > > +
> > > > > > > > +#include "test.h"
> > > > > > > > +
> > > > > > > > +using namespace std;
> > > > > > > > +
> > > > > > > > +class GstreamerSingleStreamTest : public Test
> > > > > > > > +{
> > > > > > > > +protected:
> > > > > > > > + int init() override
> > > > > > > > + {
> > > > > > > > +         /* Initialize GStreamer */
> > > > > > > > +         GError *errInit = nullptr;
> > > > > > > > +         if (!gst_init_check(nullptr, nullptr, &errInit)) {
> > > > > > > > +                 g_printerr("Could not initialize
> GStreamer: %s\n",
> > > > > > > > +                            errInit ? errInit->message :
> "unknown error");
> > > > > > > > +                 if (errInit)
> > > > > > > > +                         g_error_free(errInit);
> > > > > > > > +
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         /*
> > > > > > > > +         * Remove the system libcamera plugin, if any, and
> add the
> > > > > > > > +         * plugin from the build directory.
> > > > > > > > +         */
> > > > > > >
> > > > > > > Missing space before *
> > > > > > >
> > > > > > > > +         GstRegistry *registry = gst_registry_get();
> > > > > > > > +         GstPlugin *plugin = gst_registry_lookup(registry,
> "libgstlibcamera.so");
> > > > > > > > +         if (plugin) {
> > > > > > > > +                 gst_registry_remove_plugin(registry,
> plugin);
> > > > > > > > +                 gst_object_unref(plugin);
> > > > > > > > +         }
> > > > > > > > +
> > > > > > >
> > > > > > > Extra blank spaces at the end of the line.
> > > > > > >
> > > > > > > > +         std::string path =
> std::string(libcamera::utils::libcameraBuildPath()
> > > > > > > > +                                 + "src/gstreamer");
> > > > > > >
> > > > > > > No need for calling the std::string constructor explictly,
> > > > > > > libcamera::utils::libcameraBuildPath() returns an std::string
> and the
> > > > > > > result of the operator+() call is also an std::string.
> > > > > > >
> > > > > > > You should #include "libcamera/internal/source_paths.h"" for
> > > > > > > libcamera::utils::libcameraBuildPath().
> > > > > > >
> > > > > > > I'll fix these small issues when applying.
> > > > > > >
> > > > > > > > +         if (!gst_registry_scan_path(registry,
> path.c_str())) {
> > > > > > > > +                 g_printerr("Failed to add plugin to
> registry\n");
> > > > > > > > +                 gst_deinit();
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         /* Create the elements */
> > > > > > > > +         libcameraSrc_ =
> gst_element_factory_make("libcamerasrc", "libcamera");
> > > > >
> > > > > And now I'm getting a failure here :-( When compiling with gcc,
> and with
> > > > > the meson b_sanitize option set to 'address', this call returns
> null.
> > > > >
> > > > > 10/64 libcamera:gstreamer / single_stream_test
> > > > >  FAIL            0.48s   exit status 1
> > > > > >>> MALLOC_PERTURB_=101
> > > > > build/x86-gcc-11.1.0/test/gstreamer/single_stream_test
> > > > >
> ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> ✀
> ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > > > > stderr:
> > > > > ==14992==ASan runtime does not come first in initial library list;
> you should either link runtime to your application or manually preload it
> with LD_PRELOAD.
> > > > > ==14993==ASan runtime does not come first in initial library list;
> you should either link runtime to your application or manually preload it
> with LD_PRELOAD.
> > > > > Not all elements could be created.
> 0x6290000241f0.0x61a000019950.0x61a00001a670.(nil)
> > > > >
> > > > > =================================================================
> > > > > ==14990==ERROR: LeakSanitizer: detected memory leaks
> > > > >
> > > > > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> > > > >     #0 0x7f9daade1ac7 in __interceptor_malloc
> > > > >
> /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> > > > >     #1 0x7f9da776a938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> > > > >
> > > > > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> > > > >
> > > > >
> ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
> > > > >
> > > > > 11/64 libcamera:ipa / ipa_module_test
> > > > > OK              0.08s
> > > > >
> > > > > Interestingly, if I run the test with
> > > > >
> > > > > LD_PRELOAD=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/libasan.so.6
> > > > > ./test/gstreamer/single_stream_test
> > > > >
> > > > > then is runs fine:
> > > > >
> > > > > [25:59:46.412146534] [18711]  INFO IPAManager ipa_manager.cpp:138
> libcamera is not installed. Adding '[...]/build/x86-gcc-11.1.0/src/ipa' to
> the IPA search path
> > > > > [25:59:46.413634330] [18711]  INFO Camera camera_manager.cpp:294
> libcamera v0.0.0+2881-24c1e91b-dirty (2021-08-13T17:24:37+03:00)
> > > > > [25:59:46.663097368] [18714]  WARN CameraSensorProperties
> camera_sensor_properties.cpp:123 No static properties available for 'Sensor
> B'
> > > > > [25:59:46.663129122] [18714]  WARN CameraSensorProperties
> camera_sensor_properties.cpp:125 Please consider updating the camera sensor
> properties database
> > > > > [25:59:46.663156409] [18714]  WARN CameraSensor
> camera_sensor.cpp:403 'Sensor B': Failed to retrieve the camera location
> > > > > [25:59:46.664891182] [18714]  INFO IPAProxy ipa_proxy.cpp:130
> libcamera is not installed. Loading IPA configuration from
> '[...]/src/ipa/vimc/data'
> > > > > [25:59:46.680563655] [18715]  INFO Camera camera.cpp:870
> configuring streams: (0) 160x120-YUYV
> > > > >
> > > > > =================================================================
> > > > > ==18711==ERROR: LeakSanitizer: detected memory leaks
> > > > >
> > > > > Direct leak of 16384 byte(s) in 1 object(s) allocated from:
> > > > >     #0 0x7effa6393ac7 in __interceptor_malloc
> > > > >
> /var/tmp/portage/sys-devel/gcc-11.1.0-r2/work/gcc-11.1.0/libsanitizer/asan/asan_malloc_linux.cpp:145
> > > > >     #1 0x7effa57be938 in g_malloc ../glib-2.68.3/glib/gmem.c:106
> > > > >
> > > > > SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).
> > > > >
> > > > > The leak is a known glib issue, caught by valgrind too, so I'm not
> > > > > worried about it. The test failing to run is however a blocker.
> > > > >
> > > > > Vedant, can you reproduce the failure with the address sanitizer ?
> > > > >
> > > > > > > > +         convert0_ =
> gst_element_factory_make("videoconvert", "convert0");
> > > > > > > > +         sink0_ = gst_element_factory_make("fakesink",
> "sink0");
> > > > > > > > +
> > > > > > > > +         /* Create the empty pipeline_ */
> > > > > > > > +         pipeline_ = gst_pipeline_new("test-pipeline");
> > > > > > > > +
> > > > > > > > +         if (!pipeline_ || !convert0_ || !sink0_ ||
> !libcameraSrc_) {
> > > > > > > > +                 g_printerr("Not all elements could be
> created. %p.%p.%p.%p\n",
> > > > > > > > +                            pipeline_, convert0_, sink0_,
> libcameraSrc_);
> > > > > > > > +                 if (pipeline_)
> > > > > > > > +                         gst_object_unref(pipeline_);
> > > > > > > > +                 if (convert0_)
> > > > > > > > +                         gst_object_unref(convert0_);
> > > > > > > > +                 if (sink0_)
> > > > > > > > +                         gst_object_unref(sink0_);
> > > > > > > > +                 if (libcameraSrc_)
> > > > > > > > +                         gst_object_unref(libcameraSrc_);
> > > > > > > > +                 gst_deinit();
> > > > > > > > +
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         return TestPass;
> > > > > > > > + }
> > > > > > > > +
> > > > > > > > + void cleanup() override
> > > > > > > > + {
> > > > > > > > +         gst_object_unref(pipeline_);
> > > > > > > > +         gst_deinit();
> > > > > > > > + }
> > > > > > > > +
> > > > > > > > + int run() override
> > > > > > > > + {
> > > > > > > > +         GstStateChangeReturn ret;
> > > > > > > > +         g_autoptr(GstBus) bus;
> > > > > > > > +         g_autoptr(GstMessage) msg;
> > > > > >
> > > > > > I've also had to initialize those two variables to nullptr, to
> fix
> > > > > >
> > > > > > In file included from /usr/lib/glib-2.0/include/glibconfig.h:9,
> > > > > >                  from /usr/include/glib-2.0/glib/gtypes.h:32,
> > > > > >                  from /usr/include/glib-2.0/glib/galloca.h:32,
> > > > > >                  from /usr/include/glib-2.0/glib.h:30,
> > > > > >                  from /usr/include/gstreamer-1.0/gst/gst.h:27,
> > > > > >                  from
> > > > > ../../test/gstreamer/gstreamer_single_stream_test.cpp:14:
> > > > > > /usr/include/glib-2.0/glib/gmacros.h: In member function
> ‘virtual int GstreamerSingleStreamTest::run()’:
> > > > > > /usr/include/glib-2.0/glib/gmacros.h:1045:7: error: ‘msg’ may be
> used uninitialized in this function [-Werror=maybe-uninitialized]
> > > > > >  1045 |     { if (_ptr) (cleanup) ((ParentName *) _ptr); }
> > > > >                                                 \
> > > > > >       |       ^~
> > > > > > ../../test/gstreamer/gstreamer_single_stream_test.cpp:108:25:
> note: ‘msg’ was declared here
> > > > > >   108 |   g_autoptr(GstMessage) msg;
> > > > > >       |                         ^~~
> > > > > >
> > > > > > when cross-compiling for ARM.
> > > > > >
> > > > > > > > +
> > > > > > > > +         /* Build the pipeline */
> > > > > > > > +         gst_bin_add_many(GST_BIN(pipeline_),
> libcameraSrc_, convert0_, sink0_, NULL);
> > > > > > > > +         if (gst_element_link_many(libcameraSrc_,
> convert0_, sink0_, NULL) != TRUE) {
> > > > > > > > +                 g_printerr("Elements could not be
> linked.\n");
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         /* Start playing */
> > > > > > > > +         ret = gst_element_set_state(pipeline_,
> GST_STATE_PLAYING);
> > > > > > > > +         if (ret == GST_STATE_CHANGE_FAILURE) {
> > > > > > > > +                 g_printerr("Unable to set the pipeline to
> the playing state.\n");
> > > > > > > > +                 return TestFail;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         /* Wait until error or EOS or timeout after 2
> seconds */
> > > > > > > > +         GstClockTime timeout = 2000000000;
> > > > > > > > +         bus = gst_element_get_bus(pipeline_);
> > > > > > > > +         msg = gst_bus_timed_pop_filtered(bus, timeout,
> > > > > > > > +
> GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
> > > > > > > > +         gst_element_set_state(pipeline_, GST_STATE_NULL);
> > > > > > > > +
> > > > > > > > +         /* Parse error message */
> > > > > > > > +         if (msg == NULL)
> > > > > > > > +                 return TestPass;
> > > > > > > > +
> > > > > > > > +         switch (GST_MESSAGE_TYPE(msg)) {
> > > > > > > > +         case GST_MESSAGE_ERROR:
> > > > > > > > +                 gstreamer_print_error(msg);
> > > > > > > > +                 break;
> > > > > > > > +         case GST_MESSAGE_EOS:
> > > > > > > > +                 g_print("End-Of-Stream reached.\n");
> > > > > > > > +                 break;
> > > > > > > > +         default:
> > > > > > > > +                 g_printerr("Unexpected message
> received.\n");
> > > > > > > > +                 break;
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         return TestFail;
> > > > > > > > + }
> > > > > > > > +
> > > > > > > > +private:
> > > > > > > > + void gstreamer_print_error(GstMessage *msg)
> > > > > > > > + {
> > > > > > > > +         GError *err;
> > > > > > > > +         gchar *debug_info;
> > > > > > > > +
> > > > > > > > +         gst_message_parse_error(msg, &err, &debug_info);
> > > > > > > > +         g_printerr("Error received from element %s: %s\n",
> > > > > > > > +                    GST_OBJECT_NAME(msg->src),
> err->message);
> > > > > > > > +         g_printerr("Debugging information: %s\n",
> > > > > > > > +                    debug_info ? debug_info : "none");
> > > > > > > > +         g_clear_error(&err);
> > > > > > > > +         g_free(debug_info);
> > > > > > > > + }
> > > > > > > > +
> > > > > > > > + GstElement *pipeline_;
> > > > > > > > + GstElement *libcameraSrc_;
> > > > > > > > + GstElement *convert0_;
> > > > > > > > + GstElement *sink0_;
> > > > > > > > +};
> > > > > > > > +
> > > > > > > > +TEST_REGISTER(GstreamerSingleStreamTest)
> > > > > > > > diff --git a/test/gstreamer/meson.build
> b/test/gstreamer/meson.build
> > > > > > > > new file mode 100644
> > > > > > > > index 00000000..b99aa0da
> > > > > > > > --- /dev/null
> > > > > > > > +++ b/test/gstreamer/meson.build
> > > > > > > > @@ -0,0 +1,19 @@
> > > > > > > > +# SPDX-License-Identifier: CC0-1.0
> > > > > > > > +
> > > > > > > > +if not gst_enabled
> > > > > > > > +    subdir_done()
> > > > > > > > +endif
> > > > > > > > +
> > > > > > > > +gstreamer_tests = [
> > > > > > > > +    ['single_stream_test',
> 'gstreamer_single_stream_test.cpp'],
> > > > > > > > +]
> > > > > > > > +gstreamer_dep = dependency('gstreamer-1.0', required: true)
> > > > > > > > +
> > > > > > > > +foreach t : gstreamer_tests
> > > > > > > > +    exe = executable(t[0], t[1],
> > > > > > > > +                     dependencies : [libcamera_private,
> gstreamer_dep],
> > > > > > > > +                     link_with : test_libraries,
> > > > > > > > +                     include_directories :
> test_includes_internal)
> > > > > > > > +
> > > > > > > > +    test(t[0], exe, suite : 'gstreamer', is_parallel :
> false)
> > > > > > > > +endforeach
> > > > > > > > diff --git a/test/meson.build b/test/meson.build
> > > > > > > > index 3bceb5df..d0466f17 100644
> > > > > > > > --- a/test/meson.build
> > > > > > > > +++ b/test/meson.build
> > > > > > > > @@ -11,6 +11,7 @@ subdir('libtest')
> > > > > > > >
> > > > > > > >  subdir('camera')
> > > > > > > >  subdir('controls')
> > > > > > > > +subdir('gstreamer')
> > > > > > > >  subdir('ipa')
> > > > > > > >  subdir('ipc')
> > > > > > > >  subdir('log')
>
> --
> Regards,
>
> Laurent Pinchart
>

Patch
diff mbox series

diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp
new file mode 100644
index 00000000..eecd3274
--- /dev/null
+++ b/test/gstreamer/gstreamer_single_stream_test.cpp
@@ -0,0 +1,153 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2021, Vedant Paranjape
+ *
+ * ipa_interface_test.cpp - Test the IPA interface
+ */
+
+#include <iostream>
+
+#include <libcamera/base/utils.h>
+
+#include <gst/gst.h>
+
+#include "test.h"
+
+using namespace std;
+
+class GstreamerSingleStreamTest : public Test
+{
+protected:
+	int init() override
+	{
+		/* Initialize GStreamer */
+		GError *errInit = nullptr;
+		if (!gst_init_check(nullptr, nullptr, &errInit)) {
+			g_printerr("Could not initialize GStreamer: %s\n",
+				   errInit ? errInit->message : "unknown error");
+			if (errInit)
+				g_error_free(errInit);
+
+			return TestFail;
+		}
+
+		/*
+		* Remove the system libcamera plugin, if any, and add the
+		* plugin from the build directory.
+		*/
+		GstRegistry *registry = gst_registry_get();
+		GstPlugin *plugin = gst_registry_lookup(registry, "libgstlibcamera.so");
+		if (plugin) {
+			gst_registry_remove_plugin(registry, plugin);
+			gst_object_unref(plugin);
+		}
+		
+		std::string path = std::string(libcamera::utils::libcameraBuildPath()
+					+ "src/gstreamer");
+		if (!gst_registry_scan_path(registry, path.c_str())) {
+			g_printerr("Failed to add plugin to registry\n");
+			gst_deinit();
+			return TestFail;
+		}
+
+		/* Create the elements */
+		libcameraSrc_ = gst_element_factory_make("libcamerasrc", "libcamera");
+		convert0_ = gst_element_factory_make("videoconvert", "convert0");
+		sink0_ = gst_element_factory_make("fakesink", "sink0");
+
+		/* Create the empty pipeline_ */
+		pipeline_ = gst_pipeline_new("test-pipeline");
+
+		if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) {
+			g_printerr("Not all elements could be created. %p.%p.%p.%p\n",
+				   pipeline_, convert0_, sink0_, libcameraSrc_);
+			if (pipeline_)
+				gst_object_unref(pipeline_);
+			if (convert0_)
+				gst_object_unref(convert0_);
+			if (sink0_)
+				gst_object_unref(sink0_);
+			if (libcameraSrc_)
+				gst_object_unref(libcameraSrc_);
+			gst_deinit();
+
+			return TestFail;
+		}
+
+		return TestPass;
+	}
+
+	void cleanup() override
+	{
+		gst_object_unref(pipeline_);
+		gst_deinit();
+	}
+
+	int run() override
+	{
+		GstStateChangeReturn ret;
+		g_autoptr(GstBus) bus;
+		g_autoptr(GstMessage) msg;
+
+		/* Build the pipeline */
+		gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL);
+		if (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) {
+			g_printerr("Elements could not be linked.\n");
+			return TestFail;
+		}
+
+		/* Start playing */
+		ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
+		if (ret == GST_STATE_CHANGE_FAILURE) {
+			g_printerr("Unable to set the pipeline to the playing state.\n");
+			return TestFail;
+		}
+
+		/* Wait until error or EOS or timeout after 2 seconds */
+		GstClockTime timeout = 2000000000;
+		bus = gst_element_get_bus(pipeline_);
+		msg = gst_bus_timed_pop_filtered(bus, timeout,
+						 GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));
+		gst_element_set_state(pipeline_, GST_STATE_NULL);
+
+		/* Parse error message */
+		if (msg == NULL)
+			return TestPass;
+
+		switch (GST_MESSAGE_TYPE(msg)) {
+		case GST_MESSAGE_ERROR:
+			gstreamer_print_error(msg);
+			break;
+		case GST_MESSAGE_EOS:
+			g_print("End-Of-Stream reached.\n");
+			break;
+		default:
+			g_printerr("Unexpected message received.\n");
+			break;
+		}
+
+		return TestFail;
+	}
+
+private:
+	void gstreamer_print_error(GstMessage *msg)
+	{
+		GError *err;
+		gchar *debug_info;
+
+		gst_message_parse_error(msg, &err, &debug_info);
+		g_printerr("Error received from element %s: %s\n",
+			   GST_OBJECT_NAME(msg->src), err->message);
+		g_printerr("Debugging information: %s\n",
+			   debug_info ? debug_info : "none");
+		g_clear_error(&err);
+		g_free(debug_info);
+	}
+
+	GstElement *pipeline_;
+	GstElement *libcameraSrc_;
+	GstElement *convert0_;
+	GstElement *sink0_;
+};
+
+TEST_REGISTER(GstreamerSingleStreamTest)
diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
new file mode 100644
index 00000000..b99aa0da
--- /dev/null
+++ b/test/gstreamer/meson.build
@@ -0,0 +1,19 @@ 
+# SPDX-License-Identifier: CC0-1.0
+
+if not gst_enabled
+    subdir_done()
+endif
+
+gstreamer_tests = [
+    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
+]
+gstreamer_dep = dependency('gstreamer-1.0', required: true)
+
+foreach t : gstreamer_tests
+    exe = executable(t[0], t[1],
+                     dependencies : [libcamera_private, gstreamer_dep],
+                     link_with : test_libraries,
+                     include_directories : test_includes_internal)
+
+    test(t[0], exe, suite : 'gstreamer', is_parallel : false)
+endforeach
diff --git a/test/meson.build b/test/meson.build
index 3bceb5df..d0466f17 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -11,6 +11,7 @@  subdir('libtest')
 
 subdir('camera')
 subdir('controls')
+subdir('gstreamer')
 subdir('ipa')
 subdir('ipc')
 subdir('log')