From 737fb2980a2e8953db2cca86c00b4abf96bfe4c8 Mon Sep 17 00:00:00 2001 From: Kieth Liu Date: Tue, 22 Sep 2015 02:21:09 +0000 Subject: add frame capture API Change-Id: Ib8c2abcdedb5572d9e1af33a7602acd2ef06ff4b --- diff --git a/Android.mk b/Android.mk index d5ddce6..b7040c8 100644 --- a/Android.mk +++ b/Android.mk @@ -11,33 +11,48 @@ TVAPI_PATH := $(LOCAL_PATH)/tvapi LIB_SQLITE_PATH := $(wildcard external/sqlite) AM_LIBPLAYER_PATH := $(wildcard vendor/amlogic/frameworks/av/LibPlayer) + +ifneq (,$(wildcard hardware/amlogic/gralloc)) + GRALLOC_DIR := hardware/amlogic/gralloc +else + GRALLOC_DIR := hardware/libhardware/modules/gralloc +endif + LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_SHARED_LIBRARIES := libcutils liblog -LOCAL_SRC_FILES := tv_input.cpp +LOCAL_SRC_FILES := tv_input.cpp \ +screen_source/v4l2_vdin.cpp LOCAL_MODULE := tv_input.amlogic LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES += \ $(TVAPI_PATH)/libtv \ $(TVAPI_PATH)/android \ - $(DVB_PATH)/android/ndk/include \ - $(DVB_PATH)/include/am_adp \ - $(DVB_PATH)/include/am_mw \ - $(DVB_PATH)/include/am_ver \ - $(DVB_PATH)/android/ndk/include \ + $(DVB_PATH)/android/ndk/include \ + $(DVB_PATH)/include/am_adp \ + $(DVB_PATH)/include/am_mw \ + $(DVB_PATH)/include/am_ver \ + $(DVB_PATH)/android/ndk/include \ $(LIB_SQLITE_PATH)/dist \ - $(TVAPI_PATH)/libtv/tvdb \ - $(TVAPI_PATH)/libtv/tv \ - $(TVAPI_PATH)/libtv/include \ - $(AM_LIBPLAYER_PATH)/amadec/include \ - $(AM_LIBPLAYER_PATH)/amcodec/include \ - $(AM_LIBPLAYER_PATH)/amffmpeg \ - $(AM_LIBPLAYER_PATH)/amplayer \ - system/media/audio_effects/include \ + $(TVAPI_PATH)/libtv/tvdb \ + $(TVAPI_PATH)/libtv/tv \ + $(TVAPI_PATH)/libtv/include \ + $(AM_LIBPLAYER_PATH)/amadec/include \ + $(AM_LIBPLAYER_PATH)/amcodec/include \ + $(AM_LIBPLAYER_PATH)/amffmpeg \ + $(AM_LIBPLAYER_PATH)/amplayer \ + system/media/audio_effects/include \ + system/core/libion/include \ + system/core/libion/kernel-headers \ + $(GRALLOC_DIR) \ + screen_source LOCAL_SHARED_LIBRARIES += \ libtv \ libtvserver \ libtv_jni + +LOCAL_SHARED_LIBRARIES += libutils liblog libui + include $(BUILD_SHARED_LIBRARY) include $(LOCAL_PATH)/tvapi/Android.mk diff --git a/screen_source/Android.mk b/screen_source/Android.mk new file mode 100644 index 0000000..a40269f --- a/dev/null +++ b/screen_source/Android.mk @@ -0,0 +1,31 @@ +# Copyright (C) 2013 Amlogic +# +# + +LOCAL_PATH := $(call my-dir) + +# HAL module implemenation, not prelinked and stored in +# /system/lib/hw/screen_source.amlogic.so +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := aml_screen.cpp v4l2_vdin.cpp + +ifneq (,$(wildcard hardware/amlogic/gralloc)) + GRALLOC_DIR := hardware/amlogic/gralloc +else + GRALLOC_DIR := hardware/libhardware/modules/gralloc +endif + +LOCAL_C_INCLUDES += frameworks/native/include/utils \ + frameworks/native/include/android \ + system/core/include/utils \ + system/core/libion/include \ + system/core/libion/kernel-headers \ + $(GRALLOC_DIR) + +LOCAL_SHARED_LIBRARIES:= libutils liblog libui + +LOCAL_MODULE := screen_source.amlogic +LOCAL_CFLAGS:= -DLOG_TAG=\"screen_source\" +LOCAL_MODULE_TAGS := optional +include $(BUILD_SHARED_LIBRARY) diff --git a/screen_source/aml_screen.cpp b/screen_source/aml_screen.cpp new file mode 100644 index 0000000..62fb94b --- a/dev/null +++ b/screen_source/aml_screen.cpp @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "screen_source" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + +#include "v4l2_vdin.h" + +#ifndef LOGD +#define LOGD ALOGD +#endif +#ifndef LOGV +#define LOGV ALOGV +#endif +#ifndef LOGE +#define LOGE ALOGE +#endif +#ifndef LOGI +#define LOGI ALOGI +#endif + +static unsigned int gAmlScreenOpen = 0; +static android::Mutex gAmlScreenLock; + +/*****************************************************************************/ + +static int aml_screen_device_open(const struct hw_module_t *module, const char *name, + struct hw_device_t **device); + +static struct hw_module_methods_t aml_screen_module_methods = { +open: + aml_screen_device_open +}; + +aml_screen_module_t HAL_MODULE_INFO_SYM = { +common: + { +tag: + HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, +id: + AML_SCREEN_HARDWARE_MODULE_ID, +name: "aml screen source module" + , +author: "Amlogic" + , +methods: + &aml_screen_module_methods, +dso : + NULL, +reserved : + {0}, + } +}; + +/*****************************************************************************/ + +static int aml_screen_device_close(struct hw_device_t *dev) +{ + android::vdin_screen_source *source = NULL; + aml_screen_device_t *ctx = (aml_screen_device_t *)dev; + + android::Mutex::Autolock lock(gAmlScreenLock); + if (ctx) { + if (ctx->priv) { + source = (android::vdin_screen_source *)ctx->priv; + delete source; + source = NULL; + } + free(ctx); + } + gAmlScreenOpen--; + return 0; +} + +int screen_source_start(struct aml_screen_device *dev) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->start(); +} + +int screen_source_stop(struct aml_screen_device *dev) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->stop(); +} + +int screen_source_pause(struct aml_screen_device *dev) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->pause(); +} + +int screen_source_get_format(struct aml_screen_device *dev) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->get_format(); +} + +int screen_source_set_format(struct aml_screen_device *dev, int width, int height, int pix_format) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + + if ((width > 0) && (height > 0) && ((pix_format == V4L2_PIX_FMT_NV21) || (pix_format == V4L2_PIX_FMT_YUV420))) { + return source->set_format(width, height, pix_format); + } else { + return source->set_format(); + } +} + +int screen_source_set_rotation(struct aml_screen_device *dev, int degree) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->set_rotation(degree); +} + +int screen_source_set_crop(struct aml_screen_device *dev, int x, int y, int width, int height) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + + if ((x >= 0) && (y >= 0) && (width > 0) && (height > 0)) + return source->set_crop(x, y, width, height); + + return android::BAD_VALUE; +} + +int screen_source_set_amlvideo2_crop(struct aml_screen_device *dev, int x, int y, int width, int height) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + + if ((x >= 0) && (y >= 0) && (width > 0) && (height > 0)) + return source->set_amlvideo2_crop(x, y, width, height); + + return android::BAD_VALUE; +} + +int screen_source_aquire_buffer(struct aml_screen_device *dev, aml_screen_buffer_info_t *buff_info) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + + return source->aquire_buffer(buff_info); +} + +int screen_source_release_buffer(struct aml_screen_device *dev, long *ptr) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->release_buffer(ptr); +} + +int screen_source_set_state_callback(struct aml_screen_device *dev, olStateCB callback) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->set_state_callback(callback); +} + +int screen_source_set_preview_window(struct aml_screen_device *dev, ANativeWindow *window) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->set_preview_window(window); +} + +int screen_source_set_data_callback(struct aml_screen_device *dev, app_data_callback callback, void *user) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->set_data_callback(callback, user); +} + +int screen_source_set_frame_rate(struct aml_screen_device *dev, int frameRate) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->set_frame_rate(frameRate); +} + +int screen_source_set_source_type(struct aml_screen_device *dev, SOURCETYPE sourceType) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->set_source_type(sourceType); +} + +int screen_source_get_source_type(struct aml_screen_device *dev) +{ + android::vdin_screen_source *source = (android::vdin_screen_source *)dev->priv; + return source->get_source_type(); +} + +/* int screen_source_inc_buffer_refcount(struct aml_screen_device* dev, int* ptr) +{ + android::vdin_screen_source* source = (android::vdin_screen_source*)dev->priv; + return source->inc_buffer_refcount(ptr); +} */ + +/*****************************************************************************/ + +static int aml_screen_device_open(const struct hw_module_t *module, const char *name, + struct hw_device_t **device) +{ + int status = -EINVAL; + android::vdin_screen_source *source = NULL; + android::Mutex::Autolock lock(gAmlScreenLock); + + LOGV("aml_screen_device_open"); + + if (!strcmp(name, AML_SCREEN_SOURCE)) { + if (gAmlScreenOpen > 1) { + ALOGD("aml screen device already open"); + *device = NULL; + return -EINVAL; + } + + aml_screen_device_t *dev = (aml_screen_device_t *)malloc(sizeof(aml_screen_device_t)); + + if (!dev) { + LOGE("no memory for the screen source device"); + return -ENOMEM; + } + /* initialize handle here */ + memset(dev, 0, sizeof(*dev)); + + source = new android::vdin_screen_source; + if (!source) { + LOGE("no memory for class of vdin_screen_source"); + free (dev); + return -ENOMEM; + } + + if (source->init() != 0) { + LOGE("open vdin_screen_source failed!"); + free (dev); + return -1; + } + + dev->priv = (void *)source; + + /* initialize the procs */ + dev->common.tag = HARDWARE_DEVICE_TAG; + dev->common.version = 0; + dev->common.module = const_cast(module); + dev->common.close = aml_screen_device_close; + + dev->ops.start = screen_source_start; + dev->ops.stop = screen_source_stop; + dev->ops.pause = screen_source_pause; + dev->ops.get_format = screen_source_get_format; + dev->ops.set_format = screen_source_set_format; + dev->ops.set_rotation = screen_source_set_rotation; + dev->ops.set_crop = screen_source_set_crop; + dev->ops.set_amlvideo2_crop = screen_source_set_amlvideo2_crop; + dev->ops.aquire_buffer = screen_source_aquire_buffer; + dev->ops.release_buffer = screen_source_release_buffer; + dev->ops.setStateCallBack = screen_source_set_state_callback; + dev->ops.setPreviewWindow = screen_source_set_preview_window; + dev->ops.setDataCallBack = screen_source_set_data_callback; + dev->ops.set_frame_rate = screen_source_set_frame_rate; + dev->ops.set_source_type = screen_source_set_source_type; + dev->ops.get_source_type = screen_source_get_source_type; + // dev->ops.inc_buffer_refcount = screen_source_inc_buffer_refcount; + *device = &dev->common; + status = 0; + gAmlScreenOpen++; + } + return status; +} diff --git a/screen_source/v4l2_vdin.cpp b/screen_source/v4l2_vdin.cpp new file mode 100644 index 0000000..bd63166 --- a/dev/null +++ b/screen_source/v4l2_vdin.cpp @@ -0,0 +1,676 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ + + +//reinclude because of a bug with the log macros +//#define LOG_NDEBUG 0 +#define LOG_TAG "V4L2VINSOURCE" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "v4l2_vdin.h" +#include +#include +#include + +namespace android { + +#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(x) (x + (BOUNDRY) - 1)& ~((BOUNDRY) - 1) + + 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: + buf_size = width * height * 3 / 2; + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_RGB565: + buf_size = width * height * 2; + break; + case V4L2_PIX_FMT_RGB24: + buf_size = width * height * 3; + break; + case V4L2_PIX_FMT_RGB32: + buf_size = width * height * 4; + break; + default: + ALOGE("Invalid format"); + buf_size = 0; + } + return buf_size; + } + + static int getNativeWindowFormat(int format) + { + int nativeFormat = HAL_PIXEL_FORMAT_YCbCr_422_I; + + switch (format) { + case V4L2_PIX_FMT_YVU420: + nativeFormat = HAL_PIXEL_FORMAT_YV12; + break; + case V4L2_PIX_FMT_NV21: + nativeFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; + break; + case V4L2_PIX_FMT_YUYV: + nativeFormat = HAL_PIXEL_FORMAT_YCbCr_422_I; + break; + case V4L2_PIX_FMT_RGB565: + nativeFormat = HAL_PIXEL_FORMAT_RGB_565; + break; + case V4L2_PIX_FMT_RGB24: + nativeFormat = HAL_PIXEL_FORMAT_RGB_888; + break; + case V4L2_PIX_FMT_RGB32: + nativeFormat = HAL_PIXEL_FORMAT_RGBA_8888; + break; + default: + ALOGE("Invalid format,Use default format"); + } + return nativeFormat; + } + + + static ANativeWindowBuffer *handle_to_buffer(buffer_handle_t *handle) + { + return container_of(handle, ANativeWindowBuffer, handle); + } + + vdin_screen_source::vdin_screen_source() + : mCameraHandle(-1), + mVideoInfo(NULL) + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + } + + int vdin_screen_source::init() + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + mCameraHandle = open("/dev/video11", O_RDWR | O_NONBLOCK); + if (mCameraHandle < 0) { + ALOGE("[%s %d] mCameraHandle:%x [%s]", __FUNCTION__, __LINE__, mCameraHandle, strerror(errno)); + return -1; + } + mVideoInfo = (struct VideoInfo *) calloc (1, sizeof (struct VideoInfo)); + if (mVideoInfo == NULL) { + ALOGE("[%s %d] no memory for mVideoInfo", __FUNCTION__, __LINE__); + close(mCameraHandle); + return NO_MEMORY; + } + mBufferCount = 4; + mPixelFormat = V4L2_PIX_FMT_NV21; + mNativeWindowPixelFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; + mFrameWidth = 1280; + mFrameHeight = 720; + mBufferSize = mFrameWidth * mFrameHeight * 3 / 2; + mSetStateCB = NULL; + mState = STOP; + mANativeWindow = NULL; + mFrameType = 0; + mWorkThread = NULL; + mDataCB = NULL; + mOpen = false; + return NO_ERROR; + } + + vdin_screen_source::~vdin_screen_source() + { + if (mVideoInfo) { + free (mVideoInfo); + } + if (mCameraHandle >= 0) { + close(mCameraHandle); + } + } + + int vdin_screen_source::start_v4l2_device() + { + int ret = -1; + + ALOGV("[%s %d] mCameraHandle:%x", __FUNCTION__, __LINE__, mCameraHandle); + + ioctl(mCameraHandle, VIDIOC_QUERYCAP, &mVideoInfo->cap); + + mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->rb.memory = V4L2_MEMORY_MMAP; + mVideoInfo->rb.count = mBufferCount; + + ret = ioctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); + + if (ret < 0) { + ALOGE("[%s %d] VIDIOC_REQBUFS:%d mCameraHandle:%x", __FUNCTION__, __LINE__, ret, mCameraHandle); + return ret; + } + + for (int i = 0; i < mBufferCount; i++) { + memset (&mVideoInfo->buf, 0, sizeof (struct v4l2_buffer)); + + mVideoInfo->buf.index = i; + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + + ret = ioctl (mCameraHandle, VIDIOC_QUERYBUF, &mVideoInfo->buf); + if (ret < 0) { + ALOGE("[%s %d]VIDIOC_QUERYBUF %d failed", __FUNCTION__, __LINE__, i); + return ret; + } + mVideoInfo->canvas[i] = mVideoInfo->buf.reserved; + mVideoInfo->mem[i] = (long *)mmap (0, mVideoInfo->buf.length, PROT_READ | PROT_WRITE, + MAP_SHARED, mCameraHandle, mVideoInfo->buf.m.offset); + + if (mVideoInfo->mem[i] == MAP_FAILED) { + ALOGE("[%s %d] MAP_FAILED", __FUNCTION__, __LINE__); + return -1; + } + mVideoInfo->refcount[i] = 0; + mBufs.add(mVideoInfo->mem[i], i); + } + ALOGV("[%s %d] VIDIOC_QUERYBUF successful", __FUNCTION__, __LINE__); + + for (int i = 0; i < mBufferCount; i++) { + mVideoInfo->buf.index = i; + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + ret = ioctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); + if (ret < 0) { + ALOGE("VIDIOC_QBUF Failed"); + return -1; + } + } + enum v4l2_buf_type bufType; + bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret = ioctl (mCameraHandle, VIDIOC_STREAMON, &bufType); + + ALOGV("[%s %d] VIDIOC_STREAMON:%x", __FUNCTION__, __LINE__, ret); + return ret; + } + + int vdin_screen_source::stop_v4l2_device() + { + int ret; + enum v4l2_buf_type bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret = ioctl (mCameraHandle, VIDIOC_STREAMOFF, &bufType); + if (ret < 0) { + ALOGE("StopStreaming: Unable to stop capture: %s", strerror(errno)); + } + for (int i = 0; i < mBufferCount; i++) { + if (munmap(mVideoInfo->mem[i], mVideoInfo->buf.length) < 0) { + ALOGE("Unmap failed"); + } + } + return ret; + } + + int vdin_screen_source::start() + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + int ret; + if (mOpen == true) { + ALOGI("already open"); + return NO_ERROR; + } + + ret = start_v4l2_device(); + if (ret != NO_ERROR) { + ALOGE("Start v4l2 device failed:%d", ret); + return ret; + } + if (mFrameType & NATIVE_WINDOW_DATA) { + ret = init_native_window(); + if (ret != NO_ERROR) { + ALOGE("Init Native Window Failed:%d", ret); + return ret; + } + } + if (mFrameType & NATIVE_WINDOW_DATA || mFrameType & CALL_BACK_DATA) { + ALOGD("Create Work Thread"); + mWorkThread = new WorkThread(this); + } + if (mSetStateCB != NULL) { + mSetStateCB(START); + } + mState = START; + mOpen = true; + ALOGV("%s %d ret:%d", __FUNCTION__, __LINE__, ret); + return NO_ERROR; + } + + int vdin_screen_source::pause() + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + mState = PAUSE; + if (mSetStateCB != NULL) { + mSetStateCB(PAUSE); + } + return NO_ERROR; + } + int vdin_screen_source::stop() + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + int ret; + mState = STOPING; + + if (mWorkThread != NULL) { + mWorkThread->requestExitAndWait(); + mWorkThread.clear(); + } + + mBufferCount = 0; + mState = STOP; + if (mSetStateCB != NULL) { + mSetStateCB(STOP); + } + mOpen = false; + return ret; + } + + int vdin_screen_source::set_state_callback(olStateCB callback) + { + if (!callback) { + ALOGE("NULL state callback pointer"); + return BAD_VALUE; + } + mSetStateCB = callback; + return NO_ERROR; + } + + int vdin_screen_source::set_preview_window(ANativeWindow *window) + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + if (mOpen == true) { + return NO_ERROR; + } + //can work without a valid window object ? + if (window == NULL) { + ALOGD("NULL window object passed to ScreenSource"); + if (mWorkThread != NULL) { + mWorkThread->requestExitAndWait(); + mWorkThread.clear(); + } + mFrameType &= ~NATIVE_WINDOW_DATA; + return NO_ERROR; + } + mFrameType |= NATIVE_WINDOW_DATA; + mANativeWindow = window; + return NO_ERROR; + } + + int vdin_screen_source::set_data_callback(app_data_callback callback, void *user) + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + if (callback == NULL) { + ALOGE("NULL data callback pointer"); + return BAD_VALUE; + } + mDataCB = callback; + mUser = user; + mFrameType |= CALL_BACK_DATA; + return NO_ERROR; + } + + int vdin_screen_source::get_format() + { + return mPixelFormat; + } + + int vdin_screen_source::set_format(int width, int height, int color_format) + { + ALOGV("[%s %d]", __FUNCTION__, __LINE__); + if (mOpen == true) { + return NO_ERROR; + } + int ret; + mVideoInfo->width = ALIGN(width); + mVideoInfo->height = height; + mVideoInfo->framesizeIn = (mVideoInfo->width * mVideoInfo->height << 3); //note color format + mVideoInfo->formatIn = color_format; + + mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->format.fmt.pix.width = ALIGN(width); + mVideoInfo->format.fmt.pix.height = height; + mVideoInfo->format.fmt.pix.pixelformat = color_format; + mPixelFormat = color_format; + mNativeWindowPixelFormat = getNativeWindowFormat(color_format); + mFrameWidth = ALIGN(width); + mFrameHeight = height; + mBufferSize = getBufSize(color_format, mFrameWidth, mFrameHeight); + ALOGD("mFrameWidth:%d,mFrameHeight:%d", mFrameWidth, mFrameHeight); + ALOGD("mPixelFormat:%x,mNativeWindowPixelFormat:%x,mBufferSize:%d", mPixelFormat, mNativeWindowPixelFormat, mBufferSize); + ret = ioctl(mCameraHandle, VIDIOC_S_FMT, &mVideoInfo->format); + if (ret < 0) { + ALOGE("[%s %d]VIDIOC_S_FMT %d", __FUNCTION__, __LINE__, ret); + return ret; + } + return ret; + } + + int vdin_screen_source::set_rotation(int degree) + { + ALOGV("[%s %d]", __FUNCTION__, __LINE__); + + int ret = 0; + struct v4l2_control ctl; + + if (mCameraHandle < 0) { + return -1; + } + + if ((degree != 0) && (degree != 90) && (degree != 180) && (degree != 270)) { + ALOGE("Set rotate value invalid: %d.", degree); + return -1; + } + + memset( &ctl, 0, sizeof(ctl)); + ctl.value = degree; + ctl.id = V4L2_ROTATE_ID; + ret = ioctl(mCameraHandle, VIDIOC_S_CTRL, &ctl); + + if (ret < 0) { + ALOGE("Set rotate value fail: %s. ret=%d", strerror(errno), ret); + } + return ret ; + } + + int vdin_screen_source::set_crop(int x, int y, int width, int height) + { + ALOGV("[%s %d]", __FUNCTION__, __LINE__); + if (NULL == mANativeWindow.get()) + return BAD_VALUE; + + int err = NO_ERROR; + android_native_rect_t crop = { x, y, x + width - 1, y + height - 1 }; + err = native_window_set_crop(mANativeWindow.get(), &crop); + if (err != 0) { + ALOGW("Failed to set crop!"); + return err; + } + return NO_ERROR; + } + + int vdin_screen_source::set_frame_rate(int frameRate) + { + ALOGV("[%s %d]", __FUNCTION__, __LINE__); + int ret = 0; + struct v4l2_control ctl; + + if (mCameraHandle < 0) { + return -1; + } + + struct v4l2_streamparm sparm; + memset(&sparm, 0, sizeof( sparm )); + sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//stream_flag; + sparm.parm.output.timeperframe.denominator = frameRate; + sparm.parm.output.timeperframe.numerator = 1; + + ret = ioctl(mCameraHandle, VIDIOC_S_PARM, &sparm); + if (ret < 0) { + ALOGE("Set frame rate fail: %s. ret=%d", strerror(errno), ret); + } + return ret ; + } + + int vdin_screen_source::set_amlvideo2_crop(int x, int y, int width, int height) + { + ALOGV("[%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; + crop.c.left = x; + crop.c.top = y; + crop.c.width = width; + crop.c.height = height; + ret = ioctl(mCameraHandle, VIDIOC_S_CROP, &crop); + if (ret) { + ALOGE("Set frame rate fail: %s. ret=%d", strerror(errno), ret); + } + + return ret ; + } + + int vdin_screen_source::set_source_type(int sourceType) + { + ALOGV("[%s %d]", __FUNCTION__, __LINE__); + int ret = 0; + + ret = ioctl(mCameraHandle, VIDIOC_S_INPUT, &sourceType); + if (ret < 0) { + ALOGE("Set source type fail: %s. ret:%d", strerror(errno), ret); + } + return ret; + } + + int vdin_screen_source::get_source_type() + { + ALOGV("[%s %d]", __FUNCTION__, __LINE__); + int ret = -1; + int sourceType; + + ret = ioctl(mCameraHandle, VIDIOC_G_INPUT, &sourceType); + if (ret < 0) { + ALOGE("Set source type fail: %s. ret:%d", strerror(errno), ret); + return ret; + } + return sourceType; + } + + int vdin_screen_source::aquire_buffer(aml_screen_buffer_info_t *buff_info) + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + int ret = -1; + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + + ret = ioctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf); + if (ret < 0) { + if (EAGAIN == errno) { + ret = -EAGAIN; + } else { + ALOGE("[%s %d]aquire_buffer %d", __FUNCTION__, __LINE__, ret); + } + buff_info->buffer_mem = 0; + buff_info->buffer_canvas = 0; + return ret; + } + buff_info->buffer_mem = mVideoInfo->mem[mVideoInfo->buf.index]; + buff_info->buffer_canvas = mVideoInfo->canvas[mVideoInfo->buf.index]; + buff_info->tv_sec = mVideoInfo->buf.timestamp.tv_sec; + buff_info->tv_usec = mVideoInfo->buf.timestamp.tv_usec; + return ret; + } + + /* int vdin_screen_source::inc_buffer_refcount(int *ptr){ + ALOGV("%s %d", __FUNCTION__, __LINE__); + int ret = -1; + int index; + index = mBufs.valueFor((unsigned int)ptr); + mVideoInfo->refcount[index] += 1; + return true; + } */ + + int vdin_screen_source::release_buffer(long *ptr) + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + int ret = -1; + int currentIndex; + v4l2_buffer hbuf_query; + + Mutex::Autolock autoLock(mLock); + + currentIndex = mBufs.valueFor(ptr); + if (mVideoInfo->refcount[currentIndex] > 0) { + mVideoInfo->refcount[currentIndex] -= 1; + } else { + ALOGE("return buffer when refcount already zero"); + return 0; + } + if (mVideoInfo->refcount[currentIndex] == 0) { + memset(&hbuf_query, 0, sizeof(v4l2_buffer)); + hbuf_query.index = currentIndex; + hbuf_query.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + hbuf_query.memory = V4L2_MEMORY_MMAP; + ALOGV("return buffer :%d", currentIndex); + ret = ioctl(mCameraHandle, VIDIOC_QBUF, &hbuf_query); + if (ret != 0) { + ALOGE("Return Buffer :%d failed", currentIndex); + } + } + return 0; + } + + int vdin_screen_source::init_native_window() + { + ALOGV("%s %d", __FUNCTION__, __LINE__); + int err = NO_ERROR; + + if (NULL == mANativeWindow.get()) { + return BAD_VALUE; + } + + // Set gralloc usage bits for window. + err = native_window_set_usage(mANativeWindow.get(), SCREENSOURCE_GRALLOC_USAGE); + if (err != 0) { + ALOGE("native_window_set_usage failed: %s\n", strerror(-err)); + if (ENODEV == err ) { + ALOGE("Preview surface abandoned!"); + mANativeWindow = NULL; + } + return err; + } + + ALOGD("Number of buffers set to ANativeWindow %d", mBufferCount); + ///Set the number of buffers needed for camera preview + err = native_window_set_buffer_count(mANativeWindow.get(), mBufferCount); + if (err != 0) { + ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), -err); + if (ENODEV == err) { + ALOGE("Preview surface abandoned!"); + mANativeWindow = NULL; + } + return err; + } + + ALOGD("native_window_set_buffers_geometry format:0x%x", mNativeWindowPixelFormat); + // Set window geometry + err = native_window_set_buffers_geometry( + mANativeWindow.get(), + mFrameWidth, + mFrameHeight, + mNativeWindowPixelFormat); + + if (err != 0) { + ALOGE("native_window_set_buffers_geometry failed: %s", strerror(-err)); + if ( ENODEV == err ) { + ALOGE("Surface abandoned!"); + mANativeWindow = NULL; + } + return err; + } + err = native_window_set_scaling_mode(mANativeWindow.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + if (err != 0) { + ALOGW("Failed to set scaling mode: %d", err); + return err; + } + return NO_ERROR; + } + + int vdin_screen_source::workThread() + { + bool buff_keep = false; + int index; + aml_screen_buffer_info_t buff_info; + int ret; + long *src = NULL; + unsigned char *dest = NULL; + uint8_t *handle = NULL; + ANativeWindowBuffer *buf; + if (mState == START) { + usleep(5000); + ret = aquire_buffer(&buff_info); + if (ret != 0 || (buff_info.buffer_mem == 0)) { + ALOGV("Get V4l2 buffer failed"); + return ret; + } + src = (long *)buff_info.buffer_mem; + index = mBufs.valueFor(src); + if (mFrameType & NATIVE_WINDOW_DATA) { + mVideoInfo->refcount[index] += 1; + if (mANativeWindow.get() == NULL) { + ALOGE("Null window"); + return BAD_VALUE; + } + ret = mANativeWindow->dequeueBuffer_DEPRECATED(mANativeWindow.get(), &buf); + if (ret != 0) { + ALOGE("dequeue buffer failed :%s (%d)", strerror(-ret), -ret); + return BAD_VALUE; + } + mANativeWindow->lockBuffer_DEPRECATED(mANativeWindow.get(), buf); + sp graphicBuffer(new GraphicBuffer(buf, false)); + graphicBuffer->lock(SCREENSOURCE_GRALLOC_USAGE, (void **)&dest); + if (dest == NULL) { + ALOGE("Invalid Gralloc Handle"); + return BAD_VALUE; + } + memcpy(dest, src, mBufferSize); + graphicBuffer->unlock(); + mANativeWindow->queueBuffer_DEPRECATED(mANativeWindow.get(), buf); + graphicBuffer.clear(); + ALOGV("queue one buffer to native window"); + release_buffer(src); + } + if (mFrameType & CALL_BACK_DATA && mDataCB != NULL && mState == START) { + mVideoInfo->refcount[index] += 1; + mDataCB(mUser, &buff_info); + } + } + return NO_ERROR; + } + +} diff --git a/screen_source/v4l2_vdin.h b/screen_source/v4l2_vdin.h new file mode 100644 index 0000000..0277884 --- a/dev/null +++ b/screen_source/v4l2_vdin.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace android { + +#define NB_BUFFER 6 + + struct VideoInfo { + struct v4l2_capability cap; + struct v4l2_format format; + struct v4l2_buffer buf; + struct v4l2_requestbuffers rb; + long *mem[NB_BUFFER]; + unsigned canvas[NB_BUFFER]; + unsigned refcount[NB_BUFFER]; + bool isStreaming; + int width; + int height; + int formatIn; + int framesizeIn; + }; + enum State { + START, + PAUSE, + STOPING, + STOP, + }; + + enum FrameType { + NATIVE_WINDOW_DATA = 0x1, + CALL_BACK_DATA = 0x2, + }; + + typedef void (*olStateCB)(int state); + + typedef void (*app_data_callback)(void *user, aml_screen_buffer_info_t *buff_info); + +#define SCREENSOURCE_GRALLOC_USAGE GRALLOC_USAGE_HW_TEXTURE | \ + GRALLOC_USAGE_HW_RENDER | \ + GRALLOC_USAGE_SW_READ_RARELY | \ + GRALLOC_USAGE_SW_WRITE_NEVER + + class vdin_screen_source { + public: + vdin_screen_source(); + ~vdin_screen_source(); + int init(); + int start(); + int stop(); + int pause(); + int get_format(); + int set_format(int width = 640, int height = 480, int color_format = V4L2_PIX_FMT_NV21); + int set_rotation(int degree); + int set_crop(int x, int y, int width, int height); + int set_amlvideo2_crop(int x, int y, int width, int height); + int aquire_buffer(aml_screen_buffer_info_t *buff_info); + // int inc_buffer_refcount(int* ptr); + int release_buffer(long *ptr); + int set_state_callback(olStateCB callback); + int set_data_callback(app_data_callback callback, void *user); + int set_preview_window(ANativeWindow *window); + int set_frame_rate(int frameRate); + int set_source_type(int sourceType); + int get_source_type(); + int start_v4l2_device(); + int stop_v4l2_device(); + private: + int init_native_window(); + int workThread(); + private: + class WorkThread : public Thread { + vdin_screen_source *mSource; + public: + WorkThread(vdin_screen_source *source) : + Thread(false), mSource(source) { } + virtual void onFirstRef() + { + run("vdin screen source work thread", PRIORITY_URGENT_DISPLAY); + } + virtual bool threadLoop() + { + mSource->workThread(); + // loop until we need to quit + return true; + } + }; + private: + int mCurrentIndex; + KeyedVector mBufs; + int mBufferCount; + int mFrameWidth; + int mFrameHeight; + int mBufferSize; + volatile int mState; + olStateCB mSetStateCB; + int mPixelFormat; + int mNativeWindowPixelFormat; + sp mANativeWindow; + sp mWorkThread; + mutable Mutex mLock; + int mCameraHandle; + struct VideoInfo *mVideoInfo; + int mFrameType; + app_data_callback mDataCB; + bool mOpen; + void *mUser; + }; + +} diff --git a/tv_input.cpp b/tv_input.cpp index 0cfc0b4..8c8a224 100644 --- a/tv_input.cpp +++ b/tv_input.cpp @@ -25,12 +25,20 @@ #include #include #include +#include +#include +#include /*****************************************************************************/ #define LOGD(...) \ { \ __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__); } +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof(((type *) 0)->member) *__mptr = (ptr); \ + (type *) ((char *) __mptr - (char *)(&((type *)0)->member)); }) +#endif typedef struct tv_input_private { tv_input_device_t device; @@ -40,6 +48,7 @@ typedef struct tv_input_private { void *callback_data; //TvService* pTvService; CTv *pTv; + vdin_screen_source *pScreen; } tv_input_private_t; static int notify_ATV_device_available(tv_input_private_t *priv) @@ -290,7 +299,7 @@ static int tv_input_initialize(struct tv_input_device *dev, /* HDMI3_DEVICE_AVAILABLE */ notify_HDMI_device_available(priv, SOURCE_HDMI3, 1); notify_HDMI_stream_configurations_change(priv, SOURCE_HDMI3, 1); - + // return 0; } @@ -318,6 +327,8 @@ static int tv_input_open_stream(struct tv_input_device *dev, int device_id, priv->pTv->SetSourceSwitchInput((tv_source_input_t) device_id); return 0; } else if (stream->stream_id == FRAME_CAPTURE_STREAM_ID) { + priv->pScreen->set_format(1920, 1080, V4L2_PIX_FMT_NV21); + priv->pScreen->start_v4l2_device(); return 0; } } @@ -328,18 +339,49 @@ static int tv_input_close_stream(struct tv_input_device *dev, int device_id, int stream_id) { tv_input_private_t *priv = (tv_input_private_t *)dev; - if (priv) { + if (stream_id == NORMAL_STREAM_ID) { LOGD ( "%s, SetSourceSwitchInput id = %d\n", __FUNCTION__, device_id ); priv->pTv->StopTvLock(); return 0; + } else if (stream_id == FRAME_CAPTURE_STREAM_ID) { + priv->pScreen->stop_v4l2_device(); + return 0; } return -EINVAL; } static int tv_input_request_capture( - struct tv_input_device *, int, int, buffer_handle_t, uint32_t) + struct tv_input_device *dev, int device_id, int stream_id, buffer_handle_t buffer, uint32_t seq) { - return -EINVAL; + tv_input_private_t *priv = (tv_input_private_t *)dev; + int index; + aml_screen_buffer_info_t buff_info; + int mFrameWidth , mFrameHeight ; + int ret; + long *src = NULL; + unsigned char *dest = NULL; + ANativeWindowBuffer *buf; + ret = priv->pScreen->aquire_buffer(&buff_info); + if (ret != 0 || (buff_info.buffer_mem == 0)) { + LOGD("Get V4l2 buffer failed"); + return -EWOULDBLOCK; + } + src = (long *)buff_info.buffer_mem; + + buf = container_of(&buffer, ANativeWindowBuffer, handle); + + sp graphicBuffer(new GraphicBuffer(buf, false)); + graphicBuffer->lock(SCREENSOURCE_GRALLOC_USAGE, (void **)&dest); + if (dest == NULL) { + LOGD("Invalid Gralloc Handle"); + return -EWOULDBLOCK; + } + memcpy(dest, src, mFrameWidth * mFrameHeight * 3 / 2); + graphicBuffer->unlock(); + graphicBuffer.clear(); + LOGD("queue one buffer to native window"); + priv->pScreen->release_buffer(src); + return 0; } static int tv_input_cancel_capture(struct tv_input_device *, int, int, uint32_t) @@ -376,6 +418,10 @@ static int tv_input_device_open(const struct hw_module_t *module, dev->pTv = new CTv(); TvService::instantiate(dev->pTv); dev->pTv->OpenTv(); + dev->pScreen = new vdin_screen_source(); + if (dev->pScreen->init() != 0 ) { + LOGD("init screen source not ok!"); + } /* initialize the procs */ dev->device.common.tag = HARDWARE_DEVICE_TAG; dev->device.common.version = TV_INPUT_DEVICE_API_VERSION_0_1; -- cgit