From patchwork Tue Aug 31 20:02:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vedant Paranjape X-Patchwork-Id: 13585 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 19675BD87D for ; Tue, 31 Aug 2021 20:02:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 667DD6916A; Tue, 31 Aug 2021 22:02:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="BVNTHqH4"; dkim-atps=neutral Received: from mail-pl1-x635.google.com (mail-pl1-x635.google.com [IPv6:2607:f8b0:4864:20::635]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 708B368890 for ; Tue, 31 Aug 2021 22:02:44 +0200 (CEST) Received: by mail-pl1-x635.google.com with SMTP id q21so123995plq.3 for ; Tue, 31 Aug 2021 13:02:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=mK0SR8LFbaPpAzn81nIZduGoqKj2VZu0iwY36xYFaaY=; b=BVNTHqH44J3TOeUYEgMkGnvQB+5dlLZPLKw08vto7YjQoKcJEFV7Uy9MZGawxkwemy xMIW/oR14OOkEWCbRRo7LLMo5zIjrT7mG6xXsPnoEjmXR7InIJ149uJ+nsNb4t8SzJT+ 51bDILzJ4wUs2hCInA9AFgP0Tc4YTyG5CrC0kUgBHYbwQgyP+LNzopisf1nP5XjhmHmF u0eAUIKNm5l9W4OA5HRyJax5UaIkvaNiPb18jMcZjrtbxhsa94xKJzrG0A+0JV9OcPpr Y+1lvjpH95u733nyBjW6dG+IkZd7ckZDenu12q/s3BAydcIDbH617so3oyiJw6EJg08d txrQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=mK0SR8LFbaPpAzn81nIZduGoqKj2VZu0iwY36xYFaaY=; b=B5GhOnmLTHTgs3EgKEmQCX6Suu1mgQtM+8R9hrS3iI5IUbkgBVxYtlfRw/v2Sv8/+R ARAHSDG+69z/BZo5xTf0hT6zaG+BT5C8AwKB84C5qNsaCJnFWDBwzyQc30y5fHOC5l0T /NE9PrVqvpA3XW2qE93x7grsVMN3YHxdZfKWWy3nifDDe/taMSz+Wo6FJaGmG59cF5x/ eaindnWmr0LxcnMrGOjrov4B4ql+mjPUwulN0uh8rEZhEL8NXYfnN5KS5ILAasmgo1in WSCIFwRlFLuPWpfEtdziOvlburdj9TFd/nnCP96qc7k6POPgkNkJq4bAa1Gk6If3YigP RfZg== X-Gm-Message-State: AOAM533+zqS9jR3NDfAPDTqnoUPsoFm+QcIroHg6pr5Z8VfEsZZRGF5l A81CNBW29m+SXYn0YCuLl5rmfT6sDMNFAjXq X-Google-Smtp-Source: ABdhPJyddCnKIxNED/8vFEnjdmNIQOeciBtmWKI3xJVhXCoybOt9lqS7YiwbBAMln8sqNN58W8vCkA== X-Received: by 2002:a17:90a:680c:: with SMTP id p12mr7521142pjj.33.1630440162302; Tue, 31 Aug 2021 13:02:42 -0700 (PDT) Received: from localhost.localdomain ([1.186.166.49]) by smtp.googlemail.com with ESMTPSA id a15sm7776835pgn.25.2021.08.31.13.02.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Aug 2021 13:02:42 -0700 (PDT) From: Vedant Paranjape To: libcamera-devel@lists.libcamera.org Date: Wed, 1 Sep 2021 01:32:17 +0530 Message-Id: <20210831200217.1323962-1-vedantparanjape160201@gmail.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3] test: gstreamer: Factor out code into a base class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Vedant Paranjape Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Lot of code used in single stream test is boiler plate and common across every gstreamer test. Factored out this code into a base class called GstreamerTest. Also updated the gstreamer_single_stream_test to use the GstreamerTest base class Signed-off-by: Vedant Paranjape Reviewed-by: Nicolas Dufresne --- .../gstreamer_single_stream_test.cpp | 145 +++------------- test/gstreamer/gstreamer_test.cpp | 157 ++++++++++++++++++ test/gstreamer/gstreamer_test.h | 39 +++++ test/gstreamer/meson.build | 2 +- 4 files changed, 221 insertions(+), 122 deletions(-) create mode 100644 test/gstreamer/gstreamer_test.cpp create mode 100644 test/gstreamer/gstreamer_test.h diff --git a/test/gstreamer/gstreamer_single_stream_test.cpp b/test/gstreamer/gstreamer_single_stream_test.cpp index 4c8d4804..c27e4d36 100644 --- a/test/gstreamer/gstreamer_single_stream_test.cpp +++ b/test/gstreamer/gstreamer_single_stream_test.cpp @@ -14,104 +14,48 @@ #include +#include "gstreamer_test.h" #include "test.h" using namespace std; -extern "C" { -const char *__asan_default_options() -{ - /* - * Disable leak detection due to a known global variable initialization - * leak in glib's g_quark_init(). This should ideally be handled by - * using a suppression file instead of disabling leak detection. - */ - return "detect_leaks=false"; -} -} - -class GstreamerSingleStreamTest : public Test +class GstreamerSingleStreamTest : public GstreamerTest, public Test { +public: + GstreamerSingleStreamTest() + : GstreamerTest() + { + } + protected: int init() override { - /* - * GStreamer by default spawns a process to run the - * gst-plugin-scanner helper. If libcamera is compiled with ASan - * enabled, and as GStreamer is most likely not, this causes the - * ASan link order check to fail when gst-plugin-scanner - * dlopen()s the plugin as many libraries will have already been - * loaded by then. Fix this issue by disabling spawning of a - * child helper process when scanning the build directory for - * plugins. - */ - gst_registry_fork_set_enabled(false); - - /* Initialize GStreamer */ - g_autoptr(GError) errInit = NULL; - if (!gst_init_check(nullptr, nullptr, &errInit)) { - g_printerr("Could not initialize GStreamer: %s\n", - errInit ? errInit->message : "unknown error"); + if (status_ != TestPass) + return status_; - return TestFail; - } + g_autoptr(GstElement) convert0__ = gst_element_factory_make("videoconvert", "convert0"); + g_autoptr(GstElement) sink0__ = gst_element_factory_make("fakesink", "sink0"); + g_object_ref_sink(convert0__); + g_object_ref_sink(sink0__); - /* - * Remove the system libcamera plugin, if any, and add the - * plugin from the build directory. - */ - GstRegistry *registry = gst_registry_get(); - GstPlugin *plugin = gst_registry_lookup(registry, "libgstlibcamera.so"); - if (plugin) { - gst_registry_remove_plugin(registry, plugin); - gst_object_unref(plugin); - } + if (!convert0__ || !sink0__) { + g_printerr("Not all elements could be created. %p.%p\n", + convert0__, sink0__); - std::string path = libcamera::utils::libcameraBuildPath() - + "src/gstreamer"; - if (!gst_registry_scan_path(registry, path.c_str())) { - g_printerr("Failed to add plugin to registry\n"); - gst_deinit(); return TestFail; } - /* Create the elements */ - libcameraSrc_ = gst_element_factory_make("libcamerasrc", "libcamera"); - convert0_ = gst_element_factory_make("videoconvert", "convert0"); - sink0_ = gst_element_factory_make("fakesink", "sink0"); - - /* Create the empty pipeline_ */ - pipeline_ = gst_pipeline_new("test-pipeline"); - - if (!pipeline_ || !convert0_ || !sink0_ || !libcameraSrc_) { - g_printerr("Not all elements could be created. %p.%p.%p.%p\n", - pipeline_, convert0_, sink0_, libcameraSrc_); - if (pipeline_) - gst_object_unref(pipeline_); - if (convert0_) - gst_object_unref(convert0_); - if (sink0_) - gst_object_unref(sink0_); - if (libcameraSrc_) - gst_object_unref(libcameraSrc_); - gst_deinit(); + convert0_ = reinterpret_cast(g_steal_pointer(&convert0__)); + sink0_ = reinterpret_cast(g_steal_pointer(&sink0__)); + if (gstreamer_create_pipeline() != TestPass) return TestFail; - } return TestPass; } - void cleanup() override - { - gst_object_unref(pipeline_); - gst_deinit(); - } - int run() override { - GstStateChangeReturn ret; - /* Build the pipeline */ gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_, convert0_, sink0_, NULL); if (gst_element_link_many(libcameraSrc_, convert0_, sink0_, NULL) != TRUE) { @@ -119,57 +63,16 @@ protected: return TestFail; } - /* Start playing */ - ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING); - if (ret == GST_STATE_CHANGE_FAILURE) { - g_printerr("Unable to set the pipeline to the playing state.\n"); + if (gstreamer_start_pipeline() != TestPass) return TestFail; - } - /* Wait until error or EOS or timeout after 2 seconds */ - constexpr GstMessageType msgType = - static_cast(GST_MESSAGE_ERROR | GST_MESSAGE_EOS); - constexpr GstClockTime timeout = 2 * GST_SECOND; - - g_autoptr(GstBus) bus = gst_element_get_bus(pipeline_); - g_autoptr(GstMessage) msg = gst_bus_timed_pop_filtered(bus, timeout, msgType); - - gst_element_set_state(pipeline_, GST_STATE_NULL); - - /* Parse error message */ - if (msg == NULL) - return TestPass; - - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_ERROR: - gstreamer_print_error(msg); - break; - case GST_MESSAGE_EOS: - g_print("End-Of-Stream reached.\n"); - break; - default: - g_printerr("Unexpected message received.\n"); - break; - } + if (gstreamer_process_event() != TestPass) + return TestFail; - return TestFail; + return TestPass; } private: - void gstreamer_print_error(GstMessage *msg) - { - g_autoptr(GError) err = NULL; - g_autofree gchar *debug_info = NULL; - - gst_message_parse_error(msg, &err, &debug_info); - g_printerr("Error received from element %s: %s\n", - GST_OBJECT_NAME(msg->src), err->message); - g_printerr("Debugging information: %s\n", - debug_info ? debug_info : "none"); - } - - GstElement *pipeline_; - GstElement *libcameraSrc_; GstElement *convert0_; GstElement *sink0_; }; diff --git a/test/gstreamer/gstreamer_test.cpp b/test/gstreamer/gstreamer_test.cpp new file mode 100644 index 00000000..22128c4c --- /dev/null +++ b/test/gstreamer/gstreamer_test.cpp @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021, Vedant Paranjape + * + * libcamera Gstreamer element API tests + */ + +#include "gstreamer_test.h" + +#include "test.h" + +using namespace std; + +extern "C" { +const char *__asan_default_options() +{ + /* + * Disable leak detection due to a known global variable initialization + * leak in glib's g_quark_init(). This should ideally be handled by + * using a suppression file instead of disabling leak detection. + */ + return "detect_leaks=false"; +} +} + +GstreamerTest::GstreamerTest() +{ + /* + * GStreamer by default spawns a process to run the + * gst-plugin-scanner helper. If libcamera is compiled with ASan + * enabled, and as GStreamer is most likely not, this causes the + * ASan link order check to fail when gst-plugin-scanner + * dlopen()s the plugin as many libraries will have already been + * loaded by then. Fix this issue by disabling spawning of a + * child helper process when scanning the build directory for + * plugins. + */ + gst_registry_fork_set_enabled(false); + + /* Initialize GStreamer */ + g_autoptr(GError) errInit = NULL; + if (!gst_init_check(nullptr, nullptr, &errInit)) { + g_printerr("Could not initialize GStreamer: %s\n", + errInit ? errInit->message : "unknown error"); + + status_ = TestFail; + return; + } + + /* + * Remove the system libcamera plugin, if any, and add the + * plugin from the build directory. + */ + GstRegistry *registry = gst_registry_get(); + g_autoptr(GstPlugin) plugin = gst_registry_lookup(registry, "libgstlibcamera.so"); + if (plugin) { + gst_registry_remove_plugin(registry, plugin); + } + + std::string path = libcamera::utils::libcameraBuildPath() + "src/gstreamer"; + if (!gst_registry_scan_path(registry, path.c_str())) { + g_printerr("Failed to add plugin to registry\n"); + + status_ = TestFail; + return; + } + + status_ = TestPass; +} + +GstreamerTest::~GstreamerTest() +{ + if (pipeline_) + gst_object_unref(pipeline_); + if (status_ == TestFail) { + gst_object_unref(libcameraSrc_); + } + + gst_deinit(); +} + +int GstreamerTest::gstreamer_create_pipeline() +{ + g_autoptr(GstElement) libcameraSrc__ = gst_element_factory_make("libcamerasrc", "libcamera"); + pipeline_ = gst_pipeline_new("test-pipeline"); + g_object_ref_sink(libcameraSrc__); + + if (!libcameraSrc__ || !pipeline_) { + g_printerr("Unable to create create pipeline %p.%p\n", + libcameraSrc__, pipeline_); + + return TestFail; + } + + libcameraSrc_ = reinterpret_cast(g_steal_pointer(&libcameraSrc__)); + + return TestPass; +} + +int GstreamerTest::gstreamer_start_pipeline() +{ + GstStateChangeReturn ret; + + /* Start playing */ + ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_printerr("Unable to set the pipeline to the playing state.\n"); + return TestFail; + } + + return TestPass; +} + +int GstreamerTest::gstreamer_process_event() +{ + /* Wait until error or EOS or timeout after 2 seconds */ + constexpr GstMessageType msgType = + static_cast(GST_MESSAGE_ERROR | GST_MESSAGE_EOS); + constexpr GstClockTime timeout = 2 * GST_SECOND; + + g_autoptr(GstBus) bus = gst_element_get_bus(pipeline_); + g_autoptr(GstMessage) msg = gst_bus_timed_pop_filtered(bus, timeout, msgType); + + gst_element_set_state(pipeline_, GST_STATE_NULL); + + /* Parse error message */ + if (msg == NULL) { + return TestPass; + } + + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_ERROR: + gstreamer_print_error(msg); + break; + case GST_MESSAGE_EOS: + g_print("End-Of-Stream reached.\n"); + break; + default: + g_printerr("Unexpected message received.\n"); + break; + } + + return TestFail; +} + +void GstreamerTest::gstreamer_print_error(GstMessage *msg) +{ + g_autoptr(GError) err = NULL; + g_autofree gchar *debug_info = NULL; + + gst_message_parse_error(msg, &err, &debug_info); + g_printerr("Error received from element %s: %s\n", + GST_OBJECT_NAME(msg->src), err->message); + g_printerr("Debugging information: %s\n", + debug_info ? debug_info : "none"); +} + diff --git a/test/gstreamer/gstreamer_test.h b/test/gstreamer/gstreamer_test.h new file mode 100644 index 00000000..cdffdea9 --- /dev/null +++ b/test/gstreamer/gstreamer_test.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021, Vedant Paranjape + * + * gstreamer_test.cpp - GStreamer test base class + */ + +#ifndef __LIBCAMERA_GSTREAMER_TEST_H__ +#define __LIBCAMERA_GSTREAMER_TEST_H__ + +#include +#include + +#include + +#include "libcamera/internal/source_paths.h" + +#include + +using namespace std; + +class GstreamerTest +{ +public: + GstreamerTest(); + virtual ~GstreamerTest(); + +protected: + virtual int gstreamer_create_pipeline(); + int gstreamer_start_pipeline(); + int gstreamer_process_event(); + void gstreamer_print_error(GstMessage *msg); + + GstElement *pipeline_; + GstElement *libcameraSrc_; + int status_; +}; + +#endif /* __LIBCAMERA_GSTREAMER_TEST_H__ */ diff --git a/test/gstreamer/meson.build b/test/gstreamer/meson.build index b99aa0da..aca53b92 100644 --- a/test/gstreamer/meson.build +++ b/test/gstreamer/meson.build @@ -10,7 +10,7 @@ gstreamer_tests = [ gstreamer_dep = dependency('gstreamer-1.0', required: true) foreach t : gstreamer_tests - exe = executable(t[0], t[1], + exe = executable(t[0], t[1], 'gstreamer_test.cpp', dependencies : [libcamera_private, gstreamer_dep], link_with : test_libraries, include_directories : test_includes_internal)