/* ******************************************************************************* * 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(*this, &VideoProcessor::handlePreviousParameterChanged); } VideoProcessor::~VideoProcessor() { ResourceManager::freeVPSSGroupID(deviceID()); } void VideoProcessor::start() { auto pPrevious = previousComponents().first().cast(); 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().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& pNotication) { auto pPrevious = previousComponents().first().cast(); 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().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; } } }