/* * Copyright (C) 2024 Amlogic Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "BinderServer.h" #include "MesonVideoCompositor.h" #include "DispAdptLog.h" #include "VscalerEvent.h" #define GET_DISPLAY(display) \ std::shared_ptr mesonDisplay; \ std::map>::iterator it = \ mDisplays.find(display); \ if (it != mDisplays.end()) { \ mesonDisplay = it->second; \ } else {\ DISPLAY_LOGE("(%s) met invalid display id (%d)",\ __func__, (int)display); \ return MESON_ERROR_BAD_DISPLAY; \ } mesonVideoCompositor::mesonVideoCompositor() { DispAdptLogInit(); mGpscFd = open(GP_FILE_PATH, O_RDWR); for (uint32_t i = 0; i < 1; i ++) { /*create meson display*/ auto disp = std::make_shared(i); disp->initialize(); disp->createGpscPlane(mGpscFd); mDisplays.emplace(i, disp); } mDrmLeaseFd = -1; if (mGpscFd >= 0) { mExitThread = false; if (pthread_create(&mGpscThread, NULL, GpscThreadMain, (void *)this)) DISPLAY_LOGE("create gpsc thread fail: %d\n", errno); } } mesonVideoCompositor::~mesonVideoCompositor() { if (mDrmLeaseFd >= 0) close(mDrmLeaseFd); mDrmLeaseFd = -1; } void* mesonVideoCompositor::GpscThreadMain(void *data) { mesonVideoCompositor *pThis = (mesonVideoCompositor *)data; struct pollfd pfd; pfd.fd = pThis->mGpscFd; pfd.events = POLLIN | POLLRDNORM; pfd.revents = 0; int pollrtn; while (true) { if (pThis->mExitThread) { pthread_exit(0); return NULL; } pollrtn = poll(&pfd, 1, 32); if (pollrtn <= 0) continue; if (pfd.revents & POLLIN) { unsigned int connectId; if (ioctl(pThis->mGpscFd, GPSCALER_GET_CONNECT_ID, &connectId) >= 0) { for (auto it = pThis->mDisplays.begin(); it != pThis->mDisplays.end(); it++) { it->second->setGpscConnectId(connectId); } } } } } meson_videotunnel_id_t mesonVideoCompositor::GetVideoTunnelId(int32_t src, int32_t attr, int32_t scalerId) { int id = MESON_USE_VDEC_TUNNEL; if (src == V4L2_EXT_VSC_INPUT_SRC_JPEG) { // VO if (scalerId == VT_SCALER_0) id = MESON_USE_VO_TUNNEL; else if (scalerId == VT_SCALER_1) id = MESON_USE_VO_EXT_TUNNEL; } if (src == V4L2_EXT_VSC_INPUT_SRC_HDMI || // HDMI (src == V4L2_EXT_VSC_INPUT_SRC_AVD && attr == 0) || // ATV src == V4L2_EXT_VSC_INPUT_SRC_TEXTURE) { // TTV if (scalerId == VT_SCALER_0) id = MESON_USE_TVIN_TUNNEL; else if (scalerId == VT_SCALER_1) id = MESON_USE_TVIN_EXT_TUNNEL; } if (src == V4L2_EXT_VSC_INPUT_SRC_VDEC) // VDEC id = MESON_USE_VDEC_TUNNEL + scalerId; if (!src) id += scalerId; return (meson_videotunnel_id_t)id; } int mesonVideoCompositor::connectScaler(int32_t displayId, int32_t scalerId) { std::lock_guard lock(mMutex); GET_DISPLAY(displayId); int32_t layerId = 0; auto layer_it = mLayers.find(scalerId); if (layer_it == mLayers.end()) { mesonDisplay->createLayer(layerId); mLayers.emplace(scalerId, layerId); } mConnectCount[scalerId]++; DISPLAY_LOGV("connect scaler: %d, layer: %d, count: %d\n", scalerId, layerId, mConnectCount[scalerId]); return MESON_ERROR_NONE; } int mesonVideoCompositor::disconnectScaler(int32_t displayId, int32_t scalerId, int32_t index) { std::lock_guard lock(mMutex); GET_DISPLAY(displayId); auto layer_it = mLayers.find(scalerId); if (layer_it != mLayers.end()) { mConnectCount[scalerId]--; if (mConnectCount[scalerId] == 0) { DISPLAY_LOGV("disconnect scaler: %d\n", scalerId); mesonDisplay->destroyLayer(layer_it->second); mLayers.erase(layer_it); } } if (mLayers.size() == 0) mesonDisplay->clearPlane(); return MESON_ERROR_NONE; } int32_t mesonVideoCompositor::getLayerIdByScaler(int32_t scalerId) { int32_t layerId; auto it = mLayers.find(scalerId); if (it != mLayers.end()) { layerId = it->second; } else { DISPLAY_LOGE("error not connect scaler: %d\n", scalerId); layerId = 0; } return layerId; } int mesonVideoCompositor::getLayerWinRegion(int32_t displayId, int32_t scalerId, struct v4l2_ext_vsc_win_region &win) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->getLayerWinRegion(layerId, win); } int mesonVideoCompositor::setOriginalResolution(int32_t displayId, int32_t scalerId, meson_rect_t rect, meson_rect_t punch) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); if (layerId == 0) return MESON_ERROR_BAD_LAYER; mesonDisplay->setLayerOriginalResolution(layerId, rect, punch); return MESON_ERROR_NONE; } int mesonVideoCompositor::setScalerSourceCrop(int32_t displayId, int32_t scalerId, struct rect crop) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->setLayerSourceCrop(layerId, crop); } int mesonVideoCompositor::setScalerDisplayFrame(int32_t displayId, int32_t scalerId, struct rect frame) { drm_rect_t rect = { 0 }; int32_t layerId = getLayerIdByScaler(scalerId); GET_DISPLAY(displayId); rect.left = frame.x; rect.top = frame.y; rect.right = frame.x + frame.w; rect.bottom = frame.y + frame.h; return mesonDisplay->setLayerDispFrame(layerId, rect); } int mesonVideoCompositor::setScalerTransform(int32_t displayId, int32_t scalerId, int32_t transform) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); if (layerId == 0) return MESON_ERROR_BAD_LAYER; int ret = mesonDisplay->setLayerTransform(layerId, transform); uint8_t dat[EVENT_WINDOW_REGION_MAX] = { 0 }; struct v4l2_ext_vsc_win_region win = { 0 }; struct v4l2_ext_video_rect disFrame; VscEventWindowRegionInfo *info = (VscEventWindowRegionInfo *)dat; VscEventType vEventType = { 0 }; VscalerEvent *vEvent = &(VscalerEvent::getInstance()); getLayerWinRegion(displayId, scalerId, win); disFrame = win.out; info->x = disFrame.x; info->y = disFrame.y; info->w = disFrame.w; info->h = disFrame.h; info->time = mesonDisplay->getVideoDelay(DEFAULT_FPS); info->px = win.punch.x; info->py = win.punch.y; info->pw = win.punch.w; info->ph = win.punch.h; vEventType = vEvent->makeEventData(displayId, scalerId, V4L2_CID_EXT_VSC_SUBSCRIBE_APPLYING_DONE_WINDOW_REGION, dat, EVENT_WINDOW_REGION_MAX); vEvent->addEventToQueue(scalerId, vEventType); return ret; } int mesonVideoCompositor::getZorder(int32_t displayId, int32_t scalerId, struct v4l2_ext_vsc_zorder &z) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->getLayerZorder(layerId, z); } int mesonVideoCompositor::setZorder(int32_t displayId, int32_t scalerId, int32_t zorder, int32_t alpha) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); if (layerId == 0) return MESON_ERROR_BAD_LAYER; float alp = (float)alpha / 255; mesonDisplay->setLayerZorder(layerId, zorder); mesonDisplay->setLayerPlaneAlpha(layerId, alp); return MESON_ERROR_NONE; } int mesonVideoCompositor::getConnectInfo(int32_t displayId, int32_t scalerId, struct v4l2_ext_vsc_connect_info &info) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); if (layerId == 0) return MESON_ERROR_BAD_LAYER; return mesonDisplay->getLayerConnectInfo(layerId, info); } int mesonVideoCompositor::setConnectInfo(int32_t displayId, int32_t scalerId, int32_t src, int32_t index, int32_t attr, int32_t out, int32_t openIndex) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); if (layerId == 0) return MESON_ERROR_BAD_LAYER; mesonDisplay->setLayerConnectInfo(layerId, src, index, attr, out); if (src == V4L2_EXT_VSC_INPUT_SRC_NONE || out == V4L2_EXT_VSC_DEST_NONE) { // todo: disable display return MESON_ERROR_NONE; } meson_videotunnel_id_t tunnelId = GetVideoTunnelId(src, attr, scalerId); if (out == V4L2_EXT_VSC_DEST_DISPLAY) { mesonDisplay->setTunnelId(layerId, tunnelId); if (scalerId == VT_SCALER_0) { struct v4l2_ext_vsc_win_prop prop; mesonDisplay->getLayerWinProp(getLayerIdByScaler(VT_SCALER_1), prop); if (prop.mirror_mode == V4L2_EXT_VSC_MIRROR_MODE_ON) mesonDisplay->setTunnelId(getLayerIdByScaler(VT_SCALER_1), tunnelId); } } return MESON_ERROR_NONE; } int mesonVideoCompositor::getWinProp(int32_t displayId, int32_t scalerId, struct v4l2_ext_vsc_win_prop &prop) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->getLayerWinProp(layerId, prop); } int mesonVideoCompositor::setWinProp(int32_t displayId, int32_t scalerId, int32_t winmode, int32_t mirrormode, int32_t memtype) { GET_DISPLAY(displayId); if (scalerId == VT_SCALER_0) return MESON_ERROR_NONE; int32_t layerId = getLayerIdByScaler(scalerId); if (layerId == 0) return MESON_ERROR_BAD_LAYER; struct v4l2_ext_vsc_connect_info info; int ret = 0; mesonDisplay->setLayerWinProp(layerId, winmode, mirrormode, memtype); if (mirrormode != V4L2_EXT_VSC_MIRROR_MODE_NONE) { if (mirrormode == V4L2_EXT_VSC_MIRROR_MODE_ON) { ret = mesonDisplay->getLayerConnectInfo(getLayerIdByScaler(VT_SCALER_0), info); if (!ret && info.in.src != V4L2_EXT_VSC_INPUT_SRC_NONE) scalerId = VT_SCALER_0; } else { ret = mesonDisplay->getLayerConnectInfo(getLayerIdByScaler(scalerId), info); } if (ret) return ret; meson_videotunnel_id_t tunnelId = GetVideoTunnelId(info.in.src, info.in.attr, scalerId); mesonDisplay->setTunnelId(layerId, tunnelId); } return MESON_ERROR_NONE; } int mesonVideoCompositor::setAspectratio(int32_t displayId, int32_t scalerId, struct v4l2_ext_vsc_aspectratio_policy policy) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->setAspectratio(layerId, policy); } int mesonVideoCompositor::setLayerOrbitWindow(int32_t displayId, int32_t scalerId, struct v4l2_ext_vsc_orbit_window &info) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->setLayerOrbitWindow(layerId, info); } int mesonVideoCompositor::setLayerOrbitMove(int32_t displayId, int32_t scalerId, struct v4l2_ext_vsc_orbit_move &info) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->setLayerOrbitMove(layerId, info); } int mesonVideoCompositor::getHDR(int32_t displayId, int *value) { int ret = -1; GET_DISPLAY(displayId); *value = V4L2_EXT_VSC_HDR_TYPE_HDR_RESERVED2; ret = mesonDisplay->getHDR(); if (ret == MESON_HDR10PLUS || ret == MESON_HDR10_ST2084 || ret == MESON_HDR10_TRADITIONAL) *value = V4L2_EXT_VSC_HDR_TYPE_HDR10; if (ret == MESON_DOLBYVISION_STD) *value = V4L2_EXT_VSC_HDR_TYPE_DOLBY; if (ret == MESON_DOLBYVISION_LL) *value = V4L2_EXT_VSC_HDR_TYPE_DOLBY_LL; if (ret == MESON_HDR_HLG) *value = V4L2_EXT_VSC_HDR_TYPE_HLG; if (ret == MESON_SDR) *value = V4L2_EXT_VSC_HDR_TYPE_SDR; return ret >= 0 ? 0 : -1; } int mesonVideoCompositor::setHDR(int32_t displayId, int value) { GET_DISPLAY(displayId); int hdr = MESON_SDR; if (value == V4L2_EXT_VSC_HDR_TYPE_SDR) hdr = MESON_SDR; if (value == V4L2_EXT_VSC_HDR_TYPE_HDR10) hdr = MESON_HDR10_ST2084; if (value == V4L2_EXT_VSC_HDR_TYPE_DOLBY) hdr = MESON_DOLBYVISION_STD; if (value == V4L2_EXT_VSC_HDR_TYPE_HLG) hdr = MESON_HDR_HLG; if (value == V4L2_EXT_VSC_HDR_TYPE_DOLBY_LL) hdr = MESON_DOLBYVISION_LL; return mesonDisplay->setHDR(hdr); } int mesonVideoCompositor::getBgColor(int32_t displayId, int *value) { GET_DISPLAY(displayId); return mesonDisplay->getBgColor(value); } int mesonVideoCompositor::setBgColor(int32_t displayId, int32_t scalerId, int value) { GET_DISPLAY(displayId); int ret = mesonDisplay->setBgColor(value); if (value == V4L2_EXT_VSC_WIN_COLOR_NORMAL) { VscalerEvent *vEvent = &(VscalerEvent::getInstance()); vEvent->makeMuteOff(scalerId); } return ret; } int mesonVideoCompositor::getLayerFreeze(int32_t displayId, int32_t scalerId, int *freeze) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->getLayerFreeze(layerId, freeze); } int mesonVideoCompositor::setLayerFreeze(int32_t displayId, int32_t scalerId, int freeze) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->setLayerFreeze(layerId, freeze); } int mesonVideoCompositor::getLayerFreezeFrameBuffer(int32_t displayId, int32_t scalerId, int *freeze) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->getLayerFreezeFrameBuffer(layerId, freeze); } int mesonVideoCompositor::setLayerFreezeFrameBuffer(int32_t displayId, int32_t scalerId, int freeze) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->setLayerFreezeFrameBuffer(layerId, freeze); } /* hdmi tx function begin */ int mesonVideoCompositor::getHdmitxConnection(int32_t displayId, int &state) { GET_DISPLAY(displayId); return mesonDisplay->getHdmitxConnection(state); } int mesonVideoCompositor::getHdmitxHdrType(int32_t displayId, int &value) { GET_DISPLAY(displayId); return mesonDisplay->getHdmitxHdrType(value); } int mesonVideoCompositor::getHdmitxHdcpVersion(int32_t displayId, int &value) { GET_DISPLAY(displayId); return mesonDisplay->getHdmitxHdcpVersion(value); } int mesonVideoCompositor::getHdmitxHdrPolicy(int32_t displayId, int &value) { int ret = -1; int policy = -1; GET_DISPLAY(displayId); ret = mesonDisplay->getHdmitxHdrPolicy(policy); switch (policy) { case MESON_HDR_POLICY_FOLLOW_SINK: value = V4L2_EXT_HDMITX_HDR_POLICY_ENABLE; break; case MESON_HDR_POLICY_FOLLOW_SOURCE: value = V4L2_EXT_HDMITX_HDR_POLICY_AUTO; break; default: value = V4L2_EXT_HDMITX_HDR_POLICY_DISABLE; break; } return ret; } int mesonVideoCompositor::setHdmitxHdrPolicy(int32_t displayId, int value) { GET_DISPLAY(displayId); return mesonDisplay->setHdmitxHdrPolicy(value); } int mesonVideoCompositor::setHdmitxAvMute(int32_t displayId, enum v4l2_ext_hdmitx_avmute value) { GET_DISPLAY(displayId); return mesonDisplay->setHdmitxAvMute(value); } int mesonVideoCompositor::setHdmitxHdcpAuth(int32_t displayId, enum v4l2_ext_hdmitx_hdcp_auth value) { GET_DISPLAY(displayId); return mesonDisplay->setHdmitxHdcpAuth(value); } int mesonVideoCompositor::getHdmitxHdcpStatus(int32_t displayId, enum v4l2_ext_hdmitx_hdcp_status &value) { GET_DISPLAY(displayId); return mesonDisplay->getHdmitxHdcpStatus(value); } int mesonVideoCompositor::getHdmiTiming(int32_t displayId, struct v4l2_ext_hdmitx_timing_info &info) { GET_DISPLAY(displayId); return mesonDisplay->getHdmiTiming(info); } int mesonVideoCompositor::setHdmiTiming(int32_t displayId, struct v4l2_ext_hdmitx_timing_info &info) { GET_DISPLAY(displayId); return mesonDisplay->setHdmiTiming(info); } int mesonVideoCompositor::getHdmitxColor(int32_t displayId, struct v4l2_ext_hdmitx_color_attr &attr) { GET_DISPLAY(displayId); return mesonDisplay->getHdmitxColor(attr); } int mesonVideoCompositor::setHdmitxColor(int32_t displayId, struct v4l2_ext_hdmitx_color_attr attr) { GET_DISPLAY(displayId); return mesonDisplay->setHdmitxColor(attr); } int mesonVideoCompositor::getHdmitxRawEdid(int32_t displayId, char **dat, int &len) { GET_DISPLAY(displayId); return mesonDisplay->getHdmitxRawEdid(dat, len); } /* hdmi tx function end */ int mesonVideoCompositor::getAlphaZorder(int displayId, int32_t scalerId, struct v4l2_ext_vsc_zorder_info *info) { GET_DISPLAY(displayId); int ret = 0; info->length = 0; for (auto it = mLayers.begin(); it != mLayers.end(); it++) { int layerId = it->second; if (it->first < VT_SCALER_MAX - 1) { ret |= mesonDisplay->getLayerZorder(layerId, info->z[it->first]); info->length++; } } DISPLAY_LOGV("%s[%d]: size: %d, length: %d\n", __func__, __LINE__, mLayers.size(), info->length); return ret; } int mesonVideoCompositor::setAlphaZorder(int displayId, int32_t scalerId, struct v4l2_ext_vsc_zorder_info *info) { GET_DISPLAY(displayId); for (int i = 0; i < info->length; i++) { int32_t layerId = getLayerIdByScaler(i); if (layerId == 0) continue; float alp = (float)info->z[i].alpha / 255; mesonDisplay->setLayerZorder(layerId, info->z[i].zorder); mesonDisplay->setLayerPlaneAlpha(layerId, alp); } return 0; } int mesonVideoCompositor::getOrbitPolicy(int displayId, int32_t scalerId, struct v4l2_ext_vsc_orbit_policy *info) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->getOrbitPolicy(layerId, info); } int mesonVideoCompositor::setOrbitPolicy(int displayId, int32_t scalerId, struct v4l2_ext_vsc_orbit_policy *info) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->setOrbitPolicy(layerId, *info); } int mesonVideoCompositor::getSeamlessInfo(int displayId, int32_t scalerId, struct v4l2_ext_vsc_seamless_info *info) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->getSeamlessInfo(layerId, info); } int mesonVideoCompositor::setSeamlessInfo(int displayId, int32_t scalerId, struct v4l2_ext_vsc_seamless_info *info) { GET_DISPLAY(displayId); int32_t layerId = getLayerIdByScaler(scalerId); return mesonDisplay->setSeamlessInfo(layerId, *info); } int mesonVideoCompositor::setDrmLeaseFd(int32_t displayId, int fd) { GET_DISPLAY(displayId); if (mDrmLeaseFd >= 0) close(mDrmLeaseFd); mDrmLeaseFd = fd; return mesonDisplay->setDrmLeaseFd(fd); } /* displayadapter interface begin */ int mesonVideoCompositor::createLayer(int32_t displayId, int32_t* layerId) { int32_t id = 0; int ret; GET_DISPLAY(displayId); ret = mesonDisplay->createLayer(id); *layerId = id; return ret; } int mesonVideoCompositor::destroyLayer(int32_t displayId, int32_t layerId) { GET_DISPLAY(displayId); return mesonDisplay->destroyLayer(layerId); } int mesonVideoCompositor::setTunnelId(int32_t displayId, int32_t layerId, int32_t tunnelId) { GET_DISPLAY(displayId); return mesonDisplay->setTunnelId(layerId, tunnelId); } int mesonVideoCompositor::setLayerIndex(int32_t displayId, int32_t layerId, int32_t index) { GET_DISPLAY(displayId); return mesonDisplay->setLayerIndex(layerId, index); } int mesonVideoCompositor::setLayerZorder(int32_t displayId, int32_t layerId, int32_t zorder) { GET_DISPLAY(displayId); return mesonDisplay->setLayerZorder(layerId, zorder); } int mesonVideoCompositor::setSourceCrop(int32_t displayId, int32_t layerId, struct rect crop) { GET_DISPLAY(displayId); return mesonDisplay->setLayerSourceCrop(layerId, crop); } int mesonVideoCompositor::setDisplayFrame(int32_t displayId, int32_t layerId, struct rect frame) { drm_rect_t rect = { 0 }; GET_DISPLAY(displayId); rect.left = frame.x; rect.top = frame.y; rect.right = frame.x + frame.w; rect.bottom = frame.y + frame.h; return mesonDisplay->setLayerDispFrame(layerId, rect); } int mesonVideoCompositor::getDelayLatency(int32_t displayId, int32_t layerId) { GET_DISPLAY(displayId); return mesonDisplay->getVsyncDelayLatency(layerId); } int mesonVideoCompositor::setToMainPlane(int32_t displayId) { GET_DISPLAY(displayId); return mesonDisplay->setVideoDisplaytoMainplane(); } int mesonVideoCompositor::getUiSize(int32_t displayId, int32_t* width, int32_t* height) { GET_DISPLAY(displayId); return mesonDisplay->getUiSize(width, height); } /* displayadapter interface end */ int main(int argc, char **argv) { (void)argc; (void)argv; printf("main run\n"); std::shared_ptr meson = std::make_shared(); std::shared_ptr binS = std::make_shared(); VscalerEvent *vEvent = &(VscalerEvent::getInstance()); binS->setMesonCompositor(meson); vEvent->setBinder(binS); binS->run(binS); while (true) { usleep(1000); } return 0; }