1. 删除图片存储到本地的方式;
2. 取流方式由Opencv修改为FFmpeg方式;
3. 解码后的数据直接转为RK_FORMAT_YCbCr_422_SP格式发送给算法;
4. 视频裸流数据存储在内存中,保存30s;
5. 报警图片从报警录像视频中获取;
This commit is contained in:
hehaoyang 2023-12-08 14:17:14 +08:00
parent a53d2f2ff7
commit ff66a2e0d6
13 changed files with 936 additions and 4946 deletions

4153
.gitignore vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,50 @@
## 版本说明
| 版本 | 说明 |
| --- | --- |
| 1.00 | 初始版本 |
| 1.01 | 1. 通过RKMPP实现硬解码; <br> 2. 视频以图片的方式按帧存储到本地; |
| 1.02 | 1. 删除图片存储到本地的方式; <br> 2. 取流方式由Opencv修改为FFmpeg方式; <br> 3. 解码后的数据直接转为RK_FORMAT_YCbCr_422_SP格式发送给算法; <br> 4. 视频裸流数据存储在内存中保存30s; <br> 5. 报警图片从报警录像视频中获取; |
## 编译方法
#### 下载代码
```
git clone http://teweishi.oicp.net:3001/hehaoyang/IVA.git
```
### 创建软链接
#### 修改配置
* 进入目录
```
cd IVA/app/
```
* 取消 app.pro 文件中以下注释
```
#DEFINES += USE_RABBITMQ
#DEFINES += USE_ALGORITHM
```
* 生成 Makefile 文件
```
qmake app.pro
```
#### 创建软链接
```
cd external/npu/
ln -s /usr/lib/librknnrt.so librknn_api.so
```
### 编译
#### 编译
```
cd ../../
make debug -j4
```

View File

@ -1,10 +1,10 @@
#include "HxDataBase.h"
#include "HxUtils.h"
QMutex HxDataBase::mutex;
QSqlDatabase HxDataBase::database;
QString HxDataBase::device_id;
int HxDataBase::recording_prepend_time;
QString HxDataBase::ftp_address, HxDataBase::ftp_username, HxDataBase::ftp_password;
QString HxDataBase::qamqp_address, HxDataBase::qamqp_username, HxDataBase::qamqp_password;
int HxDataBase::algorithm_type;
@ -14,6 +14,7 @@ QStringList HxDataBase::bsd_video_input_source;
QStringList HxDataBase::bsd_warn_regions;
EventWarnParamConfig HxDataBase::warm_param_config;
CameraCalibration HxDataBase::adas_camera_calibration;
QStringList HxDataBase::alarm_protect_timestamp;
QSqlDatabase HxDataBase::open(QString filepath, QString connectionName)
{
@ -257,6 +258,9 @@ void HxDataBase::initialization()
/* 设备编号 */
device_id = read_setting("device_id", QString("TVIS"));
/* 预录时长 Seconds */
recording_prepend_time = read_setting("recording_prepend_time", 5);
/* FTP信息 */
ftp_address = read_setting("ftp_address", QString("192.168.10.10:7616"));
ftp_username = read_setting("ftp_username", QString("nvruser"));
@ -295,6 +299,9 @@ void HxDataBase::initialization()
/* 读取 ADAS 相机内外参 */
read_adas_camera_calibration();
/* 报警保护时长 */
alarm_protect_timestamp = read_setting("alarm_protect_timestamp", QString("3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3")).split(";");
}
bool HxDataBase::save_setting()
@ -302,6 +309,7 @@ bool HxDataBase::save_setting()
database.transaction();
write_setting("device_id", device_id);
write_setting("recording_prepend_time", QString::number(recording_prepend_time));
write_setting("ftp_address", ftp_address);
write_setting("ftp_username", ftp_username);
write_setting("ftp_password", ftp_password);
@ -315,6 +323,7 @@ bool HxDataBase::save_setting()
write_setting("bsd_warn_regions", bsd_warn_regions.join("*"));
write_warm_param_config();
write_adas_camera_calibration();
write_setting("alarm_protect_timestamp", alarm_protect_timestamp.join(";"));
return database.commit();
}

View File

@ -13,8 +13,8 @@
#define BSD_MAX_CHANNEL 6
#define TEMPORARY_VIDEO_DIRECTORY "temp/video"
#define TEMPORARY_ALARM_DIRECTORY "temp/alarm"
#define TEMPORARY_LOG_DIRECTORY "log"
#define TEMPORARY_RECORD_DIRECTORY "record"
class HxDataBase
{
@ -106,6 +106,9 @@ public:
/* 设备编号 */
static QString device_id;
/* 预录时长 Seconds */
static int recording_prepend_time;
/* FTP地址 */
static QString ftp_address;
@ -137,6 +140,9 @@ public:
/* ADAS 相机内外参 */
static CameraCalibration adas_camera_calibration;
/* 报警保护时长 */
static QStringList alarm_protect_timestamp;
};
#endif // HXDATABASE_H

View File

