Message ID | 20210923134653.1612991-1-vedantparanjape160201@gmail.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
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@gmail.com> > Reviewed-by: Nicolas Dufresne <nicolas.dufresne@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. > + > + 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) >
On Thu, Sep 23, 2021 at 7:35 PM Nicolas Dufresne < nicolas.dufresne@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@gmail.com> > > Reviewed-by: Nicolas Dufresne <nicolas.dufresne@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) > > > > >
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_); + + 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)