/* * Copyright (c) 2008-2016 Allwinner Technology Co. Ltd. * All rights reserved. * * File : layerControl.cpp * Description : surface display interface -- decoder and de share the buffer * History : */ //#define CONFIG_LOG_LEVEL OPTION_LOG_LEVEL_DETAIL //#define LOG_TAG "layerControl_android_newDisplay" #include "cdx_config.h" #include "layerControl.h" #include "cdx_log.h" #include "memoryAdapter.h" #include "outputCtrl.h" #include #include "CdcUtil.h" #if (((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER == 2))) #include #elif ((CONF_ANDROID_MAJOR_VER >= 4)||((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER >= 4))) #include #else #error "invalid configuration of os version." #endif #include #include #include #if ((CONF_ANDROID_MAJOR_VER >= 4)||((CONF_ANDROID_MAJOR_VER == 4)&&(CONF_ANDROID_SUB_VER >= 4))) #include #endif #include #include /* only A33 here, hide it now. */ #if 0 //((CONF_ANDROID_MAJOR_VER >= 5) && GRALLOC_PRIV == 1) #include #endif #if (defined(CONF_PTS_TOSF) && (CONF_ANDROID_MAJOR_VER >= 5)) #include "VideoFrameSchedulerWrap.h" #endif using namespace android; #if (CONF_KERNEL_VER == 304) typedef struct ion_handle* ion_handle_abstract_t; #define ION_NULL_VALUE (NULL) #elif (CONF_KERNEL_VER == 310) typedef ion_user_handle_t ion_handle_abstract_t; #define ION_NULL_VALUE (0) #else #error: not define kernel version. #endif #define GPU_BUFFER_NUM 32 /* +1 allows queue after SetGpuBufferToDecoder */ #define NUM_OF_PICTURES_KEEP_IN_NODE (GetConfigParamterInt("pic_4list_num", 3) + 1) typedef struct VPictureNode_t VPictureNode; struct VPictureNode_t { int bUsed; VideoPicture* pPicture; ANativeWindowBuffer* pNodeWindowBuf; }; typedef struct GpuBufferInfoS { ANativeWindowBuffer* pWindowBuf; ion_handle_abstract_t handle_ion; char* pBufPhyAddr; char* pBufVirAddr; int nUsedFlag; int nDequeueFlag; }GpuBufferInfoT; typedef struct LayerCtrlContext { LayerCtrl base; ANativeWindow* pNativeWindow; enum EPIXELFORMAT eDisplayPixelFormat; int nWidth; int nHeight; int nLeftOff; int nTopOff; int nDisplayWidth; int nDisplayHeight; int bLayerInitialized; int bLayerShowed; int bProtectFlag; //* use when render derect to hardware layer. VPictureNode picNodes[16]; GpuBufferInfoT mGpuBufferInfo[GPU_BUFFER_NUM]; int nGpuBufferCount; int ionFd; int b4KAlignFlag; int bHoldLastPictureFlag; int bVideoWithTwoStreamFlag; int bIsSoftDecoderFlag; unsigned int nUsage; #if (defined(CONF_PTS_TOSF) && (CONF_ANDROID_MAJOR_VER >= 5)) CdxVideoScheduler *mVideoScheduler; #endif }LayerCtrlContext; #if defined(CONF_SEND_BLACK_FRAME_TO_GPU) static int sendThreeBlackFrameToGpu(LayerCtrlContext* lc) { logd("sendThreeBlackFrameToGpu()"); ANativeWindowBuffer* pWindowBuf; void* pDataBuf; int i; int err; int pic_4list = GetConfigParamterInt("pic_4list_num", 3); if (lc->pNativeWindow == NULL || lc->bLayerInitialized == 0) { logv("skip %s", __func__); return 0; } for(i = 0; i < pic_4list; i++) { err = lc->pNativeWindow->dequeueBuffer_DEPRECATED(lc->pNativeWindow, &pWindowBuf); if(err != 0) { logw("dequeue buffer fail, return value from dequeueBuffer_DEPRECATED() method is %d.", err); return -1; } lc->pNativeWindow->lockBuffer_DEPRECATED(lc->pNativeWindow, pWindowBuf); //* lock the data buffer. { GraphicBufferMapper& graphicMapper = GraphicBufferMapper::get(); Rect bounds(lc->nWidth, lc->nHeight); graphicMapper.lock(pWindowBuf->handle, lc->nUsage, bounds, &pDataBuf); logd("graphicMapper %p", pDataBuf); } if (pDataBuf) { memset((char*)pDataBuf,0x10,(pWindowBuf->height * pWindowBuf->stride)); memset((char*)pDataBuf + pWindowBuf->height * pWindowBuf->stride, 0x80,(pWindowBuf->height * pWindowBuf->stride)/2); } int nBufAddr[7] = {0}; //nBufAddr[6] = HAL_PIXEL_FORMAT_AW_NV12; nBufAddr[6] = HAL_PIXEL_FORMAT_AW_FORCE_GPU; lc->pNativeWindow->perform(lc->pNativeWindow, NATIVE_WINDOW_SET_VIDEO_BUFFERS_INFO, nBufAddr[0], nBufAddr[1], nBufAddr[2], nBufAddr[3], nBufAddr[4], nBufAddr[5], nBufAddr[6]); //* unlock the buffer. { GraphicBufferMapper& graphicMapper = GraphicBufferMapper::get(); graphicMapper.unlock(pWindowBuf->handle); } lc->pNativeWindow->queueBuffer_DEPRECATED(lc->pNativeWindow, pWindowBuf); } return 0; } // dequeue all nativewindow buffer from BufferQueue, then cancle all. // this can make sure all buffer queued by player to render by surfaceflinger. static int makeSureBlackFrameToShow(LayerCtrlContext* lc) { logd("makeSureBlackFrameToShow()"); ANativeWindowBuffer* pWindowBuf[32]; void* pDataBuf; int i; int err; int bufCnt = lc->nGpuBufferCount; for(i = 0;i < bufCnt -1; i++) { err = lc->pNativeWindow->dequeueBuffer_DEPRECATED(lc->pNativeWindow, &pWindowBuf[i]); if(err != 0) { logw("dequeue buffer fail, return value from dequeueBuffer_DEPRECATED() method is %d.", err); break; } logv("dequeue i = %d, handle: 0x%x", i, pWindowBuf[i]->handle); } for(i--; i >= 0; i--) { logv("cancel i = %d, handle: 0x%x", i, pWindowBuf[i]->handle); lc->pNativeWindow->cancelBuffer(lc->pNativeWindow, pWindowBuf[i], -1); } return 0; } #endif //* this function just for 3D case. //* just init 32-line buffer to black color. //* (when the two stream display to 2D, the 32-line buffer will cause "Green Screen" if not init, //* as buffer have make 32-align) //* if init the whole buffer, it would take too much time. int initPartialGpuBuffer(char* pDataBuf, ANativeWindowBuffer* pWindowBuf, LayerCtrlContext* lc) { logv("initGpuBuffer, stride = %d, height = %d, ",pWindowBuf->stride,pWindowBuf->height); if(lc->eDisplayPixelFormat == PIXEL_FORMAT_NV21) { //* Y1 int nRealHeight = pWindowBuf->height/2; int nInitHeight = 32; int nSkipLen = pWindowBuf->stride*(nRealHeight - nInitHeight); int nCpyLenY = pWindowBuf->stride*nInitHeight; memset(pDataBuf+nSkipLen, 0x10, nCpyLenY); //* Y2 nSkipLen += pWindowBuf->stride*nRealHeight; memset(pDataBuf+nSkipLen, 0x10, nCpyLenY); //*UV1 nSkipLen += nCpyLenY; nSkipLen += (pWindowBuf->stride)*(nRealHeight/2 - nInitHeight/2); int nCpyLenUV = (pWindowBuf->stride)*(nInitHeight/2); memset(pDataBuf+nSkipLen, 0x80, nCpyLenUV); //*UV2 nSkipLen += (pWindowBuf->stride)*(nRealHeight/2); memset(pDataBuf+nSkipLen, 0x80, nCpyLenUV); } else { loge("the pixelFormat is not support when initPartialGpuBuffer, pixelFormat = %d", lc->eDisplayPixelFormat); return -1; } return 0; } //* copy from ACodec.cpp static int pushBlankBuffersToNativeWindow(LayerCtrlContext* lc) { logd("pushBlankBuffersToNativeWindow: pNativeWindow = %p",lc->pNativeWindow); if(lc->pNativeWindow == NULL) { logw(" the nativeWindow is null when call pushBlankBuffersToNativeWindow"); return 0; } status_t eErr = NO_ERROR; ANativeWindowBuffer* pWindowBuffer = NULL; int nNumBufs = 0; int nMinUndequeuedBufs = 0; ANativeWindowBuffer **pArrBuffer = NULL; // We need to reconnect to the ANativeWindow as a CPU client to ensure that // no frames get dropped by SurfaceFlinger assuming that these are video // frames. eErr = native_window_api_disconnect(lc->pNativeWindow,NATIVE_WINDOW_API_MEDIA); if (eErr != NO_ERROR) { loge("error push blank frames: native_window_api_disconnect failed: %s (%d)", strerror(-eErr), -eErr); return eErr; } eErr = native_window_api_connect(lc->pNativeWindow,NATIVE_WINDOW_API_CPU); if (eErr != NO_ERROR) { loge("error push blank frames: native_window_api_connect failed: %s (%d)", strerror(-eErr), -eErr); return eErr; } #if (CONF_ANDROID_MAJOR_VER >= 5) eErr = lc->pNativeWindow->perform(lc->pNativeWindow, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, 0, 0, HAL_PIXEL_FORMAT_RGBX_8888); #else eErr = native_window_set_buffers_geometry(lc->pNativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888); #endif if (eErr != NO_ERROR) { loge("set buffers geometry of nativeWindow failed: %s (%d)", strerror(-eErr), -eErr); goto error; } eErr = native_window_set_scaling_mode(lc->pNativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); if (eErr != NO_ERROR) { loge("error push blank_frames: native_window_set_scaling_mode failed: %s (%d)", strerror(-eErr), -eErr); goto error; } eErr = native_window_set_usage(lc->pNativeWindow, GRALLOC_USAGE_SW_WRITE_OFTEN); if (eErr != NO_ERROR) { loge("error push blank frames: native_window_set_usage failed: %s (%d)", strerror(-eErr), -eErr); goto error; } eErr = lc->pNativeWindow->query(lc->pNativeWindow, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &nMinUndequeuedBufs); if (eErr != NO_ERROR) { loge("query NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS failed: %s (%d)", strerror(-eErr), -eErr); goto error; } nNumBufs = nMinUndequeuedBufs + 1; if (nNumBufs < 3) nNumBufs = 3; eErr = native_window_set_buffer_count(lc->pNativeWindow, nNumBufs); if (eErr != NO_ERROR) { loge("set buffer count of nativeWindow failed: %s (%d)", strerror(-eErr), -eErr); goto error; } // We push nNumBufs + 1 buffers to ensure that we've drawn into the same // buffer twice. This should guarantee that the buffer has been displayed // on the screen and then been replaced, so an previous video frames are // guaranteed NOT to be currently displayed. logd("nNumBufs=%d", nNumBufs); //* we just push nNumBufs.If push numBus+1,it will be problem in suspension window for (int i = 0; i < nNumBufs; i++) { int fenceFd = -1; eErr = native_window_dequeue_buffer_and_wait(lc->pNativeWindow, &pWindowBuffer); if (eErr != NO_ERROR) { loge("error: native_window_dequeue_buffer_and_wait failed: %s (%d)", strerror(-eErr), -eErr); goto error; } sp mGraphicBuffer(new GraphicBuffer(pWindowBuffer, false)); // Fill the buffer with the a 1x1 checkerboard pattern ;) uint32_t* pImg = NULL; eErr = mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&pImg)); if (eErr != NO_ERROR) { loge("error push blank frames: lock failed: %s (%d)", strerror(-eErr), -eErr); goto error; } *pImg = 0; eErr = mGraphicBuffer->unlock(); if (eErr != NO_ERROR) { loge("error push blank frames: unlock failed: %s (%d)", strerror(-eErr), -eErr); goto error; } eErr = lc->pNativeWindow->queueBuffer(lc->pNativeWindow, mGraphicBuffer->getNativeBuffer(), -1); if (eErr != NO_ERROR) { loge("lc->pNativeWindow->queueBuffer failed: %s (%d)", strerror(-eErr), -eErr); goto error; } pWindowBuffer = NULL; } pArrBuffer = (ANativeWindowBuffer **)malloc((nNumBufs)*sizeof(ANativeWindowBuffer*)); for (int i = 0; i < nNumBufs-1; ++i) { eErr = native_window_dequeue_buffer_and_wait(lc->pNativeWindow, &pArrBuffer[i]); if (eErr != NO_ERROR) { loge("native_window_dequeue_buffer_and_wait failed: %s (%d)", strerror(-eErr), -eErr); goto error; } } for (int i = 0; i < nNumBufs-1; ++i) { lc->pNativeWindow->cancelBuffer(lc->pNativeWindow, pArrBuffer[i], -1); } free(pArrBuffer); pArrBuffer = NULL; error: if (eErr != NO_ERROR) { // Clean up after an error. if (pWindowBuffer != NULL) { lc->pNativeWindow->cancelBuffer(lc->pNativeWindow, pWindowBuffer, -1); } if (pArrBuffer) { free(pArrBuffer); } native_window_api_disconnect(lc->pNativeWindow, NATIVE_WINDOW_API_CPU); native_window_api_connect(lc->pNativeWindow, NATIVE_WINDOW_API_MEDIA); return eErr; } else { // Clean up after success. eErr = native_window_api_disconnect(lc->pNativeWindow, NATIVE_WINDOW_API_CPU); if (eErr != NO_ERROR) { loge("native_window_api_disconnect failed: %s (%d)", strerror(-eErr), -eErr); return eErr; } eErr = native_window_api_connect(lc->pNativeWindow, NATIVE_WINDOW_API_MEDIA); if (eErr != NO_ERROR) { loge("native_window_api_connect failed: %s (%d)", strerror(-eErr), -eErr); return eErr; } return 0; } } //* set usage, scaling_mode, pixelFormat, buffers_geometry, buffers_count, crop static int setLayerParam(LayerCtrlContext* lc) { logd("setLayerParam: PixelFormat(%d), nW(%d), nH(%d), leftoff(%d), topoff(%d)", lc->eDisplayPixelFormat,lc->nWidth, lc->nHeight,lc->nLeftOff,lc->nTopOff); logd("setLayerParam: dispW(%d), dispH(%d), buffercount(%d), bProtectFlag(%d),\ bIsSoftDecoderFlag(%d)", lc->nDisplayWidth,lc->nDisplayHeight,lc->nGpuBufferCount, lc->bProtectFlag,lc->bIsSoftDecoderFlag); int pixelFormat; unsigned int nGpuBufWidth; unsigned int nGpuBufHeight; Rect crop; lc->nUsage = 0; //* add the protected usage when the video is secure if(lc->bProtectFlag == 1) { // Verify that the ANativeWindow sends images directly to // SurfaceFlinger. int nErr = -1; int nQueuesToNativeWindow = 0; nErr = lc->pNativeWindow->query( lc->pNativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &nQueuesToNativeWindow); if (nErr != 0) { loge("error authenticating native window: %d", nErr); return nErr; } if (nQueuesToNativeWindow != 1) { loge("nQueuesToNativeWindow is not 1, PERMISSION_DENIED"); return PERMISSION_DENIED; } logd("set usage to GRALLOC_USAGE_PROTECTED"); lc->nUsage |= GRALLOC_USAGE_PROTECTED; } if(lc->bIsSoftDecoderFlag == 1) { //* gpu use this usage to malloc buffer with cache. lc->nUsage |= GRALLOC_USAGE_SW_WRITE_OFTEN; } else { //* gpu use this usage to malloc continuous physical buffer. lc->nUsage |= GRALLOC_USAGE_HW_2D; //* cpu cannot WRITE and READ the buffer if the video is protect. //* when it is not protect, cpu will W the buffer, but not often. if(lc->bProtectFlag == 0) { lc->nUsage |= GRALLOC_USAGE_SW_WRITE_RARELY; } } //* add other usage lc->nUsage |= GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP; switch(lc->eDisplayPixelFormat) { case PIXEL_FORMAT_YV12: //* why YV12 use this pixel format. pixelFormat = HAL_PIXEL_FORMAT_YV12; break; case PIXEL_FORMAT_NV21: pixelFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; break; case PIXEL_FORMAT_NV12: //* display system do not support NV12. default: { loge("unsupported pixel format."); return -1; break; } } nGpuBufWidth = lc->nWidth; //* restore nGpuBufWidth to mWidth; nGpuBufHeight = lc->nHeight; //* We should double the height if the video with two stream, //* so the nativeWindow will malloc double buffer if(lc->bVideoWithTwoStreamFlag == 1) { nGpuBufHeight = 2*nGpuBufHeight; } crop.left = lc->nLeftOff; crop.top = lc->nTopOff; crop.right = lc->nLeftOff + lc->nDisplayWidth; crop.bottom = lc->nTopOff + lc->nDisplayHeight; if(lc->nGpuBufferCount <= 0) { loge("error: the lc->nGpuBufferCount[%d] is invalid!",lc->nGpuBufferCount); return -1; } logd("set usage, lc->pNativeWindow: %p", lc->pNativeWindow); native_window_set_usage(lc->pNativeWindow,lc->nUsage); logd("set sacle"); native_window_set_scaling_mode(lc->pNativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); #if defined(CONF_PRODUCT_STB) lc->pNativeWindow->perform(lc->pNativeWindow, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, nGpuBufWidth, nGpuBufHeight, pixelFormat); #endif //native_window_set_buffers_geometry(lc->pNativeWindow, nGpuBufWidth, //nGpuBufHeight, pixelFormat); native_window_set_buffers_dimensions(lc->pNativeWindow, nGpuBufWidth, nGpuBufHeight); native_window_set_buffers_format(lc->pNativeWindow, pixelFormat); //#endif native_window_set_buffer_count(lc->pNativeWindow,lc->nGpuBufferCount); lc->pNativeWindow->perform(lc->pNativeWindow, NATIVE_WINDOW_SET_CROP, &crop); return 0; } ANativeWindowBuffer* dequeueTheInitGpuBuffer(LayerCtrlContext* lc) { int err = -1; int i = 0; int nCancelNum = 0; int nNeedCancelFlag = 0; int nCancelIndex[GPU_BUFFER_NUM] = {-1}; ANativeWindowBuffer* pWindowBuf = NULL; dequeue_buffer: //* dequeue a buffer from the nativeWindow object. err = lc->pNativeWindow->dequeueBuffer_DEPRECATED(lc->pNativeWindow, &pWindowBuf); if(err != 0) { logw("dequeue buffer fail, return value from dequeueBuffer_DEPRECATED() method is %d.", err); return NULL; } for(i = 0; i < lc->nGpuBufferCount; i++) { if(lc->mGpuBufferInfo[i].nUsedFlag == 1 && lc->mGpuBufferInfo[i].pWindowBuf == pWindowBuf) { nNeedCancelFlag = 1; nCancelIndex[nCancelNum] = i; nCancelNum++; logv("the buffer have not return ,dequeue agagin! : %p",pWindowBuf); goto dequeue_buffer; } } if(nNeedCancelFlag == 1) { for(i = 0;imGpuBufferInfo[nIndex].pWindowBuf; lc->pNativeWindow->cancelBuffer_DEPRECATED(lc->pNativeWindow, pTmpWindowBuf); } nCancelNum = 0; nNeedCancelFlag = 0; } return pWindowBuf; } int getPhyAddrOfGpuBuffer(LayerCtrlContext* lc, ANativeWindowBuffer* pWindowBuf, ion_handle_abstract_t* pHandle_ion, uintptr_t* pPhyaddress) { ion_handle_abstract_t handle_ion = ION_NULL_VALUE; uintptr_t nPhyaddress = 0; int ret; #if defined(CONF_GPU_MALI) private_handle_t* hnd = (private_handle_t *)(pWindowBuf->handle); if(hnd != NULL) { ret = ion_import(lc->ionFd, hnd->share_fd, &handle_ion); if(ret < 0) { loge("ion_import fail, maybe the buffer was free by display!"); return -1; } } else { logd("the hnd is wrong : hnd = %p",hnd); return -1; } #elif defined(CONF_GPU_IMG) IMG_native_handle_t* hnd = (IMG_native_handle_t*)(pWindowBuf->handle); if(hnd != NULL) { ret = ion_import(lc->ionFd, hnd->fd[0], &handle_ion); if(ret < 0) { loge("ion_import fail, maybe the buffer was free by display!"); return -1; } } else { logd("the hnd is wrong : hnd = %p",hnd); return -1; } #else #error invalid GPU type config #endif //* we should not get the phyaddr if it is software decoder if(lc->bIsSoftDecoderFlag == 0) { if(lc->ionFd >= 0) nPhyaddress = CdcIonGetPhyAdr(lc->ionFd, (uintptr_t)handle_ion); else { logd("the ion fd is wrong : fd = %d",lc->ionFd); return -1; } nPhyaddress -= CONF_VE_PHY_OFFSET; } *pPhyaddress = nPhyaddress; *pHandle_ion = handle_ion; return 0; } int matchWindowBufferAndPicture(LayerCtrlContext* lc, ANativeWindowBuffer* pWindowBuf, char* pGpuVirBuf, VideoPicture** ppVideoPicture, int bInitFlag) { logv("matchWindowBufferAndPicture"); int i = 0; int ret = -1; uintptr_t nPhyaddress = 0; ion_handle_abstract_t handle_ion = ION_NULL_VALUE; VideoPicture* pPicture = NULL; for(i = 0; i < lc->nGpuBufferCount; i++) { if(lc->mGpuBufferInfo[i].pWindowBuf == NULL) { ret = getPhyAddrOfGpuBuffer(lc, pWindowBuf, &handle_ion, &nPhyaddress); if(ret == -1) { loge("getPhyAddrOfGpuBuffer failed"); return -1; } if(lc->bVideoWithTwoStreamFlag == 1) { initPartialGpuBuffer(pGpuVirBuf,pWindowBuf,lc); } lc->mGpuBufferInfo[i].pWindowBuf = pWindowBuf; lc->mGpuBufferInfo[i].handle_ion = handle_ion; lc->mGpuBufferInfo[i].pBufVirAddr = pGpuVirBuf; lc->mGpuBufferInfo[i].pBufPhyAddr = (char*)nPhyaddress; lc->mGpuBufferInfo[i].nUsedFlag = 1; lc->mGpuBufferInfo[i].nDequeueFlag = 1; break; } else if(lc->mGpuBufferInfo[i].pWindowBuf == pWindowBuf) { lc->mGpuBufferInfo[i].nUsedFlag = 1; lc->mGpuBufferInfo[i].nDequeueFlag = 1; break; } } if(i == lc->nGpuBufferCount) { loge("not enouth gpu buffer , should not run here"); abort(); } //* dequeue buffer for the first time, we should not dequeue from picNode if(bInitFlag == 1) { pPicture = *ppVideoPicture; //* set the buffer address pPicture->pData0 = lc->mGpuBufferInfo[i].pBufVirAddr; pPicture->pData1 = pPicture->pData0 + (pWindowBuf->height * pWindowBuf->stride); pPicture->pData2 = pPicture->pData1 + (pWindowBuf->height * pWindowBuf->stride)/4; pPicture->phyYBufAddr = (uintptr_t)lc->mGpuBufferInfo[i].pBufPhyAddr; pPicture->phyCBufAddr = pPicture->phyYBufAddr + (pWindowBuf->height * pWindowBuf->stride); pPicture->nBufId = i; pPicture->pPrivate = (void*)(uintptr_t)lc->mGpuBufferInfo[i].handle_ion; pPicture->ePixelFormat = lc->eDisplayPixelFormat; pPicture->nWidth = pWindowBuf->stride; pPicture->nHeight = pWindowBuf->height; pPicture->nLineStride = pWindowBuf->stride; if(lc->b4KAlignFlag == 1) { uintptr_t tmpAddr = (uintptr_t)pPicture->pData1; tmpAddr = (tmpAddr + 4095) & ~4095; pPicture->pData1 = (char *)tmpAddr; pPicture->phyCBufAddr = (pPicture->phyCBufAddr + 4095) & ~4095; } } else { for(i = 0; ipicNodes[i].bUsed,lc->picNodes[i].pPicture, lc->picNodes[i].pNodeWindowBuf, pWindowBuf); if(lc->picNodes[i].bUsed == 1 && lc->picNodes[i].pPicture != NULL && lc->picNodes[i].pNodeWindowBuf == pWindowBuf) { pPicture = lc->picNodes[i].pPicture ; lc->picNodes[i].bUsed = 0; break; } } if(i == NUM_OF_PICTURES_KEEP_IN_NODE) { loge("hava no unused picture in the picNode, pDataBuf = %p",pGpuVirBuf); return -1; } } *ppVideoPicture = pPicture; return 0; } static void __LayerRelease(LayerCtrl* l) { logd("__LayerRelease"); LayerCtrlContext* lc; VPictureNode* nodePtr; int i; int ret; VideoPicture mPicBufInfo; lc = (LayerCtrlContext*)l; memset(&mPicBufInfo, 0, sizeof(VideoPicture)); logd("LayerRelease, ionFd = %d",lc->ionFd); #if defined(CONF_SEND_BLACK_FRAME_TO_GPU) if (GetConfigParamterInt("black_pic_4_SP", 0) == 1) { if(lc->bProtectFlag == 0) { if(lc->bHoldLastPictureFlag == false && lc->pNativeWindow != NULL) { sendThreeBlackFrameToGpu(lc); makeSureBlackFrameToShow(lc); } } } #endif for(i = 0; i < lc->nGpuBufferCount; i++) { //* we should queue buffer which had dequeued to gpu if(lc->mGpuBufferInfo[i].nDequeueFlag == 1) { //* unlock the buffer. ANativeWindowBuffer* pWindowBuf = lc->mGpuBufferInfo[i].pWindowBuf; GraphicBufferMapper& graphicMapper = GraphicBufferMapper::get(); graphicMapper.unlock(pWindowBuf->handle); lc->pNativeWindow->cancelBuffer_DEPRECATED(lc->pNativeWindow, pWindowBuf); lc->mGpuBufferInfo[i].nDequeueFlag = 0; } if(lc->mGpuBufferInfo[i].handle_ion != ION_NULL_VALUE) { logd("ion_free: handle_ion[%d] = %p",i,lc->mGpuBufferInfo[i].handle_ion); ion_free(lc->ionFd,lc->mGpuBufferInfo[i].handle_ion); } lc->mGpuBufferInfo[i].pWindowBuf = NULL; lc->mGpuBufferInfo[i].nUsedFlag = 0; } for(i = 0; ipicNodes[i].bUsed = 0; } if(lc->bProtectFlag == 1 /*|| lc->bHoldLastPictureFlag == 0*/) { ret = pushBlankBuffersToNativeWindow(lc); if(ret != 0) { loge("pushBlankBuffersToNativeWindow appear error!: ret = %d",ret); } } } static void __LayerDestroy(LayerCtrl* l) { logd("__LayerDestroy"); LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; if(lc->ionFd >= 0) { ion_close(lc->ionFd); } #if (defined(CONF_PTS_TOSF) && (CONF_ANDROID_MAJOR_VER >= 5)) CdxVideoSchedulerDestroy(lc->mVideoScheduler); #endif free(lc); } //* Description: set initial param -- size of display static int __LayerSetDisplayBufferSize(LayerCtrl* l, int nWidth, int nHeight) { LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; logv("Layer set picture size, width = %d, height = %d", nWidth, nHeight); lc->nWidth = nWidth; lc->nHeight = nHeight; lc->nDisplayWidth = nWidth; lc->nDisplayHeight = nHeight; lc->nLeftOff = 0; lc->nTopOff = 0; lc->bLayerInitialized = 0; if(lc->bVideoWithTwoStreamFlag == 1) { //* display the whole buffer region when 3D //* as we had init align-edge-region to black. so it will be look ok. int nScaler = 2; lc->nDisplayHeight = lc->nDisplayHeight*nScaler; } return 0; } //* Description: set initial param -- buffer count static int __LayerSetDisplayBufferCount(LayerCtrl* l, int nBufferCount) { LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; logv("LayerSetBufferCount: count = %d",nBufferCount); lc->nGpuBufferCount = nBufferCount; if(lc->nGpuBufferCount > GPU_BUFFER_NUM) lc->nGpuBufferCount = GPU_BUFFER_NUM; return lc->nGpuBufferCount; } //* Description: set display region -- can set when video is playing static int __LayerSetDisplayRegion(LayerCtrl* l, int nLeftOff, int nTopOff, int nDisplayWidth, int nDisplayHeight) { LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; logv("Layer set display region, leftOffset = %d, topOffset = %d, displayWidth = %d, \ displayHeight = %d", nLeftOff, nTopOff, nDisplayWidth, nDisplayHeight); if(nDisplayWidth != 0 && nDisplayHeight != 0) { lc->nDisplayWidth = nDisplayWidth; lc->nDisplayHeight = nDisplayHeight; lc->nLeftOff = nLeftOff; lc->nTopOff = nTopOff; if(lc->bVideoWithTwoStreamFlag == 1) { //* display the whole buffer region when 3D //* as we had init align-edge-region to black. so it will be look ok. int nScaler = 2; lc->nDisplayHeight = lc->nHeight*nScaler; } if(lc->bLayerInitialized == 1) { Rect crop; crop.left = lc->nLeftOff; crop.top = lc->nTopOff; crop.right = lc->nLeftOff + lc->nDisplayWidth; crop.bottom = lc->nTopOff + lc->nDisplayHeight; lc->pNativeWindow->perform(lc->pNativeWindow, NATIVE_WINDOW_SET_CROP, &crop); } return 0; } else return -1; } //* Description: set initial param -- displayer pixel format static int __LayerSetDisplayPixelFormat(LayerCtrl* l, enum EPIXELFORMAT ePixelFormat) { LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; logv("Layer set expected pixel format, format = %d", (int)ePixelFormat); //* add new pixel formats supported by gpu here. if(ePixelFormat == PIXEL_FORMAT_NV12 || ePixelFormat == PIXEL_FORMAT_NV21 || ePixelFormat == PIXEL_FORMAT_YV12) { lc->eDisplayPixelFormat = ePixelFormat; } else { logv("receive pixel format is %d, not match.", lc->eDisplayPixelFormat); return -1; } //* on A83-pad and A83-box , the address should 4k align when format is NV21 #if defined(CONF_GPU_IMG) if(lc->eDisplayPixelFormat == PIXEL_FORMAT_NV21) lc->b4KAlignFlag = 1; #endif return 0; } //* Description: set initial param -- video whether have two stream or not static int __LayerSetVideoWithTwoStreamFlag(LayerCtrl* l, int bVideoWithTwoStreamFlag) { LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; logv("LayerSetIsTwoVideoStreamFlag, flag = %d",bVideoWithTwoStreamFlag); lc->bVideoWithTwoStreamFlag = bVideoWithTwoStreamFlag; return 0; } //* Description: set initial param -- whether picture-bitstream decoded by software decoder static int __LayerSetIsSoftDecoderFlag(LayerCtrl* l, int bIsSoftDecoderFlag) { LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; logv("LayerSetIsSoftDecoderFlag, flag = %d",bIsSoftDecoderFlag); lc->bIsSoftDecoderFlag = bIsSoftDecoderFlag; return 0; } //* Description: set buffer timestamp -- set this param every frame static int __LayerSetBufferTimeStamp(LayerCtrl* l, int64_t nPtsAbs) { LayerCtrlContext* lc; int64_t renderTime; lc = (LayerCtrlContext*)l; #if (defined(CONF_PTS_TOSF) && (CONF_ANDROID_MAJOR_VER >= 5)) static int nVsync = -1; renderTime = CdxVideoSchedulerSchedule(lc->mVideoScheduler, nPtsAbs); #if 0 //for debug static cdx_int64 prePts = -1; static cdx_int64 prePicPts = -1; if (prePts > 0) { logd("====[diff=%lld us, preRenderTime=%lld us, curRenderTime=%lld us]," "[diff=%lld, prePicPts=%lld us, nPtsAbs=%lld us]", (renderTime - prePts)/1000, prePts/1000, renderTime/1000, (nPtsAbs - prePicPts)/1000, prePicPts/1000, nPtsAbs/1000); } prePts = renderTime; prePicPts = nPtsAbs; #endif //attention! 4 vsync period is set after measured in h5(video before audio), //different platform may has different value. if (nVsync < 0) nVsync = GetConfigParamterInt("compensate_vsync", 4); renderTime += nVsync * CdxVideoSchedulerGetVsyncPeriod(lc->mVideoScheduler); #else renderTime = nPtsAbs; #endif native_window_set_buffers_timestamp(lc->pNativeWindow, renderTime); return 0; } //* Description: reset nativewindow -- need release old resource and init newer static void __LayerResetNativeWindow(LayerCtrl* l,void* pNativeWindow) { logd("LayerResetNativeWindow : %p ",pNativeWindow); LayerCtrlContext* lc; VideoPicture mPicBufInfo; lc = (LayerCtrlContext*)l; memset(&mPicBufInfo, 0, sizeof(VideoPicture)); //* we should queue buffer which had dequeued to gpu int i; for(i = 0; i < GPU_BUFFER_NUM; i++) { if(lc->mGpuBufferInfo[i].nDequeueFlag == 1) { //* unlock the buffer. ANativeWindowBuffer* pWindowBuf = lc->mGpuBufferInfo[i].pWindowBuf; GraphicBufferMapper& graphicMapper = GraphicBufferMapper::get(); graphicMapper.unlock(pWindowBuf->handle); lc->pNativeWindow->cancelBuffer_DEPRECATED(lc->pNativeWindow, pWindowBuf); lc->mGpuBufferInfo[i].nDequeueFlag = 0; } } memset(&lc->mGpuBufferInfo,0,sizeof(GpuBufferInfoT)*GPU_BUFFER_NUM); lc->pNativeWindow = (ANativeWindow*)pNativeWindow; if(lc->pNativeWindow != NULL) lc->bLayerInitialized = 0; return ; } //* Description: get the buffer which owned by nativewindow static VideoPicture* __LayerGetBufferOwnedByGpu(LayerCtrl* l) { LayerCtrlContext* lc; VideoPicture* pPicture = NULL; lc = (LayerCtrlContext*)l; for(int i = 0; ipicNodes[i].bUsed == 1) { lc->picNodes[i].bUsed = 0; pPicture = lc->picNodes[i].pPicture; break; } } return pPicture; } //* Description: get FPS(frames per second) of GPU //* Limitation: private implement for tvbox-platform static int __LayerGetDisplayFPS(LayerCtrl* l) { enum { DISPLAY_CMD_GETDISPFPS = 0x29, }; int dispFPS = 0; LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; #if defined(CONF_PRODUCT_STB) if(lc->pNativeWindow != NULL) dispFPS = lc->pNativeWindow->perform(lc->pNativeWindow, NATIVE_WINDOW_GETPARAMETER, DISPLAY_CMD_GETDISPFPS); #endif if (dispFPS <= 0) /* DISPLAY_CMD_GETDISPFPS not support, assume a nice fps */ dispFPS = 60; return dispFPS; } static int __LayerGetBufferNumHoldByGpu(LayerCtrl* l) { CDX_UNUSE(l); return GetConfigParamterInt("pic_4list_num", 3); } //* Description: make the video to show -- control the status of display static int __LayerCtrlShowVideo(LayerCtrl* l) { LayerCtrlContext* lc; int i; lc = (LayerCtrlContext*)l; logv("LayerCtrlShowVideo, current show flag = %d", lc->bLayerShowed); #if defined(CONF_PRODUCT_STB) if(lc->bLayerShowed == 0) { if(lc->pNativeWindow != NULL) { lc->bLayerShowed = 1; lc->pNativeWindow->perform(lc->pNativeWindow, NATIVE_WINDOW_SETPARAMETER, HWC_LAYER_SHOW, 1); } else { logw("the nativeWindow is null when call LayerCtrlShowVideo()"); return -1; } } #endif return 0; } //* Description: make the video to hide -- control the status of display static int __LayerCtrlHideVideo(LayerCtrl* l) { LayerCtrlContext* lc; int i; lc = (LayerCtrlContext*)l; logv("LayerCtrlHideVideo, current show flag = %d", lc->bLayerShowed); #if defined(CONF_PRODUCT_STB) if(lc->bLayerShowed == 1) { if(lc->pNativeWindow != NULL) { lc->bLayerShowed = 0; lc->pNativeWindow->perform(lc->pNativeWindow, NATIVE_WINDOW_SETPARAMETER, HWC_LAYER_SHOW, 0); } else { logw("the nativeWindow is null when call LayerCtrlHideVideo()"); return -1; } } #endif return 0; } //* Description: query whether the video is showing -- query the status of display static int __LayerCtrlIsVideoShow(LayerCtrl* l) { LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; logv("LayerCtrlIsVideoShow : bLayerShowed = %d",lc->bLayerShowed); return lc->bLayerShowed; } //* Description: make the last pic to show always when quit playback static int __LayerCtrlHoldLastPicture(LayerCtrl* l, int bHold) { logv("LayerCtrlHoldLastPicture, bHold = %d", bHold); //*TODO LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; lc->bHoldLastPictureFlag = bHold; return 0; } //* Description: the picture buf is secure static int __LayerSetSecure(LayerCtrl* l, int bSecure) { logv("__LayerSetSecure, bSecure = %d", bSecure); //*TODO LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; lc->bProtectFlag = bSecure; return 0; } //* Description: dequeue buffer from nativewindow static int __LayerDequeueBuffer(LayerCtrl* l,VideoPicture** ppVideoPicture, int bInitFlag) { logv("__LayerDequeueBuffer, *ppVideoPicture(%p),bInitFlag(%d)", *ppVideoPicture,bInitFlag); LayerCtrlContext* lc = (LayerCtrlContext*)l; ANativeWindowBuffer* pWindowBuf = NULL; void* pDataBuf = NULL; int err = -1; int i = 0; if(lc->pNativeWindow == NULL) { logw("pNativeWindow is null when dequeue buffer"); return -1; } if(lc->bLayerInitialized == 0) { if(setLayerParam(lc) != 0) { loge("can not initialize layer."); return -1; } lc->bLayerInitialized = 1; } //* we should make sure that the dequeue buffer is new when init if(bInitFlag == 1) { pWindowBuf = dequeueTheInitGpuBuffer(lc); if(pWindowBuf == NULL) { loge("*** dequeueTheInitGpuBuffer failed"); return -1; } } else { //* dequeue a buffer from the nativeWindow object. err = lc->pNativeWindow->dequeueBuffer_DEPRECATED(lc->pNativeWindow, &pWindowBuf); if(err != 0) { logw("dequeue buffer fail, return value from dequeueBuffer_DEPRECATED() method is %d.", err); return -1; } } //* lock the data buffer. lc->pNativeWindow->lockBuffer_DEPRECATED(lc->pNativeWindow, pWindowBuf); { GraphicBufferMapper& graphicMapper = GraphicBufferMapper::get(); Rect bounds(lc->nWidth, lc->nHeight); graphicMapper.lock(pWindowBuf->handle,lc->nUsage, bounds, &pDataBuf); } err = matchWindowBufferAndPicture(lc, pWindowBuf, (char*)pDataBuf, ppVideoPicture, bInitFlag); if(err == -1) { loge("matchWindowBufferAndPicture failed"); return -1; } return 0; } //* Description: queue buffer to nativewindow static int __LayerQueueBuffer(LayerCtrl* l,VideoPicture* pInPicture, int bValid) { logv("LayerQueueBuffer: pInPicture = %p, pData0 = %p", pInPicture,pInPicture->pData0); ANativeWindowBuffer* pWindowBuf = NULL; int i = 0; char* pBuf = NULL; int nBufId = -1; LayerCtrlContext* lc = (LayerCtrlContext*)l; if(lc->bLayerInitialized == 0) { if(setLayerParam(lc) != 0) { loge("can not initialize layer."); return -1; } lc->bLayerInitialized = 1; } for(i = 0; ipicNodes[i].bUsed == 0) { lc->picNodes[i].bUsed = 1; lc->picNodes[i].pPicture = pInPicture; break; } } if(i == NUM_OF_PICTURES_KEEP_IN_NODE) { loge("*** picNode is full when queue buffer"); return -1; } //loge("*** LayerQueueBuffer pInPicture = %p, bValid = %d",pInPicture,bValid); pBuf = (char*)pInPicture->phyYBufAddr; nBufId = pInPicture->nBufId; pWindowBuf = lc->mGpuBufferInfo[nBufId].pWindowBuf; lc->picNodes[i].pNodeWindowBuf = pWindowBuf; //* unlock the buffer. { GraphicBufferMapper& graphicMapper = GraphicBufferMapper::get(); graphicMapper.unlock(pWindowBuf->handle); } if(bValid == 1) lc->pNativeWindow->queueBuffer_DEPRECATED(lc->pNativeWindow, pWindowBuf); else lc->pNativeWindow->cancelBuffer_DEPRECATED(lc->pNativeWindow, pWindowBuf); lc->mGpuBufferInfo[nBufId].nDequeueFlag = 0; logv("******LayerQueueBuffer finish!"); return 0; } //* Description: release the buffer by ion static int __LayerReleaseBuffer(LayerCtrl* l,VideoPicture* pPicture) { logd("***LayerReleaseBuffer"); LayerCtrlContext* lc; lc = (LayerCtrlContext*)l; ion_handle_abstract_t handle_ion = ION_NULL_VALUE; handle_ion = (ion_handle_abstract_t)(uintptr_t)pPicture->pPrivate; ion_free(lc->ionFd,handle_ion); return 0; } static int __LayerReset(LayerCtrl* l) { LayerCtrlContext* lc; int i; lc = (LayerCtrlContext*)l; for(i = 0; i < lc->nGpuBufferCount; i++) { //* we should queue buffer which had dequeued to gpu if(lc->mGpuBufferInfo[i].nDequeueFlag == 1) { //* unlock the buffer. ANativeWindowBuffer* pWindowBuf = lc->mGpuBufferInfo[i].pWindowBuf; GraphicBufferMapper& graphicMapper = GraphicBufferMapper::get(); graphicMapper.unlock(pWindowBuf->handle); lc->pNativeWindow->cancelBuffer_DEPRECATED(lc->pNativeWindow, pWindowBuf); lc->mGpuBufferInfo[i].nDequeueFlag = 0; } if(lc->mGpuBufferInfo[i].handle_ion != ION_NULL_VALUE) { logd("ion_free: handle_ion[%d] = %p",i,lc->mGpuBufferInfo[i].handle_ion); ion_free(lc->ionFd,lc->mGpuBufferInfo[i].handle_ion); } lc->mGpuBufferInfo[i].pWindowBuf = NULL; lc->mGpuBufferInfo[i].nUsedFlag = 0; } for(i = 0; ipicNodes[i].bUsed = 0; } return 0; } static int __LayerControl(LayerCtrl* l, int cmd, void *para) { LayerCtrlContext *lc = (LayerCtrlContext*)l; CDX_UNUSE(para); switch(cmd) { #if (defined(CONF_PTS_TOSF) && (CONF_ANDROID_MAJOR_VER >= 5)) case CDX_LAYER_CMD_RESTART_SCHEDULER: { CdxVideoSchedulerRestart(lc->mVideoScheduler); break; } #endif default: break; } return 0; } static LayerControlOpsT mLayerControlOps = { .release = __LayerRelease , .setSecureFlag = __LayerSetSecure , .setDisplayBufferSize = __LayerSetDisplayBufferSize , .setDisplayBufferCount = __LayerSetDisplayBufferCount , .setDisplayRegion = __LayerSetDisplayRegion , .setDisplayPixelFormat = __LayerSetDisplayPixelFormat , .setVideoWithTwoStreamFlag = __LayerSetVideoWithTwoStreamFlag , .setIsSoftDecoderFlag = __LayerSetIsSoftDecoderFlag , .setBufferTimeStamp = __LayerSetBufferTimeStamp , .resetNativeWindow = __LayerResetNativeWindow , .getBufferOwnedByGpu = __LayerGetBufferOwnedByGpu , .getDisplayFPS = __LayerGetDisplayFPS , .getBufferNumHoldByGpu = __LayerGetBufferNumHoldByGpu , .ctrlShowVideo = __LayerCtrlShowVideo , .ctrlHideVideo = __LayerCtrlHideVideo , .ctrlIsVideoShow = __LayerCtrlIsVideoShow , .ctrlHoldLastPicture = __LayerCtrlHoldLastPicture , .dequeueBuffer = __LayerDequeueBuffer , .queueBuffer = __LayerQueueBuffer , .releaseBuffer = __LayerReleaseBuffer , .reset = __LayerReset , .destroy = __LayerDestroy , .control = __LayerControl }; LayerCtrl* LayerCreate(void* pNativeWindow) { logv("LayerInit."); LayerCtrlContext* lc; lc = (LayerCtrlContext*)malloc(sizeof(LayerCtrlContext)); if(lc == NULL) { loge("malloc memory fail."); return NULL; } memset(lc, 0, sizeof(LayerCtrlContext)); lc->ionFd = -1; lc->ionFd = ion_open(); logd("ion open fd = %d",lc->ionFd); if(lc->ionFd < -1) { loge("ion open fail ! "); return NULL; } lc->base.ops = &mLayerControlOps; lc->base.pNativeWindow = (void*)pNativeWindow; lc->pNativeWindow = (ANativeWindow*)pNativeWindow; #if (defined(CONF_PTS_TOSF) && (CONF_ANDROID_MAJOR_VER >= 5)) lc->mVideoScheduler = CdxVideoSchedulerCreate(); if (lc->mVideoScheduler == NULL) logw("CdxVideoSchedulerCreate failed"); #endif return (LayerCtrl*)&lc->base; }