@ -10,13 +10,13 @@
/* 视频设备 */
HxVideoDevice adas_video_device, bsd_video_device[6], dsm_video_device;
HxTaskDispatch* dispatcher = new HxTaskDispatch();
HxTaskDispatch *dispatcher = new HxTaskDispatch();
QMutex upload_file_mutex;
QQueue<QString> upload_file_queue;
#ifdef USE_RABBITMQ
HxRabbitMQUtils HxRabbitMQ;
HxRabbitMQ rabbit;
#endif
/* 倒车灯10熄灭 */
@ -36,25 +36,25 @@ void HxTaskDispatch::initialization(void)
/* 算法模块初始化 */
#if USE_ALGORITHM
/* adas检测配置 */
strcpy(dispatcher->event_detect_config.szAdasDetectConfigPathName, "./algmode/adas_detect.bin");
strcpy(dispatcher->event_detect_config.szAdasDetectConfigPathName, "./resources/algmode/adas_detect.bin");
/* adas跟踪配置 */
strcpy(dispatcher->event_detect_config.szAdasTrackConfigPathName, "./algmode/adas_track.bin");
strcpy(dispatcher->event_detect_config.szAdasTrackConfigPathName, "./resources/algmode/adas_track.bin");
/* bsd检测配置 */
strcpy(dispatcher->event_detect_config.szBsdDetectConfigPathName, "./algmode/bsd_detect.bin");
// strcpy(dispatcher->event_detect_config.szRightBsdFrontDetectConfigPathName, "./algmode/bsd_detect.bin");
strcpy(dispatcher->event_detect_config.szBsdDetectConfigPathName, "./resources/algmode/bsd_detect.bin");
// strcpy(dispatcher->event_detect_config.szRightBsdFrontDetectConfigPathName, "./resources/algmode/bsd_detect.bin");
/* dsm人脸检测配置 */
strcpy(dispatcher->event_detect_config.szDsmFaceDetectConfigPathName, "./algmode/dsm_face_detect.bin");
strcpy(dispatcher->event_detect_config.szDsmFaceDetectConfigPathName, "./resources/algmode/dsm_face_detect.bin");
/* dsm人脸特征点检测配置 */
strcpy(dispatcher->event_detect_config.szDsmFaceLandMarksDetectConfigPathName, "./algmode/dsm_face_landmarks_detect.bin");
strcpy(dispatcher->event_detect_config.szDsmFaceLandMarksDetectConfigPathName, "./resources/algmode/dsm_face_landmarks_detect.bin");
/* dsm人脸认证检测配置 */
strcpy(dispatcher->event_detect_config.szDsmFaceVerificationDetectConfigPathName, "./algmode/dsm_face_verification_detect.bin");
strcpy(dispatcher->event_detect_config.szDsmFaceVerificationDetectConfigPathName, "./resources/algmode/dsm_face_verification_detect.bin");
/* dsm人眼认证检测配置 */
strcpy(dispatcher->event_detect_config.szDsmEyeLandMarksDetectConfigPathName, "./algmode/dsm_eye_landmarks_detect.bin");
strcpy(dispatcher->event_detect_config.szDsmEyeLandMarksDetectConfigPathName, "./resources/algmode/dsm_eye_landmarks_detect.bin");
/* dsm人脸认证检测配置 */
strcpy(dispatcher->event_detect_config.szDsmSmokeConfPathName, "./algmode/dsm_smoke_detect.bin");
strcpy(dispatcher->event_detect_config.szDsmCallConfPathName, "./algmode/dsm_call_detect.bin");
strcpy(dispatcher->event_detect_config.szDsmFaceFeaturePathName, "./algmode/dsm_face_feature.bin");
strcpy(dispatcher->event_detect_config.szDsmHeadPoseConfPathName, "./algmode/data_68kp");
strcpy(dispatcher->event_detect_config.szDsmSmokeConfPathName, "./resources/algmode/dsm_smoke_detect.bin");
strcpy(dispatcher->event_detect_config.szDsmCallConfPathName, "./resources/algmode/dsm_call_detect.bin");
strcpy(dispatcher->event_detect_config.szDsmFaceFeaturePathName, "./resources/algmode/dsm_face_feature.bin");
strcpy(dispatcher->event_detect_config.szDsmHeadPoseConfPathName, "./resources/algmode/data_68kp");
/* 输出调试信息 */
MvSetPrintf(false);
@ -73,9 +73,8 @@ void HxTaskDispatch::initialization(void)
if (result != 0)
HxLog::append("initialization", "set event warn param config failed!!");
/* 相机标定 */
if(MvCameraCalibration(&HxDataBase::adas_camera_calibration) != 0)
if (MvCameraCalibration(&HxDataBase::adas_camera_calibration) != 0)
HxLog::append("initialization", "camera calibration failed!!");
#endif
@ -112,121 +111,97 @@ void HxTaskDispatch::initialization(void)
dispatcher->start();
#ifdef USE_RABBITMQ
HxRabbitMQ.set(HxDataBase::qamqp_address, HxDataBase::qamqp_username, HxDataBase::qamqp_password);
HxRabbitMQ.set_exchanger_name("vehicle.direct.exchange");
HxRabbitMQ.set_queue_name("bsd_video_transcode_tag");
HxRabbitMQ.set_routing_key("bsd_video_transcode_tag_1");
rabbit.set(HxDataBase::qamqp_address, HxDataBase::qamqp_username, HxDataBase::qamqp_password);
rabbit.set_exchanger_name("vehicle.direct.exchange");
rabbit.set_queue_name("bsd_video_transcode_tag");
rabbit.set_routing_key("bsd_video_transcode_tag_1");
#endif
}
void HxTaskDispatch::listern(uint16_t port)
{
dispatcher->debug_tool = new HxSocketUtils(port);
dispatcher->debug_tool = new HxSocket(port);
connect(dispatcher->debug_tool, &HxSocketUtils::data_receive_event, dispatcher, &HxTaskDispatch::data_receive_event);
connect(dispatcher, &HxTaskDispatch::data_write_event, dispatcher->debug_tool, &HxSocketUtils::write);
connect(dispatcher->debug_tool, &HxSocket::data_receive_event, dispatcher, &HxTaskDispatch::data_receive_event);
connect(dispatcher, &HxTaskDispatch::data_write_event, dispatcher->debug_tool, &HxSocket::write);
}
void HxTaskDispatch::connect_to_host(QString address, int port)
{
dispatcher->platform = new HxSocketUtils(address, port);
dispatcher->platform = new HxSocket(address, port);
connect(dispatcher->platform, &HxSocketUtils::data_receive_event, dispatcher, &HxTaskDispatch::data_receive_event);
connect(dispatcher, &HxTaskDispatch::data_write_event, dispatcher->platform, &HxSocketUtils::write);
connect(dispatcher->platform, &HxSocket::data_receive_event, dispatcher, &HxTaskDispatch::data_receive_event);
connect(dispatcher, &HxTaskDispatch::data_write_event, dispatcher->platform, &HxSocket::write);
}
void HxTaskDispatch::algorithm_alarm_event(QDateTime time, int channel, int level, int event_type, int detect_type, int left, int top, int right, int bottom, int distance, int speed, QString base64_string, QString filepath)
void HxTaskDispatch::alarm_upload_event(int algorithm_type, QDateTime timestamp, int channel, int event_type, int danger_level, ObjectPara *object_info, int object_number, CalibrationPoint *face_land_marks, int face_land_marks_number, LaneType left_line_type, LaneType right_line_type)
{
Q_UNUSED(speed);
HxVideoDevice *device = nullptr;
switch (algorithm_type)
{
case ALGORITHM_TYPE_ADAS:
device = &adas_video_device;
break;
case ALGORITHM_TYPE_BSD:
device = &bsd_video_device[channel];
break;
case ALGORITHM_TYPE_DSM:
device = &dsm_video_device;
break;
default:
return;
}
QJsonObject root({ {"type", 4} });
/* 判断报警是否在保护时间内 */
if (!device->determine_alarm_detection_timestamp(event_type))
return;
QJsonObject msgInfo({ {"time", time.toString("yyyy-MM-dd HH:mm:ss")},
/* 生成报警图片+视频 */
auto filename = QString("%1_%2_%3_%4_%5").arg(HxDataBase::device_id).arg(algorithm_type, 2, 10, QChar('0')).arg(channel, 2, 10, QChar('0')).arg(timestamp.toString("yyyyMMdd"), timestamp.toString("HHmmss"));
device->create_alarm_data(event_type, filename);
QJsonObject root({{"type", 4}});
QJsonObject msg_info_json({{"time", timestamp.toString("yyyy-MM-dd HH:mm:ss")},
{"channel", channel},
{"level", level},
{"level", danger_level},
{"event_type", event_type},
{"detect_type", detect_type},
{"left", left},
{"top", top},
{"right", right},
{"bottom", bottom},
{"distance", distance},
{"speed", dispatcher->car_info.fVelocity},
{"image", base64_string},
{"filepath", filepath} });
{"left_line_type", left_line_type},
{"right_line_type", right_line_type},
{"image_path", QString("/%1/%2/alarm/%3.jpg").arg(QDateTime::currentDateTime().toString("yyyyMMdd"), HxDataBase::device_id, filename)},
{"record_path", QString("/%1/%2/alarm/%3.mp4").arg(QDateTime::currentDateTime().toString("yyyyMMdd"), HxDataBase::device_id, filename)}});
root.insert("msgInfo", msgInfo);
QJsonArray object_info_json;
for (int i = 0; i < object_number; i++)
{
object_info_json.append(QJsonObject({{"detect_type", object_info[i].nDetectType},
{"left", object_info[i].nLeft},
{"top", object_info[i].nTop},
{"right", object_info[i].nRight},
{"bottom", object_info[i].nBottom},
{"distance", object_info[i].fDist},
{"speed", object_info[i].fVelo},
{"ttc", object_info[i].fTTC},
{"target_post_x", object_info[i].nTargetPosX},
{"target_post_y", object_info[i].nTargetPosY}}));
}
QJsonArray face_land_marks_json;
for (int i = 0; i < face_land_marks_number; i++)
face_land_marks_json.append(QJsonObject({{"x", face_land_marks[i].x}, {"y", face_land_marks[i].y}}));
msg_info_json.insert("object_info", object_info_json);
msg_info_json.insert("face_land_marks", face_land_marks_json);
root.insert("msgInfo", msg_info_json);
emit dispatcher->data_write_event(QJsonDocument(root).toJson(QJsonDocument::Compact));
HxLog::append("algorithm", QString("alarm type=0x%1, filepath=%2").arg(QString::number(event_type, 16), filepath));
// dispatcher->send_can_data(channel, pObjectTrackEventResult->nDangerLevel, pObjectTrackEventResult->objInfo[i].nDetectType);
HxLog::append("algorithm", QString("alarm type=0x%1, filepath=%2").arg(QString::number(event_type, 16), filename));
}
CarInfoInput* HxTaskDispatch::get_car_info(void) { return &dispatcher->car_info; }
QString HxTaskDispatch::get_video_frame_data(int type, int channel, int frame_id)
{
Q_UNUSED(channel);
switch (type)
{
case 0:
return adas_video_device.build_image(frame_id);
case 1:
return bsd_video_device[channel].build_image(frame_id);
case 2:
return dsm_video_device.build_image(frame_id);
}
return "";
}
bool HxTaskDispatch::get_alarm_detection_timestamp(int type, int channel)
{
switch (type)
{
case 0:
return adas_video_device.get_alarm_detection_timestamp();
case 1:
return bsd_video_device[channel].get_alarm_detection_timestamp();
case 2:
return dsm_video_device.get_alarm_detection_timestamp();
}
return false;
}
QString HxTaskDispatch::build_alarm_image(int type, int channel, int frame_id)
{
switch (type)
{
case 0:
return adas_video_device.build_image(frame_id);
case 1:
return bsd_video_device[channel].build_image(frame_id);
case 2:
return dsm_video_device.build_image(frame_id);
}
return "";
}
QString HxTaskDispatch::build_alarm_video(int type, int channel, int frame_id)
{
switch (type)
{
case 0:
return adas_video_device.build_video(frame_id);
case 1:
return bsd_video_device[channel].build_video(frame_id);
case 2:
return dsm_video_device.build_video(frame_id);
}
return "";
}
CarInfoInput *HxTaskDispatch::get_car_info(void) { return &dispatcher->car_info; }
void HxTaskDispatch::enqueue_upload_file(QString filename)
{
@ -241,7 +216,7 @@ void HxTaskDispatch::update_heartbeat()
{
heartbeat_timestamp = QDateTime::currentDateTime();
emit data_write_event(QJsonDocument(QJsonObject({ {"type", 0} })).toJson(QJsonDocument::Compact));
emit data_write_event(QJsonDocument(QJsonObject({{"type", 0}})).toJson(QJsonDocument::Compact));
}
}
@ -380,7 +355,7 @@ void HxTaskDispatch::parsing_vehiclue_status(void)
void HxTaskDispatch::recording_upload_task(void)
{
while(true)
while (true)
{
msleep(1000);
@ -390,11 +365,11 @@ void HxTaskDispatch::recording_upload_task(void)
auto filename = upload_file_queue.dequeue();
upload_file_mutex.unlock();
QString fullpath = QString("%1/%2").arg(TEMPORARY_ALARM_DIRECTORY).arg(filename);
QString fullpath = QString("%1/%2").arg(TEMPORARY_RECORD_DIRECTORY, filename);
if(!QFile::exists(fullpath))
if (!QFile::exists(fullpath))
{
HxLog::append("recording upload task", QString("file=%1 not exists, upload failed").arg(filename));
HxLog::append("recording upload task", QString("file=%1 not exists, upload failed").arg(fullpath));
continue;
}
@ -405,19 +380,18 @@ void HxTaskDispatch::recording_upload_task(void)
{
msleep(100);
/* FTP 上传 */
HxProcess::execute(QString("curl -u %1:%2 ftp://%3/%4/ --ftp-create-dirs -T %5").arg(HxDataBase::ftp_username, HxDataBase::ftp_password, HxDataBase::ftp_address, path, fullpath));
/* 上传 */
HxProcess::start(QString("curl -u %1:%2 ftp://%3/%4/ --ftp-create-dirs -T %5").arg(HxDataBase::ftp_username, HxDataBase::ftp_password, HxDataBase::ftp_address, path, fullpath));
QString command = QString("curl -u %1:%2 --ftp-ssl --head ftp://%3/%4/%5").arg(HxDataBase::ftp_username, HxDataBase::ftp_password, HxDataBase::ftp_address, path, filename);
/* 判断FTP文件是否存在 */
auto res = HxProcess::start(command);
/* 判断文件是否存在 */
auto res = HxProcess::start(QString("curl -u %1:%2 --ftp-ssl --head ftp://%3/%4/%5").arg(HxDataBase::ftp_username, HxDataBase::ftp_password, HxDataBase::ftp_address, path, filename));
QRegExp rx("Content-Length:\\s\\d{1,9}");
if (rx.indexIn(res, 0) == -1)
continue;
/* 比较大小 */
QFileInfo info(fullpath);
auto size1 = info.size();
@ -427,10 +401,10 @@ void HxTaskDispatch::recording_upload_task(void)
{
HxLog::append("recording upload task", QString("%1 upload finish").arg(filename));
if(info.suffix() == "mp4")
if (info.suffix() == "mp4")
{
#ifdef USE_RABBITMQ
emit HxRabbitMQ.publish(QString("{\"ftproot\": \"%1\", \"complate\": true}").arg(("/"+path+"/"+filename)));
emit rabbit.publish(QString("{\"ftproot\": \"%1\", \"complate\": true}").arg(("/" + path + "/" + filename)));
#endif
}
@ -438,7 +412,7 @@ void HxTaskDispatch::recording_upload_task(void)
}
}
// QFile::remove(fullpath);
QFile::remove(fullpath);
HxLog::append("recording upload task", QString("%1 delete").arg(filename));
}
@ -452,6 +426,7 @@ void HxTaskDispatch::run()
while (true)
{
/* 事件循环用于响应信号 */
QCoreApplication::processEvents();
/* 发送心跳数据 */
@ -460,6 +435,7 @@ void HxTaskDispatch::run()
/* 分析车辆行驶状态 */
parsing_vehiclue_status();
/* 延时1s */
QThread::msleep(1000);
}
}
@ -490,7 +466,8 @@ void HxTaskDispatch::get_warn_param_config(int type)
start_event_warn_kind.append(HxDataBase::warm_param_config.bStartEventWarnKind[i]);
abnormal_warn_frame_count.append(HxDataBase::warm_param_config.nAbnormalWarnFrameCount[i] / 25);
normal_frame_count.append(HxDataBase::warm_param_config.nNormalFrameCount[i] / 25);
abnormal_warn_interval_frame_count.append(HxDataBase::warm_param_config.nAbnormalWarnIntervalFrameCount[i] / 25);
// abnormal_warn_interval_frame_count.append(HxDataBase::warm_param_config.nAbnormalWarnIntervalFrameCount[i] / 25);
abnormal_warn_interval_frame_count.append(HxDataBase::alarm_protect_timestamp.at(i).toInt());
abnormal_warn_score_threshold.append((int)(HxDataBase::warm_param_config.fAbnormalWarnScoreThreshold[i] * ((i >= 17 && i <= 20) ? 1 : 100)));
normal_warn_score_threshold.append((int)(HxDataBase::warm_param_config.fNormalWarnScoreThreshold[i] * ((i >= 17 && i <= 20) ? 1 : 100)));
@ -502,7 +479,7 @@ void HxTaskDispatch::get_warn_param_config(int type)
<< "fNormalWarnScoreThreshold=" << HxDataBase::warm_param_config.fNormalWarnScoreThreshold[i];
}
debug_tool_response_event(type, { {"start_event_warn_kind", start_event_warn_kind},
debug_tool_response_event(type, {{"start_event_warn_kind", start_event_warn_kind},
{"abnormal_warn_frame_count", abnormal_warn_frame_count},
{"normal_frame_count", normal_frame_count},
{"abnormal_warn_interval_frame_count", abnormal_warn_interval_frame_count},
@ -519,7 +496,7 @@ void HxTaskDispatch::get_warn_param_config(int type)
{"bsd_second_vel", HxDataBase::warm_param_config.fBsdSecondVel},
{"bsd_third_vel", HxDataBase::warm_param_config.fBsdThirdVel},
{"ldw_distance", HxDataBase::warm_param_config.nLdwDistance},
{"dsm_vel", HxDataBase::warm_param_config.fDsmVel} });
{"dsm_vel", HxDataBase::warm_param_config.fDsmVel}});
}
void HxTaskDispatch::set_warn_param_config(int type, QJsonObject object)
@ -539,6 +516,9 @@ void HxTaskDispatch::set_warn_param_config(int type, QJsonObject object)
HxDataBase::warm_param_config.nAbnormalWarnIntervalFrameCount[i] = abnormal_warn_interval_frame_count.at(i).toInt() * 25;
HxDataBase::warm_param_config.fAbnormalWarnScoreThreshold[i] = abnormal_warn_score_threshold.at(i).toDouble() / ((i >= 17 && i <= 20) ? 1 : 100);
HxDataBase::warm_param_config.fNormalWarnScoreThreshold[i] = normal_warn_score_threshold.at(i).toDouble() / ((i >= 17 && i <= 20) ? 1 : 100);
/* 设置报警保护时长 */
HxDataBase::alarm_protect_timestamp[i] = QString::number(abnormal_warn_interval_frame_count.at(i).toInt());
}
HxDataBase::warm_param_config.nHmwTime = object.value("hmw_time").toInt();
@ -555,24 +535,24 @@ void HxTaskDispatch::set_warn_param_config(int type, QJsonObject object)
HxDataBase::warm_param_config.fDsmVel = object.value("dsm_vel").toDouble();
#if USE_ALGORITHM
if(MvSetEventWarnParamConfig(&HxDataBase::warm_param_config) != 0)
if (MvSetEventWarnParamConfig(&HxDataBase::warm_param_config) != 0)
{
debug_tool_response_event(type, { {"status", false} });
debug_tool_response_event(type, {{"status", false}});
return;
}
#endif
debug_tool_response_event(type, { {"status", HxDataBase::save_setting()} });
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
}
void HxTaskDispatch::get_adas_camera_calibration(int type)
{
#if USE_ALGORITHM
if(MvGetCameraCalibrationInfo(&HxDataBase::adas_camera_calibration) != 0)
if (MvGetCameraCalibrationInfo(&HxDataBase::adas_camera_calibration) != 0)
return;
#endif
debug_tool_response_event(type, { {"car_len", HxDataBase::adas_camera_calibration.fCarLen},
debug_tool_response_event(type, {{"car_len", HxDataBase::adas_camera_calibration.fCarLen},
{"car_width", HxDataBase::adas_camera_calibration.fCarWidth},
{"ref_center", HxDataBase::adas_camera_calibration.fRefCenter},
{"ref_top", HxDataBase::adas_camera_calibration.fRefTop},
@ -581,7 +561,7 @@ void HxTaskDispatch::get_adas_camera_calibration(int type)
{"camera_focus", HxDataBase::adas_camera_calibration.fCameraFocus},
{"camera_dx", HxDataBase::adas_camera_calibration.fCameraDx},
{"pitch", HxDataBase::adas_camera_calibration.fPitch},
{"yaw", HxDataBase::adas_camera_calibration.fYaw} });
{"yaw", HxDataBase::adas_camera_calibration.fYaw}});
}
void HxTaskDispatch::set_adas_camera_calibration(int type, QJsonObject object)
{
@ -597,14 +577,14 @@ void HxTaskDispatch::set_adas_camera_calibration(int type, QJsonObject object)
HxDataBase::adas_camera_calibration.fYaw = object.value("yaw").toDouble();
#if USE_ALGORITHM
if(MvCameraCalibration(&HxDataBase::adas_camera_calibration) != 0)
if (MvCameraCalibration(&HxDataBase::adas_camera_calibration) != 0)
{
debug_tool_response_event(type, { {"status", false} });
debug_tool_response_event(type, {{"status", false}});
return;
}
#endif
debug_tool_response_event(type, { {"status", HxDataBase::save_setting()} });
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
}
void HxTaskDispatch::data_receive_event(QByteArray data)
@ -635,93 +615,80 @@ void HxTaskDispatch::data_receive_event(QByteArray data)
case 5:
HxProcess::start(QString("date -s %1").arg(msginfo.value("date").toString()));
HxProcess::start(QString("date -s %1").arg(msginfo.value("time").toString()));
debug_tool_response_event(type, { {"status", true} });
debug_tool_response_event(type, {{"status", true}});
HxLog::append("timing", QString(QJsonDocument(msginfo).toJson(QJsonDocument::Compact)));
break;
/* 重启 */
case 200:
debug_tool_response_event(type, { {"status", true} });
debug_tool_response_event(type, {{"status", true}});
HxProcess::start("systemctl restart app.service");
break;
/* 获取算法类型 */
case 240:
debug_tool_response_event(type, { {"mode", HxDataBase::algorithm_type} });
debug_tool_response_event(type, {{"mode", HxDataBase::algorithm_type}});
break;
/* 设置算法类型 */
case 241:
HxDataBase::algorithm_type = msginfo.value("mode").toInt();
debug_tool_response_event(type, { {"status", HxDataBase::save_setting()} });
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
break;
/* 获取ADAS视频输入源 */
case 242:
debug_tool_response_event(type, { {"source", HxDataBase::adas_video_input_source} });
debug_tool_response_event(type, {{"source", HxDataBase::adas_video_input_source}});
break;
/* 设置ADAS视频输入源 */
case 243:
HxDataBase::adas_video_input_source = msginfo.value("source").toString();
debug_tool_response_event(type, { {"status", HxDataBase::save_setting()} });
break;
/* 抓拍 */
case 244:
debug_tool_response_event(type, { {"data", adas_video_device.snap()} });
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
break;
/* 获取BSD视频输入源 */
case 245:
debug_tool_response_event(type, { {"source", HxDataBase::bsd_video_input_source[msginfo.value("channel").toInt()]} });
debug_tool_response_event(type, {{"source", HxDataBase::bsd_video_input_source[msginfo.value("channel").toInt()]}});
break;
/* 设置BSD视频输入源 */
case 246:
HxDataBase::bsd_video_input_source[msginfo.value("channel").toInt()] = msginfo.value("source").toString();
debug_tool_response_event(type, { {"status", HxDataBase::save_setting()} });
break;
/* 抓拍 */
case 247:
debug_tool_response_event(type, { {"data", bsd_video_device[msginfo.value("channel").toInt()].snap()} });
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
break;
/* 获取Dsm视频输入源 */
case 248:
debug_tool_response_event(type, { {"source", HxDataBase::dsm_video_input_source} });
debug_tool_response_event(type, {{"source", HxDataBase::dsm_video_input_source}});
break;
/* 设置Dsm视频输入源 */
case 249:
HxDataBase::dsm_video_input_source = msginfo.value("source").toString();
debug_tool_response_event(type, { {"status", HxDataBase::save_setting()} });
break;
/* 抓拍 */
case 250:
debug_tool_response_event(type, { {"data", dsm_video_device.snap()} });
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
break;
/* 获取BSD报警区域 */
case 251:
debug_tool_response_event(type, { {"data", HxDataBase::bsd_warn_regions[msginfo.value("channel").toInt()]} });
debug_tool_response_event(type, {{"data", HxDataBase::bsd_warn_regions[msginfo.value("channel").toInt()]}});
break;
/* 设置BSD报警区域 */
case 252:
HxDataBase::bsd_warn_regions[msginfo.value("channel").toInt()] = msginfo.value("data").toString();
debug_tool_response_event(type, { {"status", HxDataBase::save_setting()} });
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
break;
/* 获取设备编号及FTP信息 */
case 253:
debug_tool_response_event(type, { {"device_id", HxDataBase::device_id},
debug_tool_response_event(type, {
{"device_id", HxDataBase::device_id},
{"ftp_address", HxDataBase::ftp_address},
{"ftp_username", HxDataBase::ftp_username},
{"ftp_password", HxDataBase::ftp_password}, });
{"ftp_password", HxDataBase::ftp_password},
});
break;
/* 设置设备编号及FTP信息 */
@ -730,10 +697,9 @@ void HxTaskDispatch::data_receive_event(QByteArray data)
HxDataBase::ftp_address = msginfo.value("ftp_address").toString();
HxDataBase::ftp_username = msginfo.value("ftp_username").toString();
HxDataBase::ftp_password = msginfo.value("ftp_password").toString();
debug_tool_response_event(type, { {"status", HxDataBase::save_setting()} });
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
break;
case 255:
get_warn_param_config(type);
break;
@ -752,9 +718,9 @@ void HxTaskDispatch::data_receive_event(QByteArray data)
/* 获取 RabbitMQ 信息 */
case 259:
debug_tool_response_event(type, { {"qamqp_address", HxDataBase::qamqp_address},
debug_tool_response_event(type, {{"qamqp_address", HxDataBase::qamqp_address},
{"qamqp_username", HxDataBase::qamqp_username},
{"qamqp_password", HxDataBase::qamqp_password} });
{"qamqp_password", HxDataBase::qamqp_password}});
break;
/* 设置 RabbitMQ 信息 */
@ -762,11 +728,20 @@ void HxTaskDispatch::data_receive_event(QByteArray data)
HxDataBase::qamqp_address = msginfo.value("qamqp_address").toString();
HxDataBase::qamqp_username = msginfo.value("qamqp_username").toString();
HxDataBase::qamqp_password = msginfo.value("qamqp_password").toString();
debug_tool_response_event(type, { {"status", HxDataBase::save_setting()} });
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
break;
case 261:
debug_tool_response_event(type, {{"recording_prepend_time", HxDataBase::recording_prepend_time}});
break;
case 262:
HxDataBase::recording_prepend_time = msginfo.value("recording_prepend_time").toInt();
debug_tool_response_event(type, {{"status", HxDataBase::save_setting()}});
break;
case 0xFFFF:
adas_video_device.test();
dsm_video_device.test();
break;
}
}

