p26001-store-acs-soc-fw-app/video/hisi/mpp5/VideoProcessor.cpp
2026-09-28 21:33:04 +08:00

289 lines
9.8 KiB
C++

/*
*******************************************************************************
* INCLUDE
*******************************************************************************
*/
#include "VideoProcessor.h"
#include "Logger.h"
#include "ResourceManager.h"
#include "VideoInput.h"
#include "util/Math.h"
namespace Video
{
namespace MPP5
{
/*
*******************************************************************************
* CLASS DEFINE
*******************************************************************************
*/
VideoProcessor::VideoProcessor()
: MPPChannel((uint32_t)HI_ID_VPSS, ResourceManager::allocVPSSGroupID(), 0),
Core::VideoProcessor(Poco::format("VideoProcessor(VPSS#%u)", deviceID()))
{
registerNotificationHandle<Core::ParameterChangedNotification>(*this,
&VideoProcessor::handlePreviousParameterChanged);
}
VideoProcessor::~VideoProcessor()
{
ResourceManager::freeVPSSGroupID(deviceID());
}
void VideoProcessor::start()
{
auto pPrevious = previousComponents().first().cast<VideoComponent>();
if (!pPrevious)
throw Poco::BugcheckException(Poco::format("%s: First previous component '%s' convert to 'VideoComponent' FAIL",
name(), previousComponents().first()->name()));
setWidth(pPrevious->getWidth());
setHeight(pPrevious->getHeight());
setVideoScanMode(pPrevious->getVideoScanMode());
uint32_t width = getWidth();
uint32_t height = getHeight();
hi_vpss_grp_attr attr = {};
attr.nr_en = HI_FALSE;
attr.ie_en = HI_FALSE;
attr.dci_en = HI_FALSE;
attr.buf_share_en = HI_FALSE;
attr.buf_share_chn = 0;
attr.mcf_en = HI_FALSE;
attr.max_width = width;
attr.max_height = height;
attr.max_dei_width = width;
attr.max_dei_height = height;
attr.pixel_format = HI_PIXEL_FORMAT_YVU_SEMIPLANAR_422;
attr.dynamic_range = HI_DYNAMIC_RANGE_SDR8;
attr.frame_rate.src_frame_rate = -1;
attr.frame_rate.dst_frame_rate = -1;
if (!pPrevious.cast<VideoInput>().isNull() && getVideoScanMode() == Core::VideoScanMode::INTERLACED)
{
attr.dei_mode = HI_VPSS_DEI_MODE_AUTO;
setFrameRate(pPrevious->getFrameRate() / 2);
}
else
{
attr.dei_mode = HI_VPSS_DEI_MODE_OFF;
setFrameRate(pPrevious->getFrameRate());
}
int rc = hi_mpi_vpss_create_grp(groupID(), &attr);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: Create group FAIL: %d(%#x)", name(), rc, (uint32_t)rc),
rc);
hi_mpi_vpss_reset_grp(groupID());
rc = hi_mpi_vpss_start_grp(groupID());
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: Start group FAIL: %d(%#x)", name(), rc, (uint32_t)rc), rc);
bool isPreviousMJPEG = false;
uint32_t direction = 0;
hi_vpss_chn_attr chnAttr = {};
chnAttr.chn_mode = HI_VPSS_CHN_MODE_USER;
chnAttr.width = width;
chnAttr.height = height;
chnAttr.video_format = HI_VIDEO_FORMAT_LINEAR;
chnAttr.pixel_format = HI_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
chnAttr.dynamic_range = HI_DYNAMIC_RANGE_SDR8;
chnAttr.compress_mode = HI_COMPRESS_MODE_NONE;
chnAttr.frame_rate.src_frame_rate = -1;
chnAttr.frame_rate.dst_frame_rate = -1;
chnAttr.mirror_en = (hi_bool)getMirror();
chnAttr.flip_en = (hi_bool)getFlip();
chnAttr.depth = 0;
setVPSSVideoDirection(isPreviousMJPEG && direction, &chnAttr);
rc = hi_mpi_vpss_set_chn_attr(groupID(), channelID(), &chnAttr);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(
Poco::format("%s: Set channel#%u attr FAIL: %d(%#x)", name(), channelID(), rc, (uint32_t)rc), rc);
setVPSSChannelRotation(getRotation(), channelID());
setVPSSGroupCrop(getCrop());
rc = hi_mpi_vpss_enable_chn(groupID(), channelID());
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(
Poco::format("%s: Enable channel#%u FAIL: %d(%#x)", name(), channelID(), rc, (uint32_t)rc), rc);
}
void VideoProcessor::stop()
{
hi_mpi_vpss_disable_chn(groupID(), channelID());
hi_mpi_vpss_stop_grp(groupID());
hi_mpi_vpss_destroy_grp(groupID());
}
void VideoProcessor::onConfigChanged(ParameterNames& names)
{
if (!started())
return;
if (names.exists(_Width) || names.exists(_Height))
{
stop();
start();
publishEvent(Core::Component::Event::IMAGE_SIZE_CHANGED);
return;
}
if (names.exists(_Rotation))
setVPSSChannelRotation(getRotation(), channelID());
if (names.exists(_Crop))
setVPSSGroupCrop(getCrop());
if (names.exists(_Mirror) || names.exists(_Flip))
{
hi_vpss_chn_attr attr;
hi_mpi_vpss_get_chn_attr(groupID(), channelID(), &attr);
attr.mirror_en = (hi_bool)getMirror();
attr.flip_en = (hi_bool)getFlip();
hi_mpi_vpss_set_chn_attr(groupID(), channelID(), &attr);
}
if (names.exists(_VideoDirection))
{
hi_vpss_chn_attr attr;
hi_mpi_vpss_get_chn_attr(groupID(), channelID(), &attr);
setVPSSVideoDirection(attr.aspect_ratio.mode == HI_ASPECT_RATIO_NONE, &attr);
hi_mpi_vpss_set_chn_attr(groupID(), channelID(), &attr);
}
}
void VideoProcessor::onLink(Core::Component::Ptr pPrevious)
{
MPPChannel::doLink(pPrevious);
}
void VideoProcessor::onUnlink(Core::Component::Ptr pPrevious)
{
MPPChannel::doUnlink(pPrevious);
}
void VideoProcessor::handlePreviousParameterChanged(
const Poco::AutoPtr<Core::ParameterChangedNotification>& pNotication)
{
auto pPrevious = previousComponents().first().cast<VideoComponent>();
if (!pPrevious)
throw Poco::BugcheckException(Poco::format("%s: First previous component '%s' convert to 'VideoComponent' FAIL",
name(), previousComponents().first()->name()));
auto parameters = pNotication->parameters();
if (parameters.exists(_Width))
setWidth(pPrevious->getWidth());
if (parameters.exists(_Height))
setHeight(pPrevious->getHeight());
if (parameters.exists(_FrameRate))
setFrameRate(pPrevious->getFrameRate());
if (parameters.exists(_VideoScanMode))
{
setVideoScanMode(pPrevious->getVideoScanMode());
if (started())
{
hi_vpss_grp_attr attr;
hi_mpi_vpss_get_grp_attr(groupID(), &attr);
if (!pPrevious.cast<VideoInput>().isNull() && getVideoScanMode() == Core::VideoScanMode::INTERLACED)
{
attr.dei_mode = HI_VPSS_DEI_MODE_AUTO;
setFrameRate(pPrevious->getFrameRate() / 2);
}
else
{
attr.dei_mode = HI_VPSS_DEI_MODE_OFF;
setFrameRate(pPrevious->getFrameRate());
}
hi_mpi_vpss_set_grp_attr(groupID(), &attr);
}
parameters.insert(_FrameRate);
}
commit();
notifyNextComponents(sharedFromThis(), new Core::ParameterChangedNotification(parameters));
}
void VideoProcessor::setVPSSGroupCrop(const Core::Rect& rect)
{
int x = Util::Math::clamp(rect.x, 0, HI_VPSS_MAX_IMG_WIDTH - 1);
int y = Util::Math::clamp(rect.y, 0, HI_VPSS_MAX_IMG_HEIGHT - 1);
int width = Util::Math::clamp(rect.width, HI_VPSS_MIN_IMG_WIDTH,
Util::Math::max(HI_VPSS_MIN_IMG_WIDTH, HI_VPSS_MAX_IMG_WIDTH - rect.x));
int height = Util::Math::clamp(rect.height, HI_VPSS_MIN_IMG_HEIGHT,
Util::Math::max(HI_VPSS_MIN_IMG_HEIGHT, HI_VPSS_MAX_IMG_HEIGHT - rect.y));
hi_vpss_crop_info crop = {};
crop.enable = (hi_bool) !(rect.x == 0 && rect.y == 0 && rect.width == 0 && rect.height == 0);
crop.crop_mode = HI_COORD_ABS;
crop.crop_rect.x = x;
crop.crop_rect.y = y;
crop.crop_rect.width = width;
crop.crop_rect.height = height;
hi_mpi_vpss_set_grp_crop(groupID(), &crop);
}
void VideoProcessor::setVPSSChannelRotation(int rotation, uint32_t channelID)
{
hi_rotation_attr attr;
attr.enable = HI_TRUE;
attr.rotation_type = HI_ROTATION_ANG_FIXED;
switch (rotation)
{
default:
case 0:
attr.enable = HI_FALSE;
attr.rotation_fixed = HI_ROTATION_0;
break;
case 90:
attr.rotation_fixed = HI_ROTATION_90;
break;
case 180:
attr.rotation_fixed = HI_ROTATION_180;
break;
case 270:
attr.rotation_fixed = HI_ROTATION_270;
break;
}
int rc = hi_mpi_vpss_set_chn_rotation(groupID(), channelID, &attr);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(
Poco::format("%s: Set channel#%u rotation FAIL: %d(%#x)", name(), channelID, rc, (uint32_t)rc), rc);
}
void VideoProcessor::setVPSSVideoDirection(int direction, hi_vpss_chn_attr* attr)
{
if (!attr)
return;
if (direction)
{
uint32_t width = getWidth();
uint32_t height = getHeight();
attr->aspect_ratio.mode = HI_ASPECT_RATIO_MANUAL;
attr->aspect_ratio.bg_color = 0x000000;
attr->aspect_ratio.video_rect.width = height * height / width;
attr->aspect_ratio.video_rect.height = height;
attr->aspect_ratio.video_rect.x = (width - attr->aspect_ratio.video_rect.width) / 2;
attr->aspect_ratio.video_rect.y = 0;
}
else
attr->aspect_ratio.mode = HI_ASPECT_RATIO_NONE;
}
}
}