From a88698ced8bcd58f0f1918b10380bc66b0bfcbbc Mon Sep 17 00:00:00 2001 From: houxiao <houxiao@454eff88-639b-444f-9e54-f578c98de674> Date: 星期五, 30 十二月 2016 18:32:15 +0800 Subject: [PATCH] add pl_scale pl_fork --- RtspFace/PL_SensetimeFaceFeatureEmit.h | 6 RtspFace/PL_Scale.cpp | 240 +++++++++++++ RtspFace/PL_SensetimeFaceTrack.cpp | 241 +++++++++++++ RtspFace/main.cpp | 48 ++ RtspFace/PL_SensetimeFaceDetect.h | 31 - RtspFace/PL_SensetimeFaceDetect.cpp | 230 ------------ RtspFace/PipeLine.cpp | 12 RtspFace/PL_Fork.h | 24 + RtspFace/make.sh | 8 RtspFace/PL_SensetimeFaceTrack.h | 39 ++ RtspFace/PL_Scale.h | 41 ++ RtspFace/PL_Paint.h | 24 + RtspFace/PL_Fork.cpp | 49 ++ RtspFace/PL_H264Encoder.cpp | 21 RtspFace/logger.h | 17 15 files changed, 743 insertions(+), 288 deletions(-) diff --git a/RtspFace/PL_Fork.cpp b/RtspFace/PL_Fork.cpp new file mode 100644 index 0000000..9bf79c3 --- /dev/null +++ b/RtspFace/PL_Fork.cpp @@ -0,0 +1,49 @@ +#ifndef _PL_FORK_H_ +#define _PL_FORK_H_ + +#include "PipeLine.h" + +struct PL_Fork_Config +{ + +}; + +class PL_Fork : public PipeLineElem +{ +public: + enum ForkBy + { + FB_NONE, + FB_TURNS, + FB_RANDOM, + FB_PM_TYPE, + FB_MB_TYPE, + FB_BREAK_LIST + }; + + enum ForkSync + { + FS_NONE, + FS_SEQUENCE, + FS_PARALLEL, + FS_MAIN_PL_FIRST, + FS_MAIN_PL_LAST, + }; + +public: + PL_Fork(); + virtual ~PL_Fork(); + + virtual bool init(void* args); + virtual void finit(); + + virtual bool pay(const PipeMaterial& pm); + virtual bool gain(PipeMaterial& pm); + +private: + void* internal; +}; + +PipeLineElem* create_PL_Paint(); + +#endif diff --git a/RtspFace/PL_Fork.h b/RtspFace/PL_Fork.h new file mode 100644 index 0000000..865044e --- /dev/null +++ b/RtspFace/PL_Fork.h @@ -0,0 +1,24 @@ +#ifndef _PL_FORK_H_ +#define _PL_FORK_H_ + +#include "PipeLine.h" + +class PL_Fork : public PipeLineElem +{ +public: + PL_Fork(); + virtual ~PL_Fork(); + + virtual bool init(void* args); + virtual void finit(); + + virtual bool pay(const PipeMaterial& pm); + virtual bool gain(PipeMaterial& pm); + +private: + void* internal; +}; + +PipeLineElem* create_PL_Paint(); + +#endif diff --git a/RtspFace/PL_H264Encoder.cpp b/RtspFace/PL_H264Encoder.cpp index 1b3123a..a4d3089 100644 --- a/RtspFace/PL_H264Encoder.cpp +++ b/RtspFace/PL_H264Encoder.cpp @@ -9,9 +9,9 @@ #include <libavutil/imgutils.h> #include <libavutil/opt.h> #include <libavformat/avformat.h> - - #include <libyuv.h> } + +#include <libyuv.h> PL_H264Encoder_Config::PL_H264Encoder_Config() : inBufferSize(2*1024*1024), // 2MByte @@ -47,6 +47,8 @@ ~H264Encoder_Internal() { + delete[] buffer; + buffer = nullptr; } void reset() @@ -67,8 +69,10 @@ pAVFormatContext = nullptr; if (buffer != nullptr) + { delete[] buffer; - buffer = new uint8_t[config.inBufferSize]; + buffer = nullptr; + } } }; @@ -97,6 +101,8 @@ PL_H264Encoder_Config* config = (PL_H264Encoder_Config*)args; in->config = *config; } + + in->buffer = new uint8_t[in->config.inBufferSize]; return true; } @@ -235,7 +241,7 @@ { in->frameCount++; LOGP(DEBUG, "Succeed to encode (1) frame=%d, size=%d", in->frameCount, pAVPacket.size); - memcpy(in->buffer, pAVPacket.data, pAVPacket.size); + memcpy(in->buffer, pAVPacket.data, pAVPacket.size);//#todo check inBufferSize in->buffSize = pAVPacket.size; av_free_packet(&pAVPacket); } @@ -361,8 +367,11 @@ in->lastFrame.buffSize = in->buffSize; in->lastFrame.width = frame->width; in->lastFrame.height = frame->height; - in->lastFrame.pts = frame->pts; - //#todo resetPts + + if (in->config.resetPTS) + gettimeofday(&(in->lastFrame.pts),NULL); + else + in->lastFrame.pts = frame->pts; } return ret; diff --git a/RtspFace/PL_Paint.h b/RtspFace/PL_Paint.h new file mode 100644 index 0000000..9421a02 --- /dev/null +++ b/RtspFace/PL_Paint.h @@ -0,0 +1,24 @@ +#ifndef _PL_PAINT_H_ +#define _PL_PAINT_H_ + +#include "PipeLine.h" + +class PL_Paint : public PipeLineElem +{ +public: + PL_Paint(); + virtual ~PL_Paint(); + + virtual bool init(void* args); + virtual void finit(); + + virtual bool pay(const PipeMaterial& pm); + virtual bool gain(PipeMaterial& pm); + +private: + void* internal; +}; + +PipeLineElem* create_PL_Paint(); + +#endif diff --git a/RtspFace/PL_Scale.cpp b/RtspFace/PL_Scale.cpp new file mode 100644 index 0000000..bd6c507 --- /dev/null +++ b/RtspFace/PL_Scale.cpp @@ -0,0 +1,240 @@ +#include "PL_Scale.h" +#include "MaterialBuffer.h" +#include "logger.h" + +#include <libyuv.h> + +struct PL_Scale_Internal +{ + uint8_t* buffer; + size_t buffSize; + size_t buffSizeMax; + bool payError; + + PipeMaterial::PipeMaterialBufferType lastPmType; + MB_Frame lastFrame; + PL_Scale_Config config; + + PL_Scale_Internal() : + buffer(nullptr), buffSize(0), buffSizeMax(0), payError(true), + lastPmType(PipeMaterial::PMT_NONE), lastFrame(), config() + { + } + + ~PL_Scale_Internal() + { + delete[] buffer; + buffer = nullptr; + } + + void reset() + { + buffSize = 0; + payError = true; + + lastPmType = PipeMaterial::PMT_NONE; + + MB_Frame _lastFrame; + lastFrame = _lastFrame; + + PL_Scale_Config _config; + config = _config; + + if (buffer != nullptr) + { + delete[] buffer; + buffer = nullptr; + buffSizeMax = 0; + } + } +}; + +PipeLineElem* create_PL_Scale() +{ + return new PL_Scale; +} + +PL_Scale::PL_Scale() : internal(new PL_Scale_Internal) +{ +} + +PL_Scale::~PL_Scale() +{ + delete (PL_Scale_Internal*)internal; + internal= nullptr; +} + +bool PL_Scale::init(void* args) +{ + PL_Scale_Internal* in = (PL_Scale_Internal*)internal; + in->reset(); + + if (args != nullptr) + { + PL_Scale_Config* config = (PL_Scale_Config*)args; + in->config = *config; + } + + if (in->config.toWidth <= 0 || in->config.toHeight <= 0) + { + LOG_ERROR << "Config toWidth and toHeight should > 0"; + return false; + } + + return true; +} + +void PL_Scale::finit() +{ + PL_Scale_Internal* in = (PL_Scale_Internal*)internal; + +} + +bool image_scale(PL_Scale_Internal* in, + uint8_t* srcBuffer, int srcBuffSize, MB_Frame::MBFType srcType, uint16_t srcWidth, uint16_t srcHeight) +{ +#define SUBSAMPLE(v, a) ((((v) + (a) - 1)) / (a)) + + const int dst_width = in->config.toWidth; + const int dst_height = in->config.toHeight; + + size_t dstSizeMax = 0; + if (srcType == MB_Frame::MBFT_YUV420) + dstSizeMax = in->config.toWidth * in->config.toHeight * 1.5; + else if (srcType == MB_Frame::MBFT_BGRA) + dstSizeMax = in->config.toWidth * in->config.toHeight * 4; + else + { + LOG_ERROR << "srcType only support MBFT_YUV420 and MBFT_BGRA"; + return false; + } + + if (in->buffer == nullptr || in->buffSizeMax < dstSizeMax) + { + if (in->buffer != nullptr) + delete[] in->buffer; + in->buffer = new uint8_t[dstSizeMax]; + in->buffSizeMax = dstSizeMax; + LOG_INFO << "image_scale alloc buffer size=" << dstSizeMax; + } + + if (srcType == MB_Frame::MBFT_YUV420) + { + uint8_t* src_y = srcBuffer; + uint8_t* src_u = src_y + srcWidth * srcHeight; + uint8_t* src_v = src_u + srcWidth * srcHeight / 4; + uint8_t* dst_y = in->buffer; + uint8_t* dst_u = dst_y + dst_width * dst_height; + uint8_t* dst_v = dst_u + dst_width * dst_height / 4; + + libyuv::I420Scale( + src_y, srcWidth, + src_u, SUBSAMPLE(srcWidth, 2), + src_v, SUBSAMPLE(srcWidth, 2), + srcWidth, srcHeight, + dst_y, dst_width, + dst_u, SUBSAMPLE(dst_width, 2), + dst_v, SUBSAMPLE(dst_width, 2), + dst_width, dst_height, + (libyuv::FilterMode)(in->config.filterMode)); + + in->buffSize = dstSizeMax; + } + else if (srcType == MB_Frame::MBFT_BGRA) + { + //#todo + LOG_ERROR << "srcType only support MBFT_YUV420 and MBFT_BGRA"; + return false; + } +} + +bool PL_Scale::pay(const PipeMaterial& pm) +{ + PL_Scale_Internal* in = (PL_Scale_Internal*)internal; + + in->payError = true; + + if (pm.buffer == nullptr) + return false; + + bool ret = false; + + in->lastPmType = pm.type; + + switch(pm.type) + { + case PipeMaterial::PMT_BYTES: + { + if (in->config.defaultBytesType <= 0 || + in->config.defaultBytesWidth <= 0 || in->config.defaultBytesHeight <= 0) + { + LOG_ERROR << "defaultBytesType/defaultBytesWidth/defaultBytesHeight not set"; + return false; + } + + ret = image_scale(in, (uint8_t*)pm.buffer, pm.buffSize, (MB_Frame::MBFType)(in->config.defaultBytesType), + in->config.defaultBytesWidth, in->config.defaultBytesHeight); + } + break; + case PipeMaterial::PMT_FRAME: + { + MB_Frame* frame = (MB_Frame*)pm.buffer; + switch(frame->type) + { + case MB_Frame::MBFT_YUV420: + case MB_Frame::MBFT_BGRA: + in->lastFrame = *frame; + ret = image_scale(in, (uint8_t*)frame->buffer, frame->buffSize, frame->type, + frame->width, frame->height); + break; + default: + LOG_ERROR << "Only support MBFT_YUV420 / MBFT_BGRA"; + return false; + } + } + break; + default: + LOG_ERROR << "Only support PMT_BYTES / PMT_FRAME"; + return false; + } + + in->payError = !ret; + return ret; +} + +bool PL_Scale::gain(PipeMaterial& pm) +{ + PL_Scale_Internal* in = (PL_Scale_Internal*)internal; + + PipeMaterial newPm; + newPm.type = PipeMaterial::PMT_NONE; + newPm.former = this; + + switch(in->lastPmType) + { + case PipeMaterial::PMT_BYTES: + { + newPm.type = PipeMaterial::PMT_BYTES; + newPm.buffer = in->buffer; + newPm.buffSize = in->buffSize; + } + break; + case PipeMaterial::PMT_FRAME: + { + newPm.type = PipeMaterial::PMT_FRAME; + newPm.buffer = &(in->lastFrame); + newPm.buffSize = 0; + + in->lastFrame.buffer = in->buffer; + in->lastFrame.buffSize = in->buffSize; + in->lastFrame.width = in->config.toWidth; + in->lastFrame.height = in->config.toHeight; + } + break; + default: + LOG_ERROR << "Only support PMT_BYTES / PMT_FRAME"; + } + + pm = newPm; + return !in->payError; +} diff --git a/RtspFace/PL_Scale.h b/RtspFace/PL_Scale.h new file mode 100644 index 0000000..76e00b5 --- /dev/null +++ b/RtspFace/PL_Scale.h @@ -0,0 +1,41 @@ +#ifndef _PL_SCALE_H_ +#define _PL_SCALE_H_ + +#include "PipeLine.h" + +struct PL_Scale_Config +{ + uint16_t toWidth; + uint16_t toHeight; + int filterMode; // libyuv/scale.h/FilterMode + + // Used only pm.type==PMT_BYTES + int defaultBytesType; // MBFT_YUV420 / MBFT_BGRA + uint16_t defaultBytesWidth; + uint16_t defaultBytesHeight; + + PL_Scale_Config() : + toWidth(0), toHeight(0), filterMode(0), + defaultBytesType(0), defaultBytesWidth(0), defaultBytesHeight(0) + { } +}; + +class PL_Scale : public PipeLineElem +{ +public: + PL_Scale(); + virtual ~PL_Scale(); + + virtual bool init(void* args); + virtual void finit(); + + virtual bool pay(const PipeMaterial& pm); + virtual bool gain(PipeMaterial& pm); + +private: + void* internal; +}; + +PipeLineElem* create_PL_Scale(); + +#endif diff --git a/RtspFace/PL_SensetimeFaceDetect.cpp b/RtspFace/PL_SensetimeFaceDetect.cpp index 435bea3..cc04c79 100644 --- a/RtspFace/PL_SensetimeFaceDetect.cpp +++ b/RtspFace/PL_SensetimeFaceDetect.cpp @@ -1,231 +1 @@ #include "PL_SensetimeFaceDetect.h" -#include "MaterialBuffer.h" -#include "logger.h" - -#include <opencv2/opencv.hpp> -#include <cv_face.h> - -struct PL_SensetimeFaceDetect_Internal -{ - //uint8_t buffer[1920*1080*4]; - //size_t buffSize; - //size_t buffSizeMax; - MB_Frame lastFrame; - SensetimeFaceDetectConfig config; - - bool payError; - - cv_handle_t handle_track; - - PL_SensetimeFaceDetect_Internal() : - //buffSize(0), buffSizeMax(sizeof(buffer)), - lastFrame(), config(), payError(true), - handle_track(nullptr) - { - } - - ~PL_SensetimeFaceDetect_Internal() - { - } - - void reset() - { - //buffSize = 0; - payError = true; - - MB_Frame _lastFrame; - lastFrame = _lastFrame; - SensetimeFaceDetectConfig _config; - config = _config; - - handle_track = nullptr; - } -}; - -PipeLineElem* create_PL_SensetimeFaceDetect() -{ - return new PL_SensetimeFaceDetect; -} - -PL_SensetimeFaceDetect::PL_SensetimeFaceDetect() : internal(new PL_SensetimeFaceDetect_Internal) -{ -} - -PL_SensetimeFaceDetect::~PL_SensetimeFaceDetect() -{ - delete (PL_SensetimeFaceDetect_Internal*)internal; - internal= nullptr; -} - -bool PL_SensetimeFaceDetect::init(void* args) -{ - PL_SensetimeFaceDetect_Internal* in = (PL_SensetimeFaceDetect_Internal*)internal; - in->reset(); - - SensetimeFaceDetectConfig* config = (SensetimeFaceDetectConfig*)args; - in->config = *config; - if (in->config.point_size == 21) - in->config.point_size_config = CV_DETECT_ENABLE_ALIGN_21; - else if (in->config.point_size == 106) - in->config.point_size_config = CV_DETECT_ENABLE_ALIGN_106; - else - { - LOG_ERROR << "alignment point size must be 21 or 106"; - return false; - } - - // init handle - cv_result_t cv_result = cv_face_create_tracker(&(in->handle_track), nullptr, - in->config.point_size_config | CV_FACE_TRACKING_TWO_THREAD); - if (cv_result != CV_OK) - { - LOG_ERROR << "cv_face_create_tracker failed, error code" << cv_result; - return false; - } - - int val = 0; - cv_result = cv_face_track_set_detect_face_cnt_limit(in->handle_track, in->config.detect_face_cnt_limit, &val); - if (cv_result != CV_OK) - { - LOG_ERROR << "cv_face_track_set_detect_face_cnt_limit failed, error : " << cv_result; - return false; - } - else - LOG_ERROR << "detect face count limit : " << val; - - return true; -} - -void PL_SensetimeFaceDetect::finit() -{ - PL_SensetimeFaceDetect_Internal* in = (PL_SensetimeFaceDetect_Internal*)internal; - - // destroy track handle - cv_face_destroy_tracker(in->handle_track); - in->handle_track = nullptr; -} - -int doFaceDetect(PL_SensetimeFaceDetect_Internal* in, - uint8_t* buffer, size_t width, size_t height, size_t stride, cv_pixel_format cvPixFmt) -{ - //resize(bgr_frame, bgr_frame, Size(frame_width, frame_height), 0, 0, INTER_LINEAR); - - int face_count = 0; - cv_result_t cv_result = CV_OK; - cv_face_t* p_face = nullptr; - - // realtime track - cv_result = cv_face_track(in->handle_track, buffer, cvPixFmt, - width, height, stride, - CV_FACE_UP, &p_face, &face_count); - if (cv_result != CV_OK) - { - LOG_ERROR << "cv_face_track failed, error : " << cv_result; - cv_face_release_tracker_result(p_face, face_count); - return -1; - } - - // draw the video - cv::Mat yuvMat(cv::Size(1920,1080), CV_8UC3, buffer);//#todo - cv::Mat yMat(cv::Size(1920,1080), CV_8UC1, buffer); - for (int i = 0; i < face_count; i++) - { - LOGP(DEBUG, "face: %d-----[%d, %d, %d, %d]-----id: %d", i, - p_face[i].rect.left, p_face[i].rect.top, - p_face[i].rect.right, p_face[i].rect.bottom, p_face[i].ID); - - LOGP(DEBUG, "face pose: [yaw: %.2f, pitch: %.2f, roll: %.2f, eye distance: %.2f]", - p_face[i].yaw, - p_face[i].pitch, p_face[i].roll, p_face[i].eye_dist); - - cv::Scalar scalar_color = CV_RGB(p_face[i].ID * 53 % 256, - p_face[i].ID * 93 % 256, - p_face[i].ID * 143 % 256); - - //cv::rectangle(yMat, cv::Point2f(0, 0), cv::Point2f(50, 50), scalar_color, 2); - //cv::rectangle(yMat, cv::Point2f(500, 500), cv::Point2f(550, 550), scalar_color, 2); - - cv::rectangle(yMat, cv::Point2f(static_cast<float>(p_face[i].rect.left), - static_cast<float>(p_face[i].rect.top)), - cv::Point2f(static_cast<float>(p_face[i].rect.right), - static_cast<float>(p_face[i].rect.bottom)), scalar_color, 2); - - for (int j = 0; j < p_face[i].points_count; j++) - { - cv::circle(yMat, cv::Point2f(p_face[i].points_array[j].x, - p_face[i].points_array[j].y), 1, cv::Scalar(255, 255, 255)); - } - } - - //if (face_count > 0) - //{ - // static size_t f=0; - // char fname[50]; - // sprintf(fname, "face-%u.yuv420", ++f); - // FILE * pFile = fopen (fname,"wb"); - // fwrite (yuvMat.data , sizeof(char), 1920*1080*1.5, pFile); - // printf("write face file %s\n", fname); - // fclose(pFile); - //} - - // release the memory of face - cv_face_release_tracker_result(p_face, face_count); - - return face_count; -} - -bool PL_SensetimeFaceDetect::pay(const PipeMaterial& pm) -{ - PL_SensetimeFaceDetect_Internal* in = (PL_SensetimeFaceDetect_Internal*)internal; - - if (pm.type != PipeMaterial::PMT_FRAME) - { - LOG_ERROR << "PL_H264Encoder::pay only support PMT_FRAME"; - return false; - } - - if (pm.buffer == nullptr) - return false; - - MB_Frame* frame = (MB_Frame*)pm.buffer; - if (frame->type != MB_Frame::MBFT_YUV420) - { - LOG_ERROR << "PL_H264Encoder::pay only support MBFT_YUV420"; - return false; - } - - int face_count = doFaceDetect(in, (uint8_t*)frame->buffer, 1920, 1080, 1920, CV_PIX_FMT_YUV420P);//#todo - if (face_count < 0) - { - in->payError = true; - return false; - } - else - in->payError = false; - - //in->buffer readly - - in->lastFrame.type = MB_Frame::MBFT_YUV420; - in->lastFrame.buffer = frame->buffer;//#todo should copy - in->lastFrame.buffSize = frame->buffSize; - in->lastFrame.width = frame->width; - in->lastFrame.height = frame->height; - in->lastFrame.pts = frame->pts; - - return true; -} - -bool PL_SensetimeFaceDetect::gain(PipeMaterial& pm) -{ - PL_SensetimeFaceDetect_Internal* in = (PL_SensetimeFaceDetect_Internal*)internal; - - if (!in->payError) - { - pm.type = PipeMaterial::PMT_FRAME; - pm.buffer = &(in->lastFrame); - pm.buffSize = 0; - pm.former = this; - } - pm.former = this; - return !in->payError; -} diff --git a/RtspFace/PL_SensetimeFaceDetect.h b/RtspFace/PL_SensetimeFaceDetect.h index 0d876c0..19d48c4 100644 --- a/RtspFace/PL_SensetimeFaceDetect.h +++ b/RtspFace/PL_SensetimeFaceDetect.h @@ -1,35 +1,4 @@ #ifndef _PL_PL_SENSETIMEFACEDETECT_H_ #define _PL_PL_SENSETIMEFACEDETECT_H_ -#include "PipeLine.h" - -struct SensetimeFaceDetectConfig -{ - int point_size; // 21 / 106 - int point_size_config; // CV_DETECT_ENABLE_ALIGN_21 / CV_DETECT_ENABLE_ALIGN_106 - int detect_face_cnt_limit; // -1 - - SensetimeFaceDetectConfig() : - point_size(21), point_size_config(-1), detect_face_cnt_limit(-1) - { } -}; - -class PL_SensetimeFaceDetect : public PipeLineElem -{ -public: - PL_SensetimeFaceDetect(); - virtual ~PL_SensetimeFaceDetect(); - - virtual bool init(void* args); - virtual void finit(); - - virtual bool pay(const PipeMaterial& pm); - virtual bool gain(PipeMaterial& pm); - -private: - void* internal; -}; - -PipeLineElem* create_PL_SensetimeFaceDetect(); - #endif diff --git a/RtspFace/PL_SensetimeFaceFeatureEmit.h b/RtspFace/PL_SensetimeFaceFeatureEmit.h new file mode 100644 index 0000000..c312a0c --- /dev/null +++ b/RtspFace/PL_SensetimeFaceFeatureEmit.h @@ -0,0 +1,6 @@ +#ifndef _PL_SENSETIMEFACEFEATUREEMIT_H_ +#define _PL_SENSETIMEFACEFEATUREEMIT_H_ + +#include "PipeLine.h" + +#endif diff --git a/RtspFace/PL_SensetimeFaceTrack.cpp b/RtspFace/PL_SensetimeFaceTrack.cpp new file mode 100644 index 0000000..71cb4d3 --- /dev/null +++ b/RtspFace/PL_SensetimeFaceTrack.cpp @@ -0,0 +1,241 @@ +#include "PL_SensetimeFaceTrack.h" +#include "MaterialBuffer.h" +#include "logger.h" + +#include <opencv2/opencv.hpp> +#include <cv_face.h> + +struct PL_SensetimeFaceTrack_Internal +{ + //uint8_t buffer[1920*1080*4]; + //size_t buffSize; + //size_t buffSizeMax; + MB_Frame lastFrame; + SensetimeFaceTrackConfig config; + + bool payError; + + cv_handle_t handle_track; + + PL_SensetimeFaceTrack_Internal() : + //buffSize(0), buffSizeMax(sizeof(buffer)), + lastFrame(), config(), payError(true), + handle_track(nullptr) + { + } + + ~PL_SensetimeFaceTrack_Internal() + { + } + + void reset() + { + //buffSize = 0; + payError = true; + + MB_Frame _lastFrame; + lastFrame = _lastFrame; + SensetimeFaceTrackConfig _config; + config = _config; + + handle_track = nullptr; + } +}; + +PipeLineElem* create_PL_SensetimeFaceTrack() +{ + return new PL_SensetimeFaceTrack; +} + +PL_SensetimeFaceTrack::PL_SensetimeFaceTrack() : internal(new PL_SensetimeFaceTrack_Internal) +{ +} + +PL_SensetimeFaceTrack::~PL_SensetimeFaceTrack() +{ + delete (PL_SensetimeFaceTrack_Internal*)internal; + internal= nullptr; +} + +bool PL_SensetimeFaceTrack::init(void* args) +{ + PL_SensetimeFaceTrack_Internal* in = (PL_SensetimeFaceTrack_Internal*)internal; + in->reset(); + + SensetimeFaceTrackConfig* config = (SensetimeFaceTrackConfig*)args; + in->config = *config; + if (in->config.point_size == 21) + in->config.point_size_config = CV_DETECT_ENABLE_ALIGN_21; + else if (in->config.point_size == 106) + in->config.point_size_config = CV_DETECT_ENABLE_ALIGN_106; + else + { + LOG_ERROR << "alignment point size must be 21 or 106"; + return false; + } + + // init handle + cv_result_t cv_result = cv_face_create_tracker(&(in->handle_track), nullptr, + in->config.point_size_config | CV_FACE_TRACKING_TWO_THREAD); + if (cv_result != CV_OK) + { + LOG_ERROR << "cv_face_create_tracker failed, error code" << cv_result; + return false; + } + + int val = 0; + cv_result = cv_face_track_set_detect_face_cnt_limit(in->handle_track, in->config.detect_face_cnt_limit, &val); + if (cv_result != CV_OK) + { + LOG_ERROR << "cv_face_track_set_detect_face_cnt_limit failed, error : " << cv_result; + return false; + } + else + LOG_ERROR << "detect face count limit : " << val; + + return true; +} + +void PL_SensetimeFaceTrack::finit() +{ + PL_SensetimeFaceTrack_Internal* in = (PL_SensetimeFaceTrack_Internal*)internal; + + // destroy track handle + cv_face_destroy_tracker(in->handle_track); + in->handle_track = nullptr; +} + +int doFaceTrack(PL_SensetimeFaceTrack_Internal* in, + uint8_t* buffer, size_t width, size_t height, size_t stride, cv_pixel_format cvPixFmt) +{ + //resize(bgr_frame, bgr_frame, Size(frame_width, frame_height), 0, 0, INTER_LINEAR); + + int face_count = 0; + cv_result_t cv_result = CV_OK; + cv_face_t* p_face = nullptr; + + // realtime track + cv_result = cv_face_track(in->handle_track, buffer, cvPixFmt, + width, height, stride, + CV_FACE_UP, &p_face, &face_count); + if (cv_result != CV_OK) + { + LOG_ERROR << "cv_face_track failed, error : " << cv_result; + cv_face_release_tracker_result(p_face, face_count); + return -1; + } + + // draw the video + //cv::Mat yuvMat(cv::Size(width,height), CV_8UC3, buffer); + cv::Mat yMat(cv::Size(width,height), CV_8UC1, buffer); + for (int i = 0; i < face_count; i++) + { + LOGP(DEBUG, "face: %d-----[%d, %d, %d, %d]-----id: %d", i, + p_face[i].rect.left, p_face[i].rect.top, + p_face[i].rect.right, p_face[i].rect.bottom, p_face[i].ID); + + LOGP(DEBUG, "face pose: [yaw: %.2f, pitch: %.2f, roll: %.2f, eye distance: %.2f]", + p_face[i].yaw, + p_face[i].pitch, p_face[i].roll, p_face[i].eye_dist); + + if (in->config.draw_face_rect) + { + cv::Scalar scalar_color = CV_RGB(p_face[i].ID * 53 % 256, + p_face[i].ID * 93 % 256, + p_face[i].ID * 143 % 256); + + //cv::rectangle(yMat, cv::Point2f(0, 0), cv::Point2f(50, 50), scalar_color, 2); + //cv::rectangle(yMat, cv::Point2f(500, 500), cv::Point2f(550, 550), scalar_color, 2); + + cv::rectangle(yMat, cv::Point2f(static_cast<float>(p_face[i].rect.left), + static_cast<float>(p_face[i].rect.top)), + cv::Point2f(static_cast<float>(p_face[i].rect.right), + static_cast<float>(p_face[i].rect.bottom)), scalar_color, 2); + } + + + for (int j = 0; j < p_face[i].points_count; j++) + { + + + if (in->config.draw_face_feature_point) + { + cv::circle(yMat, cv::Point2f(p_face[i].points_array[j].x, + p_face[i].points_array[j].y), 1, cv::Scalar(255, 255, 255)); + } + } + } + + //if (face_count > 0) + //{ + // static size_t f=0; + // char fname[50]; + // sprintf(fname, "face-%u.yuv420", ++f); + // FILE * pFile = fopen (fname,"wb"); + // fwrite (yuvMat.data , sizeof(char), 1920*1080*1.5, pFile); + // printf("write face file %s\n", fname); + // fclose(pFile); + //} + + // release the memory of face + cv_face_release_tracker_result(p_face, face_count); + + return face_count; +} + +bool PL_SensetimeFaceTrack::pay(const PipeMaterial& pm) +{ + PL_SensetimeFaceTrack_Internal* in = (PL_SensetimeFaceTrack_Internal*)internal; + + if (pm.type != PipeMaterial::PMT_FRAME) + { + LOG_ERROR << "PL_H264Encoder::pay only support PMT_FRAME"; + return false; + } + + if (pm.buffer == nullptr) + return false; + + MB_Frame* frame = (MB_Frame*)pm.buffer; + if (frame->type != MB_Frame::MBFT_YUV420) + { + LOG_ERROR << "PL_H264Encoder::pay only support MBFT_YUV420"; + return false; + } + + int face_count = doFaceTrack( + in, (uint8_t*)frame->buffer, frame->width, frame->height, frame->width, CV_PIX_FMT_YUV420P); + if (face_count < 0) + { + in->payError = true; + return false; + } + else + in->payError = false; + + //in->buffer readly + + in->lastFrame.type = MB_Frame::MBFT_YUV420; + in->lastFrame.buffer = frame->buffer;//#todo should copy + in->lastFrame.buffSize = frame->buffSize; + in->lastFrame.width = frame->width; + in->lastFrame.height = frame->height; + in->lastFrame.pts = frame->pts; + + return true; +} + +bool PL_SensetimeFaceTrack::gain(PipeMaterial& pm) +{ + PL_SensetimeFaceTrack_Internal* in = (PL_SensetimeFaceTrack_Internal*)internal; + + if (!in->payError) + { + pm.type = PipeMaterial::PMT_FRAME; + pm.buffer = &(in->lastFrame); + pm.buffSize = 0; + pm.former = this; + } + pm.former = this; + return !in->payError; +} diff --git a/RtspFace/PL_SensetimeFaceTrack.h b/RtspFace/PL_SensetimeFaceTrack.h new file mode 100644 index 0000000..8ce9f5c --- /dev/null +++ b/RtspFace/PL_SensetimeFaceTrack.h @@ -0,0 +1,39 @@ +#ifndef _PL_PL_SENSETIMEFACETRACK_H_ +#define _PL_PL_SENSETIMEFACETRACK_H_ + +#include "PipeLine.h" + +struct SensetimeFaceTrackConfig +{ + int point_size; // 21 / 106 + int point_size_config; // CV_DETECT_ENABLE_ALIGN_21 / CV_DETECT_ENABLE_ALIGN_106 + int detect_face_cnt_limit; // -1 + bool draw_face_rect; + bool draw_face_feature_point; + bool generate_face_feature; // for PL_SensetimeFaceFeatureEmit + + SensetimeFaceTrackConfig() : + point_size(21), point_size_config(-1), detect_face_cnt_limit(-1), + draw_face_rect(true), draw_face_feature_point(true), generate_face_feature(false) + { } +}; + +class PL_SensetimeFaceTrack : public PipeLineElem +{ +public: + PL_SensetimeFaceTrack(); + virtual ~PL_SensetimeFaceTrack(); + + virtual bool init(void* args); + virtual void finit(); + + virtual bool pay(const PipeMaterial& pm); + virtual bool gain(PipeMaterial& pm); + +private: + void* internal; +}; + +PipeLineElem* create_PL_SensetimeFaceDetect(); + +#endif diff --git a/RtspFace/PipeLine.cpp b/RtspFace/PipeLine.cpp index 3547d94..1f3aba9 100644 --- a/RtspFace/PipeLine.cpp +++ b/RtspFace/PipeLine.cpp @@ -90,16 +90,16 @@ PipeDebugger(PipeLine* _pipeLine) : pipeLine(_pipeLine), retElem(nullptr), pm(nullptr) { - LOG_DEBUG << "pipe line begin"; + //LOG_DEBUG << "pipe line begin"; } ~PipeDebugger() { - bool retOK = (*(pipeLine->elems).rbegin() == retElem); - if (retOK) - LOG_DEBUG << "pipe line end, ret OK"; - else - LOG_WARN << "pipe line end, ret ERROR"; + //bool retOK = (*(pipeLine->elems).rbegin() == retElem); + //if (retOK) + // LOG_DEBUG << "pipe line end, ret OK"; + //else + // LOG_WARN << "pipe line end, ret ERROR"; } }; diff --git a/RtspFace/logger.h b/RtspFace/logger.h index 5d7b344..b0b0ffa 100644 --- a/RtspFace/logger.h +++ b/RtspFace/logger.h @@ -16,6 +16,14 @@ #include "log4cpp/FileAppender.hh" #include "log4cpp/PatternLayout.hh" +enum LoggerVerbose +{ + LV_ERROR, + LV_WARN, + LV_NOTICE, + LV_INFO, + LV_DEBUG +}; #define LOG(__level) log4cpp::Category::getRoot() << log4cpp::Priority::__level << __FILE__ << ":" << __LINE__ << "\t" #define LOGP(__level, __format, arg...) log4cpp::Category::getRoot().log(log4cpp::Priority::__level, "%s:%d\t" __format, __FILE__, __LINE__, ##arg); @@ -26,7 +34,7 @@ #define LOG_WARN LOG(WARN) // Important event or input which will lead to errors #define LOG_ERROR LOG(ERROR) // Error message means program running in an abnormal (not expected) way -inline void initLogger(int verbose) +inline void initLogger(LoggerVerbose verbose) { // initialize log4cpp log4cpp::Category &log = log4cpp::Category::getRoot(); @@ -43,8 +51,11 @@ } switch (verbose) { - case 2: log.setPriority(log4cpp::Priority::DEBUG); break; - case 1: log.setPriority(log4cpp::Priority::INFO); break; + case LV_DEBUG: log.setPriority(log4cpp::Priority::DEBUG); break; + case LV_INFO: log.setPriority(log4cpp::Priority::INFO); break; + case LV_NOTICE: log.setPriority(log4cpp::Priority::NOTICE); break; + case LV_WARN: log.setPriority(log4cpp::Priority::WARN); break; + case LV_ERROR: log.setPriority(log4cpp::Priority::ERROR); break; default: log.setPriority(log4cpp::Priority::NOTICE); break; } diff --git a/RtspFace/main.cpp b/RtspFace/main.cpp index 8b87ae0..412c1ac 100644 --- a/RtspFace/main.cpp +++ b/RtspFace/main.cpp @@ -6,14 +6,15 @@ #include "PL_AVFrameYUV420.h" #include "PL_AVFrameBGRA.h" #include "PL_Queue.h" +#include "PL_Scale.h" -#include "PL_SensetimeFaceDetect.h" +#include "PL_SensetimeFaceTrack.h" #include "logger.h" int main(int argc, char** argv) { - initLogger(2); + initLogger(LV_DEBUG); PipeLine pipeLine; @@ -23,8 +24,9 @@ pipeLine.register_elem_creator("PL_AVFrameYUV420", create_PL_AVFrameYUV420); pipeLine.register_elem_creator("PL_H264Encoder", create_PL_H264Encoder); pipeLine.register_elem_creator("PL_Queue", create_PL_Queue); + pipeLine.register_elem_creator("PL_Scale", create_PL_Scale); - pipeLine.register_elem_creator("PL_SensetimeFaceDetect", create_PL_SensetimeFaceDetect); + pipeLine.register_elem_creator("PL_SensetimeFaceTrack", create_PL_SensetimeFaceTrack); { PL_RTSPClient* rtspClient = (PL_RTSPClient*)pipeLine.push_elem("PL_RTSPClient"); @@ -45,18 +47,41 @@ { PL_H264Decoder* h264Decoder = (PL_H264Decoder*)pipeLine.push_elem("PL_H264Decoder"); - h264Decoder->init(nullptr); + bool ret = h264Decoder->init(nullptr); + if (!ret) + { + LOG_ERROR << "PL_H264Decoder.init error"; + exit(EXIT_FAILURE); + } } { PL_AVFrameYUV420* avFrameYUV420 = (PL_AVFrameYUV420*)pipeLine.push_elem("PL_AVFrameYUV420"); - avFrameYUV420->init(nullptr); + bool ret = avFrameYUV420->init(nullptr); + if (!ret) + { + LOG_ERROR << "PL_AVFrameYUV420.init error"; + exit(EXIT_FAILURE); + } + } + + { + PL_Scale_Config config; + config.toWidth = 800; + config.toHeight = 600; + PL_Scale* pl = (PL_Scale*)pipeLine.push_elem("PL_Scale"); + bool ret = pl->init(&config); + if (!ret) + { + LOG_ERROR << "PL_Scale.init error"; + exit(EXIT_FAILURE); + } } { - SensetimeFaceDetectConfig config; - PL_SensetimeFaceDetect* stFaceDetect = (PL_SensetimeFaceDetect*)pipeLine.push_elem("PL_SensetimeFaceDetect"); - stFaceDetect->init(&config); + SensetimeFaceTrackConfig config; + PL_SensetimeFaceTrack* pl = (PL_SensetimeFaceTrack*)pipeLine.push_elem("PL_SensetimeFaceTrack"); + pl->init(&config); } //{//#todo queue should support deep copy @@ -72,7 +97,12 @@ { PL_H264Encoder* h264Encoder = (PL_H264Encoder*)pipeLine.push_elem("PL_H264Encoder"); - h264Encoder->init(nullptr); + bool ret = h264Encoder->init(nullptr); + if (!ret) + { + LOG_ERROR << "PL_H264Encoder.init error"; + exit(EXIT_FAILURE); + } } { diff --git a/RtspFace/make.sh b/RtspFace/make.sh index 4a4892f..acdd829 100644 --- a/RtspFace/make.sh +++ b/RtspFace/make.sh @@ -51,7 +51,9 @@ g++ -g -c -std=c++11 PL_AVFrameYUV420.cpp $CFLAGS $CPPFLAGS g++ -g -c -std=c++11 PL_AVFrameBGRA.cpp $CFLAGS $CPPFLAGS g++ -g -c -std=c++11 PL_Queue.cpp $CFLAGS $CPPFLAGS -g++ -g -c -std=c++11 PL_SensetimeFaceDetect.cpp $CFLAGS $CPPFLAGS +g++ -g -c -std=c++11 PL_Scale.cpp $CFLAGS $CPPFLAGS + +g++ -g -c -std=c++11 PL_SensetimeFaceTrack.cpp $CFLAGS $CPPFLAGS g++ -g -c -std=c++11 $FFMPEGRTSPSERVER_BASE/FFmpegH264Source.cpp $CFLAGS $CPPFLAGS g++ -g -c -std=c++11 $FFMPEGRTSPSERVER_BASE/LiveRTSPServer.cpp $CFLAGS $CPPFLAGS @@ -59,8 +61,8 @@ g++ -g -std=c++11 \ main.o PipeLine.o \ - PL_RTSPClient.o PL_H264Decoder.o PL_H264Encoder.o PL_AVFrameYUV420.o PL_AVFrameBGRA.o PL_Queue.o \ - PL_SensetimeFaceDetect.o \ + PL_RTSPClient.o PL_H264Decoder.o PL_H264Encoder.o PL_AVFrameYUV420.o PL_AVFrameBGRA.o PL_Queue.o PL_Scale.o \ + PL_SensetimeFaceTrack.o \ $FFMPEGRTSPSERVER_OBJ PL_RTSPServer.o \ $LDFLAGS -o rtsp_face -- Gitblit v1.8.0