295 lines
9.2 KiB
C++
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);
|
|
}
|
|
}
|
|
}
|