[libcamera-devel] [PATCH v10] test: gstreamer: Add test for gstreamer single stream

Laurent Pinchart laurent.pinchart at ideasonboard.com
Fri Aug 13 20:42:37 CEST 2021


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 at 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 at gmail.com
> > > > > > > > Reviewed-by: Paul Elder <paul.elder at ideasonboard.com>
> > > > > > > > Reviewed-by: Kieran Bingham <kieran.bingham at 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


More information about the libcamera-devel mailing list