/* * Copyright (c) 2021 Rockchip Electronics Co., Ltd */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "HinDev.h" #include #include #include #define V4L2_ROTATE_ID 0x980922 #ifndef container_of #define container_of(ptr, type, member) ({ \ const typeof(((type *) 0)->member) *__mptr = (ptr); \ (type *) ((char *) __mptr - (char *)(&((type *)0)->member)); }) #endif #define BOUNDRY 32 #define ALIGN_32(x) ((x + (BOUNDRY) - 1)& ~((BOUNDRY) - 1)) #define ALIGN(b,w) (((b)+((w)-1))/(w)*(w)) const int kMaxDevicePathLen = 256; const char* kDevicePath = "/dev/"; constexpr char kPrefix[] = "video"; constexpr int kPrefixLen = sizeof(kPrefix) - 1; //constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1; constexpr char kHdmiNodeName[] = "rk_hdmirx"; static v4l2_buf_type TVHAL_V4L2_BUF_TYPE = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; static size_t getBufSize(int format, int width, int height) { size_t buf_size = 0; switch (format) { case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV12: { buf_size = width * height * 3 / 2; break; } case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: buf_size = width * height * 2; break; case V4L2_PIX_FMT_BGR24: buf_size = width * height * 3; break; case V4L2_PIX_FMT_RGB32: buf_size = width * height * 4; break; default: DEBUG_PRINT(3, "Invalid format"); buf_size = width * height * 3 / 2; } return buf_size; } static void two_bytes_per_pixel_memcpy_align32(unsigned char *dst, unsigned char *src, int width, int height) { int stride = (width + 31) & ( ~31); int h; for (h=0; hcurrBufferHandleIndex = 0; mHinNodeInfo->currBufferHandleFd = 0; mFramecount = 0; mNotifyQueueCb = NULL; mState = STOPED; mANativeWindow = NULL; mWorkThread = NULL; mV4L2DataFormatConvert = false; // mPreviewThreadRunning = false; // mPreviewBuffThread = NULL; mTvInputCB = NULL; mOpen = false; /** * init RTSidebandWindow */ RTSidebandInfo info; memset(&info, 0, sizeof(RTSidebandInfo)); info.structSize = sizeof(RTSidebandInfo); info.top = 0; info.left = 0; info.width = mFrameWidth; info.height = mFrameHeight; info.usage = STREAM_BUFFER_GRALLOC_USAGE; if (initType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) { mFrameType |= TYPF_SIDEBAND_WINDOW; mBufferCount = SIDEBAND_WINDOW_BUFF_CNT; info.usage |= GRALLOC_USAGE_HW_COMPOSER | RK_GRALLOC_USAGE_STRIDE_ALIGN_64; mFirstRequestCapture = false; mRequestCaptureCount = 1; } else { mFrameType |= TYPE_STREAM_BUFFER_PRODUCER; mBufferCount = APP_PREVIEW_BUFF_CNT; } info.streamType = mFrameType; info.format = mPixelFormat; //0x15 if(-1 == mSidebandWindow->init(info)) { DEBUG_PRINT(3, "mSidebandWindow->init failed !!!"); return -1; } return NO_ERROR; } int HinDevImpl::findDevice(int id, int& initWidth, int& initHeight,int& initFormat ) { ALOGD("%s called", __func__); // Find existing /dev/video* devices DIR* devdir = opendir(kDevicePath); int videofd,ret; if(devdir == 0) { ALOGE("%s: cannot open %s! Exiting threadloop", __FUNCTION__, kDevicePath); return -1; } struct dirent* de; 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(" v4l device %s found", de->d_name); char v4l2DevicePath[kMaxDevicePathLen]; char v4l2DeviceDriver[16]; snprintf(v4l2DevicePath, kMaxDevicePathLen,"%s%s", kDevicePath, de->d_name); videofd = open(v4l2DevicePath, O_RDWR); if (videofd < 0){ DEBUG_PRINT(3, "[%s %d] mHinDevHandle:%x [%s]", __FUNCTION__, __LINE__, videofd,strerror(errno)); continue; } else { DEBUG_PRINT(1, "%s open device %s successful.", __FUNCTION__, v4l2DevicePath); struct v4l2_capability cap; ret = ioctl(videofd, VIDIOC_QUERYCAP, &cap); if (ret < 0) { DEBUG_PRINT(3, "VIDIOC_QUERYCAP Failed, error: %s", strerror(errno)); close(videofd); continue; } snprintf(v4l2DeviceDriver, 16,"%s",cap.driver); DEBUG_PRINT(3, "VIDIOC_QUERYCAP driver=%s,%s", cap.driver,v4l2DeviceDriver); DEBUG_PRINT(3, "VIDIOC_QUERYCAP card=%s", cap.card); DEBUG_PRINT(3, "VIDIOC_QUERYCAP version=%d", cap.version); DEBUG_PRINT(3, "VIDIOC_QUERYCAP capabilities=0x%08x,0x%08x", cap.capabilities,V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); DEBUG_PRINT(3, "VIDIOC_QUERYCAP device_caps=0x%08x", cap.device_caps); if(!strncmp(kHdmiNodeName, v4l2DeviceDriver, sizeof(kHdmiNodeName)-1)){ mHinDevHandle = videofd; if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { ALOGE("V4L2_CAP_VIDEO_CAPTURE is a video capture device, capabilities: %x\n", cap.capabilities); TVHAL_V4L2_BUF_TYPE = V4L2_BUF_TYPE_VIDEO_CAPTURE; }else if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)) { ALOGE("V4L2_CAP_VIDEO_CAPTURE_MPLANE is a video capture device, capabilities: %x\n", cap.capabilities); TVHAL_V4L2_BUF_TYPE = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; } break; }else{ close(videofd); DEBUG_PRINT(3, "isnot hdmirx,VIDIOC_QUERYCAP driver=%s", cap.driver); } } } } closedir(devdir); if (mHinDevHandle < 0){ DEBUG_PRINT(3, "[%s %d] mHinDevHandle:%x", __FUNCTION__, __LINE__, mHinDevHandle); return -1; } mV4l2Event->initialize(mHinDevHandle); if (get_format(0, initWidth, initHeight, initFormat) == 0) { DEBUG_PRINT(3, "[%s %d] get_format fail ", __FUNCTION__, __LINE__); close(mHinDevHandle); return -1; } // mPixelFormat = DEFAULT_TVHAL_STREAM_FORMAT; mFrameWidth = initWidth; mFrameHeight = initHeight; mBufferSize = mFrameWidth * mFrameHeight * 3/2; return 0; } int HinDevImpl::makeHwcSidebandHandle() { buffer_handle_t buffer = NULL; mSidebandWindow->allocateSidebandHandle(&buffer, -1); if (!buffer) { DEBUG_PRINT(3, "allocate buffer from sideband window failed!"); return -1; } mSidebandHandle = buffer; return 0; } buffer_handle_t HinDevImpl::getSindebandBufferHandle() { if (mSidebandHandle == NULL) makeHwcSidebandHandle(); return mSidebandHandle; } HinDevImpl::~HinDevImpl() { DEBUG_PRINT(3, "%s %d", __FUNCTION__, __LINE__); if (mSidebandWindow) { mSidebandWindow->stop(); } if (mV4l2Event) mV4l2Event->closeEventThread(); if (mHinNodeInfo) free (mHinNodeInfo); if (mHinDevHandle >= 0) close(mHinDevHandle); } int HinDevImpl::start_device() { if (mFrameType & TYPF_SIDEBAND_WINDOW) { //mRequestCaptureCount = 1; } else { mRequestCaptureCount = 0; mFirstRequestCapture = true; } int ret = -1; DEBUG_PRINT(1, "[%s %d] mHinDevHandle:%x", __FUNCTION__, __LINE__, mHinDevHandle); ret = ioctl(mHinDevHandle, VIDIOC_QUERYCAP, &mHinNodeInfo->cap); if (ret < 0) { DEBUG_PRINT(3, "VIDIOC_QUERYCAP Failed, error: %s", strerror(errno)); return ret; } DEBUG_PRINT(1, "VIDIOC_QUERYCAP driver=%s", mHinNodeInfo->cap.driver); DEBUG_PRINT(1, "VIDIOC_QUERYCAP card=%s", mHinNodeInfo->cap.card); DEBUG_PRINT(1, "VIDIOC_QUERYCAP version=%d", mHinNodeInfo->cap.version); DEBUG_PRINT(1, "VIDIOC_QUERYCAP capabilities=0x%08x,0x%08x", mHinNodeInfo->cap.capabilities,V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); DEBUG_PRINT(1, "VIDIOC_QUERYCAP device_caps=0x%08x", mHinNodeInfo->cap.device_caps); mHinNodeInfo->reqBuf.type = TVHAL_V4L2_BUF_TYPE; mHinNodeInfo->reqBuf.memory = TVHAL_V4L2_BUF_MEMORY_TYPE; mHinNodeInfo->reqBuf.count = mBufferCount; ret = ioctl(mHinDevHandle, VIDIOC_REQBUFS, &mHinNodeInfo->reqBuf); if (ret < 0) { DEBUG_PRINT(3, "VIDIOC_REQBUFS Failed, error: %s", strerror(errno)); return ret; } else { ALOGD("VIDIOC_REQBUFS successful."); } aquire_buffer(); for (int i = 0; i < mBufferCount; i++) { DEBUG_PRINT(mDebugLevel, "bufferArray index = %d", mHinNodeInfo->bufferArray[i].index); DEBUG_PRINT(mDebugLevel, "bufferArray type = %d", mHinNodeInfo->bufferArray[i].type); DEBUG_PRINT(mDebugLevel, "bufferArray memory = %d", mHinNodeInfo->bufferArray[i].memory); DEBUG_PRINT(mDebugLevel, "bufferArray m.fd = %d", mHinNodeInfo->bufferArray[i].m.planes[0].m.fd); DEBUG_PRINT(mDebugLevel, "bufferArray length = %d", mHinNodeInfo->bufferArray[i].length); DEBUG_PRINT(mDebugLevel, "buffer length = %d", mSidebandWindow->getBufferLength(mHinNodeInfo->buffer_handle_poll[i])); //mHinNodeInfo->bufferArray[i].flags = V4L2_BUF_FLAG_NO_CACHE_INVALIDATE | // V4L2_BUF_FLAG_NO_CACHE_CLEAN; ret = ioctl(mHinDevHandle, VIDIOC_QBUF, &mHinNodeInfo->bufferArray[i]); if (ret < 0) { DEBUG_PRINT(3, "VIDIOC_QBUF Failed, error: %s", strerror(errno)); return -1; } } ALOGD("[%s %d] VIDIOC_QBUF successful", __FUNCTION__, __LINE__); v4l2_buf_type bufType; bufType = TVHAL_V4L2_BUF_TYPE; ret = ioctl(mHinDevHandle, VIDIOC_STREAMON, &bufType); if (ret < 0) { DEBUG_PRINT(3, "VIDIOC_STREAMON Failed, error: %s", strerror(errno)); return -1; } ALOGD("[%s %d] VIDIOC_STREAMON return=:%d", __FUNCTION__, __LINE__, ret); return ret; } int HinDevImpl::stop_device() { DEBUG_PRINT(3, "%s %d", __FUNCTION__, __LINE__); int ret; enum v4l2_buf_type bufType = TVHAL_V4L2_BUF_TYPE; ret = ioctl (mHinDevHandle, VIDIOC_STREAMOFF, &bufType); if (ret < 0) { DEBUG_PRINT(3, "StopStreaming: Unable to stop capture: %s", strerror(errno)); } return ret; } int HinDevImpl::start() { ALOGD("%s %d", __FUNCTION__, __LINE__); int ret; if(mOpen == true){ ALOGI("already open"); return NO_ERROR; } ret = start_device(); if(ret != NO_ERROR) { DEBUG_PRINT(3, "Start v4l2 device failed:%d",ret); return ret; } mSidebandWindow->allocateSidebandHandle(&mSignalHandle, HAL_PIXEL_FORMAT_BGR_888); ALOGD("Create Work Thread"); mWorkThread = new WorkThread(this); mState = START; mOpen = true; ALOGD("%s %d ret:%d", __FUNCTION__, __LINE__, ret); return NO_ERROR; } int HinDevImpl::stop() { ALOGD("%s %d", __FUNCTION__, __LINE__); int ret; mState = STOPED; if(mWorkThread != NULL){ mWorkThread->requestExit(); mWorkThread.clear(); mWorkThread = NULL; } if (mFrameType & TYPF_SIDEBAND_WINDOW) { mSidebandWindow->clearVopArea(); } enum v4l2_buf_type bufType = TVHAL_V4L2_BUF_TYPE; ret = ioctl (mHinDevHandle, VIDIOC_STREAMOFF, &bufType); if (ret < 0) { DEBUG_PRINT(3, "StopStreaming: Unable to stop capture: %s", strerror(errno)); } else { DEBUG_PRINT(3, "StopStreaming: successful."); } // cancel request buff v4l2_requestbuffers req_buffers{}; req_buffers.type = TVHAL_V4L2_BUF_TYPE; req_buffers.memory = TVHAL_V4L2_BUF_MEMORY_TYPE; req_buffers.count = 0; ret = ioctl(mHinDevHandle, VIDIOC_REQBUFS, &req_buffers); if (ret < 0) { ALOGE("%s: cancel REQBUFS failed: %s", __FUNCTION__, strerror(errno)); } else { ALOGE("%s: cancel REQBUFS successful.", __FUNCTION__); } if (mSidebandWindow) { mSidebandWindow->stop(); } release_buffer(); mDumpFrameCount = 3; mOpen = false; mFrameType = 0; if (mHinNodeInfo) free(mHinNodeInfo); if (mV4l2Event) mV4l2Event->closePipe(); if (mHinDevHandle >= 0) close(mHinDevHandle); mFirstRequestCapture = true; mRequestCaptureCount = 0; DEBUG_PRINT(3, "============================= %s end ================================", __FUNCTION__); return ret; } int HinDevImpl::set_preview_callback(NotifyQueueDataCallback callback) { if (!callback){ DEBUG_PRINT(3, "NULL state callback pointer"); return BAD_VALUE; } mNotifyQueueCb = callback; return NO_ERROR; } int HinDevImpl::set_data_callback(V4L2EventCallBack callback) { ALOGD("%s %d", __FUNCTION__, __LINE__); if (callback == NULL){ DEBUG_PRINT(3, "NULL data callback pointer"); return BAD_VALUE; } mV4l2Event->RegisterEventvCallBack(callback); return NO_ERROR; } int HinDevImpl::get_format(int fd, int &hdmi_in_width, int &hdmi_in_height,int& initFormat) { std::vector formatList; struct v4l2_fmtdesc fmtdesc; fmtdesc.index = 0; fmtdesc.type = TVHAL_V4L2_BUF_TYPE; while (ioctl(mHinDevHandle, VIDIOC_ENUM_FMT, &fmtdesc) != -1) { formatList.push_back( fmtdesc.pixelformat); DEBUG_PRINT(3, " V4L2 driver: idx=%d, \t desc:%s,format:0x%x", fmtdesc.index + 1, fmtdesc.description, fmtdesc.pixelformat); fmtdesc.index++; } v4l2_format format; format.type = TVHAL_V4L2_BUF_TYPE; vector::iterator it; for(it = formatList.begin();it != formatList.end();it++){ format.fmt.pix.pixelformat = (int)*it; if (ioctl(mHinDevHandle, VIDIOC_TRY_FMT, &format) != -1) { DEBUG_PRINT(3, "V4L2 driver try: width:%d,height:%d,format:0x%x", format.fmt.pix.width, format.fmt.pix.height,format.fmt.pix.pixelformat); hdmi_in_width = format.fmt.pix.width; hdmi_in_height = format.fmt.pix.height; mPixelFormat = format.fmt.pix.pixelformat; initFormat = getNativeWindowFormat(format.fmt.pix.pixelformat);//V4L2_PIX_FMT_BGR24; break; } } int err = ioctl(mHinDevHandle, VIDIOC_G_FMT, &format); if (err < 0) { DEBUG_PRINT(3, "[%s %d] failed, VIDIOC_G_FMT %d, %s", __FUNCTION__, __LINE__, err, strerror(err)); } else { DEBUG_PRINT(3, "after %s get from v4l2 format.type = %d ", __FUNCTION__, format.type); DEBUG_PRINT(3, "after %s get from v4l2 format.fmt.pix.width =%d", __FUNCTION__, format.fmt.pix.width); DEBUG_PRINT(3, "after %s get from v4l2 format.fmt.pix.height =%d", __FUNCTION__, format.fmt.pix.height); DEBUG_PRINT(3, "after %s get from v4l2 format.fmt.pix.pixelformat =%d", __FUNCTION__, format.fmt.pix.pixelformat); } if(hdmi_in_width == 0 || hdmi_in_height == 0) return 0; return -1; } int HinDevImpl::get_HdmiIn(bool enforce){ if(enforce && mIsHdmiIn) return mIsHdmiIn; struct v4l2_control control; memset(&control, 0, sizeof(struct v4l2_control)); control.id = V4L2_CID_DV_RX_POWER_PRESENT; int err = ioctl(mHinDevHandle, VIDIOC_G_CTRL, &control); if (err < 0) { ALOGE("Set POWER_PRESENT failed ,%d(%s)", errno, strerror(errno)); return UNKNOWN_ERROR; } mIsHdmiIn = control.value; //enum v4l2_buf_type bufType = TVHAL_V4L2_BUF_TYPE; if(mIsHdmiIn && mState == START){ /*err = ioctl(mHinDevHandle, VIDIOC_STREAMON, &bufType); if (err < 0) { DEBUG_PRINT(3, "VIDIOC_STREAMON Failed, error: %s", strerror(errno)); } for (int i = 0; i < mBufferCount; i++) { err = ioctl(mHinDevHandle, VIDIOC_QBUF, &mHinNodeInfo->bufferArray[i]); if (err < 0) { DEBUG_PRINT(3, "VIDIOC_QBUF Failed, error: %s", strerror(errno)); } } ALOGD("[%s %d] VIDIOC_STREAMON return=:%d", __FUNCTION__, __LINE__, err);*/ //mState = START; }else{ /*err = ioctl (mHinDevHandle, VIDIOC_STREAMOFF, &bufType); if (err < 0) { DEBUG_PRINT(3, "StopStreaming: Unable to stop capture: %s", strerror(errno)); }*/ mState = STOPED; } DEBUG_PRINT(3, "getHdmiIn : %d.", mIsHdmiIn); return mIsHdmiIn; } int HinDevImpl::set_mode(int displayMode) { DEBUG_PRINT(3, "run into set_mode,displaymode = %d\n", displayMode); mHinNodeInfo->displaymode = displayMode; m_displaymode = displayMode; return 0; } int HinDevImpl::set_format(int width, int height, int color_format) { ALOGD("[%s %d] width=%d, height=%d, color_format=%d, mPixelFormat=%d", __FUNCTION__, __LINE__, width, height, color_format, mPixelFormat); Mutex::Autolock autoLock(mLock); if (mOpen == true) return NO_ERROR; int ret; mFrameWidth = width; mFrameHeight = height; //mPixelFormat = color_format; mHinNodeInfo->width = width; mHinNodeInfo->height = height; mHinNodeInfo->formatIn = mPixelFormat; mHinNodeInfo->format.type = TVHAL_V4L2_BUF_TYPE; mHinNodeInfo->format.fmt.pix.width = width; mHinNodeInfo->format.fmt.pix.height = height; mHinNodeInfo->format.fmt.pix.pixelformat = mPixelFormat; ret = ioctl(mHinDevHandle, VIDIOC_S_FMT, &mHinNodeInfo->format); if (ret < 0) { DEBUG_PRINT(3, "[%s %d] failed, set VIDIOC_S_FMT %d, %s", __FUNCTION__, __LINE__, ret, strerror(ret)); return ret; } else { ALOGD("%s VIDIOC_S_FMT success. ", __FUNCTION__); } int format = getNativeWindowFormat(mPixelFormat); mSidebandWindow->setBufferGeometry(mFrameWidth, mFrameHeight, format); return ret; } int HinDevImpl::set_rotation(int degree) { ALOGD("[%s %d]", __FUNCTION__, __LINE__); int ret = 0; struct v4l2_control ctl; if(mHinDevHandle<0) return -1; if((degree!=0)&&(degree!=90)&&(degree!=180)&&(degree!=270)){ DEBUG_PRINT(3, "Set rotate value invalid: %d.", degree); return -1; } memset( &ctl, 0, sizeof(ctl)); ctl.value=degree; ctl.id = V4L2_ROTATE_ID; ret = ioctl(mHinDevHandle, VIDIOC_S_CTRL, &ctl); if(ret<0){ DEBUG_PRINT(3, "Set rotate value fail: %s. ret=%d", strerror(errno),ret); } return ret ; } int HinDevImpl::set_crop(int x, int y, int width, int height) { ALOGD("[%s %d] crop [%d - %d -%d - %d]", __FUNCTION__, __LINE__, x, y, width, height); mSidebandWindow->setCrop(x, y, width, height); return NO_ERROR; } int HinDevImpl::set_frame_rate(int frameRate) { ALOGD("[%s %d]", __FUNCTION__, __LINE__); int ret = 0; if(mHinDevHandle<0) return -1; struct v4l2_streamparm sparm; memset(&sparm, 0, sizeof( sparm )); sparm.type = TVHAL_V4L2_BUF_TYPE;//stream_flag; sparm.parm.output.timeperframe.denominator = frameRate; sparm.parm.output.timeperframe.numerator = 1; ret = ioctl(mHinDevHandle, VIDIOC_S_PARM, &sparm); if(ret < 0){ DEBUG_PRINT(3, "Set frame rate fail: %s. ret=%d", strerror(errno),ret); } return ret ; } int HinDevImpl::get_hin_crop(int *x, int *y, int *width, int *height) { ALOGD("[%s %d]", __FUNCTION__, __LINE__); int ret = 0; struct v4l2_crop crop; memset(&crop, 0, sizeof(struct v4l2_crop)); crop.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; ret = ioctl(mHinDevHandle, VIDIOC_S_CROP, &crop); if (ret) { DEBUG_PRINT(3, "get amlvideo2 crop fail: %s. ret=%d", strerror(errno),ret); } *x = crop.c.left; *y = crop.c.top; *width = crop.c.width; *height = crop.c.height; return ret ; } int HinDevImpl::set_hin_crop(int x, int y, int width, int height) { ALOGD("[%s %d]", __FUNCTION__, __LINE__); int ret = 0; struct v4l2_crop crop; memset(&crop, 0, sizeof(struct v4l2_crop)); crop.type = TVHAL_V4L2_BUF_TYPE; crop.c.left = x; crop.c.top = y; crop.c.width = width; crop.c.height = height; ret = ioctl(mHinDevHandle, VIDIOC_S_CROP, &crop); if (ret) { DEBUG_PRINT(3, "Set amlvideo2 crop fail: %s. ret=%d", strerror(errno),ret); } return ret ; } int HinDevImpl::get_current_sourcesize(int& width, int& height,int& pixelformat) { int ret = NO_ERROR; v4l2_format format; memset(&format, 0,sizeof(struct v4l2_format)); format.type = TVHAL_V4L2_BUF_TYPE; ret = ioctl(mHinDevHandle, VIDIOC_G_FMT, &format); if (ret < 0) { DEBUG_PRINT(3, "Open: VIDIOC_G_FMT Failed: %s", strerror(errno)); return ret; } width = format.fmt.pix.width; height = format.fmt.pix.height; pixelformat = getNativeWindowFormat(format.fmt.pix.pixelformat); mFrameWidth = width; mFrameHeight = height; mBufferSize = mFrameWidth * mFrameHeight * 3/2; mPixelFormat = format.fmt.pix.pixelformat; ALOGD("VIDIOC_G_FMT, w * h: %5d x %5d, fomat 0x%x", width, height,pixelformat); /*if(mIsHdmiIn){ enum v4l2_buf_type bufType = TVHAL_V4L2_BUF_TYPE; ret = ioctl(mHinDevHandle, VIDIOC_STREAMON, &bufType); ALOGD("[%s %d] VIDIOC_STREAMON return=:%d", __FUNCTION__, __LINE__, ret); if (ret < 0) { DEBUG_PRINT(3, "VIDIOC_STREAMON Failed, error: %s", strerror(errno)); } mState = START; }*/ mState = START; return ret; } int HinDevImpl::set_screen_mode(int mode) { int ret = NO_ERROR; ret = ioctl(mHinDevHandle, VIDIOC_S_OUTPUT, &mode); if (ret < 0) { DEBUG_PRINT(3, "VIDIOC_S_OUTPUT Failed: %s", strerror(errno)); return ret; } return ret; } int HinDevImpl::aquire_buffer() { int ret = UNKNOWN_ERROR; DEBUG_PRINT(mDebugLevel, "%s %d", __FUNCTION__, __LINE__); for (int i = 0; i < mBufferCount; i++) { memset(&mHinNodeInfo->planes[i], 0, sizeof(struct v4l2_plane)); memset(&mHinNodeInfo->bufferArray[i], 0, sizeof(struct v4l2_buffer)); mHinNodeInfo->bufferArray[i].index = i; mHinNodeInfo->bufferArray[i].type = TVHAL_V4L2_BUF_TYPE; mHinNodeInfo->bufferArray[i].memory = TVHAL_V4L2_BUF_MEMORY_TYPE; if (mHinNodeInfo->cap.device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) { mHinNodeInfo->bufferArray[i].m.planes = &mHinNodeInfo->planes[i]; mHinNodeInfo->bufferArray[i].length = PLANES_NUM; } ret = ioctl(mHinDevHandle, VIDIOC_QUERYBUF, &mHinNodeInfo->bufferArray[i]); if (ret < 0) { DEBUG_PRINT(3, "VIDIOC_QUERYBUF Failed, error: %s", strerror(errno)); return ret; } if (mFrameType & TYPF_SIDEBAND_WINDOW) { ret = mSidebandWindow->allocateBuffer(&mHinNodeInfo->buffer_handle_poll[i]); if (ret != 0) { DEBUG_PRINT(3, "mSidebandWindow->allocateBuffer failed !!!"); return ret; } } else { mHinNodeInfo->buffer_handle_poll[i] = mPreviewRawHandle[i].outHandle; } if (mHinNodeInfo->cap.device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) { for (int j=0; jbufferArray[i].m.planes[j].m.fd = mSidebandWindow->getBufferHandleFd(mHinNodeInfo->buffer_handle_poll[i]); if (mFrameType & TYPF_SIDEBAND_WINDOW) { mHinNodeInfo->bufferArray[i].m.planes[j].m.fd = mSidebandWindow->getBufferHandleFd(mHinNodeInfo->buffer_handle_poll[i]); } else { mHinNodeInfo->bufferArray[i].m.planes[j].m.fd = mPreviewRawHandle[i].bufferFd; } mHinNodeInfo->bufferArray[i].m.planes[j].length = 0; } } } ALOGD("[%s %d] VIDIOC_QUERYBUF successful", __FUNCTION__, __LINE__); return -1; } int HinDevImpl::release_buffer() { DEBUG_PRINT(mDebugLevel, "%s %d", __FUNCTION__, __LINE__); if (mSidebandHandle) { mSidebandWindow->freeBuffer(&mSidebandHandle, 0); mSidebandHandle = NULL; } if (mSignalHandle) { mSidebandWindow->freeBuffer(&mSignalHandle, 0); mSignalHandle = NULL; } if (mFrameType & TYPE_STREAM_BUFFER_PRODUCER) { if (!mPreviewRawHandle.empty()) { for (int i=0; ifreeBuffer(&mPreviewRawHandle[i].outHandle, 1); mPreviewRawHandle[i].outHandle = NULL; mHinNodeInfo->buffer_handle_poll[i] = NULL; } mPreviewRawHandle.clear(); } } else { for (int i=0; ifreeBuffer(&mHinNodeInfo->buffer_handle_poll[i], 0); } mHinNodeInfo->buffer_handle_poll[i] = NULL; } } return 0; } int HinDevImpl::set_preview_info(int top, int left, int width, int height) { mPreviewRawHandle.resize(APP_PREVIEW_BUFF_CNT); return 0; } int HinDevImpl::set_preview_buffer(buffer_handle_t rawHandle, uint64_t bufferId) { ALOGD("%s called, rawHandle=%p bufferId=%" PRIu64, __func__, rawHandle, bufferId); int buffHandleFd = mSidebandWindow->importHidlHandleBufferLocked(rawHandle); ALOGD("%s buffHandleFd=%d, after import rawHandle=%p", __FUNCTION__, buffHandleFd, rawHandle); mPreviewRawHandle[mPreviewBuffIndex].bufferFd = buffHandleFd; mPreviewRawHandle[mPreviewBuffIndex].bufferId = bufferId; mPreviewRawHandle[mPreviewBuffIndex].outHandle = rawHandle; mPreviewRawHandle[mPreviewBuffIndex].isRendering = false; mPreviewRawHandle[mPreviewBuffIndex].isFilled = false; mPreviewBuffIndex++; if(mPreviewBuffIndex == APP_PREVIEW_BUFF_CNT) mPreviewBuffIndex = 0; return 0; } int HinDevImpl::request_capture(buffer_handle_t rawHandle, uint64_t bufferId) { //int ret; //int bufferIndex = -1; //ALOGD("rawHandle = %p,bufferId=%lld,%lld" PRIu64, rawHandle,(long long)bufferId,(long long)mPreviewRawHandle[0].bufferId); int previewBufferIndex = -1; for (int i=0; ibufferArray[i].m.planes[0].m.fd; if (fd == mPreviewRawHandle[previewBufferIndex].bufferFd) { bufferIndex = i; requestFd = fd; break; } } DEBUG_PRINT(mDebugLevel, "request_capture previewBufferIndex=%d, bufferIndex=%d, requestFd=%d, bufferId %" PRIu64, previewBufferIndex, bufferIndex, requestFd, bufferId); if ( mFirstRequestCapture/* && mPreviewRawHandle[0].bufferId == bufferId*/) { ALOGW("first request_capture, deque first two buffer for skip"); mFirstRequestCapture = false; mHinNodeInfo->currBufferHandleIndex = 0; mRequestCaptureCount = 2; // mPreviewBuffThread = new PreviewBuffThread(this); // mPreviewThreadRunning = true; //mPreviewBuffIndex = 0; return 0; } if (mState != START) { return 0; } mRequestCaptureCount++; //ALOGD("rawHandle = %p, bufferId=%" PRIu64, rawHandle, bufferId); for (int i=0; ibufferArray[bufferIndex]); if (ret != 0) { ALOGE("VIDIOC_QBUF Buffer failed err=%s bufferIndex %d requestFd=%d %" PRIu64, strerror(errno), bufferIndex, requestFd, bufferId); } ALOGV("%s end.", __FUNCTION__); return mHinNodeInfo->currBufferHandleIndex; } void HinDevImpl::wrapCaptureResultAndNotify(uint64_t buffId,buffer_handle_t handle) { if (mState == STOPED) { return; }; /*if (mFirstRequestCapture && mPreviewRawHandle[0].bufferId == buffId) { ALOGD("first wrapCaptureResultAndNotify, ignore it."); mFirstRequestCapture = false; return; }*/ tv_input_capture_result_t result; result.buff_id = buffId; //ALOGD("%s %lld,end.", __FUNCTION__,(long long)buffId); // result.buffer = handle; //if need if(mNotifyQueueCb != NULL) mNotifyQueueCb(result); } int HinDevImpl::deal_priv_message(const std::string action, const std::map data) { ALOGD("%s %s ", __FUNCTION__, action.c_str()); if (action.compare("hdmiinout") == 0) { if (mFrameType & TYPF_SIDEBAND_WINDOW && NULL != mSidebandWindow) { if (mSignalHandle != NULL) { mSidebandWindow->show(mSignalHandle); } } return 1; } return 0; } int HinDevImpl::workThread() { int ret; if (mState == START /*&& !mFirstRequestCapture*/ && mRequestCaptureCount > 0) { //DEBUG_PRINT(3, "%s %d currBufferHandleIndex = %d", __FUNCTION__, __LINE__, mHinNodeInfo->currBufferHandleIndex); //mHinNodeInfo->bufferArray[mHinNodeInfo->currBufferHandleIndex].flags = V4L2_BUF_FLAG_NO_CACHE_INVALIDATE | // V4L2_BUF_FLAG_NO_CACHE_CLEAN; if (mFrameType & TYPF_SIDEBAND_WINDOW) { if (mHinNodeInfo->currBufferHandleIndex == SIDEBAND_WINDOW_BUFF_CNT) mHinNodeInfo->currBufferHandleIndex = mHinNodeInfo->currBufferHandleIndex % SIDEBAND_WINDOW_BUFF_CNT; } else { if (mHinNodeInfo->currBufferHandleIndex == APP_PREVIEW_BUFF_CNT) mHinNodeInfo->currBufferHandleIndex = mHinNodeInfo->currBufferHandleIndex % APP_PREVIEW_BUFF_CNT; mRequestCaptureCount--; } ret = ioctl(mHinDevHandle, VIDIOC_DQBUF, &mHinNodeInfo->bufferArray[mHinNodeInfo->currBufferHandleIndex]); if (ret < 0) { DEBUG_PRINT(3, "VIDIOC_DQBUF Failed, error: %s", strerror(errno)); return 0; } else { DEBUG_PRINT(mDebugLevel, "VIDIOC_DQBUF successful.mDumpType=%d,mDumpFrameCount=%d",mDumpType,mDumpFrameCount); } #ifdef DUMP_YUV_IMG if (mDumpType == 0 && mDumpFrameCount > 0) { char fileName[128] = {0}; sprintf(fileName, "/data/system/dumpimage/tv_input_dump_%dx%d_%d.yuv", mFrameWidth, mFrameHeight, mDumpFrameCount); mSidebandWindow->dumpImage(mHinNodeInfo->buffer_handle_poll[mHinNodeInfo->currBufferHandleIndex], fileName, 0); mDumpFrameCount--; } else if (mDumpType == 1 && mDumpFrameCount > 0) { char fileName[128] = {0}; sprintf(fileName, "/data/system/dumpimage/tv_input_dump_%dx%d.h264", mFrameWidth, mFrameHeight); mSidebandWindow->dumpImage(mHinNodeInfo->buffer_handle_poll[mHinNodeInfo->currBufferHandleIndex], fileName, 0); mDumpFrameCount--; } #endif if (mFrameType & TYPF_SIDEBAND_WINDOW) { mSidebandWindow->show(mHinNodeInfo->buffer_handle_poll[mHinNodeInfo->currBufferHandleIndex]); ret = ioctl(mHinDevHandle, VIDIOC_QBUF, &mHinNodeInfo->bufferArray[mHinNodeInfo->currBufferHandleIndex]); if (ret != 0) { DEBUG_PRINT(3, "VIDIOC_QBUF Buffer failed %s", strerror(errno)); } else { DEBUG_PRINT(mDebugLevel, "VIDIOC_QBUF %d successful.", mHinNodeInfo->currBufferHandleIndex); } } else { if (mV4L2DataFormatConvert) { mSidebandWindow->buffDataTransfer(mHinNodeInfo->buffer_handle_poll[mHinNodeInfo->currBufferHandleIndex], mPreviewRawHandle[mPreviewBuffIndex].outHandle); } for (int i=0; ibufferArray[mHinNodeInfo->currBufferHandleIndex].m.planes[0].m.fd) { wrapCaptureResultAndNotify(mPreviewRawHandle[i].bufferId,mPreviewRawHandle[i].outHandle); break; } } } debugShowFPS(); mHinNodeInfo->currBufferHandleIndex++; } return NO_ERROR; } void HinDevImpl::debugShowFPS() { if (mShowFps == 0) return; static int mFrameCount = 0; static int mLastFrameCount = 0; static nsecs_t mLastFpsTime = 0; static float mFps = 0; mFrameCount++; if (!(mFrameCount & 0x1F)) { nsecs_t now = systemTime(); nsecs_t diff = now - mLastFpsTime; mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; mLastFpsTime = now; mLastFrameCount = mFrameCount; DEBUG_PRINT(3, "tvinput: %d Frames, %2.3f FPS", mFrameCount, mFps); } } // int HinDevImpl::previewBuffThread() { // int ret; // if (mState == START) { // if (mHinNodeInfo->currBufferHandleIndex == SIDEBAND_WINDOW_BUFF_CNT) // mHinNodeInfo->currBufferHandleIndex = mHinNodeInfo->currBufferHandleIndex % SIDEBAND_WINDOW_BUFF_CNT; // DEBUG_PRINT(mDebugLevel, "%s %d currBufferHandleIndex = %d", __FUNCTION__, __LINE__, mHinNodeInfo->currBufferHandleIndex); // ret = ioctl(mHinDevHandle, VIDIOC_DQBUF, &mHinNodeInfo->bufferArray[mHinNodeInfo->currBufferHandleIndex]); // if (ret < 0) { // DEBUG_PRINT(3, "VIDIOC_DQBUF Failed, error: %s", strerror(errno)); // return -1; // } else { // DEBUG_PRINT(mDebugLevel, "VIDIOC_DQBUF successful."); // } // mSidebandWindow->buffDataTransfer(mHinNodeInfo->buffer_handle_poll[mHinNodeInfo->currBufferHandleIndex], mPreviewRawHandle[mPreviewBuffIndex].outHandle); // mPreviewRawHandle[mPreviewBuffIndex++].isFilled = true; // if (mPreviewBuffIndex == APP_PREVIEW_BUFF_CNT) // mPreviewBuffIndex = mPreviewBuffIndex % APP_PREVIEW_BUFF_CNT; // wrapCaptureResultAndNotify(mPreviewRawHandle[mPreviewBuffIndex].bufferId, mPreviewRawHandle[mPreviewBuffIndex].outHandle); // debugShowFPS(); // ret = ioctl(mHinDevHandle, VIDIOC_QBUF, &mHinNodeInfo->bufferArray[mHinNodeInfo->currBufferHandleIndex]); // if (ret != 0) { // DEBUG_PRINT(3, "VIDIOC_QBUF Buffer failed %s", strerror(errno)); // } else { // DEBUG_PRINT(mDebugLevel, "VIDIOC_QBUF successful."); // } // mHinNodeInfo->currBufferHandleIndex++; // } // return NO_ERROR; // }