View File

@ -6,6 +6,9 @@
#include "HxUtils.h"
#include "MvObjectEventDetect.h"
#include <opencv2/opencv.hpp>
#include <opencv2/freetype.hpp>
#define ALGORITHM_TYPE_ADAS 0
#define ALGORITHM_TYPE_BSD 1
#define ALGORITHM_TYPE_DSM 2
@ -31,37 +34,27 @@ public:
*/
static void connect_to_host(QString address, int port);
static void algorithm_alarm_event(QDateTime time, int channel, int level, int event_type, int detect_type, int left, int top, int right, int bottom, int distance, int speed, QString base64_string, QString filepath);
static CarInfoInput* get_car_info(void);
static QString get_video_frame_data(int type, int channel, int frame_id);
/**
* @brief alarm_upload_event
* @param type
* @param timestamp
* @param channel
* @param event_type
* @param danger_level
* @param object_info
* @param object_number
* @param face_land_marks
* @param face_land_marks_number
* @param left_line_type
* @param right_line_type
*/
static void alarm_upload_event(int type, QDateTime timestamp, int channel, int event_type, int danger_level, ObjectPara *object_info, int object_number, CalibrationPoint *face_land_marks, int face_land_marks_number, LaneType left_line_type, LaneType right_line_type);
/**
* @brief
* @param type
* @param channel
* @brief get_car_info
* @return
*/
static bool get_alarm_detection_timestamp(int type, int channel);
/**
* @brief
* @param type
* @param channel
* @param frame_id
* @return
*/
static QString build_alarm_image(int type, int channel, int frame_id);
/**
* @brief
* @param type
* @param channel
* @param frame_id
* @return
*/
static QString build_alarm_video(int type, int channel, int frame_id);
static CarInfoInput* get_car_info(void);
/**
* @brief enqueue_upload_file
@ -101,10 +94,10 @@ private:
QDateTime vehicle_status_update_time;
/* 边缘云 Socket (客户端) */
HxSocketUtils* platform;
HxSocket* platform;
/* DebugTool Socket (服务端) */
HxSocketUtils* debug_tool;
HxSocket* debug_tool;
/* 车辆状态信息 */
CarInfoInput car_info;

