android13/vendor/rockchip/hardware/interfaces/hdmi/1.0/default/Hdmi.cpp

320 lines
10 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// FIXME: your file license if you have one
#include "Hdmi.h"
#include "log/log.h"
#include <sys/inotify.h>
#include <errno.h>
#include <linux/videodev2.h>
#include <math.h>
#include "HdmiCallback.h"
#include "HdmiAudioCallback.h"
#include <condition_variable>
#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */
#define RKMODULE_GET_HDMI_MODE \
_IOR('V', BASE_VIDIOC_PRIVATE + 34, __u32)
namespace rockchip::hardware::hdmi::implementation {
sp<::rockchip::hardware::hdmi::V1_0::IHdmiCallback> mCb = nullptr;
sp<::rockchip::hardware::hdmi::V1_0::IHdmiAudioCallback> mAudioCb = nullptr;
sp<::rockchip::hardware::hdmi::V1_0::IHdmiRxStatusCallback> mStatusCb = nullptr;
sp<::rockchip::hardware::hdmi::V1_0::IFrameWarpper> mFrameWarpper = nullptr;
std::mutex mLock;
std::mutex mLockAudio;
std::mutex mLockStatusCb;
std::mutex mLockFrameWarpper;
hidl_string mDeviceId;
const int kMaxDevicePathLen = 256;
const char* kDevicePath = "/dev/";
const char kPrefix[] = "v4l-subdev";
const int kPrefixLen = sizeof(kPrefix) - 1;
const int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
char kV4l2DevicePath[kMaxDevicePathLen];
int mMipiHdmi = 0;
sp<V4L2DeviceEvent> mV4l2Event;
int findMipiHdmi()
{
DIR* devdir = opendir(kDevicePath);
if(devdir == 0) {
ALOGE("%s: cannot open %s! ", __FUNCTION__, kDevicePath);
return -1;
}
struct dirent* de;
int videofd,ret;
while ((de = readdir(devdir)) != 0) {
// Find external v4l devices that's existing before we start watching and add them
if (!strncmp(kPrefix, de->d_name, kPrefixLen)) {
std::string deviceId(de->d_name + kPrefixLen);
ALOGD("found %s", de->d_name);
char v4l2DeviceDriver[16];
snprintf(kV4l2DevicePath, kMaxDevicePathLen,"%s%s", kDevicePath, de->d_name);
videofd = open(kV4l2DevicePath, O_RDWR);
if (videofd < 0){
ALOGE("[%s %d] open device failed:%x [%s]", __FUNCTION__, __LINE__, videofd,strerror(errno));
continue;
} else {
uint32_t ishdmi;
ret = ::ioctl(videofd, RKMODULE_GET_HDMI_MODE, (void*)&ishdmi);
if (ret < 0) {
ALOGE("RKMODULE_GET_HDMI_MODE Failed, error: %s", strerror(errno));
close(videofd);
continue;
}
ALOGD("%s RKMODULE_GET_HDMI_MODE:%d",kV4l2DevicePath,ishdmi);
if (ishdmi)
{
mMipiHdmi = videofd;
ALOGD("MipiHdmi fd:%d",mMipiHdmi);
if (mMipiHdmi < 0)
{
return ret;
}
mV4l2Event->initialize(mMipiHdmi);
}
}
}
}
closedir(devdir);
return ret;
}
Return<void> Hdmi::foundHdmiDevice(const hidl_string& deviceId, const ::android::sp<::rockchip::hardware::hdmi::V1_0::IHdmiRxStatusCallback>& cb) {
ALOGD("@%s,deviceId:%s",__FUNCTION__,deviceId.c_str());
std::unique_lock<std::mutex> lk(mLockStatusCb);
mDeviceId = deviceId.c_str();
mStatusCb = cb;
lk.unlock();
return Void();
}
Return<void> Hdmi::addAudioListener(const ::android::sp<::rockchip::hardware::hdmi::V1_0::IHdmiAudioCallback>& cb) {
ALOGD("@%s",__FUNCTION__);
std::unique_lock<std::mutex> lk(mLockAudio);
mAudioCb = cb;
lk.unlock();
return Void();
}
Return<void> Hdmi::removeAudioListener(const ::android::sp<::rockchip::hardware::hdmi::V1_0::IHdmiAudioCallback>& cb)
{
ALOGD("@%s",__FUNCTION__);
std::unique_lock<std::mutex> lk(mLockAudio);
mAudioCb = nullptr;
lk.unlock();
return Void();
}
Return<void> Hdmi::onAudioChange(const ::rockchip::hardware::hdmi::V1_0::HdmiAudioStatus& status) {
ALOGD("@%s",__FUNCTION__);
std::unique_lock<std::mutex> lk(mLockAudio);
if (mAudioCb.get()!=nullptr && strstr(status.deviceId.c_str(),mDeviceId.c_str()))
{
ALOGD("@%s,cameraId:%s status:%d",__FUNCTION__,status.deviceId.c_str(),status.status);
if (status.status)
{
mAudioCb->onConnect(status.deviceId);
}else{
mAudioCb->onDisconnect(status.deviceId);
}
}
lk.unlock();
return Void();
}
Return<void> Hdmi::getHdmiDeviceId(getHdmiDeviceId_cb _hidl_cb) {
ALOGD("@%s,mDeviceId%s",__FUNCTION__,mDeviceId.c_str());
_hidl_cb(mDeviceId);
return Void();
}
Return<void> Hdmi::getMipiStatus(Hdmi::getMipiStatus_cb _hidl_cb){
ALOGD("@%s",__FUNCTION__);
V1_0::HdmiStatus status;
struct v4l2_subdev_format aFormat;
int err = ioctl(mMipiHdmi, VIDIOC_SUBDEV_G_FMT, &aFormat);
if (err < 0) {
ALOGE("VIDIOC_SUBDEV_G_FMT failed: %s", strerror(errno));
_hidl_cb(status);
return Void();
}
ALOGD("VIDIOC_SUBDEV_G_FMT: pad: %d, which: %d, width: %d, "
"height: %d, format: 0x%x, field: %d, color space: %d",
aFormat.pad,
aFormat.which,
aFormat.format.width,
aFormat.format.height,
aFormat.format.code,
aFormat.format.field,
aFormat.format.colorspace);
status.width = aFormat.format.width;
status.height = aFormat.format.height;
struct v4l2_dv_timings timings;
err = ioctl(mMipiHdmi, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, &timings);
if (err < 0) {
ALOGD("get VIDIOC_SUBDEV_QUERY_DV_TIMINGS failed ,%d(%s)", errno, strerror(errno));
_hidl_cb(status);
return Void();
}
const struct v4l2_bt_timings *bt =&timings.bt;
double tot_width, tot_height;
tot_height = bt->height +
bt->vfrontporch + bt->vsync + bt->vbackporch +
bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch;
tot_width = bt->width +
bt->hfrontporch + bt->hsync + bt->hbackporch;
ALOGD("%s:%dx%d, pixelclock:%lld Hz, %.2f fps", __func__,
timings.bt.width, timings.bt.height,
timings.bt.pixelclock,static_cast<double>(bt->pixelclock) /(tot_width * tot_height));
status.fps = round(static_cast<double>(bt->pixelclock) /(tot_width * tot_height));
struct v4l2_control control;
memset(&control, 0, sizeof(struct v4l2_control));
control.id = V4L2_CID_DV_RX_POWER_PRESENT;
err = ioctl(mMipiHdmi, VIDIOC_G_CTRL, &control);
if (err < 0) {
ALOGE("V4L2_CID_DV_RX_POWER_PRESENT failed ,%d(%s)", errno, strerror(errno));
}
ALOGD("VIDIOC_G_CTRL:%d",control.value);
status.status = control.value;
_hidl_cb(status);
return Void();
}
Return<void> Hdmi::getHdmiRxStatus(Hdmi::getHdmiRxStatus_cb _hidl_cb){
ALOGD("@%s",__FUNCTION__);
std::unique_lock<std::mutex> lk(mLockStatusCb);
V1_0::HdmiStatus status;
if (mStatusCb)
{
mStatusCb->getHdmiRxStatus(_hidl_cb);
lk.unlock();
return Void();
}
_hidl_cb(status);
lk.unlock();
return Void();
}
// Methods from ::rockchip::hardware::hdmi::V1_0::IHdmi follow.
Return<void> Hdmi::onStatusChange(uint32_t status) {
ALOGD("@%s",__FUNCTION__);
std::unique_lock<std::mutex> lk(mLock);
if (mCb.get()!=nullptr)
{
ALOGD("@%s,status:%d",__FUNCTION__,status);
if (status)
{
mCb->onConnect(mDeviceId);
}else{
mCb->onDisconnect(mDeviceId);
}
}
lk.unlock();
return Void();
}
Return<void> Hdmi::registerListener(const sp<::rockchip::hardware::hdmi::V1_0::IHdmiCallback>& cb) {
ALOGD("@%s",__FUNCTION__);
std::unique_lock<std::mutex> lk(mLock);
mCb = cb;
lk.unlock();
return Void();
}
Return<void> Hdmi::unregisterListener(const sp<::rockchip::hardware::hdmi::V1_0::IHdmiCallback>& cb) {
ALOGD("@%s",__FUNCTION__);
std::unique_lock<std::mutex> lk(mLock);
mCb = nullptr;
lk.unlock();
return Void();
}
V4L2EventCallBack Hdmi::eventCallback(void* sender,int event_type,struct v4l2_event *event){
ALOGD("@%s,event_type:%d",__FUNCTION__,event_type);
std::unique_lock<std::mutex> lk(mLock);
if (event_type == V4L2_EVENT_CTRL)
{
struct v4l2_event_ctrl* ctrl =(struct v4l2_event_ctrl*) &(event->u);
if (mCb != nullptr)
{
if (!ctrl->value)
{
mCb->onDisconnect("0");
}
}
ALOGD("V4L2_EVENT_CTRL event %d\n", ctrl->value);
}else if (event_type == V4L2_EVENT_SOURCE_CHANGE)
{
if (sender!=nullptr)
{
V4L2DeviceEvent::V4L2EventThread* eventThread = (V4L2DeviceEvent::V4L2EventThread*)sender;
sp<V4L2DeviceEvent::FormartSize> format = eventThread->getFormat();
if (format!=nullptr)
{
ALOGD("getFormatWeight:%d,getFormatHeight:%d",format->getFormatWeight(),format->getFormatHeight());
if (mCb != nullptr)
{
mCb->onFormatChange("0",format->getFormatWeight(),format->getFormatHeight());
mCb->onConnect("0");
}
}
}
}
lk.unlock();
return 0;
}
Hdmi::Hdmi(){
ALOGD("@%s.",__FUNCTION__);
mCb = new HdmiCallback();
mV4l2Event = new V4L2DeviceEvent();
mV4l2Event->RegisterEventvCallBack((V4L2EventCallBack)Hdmi::eventCallback);
findMipiHdmi();
}
Hdmi::~Hdmi(){
ALOGD("@%s",__FUNCTION__);
if (mV4l2Event)
mV4l2Event->closePipe();
if (mV4l2Event)
mV4l2Event->closeEventThread();
}
V1_0::IHdmi* HIDL_FETCH_IHdmi(const char* /* name */) {
ALOGD("@%s",__FUNCTION__);
return new Hdmi();
}
Return<void> Hdmi::setFrameDecorator(const sp<::rockchip::hardware::hdmi::V1_0::IFrameWarpper>& frameWarpper) {
ALOGD("@%s",__FUNCTION__);
std::unique_lock<std::mutex> lk(mLockFrameWarpper);
mFrameWarpper = frameWarpper;
lk.unlock();
return Void();
}
Return<void> Hdmi::decoratorFrame(const ::rockchip::hardware::hdmi::V1_0::FrameInfo& frameInfo, decoratorFrame_cb _hidl_cb) {
ALOGV("@%s",__FUNCTION__);
std::unique_lock<std::mutex> lk(mLockFrameWarpper);
rockchip::hardware::hdmi::V1_0::FrameInfo _frameInfo;
if (mFrameWarpper.get()!=nullptr)
{
V1_0::IFrameWarpper::onFrame_cb _onFrame_cb;
mFrameWarpper->onFrame(frameInfo,[&]( ::rockchip::hardware::hdmi::V1_0::FrameInfo frameInfo){
ALOGV("[%s] Receive wrapped frame(%d,%d)",__FUNCTION__,frameInfo.width,frameInfo.height);
_frameInfo = frameInfo;
});
ALOGV("[%s] Receive wrapped frame(%d,%d)",__FUNCTION__,_frameInfo.width,_frameInfo.height);
_hidl_cb(_frameInfo);
lk.unlock();
return Void();
}
_hidl_cb(frameInfo);
lk.unlock();
return Void();
}
} // namespace rockchip::hardware::hdmi::implementation