/* ******************************************************************************* * INCLUDE ******************************************************************************* */ #include "VideoOverlay.h" #include "MPPChannel.h" #include "ResourceManager.h" #include "util/Math.h" #include "Logger.h" #include #include #include #include #include namespace Video { namespace MPP5 { /* ******************************************************************************* * CLASS DEFINE ******************************************************************************* */ VideoOverlay::VideoOverlay(Core::VideoOverlayType type, const std::string& name, const Core::Rect& region) : Core::VideoOverlay(type, name, region), _handle(ResourceManager::allocRGNHandle()), _imagePhyAddr(0), _pImageVirAddr(nullptr) { hi_rgn_attr attr = {}; switch (type) { case Core::VideoOverlayType::CANVAS: attr.type = HI_RGN_OVERLAY; attr.attr.overlay.pixel_format = HI_PIXEL_FORMAT_ARGB_8888; _bytesPerPixel = 4; attr.attr.overlay.size.width = ::Util::Math::alignup(region.width, 2); attr.attr.overlay.size.height = ::Util::Math::alignup(region.height, 2); attr.attr.overlay.bg_color = 0; attr.attr.overlay.canvas_num = 2; break; case Core::VideoOverlayType::MOSAIC: attr.type = HI_RGN_MOSAIC; break; default: throw Poco::LogicException(name + ": Unimplemented type: " + std::to_string((int)type)); } int rc = hi_mpi_rgn_create(_handle, &attr); if (rc != HI_SUCCESS) throw Poco::InvalidArgumentException(Poco::format("%s: Create FAIL: %#x", name, (uint32_t)rc), rc); } VideoOverlay::~VideoOverlay() { _timer.cancel(true); if (_pImageVirAddr != nullptr && _imagePhyAddr != 0) hi_mpi_sys_mmz_free(_imagePhyAddr, _pImageVirAddr); Core::VideoComponent::Ptr o = target(); auto chn = dynamic_cast(o.get())->raw(); hi_mpi_rgn_detach_from_chn(_handle, &chn); hi_mpi_rgn_destroy(_handle); ResourceManager::freeRGNHandle(_handle); } void VideoOverlay::render(Core::Image::Ptr pImage) { hi_rgn_canvas_info info; hi_mpi_rgn_get_canvas_info(_handle, &info); uint32_t height = ::Util::Math::min((uint32_t)pImage->height(), (uint32_t)region().height); for (uint32_t y = 0; y < height; y++) { int i = 0; Core::Color color; uint8_t* pLine = (uint8_t*)info.virt_addr + y * info.stride; cimg_forX(*pImage, x) { if (x >= region().width) continue; pImage->getPixel(x, y, color); color.toARGB8888Pixel(&pLine[i]); i += _bytesPerPixel; } } hi_mpi_rgn_update_canvas(_handle); } void VideoOverlay::scrollRender(Core::Image::Ptr pImage, int hscroll) { const int W = (int)region().width; const int H = (int)::Util::Math::min((uint32_t)pImage->height(), (uint32_t)region().height); const int textWidth = (int)pImage->width(); const int winW = (int)::Util::Math::min((uint32_t)W, 4096u); const int period = 2 * W + textWidth; const uint32_t stride = ::Util::Math::alignup((uint32_t)winW * _bytesPerPixel, 8); int rc = hi_mpi_sys_mmz_alloc(&_imagePhyAddr, (void**)&_pImageVirAddr, nullptr, nullptr, (uint32_t)H * stride); if (rc != HI_SUCCESS) throw Poco::OutOfMemoryException(Poco::format("%s: Alloc MMZ FAIL: %#x", name(), (uint32_t)rc), rc); _pTextImage = pImage; _textWidth = textWidth; _winW = winW; _winH = H; _stride = stride; _period = period; if (hscroll > 0) _progressX = 0; else _progressX = period - W; const int movePixels = hscroll; const long interval = 30; _timer.schedule(Poco::Util::Timer::func( [this, W, movePixels]() { const int H = _winH; const int winW = _winW; const int textW = _textWidth; const uint32_t stride = _stride; const int period = _period; ::memset(_pImageVirAddr, 0, (uint32_t)H * stride); int startStrip = (_progressX > W) ? _progressX : W; int endStrip = ((_progressX + winW) < (W + textW)) ? (_progressX + winW) : (W + textW); if (startStrip < endStrip) { int textStart = startStrip - W; int winStart = startStrip - _progressX; int count = endStrip - startStrip; for (int y = 0; y < H; y++) { uint8_t* pWin = _pImageVirAddr + (uint32_t)y * stride + (uint32_t)winStart * _bytesPerPixel; Core::Color color; for (int x = 0; x < count; x++) { _pTextImage->getPixel(textStart + x, y, color); color.toARGB8888Pixel(&pWin[x * (int)_bytesPerPixel]); } } } hi_tde_surface srcSurface = {}; srcSurface.phys_addr = _imagePhyAddr; srcSurface.color_format = HI_TDE_COLOR_FORMAT_ARGB8888; srcSurface.height = (uint32_t)H; srcSurface.width = (uint32_t)winW; srcSurface.stride = stride; srcSurface.is_ycbcr_clut = HI_FALSE; srcSurface.alpha_max_is_255 = HI_TRUE; srcSurface.support_alpha_ex_1555 = HI_FALSE; srcSurface.alpha0 = 0XFF; srcSurface.alpha1 = 0XFF; hi_rgn_canvas_info info; hi_mpi_rgn_get_canvas_info(_handle, &info); const uint32_t dstW = ::Util::Math::min((uint32_t)region().width, 4096u); const uint32_t dstH = ::Util::Math::min((uint32_t)region().height, 4096u); hi_tde_surface dstSurface = {}; dstSurface.phys_addr = info.phys_addr; dstSurface.color_format = HI_TDE_COLOR_FORMAT_ARGB8888; dstSurface.height = dstH; dstSurface.width = dstW; dstSurface.stride = info.stride; dstSurface.is_ycbcr_clut = HI_FALSE; dstSurface.support_alpha_ex_1555 = HI_FALSE; dstSurface.alpha_max_is_255 = HI_TRUE; dstSurface.alpha0 = 0XFF; dstSurface.alpha1 = 0XFF; hi_tde_rect srcRect; srcRect.pos_x = 0; srcRect.pos_y = 0; srcRect.width = (uint32_t)winW; srcRect.height = (uint32_t)H; hi_tde_rect dstRect; dstRect.pos_x = 0; dstRect.pos_y = 0; dstRect.width = (uint32_t)winW; dstRect.height = (uint32_t)H; hi_s32 handle = hi_tde_begin_job(); hi_tde_single_src src; src.src_surface = (hi_tde_surface*)&srcSurface; src.dst_surface = (hi_tde_surface*)&dstSurface; src.src_rect = (hi_tde_rect*)&srcRect; src.dst_rect = (hi_tde_rect*)&dstRect; int rc = hi_tde_quick_copy(handle, &src); if (rc != HI_SUCCESS) { logger().error("%s: TDE quick copy FAIL: %#x", name(), (uint32_t)rc); _timer.cancel(false); return; } hi_tde_end_job(handle, HI_FALSE, HI_TRUE, 10); hi_mpi_rgn_update_canvas(_handle); _progressX += movePixels; if (movePixels > 0) { if (_progressX >= period - W) _progressX = 0; } else { if (_progressX <= 0) _progressX = period - W; } }), interval, interval); } void VideoOverlay::attach(Core::VideoComponent::Ptr pVideoComponent) { Core::VideoOverlay::attach(pVideoComponent); hi_rgn_chn_attr attr = {}; attr.is_show = HI_TRUE; switch (type()) { case Core::VideoOverlayType::CANVAS: attr.type = HI_RGN_OVERLAY; attr.attr.overlay_chn.point.x = ::Util::Math::alignup(region().x, 2); attr.attr.overlay_chn.point.y = ::Util::Math::alignup(region().y, 2); attr.attr.overlay_chn.fg_alpha = 0; attr.attr.overlay_chn.bg_alpha = 0; attr.attr.overlay_chn.layer = getLayer(); attr.attr.overlay_chn.qp_info.enable = HI_FALSE; attr.attr.overlay_chn.qp_info.is_abs_qp = HI_FALSE; attr.attr.overlay_chn.qp_info.qp_val = 0; attr.attr.overlay_chn.dst = HI_RGN_ATTACH_JPEG_MAIN; break; case Core::VideoOverlayType::MOSAIC: attr.type = HI_RGN_MOSAIC; attr.attr.mosaic_chn.rect.x = ::Util::Math::alignup(region().x, 4); ; attr.attr.mosaic_chn.rect.y = ::Util::Math::alignup(region().y, 2); attr.attr.mosaic_chn.rect.width = ::Util::Math::alignup(region().width, 4); attr.attr.mosaic_chn.rect.height = ::Util::Math::alignup(region().height, 2); attr.attr.mosaic_chn.blk_size = getBlockSize(); attr.attr.mosaic_chn.layer = getLayer(); break; default: throw Poco::LogicException(name() + ": Unimplemented type: " + std::to_string((int)type())); } auto t = target(); auto pChannel = dynamic_cast(t.get()); if (!pChannel) throw Poco::LogicException(name() + ": Unsupported target: " + target()->name()); auto chn = pChannel->raw(); int rc = hi_mpi_rgn_attach_to_chn(_handle, &chn, &attr); if (rc != HI_SUCCESS) throw Poco::InvalidArgumentException(Poco::format("%s: Attach FAIL: %#x", name(), (uint32_t)rc), rc); } void VideoOverlay::onConfigChanged(ParameterNames& names) { if (names.exists(_ZOrder)) { auto t = target(); auto pChannel = dynamic_cast(t.get()); auto chn = pChannel->raw(); hi_rgn_chn_attr attr; hi_mpi_rgn_get_display_attr(_handle, &chn, &attr); switch (attr.type) { case HI_RGN_OVERLAY: attr.attr.overlay_chn.layer = getZOrder(); break; default: break; } hi_mpi_rgn_set_display_attr(_handle, &chn, &attr); } } hi_mosaic_blk_size VideoOverlay::getBlockSize() { switch (getBlock()) { default: case 8: return HI_MOSAIC_BLK_SIZE_8; case 16: return HI_MOSAIC_BLK_SIZE_16; case 32: return HI_MOSAIC_BLK_SIZE_32; } } hi_u32 VideoOverlay::getLayer() { return ::Util::Math::clamp(getZOrder(), 0, 4); } } }