View File

@ -6,6 +6,7 @@
#include <QTcpSocket>
#include <QTcpServer>
#include <QDateTime>
#include <QStorageInfo>
#include <QCoreApplication>
#include <QProcess>
#include <QThread>
@ -18,42 +19,30 @@
#include "qamqpqueue.h"
#endif
class HxThread
{
public:
static void sleep(int millisecond)
{
auto time = QTime::currentTime().addMSecs(millisecond);
while( QTime::currentTime() < time )
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
};
/**
* @brief SocketUtils socket
* @brief Socket socket
*/
class HxSocketUtils : public QObject
class HxSocket : public QObject
{
Q_OBJECT
public:
HxSocketUtils(quint16 port)
HxSocket(quint16 port)
{
connect(&server, &QTcpServer::newConnection, this, &HxSocketUtils::new_connection);
connect(&server, &QTcpServer::newConnection, this, &HxSocket::new_connection);
server.listen(QHostAddress::Any, port);
}
HxSocketUtils(QString address, int port)
HxSocket(QString address, int port)
{
is_reconnect = true;
socket = new QTcpSocket();
connect(socket, &QTcpSocket::readyRead, this, &HxSocketUtils::ready_read);
connect(socket, &QTcpSocket::readyRead, this, &HxSocket::ready_read);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::QueuedConnection);
connect(this, &HxSocketUtils::reconnection_event, this, &HxSocketUtils::reconnection);
connect(this, &HxSocket::reconnection_event, this, &HxSocket::reconnection);
/* 域名解析 */
QHostInfo info = QHostInfo::fromName(address);
@ -76,7 +65,7 @@ public slots:
socket = server.nextPendingConnection();
connect(socket, &QTcpSocket::readyRead, this, &HxSocketUtils::ready_read);
connect(socket, &QTcpSocket::readyRead, this, &HxSocket::ready_read);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::QueuedConnection);
}
@ -120,15 +109,9 @@ public slots:
/* 等待连接 */
if (!socket->waitForConnected(500))
{
/* 使用 QThread::msleep 延时,会使 Socket 出现接收不到事件信息 (槽无法响应) */
// auto time = QTime::currentTime().addMSecs(10000);
// while (QTime::currentTime() < time)
// {
// QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
// QThread::msleep(100);
// }
HxThread::sleep(10000);
auto time = QTime::currentTime().addMSecs(10000);
while (QTime::currentTime() < time)
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
emit reconnection_event();
}
@ -145,15 +128,16 @@ private:
class HxDir
{
public:
static bool mkdir(QString name)
static bool mkpath(QString name)
{
return QDir().mkpath(name);
}
static void mkdir(QStringList names)
static void mkpath(QStringList names)
{
foreach (QString name, names) {
HxDir::mkdir(name);
foreach (QString name, names)
{
HxDir::mkpath(name);
}
}
@ -161,6 +145,17 @@ public:
{
return QDir(name).removeRecursively();
}
static double free_size(QString rootPath)
{
foreach (const QStorageInfo &storage, QStorageInfo::mountedVolumes())
{
if (rootPath == storage.rootPath())
return static_cast<double>(storage.bytesAvailable()) / 1024 / 1024 / 1024;
}
return 0;
}
};
class HxLog
@ -174,9 +169,7 @@ public:
auto current_time = QDateTime::currentDateTime();
HxDir::mkdir(QString("log/%1").arg(current_time.toString("yyyyMMdd")));
QFile file(QString("log/%1/%1.txt").arg(current_time.toString("yyyyMMdd")));
QFile file(QString("log/%1.log").arg(current_time.toString("yyyyMMdd")));
if (file.open(QIODevice::WriteOnly | QIODevice::Append))
{
@ -196,20 +189,6 @@ public:
class HxProcess
{
public:
static int execute(QString command)
{
qDebug() << command;
auto array = command.split(" ");
QString program = array.at(0);
QStringList arguments;
for (int i = 1; i < array.count(); i++)
arguments << array.at(i);
return QProcess::execute(program, arguments);
}
static QString start(QString command)
{
auto array = command.split(" ");
@ -228,7 +207,7 @@ public:
};
#ifdef USE_RABBITMQ
class HxRabbitMQUtils : public QObject
class HxRabbitMQ : public QObject
{
Q_OBJECT
public:
@ -246,7 +225,7 @@ public:
connect(&client, SIGNAL(connected()), this, SLOT(connected()));
connect(&client, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(this, &HxRabbitMQUtils::publish, this, &HxRabbitMQUtils::send_message);
connect(this, &HxRabbitMQ::publish, this, &HxRabbitMQ::send_message);
client.connectToHost();
}

View File

@ -36,9 +36,41 @@ class HxVideoDecoder
public:
HxVideoDecoder(void) {}
#ifndef USE_ALGORITHM
bool initialization(AVFormatContext* ifmt_ctx)
static int duration(QString fullpath)
{
/* 始化网络设备 */
avformat_network_init();
/* 初始化 */
AVFormatContext *ifmt_ctx = avformat_alloc_context();
/* 打开输入文件 */
if (avformat_open_input(&ifmt_ctx, fullpath.toUtf8().data(), nullptr, nullptr) < 0)
return 0;
/* 获取流信息 */
if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0)
{
avformat_close_input(&ifmt_ctx);
return -1;
}
/* 这里获取的是微秒,需要转成秒 */
int64_t tduration = ifmt_ctx->duration;
/* 打开文件流后,需要关闭,否则会一直占用视频文件,无法进行视频文件的后续操作 */
avformat_close_input(&ifmt_ctx);
/* 销毁 */
avformat_free_context(ifmt_ctx);
return tduration / 1000000;
}
#ifndef USE_ALGORITHM
void initialization(AVFormatContext *ifmt_ctx)
{
status = false;
auto video_stream_index = -1;
for (uint i = 0; i < ifmt_ctx->nb_streams; i++)
{
@ -47,14 +79,14 @@ public:
}
if (video_stream_index == -1)
return false;
return;
/* 配置解码器 */
video_dec_ctx = avcodec_alloc_context3(nullptr);
if (video_dec_ctx == nullptr)
{
printf("Could not allocate AVCodecContext");
return false;
return;
}
/* 拷贝 */
@ -63,14 +95,14 @@ public:
/* 查找解码器 */
auto codec = avcodec_find_decoder(video_dec_ctx->codec_id);
if (!codec)
return false;
return;
/* 打开解码器 */
if (avcodec_open2(video_dec_ctx, codec, nullptr) < 0)
{
codec = nullptr;
avcodec_free_context(&video_dec_ctx);
return false;
return;
}
video_dec_frame = av_frame_alloc();
@ -80,7 +112,7 @@ public:
/* 通过指定像素格式、图像宽、图像高来计算所需的内存大小 */
auto numBytes = av_image_get_buffer_size(AV_PIX_FMT_BGR24, video_dec_ctx->width, video_dec_ctx->height, 1);
/* 创建 video_out_buffer */
video_out_buffer = static_cast<uint8_t*>(av_malloc(static_cast<ulong>(numBytes) * sizeof(uint8_t)));
video_out_buffer = static_cast<uint8_t *>(av_malloc(static_cast<ulong>(numBytes) * sizeof(uint8_t)));
/* 填充数据 */
av_image_fill_arrays(video_picture_frame->data, video_picture_frame->linesize, video_out_buffer, AV_PIX_FMT_BGR24, video_dec_ctx->width, video_dec_ctx->height, 1);
@ -102,11 +134,13 @@ public:
nullptr /* 特定缩放算法需要的参数(?)默认为NULL */
);
return true;
status = true;
}
#else
bool initialization(void)
void initialization(void)
{
status = false;
MPP_RET ret = MPP_OK;
RK_U32 need_split = 1;
@ -119,29 +153,29 @@ public:
HxLog::append("mpp", QString("mpp_create failed"));
return false;
return;
}
/* 配置解器 按帧输入码流 */
ret = mpp_mpi->control(mpp_ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, (MppParam*)&need_split);
ret = mpp_mpi->control(mpp_ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, (MppParam *)&need_split);
if (MPP_OK != ret)
{
release();
HxLog::append("mpp", QString("mpi->control failed"));
return false;
return;
}
/* 配置解器 队列输入 */
ret = mpp_mpi->control(mpp_ctx, MPP_SET_INPUT_BLOCK, (MppParam*)&need_split);
ret = mpp_mpi->control(mpp_ctx, MPP_SET_INPUT_BLOCK, (MppParam *)&need_split);
if (MPP_OK != ret)
{
release();
HxLog::append("mpp", QString("mpi->control failed"));
return false;
return;
}
/* 初始化 MPP 固定为H264 */
@ -152,10 +186,10 @@ public:
HxLog::append("mpp", QString("mpp_init failed"));
return false;
return;
}
return true;
status = true;
}
#endif
@ -191,7 +225,7 @@ public:
#endif
}
void decode(AVPacket* packet, cv::Mat* mat)
void decode(AVPacket *packet, cv::Mat *mat)
{
#ifndef USE_ALGORITHM
/* 发送数据到ffmepg放到解码队列中 */
@ -201,7 +235,7 @@ public:
if (avcodec_receive_frame(video_dec_ctx, video_dec_frame) == 0)
{
/* 开始转换 */
sws_scale(video_sws_context, static_cast<const uint8_t* const*>(video_dec_frame->data), video_dec_frame->linesize, 0, video_dec_ctx->height, video_picture_frame->data, video_picture_frame->linesize);
sws_scale(video_sws_context, static_cast<const uint8_t *const *>(video_dec_frame->data), video_dec_frame->linesize, 0, video_dec_ctx->height, video_picture_frame->data, video_picture_frame->linesize);
(*mat) = cv::Mat(cv::Size(video_dec_ctx->width, video_dec_ctx->height), CV_8UC3);
(*mat).data = video_out_buffer;
@ -305,29 +339,8 @@ public:
{
RK_U32 width = mpp_frame_get_width(mpp_frame);
RK_U32 height = mpp_frame_get_height(mpp_frame);
MppBuffer mpp_buffer = mpp_frame_get_buffer(mpp_frame);
convert_to_mat(mpp_buffer, width, height, mat);
// RK_U32 h_stride = mpp_frame_get_hor_stride(mpp_frame);
// RK_U32 v_stride = mpp_frame_get_ver_stride(mpp_frame);
// cv::Mat yuv_img(height * 3 / 2, width, CV_8UC1);
// RK_U8 *base = (RK_U8 *)mpp_buffer_get_ptr(mpp_buffer);
// RK_U8 *base_c = base + h_stride * v_stride;
// int idx = 0;
// for (int i = 0; i < height; i++, base += h_stride, idx += width)
// {
// memcpy(yuv_img.data + idx, base, width);
// }
// for (int i = 0; i < height / 2; i++, base_c += h_stride, idx += width)
// {
// memcpy(yuv_img.data + idx, base_c, width);
// }
// (*mat) = cv::Mat(cv::Size(width, height), CV_8UC3);
// cv::cvtColor(yuv_img, (*mat), CV_YUV420sp2RGB);
}
}
@ -405,36 +418,10 @@ private:
return MPP_BUFFER_MODE_BUTT;
}
return ((MppBufferGroupImpl*)group)->usage;
return ((MppBufferGroupImpl *)group)->usage;
}
int write_image_to_file(void* buf, const char* filename, int sw, int sh, int fmt, int index) {
int size;
// char filePath[100];
// const char* outputFilePath = "%s/out%dw%d-h%d-%s.bin";
// snprintf(filePath, 100, outputFilePath,
// path, index, sw, sh, translate_format_str(fmt));
FILE* file = fopen(filename, "wb+");
if (!file) {
fprintf(stderr, "Could not open %s\n", filename);
return false;
}
else {
fprintf(stderr, "open %s and write ok\n", filename);
}
size = sw * sh * get_bpp_from_format(fmt);
fwrite(buf, size, 1, file);
fclose(file);
return 0;
}
bool convert_to_mat(MppBuffer mpp_buffer, RK_U32 width, RK_U32 height, cv::Mat* mat)
bool convert_to_mat(MppBuffer mpp_buffer, RK_U32 width, RK_U32 height, cv::Mat *mat)
{
int ret = 0;
im_rect src_rect, dst_rect;
@ -448,16 +435,18 @@ private:
memset(&dst_img, 0, sizeof(dst_img));
src_img = wrapbuffer_virtualaddr(mpp_buffer_get_ptr(mpp_buffer), width, height, RK_FORMAT_YCbCr_420_SP);
dst_img = wrapbuffer_virtualaddr(mat->data, width, height, RK_FORMAT_BGR_888);
dst_img = wrapbuffer_virtualaddr(mat->data, width, height, RK_FORMAT_YCbCr_422_SP);
if (src_img.width == 0 || dst_img.width == 0) {
if (src_img.width == 0 || dst_img.width == 0)
{
printf("%s, %s\n", __FUNCTION__, imStrError());
return -1;
}
src_img.format = RK_FORMAT_YCbCr_420_SP;
dst_img.format = RK_FORMAT_BGR_888;
dst_img.format = RK_FORMAT_YCbCr_422_SP;
ret = imcheck(src_img, dst_img, src_rect, dst_rect);
if (IM_STATUS_NOERROR != ret) {
if (IM_STATUS_NOERROR != ret)
{
printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));
return -1;
}
@ -468,21 +457,24 @@ private:
}
#endif
public:
bool status = false;
private:
#if USE_ALGORITHM
MppCtx mpp_ctx;
MppApi* mpp_mpi;
MppApi *mpp_mpi;
size_t max_usage;
RK_U32 frame_count = 0, frame_num, eos;
/* 缓冲区管理器 */
MppBufferGroup mpp_frame_group;
#else
uint8_t* video_out_buffer = nullptr;
struct SwsContext* video_sws_context = nullptr;
uint8_t *video_out_buffer = nullptr;
struct SwsContext *video_sws_context = nullptr;
AVCodecContext* video_dec_ctx = nullptr;
AVFrame* video_dec_frame = nullptr, * video_picture_frame = nullptr;
AVCodecContext *video_dec_ctx = nullptr;
AVFrame *video_dec_frame = nullptr, *video_picture_frame = nullptr;
#endif
};

