/* * Copyright 2020 Rockchip Electronics Co. LTD * * 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 #include #include #include "RTNodeVFilterVideoOutput.h" // NOLINT #include "RTNodeCommon.h" #include "RTVideoFrame.h" #include #ifdef RV1126_RV1109 #include "drmDsp.h" #endif #ifdef LOG_TAG #undef LOG_TAG #endif #define LOG_TAG "RTNodeVFilterVideoOutput" #define kStubRockitVideoOutputDemo MKTAG('r', 'k', 'v', 'o') static RK_S32 VO_ENABLE() { /* Enable VO */ VO_PUB_ATTR_S VoPubAttr; VO_VIDEO_LAYER_ATTR_S stLayerAttr; RK_S32 s32Ret; VO_CHN_ATTR_S stChnAttr; VO_CHN VoChn; VoChn = 0; s32Ret = RK_MPI_SYS_Init(); RT_LOGD("RK_MPI_SYS_Init ret = %d", s32Ret); VO_LAYER VoLayer = RK356X_VOP_LAYER_CLUSTER_0; VO_DEV VoDev = RK356X_VO_DEV_HD0; RK_MPI_VO_DisableLayer(VoLayer); RK_MPI_VO_DisableLayer(RK356X_VOP_LAYER_ESMART_0); RK_MPI_VO_DisableLayer(RK356X_VOP_LAYER_ESMART_1); RK_MPI_VO_DisableLayer(RK356X_VOP_LAYER_SMART_0); RK_MPI_VO_DisableLayer(RK356X_VOP_LAYER_SMART_1); RK_MPI_VO_Disable(VoDev); RT_LOGD("[%s] unint VO config first\n", __func__); memset(&VoPubAttr, 0, sizeof(VO_PUB_ATTR_S)); memset(&stLayerAttr, 0, sizeof(VO_VIDEO_LAYER_ATTR_S)); stLayerAttr.enPixFormat = RK_FMT_YUV420SP; stLayerAttr.stDispRect.s32X = 0; stLayerAttr.stDispRect.s32Y = 0; stLayerAttr.u32DispFrmRt = 30; stLayerAttr.stDispRect.u32Width = 1920; stLayerAttr.stDispRect.u32Height = 1080; stLayerAttr.stImageSize.u32Width = 1920; stLayerAttr.stImageSize.u32Height = 1080; s32Ret = RK_MPI_VO_GetPubAttr(VoDev, &VoPubAttr); if (s32Ret != RK_SUCCESS) { return s32Ret; } VoPubAttr.enIntfType = VO_INTF_HDMI; VoPubAttr.enIntfSync = VO_OUTPUT_1080P60; s32Ret = RK_MPI_VO_SetPubAttr(VoDev, &VoPubAttr); if (s32Ret != RK_SUCCESS) { return s32Ret; } s32Ret = RK_MPI_VO_Enable(VoDev); if (s32Ret != RK_SUCCESS) { return s32Ret; } s32Ret = RK_MPI_VO_SetLayerAttr(VoLayer, &stLayerAttr); if (s32Ret != RK_SUCCESS) { RK_LOGE("[%s] RK_MPI_VO_SetLayerAttr failed,s32Ret:%d\n", __func__, s32Ret); return RK_FAILURE; } s32Ret = RK_MPI_VO_BindLayer(VoLayer, VoDev, VO_LAYER_MODE_VIDEO); if (s32Ret != RK_SUCCESS) { RK_LOGE("[%s] RK_MPI_VO_BindLayer failed,s32Ret:%d\n", __func__, s32Ret); return RK_FAILURE; } s32Ret = RK_MPI_VO_EnableLayer(VoLayer); if (s32Ret != RK_SUCCESS) { RK_LOGE("[%s] RK_MPI_VO_EnableLayer failed,s32Ret:%d\n", __func__, s32Ret); return RK_FAILURE; } stChnAttr.stRect.s32X = 0; stChnAttr.stRect.s32Y = 0; stChnAttr.stRect.u32Width = stLayerAttr.stImageSize.u32Width; stChnAttr.stRect.u32Height = stLayerAttr.stImageSize.u32Height; stChnAttr.u32Priority = 0; if (1) { stChnAttr.u32FgAlpha = 128; stChnAttr.u32BgAlpha = 0; } else { stChnAttr.u32FgAlpha = 0; stChnAttr.u32BgAlpha = 128; } s32Ret = RK_MPI_VO_SetChnAttr(VoLayer, 0, &stChnAttr); if (s32Ret != RK_SUCCESS) { RK_LOGE("[%s] set chn Attr failed,s32Ret:%d\n", __func__, s32Ret); return RK_FAILURE; } s32Ret = RK_MPI_VO_EnableChn(VoLayer, 0); if (s32Ret != RK_SUCCESS) { RK_LOGE("[%s] Enalbe chn failed, s32Ret = %d\n", __func__, s32Ret); return RK_FAILURE; } return RK_SUCCESS; } RTNodeVFilterVideoOutput::RTNodeVFilterVideoOutput() { mLock = new RtMutex(); RT_ASSERT(RT_NULL != mLock); } RTNodeVFilterVideoOutput::~RTNodeVFilterVideoOutput() { rt_safe_delete(mLock); } RT_RET RTNodeVFilterVideoOutput::open(RTTaskNodeContext *context) { RT_LOGD("wttt RTNodeVFilterVideoOutput open"); RtMetaData* inputMeta = context->options(); drmInitSuccess = 0; #ifdef RK356X VO_ENABLE(); pstVFrame = (VIDEO_FRAME_INFO_S *)(calloc(sizeof(VIDEO_FRAME_INFO_S), 1)); #endif #ifdef RV1126_RV1109 if (initDrmDsp() < 0) { RT_LOGE("DRM display init failed\n"); } else { drmInitSuccess = 1; } #endif gettimeofday(&beginTime, NULL); frameCount = 0; return RT_OK; } RT_RET RTNodeVFilterVideoOutput::process(RTTaskNodeContext *context) { RT_RET err = RT_OK; RTVideoFrame *srcBuffer = RT_NULL; RtMutex::RtAutolock autoLock(mLock); RK_S32 ret = RT_OK; INT32 count = context->inputQueueSize("image:nv12"); while (count) { srcBuffer = reinterpret_vframe(context->dequeInputBuffer("image:nv12")); if (srcBuffer == RT_NULL) continue; count--; #ifdef RV1126_RV1109 if (drmInitSuccess) { ret = drmDspFrame(srcBuffer->getWidth(), srcBuffer->getHeight(), srcBuffer->getData(), DRM_FORMAT_NV12); if (ret == RT_OK) { if (!access(HDMI_RKVO_DEBUG_FPS, 0)) { ++frameCount; if (frameCount == 100) { struct timeval now_time; gettimeofday(&now_time, NULL); float use_times = (now_time.tv_sec * 1000 + now_time.tv_usec / 1000) - (beginTime.tv_sec * 1000 + beginTime.tv_usec / 1000); beginTime.tv_sec = now_time.tv_sec; beginTime.tv_usec = now_time.tv_usec; float fps = (1000 * frameCount) / use_times; frameCount = 0; RT_LOGE("hdmi rkvo fps = %0.1f", fps); } } } else { RT_LOGE("drmDspFrame failed ret = %d", ret); } } #endif #ifdef RK356X RK_VOID *pMblk; VO_LAYER VoVideoLayer; VO_CHN VoChn; VoVideoLayer = RK356X_VOP_LAYER_CLUSTER_0; VoChn = 0; /*fill pMbBlk*/ pstVFrame->stVFrame.pMbBlk = srcBuffer; pstVFrame->stVFrame.u32Width = srcBuffer->getWidth(); pstVFrame->stVFrame.u32Height = srcBuffer->getHeight(); pstVFrame->stVFrame.u32VirWidth = srcBuffer->getWidth(); pstVFrame->stVFrame.u32VirHeight = srcBuffer->getHeight(); pstVFrame->stVFrame.enPixelFormat = RK_FMT_YUV420SP; pstVFrame->stVFrame.enCompressMode = COMPRESS_MODE_NONE; do { ret = RK_MPI_VO_SendFrame(VoVideoLayer, VoChn, pstVFrame, -1); if (ret == RT_OK) { if (!access(HDMI_RKVO_DEBUG_FPS, 0)) { ++frameCount; if (frameCount == 100) { struct timeval now_time; gettimeofday(&now_time, NULL); float use_times = (now_time.tv_sec * 1000 + now_time.tv_usec / 1000) - (beginTime.tv_sec * 1000 + beginTime.tv_usec / 1000); beginTime.tv_sec = now_time.tv_sec; beginTime.tv_usec = now_time.tv_usec; float fps = (1000 * frameCount) / use_times; frameCount = 0; RT_LOGE("hdmi rkvo fps = %0.1f", fps); } } break; } else { RT_LOGE("RK_MPI_VO_SendFrame failed ret = %d", ret); RK_MPI_VO_DestroyGraphicsFrameBuffer(pMblk); break; } } while (0); #endif srcBuffer->release(); } return err; } RT_RET RTNodeVFilterVideoOutput::close(RTTaskNodeContext *context) { RT_LOGD("wttt RTNodeVFilterVideoOutput close"); RT_RET err = RT_OK; #ifdef RV1126_RV1109 if (drmInitSuccess) { deInitDrmDsp(); } #endif #ifdef RK356X if(pstVFrame) free(pstVFrame); #endif return err; } RT_RET RTNodeVFilterVideoOutput::invokeInternal(RtMetaData *meta) { RT_LOGD("wttt RTNodeVFilterVideoOutput invokeInternal"); const char *command; if (RT_NULL == meta) { return RT_ERR_NULL_PTR; } return RT_OK; } static RTTaskNode* createVideoOutputFilter() { RT_LOGD("wttt RTNodeVFilterVideoOutput createVideoOutputFilter"); return new RTNodeVFilterVideoOutput(); } /***************************************** * register node stub to RTTaskNodeFactory *****************************************/ RTNodeStub node_stub_filter_video_output { .mUid = kStubRockitVideoOutputDemo, .mName = "rkvo", .mVersion = "v1.0", .mCreateObj = createVideoOutputFilter, .mCapsSrc = { "video/x-raw", RT_PAD_SRC, RT_MB_TYPE_VFRAME, {RT_NULL, RT_NULL} }, .mCapsSink = { "video/x-raw", RT_PAD_SINK, RT_MB_TYPE_VFRAME, {RT_NULL, RT_NULL} }, }; RT_NODE_FACTORY_REGISTER_STUB(node_stub_filter_video_output);