通过webrtc成功。
This commit is contained in:
parent
74a38cb67a
commit
d54ffd6541
2
.vscode/c_cpp_properties.json
vendored
2
.vscode/c_cpp_properties.json
vendored
@ -4,7 +4,7 @@
|
|||||||
"name": "Linux",
|
"name": "Linux",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"${workspaceFolder}/**",
|
"${workspaceFolder}/**",
|
||||||
"${workspaceFolder}/3rdparty/ds_pedestrian_mot_hisi/include",
|
"/opt/aarch64-v01c01-linux-gnu-gcc/lib/libdatachannel-0.22.5/include",
|
||||||
"/opt/aarch64-v01c01-linux-gnu-gcc/lib/boost_1_87_0/include",
|
"/opt/aarch64-v01c01-linux-gnu-gcc/lib/boost_1_87_0/include",
|
||||||
"/opt/aarch64-v01c01-linux-gnu-gcc/lib/libdatachannel-0.22.5",
|
"/opt/aarch64-v01c01-linux-gnu-gcc/lib/libdatachannel-0.22.5",
|
||||||
"/opt/aarch64-v01c01-linux-gnu-gcc/lib/ZLMediaKit/include",
|
"/opt/aarch64-v01c01-linux-gnu-gcc/lib/ZLMediaKit/include",
|
||||||
|
156
3rdparty/fsan_sensorsdk/include/sensorsdk_api.h
vendored
Normal file
156
3rdparty/fsan_sensorsdk/include/sensorsdk_api.h
vendored
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#ifndef __SENSOR_SDK_API_H__
|
||||||
|
#define __SENSOR_SDK_API_H__
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SENSOR_SDK_SUCC = 0,
|
||||||
|
SENSOR_SDK_INVALID_INPARAM, //参数非法
|
||||||
|
SENSOR_SDK_NOT_INIT, //未初始化
|
||||||
|
SENSOR_SDK_LICENSE_INIT_FAIL, //license 库初始化失败
|
||||||
|
SENSOR_SDK_NOT_AUTH, //未授权
|
||||||
|
SENSOR_SDK_MUTI_PROCESS_INIT, //多个實例初始化
|
||||||
|
SENSOR_SDK_AUTOLENS_GET_PARAM, //获取参数失败
|
||||||
|
SENSOR_SDK_AUTOLENS_SET_PARAM, //设置参数失败
|
||||||
|
SENSOR_SDK_AUTOLENS_SET_AF_PARAM,//设置AF参数失败
|
||||||
|
SENSOR_SDK_ERROR, //其他错误
|
||||||
|
|
||||||
|
}SENSOR_SDK_ERROR_TYPE;
|
||||||
|
//autolens
|
||||||
|
enum {
|
||||||
|
|
||||||
|
SensorSDK_AutoLens_Type_ZeroCheck=0x0, //零点矫正, 无参数
|
||||||
|
SensorSDK_AutoLens_Type_ZoomIn , // 参数 1-10为速度 ,-1 为停止 ,以下无特殊时同此
|
||||||
|
SensorSDK_AutoLens_Type_ZoomOut ,
|
||||||
|
SensorSDK_AutoLens_Type_FocusNear ,
|
||||||
|
SensorSDK_AutoLens_Type_FocusFar ,
|
||||||
|
SensorSDK_AutoLens_Type_FocusAuto , //自动聚焦
|
||||||
|
SensorSDK_AutoLens_Type_EnableAuto , // 设置是否启用自动聚焦
|
||||||
|
SensorSDK_AutoLens_Type_ZoomFocus , // 精确定位到指定的位置,
|
||||||
|
SensorSDK_AutoLens_Type_ZoomPos , // int 精确定位
|
||||||
|
SensorSDK_AutoLens_Type_ZoomRange , // int 定位范围
|
||||||
|
SensorSDK_AutoLens_Type_FocusPos , // int 精确定位
|
||||||
|
SensorSDK_AutoLens_Type_FocusRange , // int 获取 取值范围,精确定位时用
|
||||||
|
SensorSDK_AutoLens_Type_ZoomRate , // int 300 代表3.00倍
|
||||||
|
SensorSDK_AutoLens_Type_IRCUT , // 0 全波段, 1 可见光模式, 2 红外模式
|
||||||
|
|
||||||
|
//new
|
||||||
|
SensorSDK_AutoLens_Type_Iris_OPEN, // 光圈大 //需要带步长参数1-64 光圈范围固定0-0X3FF
|
||||||
|
SensorSDK_AutoLens_Type_Iris_CLOSE, // 光圈小 //需要带步长参数1-64
|
||||||
|
SensorSDK_AutoLens_Type_IrisPos, // 获取光圈位置
|
||||||
|
|
||||||
|
SensorSDK_AutoLens_Type_Fov, //获取对角线视场角精确到0.01度 60度 6000(表示60度)
|
||||||
|
SensorSDK_AutoLens_Type_Auto_Check, //设置镜头曲线校准
|
||||||
|
SensorSDK_AutoLens_Type_AF_Status, //获取 AF状态
|
||||||
|
SensorSDK_AutoLens_Type_ZoomPos_By_Fov, //获取 输入FOV输出ZOOMPOS 调用get接口
|
||||||
|
SensorSDK_AutoLens_Type_Fov_By_ZoomPos, //获取 输入ZOOMPOS的值输出FOV 调用get接口
|
||||||
|
SensorSDK_AutoLens_Type_Efi, //获取焦距
|
||||||
|
SensorSDK_AutoLens_Type_Lens_Offset, //获取镜头中心点偏移量输出水平偏移量和垂直偏移量(**保留暂不使用**)
|
||||||
|
SensorSDK_AutoLens_Type_Check_Offset, //设置镜头中心偏移量校准
|
||||||
|
SensorSDK_AutoLens_Type_IRCUTLensAuto=0x100, //设置 0 :夜晚1:白天
|
||||||
|
SensorSDK_AutoLens_Type_Motor_Hysteresis=0x101, //马达间隙(1-100)步(**保留暂不使用**)
|
||||||
|
|
||||||
|
|
||||||
|
}SENSORSDK_AUTOLENS_TYPE_E;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int nStop; // 1- 停止
|
||||||
|
int nSpeed; // 速度 1-10, nStop==0时有效
|
||||||
|
|
||||||
|
}SensorSDK_AutoLens_Param_Base_T;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
|
||||||
|
SensorSDK_AutoLens_Param_Base_T Param_Base;
|
||||||
|
int nZoomRate; // 300 代表 3.00倍
|
||||||
|
int nIrCut; // 0-全波段,1-可见光,2红外模式
|
||||||
|
int nZoomPos; // 定位, 先获取范围,再定位,定位必须是有效范围内
|
||||||
|
int nZoomRange; // 范围
|
||||||
|
int nFocusPos; // 定位
|
||||||
|
int nFocusRange; // 聚焦定位取值范围
|
||||||
|
int nEnableAuto; // 使能 自动 聚焦功能
|
||||||
|
int nZoomFocusPos[2]; // nZoomFocusPos[0]:focuspos,nZoomFocusPos[1]:zoompos
|
||||||
|
int nIrStep; // 光圈步长1-64
|
||||||
|
int nIrPos; // 定位
|
||||||
|
int nFOV; // 对角线视场角[ 1, 6000]表示 0.01度到60度
|
||||||
|
int nEFI; // 焦距
|
||||||
|
int nAFStatus; // 自动镜头状态
|
||||||
|
int nFOVZoomPos; // nFOVZoomPos 输入输出
|
||||||
|
int nIRCUTLensAuto; // 0-夜晚 1-白天
|
||||||
|
int ress[4];
|
||||||
|
}Params;
|
||||||
|
}SENSOR_SDK_AUTOLENS_PARAM_T;
|
||||||
|
|
||||||
|
enum SENSOR_SDK_AF_STATUS_E
|
||||||
|
{
|
||||||
|
SENSOR_SDK_AF_STATUS_IDLE = 0x1,
|
||||||
|
SENSOR_SDK_AF_STATUS_DO_ZOOM,
|
||||||
|
SENSOR_SDK_AF_STATUS_DO_FOCUS,
|
||||||
|
SENSOR_SDK_AF_STATUS_DO_AUTO_FOCUS,
|
||||||
|
SENSOR_SDK_AF_STATUS_ZOOM_ING,
|
||||||
|
SENSOR_SDK_AF_STATUS_FOCUS_ING,
|
||||||
|
SENSOR_SDK_AF_STATUS_AUTO_FOCUS_ING,
|
||||||
|
SENSOR_SDK_AF_STATUS_DETECT,
|
||||||
|
SENSOR_SDK_AF_STATUS_TEST,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _SensorSDK_CameraLens
|
||||||
|
{
|
||||||
|
int AFControlModel; //对焦控制方式 0----自动 1----半自动 2----手动
|
||||||
|
int AFArea; //对焦区域选择 (保留)0----全区域对焦 1----中心对焦
|
||||||
|
int AFSearchModel; //对焦区搜索方式 0 --- 全景, 1 --- 1.5m, 2 --- 3m, 3 --- 6m, 4 --- 无穷远
|
||||||
|
int AFSensitivity; //对焦灵敏度 0 ~255
|
||||||
|
int DigitZoomEnable; //数字ZOOM允许
|
||||||
|
int IrisControl; //光圈调节0 自动 1手动
|
||||||
|
} SensorSDK_CameraLens;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
// SDK 初始化接口
|
||||||
|
// nFlashPartIdx : 软件授权信息存放的分区索引号,注意分区需要自己提前创建好
|
||||||
|
// 例如分区为/dev/mmcblk0p5,此处参数取值为5
|
||||||
|
// 分区为/dev/mtd6,此处参数取值为6
|
||||||
|
// BoardLine 板接口定义,000,第一位代表zoomfocus顺序,后面两个代表两个电机方向;每位取值为 0或者1
|
||||||
|
// szLensType 镜头型号,可取值如下
|
||||||
|
/*
|
||||||
|
"MUXIA_5X",
|
||||||
|
"RICOM_AF3610_4K","YS_15_3_XM02","RICOM_3312_4K","RICOM_27135_6MP", "RICOM_2812_5MP","RICOM_2812_2MP",
|
||||||
|
"YT_6022_3MP","YT_3610_3MP","YT_3611_4K","YT_27135_HD","YT_27135_4MP","YT_2712_HD","YT_2812_4MP","YT_2812_2MP","RICOM_2812_3MP",
|
||||||
|
"YT_550_2MP","RICOM_5M_50MM_1_27F","YT6022","YT3013","YT2712","YT3610","3.6-10mm","YT2812","YT3015","RICON2814","RICON2812","YT2808",
|
||||||
|
"2.8-8mm","RICOM_4K_AF2710DC","RICOM_4K_33_120MM_14F","RICOM_3M_28_120MM_14F","RICOM_5M_38_100MM","RICOM_2M_22_120MM_14F","RICOM_3M_28_80MM"
|
||||||
|
*/
|
||||||
|
// szAutoLensParmPath: 保存当前变焦状态用的路径,路径必须可写
|
||||||
|
// pCameralens: 自动聚焦镜头参数
|
||||||
|
|
||||||
|
//return 错误码见 SENSOR_SDK_ERROR_TYPE
|
||||||
|
|
||||||
|
//初始化接口
|
||||||
|
int SensorSdk_Init(int nFlashPartIdx,char *szBoardLine,char *szLensType ,
|
||||||
|
char *szAutoLensParmPath /* 保存当前变焦状态用的路径 */, SensorSDK_CameraLens *pCameralens = 0);
|
||||||
|
|
||||||
|
//获取授权状态 SENSOR_SDK_SUCC-授权成功
|
||||||
|
int SensorSdk_GetAuthStatus();
|
||||||
|
|
||||||
|
// 镜头变焦变倍 接口
|
||||||
|
// 设置 动作
|
||||||
|
// nType : 见 SensorSDK_AutoLens_Type_XXX 宏定义
|
||||||
|
// nParam : SENSOR_SDK_AUTOLENS_PARAM_T
|
||||||
|
int SensorSdk_AutoLens_SetParam(int nDev,int nType,SENSOR_SDK_AUTOLENS_PARAM_T *pParam);
|
||||||
|
// 获取当前 信息
|
||||||
|
int SensorSdk_AutoLens_GetParam(int nDev,int nType,SENSOR_SDK_AUTOLENS_PARAM_T *pParam);
|
||||||
|
//設置自动聚焦镜头参数
|
||||||
|
int SensorSdk_AutoLens_SetAFParam(SensorSDK_CameraLens *pCameralens);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
BIN
3rdparty/fsan_sensorsdk/ko/ants_spi_ms41908_ex.ko
vendored
Normal file
BIN
3rdparty/fsan_sensorsdk/ko/ants_spi_ms41908_ex.ko
vendored
Normal file
Binary file not shown.
BIN
3rdparty/fsan_sensorsdk/libs/libsensorsdk.so
vendored
Normal file
BIN
3rdparty/fsan_sensorsdk/libs/libsensorsdk.so
vendored
Normal file
Binary file not shown.
@ -10,6 +10,7 @@ option(CROSS_BUILD "build for embeded product." ON)
|
|||||||
if(CROSS_BUILD)
|
if(CROSS_BUILD)
|
||||||
set(Libraries_ROOT /opt/aarch64-v01c01-linux-gnu-gcc/lib)
|
set(Libraries_ROOT /opt/aarch64-v01c01-linux-gnu-gcc/lib)
|
||||||
set(OpenCV_DIR ${Libraries_ROOT}/opencv-4.11.0/lib/cmake/opencv4)
|
set(OpenCV_DIR ${Libraries_ROOT}/opencv-4.11.0/lib/cmake/opencv4)
|
||||||
|
set(LibDataChannel_DIR ${Libraries_ROOT}/libdatachannel-0.22.5/lib/cmake/LibDataChannel)
|
||||||
set(OPENSSL_ROOT_DIR ${Libraries_ROOT}/openssl-3.4.1)
|
set(OPENSSL_ROOT_DIR ${Libraries_ROOT}/openssl-3.4.1)
|
||||||
set(OPENSSL_LIBRARY_DIRS ${OPENSSL_ROOT_DIR}/libs)
|
set(OPENSSL_LIBRARY_DIRS ${OPENSSL_ROOT_DIR}/libs)
|
||||||
set(SCTP_ROOT ${Libraries_ROOT}/usrsctp-0.9.5.0)
|
set(SCTP_ROOT ${Libraries_ROOT}/usrsctp-0.9.5.0)
|
||||||
|
@ -1,28 +1,39 @@
|
|||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
find_package(OpenCV REQUIRED)
|
find_package(OpenCV REQUIRED)
|
||||||
|
find_package(LibDataChannel REQUIRED)
|
||||||
|
find_package(Boost COMPONENTS json REQUIRED)
|
||||||
|
|
||||||
add_executable(PassengerStatistics main.cpp
|
add_executable(PassengerStatistics main.cpp
|
||||||
|
Camera.h Camera.cpp
|
||||||
ImageUtilities.h ImageUtilities.cpp
|
ImageUtilities.h ImageUtilities.cpp
|
||||||
RtspServer.h RtspServer.cpp
|
RtspServer.h RtspServer.cpp
|
||||||
VideoInput.h VideoInput.cpp
|
VideoInput.h VideoInput.cpp
|
||||||
|
|
||||||
|
WebRTC/Streamer.h WebRTC/Streamer.cpp
|
||||||
|
WebRTC/Helpers.h WebRTC/Helpers.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(PassengerStatistics
|
target_include_directories(PassengerStatistics
|
||||||
PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty/rw_mpp/include
|
PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty/rw_mpp/include
|
||||||
|
PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty/fsan_sensorsdk/include
|
||||||
PRIVATE ${ZLMediaKit_INCLUDE_DIR}
|
PRIVATE ${ZLMediaKit_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_directories(PassengerStatistics
|
target_link_directories(PassengerStatistics
|
||||||
PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty/rw_mpp/lib
|
PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty/rw_mpp/lib
|
||||||
|
PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty/fsan_sensorsdk/libs
|
||||||
PRIVATE ${ZLMediaKit_LIBRARY_DIRS}
|
PRIVATE ${ZLMediaKit_LIBRARY_DIRS}
|
||||||
PRIVATE ${OPENSSL_LIBRARY_DIRS}
|
PRIVATE ${OPENSSL_LIBRARY_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(PassengerStatistics
|
target_link_libraries(PassengerStatistics
|
||||||
PRIVATE Kylin::Core
|
PRIVATE Kylin::Core
|
||||||
|
PRIVATE LibDataChannel::LibDataChannel
|
||||||
PRIVATE OpenSSL::SSL
|
PRIVATE OpenSSL::SSL
|
||||||
PRIVATE OpenSSL::Crypto
|
PRIVATE OpenSSL::Crypto
|
||||||
|
PRIVATE Boost::json
|
||||||
PRIVATE rw_mpp
|
PRIVATE rw_mpp
|
||||||
|
PRIVATE sensorsdk
|
||||||
PRIVATE mk_api
|
PRIVATE mk_api
|
||||||
PRIVATE ${OpenCV_LIBS}
|
PRIVATE ${OpenCV_LIBS}
|
||||||
PRIVATE ${SCTP_LIBRARIES}
|
PRIVATE ${SCTP_LIBRARIES}
|
||||||
|
48
Main/Camera.cpp
Normal file
48
Main/Camera.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "Camera.h"
|
||||||
|
#include "Core/Logger.h"
|
||||||
|
#include "sensorsdk_api.h"
|
||||||
|
|
||||||
|
Camera::Camera() {
|
||||||
|
SensorSDK_CameraLens cameraLens = {};
|
||||||
|
cameraLens.AFControlModel = 2;
|
||||||
|
|
||||||
|
char boardLine[] = "000";
|
||||||
|
char lensType[] = "YT_2812_2MP";
|
||||||
|
char autoLensParmPath[] = "/data";
|
||||||
|
int status = SensorSdk_Init(7, boardLine, lensType, autoLensParmPath, &cameraLens);
|
||||||
|
if (status == 0) {
|
||||||
|
LOG(info) << "SensorSdk_Init() successed.";
|
||||||
|
} else {
|
||||||
|
LOG(info) << "SensorSdk_Init() failed.";
|
||||||
|
}
|
||||||
|
|
||||||
|
SENSOR_SDK_AUTOLENS_PARAM_T parameter = {0};
|
||||||
|
parameter.Params.nIrCut = 1;
|
||||||
|
status = SensorSdk_AutoLens_SetParam(0, SensorSDK_AutoLens_Type_IRCUT, ¶meter);
|
||||||
|
if (status == 0) {
|
||||||
|
LOG(info) << "SensorSdk_AutoLens_SetParam() successed.";
|
||||||
|
} else {
|
||||||
|
LOG(info) << "SensorSdk_AutoLens_SetParam() failed.";
|
||||||
|
}
|
||||||
|
initIrCutGpio();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::initIrCutGpio() {
|
||||||
|
constexpr auto initCommand = R"(
|
||||||
|
/system/bin/bspmm 0x179f0014 0x1200;
|
||||||
|
echo 84 > /sys/class/gpio/export;
|
||||||
|
echo out > /sys/class/gpio/gpio84/direction;
|
||||||
|
echo 83 > /sys/class/gpio/export;
|
||||||
|
echo out > /sys/class/gpio/gpio83/direction;
|
||||||
|
)";
|
||||||
|
system(initCommand);
|
||||||
|
|
||||||
|
constexpr auto dayCommand = R"(
|
||||||
|
echo 0 > /sys/class/gpio/gpio84/value;
|
||||||
|
echo 1 > /sys/class/gpio/gpio83/value;
|
||||||
|
sleep 1;
|
||||||
|
echo 0 > /sys/class/gpio/gpio84/value;
|
||||||
|
echo 0 > /sys/class/gpio/gpio83/value;
|
||||||
|
)";
|
||||||
|
system(dayCommand);
|
||||||
|
}
|
12
Main/Camera.h
Normal file
12
Main/Camera.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __CAMERA_H__
|
||||||
|
#define __CAMERA_H__
|
||||||
|
|
||||||
|
class Camera {
|
||||||
|
public:
|
||||||
|
Camera();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initIrCutGpio();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __CAMERA_H__
|
@ -87,8 +87,8 @@ bool VideoInput::startEncode() {
|
|||||||
config.raw_max_height = 1664;
|
config.raw_max_height = 1664;
|
||||||
config.width = 1280;
|
config.width = 1280;
|
||||||
config.height = 720;
|
config.height = 720;
|
||||||
config.gop = 15;
|
config.gop = 5;
|
||||||
config.framerate = 15;
|
config.framerate = 25;
|
||||||
config.rc_type = RC_VBR;
|
config.rc_type = RC_VBR;
|
||||||
|
|
||||||
S_venc_rc_vbr vbr;
|
S_venc_rc_vbr vbr;
|
||||||
|
32
Main/WebRTC/Helpers.cpp
Normal file
32
Main/WebRTC/Helpers.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "Helpers.h"
|
||||||
|
#include <mutex>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
Client::Client(std::shared_ptr<rtc::PeerConnection> pc) {
|
||||||
|
m_peerConnection = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Client::State Client::state() const {
|
||||||
|
std::shared_lock lock(m_mutex);
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::setState(State state) {
|
||||||
|
std::unique_lock lock(m_mutex);
|
||||||
|
m_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<rtc::PeerConnection> Client::peerConnection() const {
|
||||||
|
return m_peerConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientTrack::ClientTrack(std::string id, std::shared_ptr<ClientTrackData> trackData) {
|
||||||
|
this->id = id;
|
||||||
|
this->trackData = trackData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t currentTimeInMicroSeconds() {
|
||||||
|
struct timeval time;
|
||||||
|
gettimeofday(&time, NULL);
|
||||||
|
return uint64_t(time.tv_sec) * 1000 * 1000 + time.tv_usec;
|
||||||
|
}
|
48
Main/WebRTC/Helpers.h
Normal file
48
Main/WebRTC/Helpers.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef __HELPERS_H__
|
||||||
|
#define __HELPERS_H__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <rtc/rtc.hpp>
|
||||||
|
#include <shared_mutex>
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::weak_ptr<T> make_weak_ptr(std::shared_ptr<T> ptr) {
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t currentTimeInMicroSeconds();
|
||||||
|
|
||||||
|
struct ClientTrackData {
|
||||||
|
std::shared_ptr<rtc::Track> track;
|
||||||
|
std::shared_ptr<rtc::RtcpSrReporter> sender;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Client {
|
||||||
|
public:
|
||||||
|
enum class State {
|
||||||
|
Waiting,
|
||||||
|
WaitingForVideo,
|
||||||
|
WaitingForAudio,
|
||||||
|
Ready,
|
||||||
|
};
|
||||||
|
Client(std::shared_ptr<rtc::PeerConnection> pc);
|
||||||
|
State state() const;
|
||||||
|
void setState(State state);
|
||||||
|
std::shared_ptr<rtc::PeerConnection> peerConnection() const;
|
||||||
|
std::optional<std::shared_ptr<ClientTrackData>> video;
|
||||||
|
std::optional<std::shared_ptr<rtc::DataChannel>> dataChannel;
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable std::shared_mutex m_mutex;
|
||||||
|
State m_state = State::Waiting;
|
||||||
|
std::shared_ptr<rtc::PeerConnection> m_peerConnection;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ClientTrack {
|
||||||
|
std::string id;
|
||||||
|
std::shared_ptr<ClientTrackData> trackData;
|
||||||
|
ClientTrack(std::string id, std::shared_ptr<ClientTrackData> trackData);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __HELPERS_H__
|
187
Main/WebRTC/Streamer.cpp
Normal file
187
Main/WebRTC/Streamer.cpp
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
#include "Streamer.h"
|
||||||
|
#include "Core/Logger.h"
|
||||||
|
#include "Helpers.h"
|
||||||
|
#include <boost/asio/io_context.hpp>
|
||||||
|
#include <boost/asio/strand.hpp>
|
||||||
|
#include <boost/json/parse.hpp>
|
||||||
|
#include <boost/json/serialize.hpp>
|
||||||
|
#include <rtc/rtc.hpp>
|
||||||
|
|
||||||
|
class WebRTCStreamerPrivate {
|
||||||
|
public:
|
||||||
|
WebRTCStreamerPrivate(boost::asio::io_context &ioContext) : strand{ioContext.get_executor()} {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ClientTrackData> addVideo(const std::shared_ptr<rtc::PeerConnection> pc, const uint8_t payloadType,
|
||||||
|
const uint32_t ssrc, const std::string cname, const std::string msid,
|
||||||
|
const std::function<void(void)> onOpen) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
auto video = rtc::Description::Video(cname);
|
||||||
|
video.addH264Codec(payloadType);
|
||||||
|
video.addSSRC(ssrc, cname, msid, cname);
|
||||||
|
auto track = pc->addTrack(video);
|
||||||
|
|
||||||
|
auto rtpConfig = std::make_shared<rtc::RtpPacketizationConfig>(
|
||||||
|
ssrc, cname, payloadType, rtc::H264RtpPacketizer::defaultClockRate); // create RTP configuration
|
||||||
|
rtpConfig->startTimestamp = rtpConfig->secondsToTimestamp(
|
||||||
|
static_cast<double>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count()) / 1000);
|
||||||
|
|
||||||
|
auto packetizer = std::make_shared<rtc::H264RtpPacketizer>(rtc::NalUnit::Separator::StartSequence,
|
||||||
|
rtpConfig); // create packetizer
|
||||||
|
|
||||||
|
auto srReporter = std::make_shared<rtc::RtcpSrReporter>(rtpConfig); // add RTCP SR handler
|
||||||
|
packetizer->addToChain(srReporter);
|
||||||
|
|
||||||
|
auto nackResponder = std::make_shared<rtc::RtcpNackResponder>(); // add RTCP NACK handler
|
||||||
|
packetizer->addToChain(nackResponder);
|
||||||
|
|
||||||
|
track->setMediaHandler(packetizer); // set handler
|
||||||
|
track->onOpen(onOpen);
|
||||||
|
auto trackData = std::make_shared<ClientTrackData>();
|
||||||
|
trackData->track = track;
|
||||||
|
trackData->sender = srReporter;
|
||||||
|
return trackData;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Client> createPeerConnection(const rtc::Configuration &config, std::string id) {
|
||||||
|
auto pc = std::make_shared<rtc::PeerConnection>(config);
|
||||||
|
auto client = std::make_shared<Client>(pc);
|
||||||
|
|
||||||
|
pc->onStateChange([this, id](rtc::PeerConnection::State state) {
|
||||||
|
LOG(info) << "State: " << state;
|
||||||
|
if (state == rtc::PeerConnection::State::Disconnected || state == rtc::PeerConnection::State::Failed ||
|
||||||
|
state == rtc::PeerConnection::State::Closed) {
|
||||||
|
boost::asio::post(strand, [this, id]() { m_clients.erase(id); }); // remove disconnected client
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pc->onGatheringStateChange([this, wpc = make_weak_ptr(pc), id](rtc::PeerConnection::GatheringState state) {
|
||||||
|
LOG(info) << "Gathering State: " << state;
|
||||||
|
if (state == rtc::PeerConnection::GatheringState::Complete) {
|
||||||
|
if (auto pc = wpc.lock()) {
|
||||||
|
auto description = pc->localDescription();
|
||||||
|
boost::json::object message;
|
||||||
|
message["id"] = id;
|
||||||
|
message["type"] = description->typeString();
|
||||||
|
message["sdp"] = std::string(description.value());
|
||||||
|
websocket->send(boost::json::serialize(message)); // Gathering complete, send answer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client->video = addVideo(pc, 102, 1, "video-stream", "stream", [this, id, wc = make_weak_ptr(client)]() {
|
||||||
|
boost::asio::post(strand, [this, wc]() {
|
||||||
|
if (auto c = wc.lock()) {
|
||||||
|
c->setState(Client::State::Ready);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
LOG(info) << "Video from " << id << " opened";
|
||||||
|
});
|
||||||
|
|
||||||
|
auto dc = pc->createDataChannel("ping-pong");
|
||||||
|
dc->onOpen([id, wdc = make_weak_ptr(dc)]() {
|
||||||
|
if (auto dc = wdc.lock()) {
|
||||||
|
dc->send("Ping");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dc->onMessage(nullptr, [id, wdc = make_weak_ptr(dc)](std::string msg) {
|
||||||
|
LOG(info) << "Message from " << id << " received: " << msg;
|
||||||
|
if (auto dc = wdc.lock()) {
|
||||||
|
dc->send("Ping");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client->dataChannel = dc;
|
||||||
|
|
||||||
|
pc->setLocalDescription();
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
void onWebSocketMesssage(const boost::json::object &message) {
|
||||||
|
if (!message.contains("id") || !message.contains("type")) return;
|
||||||
|
std::string id = std::string(message.at("id").as_string());
|
||||||
|
std::string type = std::string(message.at("type").as_string());
|
||||||
|
if (type == "request") {
|
||||||
|
m_clients.emplace(id, createPeerConnection(configuration, id));
|
||||||
|
} else if (type == "answer") {
|
||||||
|
if (m_clients.count(id)) {
|
||||||
|
auto &peer = m_clients.at(id);
|
||||||
|
std::string sdp = std::string(message.at("sdp").as_string());
|
||||||
|
auto pc = peer->peerConnection();
|
||||||
|
auto description = rtc::Description(sdp, type);
|
||||||
|
pc->setRemoteDescription(description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boost::asio::strand<boost::asio::io_context::executor_type> strand;
|
||||||
|
rtc::Configuration configuration;
|
||||||
|
std::shared_ptr<rtc::WebSocket> websocket;
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<Client>> m_clients;
|
||||||
|
};
|
||||||
|
|
||||||
|
Streamer::~Streamer() {
|
||||||
|
if (m_d != nullptr) {
|
||||||
|
delete m_d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Streamer::start(const std::string &signalServerAddress, uint16_t signalServerPort) {
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
std::string localId = "server";
|
||||||
|
LOG(info) << "The local ID is: " << localId;
|
||||||
|
|
||||||
|
rtc::WebSocket::Configuration c;
|
||||||
|
c.disableTlsVerification = true;
|
||||||
|
m_d->websocket = std::make_shared<rtc::WebSocket>(c);
|
||||||
|
m_d->websocket->onOpen([]() { LOG(info) << "WebSocket connected, signaling ready"; });
|
||||||
|
m_d->websocket->onClosed([]() { LOG(info) << "WebSocket closed"; });
|
||||||
|
m_d->websocket->onError([](const std::string &error) { LOG(error) << "WebSocket failed: " << error; });
|
||||||
|
|
||||||
|
m_d->websocket->onMessage([this](std::variant<rtc::binary, std::string> data) {
|
||||||
|
if (!std::holds_alternative<std::string>(data)) return;
|
||||||
|
auto &text = std::get<std::string>(data);
|
||||||
|
LOG(info) << "ws received: " << std::endl << text;
|
||||||
|
auto value = boost::json::parse(text);
|
||||||
|
boost::asio::post(m_d->strand,
|
||||||
|
[this, value = std::move(value)]() { m_d->onWebSocketMesssage(value.as_object()); });
|
||||||
|
});
|
||||||
|
|
||||||
|
const std::string url =
|
||||||
|
"wss://" + signalServerAddress + ":" + std::to_string(signalServerPort) + "/api/v1/webrtc/signal/" + localId;
|
||||||
|
LOG(info) << "URL is " << url;
|
||||||
|
m_d->websocket->open(url);
|
||||||
|
LOG(info) << "Waiting for signaling to be connected...";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Streamer::push(const uint8_t *data, uint32_t size) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
boost::asio::post(m_d->strand, [this, frame = rtc::binary(reinterpret_cast<const rtc::byte *>(data),
|
||||||
|
reinterpret_cast<const rtc::byte *>(data) + size)]() {
|
||||||
|
for (auto &[id, client] : m_d->m_clients) {
|
||||||
|
if (client->state() != Client::State::Ready) continue;
|
||||||
|
auto sender = (*client->video)->sender;
|
||||||
|
auto track = (*client->video)->track;
|
||||||
|
|
||||||
|
sender->rtpConfig->timestamp = sender->rtpConfig->secondsToTimestamp(
|
||||||
|
static_cast<double>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count()) /
|
||||||
|
1000);
|
||||||
|
auto reportElapsedTimestamp = sender->rtpConfig->timestamp - sender->lastReportedTimestamp();
|
||||||
|
if (sender->rtpConfig->timestampToSeconds(reportElapsedTimestamp) > 1) {
|
||||||
|
sender->setNeedsToReport();
|
||||||
|
}
|
||||||
|
track->send(frame);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Streamer::Streamer(boost::asio::io_context &ioContext) : m_d{new WebRTCStreamerPrivate(ioContext)} {
|
||||||
|
rtc::InitLogger(rtc::LogLevel::Debug);
|
||||||
|
std::string stunServer = "stun:amass.fun:5349"; // ssl
|
||||||
|
m_d->configuration.iceServers.emplace_back(stunServer);
|
||||||
|
LOG(info) << "STUN server is " << stunServer;
|
||||||
|
|
||||||
|
rtc::IceServer turnServer("amass.fun", 5349, "amass", "88888888");
|
||||||
|
m_d->configuration.iceServers.emplace_back(turnServer);
|
||||||
|
|
||||||
|
m_d->configuration.disableAutoNegotiation = true;
|
||||||
|
}
|
25
Main/WebRTC/Streamer.h
Normal file
25
Main/WebRTC/Streamer.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef __WEBRTCSTREAMER_H__
|
||||||
|
#define __WEBRTCSTREAMER_H__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace asio {
|
||||||
|
class io_context;
|
||||||
|
}
|
||||||
|
} // namespace boost
|
||||||
|
class WebRTCStreamerPrivate;
|
||||||
|
|
||||||
|
class Streamer {
|
||||||
|
public:
|
||||||
|
Streamer(boost::asio::io_context &ioContext);
|
||||||
|
~Streamer();
|
||||||
|
void start(const std::string &signalServerAddress, uint16_t signalServerPort);
|
||||||
|
void push(const uint8_t *data, uint32_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
WebRTCStreamerPrivate *m_d = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __WEBRTCSTREAMER_H__
|
@ -1,9 +1,11 @@
|
|||||||
|
#include "Camera.h"
|
||||||
#include "Core/DateTime.h"
|
#include "Core/DateTime.h"
|
||||||
#include "Core/IoContext.h"
|
#include "Core/IoContext.h"
|
||||||
#include "Core/Logger.h"
|
#include "Core/Logger.h"
|
||||||
#include "Core/Singleton.h"
|
#include "Core/Singleton.h"
|
||||||
#include "RtspServer.h"
|
#include "RtspServer.h"
|
||||||
#include "VideoInput.h"
|
#include "VideoInput.h"
|
||||||
|
#include "WebRTC/Streamer.h"
|
||||||
#include "rw_mpp_api.h"
|
#include "rw_mpp_api.h"
|
||||||
#include <boost/asio/signal_set.hpp>
|
#include <boost/asio/signal_set.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -17,21 +19,16 @@ int main(int argc, char const *argv[]) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
auto camera = Singleton<Camera>::construct();
|
||||||
auto ioContext = Singleton<IoContext>::construct(std::thread::hardware_concurrency());
|
auto ioContext = Singleton<IoContext>::construct(std::thread::hardware_concurrency());
|
||||||
auto rtsp = std::make_shared<RtspServer>();
|
auto rtsp = std::make_shared<RtspServer>();
|
||||||
|
auto streamer = std::make_shared<Streamer>(*ioContext->ioContext());
|
||||||
std::shared_ptr<std::ofstream> ofs;
|
streamer->start("amass.fun", 443);
|
||||||
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);
|
auto video = std::make_shared<VideoInput>(2592, 1536);
|
||||||
video->setPacketHandler([&](const uint8_t *data, uint32_t size) {
|
video->setPacketHandler([&](const uint8_t *data, uint32_t size) {
|
||||||
// ofs->write(reinterpret_cast<const char *>(data), size);
|
|
||||||
// pusher->push(data, size);
|
|
||||||
rtsp->push(data, size);
|
rtsp->push(data, size);
|
||||||
|
streamer->push(data, size);
|
||||||
});
|
});
|
||||||
video->start();
|
video->start();
|
||||||
// video->startFileInput("/data/sdcard/HM1.264", 1280, 720);
|
// video->startFileInput("/data/sdcard/HM1.264", 1280, 720);
|
||||||
|
@ -70,8 +70,9 @@ function init() {
|
|||||||
echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/ZLMediaKit/lib/libmk_api.so /data/sdcard/PassengerStatistics/lib" | sftp danki
|
echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/ZLMediaKit/lib/libmk_api.so /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/opencv-4.11.0/lib/libopencv_world.so.4.11.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/opencv-4.11.0/lib/libopencv_world.so.4.11.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/usrsctp-0.9.5.0/lib/libusrsctp.so.2.0.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/usrsctp-0.9.5.0/lib/libusrsctp.so.2.0.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
|
echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/libdatachannel-0.22.5/lib/libdatachannel.so.0.22.5 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
# echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/LeakTracer/libleaktracer.so /data/sdcard/PassengerStatistics/lib" | sftp -i resources/ssh_host_rsa_key_ok root@${TARGET_IP}
|
# echo "put /opt/aarch64-v01c01-linux-gnu-gcc/lib/LeakTracer/libleaktracer.so /data/sdcard/PassengerStatistics/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_container.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
echo "put ${BOOST_LIBDIR}/libboost_log_setup.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
echo "put ${BOOST_LIBDIR}/libboost_log_setup.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
echo "put ${BOOST_LIBDIR}/libboost_log.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
echo "put ${BOOST_LIBDIR}/libboost_log.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
echo "put ${BOOST_LIBDIR}/libboost_atomic.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
echo "put ${BOOST_LIBDIR}/libboost_atomic.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
@ -80,7 +81,7 @@ function init() {
|
|||||||
echo "put ${BOOST_LIBDIR}/libboost_filesystem.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
echo "put ${BOOST_LIBDIR}/libboost_filesystem.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
echo "put ${BOOST_LIBDIR}/libboost_thread.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
echo "put ${BOOST_LIBDIR}/libboost_thread.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
# 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_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_json.so.1.87.0 /data/sdcard/PassengerStatistics/lib" | sftp danki
|
||||||
# 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_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 /' >> /etc/profile"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user