View File

@ -1,49 +1,23 @@
#include "HxVideoDevice.h"
#include "HxDataBase.h"
#include "HxUtils.h"
/* bsd算法结果处理函数 */
void algorithm_alarm_callback(int nDataChannel, ObjectTrackEventResult* pObjectTrackEventResult, void* pPrivData)
/* 算法报警处理函数 */
void algorithm_detection_callback(int nDataChannel, ObjectTrackEventResult *pObjectTrackEventResult, void *pPrivData)
{
Q_UNUSED(nDataChannel);
Q_UNUSED(pPrivData);
int algorithm_type = 0, channel = 0;
QDateTime current_time = QDateTime::currentDateTime();
if (pObjectTrackEventResult->nEventType == 0)
return;
if (nDataChannel == 0) /* ADAS */
if (nDataChannel == 0)
{
if (!HxTaskDispatch::get_alarm_detection_timestamp(ALGORITHM_TYPE_ADAS, 0))
return;
qDebug() << current_time.toString("[yyyy-MM-dd HH:mm:ss] ") << " Adas FrameId=" << pObjectTrackEventResult->nFrameId << " nEventType=" << pObjectTrackEventResult->nEventType;
/* 生成报警图片 */
auto image_path = HxTaskDispatch::build_alarm_image(ALGORITHM_TYPE_ADAS, 0, pObjectTrackEventResult->nFrameId);
/* 生成报警视频 */
auto record_path = HxTaskDispatch::build_alarm_video(ALGORITHM_TYPE_ADAS, 0, pObjectTrackEventResult->nFrameId);
/* 上传 */
HxTaskDispatch::algorithm_alarm_event(current_time, 0, 0, pObjectTrackEventResult->nEventType, 0, 0, 0, 0, 0, 0, 0, image_path, record_path);
algorithm_type = ALGORITHM_TYPE_ADAS;
}
else if (nDataChannel == 2) /* DSM */
else if (nDataChannel == 2)
{
if (!HxTaskDispatch::get_alarm_detection_timestamp(ALGORITHM_TYPE_DSM, 0))
return;
qDebug() << current_time.toString("[yyyy-MM-dd HH:mm:ss] ") << " Dsm FrameId=" << pObjectTrackEventResult->nFrameId << " nEventType=" << pObjectTrackEventResult->nEventType;
/* 生成报警图片 */
auto image_path = HxTaskDispatch::build_alarm_image(ALGORITHM_TYPE_DSM, 0, pObjectTrackEventResult->nFrameId);
/* 生成报警视频 */
auto record_path = HxTaskDispatch::build_alarm_video(ALGORITHM_TYPE_DSM, 0, pObjectTrackEventResult->nFrameId);
/* 上传 */
HxTaskDispatch::algorithm_alarm_event(current_time, 1, 0, pObjectTrackEventResult->nEventType, 0, 0, 0, 0, 0, 0, 0, image_path, record_path);
algorithm_type = ALGORITHM_TYPE_DSM;
}
else if (nDataChannel == 1 || /* BSD-右前 */
nDataChannel == 3 || /* BSD-右后 */
@ -52,7 +26,7 @@ void algorithm_alarm_callback(int nDataChannel, ObjectTrackEventResult* pObjectT
nDataChannel == 6 || /* BSD-前 */
nDataChannel == 7) /* BSD-后 */
{
int channel = 0;
algorithm_type = ALGORITHM_TYPE_BSD;
switch (nDataChannel)
{
@ -75,78 +49,45 @@ void algorithm_alarm_callback(int nDataChannel, ObjectTrackEventResult* pObjectT
channel = 5;
break;
}
}
if (!HxTaskDispatch::get_alarm_detection_timestamp(ALGORITHM_TYPE_BSD, channel))
return;
qDebug("ProcessBsdAlgResult nDataChannel=%d,nFrameId=%d,nObjectNumber=%d,nEventType=%x,nDangerLevel=%d\n", nDataChannel, pObjectTrackEventResult->nFrameId, pObjectTrackEventResult->nObjectNumber, pObjectTrackEventResult->nEventType, pObjectTrackEventResult->nDangerLevel);
for (int i = 0; i < pObjectTrackEventResult->nObjectNumber; i++)
for (int i = 0; i < EVENT_WARN_NUM; i++)
{
qDebug("pObjectTrackEventResult->objInfo[i].nDetectType=%d\n", pObjectTrackEventResult->objInfo[i].nDetectType);
qDebug("nLeft=%d,nTop=%d,nRight=%d,nBottom=%d\n", pObjectTrackEventResult->objInfo[i].nLeft, pObjectTrackEventResult->objInfo[i].nTop, pObjectTrackEventResult->objInfo[i].nRight, pObjectTrackEventResult->objInfo[i].nBottom);
if (pObjectTrackEventResult->objInfo[i].nDetectType == 0)
continue;
/* 生成报警图片 */
auto image_path = HxTaskDispatch::build_alarm_image(ALGORITHM_TYPE_BSD, channel, pObjectTrackEventResult->nFrameId);
/* 生成报警视频 */
auto record_path = HxTaskDispatch::build_alarm_video(ALGORITHM_TYPE_BSD, channel, pObjectTrackEventResult->nFrameId);
/* 上传 */
HxTaskDispatch::algorithm_alarm_event(current_time, channel,
if ((pObjectTrackEventResult->nEventType >> i & 0x01) == 0x01)
{
HxTaskDispatch::alarm_upload_event(algorithm_type,
current_time,
channel,
i + 1,
pObjectTrackEventResult->nDangerLevel,
pObjectTrackEventResult->nEventType,
pObjectTrackEventResult->objInfo[i].nDetectType,
pObjectTrackEventResult->objInfo[i].nLeft,
pObjectTrackEventResult->objInfo[i].nTop,
pObjectTrackEventResult->objInfo[i].nRight,
pObjectTrackEventResult->objInfo[i].nBottom,
pObjectTrackEventResult->objInfo[i].fDist,
pObjectTrackEventResult->objInfo[i].fVelo,
image_path,
record_path);
pObjectTrackEventResult->objInfo,
pObjectTrackEventResult->nObjectNumber,
pObjectTrackEventResult->tFaceLandMarks,
pObjectTrackEventResult->nFaceLandMarksNum,
pObjectTrackEventResult->nLeftLineType,
pObjectTrackEventResult->nRightLineType);
}
}
}
// adas算法车道线结果处理函数
void algorithm_lane_line_callback(DrawPointInfo* pPointInfo, void* pPrivData)
{
Q_UNUSED(pPrivData);
for (int i = 0; i < 4; i++)
{
printf("ProcessAdasAlgLaneLineResult pPointInfo->nPointCounters[i]=%d\n", pPointInfo->nPointCounters[i]);
for (unsigned int j = 0; j < pPointInfo->nPointCounters[i]; j++)
{
printf("pSrcPointX=%d,pSrcPointY=%d\n", pPointInfo->pSrcPointX[i][j], pPointInfo->pSrcPointY[i][j]);
}
}
return;
}
HxVideoDevice::HxVideoDevice(void)
{
detect_frame_buffer.u32Width = 1280;
detect_frame_buffer.u32Height = 720;
MvGetFrameBlkInfo(&detect_frame_buffer);
m_detect_frame_buffer.u32Width = 1280;
m_detect_frame_buffer.u32Height = 720;
m_detect_frame_buffer.pu8VirAddr = (unsigned char *)calloc(m_detect_frame_buffer.u32Width * m_detect_frame_buffer.u32Height * 3, sizeof(unsigned char));
}
bgr_frame_buffer.u32Width = 1280;
bgr_frame_buffer.u32Height = 720;
MvGetFrameBlkInfo(&bgr_frame_buffer);
HxVideoDevice::~HxVideoDevice(void)
{
free(m_detect_frame_buffer.pu8VirAddr);
}
void HxVideoDevice::set(int type, QString address)
{
this->type = type;
this->address = address;
m_type = type;
m_address = address;
#if USE_ALGORITHM
auto result = MvSetAlgResultFuncCallback(type, algorithm_alarm_callback, nullptr);
auto result = MvSetAlgResultFuncCallback(m_type, algorithm_detection_callback, nullptr);
if (result != 0)
return;
#endif
@ -158,199 +99,165 @@ void HxVideoDevice::set(int type, QString address, BsdWarnRegion region)
{
Q_UNUSED(region);
this->type = type;
this->address = address;
this->detection_status = false;
m_type = type;
m_address = address;
m_detection_status = false;
#if USE_ALGORITHM
auto result = MvSetAlgResultFuncCallback(type, algorithm_alarm_callback, nullptr);
auto result = MvSetAlgResultFuncCallback(m_type, algorithm_detection_callback, nullptr);
if (result != 0)
return;
MvSetBsdWarnRegion(type, &region);
MvSetBsdWarnRegion(m_type, &region);
#endif
start();
}
void HxVideoDevice::set(bool status) { detection_status = status; }
void HxVideoDevice::set(bool status) { m_detection_status = status; }
bool HxVideoDevice::get_alarm_detection_timestamp(void) { return alarm_detection_timestamp.secsTo(QDateTime::currentDateTime()) > 10; }
QString HxVideoDevice::snap()
bool HxVideoDevice::determine_alarm_detection_timestamp(int event_type)
{
// QString filename = "";
if (!m_alarm_detection_timestamps.contains(event_type))
{
m_alarm_detection_timestamps.insert(event_type, QDateTime::currentDateTime());
return true;
}
// record_frames_mutex.lock();
// if (record_frames.size() > 0)
// filename = record_frames.last();
// record_frames_mutex.unlock();
return m_alarm_detection_timestamps[event_type].secsTo(QDateTime::currentDateTime()) > HxDataBase::alarm_protect_timestamp.at(event_type).toInt();
}
// QFile file(filename);
// if (file.open(QIODevice::ReadOnly))
// return file.readAll().toBase64();
// return "";
void HxVideoDevice::create_alarm_data(int event_type, QString filename)
{
/* 更新报警检测时间戳 */
m_alarm_detection_timestamps[event_type] = QDateTime::currentDateTime();
/* 如果创建队列中存在该文件, 则不在重复创建 */
if (m_records.contains(filename))
return;
/* 创建线程 */
QtConcurrent::run([=](QDateTime _alarm_timestamp, QString _filename)
{
Mat mat;
int frame_id = 0;
VideoCapture capture;
HxVideoWriter video_writer;
video_frame_mutex.lock();
video_frame.copyTo(mat);
video_frame_mutex.unlock();
/* 添加文件名称, 表示正在创建 */
m_records_mutex.lock();
m_records.append(filename);
m_records_mutex.unlock();
return snap(mat);
}
sleep(HxDataBase::recording_prepend_time);
QString HxVideoDevice::build_image(int frame_id)
{
auto start_id = frame_id - video_fps * 5, end_id = frame_id + video_fps * 5;
QQueue<HxVideoFrame> frames;
alarm_detection_timestamp = QDateTime::currentDateTime();
m_prerecorded_frames_mutex.lock();
for (auto it = m_prerecorded_frames.begin(); it != m_prerecorded_frames.end(); ++it) {
if(it->time > _alarm_timestamp.addSecs(-1 * (HxDataBase::recording_prepend_time + 1)) && it->time < _alarm_timestamp.addSecs(HxDataBase::recording_prepend_time + 1))
frames.enqueue(it->copy());
}
m_prerecorded_frames_mutex.unlock();
QString filename = QString("%1_%2_%3.jpg").arg(start_id > 0 ? start_id : 0).arg(end_id).arg(QDateTime::currentDateTime().toString("yyyyMMddHHmmsszzz"));
QString image_path = QString("%1/%2.jpg").arg(TEMPORARY_RECORD_DIRECTORY, _filename);
QString record_path = QString("%1/%2.avi").arg(TEMPORARY_RECORD_DIRECTORY, _filename);
QString _record_path = QString("%1/%2.mp4").arg(TEMPORARY_RECORD_DIRECTORY, _filename);
record_frames_mutex.lock();
if (record_frames.contains(frame_id))
QFile::copy(record_frames[frame_id], QString("%1/%2").arg(TEMPORARY_ALARM_DIRECTORY).arg(filename));
record_frames_mutex.unlock();
HxLog::append("recording", QString("%1 frames count=%2").arg(_record_path).arg(frames.count()));
HxTaskDispatch::enqueue_upload_file(filename);
while(!frames.isEmpty())
{
frame_id++;
return QString("/%1/%2/alarm/%3").arg(QDateTime::currentDateTime().toString("yyyyMMdd"), HxDataBase::device_id, filename);
}
auto frame = frames.dequeue();
QString HxVideoDevice::build_video(int frame_id)
{
auto start_id = frame_id - video_fps * 5, end_id = frame_id + video_fps * 5;
/* 如果文件未被打开 */
if(!video_writer.open_status)
{
/* 查找关键帧 */
if (frame.packet->flags & AV_PKT_FLAG_KEY)
{
HxLog::append("recording", QString("%1 find %2 (AV_PKT_FLAG_KEY)").arg(_record_path).arg(frame_id));
QString filename = QString("%1_%2_%3.mp4").arg(start_id > 0 ? start_id : 0).arg(end_id).arg(QDateTime::currentDateTime().toString("yyyyMMddHHmmsszzz"));
/* 打开(创建)文件 */
video_writer.open(frame.ifmt_ctx, record_path);
if(!video_writer.open_status)
{
video_writer.close();
record_queue_mutex.lock();
record_queue.enqueue(filename);
record_queue_mutex.unlock();
frame.free();
return QString("/%1/%2/alarm/%3").arg(QDateTime::currentDateTime().toString("yyyyMMdd"), HxDataBase::device_id, filename);
goto END;
}
}
}
/* 在打开的状态, 开始写入帧数据 */
if(video_writer.open_status)
{
video_writer.send(frame.packet);
}
frame.free();
msleep(10);
}
if(video_writer.open_status)
{
video_writer.close();
if(!QFile::exists(record_path))
goto END;
HxLog::append("recording", QString("%1 create success").arg(_record_path));
capture = VideoCapture(record_path.toUtf8().data());
if(capture.isOpened())
{
capture.set(CAP_PROP_POS_FRAMES, static_cast<int>(capture.get(CV_CAP_PROP_FRAME_COUNT)) / 2);
if(capture.read(mat))
{
vector <int> compression_params;
compression_params.push_back(IMWRITE_JPEG_QUALITY);
compression_params.push_back(90);
if(imwrite(image_path.toUtf8().data(), mat, compression_params))
HxTaskDispatch::enqueue_upload_file(_filename+".jpg");
}
capture.release();
}
QFile::rename(record_path, _record_path);
HxTaskDispatch::enqueue_upload_file(_filename+".mp4");
END:
while(!frames.isEmpty())
frames.dequeue().free();
/* 删除文件表示, 待验证 */
m_records_mutex.lock();
m_records.removeAll(_filename);
m_records_mutex.unlock();
} },
m_alarm_detection_timestamps[event_type], filename);
}
void HxVideoDevice::test(void)
{
ObjectTrackEventResult pObjectTrackEventResult;
pObjectTrackEventResult.nFrameId = record_frames.lastKey();
pObjectTrackEventResult.nEventType = EVENT_PCW;
pObjectTrackEventResult.nFrameId = 0;
pObjectTrackEventResult.nEventType = m_type == 0 ? (ObjectEventType)(EVENT_PCW | EVENT_HMW) : EVENT_YAWN;
pObjectTrackEventResult.nObjectNumber = 1;
pObjectTrackEventResult.objInfo[0].nDetectType = PEDESTRIAN_TYPE;
algorithm_alarm_callback(0, &pObjectTrackEventResult, nullptr);
algorithm_detection_callback(0, &pObjectTrackEventResult, nullptr);
}
vector<uint8_t> HxVideoDevice::compress(Mat frame, int quality)
{
vector<uint8_t> buffer;
vector<int> compress_params;
compress_params.push_back(IMWRITE_JPEG_QUALITY);
compress_params.push_back(quality);
imencode(".jpg", frame, buffer, compress_params);
return buffer;
}
QString HxVideoDevice::snap(Mat frame) { return frame.data == nullptr ? "" : snap(compress(frame, 50)); }
QString HxVideoDevice::snap(vector<uint8_t> buffer) { return QString(QByteArray::fromRawData((const char*)buffer.data(), buffer.size()).toBase64()); }
void HxVideoDevice::recording_creation_task(void)
{
while (true)
{
if (record_queue.size() > 0)
{
record_queue_mutex.lock();
auto filename = record_queue.dequeue();
record_queue_mutex.unlock();
HxLog::append("recording", QString("type=%1, count=%2, %3 creation task start").arg(type).arg(record_queue.size()).arg(filename));
auto data = filename.split("_");
auto start_id = data[0].toInt(), end_id = data[1].toInt();
while (true)
{
record_frames_mutex.lock();
auto first_key = record_frames.firstKey();
auto last_key = record_frames.lastKey();
record_frames_mutex.unlock();
if (last_key < first_key)
{
HxLog::append("recording", QString("%1 not found last id, creation failed").arg(filename));
break;
}
/* 判断最新的视频帧是否超过设定的时间 */
if (last_key >= end_id)
{
record_frames_mutex.lock();
auto _record_frames = record_frames;
_record_frames.detach();
record_frames_mutex.unlock();
QString fullpath = QString("%1/%2").arg(TEMPORARY_ALARM_DIRECTORY).arg(filename);
VideoWriter writer(fullpath.toUtf8().data(), CV_FOURCC('m', 'p', '4', 'v'), video_fps, Size(video_width, video_height), true);
for (int i = start_id; i <= end_id; i++)
{
if (_record_frames.contains(i))
{
auto __frame = imread(_record_frames[i].toUtf8().data(), CV_LOAD_IMAGE_COLOR);
writer.write(__frame);
HxLog::append("recording", QString("%1 write frame id:%2").arg(filename).arg(i));
}
}
writer.release();
HxTaskDispatch::enqueue_upload_file(filename);
HxLog::append("recording", QString("%1 creation success").arg(type).arg(filename));
break;
}
msleep(100);
}
}
msleep(500);
}
}
void HxVideoDevice::video_frame_queue_check(void)
{
while (true)
{
/* 缓存队列超过30s, 删除掉头数据 */
record_frames_mutex.lock();
while (record_frames.count() > video_fps * 300)
{
auto filename = record_frames.first();
QFile::remove(filename);
record_frames.remove(record_frames.firstKey());
msleep(1);
}
record_frames_mutex.unlock();
msleep(1000);
}
}
void HxVideoDevice::video_frame_read_process()
void HxVideoDevice::read_process(void)
{
while (true)
{
@ -358,7 +265,7 @@ void HxVideoDevice::video_frame_read_process()
int error = 0;
AVDictionary* avdic = nullptr;
AVDictionary *avdic = nullptr;
/* 减少卡顿或者花屏现象,相当于增加或扩大了缓冲区,给予编码和发送足够的时间 */
av_dict_set(&avdic, "buffer_size", "1024000", 0);
@ -375,7 +282,7 @@ void HxVideoDevice::video_frame_read_process()
ifmt_ctx = avformat_alloc_context();
error = avformat_open_input(&ifmt_ctx, address.toUtf8().data(), nullptr, &avdic);
error = avformat_open_input(&ifmt_ctx, m_address.toUtf8().data(), nullptr, &avdic);
av_dict_free(&avdic);
@ -383,7 +290,7 @@ void HxVideoDevice::video_frame_read_process()
{
avformat_free_context(ifmt_ctx);
HxLog::append("videolivestream", QString("type=%1, avformat_open_input failed, errorcode=%2").arg(type).arg(error));
HxLog::append("videolivestream", QString("type=%1, avformat_open_input failed, errorcode=%2").arg(m_type).arg(error));
continue;
}
@ -394,48 +301,34 @@ void HxVideoDevice::video_frame_read_process()
avformat_free_context(ifmt_ctx);
HxLog::append("videolivestream", QString("type=%1, avformat_find_stream_info failed").arg(type));
HxLog::append("videolivestream", QString("type=%1, avformat_find_stream_info failed").arg(m_type));
return;
}
av_dump_format(ifmt_ctx, 0, address.toUtf8().data(), 0);
av_dump_format(ifmt_ctx, 0, m_address.toUtf8().data(), 0);
video_stream_index = -1;
auto m_video_stream_index = -1;
for (uint i = 0; i < ifmt_ctx->nb_streams; i++)
{
if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
video_fps = ifmt_ctx->streams[i]->avg_frame_rate.num;
video_width = ifmt_ctx->streams[i]->codecpar->width;
video_height = ifmt_ctx->streams[i]->codecpar->height;
video_stream_index = static_cast<int>(i);
m_video_stream_index = static_cast<int>(i);
HxLog::append("videolivestream", QString("type=%1, video_fps=%2, video_width=%3, video_height=%4").arg(type).arg(video_fps).arg(video_width).arg(video_height));
m_video_fps = ifmt_ctx->streams[i]->avg_frame_rate.num;
HxLog::append("videolivestream", QString("type=%1, video_fps=%2").arg(m_type).arg(m_video_fps));
break;
}
}
if (video_stream_index == -1)
if (m_video_stream_index == -1)
{
avformat_close_input(&ifmt_ctx);
avformat_free_context(ifmt_ctx);
HxLog::append("videolivestream", QString("type=%1, not found video stream").arg(type));
return;
}
bool decoder_status = false;
#if USE_ALGORITHM
decoder_status = decoder.initialization();
#else
decoder_status = decoder.initialization(ifmt_ctx);
#endif
if (!decoder_status)
{
HxLog::append("videolivestream", QString("type=%1, decoder initialization failed").arg(type));
HxLog::append("videolivestream", QString("type=%1, not found video stream").arg(m_type));
return;
}
@ -447,22 +340,17 @@ void HxVideoDevice::video_frame_read_process()
if (av_read_frame(ifmt_ctx, &packet) < 0)
break;
if (packet.stream_index == video_stream_index)
{
Mat mat;
decoder.decode(&packet, &mat);
m_decoding_frames_mutex.lock();
m_decoding_frames.enqueue(HxVideoFrame(ifmt_ctx, &packet));
m_decoding_frames_mutex.unlock();
if (mat.data != nullptr)
{
video_frame_mutex.lock();
mat.copyTo(video_frame);
video_frame_mutex.unlock();
}
}
m_prerecorded_frames_mutex.lock();
m_prerecorded_frames.enqueue(HxVideoFrame(ifmt_ctx, &packet));
m_prerecorded_frames_mutex.unlock();
av_packet_unref(&packet);
msleep(1000 / video_fps);
msleep(1000 / m_video_fps);
}
if (ifmt_ctx != nullptr)
@ -471,137 +359,91 @@ void HxVideoDevice::video_frame_read_process()
avformat_free_context(ifmt_ctx);
ifmt_ctx = nullptr;
}
}
}
decoder.release();
void HxVideoDevice::decoding_process(void)
{
Mat mat;
int m_frame_id = 0;
while (true)
{
msleep(10);
if (m_decoding_frames.isEmpty())
continue;
m_decoding_frames_mutex.lock();
auto frame = m_decoding_frames.dequeue();
m_decoding_frames_mutex.unlock();
if (!m_video_decoder.status)
{
#if USE_ALGORITHM
m_video_decoder.initialization();
#else
if (ifmt_ctx != nullptr)
m_video_decoder.initialization(ifmt_ctx);
#endif
if (!m_video_decoder.status)
{
HxLog::append("videolivestream", QString("type=%1, decoder initialization failed").arg(m_type));
goto frame_free;
}
}
/* 获取YUV数据 */
m_video_decoder.decode(frame.packet, &mat);
if (mat.data != nullptr)
{
/* 是否开始进行分析 */
if (m_detection_status)
{
/* 获取车速 */
auto car_info = HxTaskDispatch::get_car_info();
if (car_info->fVelocity >= 10)
{
m_detect_frame_buffer.nFrameId = m_frame_id; // 帧号
m_detect_frame_buffer.u64PTS = QDateTime::currentMSecsSinceEpoch(); // 时间戳(毫秒)
m_detect_frame_buffer.pu8VirAddr = mat.data;
#if USE_ALGORITHM
MvObjectEventDetect(this->m_type, &m_detect_frame_buffer, car_info);
#endif
m_frame_id++;
}
}
}
frame_free:
frame.free();
}
}
void HxVideoDevice::run()
{
/* 启动 录像创建任务 */
QtConcurrent::run(this, &HxVideoDevice::recording_creation_task);
/* 创建 缓存队列监控线程 */
QtConcurrent::run(this, &HxVideoDevice::video_frame_queue_check);
/* 创建 视频读取线程 */
QtConcurrent::run(this, &HxVideoDevice::video_frame_read_process);
QtConcurrent::run(this, &HxVideoDevice::read_process);
QDateTime time = QDateTime::currentDateTime();
/* 创建 录像 线程 */
QtConcurrent::run(this, &HxVideoDevice::decoding_process);
while (true)
{
// if(time.secsTo(QDateTime::currentDateTime()) >= (1000/video_fps))
/* 判断是否超过预录时长 */
if (!m_prerecorded_frames.isEmpty())
{
time = QDateTime::currentDateTime();
Mat mat;
video_frame_mutex.lock();
video_frame.copyTo(mat);
video_frame_mutex.unlock();
if (mat.data != nullptr)
while (QDateTime::currentDateTime() > m_prerecorded_frames.first().time.addSecs(60))
{
QString filename = QString("%1/%2_%3_%4.jpg").arg(TEMPORARY_VIDEO_DIRECTORY).arg(QDateTime::currentDateTime().toString("yyyyMMddHHmmsszzz")).arg(type).arg(frame_id);
vector<int> compress_params;
compress_params.push_back(IMWRITE_JPEG_QUALITY);
compress_params.push_back(90);
imwrite(filename.toUtf8().data(), mat, compress_params);
record_frames_mutex.lock();
record_frames.insert(frame_id, filename);
record_frames_mutex.unlock();
if (detection_status)
{
auto car_info = HxTaskDispatch::get_car_info();
if (car_info->fVelocity > 10)
{
bgr_frame_buffer.nFrameId = frame_id; // 帧号
bgr_frame_buffer.u64PTS = QDateTime::currentMSecsSinceEpoch(); // 时间戳(毫秒)
memcpy(bgr_frame_buffer.pu8VirAddr, mat.data, 1280 * 720 * 3);
MvConvertImage(&bgr_frame_buffer, &detect_frame_buffer); // bgr->nv16
#if USE_ALGORITHM
MvObjectEventDetect(this->type, &detect_frame_buffer, car_info);
#endif
m_prerecorded_frames_mutex.lock();
m_prerecorded_frames.dequeue().free();
m_prerecorded_frames_mutex.unlock();
}
}
frame_id++;
}
}
msleep(15);
msleep(1000);
}
}
int HxVideoDevice::MvGetFrameBlkInfo(VideoFrameDataInfo* pImageDataInfo)
{
Q_UNUSED(pImageDataInfo);
#if USE_ALGORITHM
if (pImageDataInfo == NULL)
return -1;
pImageDataInfo->pu8VirAddr = (unsigned char*)calloc(pImageDataInfo->u32Width * pImageDataInfo->u32Height * 3, sizeof(unsigned char));
if (pImageDataInfo->pu8VirAddr == NULL)
return -1;
#endif
return 0;
}
int HxVideoDevice::MvReleaseFrameBlkInfo(VideoFrameDataInfo* pImageDataInfo)
{
Q_UNUSED(pImageDataInfo);
#if USE_ALGORITHM
if (pImageDataInfo == NULL)
return -1;
if (pImageDataInfo->pu8VirAddr == NULL)
return -1;
free(pImageDataInfo->pu8VirAddr);
#endif
return 0;
}
int HxVideoDevice::MvConvertImage(VideoFrameDataInfo* pSrcImageDataInfo, VideoFrameDataInfo* pDstImageDataInfo)
{
Q_UNUSED(pSrcImageDataInfo);
Q_UNUSED(pDstImageDataInfo);
#if USE_ALGORITHM
rga_buffer_t src;
rga_buffer_t dst;
src = wrapbuffer_virtualaddr(pSrcImageDataInfo->pu8VirAddr, pSrcImageDataInfo->u32Width, pSrcImageDataInfo->u32Height, RK_FORMAT_BGR_888);
dst = wrapbuffer_virtualaddr(pDstImageDataInfo->pu8VirAddr, pDstImageDataInfo->u32Width, pDstImageDataInfo->u32Height, RK_FORMAT_YCbCr_420_SP);
if (src.width == 0 || dst.width == 0)
{
return -1;
}
src.format = RK_FORMAT_BGR_888;
dst.format = RK_FORMAT_YCbCr_422_SP;
IM_STATUS STATUS;
STATUS = imcvtcolor(src, dst, src.format, dst.format);
if (STATUS != IM_STATUS_SUCCESS)
{
qDebug("imcvtcolor error\n");
return -1;
}
pDstImageDataInfo->u64PTS = pSrcImageDataInfo->u64PTS;
pDstImageDataInfo->nFrameId = pSrcImageDataInfo->nFrameId;
#endif
return 0;
}

