file tree reorganized
This commit is contained in:
1 parent
c955bb466e
commit
6f9c0d702d
13 files changed
-68
No files matched your search
File renamed without changes.
@@ -1,61 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(image2rtsp)
|
||||
|
||||
# Default to C99
|
||||
if(NOT CMAKE_C_STANDARD)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
endif()
|
||||
|
||||
# Default to C++14
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# find dependencies
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(sensor_msgs REQUIRED)
|
||||
pkg_check_modules(GST REQUIRED
|
||||
gstreamer-1.0
|
||||
gstreamer-app-1.0
|
||||
gstreamer-rtsp-server-1.0
|
||||
)
|
||||
file(GLOB SOURCES src/video.cpp)
|
||||
|
||||
add_executable(image2rtsp src/image2rtsp.cpp ${SOURCES})
|
||||
ament_target_dependencies(image2rtsp rclcpp sensor_msgs)
|
||||
|
||||
include_directories(
|
||||
${GST_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(image2rtsp
|
||||
${GST_LIBRARIES}
|
||||
)
|
||||
|
||||
install(TARGETS
|
||||
image2rtsp
|
||||
DESTINATION lib/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY
|
||||
config
|
||||
launch
|
||||
DESTINATION share/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
# Install Python modules
|
||||
ament_python_install_package(python)
|
||||
|
||||
# Install Python executables
|
||||
install(PROGRAMS
|
||||
python/rtsp.py
|
||||
DESTINATION lib/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
|
||||
ament_package()
|
||||
@@ -1,24 +0,0 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
||||
@@ -1,67 +0,0 @@
|
||||
## Acknowledgement
|
||||
This project is a migration from ROS1 to ROS2. The original code was developed by [CircusMonkey](https://github.com/CircusMonkey/ros_rtsp/tree/master). I would like to express my gratitude for his contribution.
|
||||
|
||||
## image2rtsp
|
||||
The migration is still in process, thus the full functionality of the original package is not presented yet. The current version supports only the conversion of one chosen ROS2 topic into an RTSP stream with an expected delay of about 30-50ms.
|
||||
It is being developed on Ubuntu 20.04 with ROS2 Foxy.
|
||||
|
||||
## Dependencies
|
||||
- ROS2 foxy
|
||||
|
||||
- gstreamer libs:
|
||||
```bash
|
||||
sudo apt-get install libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev libgstreamer-plugins-bad1.0-dev libgstrtspserver-1.0-dev gstreamer1.0-plugins-ugly gstreamer1.0-plugins-bad
|
||||
```
|
||||
## Install
|
||||
- Clone the package:
|
||||
```bashrc
|
||||
git clone https://github.com/45kmh/ros2_rtsp.git
|
||||
```
|
||||
- Adjust `parameters.yaml` according to your needs:
|
||||
```bashrc
|
||||
gedit ~/image2rtsp/src/image2rtsp/config/parameters.yaml
|
||||
```
|
||||
# Example ROS2 Image topic stream
|
||||
topic: "/color/image_raw" # The ROS2 topic to subscribe to
|
||||
mountpoint: "/back" # Choose the mountpoint for the rtsp stream.
|
||||
# This will be able to be accessed from rtsp://<server_ip>/portAndMountpoint
|
||||
caps: "video/x-raw,framerate=10/1,width=640,height=480"
|
||||
# Set the caps to be applied after getting the ROS2 Image and before the x265 encoder.
|
||||
bitrate: "500"
|
||||
port: "8554"
|
||||
local_only: True # True = rtsp://127.0.0.1:port (The stream is accessible only from the local machine)
|
||||
# False = rtsp://0.0.0.0:portAndMountpoint (The stream is accessible from the outside)
|
||||
# For example, to access the stream running on the machine with IP = 192.168.20.20,
|
||||
# use rtsp://192.186.20.20:portAndMountpoint
|
||||
# True = rtsp://127.0.0.1:portAndMountpoint (The stream is accessible only from the local machine)
|
||||
- Save your configuration and navigate to `image2rtsp ` colcon root, source and build the package:
|
||||
```bashrc
|
||||
cd ~/image2rtsp/
|
||||
colcon build --packages-select image2rtsp
|
||||
```
|
||||
## Run
|
||||
- Source `install` and launch the package:
|
||||
```bashrc
|
||||
source install/setup.bash
|
||||
ros2 launch image2rtsp image2rtsp.launch.py
|
||||
```
|
||||
Don't use **`ros2 run`**!
|
||||
|
||||
## Check the stream
|
||||
To check the stream, follow the instructions for gstreamer, mpv or VLC provided by [CircusMonkey](https://github.com/CircusMonkey/ros_rtsp/blob/master/README.md) or use python script (ensure before that the open-cv library is installed, if not `pip install opencv-python`):
|
||||
```bash
|
||||
gedit ~/image2rtsp/src/image2rtsp/python/rtsp.py
|
||||
```
|
||||
Replace the `rtsp://127.0.0.1:8554/back` with your server's IP address, port and mount point `rtsp://YOUR_IP:PORT/MOUNT_POINT`. Save and run:
|
||||
```bash
|
||||
python3 ~/image2rtsp/src/image2rtsp/python/rtsp.py
|
||||
```
|
||||
## Limitations
|
||||
- As was previously mentioned, this package allows the conversion of only one topic into an RTSP Stream.
|
||||
- Some machines may have a significantly bigger delay of about 150-200ms. The reason is currently unknown.
|
||||
## To Do
|
||||
- Add a branch with the package rewritten as a ROS2 component
|
||||
- Port the package to Nvidia Jetson Orin. Will the use of the Nvidia encoder make the delay smaller?
|
||||
- Port packages to ROS2 Humble.
|
||||
- Complete the functionality according to the functionality of the original ROS package.
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/image2rtsp:
|
||||
ros__parameters:
|
||||
topic: "/color/image_raw"
|
||||
mountpoint: "/back"
|
||||
bitrate: "500"
|
||||
caps: "video/x-raw,framerate=10/1,width=640,height=480"
|
||||
port: "8554"
|
||||
local_only: True # True = rtsp://127.0.0.1:port (The stream is accessible only from the local machine)
|
||||
# False = rtsp://0.0.0.0:portAndMountpoint (The stream is accessible from the outside)
|
||||
# For example, to access the stream running on the machine with IP = 192.168.20.20,
|
||||
# use rtsp://192.186.20.20:portAndMountpoint
|
||||
# True = rtsp://127.0.0.1:portAndMountpoint (The stream is accessible only from the local machine)
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef IMAGE2RTSP_IMAGE2RTSP_HPP
|
||||
#define IMAGE2RTSP_IMAGE2RTSP_HPP
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/rtsp-server/rtsp-server.h>
|
||||
#include <rclcpp/rclcpp.hpp>
|
||||
#include <string>
|
||||
#include "sensor_msgs/msg/image.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Image2rtsp : public rclcpp::Node{
|
||||
public:
|
||||
Image2rtsp();
|
||||
GstRTSPServer *rtsp_server;
|
||||
|
||||
private:
|
||||
string topic;
|
||||
string mountpoint;
|
||||
string bitrate;
|
||||
string caps;
|
||||
string port;
|
||||
string pipeline;
|
||||
string pipeline_head;
|
||||
string pipeline_tail;
|
||||
bool local_only;
|
||||
GstAppSrc *appsrc;
|
||||
|
||||
void video_mainloop_start();
|
||||
void rtsp_server_add_url(const char *url, const char *sPipeline, GstElement **appsrc);
|
||||
void topic_callback(const sensor_msgs::msg::Image::SharedPtr msg);
|
||||
GstRTSPServer *rtsp_server_create(const string &port, const bool local_only);
|
||||
GstCaps *gst_caps_new_from_image(const sensor_msgs::msg::Image::SharedPtr &msg);
|
||||
rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr subscription_;
|
||||
};
|
||||
|
||||
static void media_configure(GstRTSPMediaFactory *factory, GstRTSPMedia *media, GstElement **appsrc);
|
||||
static void *mainloop(void *arg);
|
||||
static gboolean session_cleanup(Image2rtsp *node, rclcpp::Logger logger, gboolean ignored);
|
||||
|
||||
#endif // IMAGE2RTSP_IMAGE2RTSP_HPP
|
||||
@@ -1,233 +0,0 @@
|
||||
|
||||
/*********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright (c) 2009, Willow Garage, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of the Willow Garage nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SENSOR_MSGS_IMAGE_ENCODINGS_H
|
||||
#define SENSOR_MSGS_IMAGE_ENCODINGS_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace sensor_msgs
|
||||
{
|
||||
namespace image_encodings
|
||||
{
|
||||
const std::string RGB8 = "rgb8";
|
||||
const std::string RGBA8 = "rgba8";
|
||||
const std::string RGB16 = "rgb16";
|
||||
const std::string RGBA16 = "rgba16";
|
||||
const std::string BGR8 = "bgr8";
|
||||
const std::string BGRA8 = "bgra8";
|
||||
const std::string BGR16 = "bgr16";
|
||||
const std::string BGRA16 = "bgra16";
|
||||
const std::string MONO8="mono8";
|
||||
const std::string MONO16="mono16";
|
||||
|
||||
// OpenCV CvMat types
|
||||
const std::string TYPE_8UC1="8UC1";
|
||||
const std::string TYPE_8UC2="8UC2";
|
||||
const std::string TYPE_8UC3="8UC3";
|
||||
const std::string TYPE_8UC4="8UC4";
|
||||
const std::string TYPE_8SC1="8SC1";
|
||||
const std::string TYPE_8SC2="8SC2";
|
||||
const std::string TYPE_8SC3="8SC3";
|
||||
const std::string TYPE_8SC4="8SC4";
|
||||
const std::string TYPE_16UC1="16UC1";
|
||||
const std::string TYPE_16UC2="16UC2";
|
||||
const std::string TYPE_16UC3="16UC3";
|
||||
const std::string TYPE_16UC4="16UC4";
|
||||
const std::string TYPE_16SC1="16SC1";
|
||||
const std::string TYPE_16SC2="16SC2";
|
||||
const std::string TYPE_16SC3="16SC3";
|
||||
const std::string TYPE_16SC4="16SC4";
|
||||
const std::string TYPE_32SC1="32SC1";
|
||||
const std::string TYPE_32SC2="32SC2";
|
||||
const std::string TYPE_32SC3="32SC3";
|
||||
const std::string TYPE_32SC4="32SC4";
|
||||
const std::string TYPE_32FC1="32FC1";
|
||||
const std::string TYPE_32FC2="32FC2";
|
||||
const std::string TYPE_32FC3="32FC3";
|
||||
const std::string TYPE_32FC4="32FC4";
|
||||
const std::string TYPE_64FC1="64FC1";
|
||||
const std::string TYPE_64FC2="64FC2";
|
||||
const std::string TYPE_64FC3="64FC3";
|
||||
const std::string TYPE_64FC4="64FC4";
|
||||
|
||||
// Bayer encodings
|
||||
const std::string BAYER_RGGB8="bayer_rggb8";
|
||||
const std::string BAYER_BGGR8="bayer_bggr8";
|
||||
const std::string BAYER_GBRG8="bayer_gbrg8";
|
||||
const std::string BAYER_GRBG8="bayer_grbg8";
|
||||
const std::string BAYER_RGGB16="bayer_rggb16";
|
||||
const std::string BAYER_BGGR16="bayer_bggr16";
|
||||
const std::string BAYER_GBRG16="bayer_gbrg16";
|
||||
const std::string BAYER_GRBG16="bayer_grbg16";
|
||||
|
||||
// Miscellaneous
|
||||
// This is the UYVY version of YUV422 codec http://www.fourcc.org/yuv.php#UYVY
|
||||
// with an 8-bit depth
|
||||
const std::string YUV422="yuv422";
|
||||
|
||||
// Prefixes for abstract image encodings
|
||||
const std::string ABSTRACT_ENCODING_PREFIXES[] = {
|
||||
"8UC", "8SC", "16UC", "16SC", "32SC", "32FC", "64FC"};
|
||||
|
||||
// Utility functions for inspecting an encoding string
|
||||
static inline bool isColor(const std::string& encoding)
|
||||
{
|
||||
return encoding == RGB8 || encoding == BGR8 ||
|
||||
encoding == RGBA8 || encoding == BGRA8 ||
|
||||
encoding == RGB16 || encoding == BGR16 ||
|
||||
encoding == RGBA16 || encoding == BGRA16;
|
||||
}
|
||||
|
||||
static inline bool isMono(const std::string& encoding)
|
||||
{
|
||||
return encoding == MONO8 || encoding == MONO16;
|
||||
}
|
||||
|
||||
static inline bool isBayer(const std::string& encoding)
|
||||
{
|
||||
return encoding == BAYER_RGGB8 || encoding == BAYER_BGGR8 ||
|
||||
encoding == BAYER_GBRG8 || encoding == BAYER_GRBG8 ||
|
||||
encoding == BAYER_RGGB16 || encoding == BAYER_BGGR16 ||
|
||||
encoding == BAYER_GBRG16 || encoding == BAYER_GRBG16;
|
||||
}
|
||||
|
||||
static inline bool hasAlpha(const std::string& encoding)
|
||||
{
|
||||
return encoding == RGBA8 || encoding == BGRA8 ||
|
||||
encoding == RGBA16 || encoding == BGRA16;
|
||||
}
|
||||
|
||||
static inline int numChannels(const std::string& encoding)
|
||||
{
|
||||
// First do the common-case encodings
|
||||
if (encoding == MONO8 ||
|
||||
encoding == MONO16)
|
||||
return 1;
|
||||
if (encoding == BGR8 ||
|
||||
encoding == RGB8 ||
|
||||
encoding == BGR16 ||
|
||||
encoding == RGB16)
|
||||
return 3;
|
||||
if (encoding == BGRA8 ||
|
||||
encoding == RGBA8 ||
|
||||
encoding == BGRA16 ||
|
||||
encoding == RGBA16)
|
||||
return 4;
|
||||
if (encoding == BAYER_RGGB8 ||
|
||||
encoding == BAYER_BGGR8 ||
|
||||
encoding == BAYER_GBRG8 ||
|
||||
encoding == BAYER_GRBG8 ||
|
||||
encoding == BAYER_RGGB16 ||
|
||||
encoding == BAYER_BGGR16 ||
|
||||
encoding == BAYER_GBRG16 ||
|
||||
encoding == BAYER_GRBG16)
|
||||
return 1;
|
||||
|
||||
// Now all the generic content encodings
|
||||
// TODO: Rewrite with regex when ROS supports C++11
|
||||
for (size_t i=0; i < sizeof(ABSTRACT_ENCODING_PREFIXES) / sizeof(*ABSTRACT_ENCODING_PREFIXES); i++)
|
||||
{
|
||||
std::string prefix = ABSTRACT_ENCODING_PREFIXES[i];
|
||||
if (encoding.substr(0, prefix.size()) != prefix)
|
||||
continue;
|
||||
if (encoding.size() == prefix.size())
|
||||
return 1; // ex. 8UC -> 1
|
||||
int n_channel = atoi(encoding.substr(prefix.size(),
|
||||
encoding.size() - prefix.size()).c_str()); // ex. 8UC5 -> 5
|
||||
if (n_channel != 0)
|
||||
return n_channel; // valid encoding string
|
||||
}
|
||||
|
||||
if (encoding == YUV422)
|
||||
return 2;
|
||||
|
||||
throw std::runtime_error("Unknown encoding " + encoding);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int bitDepth(const std::string& encoding)
|
||||
{
|
||||
if (encoding == MONO16)
|
||||
return 16;
|
||||
if (encoding == MONO8 ||
|
||||
encoding == BGR8 ||
|
||||
encoding == RGB8 ||
|
||||
encoding == BGRA8 ||
|
||||
encoding == RGBA8 ||
|
||||
encoding == BAYER_RGGB8 ||
|
||||
encoding == BAYER_BGGR8 ||
|
||||
encoding == BAYER_GBRG8 ||
|
||||
encoding == BAYER_GRBG8)
|
||||
return 8;
|
||||
|
||||
if (encoding == MONO16 ||
|
||||
encoding == BGR16 ||
|
||||
encoding == RGB16 ||
|
||||
encoding == BGRA16 ||
|
||||
encoding == RGBA16 ||
|
||||
encoding == BAYER_RGGB16 ||
|
||||
encoding == BAYER_BGGR16 ||
|
||||
encoding == BAYER_GBRG16 ||
|
||||
encoding == BAYER_GRBG16)
|
||||
return 16;
|
||||
|
||||
// Now all the generic content encodings
|
||||
// TODO: Rewrite with regex when ROS supports C++11
|
||||
for (size_t i=0; i < sizeof(ABSTRACT_ENCODING_PREFIXES) / sizeof(*ABSTRACT_ENCODING_PREFIXES); i++)
|
||||
{
|
||||
std::string prefix = ABSTRACT_ENCODING_PREFIXES[i];
|
||||
if (encoding.substr(0, prefix.size()) != prefix)
|
||||
continue;
|
||||
if (encoding.size() == prefix.size())
|
||||
return atoi(prefix.c_str()); // ex. 8UC -> 8
|
||||
int n_channel = atoi(encoding.substr(prefix.size(),
|
||||
encoding.size() - prefix.size()).c_str()); // ex. 8UC10 -> 10
|
||||
if (n_channel != 0)
|
||||
return atoi(prefix.c_str()); // valid encoding string
|
||||
}
|
||||
|
||||
if (encoding == YUV422)
|
||||
return 8;
|
||||
|
||||
throw std::runtime_error("Unknown encoding " + encoding);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,20 +0,0 @@
|
||||
import os
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
from launch import LaunchDescription
|
||||
from launch_ros.actions import Node
|
||||
|
||||
def generate_launch_description():
|
||||
config = os.path.join(
|
||||
get_package_share_directory('image2rtsp'),
|
||||
'config',
|
||||
'parameters.yaml'
|
||||
)
|
||||
|
||||
return LaunchDescription([
|
||||
Node(
|
||||
package='image2rtsp',
|
||||
executable='image2rtsp',
|
||||
name='image2rtsp',
|
||||
parameters=[config]
|
||||
)
|
||||
])
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>image2rtsp</name>
|
||||
<version>0.0.0</version>
|
||||
<description>topic to RTSP stream package</description>
|
||||
<maintainer email="dmalad@rptu.de">dmitry</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
|
||||
<depend>rclcpp</depend>
|
||||
<depend>sensor_msgs</depend>
|
||||
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
<exec_depend>ros2launch</exec_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
Whitespace-only changes.
@@ -1,15 +0,0 @@
|
||||
import cv2
|
||||
|
||||
cap = cv2.VideoCapture('rtsp://127.0.0.1:8554/back')
|
||||
|
||||
while True:
|
||||
ret, frame = cap.read()
|
||||
|
||||
if ret:
|
||||
cv2.imshow('RTSP Stream', frame)
|
||||
|
||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||
break
|
||||
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
File renamed without changes.
Reference in new issue
Block a user