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

Vedant Paranjape vedantparanjape160201 at gmail.com
Tue Sep 14 12:42:35 CEST 2021


On Tue, Sep 14, 2021 at 4:09 PM Vedant Paranjape <
vedantparanjape160201 at gmail.com> wrote:

> Hi Jean-Michel
> Thanks for your review.
>
>
> On Tue, Sep 14, 2021 at 3:53 PM Jean-Michel Hautbois <
> jeanmichel.hautbois at ideasonboard.com> wrote:
>
>> Hi Vedant,
>>
>> On 14/09/2021 10:46, Vedant Paranjape wrote:
>> > This patch adds a test to test if multi stream using libcamera's
>> > gstreamer element works.
>>
>> A test to test :-) ?
>> A proposal (I am not good at writing commit messages though so, please
>> use it with care :-)):
>>
>
> haha, even the single stream test had same commit message, and it went in,
> so didn't think about anything different.
>
> >
>> > Test will run only on devices that support multistream output, i.e.,
>> > devices that use IPU3 and RPI pipeline. This was tested on a Raspberry
>> > Pi 4B+
>> >
>> > Signed-off-by: Vedant Paranjape <vedantparanjape160201 at gmail.com>
>> > Reviewed-by: Paul Elder <paul.elder at ideasonboard.com>
>> > Tested-by: Paul Elder <paul.elder at ideasonboard.com>
>> > ---
>> >  .../gstreamer/gstreamer_multi_stream_test.cpp | 138 ++++++++++++++++++
>> >  test/gstreamer/meson.build                    |   1 +
>> >  2 files changed, 139 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..aea9a1dcb211
>> > --- /dev/null
>> > +++ b/test/gstreamer/gstreamer_multi_stream_test.cpp
>> > @@ -0,0 +1,138 @@
>> > +/* 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;
>> > +             }
>> > +
>> > +             g_autoptr(GstElement) convert0 =
>> gst_element_factory_make("videoconvert", "convert0");
>> > +             g_autoptr(GstElement) convert1 =
>> gst_element_factory_make("videoconvert", "convert1");
>>
>> Why do you need a convert element ? AFAIK you are outputting into a
>> fakesink it should not be an issue ?
>>
>
> This is an artifact from the old code which used autovideosink but was
> changed to fakesink. I'll test if removing it works, I'd want to use stats
> property in future, I assume it won't work if I remove videoconvert.
>
> > +             g_autoptr(GstElement) sink0 =
>> gst_element_factory_make("fakesink", "sink0");
>> > +             g_autoptr(GstElement) sink1 =
>> gst_element_factory_make("fakesink", "sink1");
>> > +             g_autoptr(GstElement) queue0 =
>> gst_element_factory_make("queue", "queue0");
>> > +             g_autoptr(GstElement) queue1 =
>> gst_element_factory_make("queue", "queue1");
>> > +             g_object_ref_sink(convert0);
>> > +             g_object_ref_sink(convert1);
>> > +             g_object_ref_sink(sink0);
>> > +             g_object_ref_sink(sink1);
>> > +             g_object_ref_sink(queue0);
>> > +             g_object_ref_sink(queue1);
>>
>> I don't really like that, why can't you use
>> gst_parse_bin_from_description() for instance ?
>> That way you would get a bin you could link to libcamerasrc.
>>
>
> I think the answer to that lies in run() function, I'm doing using request
> pads so, that won't be possible if I just use a bin. I maybe wrong, I'll
> wait for Nicolas's comment as you said.
>

s/ I'm doing using request pads / I'm working with pads of the queue element

Note: it is a long time since I really use GStreamer so I may not be
>> up-to-date, Nicolas may a different comment, and he would be the one to
>> follow ;-).
>>
>> > +
>> > +             if (!convert0 || !convert1 || !sink0 || !sink1 || !queue0
>> || !queue1) {
>> > +                     g_printerr("Not all elements could be created.
>> %p.%p.%p.%p.%p.%p\n",
>> > +                                convert0, convert1, sink0, sink1,
>> queue0, queue1);
>> > +
>> > +                     return TestFail;
>> > +             }
>> > +
>> > +             if (createPipeline() != TestPass)
>> > +                     return TestFail;
>> > +
>> > +             convert0_ = reinterpret_cast<GstElement
>> *>(g_steal_pointer(&convert0));
>> > +             convert1_ = reinterpret_cast<GstElement
>> *>(g_steal_pointer(&convert1));
>> > +             sink0_ = reinterpret_cast<GstElement
>> *>(g_steal_pointer(&sink0));
>> > +             sink1_ = reinterpret_cast<GstElement
>> *>(g_steal_pointer(&sink1));
>> > +             queue0_ = reinterpret_cast<GstElement
>> *>(g_steal_pointer(&queue0));
>> > +             queue1_ = reinterpret_cast<GstElement
>> *>(g_steal_pointer(&queue1));
>> > +
>> > +             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_,
>> queue0_, queue1_,
>> > +                              convert0_, convert1_, sink0_, sink1_,
>> NULL);
>> > +             if (gst_element_link_many(queue0_, convert0_, sink0_,
>> NULL) != TRUE ||
>> > +                 gst_element_link_many(queue1_, convert1_, sink1_,
>> NULL) != TRUE) {
>> > +                     g_printerr("Elements could not be linked.\n");
>> > +                     return TestFail;
>> > +             }
>> > +
>> > +             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");
>> > +             GstPad *queue0_sink_pad =
>> gst_element_get_static_pad(queue0_, "sink");
>> > +             GstPad *queue1_sink_pad =
>> gst_element_get_static_pad(queue1_, "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) {
>> > +                     if (queue0_sink_pad)
>> > +                             gst_object_unref(queue0_sink_pad);
>> > +                     if (queue1_sink_pad)
>> > +                             gst_object_unref(queue1_sink_pad);
>> > +                     g_printerr("Pads could not be linked.\n");
>> > +                     return TestFail;
>> > +             }
>> > +             gst_object_unref(queue0_sink_pad);
>> > +             gst_object_unref(queue1_sink_pad);
>> > +
>> > +             if (startPipeline() != TestPass)
>> > +                     return TestFail;
>> > +
>> > +             if (processEvent() != TestPass)
>> > +                     return TestFail;
>> > +
>> > +             return TestPass;
>> > +     }
>> > +
>> > +private:
>> > +     std::string cameraName;
>> > +     GstElement *convert0_;
>> > +     GstElement *convert1_;
>> > +     GstElement *sink0_;
>> > +     GstElement *sink1_;
>> > +     GstElement *queue0_;
>> > +     GstElement *queue1_;
>> > +};
>> > +
>> > +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)
>> >
>> >
>>
>
> Regards,
> *Vedant Paranjape*
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.libcamera.org/pipermail/libcamera-devel/attachments/20210914/d488fd12/attachment.htm>


More information about the libcamera-devel mailing list