#include "PL_Scale.h"
|
#include "MaterialBuffer.h"
|
#include "logger.h"
|
#include "MediaHelper.h"
|
#include <libyuv.h>
|
|
struct PL_Scale_Internal
|
{
|
uint8_t* buffer;
|
size_t buffSize;
|
size_t buffSizeMax;
|
bool payError;
|
|
PipeMaterial::PipeMaterialBufferType lastPmType;
|
MB_Frame tempFrame;
|
PL_Scale_Config config;
|
|
PL_Scale_Internal() :
|
buffer(nullptr), buffSize(0), buffSizeMax(0), payError(true),
|
lastPmType(PipeMaterial::PMT_NONE), tempFrame(), config()
|
{
|
}
|
|
~PL_Scale_Internal()
|
{
|
delete[] buffer;
|
buffer = nullptr;
|
}
|
|
void reset()
|
{
|
buffSize = 0;
|
payError = true;
|
|
lastPmType = PipeMaterial::PMT_NONE;
|
|
MB_Frame _tempFrame;
|
tempFrame = _tempFrame;
|
|
PL_Scale_Config _config;
|
config = _config;
|
|
if (buffSizeMax > 0)
|
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" << std::endl;
|
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, size_t buffSize, MB_Frame::MBFType srcType, uint16_t srcWidth, uint16_t srcHeight)
|
{
|
const int dst_width = in->config.toWidth;
|
const int dst_height = in->config.toHeight;
|
|
size_t dstSizeMax = 0;
|
if ((dst_width != srcWidth && dst_height != srcHeight) || in->config.copyData)
|
{
|
if (srcType == MB_Frame::MBFT_YUV420 || srcType == MB_Frame::MBFT_NV12)
|
dstSizeMax = in->config.toWidth * in->config.toHeight * 2; // #todo 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" << std::endl;
|
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 << std::endl;
|
}
|
}
|
else
|
{
|
in->buffer = srcBuffer;
|
in->buffSize = buffSize;
|
in->buffSizeMax = 0;
|
|
return true;
|
}
|
|
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, MH_SUBSAMPLE1(srcWidth, 2),
|
src_v, MH_SUBSAMPLE1(srcWidth, 2),
|
srcWidth, srcHeight,
|
dst_y, dst_width,
|
dst_u, MH_SUBSAMPLE1(dst_width, 2),
|
dst_v, MH_SUBSAMPLE1(dst_width, 2),
|
dst_width, dst_height,
|
(libyuv::FilterMode)(in->config.filterMode));
|
|
in->buffSize = dstSizeMax;
|
}
|
else if (srcType == MB_Frame::MBFT_NV12)
|
{
|
const uint8_t* src_y = (const uint8_t*)(srcBuffer);
|
const uint8_t* src_uv = (const uint8_t*)(src_y + (srcHeight * srcWidth));
|
|
// RK3288, 1920->640: 2.8~12ms, avg=4ms
|
uint8_t* dst_y = (uint8_t*)(in->buffer);
|
uint8_t* dst_uv = (uint8_t*)(dst_y + (dst_height * dst_width));
|
|
libyuv::ScalePlane(src_y, srcWidth,
|
srcWidth, srcHeight,
|
dst_y, dst_width,
|
dst_width, dst_height,
|
libyuv::kFilterNone);
|
|
libyuv::ScalePlane_16((uint16*)src_uv, MH_SUBSAMPLE1(srcWidth, 2),
|
MH_SUBSAMPLE1(srcWidth, 2), MH_SUBSAMPLE1(srcHeight, 2),
|
(uint16*)dst_uv, MH_SUBSAMPLE1(dst_width, 2),
|
MH_SUBSAMPLE1(dst_width, 2), MH_SUBSAMPLE1(dst_height, 2),
|
libyuv::kFilterNone);
|
|
in->buffSize = dstSizeMax;
|
}
|
else if (srcType == MB_Frame::MBFT_BGRA)
|
{
|
//#todo
|
LOG_ERROR << "srcType only support MBFT_YUV420 and MBFT_NV12" << std::endl;
|
return false;
|
}
|
else
|
{
|
LOG_ERROR << "srcType only support MBFT_YUV420 and MBFT_NV12" << std::endl;
|
return false;
|
}
|
|
return true;
|
}
|
|
/*static*/ bool PL_Scale::pay_breaker_MBFT(const PipeMaterial* pm, void* args)
|
{
|
PL_Scale_Internal* in = (PL_Scale_Internal*)args;
|
|
MB_Frame* mbf = (MB_Frame*)pm->buffer;
|
in->payError = !image_scale(in, (uint8_t*)mbf->buffer, mbf->buffSize, mbf->type, mbf->width, mbf->height);
|
|
if (!(in->payError))
|
in->tempFrame = *mbf;
|
|
return false;
|
}
|
|
bool PL_Scale::pay(const PipeMaterial& pm)
|
{
|
PL_Scale_Internal* in = (PL_Scale_Internal*)internal;
|
|
in->payError = true;
|
if (in->payError)
|
pm.breake(PipeMaterial::PMT_FRAME_LIST, MB_Frame::MBFT_YUV420, pay_breaker_MBFT, in);
|
if (in->payError)
|
pm.breake(PipeMaterial::PMT_FRAME_LIST, MB_Frame::MBFT_NV12, pay_breaker_MBFT, in);
|
if (in->payError)
|
pm.breake(PipeMaterial::PMT_FRAME, MB_Frame::MBFT_YUV420, pay_breaker_MBFT, in);
|
if (in->payError)
|
pm.breake(PipeMaterial::PMT_FRAME, MB_Frame::MBFT_NV12, pay_breaker_MBFT, in);
|
if (in->payError)
|
pm.breake(PipeMaterial::PMT_FRAME, MB_Frame::MBFT_RGB565, pay_breaker_MBFT, in);
|
|
if (!(in->payError))
|
in->lastPmType = pm.type;
|
|
return !(in->payError);
|
}
|
|
bool PL_Scale::gain(PipeMaterial& pm)
|
{
|
PL_Scale_Internal* in = (PL_Scale_Internal*)internal;
|
|
if (in->payError)
|
return false;
|
|
PipeMaterial newPm;
|
newPm.type = PipeMaterial::PMT_NONE;
|
newPm.former = this;
|
|
if (in->lastPmType == PipeMaterial::PMT_BYTES)
|
{
|
newPm.type = PipeMaterial::PMT_BYTES;
|
newPm.buffer = in->buffer;
|
newPm.buffSize = in->buffSize;
|
}
|
else
|
{
|
newPm.type = PipeMaterial::PMT_FRAME;
|
newPm.buffer = &(in->tempFrame);
|
newPm.buffSize = 0;
|
|
in->tempFrame.buffer = in->buffer;
|
in->tempFrame.buffSize = in->buffSize;
|
in->tempFrame.width = in->config.toWidth;
|
in->tempFrame.height = in->config.toHeight;
|
}
|
|
pm = newPm;
|
return !in->payError;
|
}
|