/* ******************************************************************************* * INCLUDE ******************************************************************************* */ #include "VideoMixer.h" #include "util/Math.h" #include #include 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()->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()->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(std::round(region.x * WIDTH)), 0, WIDTH - 32), 2); attr.rect.y = ::Util::Math::aligndown( ::Util::Math::clamp(static_cast(std::round(region.y * HEIGHT)), 0, HEIGHT - 32), 2); attr.rect.width = ::Util::Math::aligndown( ::Util::Math::clamp(static_cast(std::round(region.width * WIDTH)), 32, WIDTH - attr.rect.x), 2); attr.rect.height = ::Util::Math::aligndown( ::Util::Math::clamp(static_cast(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::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( [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); } } }