View File

@ -1,7 +1,6 @@
#ifndef HXVIDEODEVICE_H
#define HXVIDEODEVICE_H
#include <QtConcurrent>
#include <QThread>
#include <QDateTime>
@ -10,12 +9,10 @@
#include "HxTaskDispatch.h"
#include "HxDataBase.h"
#include "HxVideoWriter.h"
#include "HxVideoDecoder.h"
#include <opencv2/opencv.hpp>
//#include "HxMpp.h"
#if USE_ALGORITHM
#include "rga.h"
#include "im2d.hpp"
@ -29,75 +26,143 @@ extern "C"
using namespace cv;
using namespace std;
typedef struct __HxVideoFrame
{
QDateTime time;
AVFormatContext *ifmt_ctx;
AVPacket *packet;
__HxVideoFrame() {}
__HxVideoFrame(AVFormatContext *ifmt_ctx, AVPacket *packet)
{
this->time = QDateTime::currentDateTime();
this->ifmt_ctx = ifmt_ctx;
this->packet = av_packet_clone(packet);
}
__HxVideoFrame(QDateTime time, AVFormatContext *ifmt_ctx, AVPacket *packet)
{
this->time = time;
this->ifmt_ctx = ifmt_ctx;
this->packet = av_packet_clone(packet);
}
__HxVideoFrame copy() { return __HxVideoFrame(this->time, this->ifmt_ctx, this->packet); }
void free()
{
ifmt_ctx = nullptr;
if (packet)
{
av_packet_unref(packet);
av_packet_free(&packet);
}
}
} HxVideoFrame;
class HxVideoDevice : public QThread
{
Q_OBJECT
public:
HxVideoDevice(void);
~HxVideoDevice(void);
/**
* @brief
* @param type
* @param address
*/
void set(int type, QString address);
/**
* @brief
* @param type
* @param address
* @param region BSD报警区域
*/
void set(int type, QString address, BsdWarnRegion region);
/**
* @brief
* @param status true: ; false:
*/
void set(bool status);
bool get_alarm_detection_timestamp(void);
QString snap(void);
QString build_image(int frame_id);
QString build_video(int frame_id);
/**
* @brief
* @param event_type
* @return true: ; false:
*/
bool determine_alarm_detection_timestamp(int event_type);
/**
* @brief ()
* @param event_type
* @param filename
*/
void create_alarm_data(int event_type, QString filename);
/**
* @brief
*/
void test(void);
private:
vector<uint8_t> compress(Mat frame, int quality);
QString snap(Mat frame);
QString snap(vector<uint8_t> data);
void recording_creation_task(void);
void video_frame_queue_check(void);
/* 读取线程 */
void read_process(void);
void video_frame_read_process(void);
void video_decoder_packet(AVPacket packet);
/* 解码线程 */
void decoding_process(void);
protected:
void run() override;
;
private:
int MvGetFrameBlkInfo(VideoFrameDataInfo *pImageDataInfo);
int MvReleaseFrameBlkInfo(VideoFrameDataInfo *pImageDataInfo);
int MvConvertImage(VideoFrameDataInfo *pSrcImageDataInfo, VideoFrameDataInfo *pDstImageDataInfo);
/* 算法通道类型 */
int m_type;
private:
int type;
int frame_id = 0;
QString address = "";
QDateTime alarm_detection_timestamp = QDateTime::currentDateTime();
bool detection_status = true;
/* 视频帧率 */
int m_video_fps = 25;
QMutex record_queue_mutex;
QQueue<QString> record_queue;
/* 视频地址(RTSP流) */
QString m_address = "";
VideoFrameDataInfo detect_frame_buffer;
VideoFrameDataInfo bgr_frame_buffer;
/* 报警检测时间 */
QMap<int, QDateTime> m_alarm_detection_timestamps;
// QMutex video_frames_mutex;
// QQueue<Mat> video_frames;
/* 检测状态(是否送帧给算法的标识) */
bool m_detection_status = true;
QMutex video_frame_mutex;
Mat video_frame;
/* 正在创建的录像文件 */
QMutex m_records_mutex;
QList<QString> m_records;
QMutex record_frames_mutex;
QMap<int, QString> record_frames;
/* 视频图像帧信息 */
VideoFrameDataInfo m_detect_frame_buffer;
int video_fps = 25;
int video_width = 0, video_height = 0;
int video_stream_index = 0;
bool connect_status;
/* FFmpeg */
AVFormatContext *ifmt_ctx;
HxVideoDecoder decoder;
/* 解码帧队列及锁 */
QMutex m_decoding_frames_mutex;
QQueue<HxVideoFrame> m_decoding_frames;
// uint8_t *video_out_buffer = nullptr;
// struct SwsContext *video_sws_context = nullptr;
/* 预录帧队列及锁 */
QMutex m_prerecorded_frames_mutex;
QQueue<HxVideoFrame> m_prerecorded_frames;
// AVCodecContext *video_dec_ctx = nullptr;
// AVFrame *video_dec_frame = nullptr, *video_picture_frame = nullptr;
/* 视频打包类 */
HxVideoWriter m_video_writer;
/* 视频解码类 */
HxVideoDecoder m_video_decoder;
};
#endif

