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

295 lines
9.2 KiB
C++

/*
*******************************************************************************
* INCLUDE
*******************************************************************************
*/
#include "VideoMixer.h"
#include "util/Math.h"
#include <hi_mpi_vo.h>
#include <cmath>
namespace Video
{
namespace MPP5
{
/*
*******************************************************************************
* CONSTANTS
*******************************************************************************
*/
#define WIDTH 1920
#define HEIGHT 1080
#define FRAMTE_RATE 60
#define VO_DEVICE_ID 1
#define VIDEO_LAYER_ID 1
#define VO_WBC_ID 0
#define VO_MAX_CHN_NUM (HI_VO_MAX_CHN_NUM - 1)
#define VO_CHN_PLACEHOLDER_ID (VO_MAX_CHN_NUM - 1)
/*
*******************************************************************************
* CLASS DEFINE
*******************************************************************************
*/
VideoMixer::Channel::Channel(VideoMixer::Ptr pMixer, uint32_t id)
: MPPChannel((uint32_t)HI_ID_VO, VIDEO_LAYER_ID, id), Core::VideoMixer::Channel("MPP5::VHD1", pMixer, id)
{
}
VideoMixer::Channel::~Channel()
{
}
void VideoMixer::Channel::start()
{
if (mixer().cast<VideoMixer>()->started())
activate();
}
void VideoMixer::Channel::stop()
{
if (getActivated())
deactivate();
}
void VideoMixer::Channel::onConfigChanged(ParameterNames& names)
{
Core::VideoMixer::Channel::onConfigChanged(names);
if (!started())
return;
if (names.exists(_Attach))
{
if (!getAttach())
deactivate();
else if (mixer().cast<VideoMixer>()->started())
activate();
}
if ((names.exists(_Region) || names.exists(_ZOrder)) && getActivated())
configureChannel();
}
void VideoMixer::Channel::onLink(Core::Component::Ptr pPrevious)
{
MPPChannel::doLink(pPrevious);
}
void VideoMixer::Channel::onUnlink(Core::Component::Ptr pPrevious)
{
MPPChannel::doUnlink(pPrevious);
}
void VideoMixer::Channel::activate()
{
configureChannel();
int rc = hi_mpi_vo_enable_chn(VIDEO_LAYER_ID, channelID());
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(
Poco::format("%s: enable FAIL: %d(%#x)", mixer()->name() + "/" + name(), rc, (uint32_t)rc), rc);
setActivated(true);
}
void VideoMixer::Channel::deactivate()
{
hi_mpi_vo_disable_chn(VIDEO_LAYER_ID, channelID());
setActivated(false);
}
void VideoMixer::Channel::configureChannel()
{
const auto region = getRegion();
hi_vo_chn_attr attr;
attr.priority = ::Util::Math::clamp(getZOrder(), 0, VO_MAX_CHN_NUM - 2) + 1;
attr.rect.x =
::Util::Math::aligndown(::Util::Math::clamp(static_cast<int>(std::round(region.x * WIDTH)), 0, WIDTH - 32), 2);
attr.rect.y = ::Util::Math::aligndown(
::Util::Math::clamp(static_cast<int>(std::round(region.y * HEIGHT)), 0, HEIGHT - 32), 2);
attr.rect.width = ::Util::Math::aligndown(
::Util::Math::clamp(static_cast<int>(std::round(region.width * WIDTH)), 32, WIDTH - attr.rect.x), 2);
attr.rect.height = ::Util::Math::aligndown(
::Util::Math::clamp(static_cast<int>(std::round(region.height * HEIGHT)), 32, HEIGHT - attr.rect.y), 2);
;
attr.deflicker_en = HI_FALSE;
int rc = hi_mpi_vo_set_chn_attr(VIDEO_LAYER_ID, channelID(), &attr);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(
Poco::format("%s: set chn attr FAIL: %d(%#x)", mixer()->name() + "/" + name(), rc, (uint32_t)rc), rc);
}
/*
*******************************************************************************
* CLASS DEFINE
*******************************************************************************
*/
VideoMixer::VideoMixer(const std::string& name)
: MPPChannel((uint32_t)HI_ID_VO, VO_DEVICE_ID, 0), Core::VideoMixer(Poco::format("%s(MPP5::VO::DHD1)", name))
{
setWidth(WIDTH);
setHeight(HEIGHT);
setFrameRate(FRAMTE_RATE);
setSignalLost(false);
}
VideoMixer::~VideoMixer()
{
}
void VideoMixer::start()
{
int rc = hi_mpi_vo_enable(deviceID());
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: enable VO FAIL: %d(%#x)", name(), rc, (uint32_t)rc), rc);
{
hi_vo_video_layer_attr attr;
attr.display_rect.x = 0;
attr.display_rect.y = 0;
attr.display_rect.width = WIDTH;
attr.display_rect.height = HEIGHT;
attr.img_size.width = WIDTH;
attr.img_size.height = HEIGHT;
attr.display_frame_rate = FRAMTE_RATE;
attr.pixel_format = HI_PIXEL_FORMAT_YVU_SEMIPLANAR_422;
attr.double_frame_en = HI_FALSE;
attr.cluster_mode_en = HI_FALSE;
attr.dst_dynamic_range = HI_DYNAMIC_RANGE_SDR8;
attr.display_buf_len = 4;
attr.partition_mode = HI_VO_PARTITION_MODE_SINGLE;
attr.compress_mode = HI_COMPRESS_MODE_NONE;
rc = hi_mpi_vo_set_video_layer_attr(VIDEO_LAYER_ID, &attr);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(
Poco::format("%s: set video layer attr FAIL: %d(%#x)", name(), rc, (uint32_t)rc), rc);
rc = hi_mpi_vo_enable_video_layer(VIDEO_LAYER_ID);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(
Poco::format("%s: enable video layer FAIL: %d(%#x)", name(), rc, (uint32_t)rc), rc);
}
{
hi_vo_wbc_src src;
src.src_type = HI_VO_WBC_SRC_VIDEO;
src.src_id = VIDEO_LAYER_ID;
rc = hi_mpi_vo_set_wbc_src(VO_WBC_ID, &src);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: set WBC src FAIL: %d(%#x)", name(), rc, (uint32_t)rc),
rc);
rc = hi_mpi_vo_set_wbc_mode(VO_WBC_ID, HI_VO_WBC_MODE_NORM);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: set WBC mode FAIL: %d(%#x)", name(), rc, (uint32_t)rc),
rc);
hi_vo_wbc_attr attr;
attr.target_size.width = WIDTH;
attr.target_size.height = HEIGHT;
attr.pixel_format = HI_PIXEL_FORMAT_YVU_SEMIPLANAR_422;
attr.frame_rate = -1;
attr.dynamic_range = HI_DYNAMIC_RANGE_SDR8;
attr.compress_mode = HI_COMPRESS_MODE_NONE;
rc = hi_mpi_vo_set_wbc_attr(VO_WBC_ID, &attr);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: set WBC attr FAIL: %d(%#x)", name(), rc, (uint32_t)rc),
rc);
rc = hi_mpi_vo_enable_wbc(VO_WBC_ID);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: enable WBC FAIL: %d(%#x)", name(), rc, (uint32_t)rc),
rc);
}
foreachChannel<Channel>(
[](Channel::Ptr pChannel) -> void
{
if (pChannel->getAttach())
pChannel->activate();
});
{
hi_vo_chn_attr attr;
attr.priority = 0;
attr.rect.x = 0;
attr.rect.y = 0;
attr.rect.width = 32;
attr.rect.height = 32;
attr.deflicker_en = HI_FALSE;
hi_mpi_vo_set_chn_attr(VIDEO_LAYER_ID, VO_CHN_PLACEHOLDER_ID, &attr);
hi_mpi_vo_enable_chn(VIDEO_LAYER_ID, VO_CHN_PLACEHOLDER_ID);
}
Core::VideoMixer::start();
}
void VideoMixer::stop()
{
hi_mpi_vo_disable_chn(VIDEO_LAYER_ID, VO_CHN_PLACEHOLDER_ID);
foreachChannel<Channel>(
[this](Channel::Ptr pChannel) -> void
{
if (pChannel->getActivated())
pChannel->deactivate();
});
Core::VideoMixer::stop();
int rc = hi_mpi_vo_disable_wbc(VO_WBC_ID);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: disable WBC FAIL: %d(%#x)", name(), rc, (uint32_t)rc), rc);
rc = hi_mpi_vo_disable_video_layer(VIDEO_LAYER_ID);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(
Poco::format("%s: disable video layer FAIL: %d(%#x)", name(), rc, (uint32_t)rc), rc);
rc = hi_mpi_vo_disable(VO_DEVICE_ID);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: disable VO FAIL: %d(%#x)", name(), rc, (uint32_t)rc), rc);
}
void VideoMixer::initialize()
{
hi_vo_pub_attr attr;
attr.bg_color = 0x000000;
attr.intf_type = HI_VO_INTF_BT1120;
attr.intf_sync = HI_VO_OUT_1080P60;
int rc = hi_mpi_vo_set_pub_attr(deviceID(), &attr);
if (rc != HI_SUCCESS)
throw Poco::InvalidAccessException(Poco::format("%s: set-pub FAIL: %d(%#x)", name(), rc, (uint32_t)rc), rc);
}
void VideoMixer::deinitialize()
{
}
void VideoMixer::onConfigChanged(ParameterNames& names)
{
}
Core::VideoMixer::Channel::Ptr VideoMixer::createChannel(uint32_t id)
{
if (id >= VO_CHN_PLACEHOLDER_ID)
throw Poco::InvalidArgumentException(
Poco::format("%s: channel id %u overrage: [0,%u]", name(), id, (uint32_t)(VO_CHN_PLACEHOLDER_ID - 1)),
-EINVAL);
return new Channel(Ptr(this, true), id);
}
}
}