Train_Identify/nvidia_ascend_engine/common_engine/DataSourceEngine/CameraEngine.cpp

1 line
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "CameraEngine.h"
#include "myutils.h"
using namespace ai_matrix;
namespace
{
const int LOW_THRESHOLD = 128;
const int MAX_THRESHOLD = 4096;
const uint16_t DELAY_TIME = 20000;
}
CameraEngine::CameraEngine() {}
CameraEngine::~CameraEngine() {}
APP_ERROR CameraEngine::Init()
{
bUseEngine_ = true;
bHwDecode_ = MyYaml::GetIns()->GetBoolValue("gc_hardware_decode");
dataSourceConfig_ = MyYaml::GetIns()->GetDataSourceConfigById(engineId_); //获取摄像机参数
if (MyYaml::GetIns()->GetStringValue("gc_data_source") != "camera" || !dataSourceConfig_.bUse)
{
bUseEngine_ = false;
LogWarn << "engineId_:" << engineId_ << " not use engine";
return APP_ERR_OK;
}
strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1";
nDelayTime = MyYaml::GetIns()->GetIntValue("gc_load_delay");
LogInfo << "engineId_:" << engineId_ << " CameraEngine Init ok";
return APP_ERR_OK;
}
APP_ERROR CameraEngine::DeInit()
{
if (!bUseEngine_)
{
LogWarn << "engineId_:" << engineId_ << " not use engine";
return APP_ERR_OK;
}
ResetCamera();
LogInfo << "engineId_:" << engineId_ << " CameraEngine DeInit ok";
return APP_ERR_OK;
}
void CameraEngine::ResetCamera()
{
if (pFormatCtx_ != nullptr)
{
// clear th cache of the queue
avformat_close_input(&pFormatCtx_);
pFormatCtx_ = nullptr;
}
}
APP_ERROR CameraEngine::ConnectCamera()
{
pFormatCtx_ = CreateFormatContext(); // create context
if (pFormatCtx_ == nullptr)
{
LogError << "engineId_:" << engineId_ << " pFormatCtx_ null!";
return APP_ERR_COMM_FAILURE;
}
//0-代表输入
av_dump_format(pFormatCtx_, 0, dataSourceConfig_.strUrl.c_str(), 0);
// get stream infomation
int iRet = APP_ERR_OK;
iRet = GetStreamInfo();
if (iRet != APP_ERR_OK)
{
LogError << "engineId_:" << engineId_ << " Stream Info Check failed, iRet = " << iRet;
return APP_ERR_COMM_FAILURE;
}
return APP_ERR_OK;
}
APP_ERROR CameraEngine::GetStreamInfo()
{
if (pFormatCtx_ != nullptr)
{
iVideoStream_ = -1;
iAudioStream_ = -1;
//frameInfo_.iFrameId = 0; //帧号从0开始
for (unsigned int i = 0; i < pFormatCtx_->nb_streams; i++)
{
AVStream *inStream = pFormatCtx_->streams[i];
if (inStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
iVideoStream_ = i;
frameInfo_.iHeight = inStream->codecpar->height;
frameInfo_.iWidth = inStream->codecpar->width;
//获取帧率,帧率的打印都在流中的两个成员.且应取平均帧率为先,为{x,0}或者{0,1}则取实时帧率
if (inStream->avg_frame_rate.den == 0 || (inStream->avg_frame_rate.num == 0 && inStream->avg_frame_rate.den == 1))
{
frameInfo_.iRate = inStream->r_frame_rate.num / inStream->r_frame_rate.den;
}
else
{
frameInfo_.iRate = inStream->avg_frame_rate.num / inStream->avg_frame_rate.den;
}
LogDebug << "engineId_:" << engineId_ << " width:" << frameInfo_.iWidth << " height:" << frameInfo_.iHeight
<< " rate:" << frameInfo_.iRate << " iVideoStream_:" << iVideoStream_;
}
else if (inStream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
iAudioStream_ = i;
LogDebug << "engineId_:" << engineId_ << " iAudioStream_:" << iAudioStream_;
}
}
if (iVideoStream_ == -1)
{
LogError << "engineId_:" << engineId_ << " Didn't find a video stream!";
return APP_ERR_COMM_FAILURE;
}
if (frameInfo_.iHeight < LOW_THRESHOLD || frameInfo_.iWidth < LOW_THRESHOLD ||
frameInfo_.iHeight > MAX_THRESHOLD || frameInfo_.iWidth > MAX_THRESHOLD)
{
LogError << "engineId_:" << engineId_ << " Size of frame is not supported in DVPP Video Decode!";
return APP_ERR_COMM_FAILURE;
}
AVCodecID codecId = pFormatCtx_->streams[iVideoStream_]->codecpar->codec_id;
if (codecId == AV_CODEC_ID_H264)
{
int profile = pFormatCtx_->streams[iVideoStream_]->codecpar->profile;
if (profile == FF_PROFILE_H264_BASELINE)
{
frameInfo_.format = H264_BASELINE_LEVEL;
}
else if (profile == FF_PROFILE_H264_MAIN)
{
frameInfo_.format = H264_MAIN_LEVEL;
}
else if (profile == FF_PROFILE_H264_HIGH)
{
frameInfo_.format = H264_HIGH_LEVEL;
}
else
{
LogError << "engineId_:" << engineId_ << " not support h264 profile";
return APP_ERR_COMM_FAILURE;
}
}
else if (codecId == AV_CODEC_ID_H265)
{
int profile = pFormatCtx_->streams[iVideoStream_]->codecpar->profile;
if (profile == FF_PROFILE_HEVC_MAIN)
{
frameInfo_.format = H265_MAIN_LEVEL;
}
else
{
LogError << "engineId_:" << engineId_ << " not support h265 profile";
return APP_ERR_COMM_FAILURE;
}
}
else
{
LogError << "engineId_:" << engineId_ << " Error unsupported format" << codecId;
return APP_ERR_COMM_FAILURE;
}
}
return APP_ERR_OK;
}
AVFormatContext *CameraEngine::CreateFormatContext()
{
// create message for stream pull
AVFormatContext *pFormatContext = nullptr;
AVDictionary *pOptions = nullptr;
// formatContext = avformat_alloc_context();
if (dataSourceConfig_.strUrl.find("rtsp:") != std::string::npos) // rtsp
{
av_dict_set(&pOptions, "rtsp_transport", "tcp", 0); // 指定其传输方式为TCP
// av_dict_set(&pOptions, "stimeout", "3000000", 0); // 设置超时3秒
// av_dict_set(&pOptions, "rw_timeout", "3000", 0); //单位:ms
av_dict_set(&pOptions, "timeout", "3000000", 0); //设置超时时间为3秒
}
//av_register_all(); //注册所有支持的格式(这里一定注册这些,否则会因为协议解析问题报错!!!)
//avcodec_register_all(); //注册编解码器
//avformat_network_init(); //注册网格格式,如果为本地文件则可以去掉该代码
int iRet = avformat_open_input(&pFormatContext, dataSourceConfig_.strUrl.c_str(), nullptr, &pOptions);
if (nullptr != pOptions)
{
av_dict_free(&pOptions);
}
if (iRet != 0)
{
LogError << "engineId_:" << engineId_ << " Couldn't open input stream " << dataSourceConfig_.strUrl.c_str() << ", iRet=" << iRet;
return nullptr;
}
// pFormatContext->flags |= AVFMT_FLAG_NONBLOCK;
// pFormatContext->pb->flags |= AVIO_FLAG_NONBLOCK;
// av_dict_set(&pFormatContext->interrupt_callback.callback, "timeout", "3000", 0);
// iRet = avio_open2(&pFormatContext->pb, dataSourceConfig_.strUrl.c_str(), AVIO_FLAG_READ, NULL, NULL) < 0;
// {
// // 处理错误
// LogError << "engineId_:" << engineId_ << "avio_open2 iRet=" << iRet;
// return nullptr;
// }
iRet = avformat_find_stream_info(pFormatContext, nullptr);
if (iRet != 0)
{
LogError << "engineId_:" << engineId_ << " Couldn't find stream information, iRet = " << iRet;
return nullptr;
}
return pFormatContext;
}
//av_read_frame的中断回调函数
// int CameraEngine::InterruptCallback(void *pData)
// {
// TimeoutContext* pTimeOutCtx = (TimeoutContext*)pData;
// LogDebug << "InterruptCallback i64Timeout:" << pTimeOutCtx->i64Timeout;
// return std::chrono::duration_cast<std::chrono::milliseconds>(
// std::chrono::system_clock::now().time_since_epoch())
// .count() >= pTimeOutCtx->i64Timeout
// ? AVERROR_EXIT
// : 0;
// }
APP_ERROR CameraEngine::Process()
{
int iRet = APP_ERR_OK;
if (!bUseEngine_)
{
LogWarn << "engineId_:" << engineId_ << " not use engine";
return APP_ERR_OK;
}
if (bHwDecode_)
{
iRet = ConnectCamera();
if (iRet == APP_ERR_OK)
{
LogInfo << "engineId_:" << engineId_ << " Start the stream......";
bReconnectFlag_ = false;
}
else
{
ResetCamera();
bReconnectFlag_ = true;
}
// Pull data cyclically
AVPacket pkt;
while (!isStop_)
{
//重连相机
if (bReconnectFlag_)
{
iRet = ConnectCamera();
if (iRet == APP_ERR_OK)
{
LogInfo << "engineId_:" << engineId_ << " Start the stream......";
bReconnectFlag_ = false;
this->bCameraError_ = false;
} else {
if (!this->bCameraError_) {
outputQueMap_[strPort1_]->push(
std::static_pointer_cast<void>(
std::make_shared<std::string>("摄像头连接失败!")));
this->bCameraError_ = true;
}
ResetCamera();
std::this_thread::sleep_for(std::chrono::seconds(3)); //3秒后重连
continue;
}
}
//设置av_read_frame中断函数 (中断函数中超过1s则中断处理)
// TimeoutContext timeoutCtx = { std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() + 1000 };
// pFormatCtx_->interrupt_callback.callback = &CameraEngine::InterruptCallback;
// pFormatCtx_->interrupt_callback.opaque = &timeoutCtx;
av_init_packet(&pkt); //init pkt
iRet = av_read_frame(pFormatCtx_, &pkt); //需要一直读取,否则获取到的是历史数据
if (iRet != 0)
{
outputQueMap_[strPort1_]->push(std::static_pointer_cast<void>(std::make_shared<std::string>("图像读取失败!")));
LogError << "engineId_:" << engineId_ << " Read frame failed, reconnect iRet:" << iRet;
av_packet_unref(&pkt);
//重连相机
ResetCamera();
bReconnectFlag_ = true;
continue;
}
else if (pkt.stream_index == iVideoStream_) //只解码视频流
{
// LogDebug << "iRet:" << iRet << " pkt.size:" << pkt.size;
if (pkt.size <= 0)
{
LogError << "engineId_:" << engineId_ << " Invalid pkt.size: " << pkt.size;
av_packet_unref(&pkt);
continue;
}
if (dataSourceConfig_.strUrl.find(".mp4") != std::string::npos)
{
const char szStartCode[4] = {0, 0, 0, 1};
if (bIsAvc_ || memcmp(szStartCode, pkt.data, 4) != 0)
{ // is avc1 code, have no start code of H264
int iLen = 0;
uint8_t *p = pkt.data;
bIsAvc_ = true;
do
{ // add start_code for each NAL, one frame may have multi NALs.
iLen = ntohl(*((long *)p));
memcpy(p, szStartCode, 4);
p += 4;
p += iLen;
if (p >= pkt.data + pkt.size)
{
break;
}
} while (1);
}
}
void* pH264Buffer = nullptr;
pH264Buffer = new uint8_t[pkt.size];
memcpy(pH264Buffer, pkt.data, pkt.size);
//组织数据
std::shared_ptr<ProcessData> pProcessData = std::make_shared<ProcessData>();
pProcessData->iWidth = frameInfo_.iWidth;
pProcessData->iHeight = frameInfo_.iHeight;
pProcessData->iRate = frameInfo_.iRate;
pProcessData->i64TimeStamp = MyUtils::getins()->GetCurrentTimeMillis();
pProcessData->iDataSource = engineId_;
pProcessData->iSize = pkt.size;
pProcessData->pData.reset(pH264Buffer, [](void* data){if(data) {delete[] data; data = nullptr;}}); //智能指针管理内存
//push端口0视频解码
iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pProcessData));
if (iRet != APP_ERR_OK)
{
LogError << "engineId_:" << engineId_ << "push the h264 frame data failed...";
}
}
else if (pkt.stream_index == iAudioStream_)
{
//音频流不处理。
}
else
{
LogError << "engineId_:" << engineId_ << " stream err stream_index:" << pkt.stream_index;
}
av_packet_unref(&pkt); //unref
if (dataSourceConfig_.strUrl.find("rtsp:") == std::string::npos) // 如果不是rtsp定时发送
{
usleep(DELAY_TIME); // delay 40ms
}
}
}
else
{
//从摄像头RTSP拉流
const std::string videoStreamAddress = std::string("rtspsrc location=") + dataSourceConfig_.strUrl.c_str() + " latency=10 ! \
rtph264depay ! h264parse ! nvv4l2decoder enable-max-performance=1 enable-frame-type-reporting=1 ! nvvidconv ! video/x-raw, format=(string)BGRx ! videoconvert ! appsink";
VideoCapture capture_video;
while(!capture_video.open(videoStreamAddress)){ //, cv::CAP_FFMPEG
LogInfo<<"Restart Opening video stream or file ..."<<std::endl;
sleep(1);
}
LogInfo<<"Opening video stream or file Success:"<<engineId_;
int frameW = capture_video.get(3);
int frameH = capture_video.get(4);
int frameRate = capture_video.get(5);
usleep(nDelayTime * 1000 * 1000);
int nFrameid = 0;
bool breadend = false;
cv::Mat frame(frameH, frameW, CV_8UC3);
while (!isStop_)
{
std::shared_ptr<FrameData> pBGRFrameData = std::make_shared<FrameData>();
std::shared_ptr<ProcessData> pProcessData = std::make_shared<ProcessData>();
if(!capture_video.read(frame)) {
capture_video.release();
while(!capture_video.open(videoStreamAddress)){ //, cv::CAP_FFMPEG
LogInfo<<"Restart Opening video stream or file ..."<<std::endl;
sleep(1);
}
continue;
}
unsigned int resizepBGRBuffer_Size = IMAGE_WIDTH*IMAGE_HEIGHT*3;
cv::Mat mtInImage, mtOutImage;
cv::resize(frame, mtInImage, cv::Size(IMAGE_WIDTH, IMAGE_HEIGHT));
cv::cvtColor(mtInImage, mtOutImage, cv::COLOR_BGR2RGB);
void* resizeBGRBufferobj = nullptr;
resizeBGRBufferobj = new uint8_t[resizepBGRBuffer_Size];
memcpy(resizeBGRBufferobj, mtOutImage.data, resizepBGRBuffer_Size);
pBGRFrameData->iDataSource = engineId_;
pBGRFrameData->iFrameId = nFrameid++;
pBGRFrameData->iSize = resizepBGRBuffer_Size;
pBGRFrameData->frameInfo.iWidth = IMAGE_WIDTH;
pBGRFrameData->frameInfo.iHeight = IMAGE_HEIGHT;
pBGRFrameData->frameInfo.iRate = frameRate;
pProcessData->pVoidData = std::static_pointer_cast<void>(pBGRFrameData);
pProcessData->pData.reset(resizeBGRBufferobj, [](void* data){if(data) {delete[] data; data = nullptr;}});
if (nFrameid >= 0xFFFFFFFF) {nFrameid = 0;}
pBGRFrameData->i64TimeStamp = MyUtils::getins()->GetCurrentTimeMillis();
pProcessData->iWidth = pBGRFrameData->frameInfo.iWidth;
pProcessData->iHeight = pBGRFrameData->frameInfo.iHeight;
pProcessData->iHeight = pBGRFrameData->frameInfo.iRate;
iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pProcessData));
}
}
return APP_ERR_OK;
}