IVA/app/HxVideoDevice.cpp

450 lines
15 KiB
C++
Raw Permalink Normal View History

2023-10-20 23:36:22 +08:00
#include "HxVideoDevice.h"
2023-11-27 14:03:29 +08:00
#include "HxDataBase.h"
#include "HxUtils.h"
2023-10-20 23:36:22 +08:00
/* 算法报警处理函数 */
void algorithm_detection_callback(int nDataChannel, ObjectTrackEventResult *pObjectTrackEventResult, void *pPrivData)
2023-10-20 23:36:22 +08:00
{
Q_UNUSED(nDataChannel);
Q_UNUSED(pPrivData);
int algorithm_type = 0, channel = 0;
QDateTime current_time = QDateTime::currentDateTime();
if (nDataChannel == 0)
2023-10-20 23:36:22 +08:00
{
algorithm_type = ALGORITHM_TYPE_ADAS;
2023-10-20 23:36:22 +08:00
}
else if (nDataChannel == 2)
2023-10-20 23:36:22 +08:00
{
algorithm_type = ALGORITHM_TYPE_DSM;
2023-10-20 23:36:22 +08:00
}
else if (nDataChannel == 1 || /* BSD-右前 */
nDataChannel == 3 || /* BSD-右后 */
nDataChannel == 4 || /* BSD-左前 */
nDataChannel == 5 || /* BSD-左后 */
nDataChannel == 6 || /* BSD-前 */
nDataChannel == 7) /* BSD-后 */
2023-10-20 23:36:22 +08:00
{
algorithm_type = ALGORITHM_TYPE_BSD;
2023-10-20 23:36:22 +08:00
switch (nDataChannel)
{
case 6:
channel = 0;
break;
case 7:
channel = 1;
break;
case 4:
channel = 2;
break;
case 1:
channel = 3;
break;
case 5:
channel = 4;
break;
case 3:
channel = 5;
break;
}
}
for (int i = 0; i < EVENT_WARN_NUM; i++)
{
if ((pObjectTrackEventResult->nEventType >> i & 0x01) == 0x01)
{
HxTaskDispatch::alarm_upload_event(algorithm_type,
current_time,
channel,
i + 1,
pObjectTrackEventResult->nDangerLevel,
pObjectTrackEventResult->objInfo,
pObjectTrackEventResult->nObjectNumber,
pObjectTrackEventResult->tFaceLandMarks,
pObjectTrackEventResult->nFaceLandMarksNum,
pObjectTrackEventResult->nLeftLineType,
pObjectTrackEventResult->nRightLineType);
}
}
}
HxVideoDevice::HxVideoDevice(void)
2023-10-20 23:36:22 +08:00
{
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));
}
2023-10-20 23:36:22 +08:00
HxVideoDevice::~HxVideoDevice(void)
{
free(m_detect_frame_buffer.pu8VirAddr);
2023-10-20 23:36:22 +08:00
}
void HxVideoDevice::set(int type, QString address)
2023-10-20 23:36:22 +08:00
{
m_type = type;
m_address = address;
2023-10-20 23:36:22 +08:00
#if USE_ALGORITHM
auto result = MvSetAlgResultFuncCallback(m_type, algorithm_detection_callback, nullptr);
2023-10-20 23:36:22 +08:00
if (result != 0)
return;
#endif
start();
}
void HxVideoDevice::set(int type, QString address, BsdWarnRegion region)
2023-10-20 23:36:22 +08:00
{
Q_UNUSED(region);
m_type = type;
m_address = address;
m_detection_status = false;
2023-10-20 23:36:22 +08:00
#if USE_ALGORITHM
auto result = MvSetAlgResultFuncCallback(m_type, algorithm_detection_callback, nullptr);
2023-10-20 23:36:22 +08:00
if (result != 0)
return;
MvSetBsdWarnRegion(m_type, &region);
2023-10-20 23:36:22 +08:00
#endif
start();
}
void HxVideoDevice::set(bool status) { m_detection_status = status; }
2023-10-20 23:36:22 +08:00
bool HxVideoDevice::determine_alarm_detection_timestamp(int event_type)
2023-11-27 14:03:29 +08:00
{
if (!m_alarm_detection_timestamps.contains(event_type))
{
m_alarm_detection_timestamps.insert(event_type, QDateTime::currentDateTime());
return true;
}
2023-10-20 23:36:22 +08:00
return m_alarm_detection_timestamps[event_type].secsTo(QDateTime::currentDateTime()) > HxDataBase::alarm_protect_timestamp.at(event_type).toInt();
}
2023-10-20 23:36:22 +08:00
void HxVideoDevice::create_alarm_data(int event_type, QString filename)
{
/* 更新报警检测时间戳 */
m_alarm_detection_timestamps[event_type] = QDateTime::currentDateTime();
2023-10-20 23:36:22 +08:00
/* 如果创建队列中存在该文件, 则不在重复创建 */
if (m_records.contains(filename))
return;
2023-10-20 23:36:22 +08:00
/* 创建线程 */
QtConcurrent::run([=](QDateTime _alarm_timestamp, QString _filename)
{
Mat mat;
int frame_id = 0;
VideoCapture capture;
HxVideoWriter video_writer;
2023-10-20 23:36:22 +08:00
/* 添加文件名称, 表示正在创建 */
m_records_mutex.lock();
m_records.append(filename);
m_records_mutex.unlock();
2023-10-20 23:36:22 +08:00
sleep(HxDataBase::recording_prepend_time);
2023-10-20 23:36:22 +08:00
QQueue<HxVideoFrame> frames;
2023-10-20 23:36:22 +08:00
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();
2023-10-20 23:36:22 +08:00
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);
2023-10-20 23:36:22 +08:00
HxLog::append("recording", QString("%1 frames count=%2").arg(_record_path).arg(frames.count()));
2023-10-20 23:36:22 +08:00
while(!frames.isEmpty())
{
frame_id++;
2023-10-20 23:36:22 +08:00
auto frame = frames.dequeue();
2023-10-20 23:36:22 +08:00
/* 如果文件未被打开 */
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));
2023-10-20 23:36:22 +08:00
/* 打开(创建)文件 */
video_writer.open(frame.ifmt_ctx, record_path);
if(!video_writer.open_status)
{
video_writer.close();
2023-10-20 23:36:22 +08:00
frame.free();
2023-10-20 23:36:22 +08:00
goto END;
}
}
}
2023-10-20 23:36:22 +08:00
/* 在打开的状态, 开始写入帧数据 */
if(video_writer.open_status)
{
video_writer.send(frame.packet);
}
2023-10-20 23:36:22 +08:00
frame.free();
msleep(10);
}
if(video_writer.open_status)
{
video_writer.close();
2023-11-27 14:03:29 +08:00
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");
}
2023-10-20 23:36:22 +08:00
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);
}
2023-10-20 23:36:22 +08:00
void HxVideoDevice::test(void)
{
ObjectTrackEventResult pObjectTrackEventResult;
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_detection_callback(0, &pObjectTrackEventResult, nullptr);
}
void HxVideoDevice::read_process(void)
{
while (true)
{
2023-11-27 14:03:29 +08:00
msleep(5000);
2023-10-20 23:36:22 +08:00
2023-11-27 14:03:29 +08:00
int error = 0;
AVDictionary *avdic = nullptr;
2023-11-27 14:03:29 +08:00
/* 减少卡顿或者花屏现象,相当于增加或扩大了缓冲区,给予编码和发送足够的时间 */
av_dict_set(&avdic, "buffer_size", "1024000", 0);
// /* 减少采集缓存 */
// av_dict_set(&avdic, "preset", "fast", 0);
// av_dict_set(&avdic, "tune", "zerolatency", 0);
// /* 减少音频采集sampels数量 */
// av_dict_set(&avdic, "audio_buffer_size","30", 0);
av_dict_set(&avdic, "stimeout", "500000", 0);
av_dict_set(&avdic, "max_delay", "500000", 0);
av_dict_set(&avdic, "rtsp_transport", "tcp", 0);
avformat_network_init();
ifmt_ctx = avformat_alloc_context();
error = avformat_open_input(&ifmt_ctx, m_address.toUtf8().data(), nullptr, &avdic);
2023-11-27 14:03:29 +08:00
av_dict_free(&avdic);
if (error != 0)
{
avformat_free_context(ifmt_ctx);
HxLog::append("videolivestream", QString("type=%1, avformat_open_input failed, errorcode=%2").arg(m_type).arg(error));
2023-11-27 14:03:29 +08:00
continue;
}
if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0)
{
2023-11-27 14:03:29 +08:00
avformat_close_input(&ifmt_ctx);
avformat_free_context(ifmt_ctx);
HxLog::append("videolivestream", QString("type=%1, avformat_find_stream_info failed").arg(m_type));
2023-10-20 23:36:22 +08:00
2023-11-27 14:03:29 +08:00
return;
}
av_dump_format(ifmt_ctx, 0, m_address.toUtf8().data(), 0);
2023-11-27 14:03:29 +08:00
auto m_video_stream_index = -1;
2023-11-27 14:03:29 +08:00
for (uint i = 0; i < ifmt_ctx->nb_streams; i++)
{
if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
m_video_stream_index = static_cast<int>(i);
2023-10-20 23:36:22 +08:00
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));
2023-11-27 14:03:29 +08:00
break;
}
}
2023-10-20 23:36:22 +08:00
if (m_video_stream_index == -1)
{
2023-11-27 14:03:29 +08:00
avformat_close_input(&ifmt_ctx);
avformat_free_context(ifmt_ctx);
2023-10-20 23:36:22 +08:00
HxLog::append("videolivestream", QString("type=%1, not found video stream").arg(m_type));
2023-11-27 14:03:29 +08:00
return;
2023-10-20 23:36:22 +08:00
}
2023-11-27 14:03:29 +08:00
while (true)
{
AVPacket packet;
if (av_read_frame(ifmt_ctx, &packet) < 0)
break;
m_decoding_frames_mutex.lock();
m_decoding_frames.enqueue(HxVideoFrame(ifmt_ctx, &packet));
m_decoding_frames_mutex.unlock();
2023-11-27 14:03:29 +08:00
m_prerecorded_frames_mutex.lock();
m_prerecorded_frames.enqueue(HxVideoFrame(ifmt_ctx, &packet));
m_prerecorded_frames_mutex.unlock();
2023-11-27 14:03:29 +08:00
av_packet_unref(&packet);
msleep(1000 / m_video_fps);
2023-11-27 14:03:29 +08:00
}
if (ifmt_ctx != nullptr)
{
avformat_close_input(&ifmt_ctx);
avformat_free_context(ifmt_ctx);
ifmt_ctx = nullptr;
}
2023-10-20 23:36:22 +08:00
}
}
void HxVideoDevice::decoding_process(void)
2023-10-20 23:36:22 +08:00
{
Mat mat;
int m_frame_id = 0;
2023-10-20 23:36:22 +08:00
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)
{
2023-11-27 14:03:29 +08:00
#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;
2023-11-27 14:03:29 +08:00
}
}
2023-10-20 23:36:22 +08:00
/* 获取YUV数据 */
m_video_decoder.decode(frame.packet, &mat);
2023-10-20 23:36:22 +08:00
if (mat.data != nullptr)
{
/* 是否开始进行分析 */
if (m_detection_status)
{
/* 获取车速 */
auto car_info = HxTaskDispatch::get_car_info();
2023-10-20 23:36:22 +08:00
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;
2023-10-20 23:36:22 +08:00
#if USE_ALGORITHM
MvObjectEventDetect(this->m_type, &m_detect_frame_buffer, car_info);
2023-10-20 23:36:22 +08:00
#endif
m_frame_id++;
}
}
}
frame_free:
frame.free();
}
2023-10-20 23:36:22 +08:00
}
void HxVideoDevice::run()
2023-10-20 23:36:22 +08:00
{
/* 创建 视频读取线程 */
QtConcurrent::run(this, &HxVideoDevice::read_process);
2023-10-20 23:36:22 +08:00
/* 创建 录像 线程 */
QtConcurrent::run(this, &HxVideoDevice::decoding_process);
2023-10-20 23:36:22 +08:00
while (true)
2023-10-20 23:36:22 +08:00
{
/* 判断是否超过预录时长 */
if (!m_prerecorded_frames.isEmpty())
{
while (QDateTime::currentDateTime() > m_prerecorded_frames.first().time.addSecs(60))
{
m_prerecorded_frames_mutex.lock();
m_prerecorded_frames.dequeue().free();
m_prerecorded_frames_mutex.unlock();
}
}
2023-10-20 23:36:22 +08:00
msleep(1000);
2023-10-20 23:36:22 +08:00
}
}