239
app/HxVideoWriter.h Normal file
View File

@ -0,0 +1,239 @@
#ifndef HXVIDEOWRITER_H
#define HXVIDEOWRITER_H
#include <QObject>
#include <QDebug>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/time.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include <libavutil/audio_fifo.h>
}
class HxVideoWriter
{
public:
HxVideoWriter() : open_status(false) {}
void open(AVFormatContext *ifmt_ctx, QString filename)
{
int ret = -1;
video_index = -1;
audio_index = -1;
video_frame_index = 0;
audio_frame_index = 0;
ofmt_ctx = nullptr;
video_dec_stream = nullptr;
audio_dec_stream = nullptr;
/* 查找流中视频与音频位置 */
if (ifmt_ctx->nb_streams > 2)
{
m_error = QObject::tr("数据流异常");
return;
}
for (uint i = 0; i < ifmt_ctx->nb_streams; i++)
{
if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
video_index = static_cast<int>(i);
video_dec_stream = ifmt_ctx->streams[i];
}
else if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
audio_index = static_cast<int>(i);
audio_dec_stream = ifmt_ctx->streams[i];
}
}
if (video_index == -1)
{
m_error = QObject::tr("未找到视频流");
return;
}
avformat_alloc_output_context2(&ofmt_ctx, nullptr, nullptr, filename.toStdString().data());
if (!ofmt_ctx)
{
m_error = QObject::tr("无法打开输出文件");
return;
}
for (uint i = 0; i < ifmt_ctx->nb_streams; i++)
{
/* 根据输入流创建输出流 */
AVCodec *codec = avcodec_find_decoder(ifmt_ctx->streams[i]->codecpar->codec_id);
AVStream *out_stream = avformat_new_stream(ofmt_ctx, codec);
if (!out_stream)
{
m_error = QObject::tr("无法创建输出流");
return;
}
/* 复制AVCodecContext的设置 */
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
ret = avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[i]->codecpar);
if (ret < 0)
{
m_error = QObject::tr("未能将输入流中的codepar复制到编解码器上下文");
avcodec_free_context(&codec_ctx);
return;
}
codec_ctx->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_parameters_from_context(out_stream->codecpar, codec_ctx);
if (ret < 0)
{
m_error = QObject::tr("无法将编解码器上下文复制到输出流codepar上下文");
avcodec_free_context(&codec_ctx);
return;
}
avcodec_free_context(&codec_ctx);
}
ofmt_ctx->streams[video_index]->time_base = {1, 25};
av_dump_format(ofmt_ctx, 0, filename.toStdString().data(), 1);
if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
{
ret = avio_open(&ofmt_ctx->pb, filename.toStdString().data(), AVIO_FLAG_WRITE);
if (ret < 0)
{
m_error = QObject::tr("无法打开输出文件");
return;
}
}
ret = avformat_write_header(ofmt_ctx, nullptr);
if (ret < 0)
{
m_error = QObject::tr("无法写入文件头信息");
return;
}
open_status = true;
}
void send(AVPacket *packet)
{
auto out_stream = ofmt_ctx->streams[packet->stream_index];
if (packet->stream_index == video_index)
{
auto pts = av_rescale_q_rnd(packet->pts, video_dec_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
auto dts = av_rescale_q_rnd(packet->dts, video_dec_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
if (video_frame_index == 0)
{
video_pts = pts < 0 ? 0 : pts;
video_dts = dts < 0 ? 0 : dts;
}
else if (video_frame_index == 1)
{
if (video_pts > pts)
video_pts = pts;
else
video_pts = pts - video_pts;
if (video_dts > dts)
video_dts = dts;
else
video_dts = dts - video_dts;
}
packet->pts = video_pts * video_frame_index;
packet->dts = video_dts * video_frame_index;
packet->duration = 0;
video_frame_index++;
}
else if (packet->stream_index == audio_index)
{
auto pts = av_rescale_q_rnd(packet->pts, audio_dec_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
auto dts = av_rescale_q_rnd(packet->dts, audio_dec_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
if (audio_frame_index == 1 && pts > 0)
{
audio_pts = pts - audio_pts;
audio_dts = dts - audio_dts;
}
else if (audio_frame_index == 0)
{
audio_pts = pts < 0 ? 0 : pts;
audio_dts = dts < 0 ? 0 : dts;
}
packet->pts = audio_pts * audio_frame_index;
packet->dts = audio_dts * audio_frame_index;
packet->duration = 0;
audio_frame_index++;
}
auto ret = av_interleaved_write_frame(ofmt_ctx, packet);
if (ret < 0)
{
// HxTrace::debug_write_line("VideoWrite", QString("Error muxing packet, ret = %1").arg(ret));
qDebug() << "Error muxing packet";
// 这里是否需要做处理 ???
}
}
void close()
{
// Write file trailer
if (open_status)
av_write_trailer(ofmt_ctx);
video_pts = 0;
video_dts = 0;
audio_pts = 0;
audio_dts = 0;
video_frame_index = 0;
audio_frame_index = 0;
/* close output */
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
}
QString error() { return m_error; }
public:
bool open_status;
private:
QString m_error;
int video_index, audio_index;
int video_frame_index, audio_frame_index;
long long video_pts, video_dts, audio_pts, audio_dts;
AVFormatContext *ofmt_ctx;
AVStream *video_dec_stream, *audio_dec_stream;
};
#endif

View File

@ -23,7 +23,7 @@ CONFIG += c++11
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
# Input
HEADERS += HxDataBase.h HxTaskDispatch.h HxUtils.h HxVideoDevice.h HxVideoDecoder.h
HEADERS += HxDataBase.h HxTaskDispatch.h HxUtils.h HxVideoDevice.h HxVideoDecoder.h HxVideoWriter.h
SOURCES += HxDataBase.cpp HxTaskDispatch.cpp HxVideoDevice.cpp main.cpp
#DEFINES += USE_RABBITMQ
@ -57,9 +57,7 @@ unix {
LIBS += -L$$PWD/external/npu -lrknn_api
# LIBS += /usr/lib/librga.so
LIBS += -L/root/works/librga/libs/Linux/gcc-aarch64 -lrga
PRE_TARGETDEPS += /root/works/librga/libs/Linux/gcc-aarch64/librga.a
LIBS += /usr/lib/librga.so
LIBS += /usr/local/lib/librockchip_mpp.so
}

View File

@ -3,9 +3,6 @@
#include <HxDataBase.h>
#include "HxTaskDispatch.h"
#include <opencv2/opencv.hpp>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
@ -17,8 +14,8 @@ int main(int argc, char *argv[])
HxLog::append("application", "startup");
/* 创建数据缓存目录 */
HxDir::mkdir({{TEMPORARY_VIDEO_DIRECTORY},
{TEMPORARY_ALARM_DIRECTORY}});
HxDir::mkpath({{TEMPORARY_LOG_DIRECTORY},
{TEMPORARY_RECORD_DIRECTORY}});
/* 设置最大线程个数 */
QThreadPool::globalInstance()->setMaxThreadCount(100);