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();
+}

Reply via email to