This is an automated email from the ASF dual-hosted git repository.
phrocker pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
The following commit(s) were added to refs/heads/master by this push:
new 1ae1def MINIFICPP-854 CaptureRTSPFrame with OpenCV
1ae1def is described below
commit 1ae1def4e2735ffafad3d238945c225a2950de0d
Author: Jeremy Dyer <[email protected]>
AuthorDate: Tue Mar 5 15:37:12 2019 -0500
MINIFICPP-854 CaptureRTSPFrame with OpenCV
This closes #561.
Signed-off-by: Marc Parisi <[email protected]>
---
CMakeLists.txt | 32 ++--
README.md | 1 +
bootstrap.sh | 4 +
bstrp_functions.sh | 4 +-
cmake/Extensions.cmake | 33 +++-
extensions/opencv/CMakeLists.txt | 65 ++++++++
extensions/opencv/CaptureRTSPFrame.cpp | 170 +++++++++++++++++++++
extensions/opencv/CaptureRTSPFrame.h | 141 +++++++++++++++++
libminifi/test/opencv-tests/CMakeLists.txt | 39 +++++
.../test/opencv-tests/CaptureRTSPFrameTest.cpp | 72 +++++++++
10 files changed, 545 insertions(+), 16 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c3ab96b..1bc647f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,7 +37,7 @@ option(USE_SHARED_LIBS "Builds using shared libraries" ON)
option(ENABLE_PYTHON "Instructs the build system to enable building shared
objects for the python lib" OFF)
-cmake_dependent_option(STATIC_BUILD "Attempts to statically link as many
dependencies as possible." ON "NOT ENABLE_PYTHON; NOT USE_SHARED_LIBS" OFF)
+cmake_dependent_option(STATIC_BUILD "Attempts to statically link as many
dependencies as possible." ON "NOT ENABLE_PYTHON; NOT USE_SHARED_LIBS" OFF)
cmake_dependent_option(USE_SYSTEM_OPENSSL "Instructs the build system to
search for and use an SSL library available in the host system" ON "NOT
STATIC_BUILD" OFF)
option(LIBC_STATIC "Instructs the build system to statically link libstdc++
and glibc into minifiexe. Experiemental" OFF)
@@ -47,9 +47,8 @@ option(ENABLE_OPS "Enable Operations/zlib Tools" ON)
option(USE_SYSTEM_UUID "Instructs the build system to search for and use a
UUID library available in the host system" OFF)
option(ENABLE_JNI "Instructs the build system to enable the JNI extension" OFF)
-
+option(ENABLE_OPENCV "Instructs the build system to enable the OpenCV
extension" OFF)
cmake_dependent_option(USE_SYSTEM_CURL "Instructs the build system to search
for and use a cURL library available in the host system" ON "NOT STATIC_BUILD"
OFF)
-
option(BUILD_SHARED_LIBS "Build yaml cpp shared lib" OFF)
cmake_dependent_option(USE_SYSTEM_ZLIB "Instructs the build system to search
for and use a zlib library available in the host system" ON "NOT STATIC_BUILD"
OFF)
@@ -187,7 +186,7 @@ list(APPEND CMAKE_MODULE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if (NOT OPENSSL_OFF)
if(USE_SYSTEM_OPENSSL)
-
+
# Set the right openssl root path
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl/")
@@ -239,19 +238,19 @@ if(WIN32 OR NOT USE_SYSTEM_ZLIB)
BUILD_BYPRODUCTS ${BYPRODUCT}
)
-
+
add_library(z STATIC IMPORTED)
set_target_properties(z PROPERTIES IMPORTED_LOCATION
"${CMAKE_CURRENT_BINARY_DIR}/${BYPRODUCT}")
-
+
set(ZLIB_BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/${BYPRODUCT}" CACHE STRING
"" FORCE)
- set(ZLIB_BYPRODUCT_INCLUDE
"${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/zlib/include" CACHE STRING "" FORCE)
+ set(ZLIB_BYPRODUCT_INCLUDE
"${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/zlib/include" CACHE STRING "" FORCE)
set(ZLIB_BIN_DIR "${CMAKE_CURRENT_BINARY_DIR}/thirdparty/libressl-install/"
CACHE STRING "" FORCE)
-
+
add_dependencies(z zlib-external)
set(ZLIB_FOUND "YES" CACHE STRING "" FORCE)
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/zlib/include"
CACHE STRING "" FORCE)
set(ZLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/zlib/include"
CACHE STRING "" FORCE)
-
+
set(ZLIB_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/${BYPRODUCT}" CACHE STRING ""
FORCE)
set(ZLIB_LIBRARIES "${ZLIB_LIBRARY}" CACHE STRING "" FORCE)
set(ZLIB_LIBRARY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}/${BYPRODUCT}" CACHE
STRING "" FORCE)
@@ -351,13 +350,13 @@ endif()
set(CURL_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/curl/" CACHE STRING
"" FORCE)
set(CURL_BIN_DIR "${CMAKE_CURRENT_BINARY_DIR}/thirdparty/curl-install/"
CACHE STRING "" FORCE)
set(CURL_BYPRODUCT_DIR "${BYPRODUCT}" CACHE STRING "" FORCE)
-
+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/curl/dummy")
add_library(curl STATIC IMPORTED)
set_target_properties(curl PROPERTIES IMPORTED_LOCATION
"${CURL_BIN_DIR}${BYPRODUCT}")
-
-
+
+
if (OPENSSL_FOUND)
if (NOT WIN32)
set_target_properties(curl PROPERTIES INTERFACE_LINK_LIBRARIES
${OPENSSL_LIBRARIES})
@@ -558,6 +557,11 @@ if (ENABLE_AWS)
createExtension(AWS-EXTENSIONS "AWS EXTENSIONS" "This enables AWS
support" "extensions/aws" )
endif()
+## OpenCV Extesions
+option(ENABLE_OPENCV "Disables the OpenCV extensions." OFF)
+if (ENABLE_OPENCV)
+ createExtension(OPENCV-EXTENSIONS "OPENCV EXTENSIONS" "This enabled
OpenCV support" "extensions/opencv" "${TEST_DIR}/opencv-tests")
+endif()
## Bustache/template extensions
option(ENABLE_BUSTACHE "Enables Bustache (ApplyTemplate) support." OFF)
@@ -660,7 +664,7 @@ install(PROGRAMS bin/minifi.sh
install(FILES LICENSE README.md NOTICE
DESTINATION .
COMPONENT bin)
-
+
if(WIN32)
#preference is to use the exe type so that we have a solution that works well
for cross compilation
#but that leaves the onus up to the developer, so until we can automate some
of that build let's enforce
@@ -675,7 +679,7 @@ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/main/minifi
COMPONENT bin)
endif()
-
+
if (WIN32)
set(CPACK_GENERATOR "WIX")
diff --git a/README.md b/README.md
index 898be3c..3fcf676 100644
--- a/README.md
+++ b/README.md
@@ -76,6 +76,7 @@ Through JNI extensions you can run NiFi processors using
NARs. The JNI extension
| Kafka | [PublishKafka](PROCESSORS.md#publishkafka) |
-DENABLE_LIBRDKAFKA=ON |
| JNI | **NiFi Processors** | -DENABLE_JNI=ON |
| MQTT |
[ConsumeMQTT](PROCESSORS.md#consumeMQTT)<br/>[PublishMQTT](PROCESSORS.md#publishMQTT)
| -DENABLE_MQTT=ON |
+| OpenCV | [CaptureRTSPFrame](PROCESSORS.md#captureRTSPFrame) |
-DENABLE_OPENCV=ON |
| PCAP | [CapturePacket](PROCESSORS.md#capturepacket) |
-DENABLE_PCAP=ON |
| Scripting | [ExecuteScript](PROCESSORS.md#executescript)<br/>**Custom Python
Processors** | -DDISABLE_SCRIPTING=ON |
| SQLLite |
[ExecuteSQL](PROCESSORS.md#executesql)<br/>[PutSQL](PROCESSORS.md#putsql)
| -DENABLE_SQLITE=ON |
diff --git a/bootstrap.sh b/bootstrap.sh
index b85b18d..4823df9 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -281,6 +281,10 @@ add_dependency COAP_ENABLED "libtool"
add_disabled_option JNI_ENABLED ${FALSE} "ENABLE_JNI"
add_dependency JNI_ENABLED "jnibuild"
+add_disabled_option OPENCV_ENABLED ${FALSE} "ENABLE_OPENCV"
+
+add_disabled_option OPENCV_ENABLED ${FALSE} "ENABLE_OPENCV"
+
TESTS_DISABLED=${FALSE}
add_disabled_option SQLITE_ENABLED ${FALSE} "ENABLE_SQLITE"
diff --git a/bstrp_functions.sh b/bstrp_functions.sh
index 2a5bfaf..ffd8b63 100755
--- a/bstrp_functions.sh
+++ b/bstrp_functions.sh
@@ -260,6 +260,7 @@ show_supported_features() {
echo "N. Python Support ..............$(print_feature_status PYTHON_ENABLED)"
echo "O. COAP Support ................$(print_feature_status COAP_ENABLED)"
echo "V. AWS Support .................$(print_feature_status AWS_ENABLED)"
+ echo "T. OpenCV Support ..............$(print_feature_status OPENCV_ENABLED)"
echo "****************************************"
echo " Build Options."
echo "****************************************"
@@ -278,7 +279,7 @@ show_supported_features() {
read_feature_options(){
local choice
- read -p "Enter choice [ A - P or 1-3 ] " choice
+ read -p "Enter choice [ A - T or 1-3 ] " choice
choice=$(echo ${choice} | tr '[:upper:]' '[:lower:]')
case $choice in
a) ToggleFeature ROCKSDB_ENABLED ;;
@@ -302,6 +303,7 @@ read_feature_options(){
fi
;;
o) ToggleFeature COAP_ENABLED ;;
+ t) ToggleFeature OPENCV_ENABLED ;;
1) ToggleFeature TESTS_DISABLED ;;
2) EnableAllFeatures ;;
3) ToggleFeature JNI_ENABLED;;
diff --git a/cmake/Extensions.cmake b/cmake/Extensions.cmake
index 02816d8..438a783 100644
--- a/cmake/Extensions.cmake
+++ b/cmake/Extensions.cmake
@@ -76,4 +76,35 @@ if (NOT WIN32)
${CMAKE_CURRENT_LIST_DIR}/ --
${CMAKE_CURRENT_LIST_DIR}/)
endif(NOT WIN32)
-endmacro()
\ No newline at end of file
+endmacro()
+
+# ARGN WILL be the
+function (build_git_project target prefix repourl repotag)
+
+ set(exec_dir ${CMAKE_BINARY_DIR}/force_${target})
+
+ file(MAKE_DIRECTORY ${exec_dir} ${exec_dir}/build)
+
+ set(CMAKE_LIST_CONTENT "
+ include(ExternalProject)
+ ExternalProject_add(${target}
+ PREFIX ${prefix}/${target}
+ GIT_REPOSITORY ${repourl}
+ GIT_TAG ${repotag}
+ CMAKE_ARGS ${ARGN}
+ INSTALL_COMMAND \"\"
+ )
+ add_custom_target(exec_${target})
+ add_dependencies(exec_${target} ${target})
+ ")
+
+ file(WRITE ${exec_dir}/CMakeLists.txt "${CMAKE_LIST_CONTENT}")
+
+ execute_process(COMMAND ${CMAKE_COMMAND} ..
+ WORKING_DIRECTORY ${exec_dir}/build
+ )
+ execute_process(COMMAND ${CMAKE_COMMAND} --build .
+ WORKING_DIRECTORY ${exec_dir}/build
+ )
+
+endfunction()
diff --git a/extensions/opencv/CMakeLists.txt b/extensions/opencv/CMakeLists.txt
new file mode 100644
index 0000000..37ea563
--- /dev/null
+++ b/extensions/opencv/CMakeLists.txt
@@ -0,0 +1,65 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+include(${CMAKE_SOURCE_DIR}/extensions/ExtensionHeader.txt)
+
+file(GLOB SOURCES "*.cpp")
+
+set(BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}/opencv")
+set(BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/opencv-install/")
+
+set(BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}/thirdparty/opencv")
+set(BYPRODUCT "${BASE_DIR}/install")
+
+# OpenCV 4.1.0
+build_git_project(opencv-external "${BASE_DIR}"
"https://github.com/opencv/opencv.git"
"371bba8f54560b374fbcd47e7e02f015ac4969ad"
+ -DCMAKE_BUILD_TYPE=Release
+ -DCMAKE_INSTALL_PREFIX=${BYPRODUCT}
+ -DBUILD_SHARED_LIBS=OFF
+ -DBUILD_EXAMPLES=OFF
+ -DBUILD_DOCS=OFF
+ -DBUILD_PACKAGE=OFF
+ -DBUILD_opencv_apps=OFF
+ -DBUILD_PERF_TESTS=OFF
+ -DBUILD_TESTS=OFF
+ -DBUILD_opencv_calib3d=ON
+ -DBUILD_opencv_core=ON
+ -DBUILD_opencv_dnn=ON
+ -DBUILD_opencv_features2d=ON
+ -DBUILD_opencv_flann=ON
+ -DBUILD_opencv_gapi=ON
+ -DBUILD_opencv_highgui=OFF
+ -DBUILD_opencv_imgcodecs=ON
+ -DBUILD_opencv_imgproc=ON
+ -DBUILD_opencv_ml=OFF
+ -DBUILD_opencv_objdetect=ON
+ -DBUILD_opencv_photo=ON
+ -DBUILD_opencv_stitching=ON
+ -DBUILD_opencv_video=ON
+ -DBUILD_opencv_videoio=ON)
+
+add_library(minifi-opencv STATIC ${SOURCES})
+
+set(OpenCV_DIR ${BASE_DIR})
+find_package( OpenCV REQUIRED PATHS
"${BASE_DIR}/opencv-external/src/opencv-external-build/")
+target_link_libraries( minifi-opencv ${OpenCV_LIBS} )
+include_directories(${OpenCV_INCLUDE_DIRS})
+
+SET (OPENCV-EXTENSION minifi-opencv PARENT_SCOPE)
+register_extension(minifi-opencv)
\ No newline at end of file
diff --git a/extensions/opencv/CaptureRTSPFrame.cpp
b/extensions/opencv/CaptureRTSPFrame.cpp
new file mode 100644
index 0000000..445e3fb
--- /dev/null
+++ b/extensions/opencv/CaptureRTSPFrame.cpp
@@ -0,0 +1,170 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CaptureRTSPFrame.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace processors {
+
+static core::Property rtspUsername;
+static core::Property rtspPassword;
+static core::Property rtspHostname;
+static core::Property rtspURI;
+static core::Property captureFrameRate;
+static core::Property imageEncoding;
+
+core::Property CaptureRTSPFrame::RTSPUsername( // NOLINT
+ "RTSP Username",
+ "The username for connecting to the RTSP stream", "");
+core::Property CaptureRTSPFrame::RTSPPassword( // NOLINT
+ "RTSP Password",
+ "Password used to connect to the RTSP stream", "");
+core::Property CaptureRTSPFrame::RTSPHostname( // NOLINT
+ "RTSP Hostname",
+ "Hostname of the RTSP stream we are trying to connect to", "");
+core::Property CaptureRTSPFrame::RTSPURI( // NOLINT
+ "RTSP URI",
+ "URI that should be appended to the RTSP stream hostname", "");
+core::Property CaptureRTSPFrame::RTSPPort( // NOLINT
+ "RTSP Port",
+ "Port that should be connected to to receive RTSP Frames",
+ "");
+core::Property CaptureRTSPFrame::ImageEncoding( // NOLINT
+ "Image Encoding",
+ "The encoding that should be applied the the frame images captured from
the RTSP stream",
+ ".jpg"
+ );
+
+core::Relationship CaptureRTSPFrame::Success( // NOLINT
+ "success",
+ "Successful capture of RTSP frame");
+core::Relationship CaptureRTSPFrame::Failure( // NOLINT
+ "failure",
+ "Failures to capture RTSP frame");
+
+void CaptureRTSPFrame::initialize() {
+ std::set<core::Property> properties;
+ properties.insert(RTSPUsername);
+ properties.insert(RTSPPassword);
+ properties.insert(RTSPHostname);
+ properties.insert(RTSPPort);
+ properties.insert(RTSPURI);
+ properties.insert(ImageEncoding);
+ setSupportedProperties(std::move(properties));
+
+ std::set<core::Relationship> relationships;
+ relationships.insert(Success);
+ relationships.insert(Failure);
+ setSupportedRelationships(std::move(relationships));
+}
+
+void CaptureRTSPFrame::onSchedule(core::ProcessContext *context,
core::ProcessSessionFactory *sessionFactory) {
+
+ std::string value;
+
+ if (context->getProperty(RTSPUsername.getName(), value)) {
+ rtsp_username_ = value;
+ }
+ if (context->getProperty(RTSPPassword.getName(), value)) {
+ rtsp_password_ = value;
+ }
+ if (context->getProperty(RTSPHostname.getName(), value)) {
+ rtsp_host_ = value;
+ }
+ if (context->getProperty(RTSPPort.getName(), value)) {
+ rtsp_port_ = value;
+ }
+ if (context->getProperty(RTSPURI.getName(), value)) {
+ rtsp_uri_ = value;
+ }
+ if (context->getProperty(ImageEncoding.getName(), value)) {
+ image_encoding_ = value;
+ }
+
+ logger_->log_trace("CaptureRTSPFrame processor scheduled");
+
+ std::string rtspURI = "rtsp://";
+ rtspURI.append(rtsp_username_);
+ rtspURI.append(":");
+ rtspURI.append(rtsp_password_);
+ rtspURI.append("@");
+ rtspURI.append(rtsp_host_);
+ if (!rtsp_port_.empty()) {
+ rtspURI.append(":");
+ rtspURI.append(rtsp_port_);
+ }
+
+ if (!rtsp_uri_.empty()) {
+ rtspURI.append("/");
+ rtspURI.append(rtsp_uri_);
+ }
+
+ cv::VideoCapture capture(rtspURI.c_str());
+ video_capture_ = capture;
+ video_backend_driver_ = video_capture_.getBackendName();
+}
+
+void CaptureRTSPFrame::onTrigger(const std::shared_ptr<core::ProcessContext>
&context,
+ const std::shared_ptr<core::ProcessSession>
&session) {
+ auto flow_file = session->create();
+
+ cv::Mat frame;
+
+ // retrieve a frame of your source
+ if (video_capture_.read(frame)) {
+ if (!frame.empty()) {
+ CaptureRTSPFrameWriteCallback write_cb(frame, image_encoding_);
+
+ auto t = std::time(nullptr);
+ auto tm = *std::localtime(&t);
+
+ std::ostringstream oss;
+ oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S");
+ auto filename = oss.str();
+ filename.append(image_encoding_);
+
+ session->putAttribute(flow_file, "filename", filename);
+ session->putAttribute(flow_file, "video.backend.driver",
video_backend_driver_);
+
+ session->write(flow_file, &write_cb);
+ session->transfer(flow_file, Success);
+ } else {
+ logger_->log_error("Empty Mat frame received from capture");
+ session->transfer(flow_file, Failure);
+ }
+ } else {
+ logger_->log_error("Unable to read from capture handle on RTSP stream");
+ session->transfer(flow_file, Failure);
+ }
+
+ frame.release();
+
+}
+
+void CaptureRTSPFrame::notifyStop() {
+ // Release the Capture reference and free up resources.
+ video_capture_.release();
+}
+
+} /* namespace processors */
+} /* namespace minifi */
+} /* namespace nifi */
+} /* namespace apache */
+} /* namespace org */
diff --git a/extensions/opencv/CaptureRTSPFrame.h
b/extensions/opencv/CaptureRTSPFrame.h
new file mode 100644
index 0000000..e3ac740
--- /dev/null
+++ b/extensions/opencv/CaptureRTSPFrame.h
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NIFI_MINIFI_CPP_CAPTURERTSPFRAME_H
+#define NIFI_MINIFI_CPP_CAPTURERTSPFRAME_H
+
+#include <atomic>
+
+#include <core/Resource.h>
+#include <core/Processor.h>
+#include <opencv2/opencv.hpp>
+
+#include <iomanip>
+#include <ctime>
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace processors {
+
+class CaptureRTSPFrame : public core::Processor {
+
+ public:
+
+ explicit CaptureRTSPFrame(const std::string &name, utils::Identifier uuid =
utils::Identifier())
+ : Processor(name, uuid),
+ logger_(logging::LoggerFactory<CaptureRTSPFrame>::getLogger()) {
+ }
+
+ static core::Property RTSPUsername;
+ static core::Property RTSPPassword;
+ static core::Property RTSPHostname;
+ static core::Property RTSPURI;
+ static core::Property RTSPPort;
+ static core::Property ImageEncoding;
+
+ static core::Relationship Success;
+ static core::Relationship Failure;
+
+ void initialize() override;
+ void onSchedule(core::ProcessContext *context, core::ProcessSessionFactory
*sessionFactory) override;
+ void onTrigger(core::ProcessContext *context, core::ProcessSession *session)
override {
+ logger_->log_error("onTrigger invocation with raw pointers is not
implemented");
+ }
+ void onTrigger(const std::shared_ptr<core::ProcessContext> &context,
+ const std::shared_ptr<core::ProcessSession> &session)
override;
+
+ void notifyStop() override;
+
+ class CaptureRTSPFrameWriteCallback : public OutputStreamCallback {
+ public:
+ explicit CaptureRTSPFrameWriteCallback(cv::Mat image_mat, std::string
image_encoding_)
+ : image_mat_(std::move(image_mat)), image_encoding_(image_encoding_) {
+ }
+ ~CaptureRTSPFrameWriteCallback() override = default;
+
+ int64_t process(std::shared_ptr<io::BaseStream> stream) override {
+ int64_t ret = 0;
+ imencode(image_encoding_, image_mat_, image_buf_);
+ ret = stream->write(image_buf_.data(), image_buf_.size());
+ return ret;
+ }
+
+ private:
+ std::vector<uchar> image_buf_;
+ cv::Mat image_mat_;
+ std::string image_encoding_;
+ };
+
+ private:
+ std::shared_ptr<logging::Logger> logger_;
+ std::string rtsp_username_;
+ std::string rtsp_password_;
+ std::string rtsp_host_;
+ std::string rtsp_port_;
+ std::string rtsp_uri_;
+ cv::VideoCapture video_capture_;
+ std::string image_encoding_;
+ std::string video_backend_driver_;
+
+// std::function<int()> f_ex;
+//
+// std::atomic<bool> running_;
+//
+// std::unique_ptr<DataHandler> handler_;
+//
+// std::vector<std::string> endpoints;
+//
+// std::map<std::string, std::future<int>*> live_clients_;
+//
+// utils::ThreadPool<int> client_thread_pool_;
+//
+// moodycamel::ConcurrentQueue<std::unique_ptr<io::Socket>>
socket_ring_buffer_;
+//
+// bool stay_connected_;
+//
+// uint16_t concurrent_handlers_;
+//
+// int8_t endOfMessageByte;
+//
+// uint64_t reconnect_interval_;
+//
+// uint64_t receive_buffer_size_;
+//
+// uint16_t connection_attempt_limit_;
+//
+// std::shared_ptr<GetTCPMetrics> metrics_;
+//
+// // Mutex for ensuring clients are running
+//
+// std::mutex mutex_;
+//
+// std::shared_ptr<minifi::controllers::SSLContextService> ssl_service_;
+
+};
+
+REGISTER_RESOURCE(CaptureRTSPFrame, "Captures a frame from the RTSP stream at
specified intervals."); // NOLINT
+
+} /* namespace processors */
+} /* namespace minifi */
+} /* namespace nifi */
+} /* namespace apache */
+} /* namespace org */
+
+
+#endif //NIFI_MINIFI_CPP_CAPTURERTSPFRAME_H
diff --git a/libminifi/test/opencv-tests/CMakeLists.txt
b/libminifi/test/opencv-tests/CMakeLists.txt
new file mode 100644
index 0000000..3cb4bf7
--- /dev/null
+++ b/libminifi/test/opencv-tests/CMakeLists.txt
@@ -0,0 +1,39 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+file(GLOB OPENCV_TESTS "*.cpp")
+
+SET(OPENCV_TEST_COUNT 0)
+
+FOREACH(testfile ${OPENCV_TESTS})
+ get_filename_component(testfilename "${testfile}" NAME_WE)
+ add_executable("${testfilename}" "${testfile}")
+ createTests("${testfilename}")
+ target_include_directories(${testfilename} PRIVATE BEFORE
"${CMAKE_SOURCE_DIR}/extensions/opencv/")
+
+ if (APPLE)
+ target_link_libraries (${testfilename} -Wl,-all_load
minifi-opencv)
+ else ()
+ target_link_libraries (${testfilename} -Wl,--whole-archive
minifi-opencv -Wl,--no-whole-archive)
+ endif ()
+ MATH(EXPR OPENCV_TEST_COUNT "${OPENCV_TEST_COUNT}+1")
+ add_test(NAME "${testfilename}" COMMAND "${testfilename}"
WORKING_DIRECTORY ${TEST_DIR})
+ target_link_libraries(${testfilename} ${CATCH_MAIN_LIB})
+ENDFOREACH()
+message("-- Finished building ${OPENCV_TEST_COUNT} OpenCV related test
file(s)...")
\ No newline at end of file
diff --git a/libminifi/test/opencv-tests/CaptureRTSPFrameTest.cpp
b/libminifi/test/opencv-tests/CaptureRTSPFrameTest.cpp
new file mode 100644
index 0000000..9d6b6d7
--- /dev/null
+++ b/libminifi/test/opencv-tests/CaptureRTSPFrameTest.cpp
@@ -0,0 +1,72 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <uuid/uuid.h>
+#include <fstream>
+#include <map>
+#include <memory>
+#include <utility>
+#include <string>
+#include <set>
+#include "FlowController.h"
+#include "../TestBase.h"
+#include "core/Core.h"
+#include "FlowFile.h"
+#include "../unit/ProvenanceTestHelper.h"
+#include "core/Processor.h"
+#include "core/ProcessContext.h"
+#include "core/ProcessSession.h"
+#include "core/ProcessorNode.h"
+#include <iostream>
+#include "CaptureRTSPFrame.h"
+
+
+TEST_CASE("CaptureRTSPFrame", "[opencvtest1]") {
+ TestController testController;
+
+
LogTestController::getInstance().setTrace<minifi::processors::CaptureRTSPFrame>();
+ LogTestController::getInstance().setDebug<core::ProcessSession>();
+
+ std::shared_ptr<TestPlan> plan = testController.createPlan();
+ std::shared_ptr<core::Processor> captureRTSP =
plan->addProcessor("CaptureRTSPFrame", "CaptureRTSPFrame");
+
+ plan->setProperty(captureRTSP,
minifi::processors::CaptureRTSPFrame::RTSPUsername.getName(), "admin");
+ plan->setProperty(captureRTSP,
minifi::processors::CaptureRTSPFrame::RTSPPassword.getName(), "nope");
+ plan->setProperty(captureRTSP,
minifi::processors::CaptureRTSPFrame::RTSPHostname.getName(), "192.168.1.200");
+ plan->setProperty(captureRTSP,
minifi::processors::CaptureRTSPFrame::RTSPURI.getName(), "");
+ plan->setProperty(captureRTSP,
minifi::processors::CaptureRTSPFrame::RTSPPort.getName(), "");
+ plan->setProperty(captureRTSP,
minifi::processors::CaptureRTSPFrame::ImageEncoding.getName(), ".jpg");
+
+ testController.runSession(plan, false);
+ auto records = plan->getProvenanceRecords();
+ std::shared_ptr<core::FlowFile> record = plan->getCurrentFlowFile();
+ REQUIRE(record == nullptr);
+ REQUIRE(records.size() == 0);
+
+ plan->reset();
+ testController.runSession(plan, false);
+
+ records = plan->getProvenanceRecords();
+ record = plan->getCurrentFlowFile();
+ testController.runSession(plan, false);
+
+ records = plan->getProvenanceRecords();
+ record = plan->getCurrentFlowFile();
+
+ LogTestController::getInstance().reset();
+}