837 lines
28 KiB
C++
837 lines
28 KiB
C++
/*
|
|
* 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 <fcntl.h>
|
|
#include <string.h>
|
|
#include <linux/videodev2.h>
|
|
#include "wstclient_wayland.h"
|
|
#include "wstclient_plugin.h"
|
|
#include "Logger.h"
|
|
#include "ErrorCode.h"
|
|
#include "aml_version.h"
|
|
|
|
#define TAG "rlib:wstClient_plugin"
|
|
#define DEFAULT_VIDEO_SERVER "video"
|
|
|
|
WstClientPlugin::WstClientPlugin(int logCategory)
|
|
: mFullscreen(true),
|
|
mLogCategory(logCategory)
|
|
{
|
|
mIsVideoPip = false;
|
|
mBufferFormat = VIDEO_FORMAT_UNKNOWN;
|
|
mNumDroppedFrames = 0;
|
|
mCommitFrameCnt = 0;
|
|
mReadyDisplayFrameCnt = 0;
|
|
mWayland = new WstClientWayland(this, logCategory);
|
|
mWstClientSocket = NULL;
|
|
mKeepLastFrame.isSet = false;
|
|
mKeepLastFrame.value = 0;
|
|
mKeepLastFrameOnFlush.isSet = false;
|
|
mKeepLastFrameOnFlush.value = 1;
|
|
mHideVideo.isSet = false;
|
|
mHideVideo.value = 0;
|
|
mSignalFirstFramePts = false;
|
|
mImmediatelyOutput = false;
|
|
mSetCropFrameRect = false;
|
|
mFrameRateFractionNum = 0;
|
|
mFrameRateFractionDenom = 0;
|
|
mFrameRateChanged = false;
|
|
#if defined(ESSOS_RM)
|
|
mWstEssRMgrOps = new WstEssRMgrOps(logCategory);
|
|
mWstEssRMgrOps->setCallback(WstClientPlugin::essMgrCallback, this);
|
|
#endif
|
|
}
|
|
|
|
WstClientPlugin::~WstClientPlugin()
|
|
{
|
|
if (mWayland) {
|
|
delete mWayland;
|
|
mWayland = NULL;
|
|
}
|
|
#if defined(ESSOS_RM)
|
|
if (mWstEssRMgrOps) {
|
|
delete mWstEssRMgrOps;
|
|
mWstEssRMgrOps = NULL;
|
|
}
|
|
#endif
|
|
|
|
TRACE(mLogCategory,"deconstruct");
|
|
}
|
|
|
|
void WstClientPlugin::init()
|
|
{
|
|
INFO(mLogCategory,"\n--------------------------------\n"
|
|
"plugin : westeros\n"
|
|
"ARCH : %s\n"
|
|
"branch name : %s\n"
|
|
"git version : %s\n"
|
|
"change id : %s \n"
|
|
"ID : %s \n"
|
|
"last changed: %s\n"
|
|
"build-time : %s\n"
|
|
"build-name : %s\n"
|
|
"level : /tmp \n"
|
|
"--------------------------------\n",
|
|
#if defined(__aarch64__)
|
|
"arm64",
|
|
#else
|
|
"arm",
|
|
#endif
|
|
BRANCH_NAME,
|
|
GIT_VERSION,
|
|
COMMIT_CHANGEID,
|
|
COMMIT_PD,
|
|
LAST_CHANGED,
|
|
BUILD_TIME,
|
|
BUILD_NAME
|
|
);
|
|
#if defined(ESSOS_RM)
|
|
mWstEssRMgrOps->resMgrInit();
|
|
#endif
|
|
}
|
|
|
|
void WstClientPlugin::release()
|
|
{
|
|
DEBUG(mLogCategory,"release");
|
|
#if defined(ESSOS_RM)
|
|
mWstEssRMgrOps->resMgrTerm();
|
|
#endif
|
|
}
|
|
|
|
void WstClientPlugin::setCallback(void *userData, PluginCallback *callback)
|
|
{
|
|
mUserData = userData;
|
|
mCallback = callback;
|
|
}
|
|
|
|
int WstClientPlugin::openDisplay()
|
|
{
|
|
int ret = 0;
|
|
|
|
DEBUG(mLogCategory,"openDisplay");
|
|
|
|
#if defined(ESSOS_RM)
|
|
mWstEssRMgrOps->resMgrRequestDecoder(mIsVideoPip);
|
|
#endif
|
|
|
|
//connect video server first
|
|
if (!mWstClientSocket) {
|
|
bool rc;
|
|
mWstClientSocket = new WstClientSocket(this, mLogCategory);
|
|
rc = mWstClientSocket->connectToSocket(DEFAULT_VIDEO_SERVER);
|
|
if (!rc) {
|
|
ERROR(mLogCategory,"Error connect to video server fail");
|
|
delete mWstClientSocket;
|
|
mWstClientSocket = NULL;
|
|
return ERROR_OPEN_FAIL;
|
|
}
|
|
}
|
|
|
|
if (mWstClientSocket) {
|
|
mWstClientSocket->sendLayerVideoClientConnection(mIsVideoPip);
|
|
mWstClientSocket->sendResourceVideoClientConnection(mIsVideoPip);
|
|
}
|
|
|
|
ret = mWayland->connectToWayland();
|
|
if (ret != NO_ERROR) {
|
|
ERROR(mLogCategory,"Error open display");
|
|
} else {
|
|
//run wl display queue dispatch
|
|
DEBUG(mLogCategory,"To run wl display dispatch queue");
|
|
mWayland->run("display queue");
|
|
}
|
|
|
|
DEBUG(mLogCategory,"openDisplay end");
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::openWindow()
|
|
{
|
|
int ret = NO_ERROR;
|
|
|
|
DEBUG(mLogCategory,"openWindow");
|
|
mCommitFrameCnt = 0;
|
|
mNumDroppedFrames = 0;
|
|
mReadyDisplayFrameCnt = 0;
|
|
mSignalFirstFramePts = false;
|
|
/*send session info to server
|
|
we use mediasync to sync a/v,so select AV_SYNC_MODE_VIDEO_MONO as av clock*/
|
|
if (mWstClientSocket) {
|
|
if (mImmediatelyOutput) {
|
|
mWstClientSocket->sendSessionInfoVideoClientConnection(INVALID_SESSION_ID, SYNC_IMMEDIATE);
|
|
} else {
|
|
mWstClientSocket->sendSessionInfoVideoClientConnection(AV_SYNC_SESSION_V_MONO, AV_SYNC_MODE_VIDEO_MONO);
|
|
}
|
|
}
|
|
|
|
//send hide video
|
|
if (mWstClientSocket && mHideVideo.isSet) {
|
|
mWstClientSocket->sendHideVideoClientConnection(mHideVideo.value);
|
|
}
|
|
|
|
//send keep last video frame
|
|
if (mWstClientSocket && mKeepLastFrame.isSet) {
|
|
mWstClientSocket->sendKeepLastFrameVideoClientConnection(mKeepLastFrame.value);
|
|
}
|
|
|
|
//send crop frame size if set before window opened
|
|
if (mSetCropFrameRect) {
|
|
setCropFrameRect();
|
|
}
|
|
|
|
DEBUG(mLogCategory,"openWindow,end");
|
|
return ret;
|
|
}
|
|
|
|
int WstClientPlugin::prepareFrame(RenderBuffer *buffer)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::displayFrame(RenderBuffer *buffer, int64_t displayTime)
|
|
{
|
|
bool ret;
|
|
WstBufferInfo wstBufferInfo;
|
|
WstRect wstRect;
|
|
int x,y,w,h;
|
|
|
|
if (buffer->flag & BUFFER_FLAG_LAST_EMPTY_BUFFER) {
|
|
DEBUG(mLogCategory,"ignore last buffer");
|
|
handleBufferRelease(buffer);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (mWstClientSocket && mFrameRateChanged) {
|
|
mFrameRateChanged = false;
|
|
mWstClientSocket->sendRateVideoClientConnection(mFrameRateFractionNum, mFrameRateFractionDenom);
|
|
}
|
|
|
|
mWayland->getVideoBounds(&x, &y, &w, &h);
|
|
|
|
//init wstBufferInfo,must set fd to -1 value
|
|
memset(&wstBufferInfo, 0, sizeof(WstBufferInfo));
|
|
for (int i = 0; i < WST_MAX_PLANES; i++) {
|
|
wstBufferInfo.planeInfo[0].fd = -1;
|
|
wstBufferInfo.planeInfo[1].fd = -1;
|
|
wstBufferInfo.planeInfo[2].fd = -1;
|
|
}
|
|
|
|
wstBufferInfo.bufferId = buffer->id;
|
|
wstBufferInfo.planeCount = buffer->dma.planeCnt;
|
|
TRACE(mLogCategory,"buffer width:%d,height:%d",buffer->dma.width,buffer->dma.height);
|
|
for (int i = 0; i < buffer->dma.planeCnt; i++) {
|
|
wstBufferInfo.planeInfo[i].fd = buffer->dma.fd[i];
|
|
wstBufferInfo.planeInfo[i].stride = buffer->dma.stride[i];
|
|
wstBufferInfo.planeInfo[i].offset = buffer->dma.offset[i];
|
|
DEBUG(mLogCategory,"buffer id:%d,plane[%d],fd:%d,stride:%d,offset:%d",buffer->id,i,buffer->dma.fd[i],buffer->dma.stride[i],buffer->dma.offset[i]);
|
|
}
|
|
|
|
wstBufferInfo.frameWidth = buffer->dma.width;
|
|
wstBufferInfo.frameHeight = buffer->dma.height;
|
|
wstBufferInfo.frameTime = displayTime;
|
|
|
|
//change render lib video format to v4l2 support format
|
|
if (mBufferFormat == VIDEO_FORMAT_NV12) {
|
|
wstBufferInfo.pixelFormat = V4L2_PIX_FMT_NV12;
|
|
} else if (mBufferFormat == VIDEO_FORMAT_NV21) {
|
|
wstBufferInfo.pixelFormat = V4L2_PIX_FMT_NV21;
|
|
} else {
|
|
ERROR(mLogCategory,"unknown video buffer format:%d",mBufferFormat);
|
|
}
|
|
|
|
wstRect.x = x;
|
|
wstRect.y = y;
|
|
wstRect.w = w;
|
|
wstRect.h = h;
|
|
|
|
if (mWstClientSocket) {
|
|
ret = mWstClientSocket->sendFrameVideoClientConnection(&wstBufferInfo, &wstRect);
|
|
if (!ret) {
|
|
ERROR(mLogCategory,"send video frame to server fail");
|
|
handleFrameDropped(buffer);
|
|
handleBufferRelease(buffer);
|
|
return ERROR_FAILED_TRANSACTION;
|
|
}
|
|
}
|
|
|
|
//storage render buffer to manager
|
|
std::lock_guard<std::mutex> lck(mRenderLock);
|
|
std::pair<int, RenderBuffer *> item(buffer->id, buffer);
|
|
mRenderBuffersMap.insert(item);
|
|
++mCommitFrameCnt;
|
|
++mReadyDisplayFrameCnt;
|
|
TRACE(mLogCategory,"committed to westeros cnt:%d,readyDisplayFramesCnt:%d",mCommitFrameCnt,mReadyDisplayFrameCnt);
|
|
|
|
//storage displayed render buffer
|
|
std::pair<int, int64_t> displayitem(buffer->id, displayTime);
|
|
mDisplayedFrameMap.insert(displayitem);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::flush()
|
|
{
|
|
int ret;
|
|
INFO(mLogCategory,"flush");
|
|
if (mWstClientSocket) {
|
|
mWstClientSocket->sendFlushVideoClientConnection(mKeepLastFrameOnFlush.value);
|
|
}
|
|
//drop frames those had committed to westeros
|
|
std::lock_guard<std::mutex> lck(mRenderLock);
|
|
for (auto item = mDisplayedFrameMap.begin(); item != mDisplayedFrameMap.end(); ) {
|
|
int bufferid = (int)item->first;
|
|
auto bufItem = mRenderBuffersMap.find(bufferid);
|
|
if (bufItem == mRenderBuffersMap.end()) {
|
|
continue;
|
|
}
|
|
mDisplayedFrameMap.erase(item++);
|
|
RenderBuffer *renderbuffer = (RenderBuffer*) bufItem->second;
|
|
if (renderbuffer) {
|
|
handleFrameDropped(renderbuffer);
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::pause()
|
|
{
|
|
int ret;
|
|
INFO(mLogCategory,"pause");
|
|
if (mWstClientSocket) {
|
|
int waitCnt = 20; //we wait about 10 vsync duration
|
|
while (mReadyDisplayFrameCnt != 0 && waitCnt > 0) {
|
|
usleep(8000);
|
|
--waitCnt;
|
|
}
|
|
std::lock_guard<std::mutex> lck(mRenderLock);
|
|
if (mReadyDisplayFrameCnt == 0) { //send pause cmd immediatialy if no frame displays
|
|
mWstClientSocket->sendPauseVideoClientConnection(true);
|
|
}
|
|
}
|
|
mWayland->setPause(true);
|
|
#if defined(ESSOS_RM)
|
|
mWstEssRMgrOps->resMgrUpdateState(EssRMgrRes_paused);
|
|
#endif
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::resume()
|
|
{
|
|
int ret;
|
|
INFO(mLogCategory,"resume");
|
|
std::lock_guard<std::mutex> lck(mRenderLock);
|
|
if (mWstClientSocket) {
|
|
mWstClientSocket->sendPauseVideoClientConnection(false);
|
|
}
|
|
mWayland->setPause(false);
|
|
#if defined(ESSOS_RM)
|
|
mWstEssRMgrOps->resMgrUpdateState(EssRMgrRes_active);
|
|
#endif
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::closeDisplay()
|
|
{
|
|
INFO(mLogCategory,"closeDisplay, in");
|
|
mWayland->disconnectFromWayland();
|
|
INFO(mLogCategory,"closeDisplay, out");
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::closeWindow()
|
|
{
|
|
DEBUG(mLogCategory,"closeWindow, in");
|
|
if (mWstClientSocket) {
|
|
mWstClientSocket->disconnectFromSocket();
|
|
delete mWstClientSocket;
|
|
mWstClientSocket = NULL;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lck(mRenderLock);
|
|
//drop all frames those don't displayed
|
|
for (auto item = mDisplayedFrameMap.begin(); item != mDisplayedFrameMap.end(); ) {
|
|
int bufferid = (int)item->first;
|
|
auto bufItem = mRenderBuffersMap.find(bufferid);
|
|
if (bufItem == mRenderBuffersMap.end()) {
|
|
continue;
|
|
}
|
|
mDisplayedFrameMap.erase(item++);
|
|
RenderBuffer *renderbuffer = (RenderBuffer*) bufItem->second;
|
|
if (renderbuffer) {
|
|
handleFrameDropped(renderbuffer);
|
|
}
|
|
}
|
|
//release all frames those had committed to westeros server
|
|
for (auto item = mRenderBuffersMap.begin(); item != mRenderBuffersMap.end();) {
|
|
RenderBuffer *renderbuffer = (RenderBuffer*) item->second;
|
|
mRenderBuffersMap.erase(item++);
|
|
if (renderbuffer) {
|
|
handleBufferRelease(renderbuffer);
|
|
}
|
|
}
|
|
#if defined(ESSOS_RM)
|
|
mWstEssRMgrOps->resMgrUpdateState(EssRMgrRes_idle);
|
|
mWstEssRMgrOps->resMgrReleaseDecoder();
|
|
#endif
|
|
mRenderBuffersMap.clear();
|
|
mDisplayedFrameMap.clear();
|
|
mCommitFrameCnt = 0;
|
|
mNumDroppedFrames = 0;
|
|
mReadyDisplayFrameCnt = 0;
|
|
mImmediatelyOutput = false;
|
|
DEBUG(mLogCategory,"out");
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::getValue(PluginKey key, void *value)
|
|
{
|
|
switch (key) {
|
|
case PLUGIN_KEY_KEEP_LAST_FRAME: {
|
|
*(int *)value = mKeepLastFrame.value;
|
|
TRACE(mLogCategory,"get keep last frame:%d",*(int *)value);
|
|
} break;
|
|
case PLUGIN_KEY_KEEP_LAST_FRAME_ON_FLUSH: {
|
|
*(int *)value = mKeepLastFrameOnFlush.value;
|
|
TRACE(mLogCategory,"get keep last frame on flush:%d",*(int *)value);
|
|
} break;
|
|
case PLUGIN_KEY_HIDE_VIDEO: {
|
|
*(int *)value = mHideVideo.value;
|
|
TRACE(mLogCategory,"get hide video:%d",*(int *)value);
|
|
} break;
|
|
case PLUGIN_KEY_CROP_FRAME_SIZE: {
|
|
RenderRect* rect = static_cast<RenderRect*>(value);
|
|
rect->x = mCropFrameRect.x;
|
|
rect->y = mCropFrameRect.y;
|
|
rect->w = mCropFrameRect.w;
|
|
rect->h = mCropFrameRect.h;
|
|
} break;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::setValue(PluginKey key, void *value)
|
|
{
|
|
switch (key) {
|
|
case PLUGIN_KEY_WINDOW_SIZE: {
|
|
RenderRect* rect = static_cast<RenderRect*>(value);
|
|
if (mWayland) {
|
|
mWayland->setWindowSize(rect->x, rect->y, rect->w, rect->h);
|
|
}
|
|
} break;
|
|
case PLUGIN_KEY_FRAME_SIZE: {
|
|
RenderFrameSize * frameSize = static_cast<RenderFrameSize * >(value);
|
|
if (mWayland) {
|
|
mWayland->setFrameSize(frameSize->width, frameSize->height);
|
|
}
|
|
//if set crop property before set frame size,we set crop params now, because
|
|
//crop property dependent frame size
|
|
if (mSetCropFrameRect) {
|
|
setCropFrameRect();
|
|
}
|
|
} break;
|
|
case PLUGIN_KEY_VIDEO_FORMAT: {
|
|
int format = *(int *)(value);
|
|
mBufferFormat = (RenderVideoFormat) format;
|
|
DEBUG(mLogCategory,"Set video format :%d",mBufferFormat);
|
|
} break;
|
|
case PLUGIN_KEY_VIDEO_PIP: {
|
|
int pip = *(int *) (value);
|
|
mIsVideoPip = pip > 0? true:false;
|
|
} break;
|
|
case PLUGIN_KEY_KEEP_LAST_FRAME: {
|
|
int keep = *(int *) (value);
|
|
mKeepLastFrame.value = keep > 0? true:false;
|
|
mKeepLastFrame.isSet = true;
|
|
DEBUG(mLogCategory, "Set keep last frame :%d",mKeepLastFrame.value);
|
|
if (mWstClientSocket) {
|
|
mWstClientSocket->sendKeepLastFrameVideoClientConnection(mKeepLastFrame.value);
|
|
}
|
|
} break;
|
|
case PLUGIN_KEY_KEEP_LAST_FRAME_ON_FLUSH: {
|
|
int keepOnFlush = *(int *) (value);
|
|
mKeepLastFrameOnFlush.value = keepOnFlush > 0? true:false;
|
|
mKeepLastFrameOnFlush.isSet = true;
|
|
DEBUG(mLogCategory, "Set keep last frame on flush :%d",mKeepLastFrameOnFlush.value);
|
|
} break;
|
|
case PLUGIN_KEY_HIDE_VIDEO: {
|
|
int hide = *(int *)(value);
|
|
mHideVideo.value = hide > 0? true:false;
|
|
mHideVideo.isSet = true;
|
|
DEBUG(mLogCategory, "Set hide video:%d",mHideVideo.value);
|
|
if (mWstClientSocket) {
|
|
mWstClientSocket->sendHideVideoClientConnection(mHideVideo.value);
|
|
}
|
|
} break;
|
|
case PLUGIN_KEY_FORCE_ASPECT_RATIO: {
|
|
int forceAspectRatio = *(int *)(value);
|
|
if (mWayland) {
|
|
mWayland->setForceAspectRatio(forceAspectRatio > 0? true:false);
|
|
}
|
|
} break;
|
|
case PLUGIN_KEY_IMMEDIATELY_OUTPUT: {
|
|
int immediately = *(int *)(value);
|
|
mImmediatelyOutput = immediately > 0? true: false;
|
|
DEBUG(mLogCategory,"Set immediately output:%d",mImmediatelyOutput);
|
|
if (mImmediatelyOutput && mWstClientSocket) {
|
|
mWstClientSocket->sendSessionInfoVideoClientConnection(INVALID_SESSION_ID, SYNC_IMMEDIATE);
|
|
}
|
|
} break;
|
|
case PLUGIN_KEY_CROP_FRAME_SIZE: {
|
|
RenderRect* rect = static_cast<RenderRect*>(value);
|
|
mCropFrameRect.x = rect->x;
|
|
mCropFrameRect.y = rect->y;
|
|
mCropFrameRect.w = rect->w;
|
|
mCropFrameRect.h = rect->h;
|
|
mSetCropFrameRect = true;
|
|
INFO(mLogCategory,"crop params (%d,%d,%d,%d)",rect->x,rect->y,rect->w,rect->h);
|
|
setCropFrameRect();
|
|
} break;
|
|
case PLUGIN_KEY_PIXEL_ASPECT_RATIO: {
|
|
double ratio = *(double *)(value);
|
|
INFO(mLogCategory,"pixel aspect ratio :%f",ratio);
|
|
if (mWayland) {
|
|
mWayland->setPixelAspectRatio((double)ratio);
|
|
}
|
|
} break;
|
|
case PLUGIN_KEY_VIDEO_FRAME_RATE: {
|
|
RenderFraction * fraction = static_cast<RenderFraction*>(value);
|
|
INFO(mLogCategory,"frame rate,num:%d,denom:%d",fraction->num,fraction->denom);
|
|
if (fraction->num != mFrameRateFractionNum ||
|
|
fraction->denom != mFrameRateFractionDenom) {
|
|
mFrameRateFractionNum = fraction->num;
|
|
mFrameRateFractionDenom = fraction->denom;
|
|
if (mFrameRateFractionDenom == 0) {
|
|
mFrameRateFractionDenom = 1;
|
|
}
|
|
mFrameRateChanged = true;
|
|
}
|
|
if (mWstClientSocket && mFrameRateChanged) {
|
|
mFrameRateChanged = false;
|
|
mWstClientSocket->sendRateVideoClientConnection(mFrameRateFractionNum, mFrameRateFractionDenom);
|
|
}
|
|
} break;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int WstClientPlugin::unexpectReleaseFrame(RenderBuffer *buffer)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
void WstClientPlugin::handleBufferRelease(RenderBuffer *buffer)
|
|
{
|
|
if (mCallback) {
|
|
mCallback->doBufferReleaseCallback(mUserData, (void *)buffer);
|
|
}
|
|
}
|
|
|
|
void WstClientPlugin::handleFrameDisplayed(RenderBuffer *buffer)
|
|
{
|
|
if (mCallback) {
|
|
mCallback->doBufferDisplayedCallback(mUserData, (void *)buffer);
|
|
}
|
|
}
|
|
|
|
void WstClientPlugin::handleFrameDropped(RenderBuffer *buffer)
|
|
{
|
|
if (mCallback) {
|
|
mCallback->doBufferDroppedCallback(mUserData, (void *)buffer);
|
|
}
|
|
}
|
|
|
|
void WstClientPlugin::handleMsgNotify(int type, void *detail)
|
|
{
|
|
if (mCallback) {
|
|
mCallback->doMsgCallback(mUserData, type, detail);
|
|
}
|
|
}
|
|
|
|
void WstClientPlugin::essMgrCallback(int event, void *userData)
|
|
{
|
|
#if defined(ESSOS_RM)
|
|
WstClientPlugin *plugin = static_cast<WstClientPlugin *>(userData);
|
|
switch ( event )
|
|
{
|
|
case EssRMgrEvent_granted: {
|
|
DEBUG(plugin->mLogCategory,"essmgr notify granted");
|
|
plugin->openDisplay();
|
|
plugin->openWindow();
|
|
} break;
|
|
case EssRMgrEvent_revoked: {
|
|
WARNING(plugin->mLogCategory,"essos notify revoked ");
|
|
plugin->closeWindow();
|
|
plugin->closeDisplay();
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void WstClientPlugin::setVideoRect(int videoX, int videoY, int videoWidth, int videoHeight)
|
|
{
|
|
if (mWstClientSocket) {
|
|
mWstClientSocket->sendRectVideoClientConnection(videoX, videoY, videoWidth, videoHeight);
|
|
}
|
|
}
|
|
|
|
void WstClientPlugin::onWstSocketEvent(WstEvent *event)
|
|
{
|
|
ATools::Mutex::Autolock _l(mMutex);
|
|
switch (event->event)
|
|
{
|
|
case WST_REFRESH_RATE: {
|
|
int rate = event->param;
|
|
INFO(mLogCategory,"refresh rate:%d",rate);
|
|
} break;
|
|
case WST_BUFFER_RELEASE: {
|
|
int bufferid = event->param;
|
|
TRACE(mLogCategory,"Buffer release id:%d",bufferid);
|
|
RenderBuffer *renderbuffer = NULL;
|
|
bool isDropped = false;
|
|
int64_t displaytime = 0;
|
|
{
|
|
std::lock_guard<std::mutex> lck(mRenderLock);
|
|
auto renderBufferItem = mRenderBuffersMap.find(bufferid);
|
|
if (renderBufferItem == mRenderBuffersMap.end()) {
|
|
WARNING(mLogCategory,"can't find map Renderbuffer");
|
|
return ;
|
|
}
|
|
--mCommitFrameCnt;
|
|
renderbuffer = (RenderBuffer*) renderBufferItem->second;
|
|
//remove had release render buffer
|
|
mRenderBuffersMap.erase(bufferid);
|
|
auto displayFrameItem = mDisplayedFrameMap.find(bufferid);
|
|
if (displayFrameItem != mDisplayedFrameMap.end()) {
|
|
mDisplayedFrameMap.erase(bufferid);
|
|
--mReadyDisplayFrameCnt;
|
|
isDropped = true;
|
|
displaytime = (int64_t)displayFrameItem->second;
|
|
}
|
|
}
|
|
|
|
if (renderbuffer) {
|
|
/*if we can find item in mDisplayedFrameMap,
|
|
this buffer is dropped by westeros server,so we
|
|
must call displayed callback*/
|
|
if (isDropped) {
|
|
WARNING(mLogCategory,"Frame droped,pts:%lld us,displaytime:%lld,readyDisplayFramesCnt:%d",\
|
|
renderbuffer->pts/1000,displaytime,mReadyDisplayFrameCnt);
|
|
handleFrameDropped(renderbuffer);
|
|
}
|
|
handleBufferRelease(renderbuffer);
|
|
}
|
|
TRACE(mLogCategory,"remain on westeros cnt:%d",mCommitFrameCnt);
|
|
} break;
|
|
case WST_STATUS: {
|
|
int dropframes = event->param;
|
|
int64_t frameTime = event->lparam;
|
|
TRACE(mLogCategory,"WST_STATUS,dropframes:%d,frameTime:%lld",dropframes,frameTime);
|
|
RenderBuffer *renderbuffer = NULL;
|
|
if (mNumDroppedFrames != event->param) {
|
|
mNumDroppedFrames = event->param;
|
|
WARNING(mLogCategory,"frame dropped cnt:%d",mNumDroppedFrames);
|
|
}
|
|
//update status,if frameTime isn't equal -1LL
|
|
//this buffer had displayed
|
|
if (frameTime != -1LL) {
|
|
std::lock_guard<std::mutex> lck(mRenderLock);
|
|
--mReadyDisplayFrameCnt;
|
|
TRACE(mLogCategory,"displayed frame time:%lld,readyDisplayFramesCnt:%d",frameTime,mReadyDisplayFrameCnt);
|
|
int bufferId = getDisplayFrameBufferId(frameTime);
|
|
if (bufferId < 0) {
|
|
WARNING(mLogCategory,"can't find map displayed frame:%lld",frameTime);
|
|
return ;
|
|
}
|
|
auto displayItem = mDisplayedFrameMap.find(bufferId);
|
|
if (displayItem != mDisplayedFrameMap.end()) {
|
|
mDisplayedFrameMap.erase(bufferId);
|
|
}
|
|
auto item = mRenderBuffersMap.find(bufferId);
|
|
if (item != mRenderBuffersMap.end()) {
|
|
renderbuffer = (RenderBuffer*) item->second;
|
|
}
|
|
}
|
|
if (renderbuffer) {
|
|
//first frame signal
|
|
if (!mSignalFirstFramePts) {
|
|
mSignalFirstFramePts = true;
|
|
INFO(mLogCategory, "post first frame");
|
|
handleMsgNotify(MSG_FIRST_FRAME,(void*)&renderbuffer->pts);
|
|
}
|
|
handleFrameDisplayed(renderbuffer);
|
|
}
|
|
} break;
|
|
case WST_UNDERFLOW: {
|
|
uint64_t frameTime = event->lparam;
|
|
TRACE(mLogCategory,"under flow frametime:%lld",frameTime);
|
|
//under flow event sended must be after sending first frame to westeros
|
|
if (mSignalFirstFramePts) {
|
|
handleMsgNotify(MSG_UNDER_FLOW, NULL);
|
|
}
|
|
} break;
|
|
case WST_ZOOM_MODE: {
|
|
int mode = event->param;
|
|
bool globalZoomActive = event->param1 > 0? true:false;
|
|
bool allow4kZoom = event->param2 > 0? true:false;;
|
|
mWayland->setZoomMode(mode, globalZoomActive, allow4kZoom);
|
|
} break;
|
|
case WST_DEBUG_LEVEL: {
|
|
/* code */
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int WstClientPlugin::getDisplayFrameBufferId(int64_t displayTime)
|
|
{
|
|
int bufId = -1;
|
|
for (auto item = mDisplayedFrameMap.begin(); item != mDisplayedFrameMap.end(); item++) {
|
|
int64_t time = (int64_t)item->second;
|
|
if (time == displayTime) {
|
|
bufId = (int)item->first;
|
|
break;
|
|
}
|
|
}
|
|
return bufId;
|
|
}
|
|
|
|
bool WstClientPlugin::setCropFrameRect()
|
|
{
|
|
if (mWayland) {
|
|
int frameWidth,frameHeight;
|
|
mWayland->getFrameSize(&frameWidth, &frameHeight);
|
|
if (frameWidth <= 0 || frameHeight <= 0) {
|
|
WARNING(mLogCategory, "no set video frame size,set crop params later");
|
|
goto bad_param;
|
|
}
|
|
|
|
//correct crop rect if needed
|
|
if (frameWidth > 0 && (mCropFrameRect.x + mCropFrameRect.w) > frameWidth) {
|
|
if (mCropFrameRect.x < frameWidth) {
|
|
int oriX = mCropFrameRect.x;
|
|
int oriW = mCropFrameRect.w;
|
|
mCropFrameRect.w = frameWidth - mCropFrameRect.x;
|
|
WARNING(mLogCategory, "correct crop x:%d, w:%d to x:%d, w:%d", \
|
|
oriX,oriW,mCropFrameRect.x,mCropFrameRect.w);
|
|
} else {
|
|
ERROR(mLogCategory, "Error crop params (%d,%d,%d,%d) frame(%d,%d)", \
|
|
mCropFrameRect.x,mCropFrameRect.y,mCropFrameRect.w,mCropFrameRect.h,frameWidth,frameHeight);
|
|
goto bad_param;
|
|
}
|
|
}
|
|
if (frameHeight > 0 && (mCropFrameRect.y + mCropFrameRect.h) > frameHeight) {
|
|
if (mCropFrameRect.y < frameHeight) {
|
|
int oriY = mCropFrameRect.x;
|
|
int oriH = mCropFrameRect.w;
|
|
mCropFrameRect.h = frameHeight - mCropFrameRect.y;
|
|
WARNING(mLogCategory, "correct crop y:%d, h:%d to y:%d, h:%d", \
|
|
oriY,oriH,mCropFrameRect.y,mCropFrameRect.h);
|
|
} else {
|
|
ERROR(mLogCategory, "Error crop params (%d,%d,%d,%d) frame(%d,%d)", \
|
|
mCropFrameRect.x,mCropFrameRect.y,mCropFrameRect.w,mCropFrameRect.h,frameWidth,frameHeight);
|
|
goto bad_param;
|
|
}
|
|
}
|
|
INFO(mLogCategory, "crop (%d,%d,%d,%d)", \
|
|
mCropFrameRect.x,mCropFrameRect.y,mCropFrameRect.w,mCropFrameRect.h);
|
|
}
|
|
if (mWstClientSocket && mSetCropFrameRect) {
|
|
mWstClientSocket->sendCropFrameSizeClientConnection(mCropFrameRect.x, mCropFrameRect.y, mCropFrameRect.w, mCropFrameRect.h);
|
|
mSetCropFrameRect = false;
|
|
}
|
|
return true;
|
|
bad_param:
|
|
return false;
|
|
}
|
|
|
|
void *makePluginInstance(int id)
|
|
{
|
|
int fd= -1;
|
|
const char *levelPath = "/tmp/rlib_plugin_level";
|
|
const char *filePath = "/tmp/rlib_plugin_file";
|
|
|
|
int category =ALogger_init(id);
|
|
char *env = getenv("VIDEO_RENDER_PLUGIN_LOG_LEVEL");
|
|
if (env) {
|
|
int level = atoi(env);
|
|
ALogger_set_level(level);
|
|
INFO(category,"env set VIDEO_RENDER_PLUGIN_LOG_LEVEL=%d",level);
|
|
}
|
|
|
|
env = getenv("VIDEO_RENDER_PLUGIN_LOG_FILE");
|
|
if (env && strlen(env) > 0) {
|
|
ALogger_set_file(env);
|
|
INFO(category,"env set VIDEO_RENDER_PLUGIN_LOG_FILE=%s",env);
|
|
}
|
|
|
|
//get log file from /tmp/rlib_plugin_file
|
|
fd = open(filePath, O_RDONLY|O_CLOEXEC);
|
|
if ( fd >= 0 )
|
|
{
|
|
char valstr[64];
|
|
int ret;
|
|
|
|
memset(valstr, 0, sizeof(valstr));
|
|
ret = read(fd, valstr, sizeof(valstr) - 1);
|
|
if (ret > 0) {
|
|
valstr[strlen(valstr)] = '\0';
|
|
if (strlen(valstr) > 0) {
|
|
if (valstr[strlen(valstr) -1] == '\n')
|
|
valstr[strlen(valstr) -1] = '\0';
|
|
ALogger_set_file(valstr);
|
|
INFO(category,"VIDEO_RENDER_PLUGIN_LOG_FILE=%s",valstr);
|
|
}
|
|
}
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
|
|
//get log level from /tmp/rlib_plugin_level
|
|
fd= open(levelPath, O_RDONLY|O_CLOEXEC);
|
|
if ( fd >= 0 )
|
|
{
|
|
char valstr[64];
|
|
uint32_t val= 0;
|
|
int nRead;
|
|
|
|
memset(valstr, 0, sizeof(valstr));
|
|
nRead = read(fd, valstr, sizeof(valstr) - 1);
|
|
valstr[strlen(valstr)] = '\0';
|
|
if (sscanf(valstr, "%u", &val) > 0)
|
|
{
|
|
ALogger_set_level(val);
|
|
INFO(category,"set VIDEO_RENDER_PLUGIN_LOG_LEVEL=%d",val);
|
|
}
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
WstClientPlugin *pluginInstance = new WstClientPlugin(category);
|
|
return static_cast<void *>(pluginInstance);
|
|
}
|
|
|
|
void destroyPluginInstance(void * plugin)
|
|
{
|
|
int category;
|
|
|
|
WstClientPlugin *pluginInstance = static_cast<WstClientPlugin *>(plugin);
|
|
category = pluginInstance->getLogCategory();
|
|
delete pluginInstance;
|
|
ALogger_exit(category);
|
|
}
|