674 lines
23 KiB
C++
674 lines
23 KiB
C++
/*
|
|
* Copyright (c) 2021 Amlogic, Inc. All rights reserved.
|
|
*
|
|
* This source code is subject to the terms and conditions defined in the
|
|
* file 'LICENSE' which is part of this source code package.
|
|
*
|
|
* Description:
|
|
*/
|
|
#define LOG_NDEBUG 1
|
|
|
|
#include <cinttypes>
|
|
#include <chrono>
|
|
#include <string.h>
|
|
#include <DebugHelper.h>
|
|
#include "VtInstance.h"
|
|
#include "VtAllocSolidColorBuffer.h"
|
|
#ifndef LINUX_COMPILE
|
|
#include <HwcConfig.h>
|
|
#endif
|
|
|
|
#define VTINST_LOGV(fmt,...) MESON_LOGV("[%s] [%s] " fmt, mName, __func__, ##__VA_ARGS__)
|
|
#define VTINST_LOGD(fmt,...) MESON_LOGD("[%s] [%s] " fmt, mName, __func__, ##__VA_ARGS__)
|
|
#define VTINST_LOGW(fmt,...) MESON_LOGW("[%s] [%s] " fmt, mName, __func__, ##__VA_ARGS__)
|
|
#define VTINST_LOGE(fmt,...) MESON_LOGE("[%s] [%s] " fmt, mName, __func__, ##__VA_ARGS__)
|
|
|
|
namespace {
|
|
constexpr int kReleaseThreadPollMs = 16;
|
|
}
|
|
|
|
VtInstance::VtInstance(int tunnelId)
|
|
: mTunnelId(tunnelId),
|
|
mVideoTunnelDev(VideoTunnelDev::getInstance()),
|
|
mSolidBufferAllocator(VtAllocSolidColorBuffer::getInstance()),
|
|
mOwnsDefaultDependencies(false),
|
|
mReleaseThreadExit(false),
|
|
mReleaseThreadCreated(false),
|
|
mReleaseThread(0) {
|
|
mConsumers.clear();
|
|
mRefreshConsumers.clear();
|
|
mBufferQueue.clear();
|
|
memset(&mCrop, 0, sizeof(vt_rect_t));
|
|
snprintf(mName, 64, "VtInstance-%d", tunnelId);
|
|
memset(&mLastData, 0, sizeof(last_data_t));
|
|
mLastData.videoStatus = VT_VIDEO_STATUS_SHOW;
|
|
mLastData.solidBufferType = SOLID_COLOR_FOR_INVALID;
|
|
}
|
|
|
|
// New constructor with dependency injection (for testing)
|
|
VtInstance::VtInstance(int tunnelId,
|
|
VideoTunnelDev& videoTunnelDev,
|
|
ISolidColorBufferAllocator& solidBufferAllocator)
|
|
: mTunnelId(tunnelId),
|
|
mVideoTunnelDev(videoTunnelDev),
|
|
mSolidBufferAllocator(solidBufferAllocator),
|
|
mOwnsDefaultDependencies(false) {
|
|
mConsumers.clear();
|
|
mBufferQueue.clear();
|
|
memset(&mCrop, 0, sizeof(vt_rect_t));
|
|
snprintf(mName, 64, "VtInstance-%d", tunnelId);
|
|
memset(&mLastData, 0, sizeof(last_data_t));
|
|
mLastData.videoStatus = VT_VIDEO_STATUS_SHOW;
|
|
mLastData.solidBufferType = SOLID_COLOR_FOR_INVALID;
|
|
}
|
|
|
|
VtInstance::~VtInstance() {
|
|
stopReleaseThread();
|
|
auto it = mConsumers.begin();
|
|
for (; it != mConsumers.end(); it++) {
|
|
if ((*it).get())
|
|
(*it)->setReleaseListener(nullptr);
|
|
}
|
|
|
|
mConsumers.clear();
|
|
mRefreshConsumers.clear();
|
|
releaseInstanceBuffers();
|
|
disconnect();
|
|
}
|
|
|
|
int32_t VtInstance::onFrameDisplayed(std::shared_ptr<VtBufferItem> & item) {
|
|
bool needStopReleaseThread = false;
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
std::shared_ptr<VtBufferItem> ptrBufferItem;
|
|
if (mBufferQueue.empty()) {
|
|
VTINST_LOGV("buffer queue is empty (%s)", item->toString().c_str());
|
|
item->closeFd();
|
|
return -1;
|
|
}
|
|
|
|
for (auto it = mBufferQueue.begin(); it != mBufferQueue.end();) {
|
|
ptrBufferItem = *it;
|
|
if (ptrBufferItem.get() != item.get()) {
|
|
++it;
|
|
continue;
|
|
}
|
|
|
|
if (ptrBufferItem->unrefHandle()) {
|
|
it = mBufferQueue.erase(it);
|
|
needStopReleaseThread = queueReleaseBufferLocked(ptrBufferItem);
|
|
}
|
|
lock.unlock();
|
|
if (needStopReleaseThread)
|
|
stopReleaseThread();
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!item->mIsSolidBuffer)
|
|
VTINST_LOGE("cannot find (%s) in buffer queue", item->toString().c_str());
|
|
item->closeFd();
|
|
return -1;
|
|
}
|
|
|
|
int32_t VtInstance::handleRefresh() {
|
|
int32_t ret = 0;
|
|
enum vt_cmd cmd;
|
|
struct vt_cmd_data cmdData;
|
|
struct vt_meta_data meta_data;
|
|
if (mRefreshConsumers.empty())
|
|
return ret;
|
|
|
|
for (auto it = mRefreshConsumers.begin(); it != mRefreshConsumers.end(); it++) {
|
|
if (mLastData.gameMode == 1) {
|
|
memset(&cmdData, 0, sizeof(cmdData));
|
|
cmd = VT_CMD_SET_GAME_MODE;
|
|
cmdData.data = mLastData.gameMode;
|
|
ret = (*it)->onVtCmds(cmd, cmdData);
|
|
}
|
|
|
|
if (mLastData.transform != 0) {
|
|
memset(&cmdData, 0, sizeof(cmdData));
|
|
cmd = VT_CMD_SET_VIDEO_TRANSFORM;
|
|
cmdData.transform = mLastData.transform;
|
|
ret = (*it)->onVtCmds(cmd, cmdData);
|
|
}
|
|
|
|
if (vt_rect_is_valid(&mLastData.displayFrame)) {
|
|
memset(&cmdData, 0, sizeof(cmdData));
|
|
cmd = VT_CMD_SET_DISPLAY_FRAME;
|
|
cmdData.rect = mLastData.displayFrame;
|
|
ret = (*it)->onVtCmds(cmd, cmdData);
|
|
}
|
|
|
|
if (mLastData.solidBufferType != SOLID_COLOR_FOR_INVALID &&
|
|
(mLastData.videoStatus == VT_VIDEO_STATUS_COLOR_ONCE ||
|
|
mLastData.videoStatus == VT_VIDEO_STATUS_COLOR_ALWAYS ||
|
|
mLastData.videoStatus == VT_VIDEO_STATUS_COLOR_ALWAYS_FOR_VRR)) {
|
|
VTINST_LOGD("status:%s, solidBufferType:%s",
|
|
vtVideoStatusToString(mLastData.videoStatus),
|
|
vtVideoColorTypeToString(mLastData.solidBufferType));
|
|
struct uvm_fd_info info;
|
|
memset(&info, 0, sizeof(info));
|
|
mSolidBufferAllocator.getBufferInfo(mLastData.solidBufferType, info);
|
|
if (info.fd >= 0) {
|
|
std::vector<std::shared_ptr<VtBufferItem>> items;
|
|
info.fd = dup(info.fd);
|
|
memset(&meta_data, 0, sizeof(meta_data));
|
|
std::shared_ptr<VtBufferItem> item =
|
|
std::make_shared<VtBufferItem>(info.fd, info.timestamp, info, meta_data, true);
|
|
items.push_back(item);
|
|
ret = sendBufferToConsumer(mRefreshConsumers, items);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* refresh buffers*/
|
|
if (!mBufferQueue.empty() &&
|
|
mLastData.videoStatus == VT_VIDEO_STATUS_SHOW &&
|
|
mLastData.solidBufferType == SOLID_COLOR_FOR_INVALID) {
|
|
std::vector<std::shared_ptr<VtBufferItem>> items;
|
|
std::shared_ptr<VtBufferItem> lastItem = mBufferQueue.back();
|
|
if (lastItem.get()) {
|
|
items.push_back(lastItem);
|
|
ret = sendBufferToConsumer(mRefreshConsumers, items);
|
|
}
|
|
}
|
|
|
|
mRefreshConsumers.clear();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t VtInstance::registerVtConsumer(
|
|
std::shared_ptr<VtConsumer>& consumer, bool refresh) {
|
|
/* only Hwc2Layer will call this api when have
|
|
* an videotunnel layer create
|
|
*/
|
|
if (!consumer || !consumer.get()) {
|
|
VTINST_LOGE("consumer is null");
|
|
return -1;
|
|
}
|
|
consumer->setReleaseListener(this);
|
|
mConsumers.push_back(consumer);
|
|
if (refresh)
|
|
mRefreshConsumers.push_back(consumer);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t VtInstance::unregisterVtConsumer(
|
|
std::shared_ptr<VtConsumer>& consumer) {
|
|
/* only Hwc2Layer will call this api when videotunnel layer destroy.
|
|
* and Hwc2Layer will release all buffer Fd before call this api
|
|
*/
|
|
int32_t ret = -1;
|
|
|
|
if (!consumer || !consumer.get()) {
|
|
VTINST_LOGE("consumer is null");
|
|
return ret;
|
|
}
|
|
|
|
for (auto it = mRefreshConsumers.begin(); it != mRefreshConsumers.end(); ) {
|
|
std::shared_ptr<VtConsumer> item = (*it);
|
|
if (item.get() == consumer.get()) {
|
|
it = mRefreshConsumers.erase(it);
|
|
ret = 0;
|
|
break;
|
|
} else {
|
|
it++;
|
|
}
|
|
}
|
|
|
|
for (auto it = mConsumers.begin(); it != mConsumers.end(); ) {
|
|
std::shared_ptr<VtConsumer> item = (*it);
|
|
if (item.get() == consumer.get()) {
|
|
VTINST_LOGD("remove consumer");
|
|
it = mConsumers.erase(it);
|
|
ret = 0;
|
|
break;
|
|
} else {
|
|
it++;
|
|
}
|
|
}
|
|
|
|
if (ret)
|
|
VTINST_LOGW("cannot find VT consumer %p",consumer.get());
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t VtInstance::connect() {
|
|
int32_t ret = -1;
|
|
if (mTunnelId >= 0) {
|
|
ret = mVideoTunnelDev.connect(mTunnelId);
|
|
if (ret >= 0) {
|
|
VTINST_LOGD("connect to videotunnel succeeded");
|
|
} else {
|
|
VTINST_LOGE("connect to videotunnel filed");
|
|
}
|
|
} else {
|
|
VTINST_LOGE("tunnel id is invalid");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void VtInstance::disconnect() {
|
|
stopReleaseThread();
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
releaseDelayedBuffersLocked(true);
|
|
}
|
|
|
|
VTINST_LOGD("disconnect videotunnel");
|
|
if (mTunnelId >= 0)
|
|
mVideoTunnelDev.disconnect(mTunnelId);
|
|
mTunnelId = -1;
|
|
memset(&mLastData, 0, sizeof(last_data_t));
|
|
mLastData.videoStatus = VT_VIDEO_STATUS_SHOW;
|
|
mLastData.solidBufferType = SOLID_COLOR_FOR_INVALID;
|
|
}
|
|
|
|
int32_t VtInstance::sendBufferToConsumer(
|
|
std::vector<std::shared_ptr<VtConsumer>> & consumers,
|
|
std::vector<std::shared_ptr<VtBufferItem>> & items) {
|
|
int32_t ret = 0;
|
|
|
|
if (!items.empty() && !consumers.empty()) {
|
|
for (auto it = consumers.begin(); it != consumers.end(); ) {
|
|
ret = (*it)->onFrameAvailable(items);
|
|
if (ret < 0 && ret != -EAGAIN) {
|
|
VTINST_LOGE("call consumer(%p) onFrameAvailable failed", (*it).get());
|
|
it = consumers.erase(it);
|
|
ret = -EAGAIN;
|
|
} else {
|
|
it++;
|
|
if (ret != -EAGAIN)
|
|
for (auto item = items.begin(); item != items.end(); item++)
|
|
(*item)->refHandle();
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int32_t VtInstance::acquireBuffer() {
|
|
bool isNeedDisplay = true;
|
|
int32_t ret = 0;
|
|
std::vector<std::shared_ptr<VtBufferItem>> items;
|
|
|
|
if (mLastData.videoStatus == VT_VIDEO_STATUS_COLOR_ALWAYS_FOR_VRR ||
|
|
mLastData.videoStatus == VT_VIDEO_STATUS_COLOR_ALWAYS ||
|
|
mLastData.videoStatus == VT_VIDEO_STATUS_HIDE ||
|
|
mLastData.videoStatus == VT_VIDEO_STATUS_HOLD_FRAME) {
|
|
isNeedDisplay = false;
|
|
}
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
while (true) {
|
|
std::shared_ptr<VtBufferItem> item = std::make_shared<VtBufferItem>();
|
|
ret = mVideoTunnelDev.acquireBuffer(mTunnelId,
|
|
item->mBufferFd,
|
|
item->mTimeStamp,
|
|
item->mMetaData);
|
|
|
|
if (ret == 0) {
|
|
if (isNeedDisplay) {
|
|
memset(&item->mInfo, 0, sizeof(item->mInfo));
|
|
item->mInfo.fd = item->mBufferFd;
|
|
UvmDev::getInstance().getVideoInfo(item->mInfo);
|
|
#ifndef LINUX_COMPILE
|
|
if (HwcConfig::enableDrmVideo()) {
|
|
item->mInfo.crop_left += mCrop.left;
|
|
item->mInfo.crop_top += mCrop.top;
|
|
item->mInfo.crop_right -= mCrop.right;
|
|
item->mInfo.crop_bottom -= mCrop.bottom;
|
|
} else {
|
|
item->mInfo.crop_left = mCrop.left;
|
|
item->mInfo.crop_top = mCrop.top;
|
|
item->mInfo.crop_right = mCrop.right;
|
|
item->mInfo.crop_bottom = mCrop.bottom;
|
|
}
|
|
#else
|
|
item->mInfo.crop_left += mCrop.left;
|
|
item->mInfo.crop_top += mCrop.top;
|
|
item->mInfo.crop_right -= mCrop.right;
|
|
item->mInfo.crop_bottom -= mCrop.bottom;
|
|
#endif
|
|
item->mInfo.buf_stride = item->mInfo.buf_width;
|
|
item->mInfo.buf_format = DRM_FORMAT_NV21;
|
|
|
|
VTINST_LOGV("acquire buffer %d timeStamp %" PRId64
|
|
", stride %d, w/h(%d %d), crop(%d %d %d %d)",
|
|
item->mBufferFd, item->mTimeStamp, item->mInfo.buf_stride, item->mInfo.buf_width,
|
|
item->mInfo.buf_height, item->mInfo.crop_left, item->mInfo.crop_top,
|
|
item->mInfo.crop_right, item->mInfo.crop_bottom);
|
|
VTINST_LOGV("hdr types: %d hdr data: smpte2086[%f %f %f %f %f %f %f %f %f %f] cta8613[%f %f]",
|
|
item->mMetaData.hdr.validTypes,
|
|
item->mMetaData.hdr.smpte2086.displayPrimaryRed.x,
|
|
item->mMetaData.hdr.smpte2086.displayPrimaryRed.y,
|
|
item->mMetaData.hdr.smpte2086.displayPrimaryGreen.x,
|
|
item->mMetaData.hdr.smpte2086.displayPrimaryGreen.y,
|
|
item->mMetaData.hdr.smpte2086.displayPrimaryBlue.x,
|
|
item->mMetaData.hdr.smpte2086.displayPrimaryBlue.y,
|
|
item->mMetaData.hdr.smpte2086.whitePoint.x,
|
|
item->mMetaData.hdr.smpte2086.whitePoint.y,
|
|
item->mMetaData.hdr.smpte2086.maxLuminance,
|
|
item->mMetaData.hdr.smpte2086.minLuminance,
|
|
item->mMetaData.hdr.cta8613.maxContentLightLevel,
|
|
item->mMetaData.hdr.cta8613.maxFrameAverageLightLevel);
|
|
VTINST_LOGV("buffer info[%d %d %d %d %d %d %d %d %d]",item->mMetaData.stride_in_pixel,
|
|
item->mMetaData.aligned_height, item->mMetaData.bufferFormat,
|
|
item->mMetaData.buffer_w, item->mMetaData.buffer_h,
|
|
item->mMetaData.crop_x, item->mMetaData.crop_y,
|
|
item->mMetaData.crop_w, item->mMetaData.crop_h);
|
|
items.push_back(item);
|
|
mBufferQueue.push_back(std::move(item));
|
|
} else {
|
|
VTINST_LOGV("acquire buffer %d timeStamp %" PRId64 " will drop for status %s",
|
|
item->mBufferFd, item->mTimeStamp, vtVideoStatusToString(mLastData.videoStatus));
|
|
mVideoTunnelDev.releaseBuffer(mTunnelId, item->mBufferFd, -1);
|
|
}
|
|
} else if (ret == -EAGAIN) {
|
|
/* no buffer available */
|
|
break;
|
|
} else {
|
|
VTINST_LOGE("acquire buffer error %d", ret);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isNeedDisplay) {
|
|
mLastData.videoStatus = VT_VIDEO_STATUS_SHOW;
|
|
mLastData.solidBufferType = SOLID_COLOR_FOR_INVALID;
|
|
ret = sendBufferToConsumer(mConsumers, items);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
bool VtInstance::shouldDelayReleaseLocked() {
|
|
return DebugHelper::getInstance().discardOutFence() &&
|
|
DebugHelper::getInstance().videoOutFenceDepth() > 0;
|
|
}
|
|
|
|
bool VtInstance::isReleaseFenceReadyLocked(std::shared_ptr<VtBufferItem> & item) {
|
|
if (!item || item->mIsSolidBuffer)
|
|
return true;
|
|
|
|
return item->getReleaseFenceStatus() != DrmFence::Status::Unsignaled;
|
|
}
|
|
|
|
bool VtInstance::queueReleaseBufferLocked(std::shared_ptr<VtBufferItem> & item) {
|
|
if (!item)
|
|
return false;
|
|
|
|
if (item->mIsSolidBuffer) {
|
|
releaseBufferLocked(item);
|
|
return false;
|
|
}
|
|
|
|
if (!shouldDelayReleaseLocked()) {
|
|
releaseDelayedBuffersLocked(true);
|
|
releaseBufferLocked(item);
|
|
return mReleaseThreadCreated;
|
|
}
|
|
|
|
if (!startReleaseThreadLocked()) {
|
|
releaseBufferLocked(item);
|
|
return false;
|
|
}
|
|
|
|
mDelayedReleaseQueue.push_back(item);
|
|
if (mDelayedReleaseQueue.size() >= DebugHelper::getInstance().videoOutFenceDepth()) {
|
|
releaseDelayedBuffersLocked(false);
|
|
}
|
|
mReleaseCondition.notify_all();
|
|
return false;
|
|
}
|
|
|
|
void VtInstance::releaseDelayedBuffersLocked(bool force) {
|
|
if (mDelayedReleaseQueue.empty())
|
|
return;
|
|
|
|
if (force || !shouldDelayReleaseLocked()) {
|
|
while (!mDelayedReleaseQueue.empty()) {
|
|
std::shared_ptr<VtBufferItem> item = mDelayedReleaseQueue.front();
|
|
mDelayedReleaseQueue.pop_front();
|
|
releaseBufferLocked(item);
|
|
}
|
|
return;
|
|
}
|
|
|
|
while (!mDelayedReleaseQueue.empty()) {
|
|
std::shared_ptr<VtBufferItem> item = mDelayedReleaseQueue.front();
|
|
if (!isReleaseFenceReadyLocked(item))
|
|
break;
|
|
|
|
mDelayedReleaseQueue.pop_front();
|
|
releaseBufferLocked(item);
|
|
}
|
|
}
|
|
|
|
bool VtInstance::startReleaseThreadLocked() {
|
|
if (mReleaseThreadCreated)
|
|
return true;
|
|
|
|
mReleaseThreadExit = false;
|
|
int ret = pthread_create(&mReleaseThread, NULL, releaseThreadMain, this);
|
|
if (ret) {
|
|
VTINST_LOGE("failed to create release thread: %s", strerror(ret));
|
|
mReleaseThreadExit = false;
|
|
mReleaseThread = 0;
|
|
return false;
|
|
}
|
|
mReleaseThreadCreated = true;
|
|
pthread_setname_np(mReleaseThread, "VtReleaseThread");
|
|
return true;
|
|
}
|
|
|
|
void VtInstance::stopReleaseThread() {
|
|
pthread_t releaseThread;
|
|
{
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
if (!mReleaseThreadCreated)
|
|
return;
|
|
|
|
mReleaseThreadExit = true;
|
|
releaseThread = mReleaseThread;
|
|
mReleaseCondition.notify_all();
|
|
}
|
|
|
|
pthread_join(releaseThread, NULL);
|
|
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
mReleaseThreadCreated = false;
|
|
mReleaseThreadExit = false;
|
|
}
|
|
|
|
void *VtInstance::releaseThreadMain(void * data) {
|
|
set_thread_debug_info("VtReleaseThread");
|
|
VtInstance* pThis = static_cast<VtInstance*>(data);
|
|
pThis->releaseThreadLoop();
|
|
return NULL;
|
|
}
|
|
|
|
void VtInstance::releaseThreadLoop() {
|
|
while (true) {
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
|
mReleaseCondition.wait_for(lock, std::chrono::milliseconds(kReleaseThreadPollMs),
|
|
[this] { return mReleaseThreadExit; });
|
|
if (mReleaseThreadExit)
|
|
return;
|
|
|
|
releaseDelayedBuffersLocked(false);
|
|
}
|
|
}
|
|
|
|
|
|
void VtInstance::releaseBufferLocked(std::shared_ptr<VtBufferItem> & item) {
|
|
if (item.get()) {
|
|
if (!item->mIsSolidBuffer) {
|
|
VTINST_LOGV("release buffer (%s)", item->toString().c_str());
|
|
mVideoTunnelDev.releaseBuffer(mTunnelId, item->mBufferFd, item->getReleaseFenceFd());
|
|
} else {
|
|
VTINST_LOGV("release solid buffer %d", item->mBufferFd);
|
|
item->closeFd();
|
|
}
|
|
}
|
|
}
|
|
|
|
void VtInstance::releaseInstanceBuffers() {
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
releaseDelayedBuffersLocked(true);
|
|
|
|
if (mBufferQueue.empty()) {
|
|
VTINST_LOGV("buffer queue is empty");
|
|
return;
|
|
}
|
|
|
|
for (auto it = mBufferQueue.begin(); it != mBufferQueue.end(); ++it) {
|
|
std::shared_ptr<VtBufferItem> item = *it;
|
|
if (!item->mIsSolidBuffer) {
|
|
VTINST_LOGV("release buffer(%s)", item->toString().c_str());
|
|
mVideoTunnelDev.releaseBuffer(mTunnelId, item->mBufferFd, -1);
|
|
} else {
|
|
VTINST_LOGV("release solid buffer %d", item->mBufferFd);
|
|
item->closeFd();
|
|
}
|
|
}
|
|
mBufferQueue.clear();
|
|
}
|
|
|
|
void VtInstance::onVtCmds(vt_cmd_t cmd,
|
|
vt_cmd_data_t cmdData,
|
|
bool & needSendToConsumer,
|
|
struct uvm_fd_info & info) {
|
|
bool debuglog = true;
|
|
vt_video_color_t prevType = mLastData.solidBufferType;
|
|
|
|
needSendToConsumer = false;
|
|
|
|
switch (cmd) {
|
|
case VT_CMD_SET_SHOW_SOLID_COLOR:
|
|
mLastData.videoStatus = VT_VIDEO_STATUS_COLOR_ONCE;
|
|
mLastData.solidBufferType = (vt_video_color_t)cmdData.data;
|
|
break;
|
|
case VT_CMD_SET_COLOR_BLACK:
|
|
mLastData.videoStatus = (vt_video_status_t)cmdData.data;
|
|
mLastData.solidBufferType = SOLID_COLOR_FOR_BLACK;
|
|
break;
|
|
case VT_CMD_SET_COLOR_BLUE:
|
|
mLastData.videoStatus = (vt_video_status_t)cmdData.data;
|
|
mLastData.solidBufferType = SOLID_COLOR_FOR_BLUE;
|
|
break;
|
|
case VT_CMD_SET_COLOR_GREEN:
|
|
/* cannot support green buffer */
|
|
//mLastData.videoStatus = (vt_video_status_t)cmdData.data;
|
|
//mLastData.solidBufferType = SOLID_COLOR_FOR_GREEN;
|
|
mLastData.videoStatus = VT_VIDEO_STATUS_SHOW;
|
|
mLastData.solidBufferType = SOLID_COLOR_FOR_INVALID;
|
|
break;
|
|
case VT_CMD_SET_VIDEO_STATUS:
|
|
mLastData.videoStatus = (vt_video_status_t)cmdData.data;
|
|
if (mLastData.videoStatus == VT_VIDEO_STATUS_BLANK ||
|
|
mLastData.videoStatus == VT_VIDEO_STATUS_HIDE) {
|
|
mLastData.solidBufferType = SOLID_COLOR_FOR_INVALID;
|
|
needSendToConsumer = true;
|
|
}
|
|
break;
|
|
case VT_CMD_SET_SOURCE_CROP:
|
|
mCrop = cmdData.rect;
|
|
debuglog = false;
|
|
VTINST_LOGD("cmd VT_CMD_SET_SOURCE_CROP(%d %d %d %d)", mCrop.left,
|
|
mCrop.top, mCrop.right, mCrop.bottom);
|
|
break;
|
|
case VT_CMD_SET_VIDEO_TRANSFORM:
|
|
mLastData.transform = cmdData.transform;
|
|
needSendToConsumer = true;
|
|
break;
|
|
case VT_CMD_SET_GAME_MODE:
|
|
mLastData.gameMode = cmdData.data;
|
|
needSendToConsumer = true;
|
|
break;
|
|
case VT_CMD_SET_DISPLAY_FRAME:
|
|
mLastData.displayFrame = cmdData.rect;
|
|
needSendToConsumer = true;
|
|
break;
|
|
default:
|
|
debuglog = false;
|
|
needSendToConsumer = true;
|
|
break;
|
|
}
|
|
|
|
if (mLastData.videoStatus == VT_VIDEO_STATUS_COLOR_DISABLE ||
|
|
mLastData.videoStatus == VT_VIDEO_STATUS_SHOW)
|
|
mLastData.solidBufferType = SOLID_COLOR_FOR_INVALID;
|
|
|
|
if (debuglog)
|
|
VTINST_LOGD("cmd:%s, status:%s, solidBufferType:%s",
|
|
vtCmdToString(cmd), vtVideoStatusToString(mLastData.videoStatus),
|
|
vtVideoColorTypeToString(mLastData.solidBufferType));
|
|
|
|
if (prevType != mLastData.solidBufferType && mLastData.solidBufferType != SOLID_COLOR_FOR_INVALID)
|
|
mSolidBufferAllocator.getBufferInfo(mLastData.solidBufferType, info);
|
|
}
|
|
|
|
int32_t VtInstance::receiveCmds() {
|
|
bool needSendToConsumer;
|
|
int32_t ret = 0;
|
|
enum vt_cmd cmd;
|
|
struct vt_cmd_data cmdData;
|
|
struct uvm_fd_info info;
|
|
std::vector<std::shared_ptr<VtBufferItem>> items;
|
|
struct vt_meta_data meta_data;
|
|
ret = mVideoTunnelDev.receiveCmd(mTunnelId, cmd, cmdData);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
memset(&info, 0, sizeof(uvm_fd_info));
|
|
info.fd = -1;
|
|
info.fps = -1;
|
|
onVtCmds(cmd, cmdData, needSendToConsumer, info);
|
|
if (info.fd >= 0) {
|
|
VTINST_LOGD("alloc solid buffer %d, stride %d, w/h(%d %d), crop(%d %d %d %d)",
|
|
info.fd, info.buf_stride, info.buf_width,
|
|
info.buf_height, info.crop_left, info.crop_top,
|
|
info.crop_right, info.crop_bottom);
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
memset(&meta_data, 0, sizeof(meta_data));
|
|
std::shared_ptr<VtBufferItem> item =
|
|
std::make_shared<VtBufferItem> (info.fd, info.timestamp, info, meta_data, true);
|
|
items.push_back(item);
|
|
mBufferQueue.push_back(std::move(item));
|
|
}
|
|
|
|
if (!items.empty())
|
|
return sendBufferToConsumer(mConsumers,items);
|
|
|
|
if (needSendToConsumer) {
|
|
for (auto it = mConsumers.begin(); it != mConsumers.end(); it++) {
|
|
ret = (*it)->onVtCmds(cmd, cmdData);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool VtInstance::needDestroyThisInstance() {
|
|
return mConsumers.empty() ? true : false;
|
|
}
|
|
|
|
void VtInstance::onClearAlwaysVRRMode() {
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mLastData.videoStatus == VT_VIDEO_STATUS_COLOR_ALWAYS_FOR_VRR) {
|
|
mLastData.videoStatus = VT_VIDEO_STATUS_COLOR_ONCE;
|
|
VTINST_LOGV("change video statu %s -> %s",
|
|
vtVideoStatusToString(VT_VIDEO_STATUS_COLOR_ALWAYS_FOR_VRR),
|
|
vtVideoStatusToString(mLastData.videoStatus));
|
|
}
|
|
}
|