Implement rtsp pusher.
This commit is contained in:
parent
a66b965087
commit
f34bfbc22f
10
.vscode/launch.json
vendored
10
.vscode/launch.json
vendored
@ -5,11 +5,11 @@
|
||||
"name": "AppDebug",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"miDebuggerPath": "/opt/aarch64-v01c01-linux-gnu-gcc/lib/gdb-14.1/bin/aarch64-linux-gnu-gdb",
|
||||
"miDebuggerServerAddress": "192.168.8.149:8080",
|
||||
"program": "${workspaceFolder}/build/Tools/SensorCli/SensorCli",
|
||||
"miDebuggerPath": "/opt/aarch64-v01c01-linux-gnu-gcc/lib/gdb-10.2/bin/aarch64-linux-gnu-gdb",
|
||||
"miDebuggerServerAddress": "192.168.8.115:8080",
|
||||
"program": "${workspaceFolder}/build/Main/PassengerStatistics",
|
||||
"args": [],
|
||||
"stopAtEntry": true,
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
@ -20,7 +20,7 @@
|
||||
"useExtendedRemote": true,
|
||||
"setupCommands": [
|
||||
{
|
||||
"text": "set remote exec-file /data/sdcard/SensorCli",
|
||||
"text": "set remote exec-file /data/sdcard/PassengerStatistics/PassengerStatistics",
|
||||
"description": "设置嵌入式单板加载的程序",
|
||||
"ignoreFailures": false
|
||||
}
|
||||
|
@ -1,5 +1,17 @@
|
||||
add_executable(PassengerStatistics main.cpp)
|
||||
add_executable(PassengerStatistics main.cpp
|
||||
Live555RtspPusher.h Live555RtspPusher.cpp
|
||||
VideoInput.h VideoInput.cpp
|
||||
)
|
||||
|
||||
target_include_directories(PassengerStatistics
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty/rw_mpp/include
|
||||
)
|
||||
|
||||
target_link_directories(PassengerStatistics
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty/rw_mpp/lib
|
||||
)
|
||||
|
||||
target_link_libraries(PassengerStatistics
|
||||
PRIVATE Universal
|
||||
PRIVATE rw_mpp
|
||||
)
|
12
Main/Live555RtspPusher.cpp
Normal file
12
Main/Live555RtspPusher.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "Live555RtspPusher.h"
|
||||
|
||||
Live555RtspPusher::Live555RtspPusher(boost::asio::io_context &ioContext) : m_ioContext(ioContext), m_socket(ioContext) {
|
||||
using boost::asio::ip::udp;
|
||||
m_socket.open(udp::v4());
|
||||
}
|
||||
|
||||
void Live555RtspPusher::push(const uint8_t *data, uint32_t size) {
|
||||
using boost::asio::ip::udp;
|
||||
udp::endpoint point(udp::v4(), 6666);
|
||||
m_socket.send_to(boost::asio::const_buffer(data, size), point);
|
||||
}
|
16
Main/Live555RtspPusher.h
Normal file
16
Main/Live555RtspPusher.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __LIVE555RTSPPUSHER_H__
|
||||
#define __LIVE555RTSPPUSHER_H__
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
|
||||
class Live555RtspPusher {
|
||||
public:
|
||||
Live555RtspPusher(boost::asio::io_context &ioContext);
|
||||
void push(const uint8_t *data, uint32_t size);
|
||||
|
||||
private:
|
||||
boost::asio::io_context &m_ioContext;
|
||||
boost::asio::ip::udp::socket m_socket;
|
||||
};
|
||||
#endif // __LIVE555RTSPPUSHER_H__
|
128
Main/VideoInput.cpp
Normal file
128
Main/VideoInput.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
#include "VideoInput.h"
|
||||
#include "BoostLog.h"
|
||||
#include "rw_mpp_api.h"
|
||||
#include <chrono>
|
||||
|
||||
VideoInput::VideoInput(int32_t width, int32_t height) : m_width(width), m_height(height) {
|
||||
}
|
||||
|
||||
VideoInput::~VideoInput() {
|
||||
if (isStarted()) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
bool VideoInput::start() {
|
||||
if (!m_exit) {
|
||||
LOG(warning) << "camera already started...";
|
||||
return false;
|
||||
}
|
||||
S_video_cfg vcfg;
|
||||
vcfg.sns_w = -1;
|
||||
vcfg.sns_h = -1;
|
||||
vcfg.img_w = m_width;
|
||||
vcfg.img_h = m_height;
|
||||
m_vid = 0;
|
||||
m_exit = false;
|
||||
int status = rw_mpp__video_start(m_vid, &vcfg);
|
||||
if (status != 0) {
|
||||
LOG(error) << "rw_mpp__video_start() failed, status: " << status;
|
||||
m_vid = -1;
|
||||
} else {
|
||||
m_thread = std::thread(&VideoInput::run, this);
|
||||
}
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
void VideoInput::stop() {
|
||||
m_exit = true;
|
||||
if (m_encodeThread.joinable()) {
|
||||
m_encodeThread.join();
|
||||
}
|
||||
if (m_thread.joinable()) {
|
||||
m_thread.join();
|
||||
}
|
||||
rw_mpp__video_stop(m_vid);
|
||||
rw_mpp__venc_stop(m_encodeChannel);
|
||||
m_vid = -1;
|
||||
m_encodeChannel = -1;
|
||||
}
|
||||
|
||||
bool VideoInput::isStarted() const {
|
||||
return !m_exit;
|
||||
}
|
||||
|
||||
bool VideoInput::startEncode() {
|
||||
m_encodeChannel = 0;
|
||||
S_venc_config config;
|
||||
memset(&config, 0, sizeof(S_venc_config));
|
||||
config.codec = CODEC_H264;
|
||||
config.profile = H264_main;
|
||||
config.raw_max_width = 2960;
|
||||
config.raw_max_height = 1664;
|
||||
config.width = 1280;
|
||||
config.height = 720;
|
||||
config.gop = 15;
|
||||
config.framerate = 15;
|
||||
config.rc_type = RC_VBR;
|
||||
|
||||
S_venc_rc_vbr vbr;
|
||||
memset(&vbr, 0, sizeof(S_venc_rc_vbr));
|
||||
vbr.max_bitrate = 1024;
|
||||
vbr.stats_time = 1;
|
||||
config.rc_param = &vbr;
|
||||
int status = rw_mpp__venc_start(m_encodeChannel, &config, -1);
|
||||
if (status != 0) {
|
||||
LOG(error) << "rw_mpp__venc_start() failed, status: " << status;
|
||||
} else {
|
||||
m_encodeThread = std::thread(&VideoInput::encodeRun, this);
|
||||
}
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
void VideoInput::setPacketHandler(const PacketHandler &hanlder) {
|
||||
m_handler = hanlder;
|
||||
}
|
||||
|
||||
void VideoInput::run() {
|
||||
using namespace std::chrono_literals;
|
||||
S_mpp_img img;
|
||||
while (!m_exit) {
|
||||
int status = rw_mpp__video_recv(m_vid, &img, 2000);
|
||||
if (status != 0) {
|
||||
LOG(error) << "rw_mpp__video_recv() failed, status: " << status;
|
||||
std::this_thread::sleep_for(500ms);
|
||||
continue;
|
||||
}
|
||||
// LOG(info) << "camera frame size: " << img.width << "x" << img.height;
|
||||
if (m_encodeChannel >= 0) {
|
||||
rw_mpp__venc_send(m_encodeChannel, &img);
|
||||
}
|
||||
|
||||
status = rw_mpp__video_free(m_vid, &img);
|
||||
if (status != 0) {
|
||||
LOG(error) << "rw_mpp__video_free() failed, status: " << status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoInput::encodeRun() {
|
||||
using namespace std::chrono_literals;
|
||||
S_mpp_venc_frame frame;
|
||||
while (!m_exit) {
|
||||
int status = rw_mpp__venc_recv(m_encodeChannel, &frame, 1000);
|
||||
if (status != 0) {
|
||||
std::this_thread::sleep_for(500ms);
|
||||
LOG(error) << "rw_mpp__venc_recv() failed, status: " << status;
|
||||
continue;
|
||||
}
|
||||
LOG(info) << "encode frame data size: " << frame.len << ", is key frame: " << frame.is_key_frame;
|
||||
if (m_handler) {
|
||||
m_handler(frame.data, frame.len);
|
||||
}
|
||||
status = rw_mpp__venc_free(m_encodeChannel, &frame);
|
||||
if (status != 0) {
|
||||
LOG(error) << "rw_mpp__venc_free() failed, status: " << status;
|
||||
}
|
||||
}
|
||||
}
|
34
Main/VideoInput.h
Normal file
34
Main/VideoInput.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef __VIDEOINPUT_H__
|
||||
#define __VIDEOINPUT_H__
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
class VideoInput {
|
||||
public:
|
||||
using PacketHandler = std::function<void(const uint8_t *, uint32_t)>;
|
||||
VideoInput(int32_t width, int32_t height);
|
||||
~VideoInput();
|
||||
bool start();
|
||||
void stop();
|
||||
bool isStarted() const;
|
||||
bool startEncode();
|
||||
void setPacketHandler(const PacketHandler &hanlder);
|
||||
|
||||
protected:
|
||||
void run();
|
||||
void encodeRun();
|
||||
|
||||
private:
|
||||
int32_t m_width;
|
||||
int32_t m_height;
|
||||
|
||||
int32_t m_vid = -1;
|
||||
int32_t m_encodeChannel = -1;
|
||||
bool m_exit = true;
|
||||
std::thread m_thread;
|
||||
std::thread m_encodeThread;
|
||||
PacketHandler m_handler;
|
||||
};
|
||||
#endif // __VIDEOINPUT_H__
|
@ -1,7 +1,52 @@
|
||||
#include "BoostLog.h"
|
||||
#include "DateTime.h"
|
||||
#include "IoContext.h"
|
||||
#include "Live555RtspPusher.h"
|
||||
#include "VideoInput.h"
|
||||
#include "rw_mpp_api.h"
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
#include <fstream>
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
int main(int argc, char const *argv[]) {
|
||||
LOG(info) << "app start...";
|
||||
int status = rw_mpp__init();
|
||||
if (status != 0) {
|
||||
LOG(error) << "rw_mpp__init() failed, status: " << status;
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
auto ioContext = Amass::Singleton<IoContext>::instance<Amass::Construct>();
|
||||
auto pusher = std::make_shared<Live555RtspPusher>(*ioContext->ioContext());
|
||||
|
||||
std::shared_ptr<std::ofstream> ofs;
|
||||
std::ostringstream oss;
|
||||
oss << "/data/sdcard/video/record_" << DateTime::currentDateTime().toString("%Y%m%d%H%M%S") << ".h264";
|
||||
auto path = oss.str();
|
||||
LOG(info) << "write h264 to " << path;
|
||||
ofs = std::make_shared<std::ofstream>(path, std::ofstream::binary);
|
||||
|
||||
auto video = std::make_shared<VideoInput>(2592, 1536);
|
||||
video->setPacketHandler([&](const uint8_t *data, uint32_t size) {
|
||||
ofs->write(reinterpret_cast<const char *>(data), size);
|
||||
pusher->push(data, size);
|
||||
});
|
||||
video->start();
|
||||
video->startEncode();
|
||||
boost::asio::signal_set signals(*ioContext->ioContext(), SIGINT);
|
||||
signals.async_wait([&](boost::system::error_code const &, int signal) {
|
||||
LOG(info) << "capture " << (signal == SIGINT ? "SIGINT" : "SIGTERM") << ",stop!";
|
||||
video.reset();
|
||||
rw_mpp__finalize();
|
||||
ioContext->ioContext()->stop();
|
||||
});
|
||||
|
||||
ioContext->run<IoContext::Mode::Synchronous>();
|
||||
} catch (const boost::exception &e) {
|
||||
LOG(error) << "error";
|
||||
} catch (const std::exception &e) {
|
||||
LOG(error) << e.what();
|
||||
}
|
||||
|
||||
rw_mpp__finalize();
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,6 +29,9 @@ function cmake_scan() {
|
||||
}
|
||||
|
||||
function build() {
|
||||
if [ -n "$1" ]; then
|
||||
TARGET_IP=$1
|
||||
fi
|
||||
if [ ! -f "${build_path}/CMakeCache.txt" ]; then
|
||||
cmake_scan
|
||||
fi
|
||||
@ -58,17 +61,17 @@ function init() {
|
||||
echo "put ${base_path}/resources/authorized_keys /system/.ssh" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/gdb-10.2/bin/gdbserver /system/bin" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_date_time* /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_regex* /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
echo "put ${BOOST_LIBDIR}/libboost_regex.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_log_setup.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_log.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_chrono.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_filesystem.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_atomic.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_container.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_thread.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_url.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_json.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
# echo "put ${BOOST_LIBDIR}/libboost_program_options.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
echo "put ${BOOST_LIBDIR}/libboost_atomic.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
echo "put ${BOOST_LIBDIR}/libboost_container.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
echo "put ${BOOST_LIBDIR}/libboost_thread.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
echo "put ${BOOST_LIBDIR}/libboost_url.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
echo "put ${BOOST_LIBDIR}/libboost_json.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
echo "put ${BOOST_LIBDIR}/libboost_program_options.so.1.84.0 /system/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
||||
|
||||
ssh -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} "echo 'mount -o remount rw /' >> /etc/profile"
|
||||
ssh -i resources/ssh_host_rsa_key_ok root@${TARGET_IP} "echo 'mount -o remount rw /system/' >> /etc/profile"
|
||||
@ -98,7 +101,7 @@ function main() {
|
||||
shift 1
|
||||
case $cmd in
|
||||
build)
|
||||
build
|
||||
build $@
|
||||
;;
|
||||
scan)
|
||||
cmake_scan
|
||||
|
Loading…
Reference in New Issue
Block a user