#include "PL_Paint.h"
|
#include "MaterialBuffer.h"
|
#include "logger.h"
|
#include "MediaHelper.h"
|
#include <string.h> // for memcpy
|
#include <opencv2/core/mat.hpp>
|
#include <opencv2/imgproc.hpp>
|
#ifdef ENABLE_WTEXT
|
#include "CvUtil/CvxText.h"
|
#endif
|
|
PLPLType::PLPLType(const char* _val_s)
|
{
|
for (int i = 0; i < sizeof(val_s); i++)
|
val_s[i] = _val_s[i];
|
}
|
|
PLPLType::PLPLType(const wchar_t* _val_s)
|
{
|
//wchar_t* w_val_s = (wchar_t*)val_s;
|
//for (int i = 0; i < sizeof(val_s) / sizeof(wchar_t); i++)
|
// w_val_s[i] = _val_s[i];
|
|
memcpy(val_s, _val_s, sizeof(val_s));
|
}
|
|
PLPLContext::~PLPLContext()
|
{
|
#ifdef ENABLE_WTEXT
|
delete (CvxText*)cvxText;
|
cvxText = nullptr;
|
#endif
|
}
|
|
void PLPLContext::clear()
|
{
|
cmds.clear();
|
params.clear();
|
}
|
|
struct PL_Paint_Internal
|
{
|
uint8_t* buffer;
|
size_t buffSize;
|
|
PL_Paint_Config config;
|
PipeMaterial pmList[2];
|
MB_Frame lastMbfBuffOrigin;
|
MB_Frame lastMbfBuffCopy;
|
|
bool payError;
|
|
PL_Paint_Internal() :
|
buffer(nullptr), buffSize(), config(), pmList(),
|
lastMbfBuffOrigin(), lastMbfBuffCopy(),
|
payError(true)
|
{
|
}
|
|
~PL_Paint_Internal()
|
{
|
reset();
|
}
|
|
void reset()
|
{
|
delete buffer;
|
buffer = nullptr;
|
buffSize = 0;
|
|
PL_Paint_Config _config;
|
config = _config;
|
|
PipeMaterial _pm;
|
pmList[0] = _pm;
|
pmList[1] = _pm;
|
|
MB_Frame _lastMbfBuff;
|
lastMbfBuffOrigin = _lastMbfBuff;
|
lastMbfBuffCopy = _lastMbfBuff;
|
|
payError = true;
|
|
}
|
};
|
|
PipeLineElem* create_PL_Paint()
|
{
|
return new PL_Paint;
|
}
|
|
PL_Paint::PL_Paint() : internal(new PL_Paint_Internal)
|
{
|
}
|
|
PL_Paint::~PL_Paint()
|
{
|
delete (PL_Paint_Internal*)internal;
|
internal= nullptr;
|
}
|
|
bool PL_Paint::init(void* args)
|
{
|
PL_Paint_Internal* in = (PL_Paint_Internal*)internal;
|
in->reset();
|
|
if (args != nullptr)
|
{
|
PL_Paint_Config* config = (PL_Paint_Config*)args;
|
in->config = *config;
|
}
|
|
#ifdef ENABLE_WTEXT
|
if(in->config.plplCtx->cvxText != nullptr)
|
{
|
delete (CvxText*)in->config.plplCtx->cvxText;
|
}
|
|
if(!in->config.fontPath.empty())
|
{
|
CvxText* cvxText = new CvxText(in->config.fontPath.c_str());
|
in->config.plplCtx->cvxText = cvxText;
|
cvxText->setBackColor(cvScalar(128, 33, 14));
|
CvScalar font = cvScalar(40, 1, 0.2, 1);
|
cvxText->setFont(0, &font);
|
}
|
#endif
|
|
return true;
|
}
|
|
void PL_Paint::finit()
|
{
|
PL_Paint_Internal* in = (PL_Paint_Internal*)internal;
|
|
}
|
|
bool plplDraw_Rect_YUV420(PLPLContext* plplCtx, MB_Frame* paintMb, int& paramOffset)
|
{
|
int LTX = plplCtx->params[paramOffset + 0].val_i;
|
int LTY = plplCtx->params[paramOffset + 1].val_i;
|
int RBX = plplCtx->params[paramOffset + 2].val_i;
|
int RBY = plplCtx->params[paramOffset + 3].val_i;
|
paramOffset += 4;
|
|
int src_width = paintMb->width;
|
int src_height = paintMb->height;
|
uint8_t* src_y = (uint8_t*)(paintMb->buffer);
|
uint8_t* src_u = (uint8_t*)(src_y + (src_height * src_width));
|
uint8_t* src_v = (uint8_t*)(src_u + (src_height * src_width / 4));
|
cv::Mat yMat(cv::Size(src_width, src_height), CV_8UC1, src_y);
|
cv::Mat uMat(cv::Size(MH_SUBSAMPLE1(src_width, 2), MH_SUBSAMPLE1(src_height, 2)), CV_8UC1, src_u);
|
cv::Mat vMat(cv::Size(MH_SUBSAMPLE1(src_width, 2), MH_SUBSAMPLE1(src_height, 2)), CV_8UC1, src_v);
|
|
// void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0)
|
|
const PLGH_Color_YUV yuvColor(plplCtx->color_front.toY(), plplCtx->color_front.toU(), plplCtx->color_front.toV());
|
|
cv::rectangle(yMat, cv::Point(LTX, LTY), cv::Point(RBX, RBY), CV_RGB(yuvColor.Y, yuvColor.Y, yuvColor.Y), 4);
|
cv::rectangle(uMat, cv::Point(MH_SUBSAMPLE1(LTX, 2), MH_SUBSAMPLE1(LTY, 2)), cv::Point(MH_SUBSAMPLE1(RBX, 2), MH_SUBSAMPLE1(RBY, 2)), CV_RGB(yuvColor.U, yuvColor.U, yuvColor.U), 2);
|
cv::rectangle(vMat, cv::Point(MH_SUBSAMPLE1(LTX, 2), MH_SUBSAMPLE1(LTY, 2)), cv::Point(MH_SUBSAMPLE1(RBX, 2), MH_SUBSAMPLE1(RBY, 2)), CV_RGB(yuvColor.V, yuvColor.V, yuvColor.V), 2);
|
|
return true;
|
}
|
|
bool plplDraw_Rect_NV12(PLPLContext* plplCtx, MB_Frame* paintMb, int& paramOffset)
|
{
|
int LTX = plplCtx->params[paramOffset + 0].val_i;
|
int LTY = plplCtx->params[paramOffset + 1].val_i;
|
int RBX = plplCtx->params[paramOffset + 2].val_i;
|
int RBY = plplCtx->params[paramOffset + 3].val_i;
|
paramOffset += 4;
|
|
int src_width = paintMb->width;
|
int src_height = paintMb->height;
|
uint8_t* src_y = (uint8_t*)(paintMb->buffer);
|
uint8_t* src_uv = (uint8_t*)(src_y + (src_height * src_width));
|
cv::Mat yMat(cv::Size(src_width, src_height), CV_8UC1, src_y);
|
cv::Mat uvMat(cv::Size(MH_SUBSAMPLE1(src_width, 2), MH_SUBSAMPLE1(src_height, 2)), CV_16UC1, src_uv);
|
|
// void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0)
|
|
const uint16_t Y = plplCtx->color_front.toY();
|
const uint16_t UV = plplCtx->color_front.toUV();
|
|
cv::rectangle(yMat, cv::Point(LTX, LTY), cv::Point(RBX, RBY), CV_RGB(Y, Y, Y), 4);
|
cv::rectangle(uvMat, cv::Point(MH_SUBSAMPLE1(LTX, 2), MH_SUBSAMPLE1(LTY, 2)), cv::Point(MH_SUBSAMPLE1(RBX, 2), MH_SUBSAMPLE1(RBY, 2)), CV_RGB(UV, UV, UV), 2);
|
|
return true;
|
}
|
|
bool plplDraw_Rect_RGB565(PLPLContext* plplCtx, MB_Frame* paintMb, int& paramOffset)
|
{
|
int LTX = plplCtx->params[paramOffset + 0].val_i;
|
int LTY = plplCtx->params[paramOffset + 1].val_i;
|
int RBX = plplCtx->params[paramOffset + 2].val_i;
|
int RBY = plplCtx->params[paramOffset + 3].val_i;
|
paramOffset += 4;
|
|
int src_width = paintMb->width;
|
int src_height = paintMb->height;
|
uint8_t* src_rgb = (uint8_t*)(paintMb->buffer);
|
cv::Mat rgbMat(cv::Size(src_width, src_height), CV_16UC1, src_rgb);
|
|
// void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0)
|
|
const uint16_t RGB565 = plplCtx->color_front.toRGB565();
|
cv::rectangle(rgbMat, cv::Point(LTX, LTY), cv::Point(RBX, RBY), CV_RGB(RGB565, RGB565, RGB565), 4);
|
|
return true;
|
}
|
|
bool plplDraw_Text_YUV420(PLPLContext* plplCtx, MB_Frame* paintMb, int& paramOffset)
|
{
|
return false;
|
}
|
|
bool plplDraw_Text_NV12(PLPLContext* plplCtx, MB_Frame* paintMb, int& paramOffset)
|
{
|
int LTX = plplCtx->params[paramOffset + 0].val_i;
|
int LTY = plplCtx->params[paramOffset + 1].val_i;
|
const char* TXT = plplCtx->params[paramOffset + 2].val_s;
|
paramOffset += 3;
|
|
int src_width = paintMb->width;
|
int src_height = paintMb->height;
|
uint8_t* src_y = (uint8_t*)(paintMb->buffer);
|
uint8_t* src_uv = (uint8_t*)(src_y + (src_height * src_width));
|
cv::Mat yMat(cv::Size(src_width, src_height), CV_8UC1, src_y);
|
cv::Mat uvMat(cv::Size(MH_SUBSAMPLE1(src_width, 2), MH_SUBSAMPLE1(src_height, 2)), CV_16UC1, src_uv);
|
|
// void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0)
|
|
const uint16_t Y = plplCtx->color_front.toY();
|
const uint16_t UV = plplCtx->color_front.toUV();
|
|
cv::putText(yMat, TXT, cv::Point(LTX, LTY), CV_FONT_HERSHEY_COMPLEX, 1, CV_RGB(Y, Y, Y));
|
cv::putText(uvMat, TXT, cv::Point(MH_SUBSAMPLE1(LTX, 2), MH_SUBSAMPLE1(LTY, 2)), CV_FONT_HERSHEY_COMPLEX, 0.5, CV_RGB(UV, UV, UV));
|
|
return true;
|
}
|
|
bool plplDraw_Text_RGB565(PLPLContext* plplCtx, MB_Frame* paintMb, int& paramOffset)
|
{
|
int LTX = plplCtx->params[paramOffset + 0].val_i;
|
int LTY = plplCtx->params[paramOffset + 1].val_i;
|
const char* TXT = plplCtx->params[paramOffset + 2].val_s;
|
paramOffset += 3;
|
|
int src_width = paintMb->width;
|
int src_height = paintMb->height;
|
uint8_t* src_rgb = (uint8_t*)(paintMb->buffer);
|
cv::Mat rgbMat(cv::Size(src_width, src_height), CV_16UC1, src_rgb);
|
|
const uint16_t RGB565 = plplCtx->color_front.toRGB565();
|
cv::putText(rgbMat, TXT, cv::Point(LTX, LTY), CV_FONT_HERSHEY_COMPLEX, 1, CV_RGB(RGB565, RGB565, RGB565));
|
|
return true;
|
}
|
|
bool plplDraw_WText_RGB565(PLPLContext* plplCtx, MB_Frame* paintMb, int& paramOffset)
|
{
|
#ifdef ENABLE_WTEXT
|
int LTX = plplCtx->params[paramOffset + 0].val_i;
|
int LTY = plplCtx->params[paramOffset + 1].val_i;
|
const char* WTXT = plplCtx->params[paramOffset + 2].val_s;
|
paramOffset += 3;
|
|
int src_width = paintMb->width;
|
int src_height = paintMb->height;
|
uint8_t* src_rgb = (uint8_t*)(paintMb->buffer);
|
cv::Mat rgbMat(cv::Size(src_width, src_height), CV_16UC1, src_rgb);
|
|
// void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0)
|
|
const uint16_t RGB565 = plplCtx->color_front.toRGB565();
|
|
CvxText* cvText = (CvxText*)plplCtx->cvxText;
|
cvText->putText(rgbMat, (const wchar_t*)WTXT, cv::Point(LTX, LTY), CV_RGB(RGB565, RGB565, RGB565));
|
|
return true;
|
#else
|
return false;
|
#endif
|
}
|
|
bool plplDraw_WText_NV12(PLPLContext* plplCtx, MB_Frame* paintMb, int& paramOffset)
|
{
|
#ifdef ENABLE_WTEXT
|
int LTX = plplCtx->params[paramOffset + 0].val_i;
|
int LTY = plplCtx->params[paramOffset + 1].val_i;
|
const char* WTXT = plplCtx->params[paramOffset + 2].val_s;
|
paramOffset += 3;
|
|
int src_width = paintMb->width;
|
int src_height = paintMb->height;
|
uint8_t* src_y = (uint8_t*)(paintMb->buffer);
|
uint8_t* src_uv = (uint8_t*)(src_y + (src_height * src_width));
|
cv::Mat yMat(cv::Size(src_width, src_height), CV_8UC1, src_y);
|
cv::Mat uvMat(cv::Size(MH_SUBSAMPLE1(src_width, 2), MH_SUBSAMPLE1(src_height, 2)), CV_16UC1, src_uv);
|
|
// void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0)
|
|
const uint16_t Y = plplCtx->color_front.toY();
|
const uint16_t UV = plplCtx->color_front.toUV();
|
|
CvxText* cvText = (CvxText*)plplCtx->cvxText;
|
cvText->putText(yMat, (const wchar_t*)WTXT, cv::Point(LTX, LTY), CV_RGB(Y, Y, Y)); // L"中文ABCDabcd"
|
cvText->putText(uvMat, (const wchar_t*)WTXT, cv::Point(MH_SUBSAMPLE1(LTX, 2), MH_SUBSAMPLE1(LTY, 2)), CV_RGB(UV, UV, UV)); // L"中文ABCDabcd"
|
|
return true;
|
#else
|
return false;
|
#endif
|
}
|
|
bool plpl_executor(PL_Paint_Internal *in)
|
{
|
MB_Frame* paintMb = &(in->lastMbfBuffOrigin);
|
int ret = true;
|
|
if (in->config.copyData)
|
{
|
if (in->buffer == nullptr)
|
{
|
in->buffer = new uint8_t[in->lastMbfBuffOrigin.buffSize];
|
in->buffSize = in->lastMbfBuffOrigin.buffSize;
|
}
|
|
in->lastMbfBuffCopy = in->lastMbfBuffOrigin;
|
in->lastMbfBuffCopy.buffer = in->buffer;
|
in->lastMbfBuffCopy.buffSize = in->buffSize;
|
|
memcpy(in->lastMbfBuffCopy.buffer, in->lastMbfBuffOrigin.buffer, in->lastMbfBuffCopy.buffSize);
|
|
paintMb = &(in->lastMbfBuffCopy);
|
}
|
|
//for (int i=640;i<2000;i++) ((uint8_t*)paintMb->buffer)[i]=255;
|
|
PLPLContext* plplCtx = in->config.plplCtx;
|
int paramOffset = 0;
|
for (int iCmd = 0; iCmd < in->config.plplCtx->cmds.size(); iCmd++)
|
{
|
PLPLCmd cmd = plplCtx->cmds[iCmd];
|
|
switch(cmd)
|
{
|
case PLPLC_COLOR:
|
//COLOR F/B,R,G,B,A
|
if (plplCtx->params[paramOffset + 0].val_i == 'F')
|
{
|
plplCtx->color_front = PLGH_Color_RGBA(plplCtx->params[paramOffset + 1].val_i,
|
plplCtx->params[paramOffset + 2].val_i,
|
plplCtx->params[paramOffset + 3].val_i,
|
plplCtx->params[paramOffset + 4].val_i);
|
paramOffset += 5;
|
}
|
else if (plplCtx->params[paramOffset + 0].val_i == 'B')
|
{
|
plplCtx->color_back = PLGH_Color_RGBA(plplCtx->params[paramOffset + 1].val_i,
|
plplCtx->params[paramOffset + 2].val_i,
|
plplCtx->params[paramOffset + 3].val_i,
|
plplCtx->params[paramOffset + 4].val_i);
|
paramOffset += 5;
|
}
|
else
|
{
|
LOG_WARN << "plpl execute error" << LOG_ENDL;
|
return false;
|
}
|
break;
|
|
case PLPLC_FILL:
|
plplCtx->fill = plplCtx->params[paramOffset + 0].val_i;
|
paramOffset += 1;
|
break;
|
|
case PLPLC_PEN:
|
plplCtx->pen = PLGH_Pen(plplCtx->params[paramOffset + 0].val_i, plplCtx->params[paramOffset + 1].val_i);
|
paramOffset += 2;
|
break;
|
|
case PLPLC_RECT:
|
//RECT LTX,LTY,RBX,RBY
|
if (paintMb->type == MB_Frame::MBFT_YUV420)
|
ret = plplDraw_Rect_YUV420(plplCtx, paintMb, paramOffset);
|
else if (paintMb->type == MB_Frame::MBFT_NV12)
|
ret = plplDraw_Rect_NV12(plplCtx, paintMb, paramOffset);
|
else if (paintMb->type == MB_Frame::MBFT_RGB565)
|
ret = plplDraw_Rect_RGB565(plplCtx, paintMb, paramOffset);
|
else
|
ret = false;
|
break;
|
|
case PLPLC_TEXT:
|
//TEXT LTX,LTY,"STR"
|
if (paintMb->type == MB_Frame::MBFT_YUV420)
|
ret = plplDraw_Text_YUV420(plplCtx, paintMb, paramOffset);
|
else if (paintMb->type == MB_Frame::MBFT_NV12)
|
ret = plplDraw_Text_NV12(plplCtx, paintMb, paramOffset);
|
else if (paintMb->type == MB_Frame::MBFT_RGB565)
|
ret = plplDraw_Text_RGB565(plplCtx, paintMb, paramOffset);
|
else
|
ret = false;
|
break;
|
|
case PLPLC_WTEXT:
|
//WTEXT LTX,LTY,"STR"
|
if (paintMb->type == MB_Frame::MBFT_NV12)
|
ret = plplDraw_WText_NV12(plplCtx, paintMb, paramOffset);
|
else if (paintMb->type == MB_Frame::MBFT_RGB565)
|
ret = plplDraw_WText_RGB565(plplCtx, paintMb, paramOffset);
|
else
|
ret = false;
|
break;
|
}
|
}
|
|
return ret;
|
}
|
|
/*static*/ bool PL_Paint::pay_breaker_MBFT(const PipeMaterial* pm, void* args)
|
{
|
PL_Paint_Internal* in = (PL_Paint_Internal*)args;
|
MB_Frame* frame = (MB_Frame*)pm->buffer;
|
|
in->lastMbfBuffOrigin.type = frame->type;
|
in->lastMbfBuffOrigin.buffer = frame->buffer;
|
in->lastMbfBuffOrigin.buffSize = frame->buffSize;
|
in->lastMbfBuffOrigin.width = frame->width;
|
in->lastMbfBuffOrigin.height = frame->height;
|
in->lastMbfBuffOrigin.pts = frame->pts;
|
|
in->payError = !plpl_executor(in);
|
|
return false;
|
}
|
|
bool PL_Paint::pay(const PipeMaterial& pm)
|
{
|
PL_Paint_Internal* in = (PL_Paint_Internal*)internal;
|
in->payError = true;
|
if (in->payError)
|
pm.breake(PipeMaterial::PMT_FRAME, MB_Frame::MBFT_YUV420, PL_Paint::pay_breaker_MBFT, in);
|
if (in->payError)
|
pm.breake(PipeMaterial::PMT_FRAME, MB_Frame::MBFT_NV12, PL_Paint::pay_breaker_MBFT, in);
|
if (in->payError)
|
pm.breake(PipeMaterial::PMT_FRAME, MB_Frame::MBFT_RGB565, PL_Paint::pay_breaker_MBFT, in);
|
|
return !(in->payError);
|
}
|
|
bool PL_Paint::gain(PipeMaterial& pm)
|
{
|
PL_Paint_Internal* in = (PL_Paint_Internal*)internal;
|
|
if (in->payError)
|
{
|
pm.former = this;
|
return false;
|
}
|
|
if (!in->config.copyData)
|
{
|
pm.type = PipeMaterial::PMT_FRAME;
|
pm.buffer = &(in->lastMbfBuffOrigin);
|
pm.buffSize = 0;
|
}
|
else
|
{
|
in->pmList[0].type = PipeMaterial::PMT_FRAME;
|
in->pmList[0].buffer = &(in->lastMbfBuffCopy);
|
in->pmList[0].buffSize = 0;
|
in->pmList[0].former = this;
|
|
in->pmList[1].type = PipeMaterial::PMT_FRAME;
|
in->pmList[1].buffer = &(in->lastMbfBuffOrigin);
|
in->pmList[1].buffSize = 0;
|
in->pmList[1].former = this;
|
|
pm.type = PipeMaterial::PMT_PM_LIST;
|
pm.buffer = in->pmList;
|
pm.buffSize = sizeof(in->pmList) / sizeof(PipeMaterial);
|
}
|
|
pm.former = this;
|
return true;
|
}
|