289 lines
9.8 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|