#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 = 10000; } 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::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; } else { outputQueMap_[strPort1_]->push(std::static_pointer_cast(std::make_shared("摄像头连接失败!"))); ResetCamera(); std::this_thread::sleep_for(std::chrono::seconds(3)); //3秒后重连 continue; } } //设置av_read_frame中断函数 (中断函数中超过1s,则中断处理) // TimeoutContext timeoutCtx = { std::chrono::duration_cast(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(std::make_shared("图像读取失败!"))); 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 pProcessData = std::make_shared(); 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(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 ..."< pBGRFrameData = std::make_shared(); std::shared_ptr pProcessData = std::make_shared(); if(!capture_video.read(frame)) { capture_video.release(); while(!capture_video.open(videoStreamAddress)){ //, cv::CAP_FFMPEG LogInfo<<"Restart Opening video stream or file ..."<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(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(pProcessData)); } } return APP_ERR_OK; }