libvideorender: CF2 new git for libvideorender [1/1]

PD#SWPL-134637

Problem:
new git for libvideorender

Solution:
new git for libvideorender

Verify:
ap222

Change-Id: I23196f65a8a94fe6244df5bb45d676623b10d8cc
Signed-off-by: fei.deng <fei.deng@amlogic.com>
diff --git a/videotunnel/videotunnel_impl.cpp b/videotunnel/videotunnel_impl.cpp
new file mode 100644
index 0000000..e824108
--- /dev/null
+++ b/videotunnel/videotunnel_impl.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2021 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 <errno.h>
+#include <poll.h>
+#include "videotunnel_plugin.h"
+#include "videotunnel_impl.h"
+#include "Logger.h"
+#include "Times.h"
+#include "video_tunnel.h"
+#include "videotunnel.h"
+
+using namespace Tls;
+
+#define TAG "rlib:videotunnel_impl"
+
+#define UNDER_FLOW_EXPIRED_TIME_MS 83
+
+
+VideoTunnelImpl::VideoTunnelImpl(VideoTunnelPlugin *plugin)
+    : mPlugin(plugin)
+{
+    mFd = -1;
+    mInstanceId = 0;
+    mIsVideoTunnelConnected = false;
+    mQueueFrameCnt = 0;
+    mStarted = false;
+    mRequestStop = false;
+    mVideotunnelLib = NULL;
+    mFrameWidth = 0;
+    mFrameHeight = 0;
+    mUnderFlowDetect = false;
+}
+
+VideoTunnelImpl::~VideoTunnelImpl()
+{
+}
+
+bool VideoTunnelImpl::init()
+{
+    mVideotunnelLib = videotunnelLoadLib();
+    if (!mVideotunnelLib) {
+        ERROR("videotunnelLoadLib load symbol fail");
+        return false;
+    }
+    return true;
+}
+
+bool VideoTunnelImpl::release()
+{
+    if (mVideotunnelLib) {
+        videotunnelUnloadLib(mVideotunnelLib);
+        mVideotunnelLib = NULL;
+    }
+    return true;
+}
+
+bool VideoTunnelImpl::connect()
+{
+    int ret;
+    DEBUG("in");
+    mRequestStop = false;
+    mSignalFirstFrameDiplayed = false;
+    if (mVideotunnelLib && mVideotunnelLib->vtOpen) {
+        mFd = mVideotunnelLib->vtOpen();
+    }
+    if (mFd > 0) {
+        //ret = meson_vt_alloc_id(mFd, &mInstanceId);
+    }
+    if (mFd > 0 && mInstanceId >= 0) {
+        if (mVideotunnelLib && mVideotunnelLib->vtConnect) {
+             ret = mVideotunnelLib->vtConnect(mFd, mInstanceId, VT_ROLE_PRODUCER);
+        }
+        mIsVideoTunnelConnected = true;
+    } else {
+        ERROR("open videotunnel fail or alloc id fail");
+        return false;
+    }
+    INFO("vt fd:%d, instance id:%d",mFd,mInstanceId);
+    DEBUG("out");
+    return true;
+}
+
+bool VideoTunnelImpl::disconnect()
+{
+    mRequestStop = true;
+    DEBUG("in");
+    if (isRunning()) {
+        requestExitAndWait();
+        mStarted = false;
+    }
+
+    if (mFd > 0) {
+        if (mIsVideoTunnelConnected) {
+            INFO("instance id:%d",mInstanceId);
+            if (mVideotunnelLib && mVideotunnelLib->vtDisconnect) {
+                mVideotunnelLib->vtDisconnect(mFd, mInstanceId, VT_ROLE_PRODUCER);
+            }
+            mIsVideoTunnelConnected = false;
+        }
+        if (mInstanceId >= 0) {
+            INFO("free instance id:%d",mInstanceId);
+            //meson_vt_free_id(mFd, mInstanceId);
+        }
+        INFO("close vt fd:%d",mFd);
+        if (mVideotunnelLib && mVideotunnelLib->vtClose) {
+            mVideotunnelLib->vtClose(mFd);
+        }
+        mFd = -1;
+    }
+
+    //flush all buffer those do not displayed
+    DEBUG("release all posted to videotunnel buffers");
+    std::lock_guard<std::mutex> lck(mMutex);
+    for (auto item = mQueueRenderBufferMap.begin(); item != mQueueRenderBufferMap.end(); ) {
+        RenderBuffer *renderbuffer = (RenderBuffer*) item->second;
+        mQueueRenderBufferMap.erase(item++);
+        mPlugin->handleFrameDropped(renderbuffer);
+        mPlugin->handleBufferRelease(renderbuffer);
+    }
+    DEBUG("out");
+    return true;
+}
+
+bool VideoTunnelImpl::displayFrame(RenderBuffer *buf, int64_t displayTime)
+{
+    int ret;
+    if (mStarted == false) {
+        DEBUG("to run VideoTunnelImpl");
+        run("VideoTunnelImpl");
+        mStarted = true;
+        mSignalFirstFrameDiplayed = true;
+    }
+
+    int fd0 = buf->dma.fd[0];
+    //leng.fang suggest fence id set -1
+    if (mVideotunnelLib && mVideotunnelLib->vtQueueBuffer) {
+        ret = mVideotunnelLib->vtQueueBuffer(mFd, mInstanceId, fd0, -1 /*fence_fd*/, displayTime);
+        if (mUnderFlowDetect) {
+            mUnderFlowDetect = false;
+        }
+    }
+
+    std::lock_guard<std::mutex> lck(mMutex);
+    std::pair<int, RenderBuffer *> item(fd0, buf);
+    mQueueRenderBufferMap.insert(item);
+    ++mQueueFrameCnt;
+    TRACE("***fd:%d,w:%d,h:%d,displaytime:%lld,commitCnt:%d",buf->dma.fd[0],buf->dma.width,buf->dma.height,displayTime,mQueueFrameCnt);
+    mPlugin->handleFrameDisplayed(buf);
+    mLastDisplayTime = Tls::Times::getSystemTimeMs();
+    return true;
+}
+
+void VideoTunnelImpl::flush()
+{
+    DEBUG("flush");
+    std::lock_guard<std::mutex> lck(mMutex);
+    if (mVideotunnelLib && mVideotunnelLib->vtCancelBuffer) {
+        mVideotunnelLib->vtCancelBuffer(mFd, mInstanceId);
+    }
+    for (auto item = mQueueRenderBufferMap.begin(); item != mQueueRenderBufferMap.end(); ) {
+        RenderBuffer *renderbuffer = (RenderBuffer*) item->second;
+        mQueueRenderBufferMap.erase(item++);
+        mPlugin->handleFrameDropped(renderbuffer);
+        mPlugin->handleBufferRelease(renderbuffer);
+    }
+    mQueueFrameCnt = 0;
+    DEBUG("after flush,commitCnt:%d",mQueueFrameCnt);
+}
+
+void VideoTunnelImpl::setFrameSize(int width, int height)
+{
+    mFrameWidth = width;
+    mFrameHeight = height;
+    DEBUG("set frame size, width:%d, height:%d",mFrameWidth,mFrameHeight);
+}
+
+void VideoTunnelImpl::setVideotunnelId(int id)
+{
+    mInstanceId = id;
+}
+
+void VideoTunnelImpl::waitFence(int fence) {
+    if (fence > 0) {
+        struct pollfd fds;
+
+        fds.fd = fence;
+        fds.events = POLLERR | POLLNVAL | POLLHUP |POLLIN | POLLPRI | POLLRDNORM;
+        fds.revents = 0;
+
+        for ( ; ; ) {
+            int rc = poll(&fds, 1, 3000);
+            if ((rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) {
+                continue;
+            } else if (rc <= 0) {
+                if (rc == 0) errno = ETIME;
+            }
+            break;
+        }
+        close(fence);
+        fence = -1;
+    }
+}
+
+void VideoTunnelImpl::readyToRun()
+{
+    struct vt_rect rect;
+
+    if (mFrameWidth > 0 && mFrameHeight > 0) {
+        rect.left = 0;
+        rect.top = 0;
+        rect.right = mFrameWidth;
+        rect.bottom = mFrameHeight;
+        if (mVideotunnelLib && mVideotunnelLib->vtSetSourceCrop) {
+            mVideotunnelLib->vtSetSourceCrop(mFd, mInstanceId, rect);
+        }
+    }
+}
+
+bool VideoTunnelImpl::threadLoop()
+{
+    int ret;
+    int bufferId = 0;
+    int fenceId;
+    RenderBuffer *buffer = NULL;
+
+    if (mRequestStop) {
+        DEBUG("request stop");
+        return false;
+    }
+    //if last frame expired,and not send frame to compositor for under flow expired time
+    //we need to send under flow msg
+    if (mQueueFrameCnt < 1 &&
+         Tls::Times::getSystemTimeMs() - mLastDisplayTime > UNDER_FLOW_EXPIRED_TIME_MS &&
+         !mUnderFlowDetect) {
+        mUnderFlowDetect = true;
+        mPlugin->handleMsgNotify(MSG_UNDER_FLOW, NULL);
+    }
+
+    if (mVideotunnelLib && mVideotunnelLib->vtDequeueBuffer) {
+        ret = mVideotunnelLib->vtDequeueBuffer(mFd, mInstanceId, &bufferId, &fenceId);
+    }
+
+    if (ret != 0) {
+        if (mRequestStop) {
+            DEBUG("request stop");
+            return false;
+        }
+        return true;
+    }
+    if (mRequestStop) {
+        DEBUG("request stop");
+        return false;
+    }
+
+    //send uvm fd to driver after getted fence
+    waitFence(fenceId);
+
+    {
+        std::lock_guard<std::mutex> lck(mMutex);
+        auto item = mQueueRenderBufferMap.find(bufferId);
+        if (item == mQueueRenderBufferMap.end()) {
+            ERROR("Not found in mQueueRenderBufferMap bufferId:%d",bufferId);
+            return true;
+        }
+        // try locking when removing item from mQueueRenderBufferMap
+        buffer = (RenderBuffer*) item->second;
+        mQueueRenderBufferMap.erase(bufferId);
+        --mQueueFrameCnt;
+        TRACE("***dq buffer fd:%d,commitCnt:%d",bufferId,mQueueFrameCnt);
+    }
+    //send first frame displayed msg
+    if (mSignalFirstFrameDiplayed) {
+        mSignalFirstFrameDiplayed = false;
+        INFO("send first frame displayed msg");
+        mPlugin->handleMsgNotify(MSG_FIRST_FRAME,(void*)&buffer->pts);
+    }
+    mPlugin->handleBufferRelease(buffer);
+    return true;
+}
\ No newline at end of file