[{"id":18752,"web_url":"https://patchwork.libcamera.org/comment/18752/","msgid":"<ab9fb56b-ab48-7b09-a504-5bcd2218313f@ideasonboard.com>","date":"2021-08-13T08:17:57","subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Vedant,\n\nOn 13/08/2021 07:37, Vedant Paranjape wrote:\n> This patch adds a test to test if single stream using\n> libcamera's gstreamer element works.\n> \n> Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>\n> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> ---\n>  .../gstreamer_single_stream_test.cpp          | 148 ++++++++++++++++++\n>  test/gstreamer/meson.build                    |  19 +++\n>  test/meson.build                              |   1 +\n>  3 files changed, 168 insertions(+)\n>  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp\n>  create mode 100644 test/gstreamer/meson.build\n> \n> diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp\n> new file mode 100644\n> index 00000000..c0d38ff8\n> --- /dev/null\n> +++ b/test/gstreamer/gstreamer_single_stream_test.cpp\n> @@ -0,0 +1,148 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2021, Vedant Paranjape\n> + *\n> + * ipa_interface_test.cpp - Test the IPA interface\n> + */\n> +\n> +#include <iostream>\n> +\n> +#include <libcamera/base/utils.h>\n> +\n> +#include <gst/gst.h>\n> +\n> +#include \"test.h\"\n> +\n> +using namespace std;\n> +\n> +class GstreamerSingleStreamTest : public Test\n> +{\n> +protected:\n> +\tint init() override\n> +\t{\n> +\t\t/* Initialize GStreamer */\n> +\t\tGError *errInit = nullptr;\n> +\t\tif (!gst_init_check(nullptr, nullptr, &errInit)) {\n> +\t\t\tg_printerr(\"Could not initialize GStreamer: %s\\n\",\n> +\t\t\t\t   errInit ? errInit->message : \"unknown error\");\n> +\t\t\tif (errInit)\n> +\t\t\t\tg_error_free(errInit);\n> +\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/*\n> +\t\t* Remove the system libcamera plugin, if any, and add the\n> +\t\t* plugin from the build directory.\n> +\t\t*/\n\nOh - excellent, I like this a lot as it will help make sure the test\nruns what we expect it to run.\n\n> +\t\tGstRegistry *registry = gst_registry_get();\n> +\t\tGstPlugin *plugin = gst_registry_lookup(registry, \"libgstlibcamera.so\");\n> +\t\tif (plugin) {\n> +\t\t\tgst_registry_remove_plugin(registry, plugin);\n> +\t\t\tgst_object_unref(plugin);\n> +\t\t}\n> +\t\t\n> +\t\tstd::string path = std::string(libcamera::utils::libcameraBuildPath()\n> +\t\t\t\t\t+ \"src/gstreamer\");\n> +\t\tif (!gst_registry_scan_path(registry, path.c_str())) {\n> +\t\t\tg_printerr(\"Failed to add plugin to registry\\n\");\n> +\t\t\tgst_deinit();\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Create the elements */\n> +\t\tlibcameraSrc_ = gst_element_factory_make(\"libcamerasrc\", \"libcamera\");\n> +\t\tconvert0_ = gst_element_factory_make(\"videoconvert\", \"convert0\");\n> +\t\tsink0_ = gst_element_factory_make(\"fakevideosink\", \"sink0\");\n> +\n> +\t\t/* Create the empty pipeline_ */\n> +\t\tpipeline_ = gst_pipeline_new(\"test-pipeline\");\n> +\n> +\t\tif (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) {\n> +\t\t\tg_printerr(\"Not all elements could be created.\\n\");\n\nI still get failures here:\n\n> ./build/test/gstreamer/single_stream_test\n> Not all elements could be created.\n> \n> (single_stream_test:3346990): GStreamer-CRITICAL **: 09:04:43.279: gst_object_unref: assertion 'object != NULL' failed\n\nChanging this line, makes it clearer what actually has failed, so\nperhaps we should be a bit more verbose on this error print.\n\n> -                       g_printerr(\"Not all elements could be created.\\n\");\n> +                       g_printerr(\"Not all elements could be created. %p.%p.%p.%p\\n\",\n> +                                       pipeline_, convert0_, sink0_, libcameraSrc_);\n\nSo now I can see:\n\n> Not all elements could be created. 0x55d7a51a2100.0x55d7a519db20.(nil).0x55d7a518f0a0\n\nsink0_ has failed on my system. That's ... unexpected and surprising....\n\ngst-inspect-1.0 | grep fakesink\ncoreelements:  fakesink: Fake Sink\n\ngst-inspect-1.0 | grep fakevideosink\n<nothing>\n\nSo - my system has a fakesink, but not a fakevideosink.\n\nIs it preferable to use a fakevideosink? Should we always use a\nfakesink, or try to make either a fakesink or a fakevideosink, and then\nchoose the first one we make?\n\nI would ask if we use fakesink, we might not need the videoconvert - but\nI actually think having that puts some level of 'make sure the\nlibcamerasrc' element is configured as a video source, so I think it's\ngood to have.\n\n\n> +\t\t\tgst_object_unref(pipeline_);\n> +\t\t\tgst_object_unref(convert0_);\n> +\t\t\tgst_object_unref(sink0_);\n> +\t\t\tgst_object_unref(libcameraSrc_);\n\nBy very definition of entering this conditional section, at least one of\nthose four lines will cause a null-unref assertion failure.\n\nAnyway, with those issues resolved, I think this is so close, and\ncertainly a great addition.\n\nSo with those issues fixed,\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nLooking forward to be able to give a Tested-by: tag too on the next\nversion ;-)\n\n--\nKieran\n\n> +\t\t\tgst_deinit();\n> +\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\tvoid cleanup() override\n> +\t{\n> +\t\tgst_object_unref(pipeline_);\n> +\t\tgst_deinit();\n> +\t}\n> +\n> +\tint run() override\n> +\t{\n> +\t\tGstStateChangeReturn ret;\n> +\t\tg_autoptr(GstBus) bus;\n> +\t\tg_autoptr(GstMessage) msg;\n> +\n> +\t\t/* Build the pipeline */\n> +\t\tgst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL);\n> +\t\tif (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) {\n> +\t\t\tg_printerr(\"Elements could not be linked.\\n\");\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Start playing */\n> +\t\tret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);\n> +\t\tif (ret == GST_STATE_CHANGE_FAILURE) {\n> +\t\t\tg_printerr(\"Unable to set the pipeline to the playing state.\\n\");\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Wait until error or EOS or timeout after 2 seconds */\n> +\t\tGstClockTime timeout = 2000000000;\n> +\t\tbus = gst_element_get_bus(pipeline_);\n> +\t\tmsg = gst_bus_timed_pop_filtered(bus, timeout,\n> +\t\t\t\t\t\t GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));\n> +\t\tgst_element_set_state(pipeline_, GST_STATE_NULL);\n> +\n> +\t\t/* Parse error message */\n> +\t\tif (msg == NULL)\n> +\t\t\treturn TestPass;\n> +\n> +\t\tswitch (GST_MESSAGE_TYPE(msg)) {\n> +\t\tcase GST_MESSAGE_ERROR:\n> +\t\t\tgstreamer_print_error(msg);\n> +\t\t\tbreak;\n> +\t\tcase GST_MESSAGE_EOS:\n> +\t\t\tg_print(\"End-Of-Stream reached.\\n\");\n> +\t\t\tbreak;\n> +\t\tdefault:\n> +\t\t\tg_printerr(\"Unexpected message received.\\n\");\n> +\t\t\tbreak;\n> +\t\t}\n> +\n> +\t\treturn TestFail;\n> +\t}\n> +\n> +private:\n> +\tvoid gstreamer_print_error(GstMessage *msg)\n> +\t{\n> +\t\tGError *err;\n> +\t\tgchar *debug_info;\n> +\n> +\t\tgst_message_parse_error(msg, &err, &debug_info);\n> +\t\tg_printerr(\"Error received from element %s: %s\\n\",\n> +\t\t\t   GST_OBJECT_NAME(msg->src), err->message);\n> +\t\tg_printerr(\"Debugging information: %s\\n\",\n> +\t\t\t   debug_info ? debug_info : \"none\");\n> +\t\tg_clear_error(&err);\n> +\t\tg_free(debug_info);\n> +\t}\n> +\n> +\tGstElement *pipeline_;\n> +\tGstElement *libcameraSrc_;\n> +\tGstElement *convert0_;\n> +\tGstElement *sink0_;\n> +};\n> +\n> +TEST_REGISTER(GstreamerSingleStreamTest)\n> diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build\n> new file mode 100644\n> index 00000000..b99aa0da\n> --- /dev/null\n> +++ b/test/gstreamer/meson.build\n> @@ -0,0 +1,19 @@\n> +# SPDX-License-Identifier: CC0-1.0\n> +\n> +if not gst_enabled\n> +    subdir_done()\n> +endif\n> +\n> +gstreamer_tests = [\n> +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],\n> +]\n> +gstreamer_dep = dependency('gstreamer-1.0', required: true)\n> +\n> +foreach t : gstreamer_tests\n> +    exe = executable(t[0], t[1],\n> +                     dependencies : [libcamera_private, gstreamer_dep],\n> +                     link_with : test_libraries,\n> +                     include_directories : test_includes_internal)\n> +\n> +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)\n> +endforeach\n> diff --git a/test/meson.build b/test/meson.build\n> index 3bceb5df..d0466f17 100644\n> --- a/test/meson.build\n> +++ b/test/meson.build\n> @@ -11,6 +11,7 @@ subdir('libtest')\n>  \n>  subdir('camera')\n>  subdir('controls')\n> +subdir('gstreamer')\n>  subdir('ipa')\n>  subdir('ipc')\n>  subdir('log')\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 7BDBBC3240\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 13 Aug 2021 08:18:02 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A70066888E;\n\tFri, 13 Aug 2021 10:18:01 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B02B360263\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Aug 2021 10:18:00 +0200 (CEST)","from [192.168.0.20]\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 37AC4EE;\n\tFri, 13 Aug 2021 10:18:00 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"dDOUF8a4\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1628842680;\n\tbh=OsTbVpgNQqqCA57kLaEn8Gvca9CZOMKbTt+FFAz7ki8=;\n\th=To:References:From:Subject:Date:In-Reply-To:From;\n\tb=dDOUF8a4pXwxOAYIdC9nXRONUnGVBeyMAzbZAoLJUmrmAroB7kl/IeGCravAbiTfW\n\tpmGs6LqKPpgq1NzbDAiEH/4Ng92l0bOU+kLp0PK41VPWqRK06PDj467FZ+SsI+c+4l\n\tbLZx6rGRtjZ/FAVv/djM5oUNeMvmp48a1Y/yiHfg=","To":"Vedant Paranjape <vedantparanjape160201@gmail.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20210813063741.81016-1-vedantparanjape160201@gmail.com>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Message-ID":"<ab9fb56b-ab48-7b09-a504-5bcd2218313f@ideasonboard.com>","Date":"Fri, 13 Aug 2021 09:17:57 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101\n\tThunderbird/78.11.0","MIME-Version":"1.0","In-Reply-To":"<20210813063741.81016-1-vedantparanjape160201@gmail.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":18758,"web_url":"https://patchwork.libcamera.org/comment/18758/","msgid":"<CACGrz-M5P31rJzVb5O7Hxve+20e4AE_XV8s3YDSrmVnVrvMQCw@mail.gmail.com>","date":"2021-08-13T09:53:22","subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","submitter":{"id":85,"url":"https://patchwork.libcamera.org/api/people/85/","name":"Vedant Paranjape","email":"vedantparanjape160201@gmail.com"},"content":"Hi Kieran,\nThanks for the review.\n\n\nOn Fri, Aug 13, 2021 at 1:48 PM Kieran Bingham <\nkieran.bingham@ideasonboard.com> wrote:\n\n> Hi Vedant,\n>\n> On 13/08/2021 07:37, Vedant Paranjape wrote:\n> > This patch adds a test to test if single stream using\n> > libcamera's gstreamer element works.\n> >\n> > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>\n> > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> > ---\n> >  .../gstreamer_single_stream_test.cpp          | 148 ++++++++++++++++++\n> >  test/gstreamer/meson.build                    |  19 +++\n> >  test/meson.build                              |   1 +\n> >  3 files changed, 168 insertions(+)\n> >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp\n> >  create mode 100644 test/gstreamer/meson.build\n> >\n> > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp\n> b/test/gstreamer/gstreamer_single_stream_test.cpp\n> > new file mode 100644\n> > index 00000000..c0d38ff8\n> > --- /dev/null\n> > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp\n> > @@ -0,0 +1,148 @@\n> > +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> > +/*\n> > + * Copyright (C) 2021, Vedant Paranjape\n> > + *\n> > + * ipa_interface_test.cpp - Test the IPA interface\n> > + */\n> > +\n> > +#include <iostream>\n> > +\n> > +#include <libcamera/base/utils.h>\n> > +\n> > +#include <gst/gst.h>\n> > +\n> > +#include \"test.h\"\n> > +\n> > +using namespace std;\n> > +\n> > +class GstreamerSingleStreamTest : public Test\n> > +{\n> > +protected:\n> > +     int init() override\n> > +     {\n> > +             /* Initialize GStreamer */\n> > +             GError *errInit = nullptr;\n> > +             if (!gst_init_check(nullptr, nullptr, &errInit)) {\n> > +                     g_printerr(\"Could not initialize GStreamer: %s\\n\",\n> > +                                errInit ? errInit->message : \"unknown\n> error\");\n> > +                     if (errInit)\n> > +                             g_error_free(errInit);\n> > +\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             /*\n> > +             * Remove the system libcamera plugin, if any, and add the\n> > +             * plugin from the build directory.\n> > +             */\n>\n> Oh - excellent, I like this a lot as it will help make sure the test\n> runs what we expect it to run.\n>\n> > +             GstRegistry *registry = gst_registry_get();\n> > +             GstPlugin *plugin = gst_registry_lookup(registry,\n> \"libgstlibcamera.so\");\n> > +             if (plugin) {\n> > +                     gst_registry_remove_plugin(registry, plugin);\n> > +                     gst_object_unref(plugin);\n> > +             }\n> > +\n> > +             std::string path =\n> std::string(libcamera::utils::libcameraBuildPath()\n> > +                                     + \"src/gstreamer\");\n> > +             if (!gst_registry_scan_path(registry, path.c_str())) {\n> > +                     g_printerr(\"Failed to add plugin to registry\\n\");\n> > +                     gst_deinit();\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             /* Create the elements */\n> > +             libcameraSrc_ = gst_element_factory_make(\"libcamerasrc\",\n> \"libcamera\");\n> > +             convert0_ = gst_element_factory_make(\"videoconvert\",\n> \"convert0\");\n> > +             sink0_ = gst_element_factory_make(\"fakevideosink\",\n> \"sink0\");\n> > +\n> > +             /* Create the empty pipeline_ */\n> > +             pipeline_ = gst_pipeline_new(\"test-pipeline\");\n> > +\n> > +             if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_)\n> {\n> > +                     g_printerr(\"Not all elements could be created.\\n\");\n>\n> I still get failures here:\n>\n> > ./build/test/gstreamer/single_stream_test\n> > Not all elements could be created.\n> >\n> > (single_stream_test:3346990): GStreamer-CRITICAL **: 09:04:43.279:\n> gst_object_unref: assertion 'object != NULL' failed\n>\n> Changing this line, makes it clearer what actually has failed, so\n> perhaps we should be a bit more verbose on this error print.\n>\n> > -                       g_printerr(\"Not all elements could be\n> created.\\n\");\n> > +                       g_printerr(\"Not all elements could be created.\n> %p.%p.%p.%p\\n\",\n> > +                                       pipeline_, convert0_, sink0_,\n> libcameraSrc_);\n>\n> So now I can see:\n>\n> > Not all elements could be created.\n> 0x55d7a51a2100.0x55d7a519db20.(nil).0x55d7a518f0a0\n>\n> sink0_ has failed on my system. That's ... unexpected and surprising....\n>\n> gst-inspect-1.0 | grep fakesink\n> coreelements:  fakesink: Fake Sink\n>\n> gst-inspect-1.0 | grep fakevideosink\n> <nothing>\n>\n> So - my system has a fakesink, but not a fakevideosink.\n>\n> Is it preferable to use a fakevideosink? Should we always use a\n> fakesink, or try to make either a fakesink or a fakevideosink, and then\n> choose the first one we make?\n>\n\nBut it's wierd for you to not have fakevideosink installed, can you install\nit from gst-plugins-bad and Nicolas is the author of that. Since fakesink\nis packaged with gstreamer installation, and fakevideosink needs\ngst-plugins-bad, I'll just stick with fakesink to reduce dependency.\n\nI would ask if we use fakesink, we might not need the videoconvert - but\n> I actually think having that puts some level of 'make sure the\n> libcamerasrc' element is configured as a video source, so I think it's\n> good to have.\n>\n>\n> > +                     gst_object_unref(pipeline_);\n> > +                     gst_object_unref(convert0_);\n> > +                     gst_object_unref(sink0_);\n> > +                     gst_object_unref(libcameraSrc_);\n>\n> By very definition of entering this conditional section, at least one of\n> those four lines will cause a null-unref assertion failure.\n>\n\n> cleanup() isn't called if init() fails, so you need to unref pipeline_,\n> but also libcamera_src_, convert0_ and sink0_ here. The last three\n> elements don't need to be unrefered in cleanup(), because\n> gst_bin_add_many() makes the pipeline take ownership of them.\n\nThis is what Laurent said, I looked up the docs, and\ngst_element_factory_make returns a floating reference\n\n> *Returns* ( [transfer: floating][nullable]) – new GstElement\n<https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html#GstElement>\nor NULL\n<https://developer.gnome.org/glib/unstable/glib-Standard-Macros.html#NULL:CAPS>\nif unable to create element\n\nI guess I can just remove these four unrefs ?\n\nAnyway, with those issues resolved, I think this is so close, and\n> certainly a great addition.\n>\n> So with those issues fixed,\n>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n>\n> Looking forward to be able to give a Tested-by: tag too on the next\n> version ;-)\n>\n> --\n> Kieran\n>\n> > +                     gst_deinit();\n> > +\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             return TestPass;\n> > +     }\n> > +\n> > +     void cleanup() override\n> > +     {\n> > +             gst_object_unref(pipeline_);\n> > +             gst_deinit();\n> > +     }\n> > +\n> > +     int run() override\n> > +     {\n> > +             GstStateChangeReturn ret;\n> > +             g_autoptr(GstBus) bus;\n> > +             g_autoptr(GstMessage) msg;\n> > +\n> > +             /* Build the pipeline */\n> > +             gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,\n> convert0_, sink0_, NULL);\n> > +             if (gst_element_link_many(libcameraSrc_, convert0_,\n> sink0_, NULL) != TRUE) {\n> > +                     g_printerr(\"Elements could not be linked.\\n\");\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             /* Start playing */\n> > +             ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);\n> > +             if (ret == GST_STATE_CHANGE_FAILURE) {\n> > +                     g_printerr(\"Unable to set the pipeline to the\n> playing state.\\n\");\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             /* Wait until error or EOS or timeout after 2 seconds */\n> > +             GstClockTime timeout = 2000000000;\n> > +             bus = gst_element_get_bus(pipeline_);\n> > +             msg = gst_bus_timed_pop_filtered(bus, timeout,\n> > +\n> GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));\n> > +             gst_element_set_state(pipeline_, GST_STATE_NULL);\n> > +\n> > +             /* Parse error message */\n> > +             if (msg == NULL)\n> > +                     return TestPass;\n> > +\n> > +             switch (GST_MESSAGE_TYPE(msg)) {\n> > +             case GST_MESSAGE_ERROR:\n> > +                     gstreamer_print_error(msg);\n> > +                     break;\n> > +             case GST_MESSAGE_EOS:\n> > +                     g_print(\"End-Of-Stream reached.\\n\");\n> > +                     break;\n> > +             default:\n> > +                     g_printerr(\"Unexpected message received.\\n\");\n> > +                     break;\n> > +             }\n> > +\n> > +             return TestFail;\n> > +     }\n> > +\n> > +private:\n> > +     void gstreamer_print_error(GstMessage *msg)\n> > +     {\n> > +             GError *err;\n> > +             gchar *debug_info;\n> > +\n> > +             gst_message_parse_error(msg, &err, &debug_info);\n> > +             g_printerr(\"Error received from element %s: %s\\n\",\n> > +                        GST_OBJECT_NAME(msg->src), err->message);\n> > +             g_printerr(\"Debugging information: %s\\n\",\n> > +                        debug_info ? debug_info : \"none\");\n> > +             g_clear_error(&err);\n> > +             g_free(debug_info);\n> > +     }\n> > +\n> > +     GstElement *pipeline_;\n> > +     GstElement *libcameraSrc_;\n> > +     GstElement *convert0_;\n> > +     GstElement *sink0_;\n> > +};\n> > +\n> > +TEST_REGISTER(GstreamerSingleStreamTest)\n> > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build\n> > new file mode 100644\n> > index 00000000..b99aa0da\n> > --- /dev/null\n> > +++ b/test/gstreamer/meson.build\n> > @@ -0,0 +1,19 @@\n> > +# SPDX-License-Identifier: CC0-1.0\n> > +\n> > +if not gst_enabled\n> > +    subdir_done()\n> > +endif\n> > +\n> > +gstreamer_tests = [\n> > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],\n> > +]\n> > +gstreamer_dep = dependency('gstreamer-1.0', required: true)\n> > +\n> > +foreach t : gstreamer_tests\n> > +    exe = executable(t[0], t[1],\n> > +                     dependencies : [libcamera_private, gstreamer_dep],\n> > +                     link_with : test_libraries,\n> > +                     include_directories : test_includes_internal)\n> > +\n> > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)\n> > +endforeach\n> > diff --git a/test/meson.build b/test/meson.build\n> > index 3bceb5df..d0466f17 100644\n> > --- a/test/meson.build\n> > +++ b/test/meson.build\n> > @@ -11,6 +11,7 @@ subdir('libtest')\n> >\n> >  subdir('camera')\n> >  subdir('controls')\n> > +subdir('gstreamer')\n> >  subdir('ipa')\n> >  subdir('ipc')\n> >  subdir('log')\n> >\n>\n\nRegards,\nVedant","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 2F092C3240\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 13 Aug 2021 09:53:38 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 915F86888E;\n\tFri, 13 Aug 2021 11:53:37 +0200 (CEST)","from mail-yb1-xb2d.google.com (mail-yb1-xb2d.google.com\n\t[IPv6:2607:f8b0:4864:20::b2d])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5085D60263\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Aug 2021 11:53:36 +0200 (CEST)","by mail-yb1-xb2d.google.com with SMTP id c5so4637097ybn.5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Aug 2021 02:53:36 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"RTLfhO9w\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=4RMzq4SSajmr3cd6SHtFqNnokcqz1KhGotMisxMsUIY=;\n\tb=RTLfhO9wuWWkPZQBLdPCjAY1/weQugq7nkeT0BM9ugSN9qXdpzoTpR8pd8ACJFfpFw\n\t1LAh8GWFLrPnPNLHPFNTFcUNbyMfs1EochCfxJ3Zmjqo3tViSNrTFSqiIeyEDu8I22++\n\tfE/bQRB71cImNAYje2QQsUOOzGF2PlwMFTfRxuQXpm6uaWN+2SED8rQHjyXZeTdfnUnb\n\thJb6qT/yamyg+w2Cnrl2/zvyWIv1qUdPyXRWTKzzTFao0ZZDF9PmUstRRi40XEVQMWeW\n\t2WZ6p7pkK/MhVIG1SZhRjifP7NT/gKW6NTjhG3o547frl2WMyi7IC/XsK3qWLUPOyf/S\n\tPISw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=4RMzq4SSajmr3cd6SHtFqNnokcqz1KhGotMisxMsUIY=;\n\tb=qcjKB2HMhceKuxZfZ4nfl/47NINfp5sF/D1mwAK13bJ6G0LWLkkWme9qfD31WJwVk4\n\tj/wqn5z1SZ3yXjbk2JTtvp9kpPxG5PcVCW53pinXiGsBJTSWwh0NpR1/byJn0LoTwo8Y\n\tYfpD+Ooiq8wz4UcMS+QrIwz12ispb3tZvU9aW7AyOIQWgbHhNsngKxRwo4ZDsYR0UpZ8\n\twPnGEcAN9C23BuJsewzwS56VHMumWBOmmF2jTFi/XbvL4T70Y/N9I8dDXaMScgeYImJ9\n\t5b/GmkSoTblHnArrKadRwalMYfkcgPhRb3Z0bZgywxjr/zbRa9eRWIoivhzj4/iREYRr\n\t0PBA==","X-Gm-Message-State":"AOAM5320UfClbMrWtltw7OcO01ozwSXYqryqqeLiH5KKM4IvBU9KzkQ/\n\tP0Hxh3DeiakFG9w3P4qK1m9S2ZPFGhhvs7qCf21QKgSXgDuSNg==","X-Google-Smtp-Source":"ABdhPJxVf6GBcF4xe3v70ddMRYYxg+S+b/ARTkW+9RQGnqD7k9R+CCbCS7Vjvzq/FrIcMfBCfBvLYbovJ7T2/Eym43w=","X-Received":"by 2002:a25:37cf:: with SMTP id\n\te198mr1820870yba.223.1628848414989; \n\tFri, 13 Aug 2021 02:53:34 -0700 (PDT)","MIME-Version":"1.0","References":"<20210813063741.81016-1-vedantparanjape160201@gmail.com>\n\t<ab9fb56b-ab48-7b09-a504-5bcd2218313f@ideasonboard.com>","In-Reply-To":"<ab9fb56b-ab48-7b09-a504-5bcd2218313f@ideasonboard.com>","From":"Vedant Paranjape <vedantparanjape160201@gmail.com>","Date":"Fri, 13 Aug 2021 15:23:22 +0530","Message-ID":"<CACGrz-M5P31rJzVb5O7Hxve+20e4AE_XV8s3YDSrmVnVrvMQCw@mail.gmail.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Content-Type":"multipart/alternative; boundary=\"0000000000002b1f9e05c96dd3f1\"","Subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":18760,"web_url":"https://patchwork.libcamera.org/comment/18760/","msgid":"<CACGrz-OrsLmJPbVnj0nsLKpxjZUETrrnebG_Rjsom7FsEL5Dag@mail.gmail.com>","date":"2021-08-13T09:57:40","subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","submitter":{"id":85,"url":"https://patchwork.libcamera.org/api/people/85/","name":"Vedant Paranjape","email":"vedantparanjape160201@gmail.com"},"content":"Hi Kieran,\n\n\nOn Fri, Aug 13, 2021 at 1:48 PM Kieran Bingham <\nkieran.bingham@ideasonboard.com> wrote:\n\n> Hi Vedant,\n>\n> On 13/08/2021 07:37, Vedant Paranjape wrote:\n> > This patch adds a test to test if single stream using\n> > libcamera's gstreamer element works.\n> >\n> > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>\n> > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> > ---\n> >  .../gstreamer_single_stream_test.cpp          | 148 ++++++++++++++++++\n> >  test/gstreamer/meson.build                    |  19 +++\n> >  test/meson.build                              |   1 +\n> >  3 files changed, 168 insertions(+)\n> >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp\n> >  create mode 100644 test/gstreamer/meson.build\n> >\n> > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp\n> b/test/gstreamer/gstreamer_single_stream_test.cpp\n> > new file mode 100644\n> > index 00000000..c0d38ff8\n> > --- /dev/null\n> > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp\n> > @@ -0,0 +1,148 @@\n> > +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> > +/*\n> > + * Copyright (C) 2021, Vedant Paranjape\n> > + *\n> > + * ipa_interface_test.cpp - Test the IPA interface\n> > + */\n> > +\n> > +#include <iostream>\n> > +\n> > +#include <libcamera/base/utils.h>\n> > +\n> > +#include <gst/gst.h>\n> > +\n> > +#include \"test.h\"\n> > +\n> > +using namespace std;\n> > +\n> > +class GstreamerSingleStreamTest : public Test\n> > +{\n> > +protected:\n> > +     int init() override\n> > +     {\n> > +             /* Initialize GStreamer */\n> > +             GError *errInit = nullptr;\n> > +             if (!gst_init_check(nullptr, nullptr, &errInit)) {\n> > +                     g_printerr(\"Could not initialize GStreamer: %s\\n\",\n> > +                                errInit ? errInit->message : \"unknown\n> error\");\n> > +                     if (errInit)\n> > +                             g_error_free(errInit);\n> > +\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             /*\n> > +             * Remove the system libcamera plugin, if any, and add the\n> > +             * plugin from the build directory.\n> > +             */\n>\n> Oh - excellent, I like this a lot as it will help make sure the test\n> runs what we expect it to run.\n>\n> > +             GstRegistry *registry = gst_registry_get();\n> > +             GstPlugin *plugin = gst_registry_lookup(registry,\n> \"libgstlibcamera.so\");\n> > +             if (plugin) {\n> > +                     gst_registry_remove_plugin(registry, plugin);\n> > +                     gst_object_unref(plugin);\n> > +             }\n> > +\n> > +             std::string path =\n> std::string(libcamera::utils::libcameraBuildPath()\n> > +                                     + \"src/gstreamer\");\n> > +             if (!gst_registry_scan_path(registry, path.c_str())) {\n> > +                     g_printerr(\"Failed to add plugin to registry\\n\");\n> > +                     gst_deinit();\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             /* Create the elements */\n> > +             libcameraSrc_ = gst_element_factory_make(\"libcamerasrc\",\n> \"libcamera\");\n> > +             convert0_ = gst_element_factory_make(\"videoconvert\",\n> \"convert0\");\n> > +             sink0_ = gst_element_factory_make(\"fakevideosink\",\n> \"sink0\");\n> > +\n> > +             /* Create the empty pipeline_ */\n> > +             pipeline_ = gst_pipeline_new(\"test-pipeline\");\n> > +\n> > +             if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_)\n> {\n> > +                     g_printerr(\"Not all elements could be created.\\n\");\n>\n> I still get failures here:\n>\n> > ./build/test/gstreamer/single_stream_test\n> > Not all elements could be created.\n> >\n> > (single_stream_test:3346990): GStreamer-CRITICAL **: 09:04:43.279:\n> gst_object_unref: assertion 'object != NULL' failed\n>\n> Changing this line, makes it clearer what actually has failed, so\n> perhaps we should be a bit more verbose on this error print.\n>\n> > -                       g_printerr(\"Not all elements could be\n> created.\\n\");\n> > +                       g_printerr(\"Not all elements could be created.\n> %p.%p.%p.%p\\n\",\n> > +                                       pipeline_, convert0_, sink0_,\n> libcameraSrc_);\n>\n> So now I can see:\n>\n> > Not all elements could be created.\n> 0x55d7a51a2100.0x55d7a519db20.(nil).0x55d7a518f0a0\n>\n> sink0_ has failed on my system. That's ... unexpected and surprising....\n>\n> gst-inspect-1.0 | grep fakesink\n> coreelements:  fakesink: Fake Sink\n>\n> gst-inspect-1.0 | grep fakevideosink\n> <nothing>\n>\n> So - my system has a fakesink, but not a fakevideosink.\n>\n> Is it preferable to use a fakevideosink? Should we always use a\n> fakesink, or try to make either a fakesink or a fakevideosink, and then\n> choose the first one we make?\n>\n> I would ask if we use fakesink, we might not need the videoconvert - but\n> I actually think having that puts some level of 'make sure the\n> libcamerasrc' element is configured as a video source, so I think it's\n> good to have.\n>\n>\n> > +                     gst_object_unref(pipeline_);\n> > +                     gst_object_unref(convert0_);\n> > +                     gst_object_unref(sink0_);\n> > +                     gst_object_unref(libcameraSrc_);\n>\n> By very definition of entering this conditional section, at least one of\n> those four lines will cause a null-unref assertion failure.\n>\n\nIgnore the earlier comment on this part, I'll add some checking if the\nthing is not null only then take a unref.\n\n\n> Anyway, with those issues resolved, I think this is so close, and\n> certainly a great addition.\n>\n> So with those issues fixed,\n>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n>\n> Looking forward to be able to give a Tested-by: tag too on the next\n> version ;-)\n>\n> --\n> Kieran\n>\n> > +                     gst_deinit();\n> > +\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             return TestPass;\n> > +     }\n> > +\n> > +     void cleanup() override\n> > +     {\n> > +             gst_object_unref(pipeline_);\n> > +             gst_deinit();\n> > +     }\n> > +\n> > +     int run() override\n> > +     {\n> > +             GstStateChangeReturn ret;\n> > +             g_autoptr(GstBus) bus;\n> > +             g_autoptr(GstMessage) msg;\n> > +\n> > +             /* Build the pipeline */\n> > +             gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,\n> convert0_, sink0_, NULL);\n> > +             if (gst_element_link_many(libcameraSrc_, convert0_,\n> sink0_, NULL) != TRUE) {\n> > +                     g_printerr(\"Elements could not be linked.\\n\");\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             /* Start playing */\n> > +             ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);\n> > +             if (ret == GST_STATE_CHANGE_FAILURE) {\n> > +                     g_printerr(\"Unable to set the pipeline to the\n> playing state.\\n\");\n> > +                     return TestFail;\n> > +             }\n> > +\n> > +             /* Wait until error or EOS or timeout after 2 seconds */\n> > +             GstClockTime timeout = 2000000000;\n> > +             bus = gst_element_get_bus(pipeline_);\n> > +             msg = gst_bus_timed_pop_filtered(bus, timeout,\n> > +\n> GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));\n> > +             gst_element_set_state(pipeline_, GST_STATE_NULL);\n> > +\n> > +             /* Parse error message */\n> > +             if (msg == NULL)\n> > +                     return TestPass;\n> > +\n> > +             switch (GST_MESSAGE_TYPE(msg)) {\n> > +             case GST_MESSAGE_ERROR:\n> > +                     gstreamer_print_error(msg);\n> > +                     break;\n> > +             case GST_MESSAGE_EOS:\n> > +                     g_print(\"End-Of-Stream reached.\\n\");\n> > +                     break;\n> > +             default:\n> > +                     g_printerr(\"Unexpected message received.\\n\");\n> > +                     break;\n> > +             }\n> > +\n> > +             return TestFail;\n> > +     }\n> > +\n> > +private:\n> > +     void gstreamer_print_error(GstMessage *msg)\n> > +     {\n> > +             GError *err;\n> > +             gchar *debug_info;\n> > +\n> > +             gst_message_parse_error(msg, &err, &debug_info);\n> > +             g_printerr(\"Error received from element %s: %s\\n\",\n> > +                        GST_OBJECT_NAME(msg->src), err->message);\n> > +             g_printerr(\"Debugging information: %s\\n\",\n> > +                        debug_info ? debug_info : \"none\");\n> > +             g_clear_error(&err);\n> > +             g_free(debug_info);\n> > +     }\n> > +\n> > +     GstElement *pipeline_;\n> > +     GstElement *libcameraSrc_;\n> > +     GstElement *convert0_;\n> > +     GstElement *sink0_;\n> > +};\n> > +\n> > +TEST_REGISTER(GstreamerSingleStreamTest)\n> > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build\n> > new file mode 100644\n> > index 00000000..b99aa0da\n> > --- /dev/null\n> > +++ b/test/gstreamer/meson.build\n> > @@ -0,0 +1,19 @@\n> > +# SPDX-License-Identifier: CC0-1.0\n> > +\n> > +if not gst_enabled\n> > +    subdir_done()\n> > +endif\n> > +\n> > +gstreamer_tests = [\n> > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],\n> > +]\n> > +gstreamer_dep = dependency('gstreamer-1.0', required: true)\n> > +\n> > +foreach t : gstreamer_tests\n> > +    exe = executable(t[0], t[1],\n> > +                     dependencies : [libcamera_private, gstreamer_dep],\n> > +                     link_with : test_libraries,\n> > +                     include_directories : test_includes_internal)\n> > +\n> > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)\n> > +endforeach\n> > diff --git a/test/meson.build b/test/meson.build\n> > index 3bceb5df..d0466f17 100644\n> > --- a/test/meson.build\n> > +++ b/test/meson.build\n> > @@ -11,6 +11,7 @@ subdir('libtest')\n> >\n> >  subdir('camera')\n> >  subdir('controls')\n> > +subdir('gstreamer')\n> >  subdir('ipa')\n> >  subdir('ipc')\n> >  subdir('log')\n> >\n>\n\nRegards,\nVedant","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 97162BD87D\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 13 Aug 2021 09:57:55 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0687968892;\n\tFri, 13 Aug 2021 11:57:55 +0200 (CEST)","from mail-yb1-xb2d.google.com (mail-yb1-xb2d.google.com\n\t[IPv6:2607:f8b0:4864:20::b2d])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 128ED60263\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Aug 2021 11:57:53 +0200 (CEST)","by mail-yb1-xb2d.google.com with SMTP id z5so17800795ybj.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Aug 2021 02:57:52 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"BVuPbAPC\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=mBxRk4MxQ2kkjhw6kQNP5jOmznW2mRH1AGZa3zGEsYA=;\n\tb=BVuPbAPCS+YcSgNicgZoP+be9KimZTUubG30H9GfpL8L3KzGptK2TpAVyKJmGW23Oj\n\tOigSJXt2Bg1dGbpTZ5Puer1MdZzPBgFQcXWpwqiTCEmjuSwGL9Im8ZLT556cNkP6EaJM\n\tAcwUtYblVKY34PawS9ifqkIhmykM9+8I8BEksBM6ytzpA48xuJ21+UfAuF0yLr27yRzp\n\tRPdWD1ZOqOSK1Jr1g2+f2GH8bx4YPbsCxMnl5T21CSfY23G3JEVUk1sTf093gFqPW6wr\n\tekx0BCYdkrxMu57YMwvt1QDkDJPNemmogZGzKje0fqPddz5gSVEh2mTC351x4vTXEpg3\n\teOjw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=mBxRk4MxQ2kkjhw6kQNP5jOmznW2mRH1AGZa3zGEsYA=;\n\tb=tmA1m1nSJDqqoclC2cyrUvRo0c8Y4xg3gzB5l6eGunTJi9o0nRKd6Zy1OWtxuLhys8\n\t7yd9G3qGy3xKrJcNB9DTQvdyDjhPLJB8AW9Dmpl4Fty1H5T44V/SjLfUJfqZ0cI4XBZv\n\tFkc7pwpnDxwCw3z1GTMDU7e65aqdIXn9BYcpdmDCPlvj107RLgqipkPvrewnCcNVB3e3\n\t47tFq6xriMEU34N8dgwb9jczltRN+zvSU7vmS7gKd0wi3ErsUQAgvRw3MgcWSXXpBevM\n\tiCJcB4plU45/vJZVf8kQxTChBx4HUirJLuc7ddvesnSHjPNWVHlI0UZTqBKg2btEp51n\n\tKv6A==","X-Gm-Message-State":"AOAM533XR8xxbJLDylHD57/1TbYLvUaIhrPVAZegbYFj961lI1R0tZjP\n\te7yfZWNZQ6fXsEOdrSoe2INzTblp/rW5KkVck74=","X-Google-Smtp-Source":"ABdhPJyN+pvKi8RDZOn3diCpwkoOwW+lz0xIwAQSJzzmNrDgcifZTuPpJVGg+h0s2Tq3+IXK2ancJGa5A88LYUiEubA=","X-Received":"by 2002:a5b:c52:: with SMTP id d18mr1912984ybr.248.1628848671898;\n\tFri, 13 Aug 2021 02:57:51 -0700 (PDT)","MIME-Version":"1.0","References":"<20210813063741.81016-1-vedantparanjape160201@gmail.com>\n\t<ab9fb56b-ab48-7b09-a504-5bcd2218313f@ideasonboard.com>","In-Reply-To":"<ab9fb56b-ab48-7b09-a504-5bcd2218313f@ideasonboard.com>","From":"Vedant Paranjape <vedantparanjape160201@gmail.com>","Date":"Fri, 13 Aug 2021 15:27:40 +0530","Message-ID":"<CACGrz-OrsLmJPbVnj0nsLKpxjZUETrrnebG_Rjsom7FsEL5Dag@mail.gmail.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Content-Type":"multipart/alternative; boundary=\"0000000000007b468705c96de2f5\"","Subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":18761,"web_url":"https://patchwork.libcamera.org/comment/18761/","msgid":"<d73200c2-a3dd-287a-0477-4c239fe35bf2@ideasonboard.com>","date":"2021-08-13T10:02:37","subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Vedant,\n\nOn 13/08/2021 10:53, Vedant Paranjape wrote:\n> Hi Kieran,\n> Thanks for the review.\n> \n> \n> On Fri, Aug 13, 2021 at 1:48 PM Kieran Bingham\n> <kieran.bingham@ideasonboard.com\n> <mailto:kieran.bingham@ideasonboard.com>> wrote:\n> \n>     Hi Vedant,\n> \n>     On 13/08/2021 07:37, Vedant Paranjape wrote:\n>     > This patch adds a test to test if single stream using\n>     > libcamera's gstreamer element works.\n>     >\n>     > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com\n>     <mailto:vedantparanjape160201@gmail.com>>\n>     > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com\n>     <mailto:paul.elder@ideasonboard.com>>\n>     > ---\n>     >  .../gstreamer_single_stream_test.cpp          | 148\n>     ++++++++++++++++++\n>     >  test/gstreamer/meson.build                    |  19 +++\n>     >  test/meson.build                              |   1 +\n>     >  3 files changed, 168 insertions(+)\n>     >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp\n>     >  create mode 100644 test/gstreamer/meson.build\n>     >\n>     > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp\n>     b/test/gstreamer/gstreamer_single_stream_test.cpp\n>     > new file mode 100644\n>     > index 00000000..c0d38ff8\n>     > --- /dev/null\n>     > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp\n>     > @@ -0,0 +1,148 @@\n>     > +/* SPDX-License-Identifier: GPL-2.0-or-later */\n>     > +/*\n>     > + * Copyright (C) 2021, Vedant Paranjape\n>     > + *\n>     > + * ipa_interface_test.cpp - Test the IPA interface\n>     > + */\n>     > +\n>     > +#include <iostream>\n>     > +\n>     > +#include <libcamera/base/utils.h>\n>     > +\n>     > +#include <gst/gst.h>\n>     > +\n>     > +#include \"test.h\"\n>     > +\n>     > +using namespace std;\n>     > +\n>     > +class GstreamerSingleStreamTest : public Test\n>     > +{\n>     > +protected:\n>     > +     int init() override\n>     > +     {\n>     > +             /* Initialize GStreamer */\n>     > +             GError *errInit = nullptr;\n>     > +             if (!gst_init_check(nullptr, nullptr, &errInit)) {\n>     > +                     g_printerr(\"Could not initialize GStreamer:\n>     %s\\n\",\n>     > +                                errInit ? errInit->message :\n>     \"unknown error\");\n>     > +                     if (errInit)\n>     > +                             g_error_free(errInit);\n>     > +\n>     > +                     return TestFail;\n>     > +             }\n>     > +\n>     > +             /*\n>     > +             * Remove the system libcamera plugin, if any, and\n>     add the\n>     > +             * plugin from the build directory.\n>     > +             */\n> \n>     Oh - excellent, I like this a lot as it will help make sure the test\n>     runs what we expect it to run.\n> \n>     > +             GstRegistry *registry = gst_registry_get();\n>     > +             GstPlugin *plugin = gst_registry_lookup(registry,\n>     \"libgstlibcamera.so\");\n>     > +             if (plugin) {\n>     > +                     gst_registry_remove_plugin(registry, plugin);\n>     > +                     gst_object_unref(plugin);\n>     > +             }\n>     > +             \n>     > +             std::string path =\n>     std::string(libcamera::utils::libcameraBuildPath()\n>     > +                                     + \"src/gstreamer\");\n>     > +             if (!gst_registry_scan_path(registry, path.c_str())) {\n>     > +                     g_printerr(\"Failed to add plugin to\n>     registry\\n\");\n>     > +                     gst_deinit();\n>     > +                     return TestFail;\n>     > +             }\n>     > +\n>     > +             /* Create the elements */\n>     > +             libcameraSrc_ =\n>     gst_element_factory_make(\"libcamerasrc\", \"libcamera\");\n>     > +             convert0_ = gst_element_factory_make(\"videoconvert\",\n>     \"convert0\");\n>     > +             sink0_ = gst_element_factory_make(\"fakevideosink\",\n>     \"sink0\");\n>     > +\n>     > +             /* Create the empty pipeline_ */\n>     > +             pipeline_ = gst_pipeline_new(\"test-pipeline\");\n>     > +\n>     > +             if (!pipeline_ || !convert0_ || !sink0_ ||\n>     !libcameraSrc_) {\n>     > +                     g_printerr(\"Not all elements could be\n>     created.\\n\");\n> \n>     I still get failures here:\n> \n>     > ./build/test/gstreamer/single_stream_test\n>     > Not all elements could be created.\n>     >\n>     > (single_stream_test:3346990): GStreamer-CRITICAL **: 09:04:43.279:\n>     gst_object_unref: assertion 'object != NULL' failed\n> \n>     Changing this line, makes it clearer what actually has failed, so\n>     perhaps we should be a bit more verbose on this error print.\n> \n>     > -                       g_printerr(\"Not all elements could be\n>     created.\\n\");\n>     > +                       g_printerr(\"Not all elements could be\n>     created. %p.%p.%p.%p\\n\",\n>     > +                                       pipeline_, convert0_,\n>     sink0_, libcameraSrc_);\n> \n>     So now I can see:\n> \n>     > Not all elements could be created.\n>     0x55d7a51a2100.0x55d7a519db20.(nil).0x55d7a518f0a0\n> \n>     sink0_ has failed on my system. That's ... unexpected and surprising....\n> \n>     gst-inspect-1.0 | grep fakesink\n>     coreelements:  fakesink: Fake Sink\n> \n>     gst-inspect-1.0 | grep fakevideosink\n>     <nothing>\n> \n>     So - my system has a fakesink, but not a fakevideosink.\n> \n>     Is it preferable to use a fakevideosink? Should we always use a\n>     fakesink, or try to make either a fakesink or a fakevideosink, and then\n>     choose the first one we make?\n> \n> \n> But it's wierd for you to not have fakevideosink installed, can you\n> install it from gst-plugins-bad and Nicolas is the author of that. Since\n\nIt's not so weird in that case ;-)\n\nIndeed, I do not have gstreamer1.0-plugins-bad installed, and nothing in\nthis patch told me I needed to have it ;-)\n\n\n> fakesink is packaged with gstreamer installation, and fakevideosink\n> needs gst-plugins-bad, I'll just stick with fakesink to reduce dependency.\n\nThat sounds like a plan.\n\nDepending on something 'bad' ... doesn't sound too 'good' ;-)\n\n> \n>     I would ask if we use fakesink, we might not need the videoconvert - but\n>     I actually think having that puts some level of 'make sure the\n>     libcamerasrc' element is configured as a video source, so I think it's\n>     good to have.\n> \n> \n>     > +                     gst_object_unref(pipeline_);\n>     > +                     gst_object_unref(convert0_);\n>     > +                     gst_object_unref(sink0_);\n>     > +                     gst_object_unref(libcameraSrc_);\n> \n>     By very definition of entering this conditional section, at least one of\n>     those four lines will cause a null-unref assertion failure.\n> \n> \n>> cleanup() isn't called if init() fails, so you need to unref pipeline_,\n>> but also libcamera_src_, convert0_ and sink0_ here. The last three\n>> elements don't need to be unrefered in cleanup(), because\n>> gst_bin_add_many() makes the pipeline take ownership of them.\n>  \n> This is what Laurent said, I looked up the docs, and\n> gst_element_factory_make returns a floating reference\n\nPerhaps they need to be checked individually?\n\nWe know at least one or more is null - and gstreamer fires an assertion\nif you try to unref a null pointer, so presently, we're guaranteed to\nhit an assertion if one of them fails ... while we could instead print\nour error message and clean up gracefully.\n\n\n\n\n> \n>> *Returns* ( [transfer: floating][nullable]) – new GstElement\n> <https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html#GstElement>\n> or NULL\n> <https://developer.gnome.org/glib/unstable/glib-Standard-Macros.html#NULL:CAPS>\n> if unable to create element\n> \n> I guess I can just remove these four unrefs ?\n> \n>     Anyway, with those issues resolved, I think this is so close, and\n>     certainly a great addition.\n> \n>     So with those issues fixed,\n> \n>     Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com\n>     <mailto:kieran.bingham@ideasonboard.com>>\n> \n>     Looking forward to be able to give a Tested-by: tag too on the next\n>     version ;-)\n> \n>     --\n>     Kieran\n> \n>     > +                     gst_deinit();\n>     > +\n>     > +                     return TestFail;\n>     > +             }\n>     > +\n>     > +             return TestPass;\n>     > +     }\n>     > +\n>     > +     void cleanup() override\n>     > +     {\n>     > +             gst_object_unref(pipeline_);\n>     > +             gst_deinit();\n>     > +     }\n>     > +\n>     > +     int run() override\n>     > +     {\n>     > +             GstStateChangeReturn ret;\n>     > +             g_autoptr(GstBus) bus;\n>     > +             g_autoptr(GstMessage) msg;\n>     > +\n>     > +             /* Build the pipeline */\n>     > +             gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,\n>     convert0_, sink0_, NULL);\n>     > +             if (gst_element_link_many(libcameraSrc_, convert0_,\n>     sink0_, NULL) != TRUE) {\n>     > +                     g_printerr(\"Elements could not be linked.\\n\");\n>     > +                     return TestFail;\n>     > +             }\n>     > +\n>     > +             /* Start playing */\n>     > +             ret = gst_element_set_state(pipeline_,\n>     GST_STATE_PLAYING);\n>     > +             if (ret == GST_STATE_CHANGE_FAILURE) {\n>     > +                     g_printerr(\"Unable to set the pipeline to\n>     the playing state.\\n\");\n>     > +                     return TestFail;\n>     > +             }\n>     > +\n>     > +             /* Wait until error or EOS or timeout after 2 seconds */\n>     > +             GstClockTime timeout = 2000000000;\n>     > +             bus = gst_element_get_bus(pipeline_);\n>     > +             msg = gst_bus_timed_pop_filtered(bus, timeout,\n>     > +                                             \n>     GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));\n>     > +             gst_element_set_state(pipeline_, GST_STATE_NULL);\n>     > +\n>     > +             /* Parse error message */\n>     > +             if (msg == NULL)\n>     > +                     return TestPass;\n>     > +\n>     > +             switch (GST_MESSAGE_TYPE(msg)) {\n>     > +             case GST_MESSAGE_ERROR:\n>     > +                     gstreamer_print_error(msg);\n>     > +                     break;\n>     > +             case GST_MESSAGE_EOS:\n>     > +                     g_print(\"End-Of-Stream reached.\\n\");\n>     > +                     break;\n>     > +             default:\n>     > +                     g_printerr(\"Unexpected message received.\\n\");\n>     > +                     break;\n>     > +             }\n>     > +\n>     > +             return TestFail;\n>     > +     }\n>     > +\n>     > +private:\n>     > +     void gstreamer_print_error(GstMessage *msg)\n>     > +     {\n>     > +             GError *err;\n>     > +             gchar *debug_info;\n>     > +\n>     > +             gst_message_parse_error(msg, &err, &debug_info);\n>     > +             g_printerr(\"Error received from element %s: %s\\n\",\n>     > +                        GST_OBJECT_NAME(msg->src), err->message);\n>     > +             g_printerr(\"Debugging information: %s\\n\",\n>     > +                        debug_info ? debug_info : \"none\");\n>     > +             g_clear_error(&err);\n>     > +             g_free(debug_info);\n>     > +     }\n>     > +\n>     > +     GstElement *pipeline_;\n>     > +     GstElement *libcameraSrc_;\n>     > +     GstElement *convert0_;\n>     > +     GstElement *sink0_;\n>     > +};\n>     > +\n>     > +TEST_REGISTER(GstreamerSingleStreamTest)\n>     > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build\n>     > new file mode 100644\n>     > index 00000000..b99aa0da\n>     > --- /dev/null\n>     > +++ b/test/gstreamer/meson.build\n>     > @@ -0,0 +1,19 @@\n>     > +# SPDX-License-Identifier: CC0-1.0\n>     > +\n>     > +if not gst_enabled\n>     > +    subdir_done()\n>     > +endif\n>     > +\n>     > +gstreamer_tests = [\n>     > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],\n>     > +]\n>     > +gstreamer_dep = dependency('gstreamer-1.0', required: true)\n>     > +\n>     > +foreach t : gstreamer_tests\n>     > +    exe = executable(t[0], t[1],\n>     > +                     dependencies : [libcamera_private,\n>     gstreamer_dep],\n>     > +                     link_with : test_libraries,\n>     > +                     include_directories : test_includes_internal)\n>     > +\n>     > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)\n>     > +endforeach\n>     > diff --git a/test/meson.build b/test/meson.build\n>     > index 3bceb5df..d0466f17 100644\n>     > --- a/test/meson.build\n>     > +++ b/test/meson.build\n>     > @@ -11,6 +11,7 @@ subdir('libtest')\n>     > \n>     >  subdir('camera')\n>     >  subdir('controls')\n>     > +subdir('gstreamer')\n>     >  subdir('ipa')\n>     >  subdir('ipc')\n>     >  subdir('log')\n>     >\n> \n> \n> Regards,\n> Vedant","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D6CD3C3240\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 13 Aug 2021 10:02:42 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 490126888D;\n\tFri, 13 Aug 2021 12:02:42 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3E22D687FA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Aug 2021 12:02:41 +0200 (CEST)","from [192.168.0.20]\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id AF788EE;\n\tFri, 13 Aug 2021 12:02:40 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"XszagsEV\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1628848960;\n\tbh=dBmS9MTLfUYupFunWLfv7+wGRi9yaz9zjJHvqd66Yv4=;\n\th=From:To:Cc:References:Subject:Date:In-Reply-To:From;\n\tb=XszagsEVKLdt6Tz+sN9KusPLkcmWEQs9bMbioavek4SniI+l+Tp4Mo2shVSD6IflO\n\t7tOfVxJAWqa7a37XmHldS22NqWfIqOFousmtDcRcwJq0XO/1M+IqsjtFJut8bYEVha\n\ttwZtG30DnoIVZCiYLqRVVEWQgKZ2YsWJt+rmPuzQ=","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","To":"Vedant Paranjape <vedantparanjape160201@gmail.com>","References":"<20210813063741.81016-1-vedantparanjape160201@gmail.com>\n\t<ab9fb56b-ab48-7b09-a504-5bcd2218313f@ideasonboard.com>\n\t<CACGrz-M5P31rJzVb5O7Hxve+20e4AE_XV8s3YDSrmVnVrvMQCw@mail.gmail.com>","Message-ID":"<d73200c2-a3dd-287a-0477-4c239fe35bf2@ideasonboard.com>","Date":"Fri, 13 Aug 2021 11:02:37 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101\n\tThunderbird/78.11.0","MIME-Version":"1.0","In-Reply-To":"<CACGrz-M5P31rJzVb5O7Hxve+20e4AE_XV8s3YDSrmVnVrvMQCw@mail.gmail.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":18767,"web_url":"https://patchwork.libcamera.org/comment/18767/","msgid":"<YRZa+D9Hj4zfi/R5@pendragon.ideasonboard.com>","date":"2021-08-13T11:43:52","subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nOn Fri, Aug 13, 2021 at 09:17:57AM +0100, Kieran Bingham wrote:\n> On 13/08/2021 07:37, Vedant Paranjape wrote:\n> > This patch adds a test to test if single stream using\n> > libcamera's gstreamer element works.\n> > \n> > Signed-off-by: Vedant Paranjape <vedantparanjape160201@gmail.com>\n> > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> > ---\n> >  .../gstreamer_single_stream_test.cpp          | 148 ++++++++++++++++++\n> >  test/gstreamer/meson.build                    |  19 +++\n> >  test/meson.build                              |   1 +\n> >  3 files changed, 168 insertions(+)\n> >  create mode 100644 test/gstreamer/gstreamer_single_stream_test.cpp\n> >  create mode 100644 test/gstreamer/meson.build\n> > \n> > diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp\n> > new file mode 100644\n> > index 00000000..c0d38ff8\n> > --- /dev/null\n> > +++ b/test/gstreamer/gstreamer_single_stream_test.cpp\n> > @@ -0,0 +1,148 @@\n> > +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> > +/*\n> > + * Copyright (C) 2021, Vedant Paranjape\n> > + *\n> > + * ipa_interface_test.cpp - Test the IPA interface\n> > + */\n> > +\n> > +#include <iostream>\n> > +\n> > +#include <libcamera/base/utils.h>\n> > +\n> > +#include <gst/gst.h>\n> > +\n> > +#include \"test.h\"\n> > +\n> > +using namespace std;\n> > +\n> > +class GstreamerSingleStreamTest : public Test\n> > +{\n> > +protected:\n> > +\tint init() override\n> > +\t{\n> > +\t\t/* Initialize GStreamer */\n> > +\t\tGError *errInit = nullptr;\n> > +\t\tif (!gst_init_check(nullptr, nullptr, &errInit)) {\n> > +\t\t\tg_printerr(\"Could not initialize GStreamer: %s\\n\",\n> > +\t\t\t\t   errInit ? errInit->message : \"unknown error\");\n> > +\t\t\tif (errInit)\n> > +\t\t\t\tg_error_free(errInit);\n> > +\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/*\n> > +\t\t* Remove the system libcamera plugin, if any, and add the\n> > +\t\t* plugin from the build directory.\n> > +\t\t*/\n> \n> Oh - excellent, I like this a lot as it will help make sure the test\n> runs what we expect it to run.\n> \n> > +\t\tGstRegistry *registry = gst_registry_get();\n> > +\t\tGstPlugin *plugin = gst_registry_lookup(registry, \"libgstlibcamera.so\");\n> > +\t\tif (plugin) {\n> > +\t\t\tgst_registry_remove_plugin(registry, plugin);\n> > +\t\t\tgst_object_unref(plugin);\n> > +\t\t}\n> > +\t\t\n> > +\t\tstd::string path = std::string(libcamera::utils::libcameraBuildPath()\n> > +\t\t\t\t\t+ \"src/gstreamer\");\n> > +\t\tif (!gst_registry_scan_path(registry, path.c_str())) {\n> > +\t\t\tg_printerr(\"Failed to add plugin to registry\\n\");\n> > +\t\t\tgst_deinit();\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/* Create the elements */\n> > +\t\tlibcameraSrc_ = gst_element_factory_make(\"libcamerasrc\", \"libcamera\");\n> > +\t\tconvert0_ = gst_element_factory_make(\"videoconvert\", \"convert0\");\n> > +\t\tsink0_ = gst_element_factory_make(\"fakevideosink\", \"sink0\");\n> > +\n> > +\t\t/* Create the empty pipeline_ */\n> > +\t\tpipeline_ = gst_pipeline_new(\"test-pipeline\");\n> > +\n> > +\t\tif (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) {\n> > +\t\t\tg_printerr(\"Not all elements could be created.\\n\");\n> \n> I still get failures here:\n> \n> > ./build/test/gstreamer/single_stream_test\n> > Not all elements could be created.\n> > \n> > (single_stream_test:3346990): GStreamer-CRITICAL **: 09:04:43.279: gst_object_unref: assertion 'object != NULL' failed\n> \n> Changing this line, makes it clearer what actually has failed, so\n> perhaps we should be a bit more verbose on this error print.\n> \n> > -                       g_printerr(\"Not all elements could be created.\\n\");\n> > +                       g_printerr(\"Not all elements could be created. %p.%p.%p.%p\\n\",\n> > +                                       pipeline_, convert0_, sink0_, libcameraSrc_);\n> \n> So now I can see:\n> \n> > Not all elements could be created. 0x55d7a51a2100.0x55d7a519db20.(nil).0x55d7a518f0a0\n> \n> sink0_ has failed on my system. That's ... unexpected and surprising....\n> \n> gst-inspect-1.0 | grep fakesink\n> coreelements:  fakesink: Fake Sink\n> \n> gst-inspect-1.0 | grep fakevideosink\n> <nothing>\n> \n> So - my system has a fakesink, but not a fakevideosink.\n> \n> Is it preferable to use a fakevideosink? Should we always use a\n> fakesink, or try to make either a fakesink or a fakevideosink, and then\n> choose the first one we make?\n> \n> I would ask if we use fakesink, we might not need the videoconvert - but\n> I actually think having that puts some level of 'make sure the\n> libcamerasrc' element is configured as a video source, so I think it's\n> good to have.\n> \n> \n> > +\t\t\tgst_object_unref(pipeline_);\n> > +\t\t\tgst_object_unref(convert0_);\n> > +\t\t\tgst_object_unref(sink0_);\n> > +\t\t\tgst_object_unref(libcameraSrc_);\n> \n> By very definition of entering this conditional section, at least one of\n> those four lines will cause a null-unref assertion failure.\n\nIsn't't gst_object_unref() a no-op when called with a null pointer ?\n\n> Anyway, with those issues resolved, I think this is so close, and\n> certainly a great addition.\n> \n> So with those issues fixed,\n> \n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> Looking forward to be able to give a Tested-by: tag too on the next\n> version ;-)\n> \n> --\n> Kieran\n> \n> > +\t\t\tgst_deinit();\n> > +\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\treturn TestPass;\n> > +\t}\n> > +\n> > +\tvoid cleanup() override\n> > +\t{\n> > +\t\tgst_object_unref(pipeline_);\n> > +\t\tgst_deinit();\n> > +\t}\n> > +\n> > +\tint run() override\n> > +\t{\n> > +\t\tGstStateChangeReturn ret;\n> > +\t\tg_autoptr(GstBus) bus;\n> > +\t\tg_autoptr(GstMessage) msg;\n> > +\n> > +\t\t/* Build the pipeline */\n> > +\t\tgst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL);\n> > +\t\tif (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) {\n> > +\t\t\tg_printerr(\"Elements could not be linked.\\n\");\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/* Start playing */\n> > +\t\tret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);\n> > +\t\tif (ret == GST_STATE_CHANGE_FAILURE) {\n> > +\t\t\tg_printerr(\"Unable to set the pipeline to the playing state.\\n\");\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/* Wait until error or EOS or timeout after 2 seconds */\n> > +\t\tGstClockTime timeout = 2000000000;\n> > +\t\tbus = gst_element_get_bus(pipeline_);\n> > +\t\tmsg = gst_bus_timed_pop_filtered(bus, timeout,\n> > +\t\t\t\t\t\t GstMessageType((uint)GST_MESSAGE_ERROR | (uint)GST_MESSAGE_EOS));\n> > +\t\tgst_element_set_state(pipeline_, GST_STATE_NULL);\n> > +\n> > +\t\t/* Parse error message */\n> > +\t\tif (msg == NULL)\n> > +\t\t\treturn TestPass;\n> > +\n> > +\t\tswitch (GST_MESSAGE_TYPE(msg)) {\n> > +\t\tcase GST_MESSAGE_ERROR:\n> > +\t\t\tgstreamer_print_error(msg);\n> > +\t\t\tbreak;\n> > +\t\tcase GST_MESSAGE_EOS:\n> > +\t\t\tg_print(\"End-Of-Stream reached.\\n\");\n> > +\t\t\tbreak;\n> > +\t\tdefault:\n> > +\t\t\tg_printerr(\"Unexpected message received.\\n\");\n> > +\t\t\tbreak;\n> > +\t\t}\n> > +\n> > +\t\treturn TestFail;\n> > +\t}\n> > +\n> > +private:\n> > +\tvoid gstreamer_print_error(GstMessage *msg)\n> > +\t{\n> > +\t\tGError *err;\n> > +\t\tgchar *debug_info;\n> > +\n> > +\t\tgst_message_parse_error(msg, &err, &debug_info);\n> > +\t\tg_printerr(\"Error received from element %s: %s\\n\",\n> > +\t\t\t   GST_OBJECT_NAME(msg->src), err->message);\n> > +\t\tg_printerr(\"Debugging information: %s\\n\",\n> > +\t\t\t   debug_info ? debug_info : \"none\");\n> > +\t\tg_clear_error(&err);\n> > +\t\tg_free(debug_info);\n> > +\t}\n> > +\n> > +\tGstElement *pipeline_;\n> > +\tGstElement *libcameraSrc_;\n> > +\tGstElement *convert0_;\n> > +\tGstElement *sink0_;\n> > +};\n> > +\n> > +TEST_REGISTER(GstreamerSingleStreamTest)\n> > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build\n> > new file mode 100644\n> > index 00000000..b99aa0da\n> > --- /dev/null\n> > +++ b/test/gstreamer/meson.build\n> > @@ -0,0 +1,19 @@\n> > +# SPDX-License-Identifier: CC0-1.0\n> > +\n> > +if not gst_enabled\n> > +    subdir_done()\n> > +endif\n> > +\n> > +gstreamer_tests = [\n> > +    ['single_stream_test',   'gstreamer_single_stream_test.cpp'],\n> > +]\n> > +gstreamer_dep = dependency('gstreamer-1.0', required: true)\n> > +\n> > +foreach t : gstreamer_tests\n> > +    exe = executable(t[0], t[1],\n> > +                     dependencies : [libcamera_private, gstreamer_dep],\n> > +                     link_with : test_libraries,\n> > +                     include_directories : test_includes_internal)\n> > +\n> > +    test(t[0], exe, suite : 'gstreamer', is_parallel : false)\n> > +endforeach\n> > diff --git a/test/meson.build b/test/meson.build\n> > index 3bceb5df..d0466f17 100644\n> > --- a/test/meson.build\n> > +++ b/test/meson.build\n> > @@ -11,6 +11,7 @@ subdir('libtest')\n> >  \n> >  subdir('camera')\n> >  subdir('controls')\n> > +subdir('gstreamer')\n> >  subdir('ipa')\n> >  subdir('ipc')\n> >  subdir('log')","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id B905ABD87D\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 13 Aug 2021 11:43:59 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 06CD368891;\n\tFri, 13 Aug 2021 13:43:59 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E4B466888E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Aug 2021 13:43:57 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 543F74A1;\n\tFri, 13 Aug 2021 13:43:57 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"tt8BBMDQ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1628855037;\n\tbh=INUZI6LrYy4W94lQHRIxIZII+6oWmTA4YZWKTcMWgTc=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=tt8BBMDQirEcnwcdRJ0KGI0BigbUxXYtIdVcMfM5D0OmrwGrjRXy1d0N75tSQVOaG\n\t5FA+KnJC9q6r1KNSFuVeFpbbnRZXU1GU1QydX04A6LISJH6g1ge8w33tvwTF52fpcv\n\tNCxQ19IU13UEnsIlNoeE7bPGhLpvZcovi7lyfNEQ=","Date":"Fri, 13 Aug 2021 14:43:52 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Message-ID":"<YRZa+D9Hj4zfi/R5@pendragon.ideasonboard.com>","References":"<20210813063741.81016-1-vedantparanjape160201@gmail.com>\n\t<ab9fb56b-ab48-7b09-a504-5bcd2218313f@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<ab9fb56b-ab48-7b09-a504-5bcd2218313f@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v8] test: gstreamer: Add test for\n\tgstreamer single stream","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org,\n\tVedant Paranjape <vedantparanjape160201@gmail.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]