#include "PL_Scale.h" #include "MaterialBuffer.h" #include "logger.h" #include "MediaHelper.h" #include 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; }