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

Vedant Paranjape vedantparanjape160201 at gmail.com
Thu Sep 23 16:50:25 CEST 2021


On Thu, Sep 23, 2021 at 7:35 PM Nicolas Dufresne <
nicolas.dufresne at collabora.com> wrote:

> Le jeudi 23 septembre 2021 à 19:16 +0530, Vedant Paranjape a écrit :
> > This patch adds a test to test if multi stream using libcamera's
> > gstreamer element works.
> >
> > Test will run only on devices that support multistream output, i.e.,
> > devices that use IPU3 and raspberrypi pipeline. This was tested on
> > a Raspberry Pi 4B+.
> >
> > Signed-off-by: Vedant Paranjape <vedantparanjape160201 at gmail.com>
> > Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
> > ---
> >  .../gstreamer/gstreamer_multi_stream_test.cpp | 121 ++++++++++++++++++
> >  test/gstreamer/meson.build                    |   1 +
> >  2 files changed, 122 insertions(+)
> >  create mode 100644 test/gstreamer/gstreamer_multi_stream_test.cpp
> >
> > diff --git a/test/gstreamer/gstreamer_multi_stream_test.cpp
> b/test/gstreamer/gstreamer_multi_stream_test.cpp
> > new file mode 100644
> > index 000000000000..5df1dd40388a
> > --- /dev/null
> > +++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
> > @@ -0,0 +1,121 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + * Copyright (C) 2021, Vedant Paranjape
> > + *
> > + * gstreamer_multi_stream_test.cpp - GStreamer multi stream capture test
> > + */
> > +
> > +#include <iostream>
> > +#include <unistd.h>
> > +
> > +#include <libcamera/base/utils.h>
> > +
> > +#include <libcamera/libcamera.h>
> > +
> > +#include "libcamera/internal/source_paths.h"
> > +
> > +#include <gst/gst.h>
> > +
> > +#include "gstreamer_test.h"
> > +#include "test.h"
> > +
> > +using namespace std;
> > +
> > +class GstreamerMultiStreamTest : public GstreamerTest, public Test
> > +{
> > +public:
> > +     GstreamerMultiStreamTest()
> > +             : GstreamerTest()
> > +     {
> > +     }
> > +
> > +protected:
> > +     int init() override
> > +     {
> > +             if (status_ != TestPass)
> > +                     return status_;
> > +
> > +             /* Check if platform support multistream output */
> > +             libcamera::CameraManager cm;
> > +             cm.start();
> > +             bool cameraFound = false;
> > +             for (auto &camera : cm.cameras()) {
> > +                     if (camera->streams().size() > 1) {
> > +                             cameraName = camera->id();
> > +                             cameraFound = true;
> > +                             cm.stop();
> > +                             break;
> > +                     }
> > +             }
> > +
> > +             if (!cameraFound) {
> > +                     cm.stop();
> > +                     return TestSkip;
> > +             }
> > +
> > +             const gchar *streamDescription = "queue ! fakesink";
> > +             g_autoptr(GError) error0 = NULL;
> > +             g_autoptr(GError) error1 = NULL;
> > +             stream0_ =
> gst_parse_bin_from_description_full(streamDescription, TRUE, NULL,
> GST_PARSE_FLAG_FATAL_ERRORS, &error0);
> > +             stream1_ =
> gst_parse_bin_from_description_full(streamDescription, TRUE, NULL,
> GST_PARSE_FLAG_FATAL_ERRORS, &error1);
> > +
> > +             if (!stream0_) {
> > +                     g_printerr("Bin 0 could not be created (%s)\n",
> error0->message);
> > +                     return TestFail;
> > +             }
> > +             if (!stream1_) {
> > +                     g_printerr("Bin 1 could not be created (%s)\n",
> error1->message);
> > +                     return TestFail;
> > +             }
> > +             g_object_ref_sink(stream0_);
> > +             g_object_ref_sink(stream1_);
>
> In general, I refer when things are slightly more grouped together, what
> do you
> think of:
>
> +               g_autoptr(GError) error = NULL;
> +
> +               stream0_ =
> gst_parse_bin_from_description_full(streamDescription, TRUE, NULL,
> GST_PARSE_FLAG_FATAL_ERRORS, &error);
> +               if (!stream0_) {
> +                       g_printerr("Stream 0 could not be created (%s)\n",
> error->message);
> +                       return TestFail;
> +               }
> +               g_object_ref_sink(stream0_);
> +
> +               stream1_ =
> gst_parse_bin_from_description_full(streamDescription, TRUE, NULL,
> GST_PARSE_FLAG_FATAL_ERRORS, &error);
> +               if (!stream1_) {
> +                       g_printerr("Stream 1 could not be created (%s)\n",
> error->message);
> +                       return TestFail;
> +               }
> +               g_object_ref_sink(stream1_);
>
> p.s. Changed Bin into Stream, I would not get what that means if I saw an
> error
> about bin0/1, as the member is named streamX.
>

This looks much better. Sending a v3.

> +
> > +             if (createPipeline() != TestPass)
> > +                     return TestFail;
> > +
> > +             return TestPass;
> > +     }
> > +
> > +     int run() override
> > +     {
> > +             g_object_set(libcameraSrc_, "camera-name",
> cameraName.c_str(), NULL);
> > +
> > +             /* Build the pipeline */
> > +             gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
> > +                                                     stream0_,
> stream1_, NULL);
> > +
> > +             g_autoptr(GstPad) src_pad =
> gst_element_get_static_pad(libcameraSrc_, "src");
> > +             g_autoptr(GstPad) request_pad =
> gst_element_get_request_pad(libcameraSrc_, "src_%u");
> > +
> > +             {
> > +                     g_autoptr(GstPad) queue0_sink_pad =
> gst_element_get_static_pad(stream0_, "sink");
> > +                     g_autoptr(GstPad) queue1_sink_pad =
> gst_element_get_static_pad(stream1_, "sink");
> > +
> > +                     if (gst_pad_link(src_pad, queue0_sink_pad) !=
> GST_PAD_LINK_OK
> > +                             || gst_pad_link(request_pad,
> queue1_sink_pad) != GST_PAD_LINK_OK) {
> > +                             g_printerr("Pads could not be linked.\n");
> > +                             return TestFail;
> > +                     }
> > +             }
> > +
> > +             if (startPipeline() != TestPass)
> > +                     return TestFail;
> > +
> > +             if (processEvent() != TestPass)
> > +                     return TestFail;
> > +
> > +             return TestPass;
> > +     }
> > +
> > +     void cleanup() override
> > +     {
> > +             g_clear_object(&stream0_);
> > +             g_clear_object(&stream1_);
> > +     }
> > +private:
> > +     std::string cameraName;
> > +     GstElement *stream0_;
> > +     GstElement *stream1_;
> > +};
> > +
> > +TEST_REGISTER(GstreamerMultiStreamTest)
> > diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build
> > index aca53b920365..13652e87d05c 100644
> > --- a/test/gstreamer/meson.build
> > +++ b/test/gstreamer/meson.build
> > @@ -6,6 +6,7 @@ endif
> >
> >  gstreamer_tests = [
> >      ['single_stream_test',   'gstreamer_single_stream_test.cpp'],
> > +    ['multi_stream_test',   'gstreamer_multi_stream_test.cpp'],
> >  ]
> >  gstreamer_dep = dependency('gstreamer-1.0', required: true)
> >
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.libcamera.org/pipermail/libcamera-devel/attachments/20210923/8667456d/attachment-0001.htm>


More information about the libcamera-devel mailing list