#include "FaceCache.h" #include "PipeLine.h" #include "MaterialBuffer.h" #include "PL_BlockGrouping.h" #include #include #include #include #include #include #include #include #include struct OutRGBBufferWrapper { uint8_t* buffer; size_t buffSize; OutRGBBufferWrapper() : buffer(nullptr), buffSize(0) { } OutRGBBufferWrapper(uint8_t* _buffer, size_t _buffSize) : buffer(_buffer), buffSize(_buffSize) { } }; struct FcPmBreackerContextPLBG { plbg_output_vec_t lastOutputs; std::vector lastOutputsRGBBufs; uint8_t frameYUV[1920*1080*4]; size_t frameYUVSize; uint8_t frameRGB[1920*1080*4]; size_t frameRGBSize; bool frameTruncated; typedef std::map block_score_filter_map_t; block_score_filter_map_t blockScoreFilter; FcPmBreackerContextPLBG() : lastOutputs(), lastOutputsRGBBufs(), frameYUV(), frameYUVSize(0), frameRGB(),frameRGBSize(0), frameTruncated(false), blockScoreFilter() {} void reset() { lastOutputs.clear(); lastOutputsRGBBufs.clear(); frameYUVSize = 0; frameRGBSize = 0; frameTruncated = false; } void copy_data() { uint8_t* bufPtr = frameYUV; for (plbg_output_vec_t::iterator iter = lastOutputs.begin(); iter != lastOutputs.end(); ++iter) { const uint8_t* originBuf = iter->croppedData; if (originBuf == nullptr || iter->croppedDataSize == 0) continue; if (sizeof(frameYUV) - (bufPtr - frameYUV) < iter->croppedDataSize) { frameTruncated = true; LOG_WARN << "yuv buffer truncated" << LOG_ENDL; break; } iter->croppedData = bufPtr; memcpy(bufPtr, originBuf, iter->croppedDataSize); bufPtr += iter->croppedDataSize; frameYUVSize += iter->croppedDataSize; } } void convert_data() { uint8_t* bufPtr = frameRGB; for (plbg_output_vec_t::iterator iter = lastOutputs.begin(); iter != lastOutputs.end(); ++iter) { if (iter->croppedData == nullptr || iter->croppedDataSize == 0) { OutRGBBufferWrapper bw; lastOutputsRGBBufs.push_back(bw); continue; } OutRGBBufferWrapper bw; bw.buffer = bufPtr; bw.buffSize = iter->rectInOriginFrame.rect.width() * iter->rectInOriginFrame.rect.height() * 2; //RGB565 if (sizeof(frameRGB) - (bufPtr - frameRGB) < bw.buffSize) { frameTruncated = true; OutRGBBufferWrapper bw; lastOutputsRGBBufs.push_back(bw); LOG_WARN << "rgb buffer truncated" << LOG_ENDL; continue; } convertYUV420ToRGB565(*iter, bw.buffer); lastOutputsRGBBufs.push_back(bw); bufPtr += bw.buffSize; frameRGBSize += bw.buffSize; } } private: bool convertYUV420ToRGB565(const PLBG_Output& out, uint8_t* rgbBuff) { int src_height = out.rectInOriginFrame.rect.height(); int src_width = out.rectInOriginFrame.rect.width(); const uint8* src_y = (const uint8*)(out.croppedData); const uint8* src_u = (const uint8*)(src_y + (src_height * src_width)); const uint8* src_v = (const uint8*)(src_u + (src_height * src_width / 4)); if (out.originframe->type == MB_Frame::MBFT_YUV420) { libyuv::I420ToRGB565(src_y, src_width, src_v, MH_SUBSAMPLE1(src_width, 2), src_u, MH_SUBSAMPLE1(src_width, 2), rgbBuff, 2 * src_width, src_width, src_height); } else if (out.originframe->type == MB_Frame::MBFT_NV12) { libyuv::NV12ToRGB565(src_y, src_width, src_u, src_width, rgbBuff, 2 * src_width, src_width, src_height); } else return false; //{ // static size_t f = 0; // char fname[50]; // sprintf(fname, "/sdcard/face-%u-w%u-h%u.rgb", ++f, src_width, src_height); // FILE *pFile = fopen(fname, "wb"); // fwrite(rgbBuff, 1, src_height * src_width * 2, pFile); // fclose(pFile); // if (f > 20)exit(0); //} return true; } }; FaceCacheForPLBG::FaceCacheForPLBG() : _ctx(new FcPmBreackerContextPLBG), resultBuffer(nullptr) { resultBuffer = new uint8_t[FACECACHEFORPLBG_RESULT_BUFFSIZE]; } FaceCacheForPLBG::~FaceCacheForPLBG() { delete (FcPmBreackerContextPLBG*)_ctx; delete resultBuffer; resultBuffer = nullptr; } // returns count of face int FaceCacheForPLBG::cachePm(const PipeMaterial& pm) { FcPmBreackerContextPLBG& ctx(*(FcPmBreackerContextPLBG*)_ctx); ctx.reset(); plbg_output_vec_t* plbgOut = (plbg_output_vec_t*)pm.buffer; if (plbgOut->size() == 0) return 0; ctx.lastOutputs = *plbgOut; ctx.copy_data(); ctx.convert_data(); return ctx.lastOutputs.size(); } size_t FaceCacheForPLBG::getFaceCount(const PipeMaterial& pm) const { FcPmBreackerContextPLBG& ctx(*(FcPmBreackerContextPLBG*)_ctx); plbg_output_vec_t* plbgOut = (plbg_output_vec_t*)pm.buffer; bool hasFiltedBlock = false; int min_st_track_id = 0; for (plbg_output_vec_t::iterator iterBGOut = plbgOut->begin(); iterBGOut != plbgOut->end(); ++iterBGOut) { int st_track_id = (int)(int64_t)(iterBGOut->rectInOriginFrame.userData); float score = iterBGOut->score; FcPmBreackerContextPLBG::block_score_filter_map_t::iterator iterFilter = ctx.blockScoreFilter.find(st_track_id); if (iterFilter == ctx.blockScoreFilter.end()) { ctx.blockScoreFilter.insert(std::make_pair(st_track_id, score)); hasFiltedBlock = true; } else { if (iterFilter->second < score) { iterFilter->second = score; hasFiltedBlock = true; } } if (min_st_track_id > st_track_id) min_st_track_id = st_track_id; } for(FcPmBreackerContextPLBG::block_score_filter_map_t::iterator iterFilter = ctx.blockScoreFilter.begin(); iterFilter != ctx.blockScoreFilter.end(); ) { if (iterFilter->first < min_st_track_id) iterFilter = ctx.blockScoreFilter.erase(iterFilter); else ++iterFilter; } if (hasFiltedBlock) return plbgOut->size(); else return 0; } bool FaceCacheForPLBG::getFaceListPb(uint8_t* buffer, size_t& buffMaxSize) { FcPmBreackerContextPLBG& ctx(*(FcPmBreackerContextPLBG*)_ctx); if (ctx.frameTruncated) { LOG_WARN << "ctx buffer truncated" << LOG_ENDL; return false; } PbFaceList pbFaceList; pbFaceList.set_magic(pbFaceList.magic()); pbFaceList.set_image_count(ctx.lastOutputs.size()); pbFaceList.set_src_width(0); pbFaceList.set_src_height(0); for (int i = 0; i < ctx.lastOutputs.size(); i++) { PbFaceList_FaceListImage &pbFaceListImage(*(pbFaceList.add_images())); pbFaceListImage.set_idx(i); pbFaceListImage.set_st_track_id((int)(int64_t)(ctx.lastOutputs[i].rectInOriginFrame.userData)); pbFaceListImage.set_size(ctx.lastOutputs[i].croppedDataSize); pbFaceListImage.set_type(PbFaceList_FaceListImage_ImageType_MBFT_NV12); pbFaceListImage.set_width(ctx.lastOutputs[i].rectInOriginFrame.rect.width()); pbFaceListImage.set_height(ctx.lastOutputs[i].rectInOriginFrame.rect.height()); pbFaceListImage.set_top_left_x(ctx.lastOutputs[i].rectInOriginFrame.rect.leftTop.X); pbFaceListImage.set_top_left_y(ctx.lastOutputs[i].rectInOriginFrame.rect.leftTop.Y); pbFaceListImage.add_img(ctx.lastOutputs[i].croppedData, ctx.lastOutputs[i].croppedDataSize); //LOGP(ERROR, "bg output=%f", ctx.lastOutputs[i].score); //{ // static size_t f = 0; // char fname[50]; // sprintf(fname, "/sdcard/face-%u-w%u-h%u.yuv420", ++f, ctx.lastOutputs[i].rectInOriginFrame.width(), ctx.lastOutputs[i].rectInOriginFrame.height()); // FILE *pFile = fopen(fname, "wb"); // fwrite(ctx.lastOutputs[i].croppedData, 1, ctx.lastOutputs[i].croppedDataSize, pFile); // fclose(pFile); // if (f > 10)exit(0); //} } size_t s = pbFaceList.ByteSize(); buffMaxSize = std::min(s, buffMaxSize); pbFaceList.SerializeToArray(buffer, buffMaxSize); return buffMaxSize > 0; } bool FaceCacheForPLBG::getFaceListImage(std::vector& imgIdxes, uint8_t* buffImg, size_t& buffImgMaxSize) { FcPmBreackerContextPLBG& ctx(*(FcPmBreackerContextPLBG*)_ctx); if (ctx.frameTruncated) { LOG_WARN << "ctx buffer truncated" << LOG_ENDL; return false; } if (buffImgMaxSize < ctx.frameRGBSize) { LOG_WARN << "buffImg truncated" << LOG_ENDL; return false; } imgIdxes.clear(); size_t totalSize = 0; for (int i = 0; i < ctx.lastOutputs.size(); i++) { NativeImgIdx imgidx; imgidx.st_track_id = (int)(int64_t)(ctx.lastOutputs[i].rectInOriginFrame.userData); imgidx.offset = ctx.lastOutputsRGBBufs[i].buffer - ctx.frameRGB; imgidx.size = ctx.lastOutputsRGBBufs[i].buffSize; imgidx.type = MB_Frame::MBFT_RGB565; imgidx.width = ctx.lastOutputs[i].rectInOriginFrame.rect.width(); imgidx.height = ctx.lastOutputs[i].rectInOriginFrame.rect.height(); imgIdxes.push_back(imgidx); totalSize += ctx.lastOutputsRGBBufs[i].buffSize; } memcpy(buffImg, ctx.frameRGB, totalSize); buffImgMaxSize = totalSize; return true; }