Message ID | 20210813104302.200994-1-vedantparanjape160201@gmail.com |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
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')
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
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') >
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')
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 >
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')
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')
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 >
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')
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 >
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')
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')
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 >
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')