/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*#error uncomment this for compiler test!*/
//#define ALOG_NDEBUG 0
#define ALOG_NIDEBUG 0
#define LOG_TAG "QualcommUsbCamera"
#include <utils/Log.h>
#include <utils/threads.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <pthread.h>
#include <linux/uvcvideo.h>
#include "QCameraHAL.h"
#include "QualcommUsbCamera.h"
#include "QCameraUsbPriv.h"
#include "QCameraMjpegDecode.h"
#include "QCameraUsbParm.h"
#include <gralloc_priv.h>
#include <genlock.h>
extern "C" {
#include <sys/time.h>
}
camera_device_ops_t usbcam_camera_ops = {
set_preview_window: android::usbcam_set_preview_window,
set_callbacks: android::usbcam_set_CallBacks,
enable_msg_type: android::usbcam_enable_msg_type,
disable_msg_type: android::usbcam_disable_msg_type,
msg_type_enabled: android::usbcam_msg_type_enabled,
start_preview: android::usbcam_start_preview,
stop_preview: android::usbcam_stop_preview,
preview_enabled: android::usbcam_preview_enabled,
store_meta_data_in_buffers: android::usbcam_store_meta_data_in_buffers,
start_recording: android::usbcam_start_recording,
stop_recording: android::usbcam_stop_recording,
recording_enabled: android::usbcam_recording_enabled,
release_recording_frame: android::usbcam_release_recording_frame,
auto_focus: android::usbcam_auto_focus,
cancel_auto_focus: android::usbcam_cancel_auto_focus,
take_picture: android::usbcam_take_picture,
cancel_picture: android::usbcam_cancel_picture,
set_parameters: android::usbcam_set_parameters,
get_parameters: android::usbcam_get_parameters,
put_parameters: android::usbcam_put_parameters,
send_command: android::usbcam_send_command,
release: android::usbcam_release,
dump: android::usbcam_dump,
};
#define CAPTURE 1
#define DISPLAY 1
#define CALL_BACK 1
#define MEMSET 0
#define FREAD_JPEG_PICTURE 0
#define JPEG_ON_USB_CAMERA 1
#define FILE_DUMP_CAMERA 0
#define FILE_DUMP_B4_DISP 0
namespace android {
static int initUsbCamera( camera_hardware_t *camHal,
int width, int height,
int pixelFormat);
static int startUsbCamCapture( camera_hardware_t *camHal);
static int stopUsbCamCapture( camera_hardware_t *camHal);
static int initV4L2mmap( camera_hardware_t *camHal);
static int unInitV4L2mmap( camera_hardware_t *camHal);
static int launch_preview_thread( camera_hardware_t *camHal);
static int launchTakePictureThread( camera_hardware_t *camHal);
static int initDisplayBuffers( camera_hardware_t *camHal);
static int deInitDisplayBuffers( camera_hardware_t *camHal);
static int stopPreviewInternal( camera_hardware_t *camHal);
static int get_buf_from_cam( camera_hardware_t *camHal);
static int put_buf_to_cam( camera_hardware_t *camHal);
static int prvwThreadTakePictureInternal(camera_hardware_t *camHal);
static int get_buf_from_display( camera_hardware_t *camHal, int *buffer_id);
static int put_buf_to_display( camera_hardware_t *camHal, int buffer_id);
static int convert_data_frm_cam_to_disp(camera_hardware_t *camHal, int buffer_id);
static void * previewloop(void *);
static void * takePictureThread(void *);
static int convert_YUYV_to_420_NV12(char *in_buf, char *out_buf, int wd, int ht);
static int get_uvc_device(char *devname);
static int getPreviewCaptureFmt(camera_hardware_t *camHal);
static int allocate_ion_memory(QCameraHalMemInfo_t *mem_info, int ion_type);
static int deallocate_ion_memory(QCameraHalMemInfo_t *mem_info);
static int ioctlLoop(int fd, int ioctlCmd, void *args);
static int readFromFile(char* fileName, char* buffer, int bufferSize);
static int fileDump(const char* fileName, char* data, int length, int* frm_cnt);
static int encodeJpeg( camera_hardware_t *camHal);
void jpegEncodeCb (jpeg_job_status_t status,
uint8_t thumbnailDroppedFlag,
uint32_t client_hdl,
uint32_t jobId,
uint8_t* out_data,
uint32_t data_size,
void *userData);
/* HAL function implementation goes here*/
/**
* The functions need to be provided by the camera HAL.
*
* If getNumberOfCameras() returns N, the valid cameraId for getCameraInfo()
* and openCameraHardware() is 0 to N-1.
*/
extern "C" int usbcam_get_number_of_cameras()
{
/* TBR: This is hardcoded currently to 1 USB camera */
int numCameras = 1;
ALOGI("%s: E", __func__);
ALOGI("%s: X", __func__);
return numCameras;
}
extern "C" int usbcam_get_camera_info(int camera_id, struct camera_info *info)
{
int rc = -1;
ALOGI("%s: E", __func__);
/* TBR: This info is hardcoded currently irrespective of camera_id */
if(info) {
struct CameraInfo camInfo;
memset(&camInfo, -1, sizeof (struct CameraInfo));
info->facing = CAMERA_FACING_FRONT;//CAMERA_FACING_BACK;
info->orientation = 0;
rc = 0;
}
ALOGI("%s: X", __func__);
return rc;
}
/* HAL should return NULL handle if it fails to open camera hardware. */
extern "C" int usbcam_camera_device_open(
const struct hw_module_t* module, const char* id,
struct hw_device_t** hw_device)
{
int rc = -1;
camera_device *device = NULL;
camera_hardware_t *camHal;
char *dev_name;
ALOGI("%s: E", __func__);
/* initialize return handle value to NULL */
*hw_device = NULL;
camHal = new camera_hardware_t();
if(!camHal) {
ALOGE("%s: end in no mem", __func__);
return -1;
}
rc = usbCamInitDefaultParameters(camHal);
if(0 != rc)
{
ALOGE("%s: usbCamInitDefaultParameters error", __func__);
return rc;
}
#if CAPTURE
dev_name = camHal->dev_name;
rc = get_uvc_device(dev_name);
if(rc || *dev_name == '\0'){
ALOGE("%s: No UVC node found \n", __func__);
return -1;
}
camHal->fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
if (camHal->fd < 0) {
ALOGE("%s: Cannot open '%s'", __func__, dev_name);
free(camHal);
rc = -1;
}else{
rc = 0;
}
#else /* CAPTURE */
rc = 0;
#endif /* CAPTURE */
device = &camHal->hw_dev;
device->common.close = usbcam_close_camera_device;
device->ops = &usbcam_camera_ops;
device->priv = (void *)camHal;
*hw_device = &(device->common);
ALOGD("%s: camHal: %p", __func__, camHal);
ALOGI("%s: X %d", __func__, rc);
return rc;
}
extern "C" int usbcam_close_camera_device( hw_device_t *hw_dev)
{
ALOGI("%s: device =%p E", __func__, hw_dev);
int rc = -1;
camera_device_t *device = (camera_device_t *)hw_dev;
if(device) {
camera_hardware_t *camHal = (camera_hardware_t *)device->priv;
if(camHal) {
rc = close(camHal->fd);
if(rc < 0) {
ALOGE("%s: close failed ", __func__);
}
camHal->fd = 0;
delete camHal;
}else{
ALOGE("%s: camHal is NULL pointer ", __func__);
}
}
ALOGI("%s: X device =%p, rc = %d", __func__, hw_dev, rc);
return rc;
}
int usbcam_set_preview_window(struct camera_device * device,
struct preview_stream_ops *window)
{
ALOGI("%s: E", __func__);
int rc = 0;
camera_hardware_t *camHal;
VALIDATE_DEVICE_HDL(camHal, device, -1);
Mutex::Autolock autoLock(camHal->lock);
/* if window is already set, then de-init previous buffers */
if(camHal->window){
rc = deInitDisplayBuffers(camHal);
if(rc < 0) {
ALOGE("%s: deInitDisplayBuffers returned error", __func__);
}
}
camHal->window = window;
if(camHal->window){
rc = initDisplayBuffers(camHal);
if(rc < 0) {
ALOGE("%s: initDisplayBuffers returned error", __func__);
}
}
ALOGI("%s: X. rc = %d", __func__, rc);
return rc;
}
void usbcam_set_CallBacks(struct camera_device * device,
camera_notify_callback notify_cb,
camera_data_callback data_cb,
camera_data_timestamp_callback data_cb_timestamp,
camera_request_memory get_memory,
void *user)
{
ALOGI("%s: E", __func__);
camera_hardware_t *camHal;
if(device && device->priv){
camHal = (camera_hardware_t *)device->priv;
}else{
ALOGE("%s: Null device or device->priv", __func__);
return;
}
Mutex::Autolock autoLock(camHal->lock);
camHal->notify_cb = notify_cb;
camHal->data_cb = data_cb;
camHal->data_cb_timestamp = data_cb_timestamp;
camHal->get_memory = get_memory;
camHal->cb_ctxt = user;
ALOGI("%s: X", __func__);
}
void usbcam_enable_msg_type(struct camera_device * device, int32_t msg_type)
{
ALOGI("%s: E", __func__);
ALOGI("%s: msg_type: %d", __func__, msg_type);
camera_hardware_t *camHal;
if(device && device->priv){
camHal = (camera_hardware_t *)device->priv;
}else{
ALOGE("%s: Null device or device->priv", __func__);
return;
}
Mutex::Autolock autoLock(camHal->lock);
camHal->msgEnabledFlag |= msg_type;
ALOGI("%s: X", __func__);
}
void usbcam_disable_msg_type(struct camera_device * device, int32_t msg_type)
{
ALOGI("%s: E", __func__);
ALOGI("%s: msg_type: %d", __func__, msg_type);
camera_hardware_t *camHal;
if(device && device->priv){
camHal = (camera_hardware_t *)device->priv;
}else{
ALOGE("%s: Null device or device->priv", __func__);
return;
}
Mutex::Autolock autoLock(camHal->lock);
camHal->msgEnabledFlag &= ~msg_type;
ALOGI("%s: X", __func__);
}
int usbcam_msg_type_enabled(struct camera_device * device, int32_t msg_type)
{
ALOGI("%s: E", __func__);
camera_hardware_t *camHal;
if(device && device->priv){
camHal = (camera_hardware_t *)device->priv;
}else{
ALOGE("%s: Null device or device->priv", __func__);
return -1;
}
Mutex::Autolock autoLock(camHal->lock);
ALOGI("%s: X", __func__);
return (camHal->msgEnabledFlag & msg_type);
}
int usbcam_start_preview(struct camera_device * device)
{
ALOGI("%s: E", __func__);
int rc = -1;
camera_hardware_t *camHal = NULL;
VALIDATE_DEVICE_HDL(camHal, device, -1);
Mutex::Autolock autoLock(camHal->lock);
/* If preivew is already running, nothing to be done */
if(camHal->previewEnabledFlag){
ALOGI("%s: Preview is already running", __func__);
return 0;
}
#if CAPTURE
rc = initUsbCamera(camHal, camHal->prevWidth,
camHal->prevHeight, getPreviewCaptureFmt(camHal));
if(rc < 0) {
ALOGE("%s: Failed to intialize the device", __func__);
}else{
rc = startUsbCamCapture(camHal);
if(rc < 0) {
ALOGE("%s: Failed to startUsbCamCapture", __func__);
}else{
rc = launch_preview_thread(camHal);
if(rc < 0) {
ALOGE("%s: Failed to launch_preview_thread", __func__);
}
}
}
#else /* CAPTURE */
rc = launch_preview_thread(camHal);
if(rc < 0) {
ALOGE("%s: Failed to launch_preview_thread", __func__);
}
#endif /* CAPTURE */
/* if no errors, then set the flag */
if(!rc)
camHal->previewEnabledFlag = 1;
ALOGD("%s: X", __func__);
return rc;
}
void usbcam_stop_preview(struct camera_device * device)
{
ALOGD("%s: E", __func__);
int rc = 0;
camera_hardware_t *camHal;
if(device && device->priv){
camHal = (camera_hardware_t *)device->priv;
}else{
ALOGE("%s: Null device or device->priv", __func__);
return;
}
Mutex::Autolock autoLock(camHal->lock);
rc = stopPreviewInternal(camHal);
if(rc)
ALOGE("%s: stopPreviewInternal returned error", __func__);
ALOGI("%s: X", __func__);
return;
}
/* This function is equivalent to is_preview_enabled */
int usbcam_preview_enabled(struct camera_device * device)
{
ALOGI("%s: E", __func__);
camera_hardware_t *camHal;
if(device && device->priv){
camHal = (camera_hardware_t *)device->priv;
}else{
ALOGE("%s: Null device or device->priv", __func__);
return -1;
}
Mutex::Autolock autoLock(camHal->lock);
ALOGI("%s: X", __func__);
return camHal->previewEnabledFlag;
}
/* TBD */
int usbcam_store_meta_data_in_buffers(struct camera_device * device, int enable)
{
ALOGI("%s: E", __func__);
int rc = 0;
ALOGI("%s: X", __func__);
return rc;
}
/* TBD */
int usbcam_start_recording(struct camera_device * device)
{
int rc = 0;
ALOGD("%s: E", __func__);
ALOGD("%s: X", __func__);
return rc;
}
/* TBD */
void usbcam_stop_recording(struct camera_device * device)
{
ALOGD("%s: E", __func__);
ALOGD("%s: X", __func__);
}
/* TBD */
int usbcam_recording_enabled(struct camera_device * device)
{
int rc = 0;
ALOGD("%s: E", __func__);
ALOGD("%s: X", __func__);
return rc;
}
/* TBD */
void usbcam_release_recording_frame(struct camera_device * device,
const void *opaque)
{
ALOGV("%s: E", __func__);
ALOGD("%s: X", __func__);
}
/* TBD */
int usbcam_auto_focus(struct camera_device * device)
{
ALOGD("%s: E", __func__);
int rc = 0;
ALOGD("%s: X", __func__);
return rc;
}
/* TBD */
int usbcam_cancel_auto_focus(struct camera_device * device)
{
int rc = 0;
ALOGD("%s: E", __func__);
ALOGD("%s: X", __func__);
return rc;
}
int usbcam_take_picture(struct camera_device * device)
{
ALOGI("%s: E", __func__);
int rc = 0;
camera_hardware_t *camHal;
VALIDATE_DEVICE_HDL(camHal, device, -1);
Mutex::Autolock autoLock(camHal->lock);
/* If take picture is already in progress, nothing t be done */
if(camHal->takePictInProgress){
ALOGI("%s: Take picture already in progress", __func__);
return 0;
}
if(camHal->previewEnabledFlag)
{
rc = stopPreviewInternal(camHal);
if(rc){
ALOGE("%s: stopPreviewInternal returned error", __func__);
}
USB_CAM_CLOSE(camHal);
camHal->prvwStoppedForPicture = 1;
}
/* TBD: Need to handle any dependencies on video recording state */
rc = launchTakePictureThread(camHal);
if(rc)
ALOGE("%s: launchTakePictureThread error", __func__);
#if 0
/* This implementation requests preview thread to take picture */
if(camHal->previewEnabledFlag)
{
camHal->prvwCmdPending++;
camHal->prvwCmd = USB_CAM_PREVIEW_TAKEPIC;
ALOGD("%s: Take picture command set ", __func__);
}else{
ALOGE("%s: Take picture without preview started!", __func__);
rc = -1;
}
#endif
if(!rc)
camHal->takePictInProgress = 1;
ALOGI("%s: X", __func__);
return rc;
}
/* TBD */
int usbcam_cancel_picture(struct camera_device * device)
{
ALOGI("%s: E", __func__);
int rc = 0;
ALOGI("%s: X", __func__);
return rc;
}
int usbcam_set_parameters(struct camera_device * device, const char *params)
{
ALOGI("%s: E", __func__);
int rc = 0;
camera_hardware_t *camHal;
VALIDATE_DEVICE_HDL(camHal, device, -1);
Mutex::Autolock autoLock(camHal->lock);
rc = usbCamSetParameters(camHal, params);
ALOGI("%s: X", __func__);
return rc;
}
char* usbcam_get_parameters(struct camera_device * device)
{
char *parms;
ALOGI("%s: E", __func__);
camera_hardware_t *camHal;
VALIDATE_DEVICE_HDL(camHal, device, NULL);
Mutex::Autolock autoLock(camHal->lock);
parms = usbCamGetParameters(camHal);
ALOGI("%s: X", __func__);
return parms;
}
void usbcam_put_parameters(struct camera_device * device, char *parm)
{
ALOGI("%s: E", __func__);
camera_hardware_t *camHal;
if(device && device->priv){
camHal = (camera_hardware_t *)device->priv;
}else{
ALOGE("%s: Null device or device->priv", __func__);
return;
}
usbCamPutParameters(camHal, parm);
ALOGI("%s: X", __func__);
return;
}
/* TBD */
int usbcam_send_command(struct camera_device * device,
int32_t cmd, int32_t arg1, int32_t arg2)
{
int rc = 0;
ALOGI("%s: E", __func__);
ALOGI("%d", cmd);
ALOGI("%s: X", __func__);
return rc;
}
/* TBD */
void usbcam_release(struct camera_device * device)
{
ALOGI("%s: E", __func__);
#if 0
Mutex::Autolock l(&mLock);
switch(mPreviewState) {
case QCAMERA_HAL_PREVIEW_STOPPED:
break;
case QCAMERA_HAL_PREVIEW_START:
break;
case QCAMERA_HAL_PREVIEW_STARTED:
stopPreviewInternal();
break;
case QCAMERA_HAL_RECORDING_STARTED:
stopRecordingInternal();
stopPreviewInternal();
break;
case QCAMERA_HAL_TAKE_PICTURE:
cancelPictureInternal();
break;
default:
break;
}
mPreviewState = QCAMERA_HAL_PREVIEW_STOPPED;
#endif
ALOGI("%s: X", __func__);
}
/* TBD */
int usbcam_dump(struct camera_device * device, int fd)
{
ALOGI("%s: E", __func__);
int rc = 0;
ALOGI("%s: X", __func__);
return rc;
}
/*****************************************************************************
* Static function definitions below
*****************************************************************************/
/******************************************************************************/
/* No in place conversion supported. Output buffer and input MUST should be */
/* different input buffer for a 4x4 pixel video ***/
/****** YUYVYUYV 00 01 02 03 04 05 06 07 ************/
/****** YUYVYUYV 08 09 10 11 12 13 14 15 ************/
/****** YUYVYUYV 16 17 18 19 20 21 22 23 ************/
/****** YUYVYUYV 24 25 26 27 28 29 30 31 ************/
/******************************************************************************/
/* output generated by this function ******************************************/
/************************** YYYY 00 02 04 06 ************/
/************************** YYYY 08 10 12 14 ************/
/************************** YYYY 16 18 20 22 ************/
/************************** YYYY 24 26 28 30 ************/
/************************** VUVU 03 01 07 05 ************/
/************************** VUVU 19 17 23 21 ************/
/******************************************************************************/
static int convert_YUYV_to_420_NV12(char *in_buf, char *out_buf, int wd, int ht)
{
int rc =0;
int row, col, uv_row;
ALOGD("%s: E", __func__);
/* Arrange Y */
for(row = 0; row < ht; row++)
for(col = 0; col < wd * 2; col += 2)
{
out_buf[row * wd + col / 2] = in_buf[row * wd * 2 + col];
}
/* Arrange UV */
for(row = 0, uv_row = ht; row < ht; row += 2, uv_row++)
for(col = 1; col < wd * 2; col += 4)
{
out_buf[uv_row * wd + col / 2]= in_buf[row * wd * 2 + col + 2];
out_buf[uv_row * wd + col / 2 + 1] = in_buf[row * wd * 2 + col];
}
ALOGD("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: initDisplayBuffers
* Description: This function initializes the preview buffers
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 Success
* -1 Error
* Notes: none
*****************************************************************************/
static int initDisplayBuffers(camera_hardware_t *camHal)
{
preview_stream_ops *mPreviewWindow;
struct ion_fd_data ion_info_fd;
int numMinUndequeuedBufs = 0;
int rc = 0;
int gralloc_usage = 0;
int err;
int color=30;
ALOGD("%s: E", __func__);
#if DISPLAY
if(camHal == NULL) {
ALOGE("%s: camHal = NULL", __func__);
return -1;
}
mPreviewWindow = camHal->window;
if(!mPreviewWindow) {
ALOGE("%s: mPreviewWindow = NULL", __func__);
return -1;
}
/************************************************************************/
/* - get_min_undequeued_buffer_count */
/* - set_buffer_count */
/* - set_buffers_geometry */
/* - set_usage */
/* - dequeue all the display buffers */
/* - cancel buffers: release w/o displaying */
/************************************************************************/
/************************************************************************/
/* - get_min_undequeued_buffer_count */
/************************************************************************/
if(mPreviewWindow->get_min_undequeued_buffer_count) {
rc = mPreviewWindow->get_min_undequeued_buffer_count(
mPreviewWindow, &numMinUndequeuedBufs);
if (0 != rc) {
ALOGE("%s: get_min_undequeued_buffer_count returned error", __func__);
}
else
ALOGD("%s: get_min_undequeued_buffer_count returned: %d ",
__func__, numMinUndequeuedBufs);
}
else
ALOGE("%s: get_min_undequeued_buffer_count is NULL pointer", __func__);
/************************************************************************/
/* - set_buffer_count */
/************************************************************************/
if(mPreviewWindow->set_buffer_count) {
camHal->previewMem.buffer_count = numMinUndequeuedBufs
+ PRVW_DISP_BUF_CNT;
rc = mPreviewWindow->set_buffer_count(
mPreviewWindow,
camHal->previewMem.buffer_count);
if (rc != 0) {
ALOGE("%s: set_buffer_count returned error", __func__);
}else
ALOGD("%s: set_buffer_count returned success", __func__);
}else
ALOGE("%s: set_buffer_count is NULL pointer", __func__);
/************************************************************************/
/* - set_buffers_geometry */
/************************************************************************/
if(mPreviewWindow->set_buffers_geometry) {
rc = mPreviewWindow->set_buffers_geometry(mPreviewWindow,
camHal->dispWidth,
camHal->dispHeight,
camHal->dispFormat);
if (rc != 0) {
ALOGE("%s: set_buffers_geometry returned error. %s (%d)",
__func__, strerror(-rc), -rc);
}else
ALOGD("%s: set_buffers_geometry returned success", __func__);
}else
ALOGE("%s: set_buffers_geometry is NULL pointer", __func__);
/************************************************************************/
/* - set_usage */
/************************************************************************/
gralloc_usage = CAMERA_GRALLOC_HEAP_ID | CAMERA_GRALLOC_FALLBACK_HEAP_ID |
GRALLOC_USAGE_PRIVATE_UNCACHED;
if(mPreviewWindow->set_usage) {
rc = mPreviewWindow->set_usage(mPreviewWindow, gralloc_usage);
if (rc != 0) {
ALOGE("%s: set_usage returned error", __func__);
}else
ALOGD("%s: set_usage returned success", __func__);
}
else
ALOGE("%s: set_usage is NULL pointer", __func__);
/************************************************************************/
/* - dequeue all the display buffers */
/************************************************************************/
for (int cnt = 0; cnt < camHal->previewMem.buffer_count; cnt++) {
int stride;
err = mPreviewWindow->dequeue_buffer(
mPreviewWindow,
&camHal->previewMem.buffer_handle[cnt],
&camHal->previewMem.stride[cnt]);
if(!err) {
ALOGD("%s: dequeue buf: %p\n",
__func__, camHal->previewMem.buffer_handle[cnt]);
if(mPreviewWindow->lock_buffer) {
err = mPreviewWindow->lock_buffer(
mPreviewWindow,
camHal->previewMem.buffer_handle[cnt]);
ALOGD("%s: mPreviewWindow->lock_buffer success",
__func__);
}
// lock the buffer using genlock
ALOGD("%s: camera call genlock_lock, hdl=%p",
__func__, (*camHal->previewMem.buffer_handle[cnt]));
if (GENLOCK_NO_ERROR !=
genlock_lock_buffer(
(native_handle_t *) (*camHal->previewMem.buffer_handle[cnt]),
GENLOCK_WRITE_LOCK, GENLOCK_MAX_TIMEOUT))
{
ALOGE("%s: genlock_lock_buffer(WRITE) failed",
__func__);
camHal->previewMem.local_flag[cnt] = BUFFER_UNLOCKED;
}else {
ALOGD("%s: genlock_lock_buffer hdl =%p",
__func__, *camHal->previewMem.buffer_handle[cnt]);
camHal->previewMem.local_flag[cnt] = BUFFER_LOCKED;
}
/* Store this buffer details in the context */
camHal->previewMem.private_buffer_handle[cnt] =
(struct private_handle_t *) (*camHal->previewMem.buffer_handle[cnt]);
ALOGD("%s: idx = %d, fd = %d, size = %d, offset = %d", __func__,
cnt, camHal->previewMem.private_buffer_handle[cnt]->fd,
camHal->previewMem.private_buffer_handle[cnt]->size,
camHal->previewMem.private_buffer_handle[cnt]->offset);
camHal->previewMem.camera_memory[cnt] =
camHal->get_memory(
camHal->previewMem.private_buffer_handle[cnt]->fd,
camHal->previewMem.private_buffer_handle[cnt]->size,
1, camHal->cb_ctxt);
ALOGD("%s: data = %p, size = %d, handle = %p", __func__,
camHal->previewMem.camera_memory[cnt]->data,
camHal->previewMem.camera_memory[cnt]->size,
camHal->previewMem.camera_memory[cnt]->handle);
#ifdef USE_ION
/* In case of ION usage, open ION fd */
camHal->previewMem.mem_info[cnt].main_ion_fd =
open("/dev/ion", O_RDONLY);
if (camHal->previewMem.mem_info[cnt].main_ion_fd < 0) {
ALOGE("%s: failed: could not open ion device\n", __func__);
}else{
memset(&ion_info_fd, 0, sizeof(ion_info_fd));
ion_info_fd.fd =
camHal->previewMem.private_buffer_handle[cnt]->fd;
if (ioctl(camHal->previewMem.mem_info[cnt].main_ion_fd,
ION_IOC_IMPORT, &ion_info_fd) < 0) {
ALOGE("ION import failed\n");
}
}
camHal->previewMem.mem_info[cnt].fd =
camHal->previewMem.private_buffer_handle[cnt]->fd;
camHal->previewMem.mem_info[cnt].size =
camHal->previewMem.private_buffer_handle[cnt]->size;
camHal->previewMem.mem_info[cnt].handle = ion_info_fd.handle;
#endif
}
else
ALOGE("%s: dequeue buf %d failed \n", __func__, cnt);
}
/************************************************************************/
/* - cancel buffers: queue w/o displaying */
/************************************************************************/
for (int cnt = 0; cnt < camHal->previewMem.buffer_count; cnt++) {
if (GENLOCK_FAILURE == genlock_unlock_buffer(
(native_handle_t *)(*(camHal->previewMem.buffer_handle[cnt])))){
ALOGE("%s: genlock_unlock_buffer failed: hdl =%p", __func__,
(*(camHal->previewMem.buffer_handle[cnt])) );
} else {
camHal->previewMem.local_flag[cnt] = BUFFER_UNLOCKED;
ALOGD("%s: genlock_unlock_buffer success: hdl = %p",
__func__, (*(camHal->previewMem.buffer_handle[cnt])));
}
err = mPreviewWindow->cancel_buffer(mPreviewWindow,
(buffer_handle_t *)camHal->previewMem.buffer_handle[cnt]);
if(!err) {
ALOGD("%s: cancel_buffer successful: %p\n",
__func__, camHal->previewMem.buffer_handle[cnt]);
}else
ALOGE("%s: cancel_buffer failed: %p\n", __func__,
camHal->previewMem.buffer_handle[cnt]);
}
#else
rc = 0;
#endif /* #if DISPLAY */
ALOGD("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: deInitDisplayBuffers
* Description: This function de-initializes all the display buffers allocated
* in initDisplayBuffers
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 Success
* -1 Error
* Notes: none
*****************************************************************************/
static int deInitDisplayBuffers(camera_hardware_t *camHal)
{
int rc = 0;
preview_stream_ops *previewWindow;
ALOGD("%s: E", __func__);
if(!camHal || !camHal->window) {
ALOGE("%s: camHal = NULL or window = NULL ", __func__);
return -1;
}
previewWindow = camHal->window;
/************************************************************************/
/* - Release all buffers that were acquired using get_memory */
/* - If using ION memory, free ION related resources */
/* - genUnlock if buffer is genLocked */
/* - Cancel buffers: queue w/o displaying */
/************************************************************************/
#if DISPLAY
for (int cnt = 0; cnt < camHal->previewMem.buffer_count; cnt++) {
/* Release all buffers that were acquired using get_memory */
camHal->previewMem.camera_memory[cnt]->release(
camHal->previewMem.camera_memory[cnt]);
#ifdef USE_ION
/* If using ION memory, free ION related resources */
struct ion_handle_data ion_handle;
memset(&ion_handle, 0, sizeof(ion_handle));
ion_handle.handle = camHal->previewMem.mem_info[cnt].handle;
if (ioctl(camHal->previewMem.mem_info[cnt].main_ion_fd,
ION_IOC_FREE, &ion_handle) < 0) {
ALOGE("%s: ion free failed\n", __func__);
}
close(camHal->previewMem.mem_info[cnt].main_ion_fd);
#endif
/* genUnlock if buffer is genLocked */
if(camHal->previewMem.local_flag[cnt] == BUFFER_LOCKED){
if (GENLOCK_FAILURE == genlock_unlock_buffer(
(native_handle_t *)(*(camHal->previewMem.buffer_handle[cnt])))){
ALOGE("%s: genlock_unlock_buffer failed: hdl =%p", __func__,
(*(camHal->previewMem.buffer_handle[cnt])) );
} else {
camHal->previewMem.local_flag[cnt] = BUFFER_UNLOCKED;
ALOGD("%s: genlock_unlock_buffer success: hdl = %p",
__func__, (*(camHal->previewMem.buffer_handle[cnt])));
}
}
/* cancel buffers: enqueue w/o displaying */
rc = previewWindow->cancel_buffer(previewWindow,
(buffer_handle_t *)camHal->previewMem.buffer_handle[cnt]);
if(!rc) {
ALOGD("%s: cancel_buffer successful: %p\n",
__func__, camHal->previewMem.buffer_handle[cnt]);
}else
ALOGE("%s: cancel_buffer failed: %p\n", __func__,
camHal->previewMem.buffer_handle[cnt]);
}
#endif /* #if DISPLAY */
memset(&camHal->previewMem, 0, sizeof(camHal->previewMem));
ALOGD("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: getPreviewCaptureFmt
* Description: This function implements the logic to decide appropriate
* capture format from the USB camera
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* Capture format. Default (V4L2_PIX_FMT_MJPEG)
*
* Notes: none
*****************************************************************************/
static int getPreviewCaptureFmt(camera_hardware_t *camHal)
{
int i = 0, mjpegSupported = 0, h264Supported = 0;
struct v4l2_fmtdesc fmtdesc;
memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc));
/************************************************************************/
/* - Query the camera for all supported formats */
/* - Based on the resolution, pick an apporpriate format */
/************************************************************************/
/************************************************************************/
/* - Query the camera for all supported formats */
/************************************************************************/
for(i = 0; ; i++) {
fmtdesc.index = i;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctlLoop(camHal->fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
if (EINVAL == errno) {
ALOGI("%s: Queried all formats till index %d\n", __func__, i);
break;
} else {
ALOGE("%s: VIDIOC_ENUM_FMT failed", __func__);
}
}
if(V4L2_PIX_FMT_MJPEG == fmtdesc.pixelformat){
mjpegSupported = 1;
ALOGI("%s: V4L2_PIX_FMT_MJPEG is supported", __func__ );
}
if(V4L2_PIX_FMT_H264 == fmtdesc.pixelformat){
h264Supported = 1;
ALOGI("%s: V4L2_PIX_FMT_H264 is supported", __func__ );
}
}
/************************************************************************/
/* - Based on the resolution, pick an apporpriate format */
/************************************************************************/
//V4L2_PIX_FMT_MJPEG; V4L2_PIX_FMT_YUYV; V4L2_PIX_FMT_H264 = 0x34363248;
camHal->captureFormat = V4L2_PIX_FMT_YUYV;
if(camHal->prevWidth > 640){
if(1 == mjpegSupported)
camHal->captureFormat = V4L2_PIX_FMT_MJPEG;
else if(1 == h264Supported)
camHal->captureFormat = V4L2_PIX_FMT_H264;
}
ALOGI("%s: Capture format chosen: 0x%x. 0x%x:YUYV. 0x%x:MJPEG. 0x%x: H264",
__func__, camHal->captureFormat, V4L2_PIX_FMT_YUYV,
V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_H264);
return camHal->captureFormat;
}
/******************************************************************************
* Function: getMjpegdOutputFormat
* Description: This function maps display pixel format enum to JPEG output
* format enum
*
* Input parameters:
* dispFormat - Display pixel format
*
* Return values:
* (int)mjpegOutputFormat
*
* Notes: none
*****************************************************************************/
static int getMjpegdOutputFormat(int dispFormat)
{
int mjpegOutputFormat = YCRCBLP_H2V2;
if(HAL_PIXEL_FORMAT_YCrCb_420_SP == dispFormat)
mjpegOutputFormat = YCRCBLP_H2V2;
return mjpegOutputFormat;
}
/******************************************************************************
* Function: ioctlLoop
* Description: This function is a blocking call around ioctl
*
* Input parameters:
* fd - IOCTL fd
* ioctlCmd - IOCTL command
* args - IOCTL arguments
*
* Return values:
* (int)mjpegOutputFormat
*
* Notes: none
*****************************************************************************/
static int ioctlLoop(int fd, int ioctlCmd, void *args)
{
int rc = -1;
while(1)
{
rc = ioctl(fd, ioctlCmd, args);
if(!((-1 == rc) && (EINTR == errno)))
break;
}
return rc;
}
/******************************************************************************
* Function: initV4L2mmap
* Description: This function requests for V4L2 driver allocated buffers
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int initV4L2mmap(camera_hardware_t *camHal)
{
int rc = -1;
struct v4l2_requestbuffers reqBufs;
struct v4l2_buffer tempBuf;
ALOGD("%s: E", __func__);
memset(&reqBufs, 0, sizeof(v4l2_requestbuffers));
reqBufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqBufs.memory = V4L2_MEMORY_MMAP;
reqBufs.count = PRVW_CAP_BUF_CNT;
if (-1 == ioctlLoop(camHal->fd, VIDIOC_REQBUFS, &reqBufs)) {
if (EINVAL == errno) {
ALOGE("%s: does not support memory mapping\n", __func__);
} else {
ALOGE("%s: VIDIOC_REQBUFS failed", __func__);
}
}
ALOGD("%s: VIDIOC_REQBUFS success", __func__);
if (reqBufs.count < PRVW_CAP_BUF_CNT) {
ALOGE("%s: Insufficient buffer memory on\n", __func__);
}
camHal->buffers =
( bufObj* ) calloc(reqBufs.count, sizeof(bufObj));
if (!camHal->buffers) {
ALOGE("%s: Out of memory\n", __func__);
}
/* Store the indexes in the context. Useful during releasing */
for (camHal->n_buffers = 0;
camHal->n_buffers < reqBufs.count;
camHal->n_buffers++) {
memset(&tempBuf, 0, sizeof(tempBuf));
tempBuf.index = camHal->n_buffers;
tempBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
tempBuf.memory = V4L2_MEMORY_MMAP;
if (-1 == ioctlLoop(camHal->fd, VIDIOC_QUERYBUF, &tempBuf))
ALOGE("%s: VIDIOC_QUERYBUF failed", __func__);
ALOGD("%s: VIDIOC_QUERYBUF success", __func__);
camHal->buffers[camHal->n_buffers].len = tempBuf.length;
camHal->buffers[camHal->n_buffers].data =
mmap(NULL /* start anywhere */,
tempBuf.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
camHal->fd, tempBuf.m.offset);
if (MAP_FAILED == camHal->buffers[camHal->n_buffers].data)
ALOGE("%s: mmap failed", __func__);
}
ALOGD("%s: X", __func__);
return 0;
}
/******************************************************************************
* Function: unInitV4L2mmap
* Description: This function unmaps the V4L2 driver buffers
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int unInitV4L2mmap(camera_hardware_t *camHal)
{
int i, rc = 0;
ALOGD("%s: E", __func__);
for (i = 0; i < camHal->n_buffers; i++)
if (-1 == munmap(camHal->buffers[i].data, camHal->buffers[i].len)){
ALOGE("%s: munmap failed for buffer: %d", __func__, i);
rc = -1;
}
ALOGD("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: initUsbCamera
* Description: This function sets the resolution and pixel format of the
* USB camera
*
* Input parameters:
* camHal - camera HAL handle
* width - picture width in pixels
* height - picture height in pixels
* pixelFormat - capture format for the camera
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int initUsbCamera(camera_hardware_t *camHal, int width, int height,
int pixelFormat)
{
int rc = -1;
struct v4l2_capability cap;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format v4l2format;
unsigned int min;
ALOGI("%s: E", __func__);
if (-1 == ioctlLoop(camHal->fd, VIDIOC_QUERYCAP, &cap)) {
if (EINVAL == errno) {
ALOGE( "%s: This is not V4L2 device\n", __func__);
return -1;
} else {
ALOGE("%s: VIDIOC_QUERYCAP errno: %d", __func__, errno);
}
}
ALOGD("%s: VIDIOC_QUERYCAP success", __func__);
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
ALOGE("%s: This is not video capture device\n", __func__);
return -1;
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
ALOGE("%s: This does not support streaming i/o\n", __func__);
return -1;
}
/* Select video input, video standard and tune here. */
memset(&cropcap, 0, sizeof(cropcap));
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (0 == ioctlLoop(camHal->fd, VIDIOC_CROPCAP, &cropcap)) {
/* reset to default */
crop.c = cropcap.defrect;
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ALOGD("%s: VIDIOC_CROPCAP success", __func__);
if (-1 == ioctlLoop(camHal->fd, VIDIOC_S_CROP, &crop)) {
switch (errno) {
case EINVAL:
/* Cropping not supported. */
break;
default:
/* Errors ignored. */
break;
}
}
ALOGD("%s: VIDIOC_S_CROP success", __func__);
} else {
/* Errors ignored. */
ALOGE("%s: VIDIOC_S_CROP failed", __func__);
}
memset(&v4l2format, 0, sizeof(v4l2format));
v4l2format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
{
v4l2format.fmt.pix.field = V4L2_FIELD_NONE;
v4l2format.fmt.pix.pixelformat = pixelFormat;
v4l2format.fmt.pix.width = width;
v4l2format.fmt.pix.height = height;
if (-1 == ioctlLoop(camHal->fd, VIDIOC_S_FMT, &v4l2format))
{
ALOGE("%s: VIDIOC_S_FMT failed", __func__);
return -1;
}
ALOGD("%s: VIDIOC_S_FMT success", __func__);
/* Note VIDIOC_S_FMT may change width and height. */
}
/* TBR: In case of user pointer buffers, v4l2format.fmt.pix.sizeimage */
/* might have to be calculated as per V4L2 sample application due to */
/* open source driver bug */
rc = initV4L2mmap(camHal);
ALOGI("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: startUsbCamCapture
* Description: This function queues buffer objects to the driver and sends
* STREAM ON command to the USB camera driver
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int startUsbCamCapture(camera_hardware_t *camHal)
{
int rc = -1;
unsigned int i;
enum v4l2_buf_type v4l2BufType;
ALOGD("%s: E", __func__);
for (i = 0; i < camHal->n_buffers; ++i) {
struct v4l2_buffer tempBuf;
memset(&tempBuf, 0, sizeof(tempBuf));
tempBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
tempBuf.memory = V4L2_MEMORY_MMAP;
tempBuf.index = i;
if (-1 == ioctlLoop(camHal->fd, VIDIOC_QBUF, &tempBuf))
ALOGE("%s: VIDIOC_QBUF for %d buffer failed", __func__, i);
else
ALOGD("%s: VIDIOC_QBUF for %d buffer success", __func__, i);
}
v4l2BufType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctlLoop(camHal->fd, VIDIOC_STREAMON, &v4l2BufType))
ALOGE("%s: VIDIOC_STREAMON failed", __func__);
else
{
ALOGD("%s: VIDIOC_STREAMON success", __func__);
rc = 0;
}
ALOGD("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: stopUsbCamCapture
* Description: This function sends STREAM OFF command to the USB camera driver
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int stopUsbCamCapture(camera_hardware_t *camHal)
{
int rc = -1;
unsigned int i;
enum v4l2_buf_type v4l2BufType;
ALOGD("%s: E", __func__);
if(!camHal->fd){
ALOGE("%s: camHal->fd = NULL ", __func__);
return -1;
}
v4l2BufType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctlLoop(camHal->fd, VIDIOC_STREAMOFF, &v4l2BufType)){
ALOGE("%s: VIDIOC_STREAMOFF failed", __func__);
rc = -1;
}else{
ALOGD("%s: VIDIOC_STREAMOFF success", __func__);
rc = 0;
}
ALOGD("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: stopPreviewInternal
* Description: This function sends EXIT command to prview loop thread,
* stops usb camera capture and uninitializes MMAP. This function
* assumes that calling function has locked camHal->lock
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int stopPreviewInternal(camera_hardware_t *camHal)
{
int rc = 0;
ALOGD("%s: E", __func__);
if(camHal->previewEnabledFlag)
{
camHal->prvwCmdPending++;
camHal->prvwCmd = USB_CAM_PREVIEW_EXIT;
/* yield lock while waiting for the preview thread to exit */
camHal->lock.unlock();
if(pthread_join(camHal->previewThread, NULL)){
ALOGE("%s: Error in pthread_join preview thread", __func__);
}
camHal->lock.lock();
if(stopUsbCamCapture(camHal)){
ALOGE("%s: Error in stopUsbCamCapture", __func__);
rc = -1;
}
if(unInitV4L2mmap(camHal)){
ALOGE("%s: Error in stopUsbCamCapture", __func__);
rc = -1;
}
camHal->previewEnabledFlag = 0;
}
ALOGD("%s: X, rc: %d", __func__, rc);
return rc;
}
#if 1
/******************************************************************************
* Function: prvwThreadTakePictureInternal
* Description: This function processes one camera frame to get JPEG encoded
* picture.
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int prvwThreadTakePictureInternal(camera_hardware_t *camHal)
{
int rc = 0;
QCameraHalMemInfo_t *mem_info;
ALOGD("%s: E", __func__);
/************************************************************************/
/* - If requested for shutter notfication, callback */
/* - Dequeue capture buffer from USB camera */
/* - Send capture buffer to JPEG encoder for JPEG compression */
/* - If jpeg frames callback is requested, callback with jpeg buffers */
/* - Enqueue capture buffer back to USB camera */
/************************************************************************/
/************************************************************************/
/* - If requested for shutter notfication, callback */
/************************************************************************/
if (camHal->msgEnabledFlag & CAMERA_MSG_SHUTTER){
camHal->lock.unlock();
camHal->notify_cb(CAMERA_MSG_SHUTTER, 0, 0, camHal->cb_ctxt);
camHal->lock.lock();
}
#if CAPTURE
/************************************************************************/
/* - Dequeue capture buffer from USB camera */
/************************************************************************/
if (0 == get_buf_from_cam(camHal))
ALOGD("%s: get_buf_from_cam success", __func__);
else
ALOGE("%s: get_buf_from_cam error", __func__);
#endif
/************************************************************************/
/* - Send capture buffer to JPEG encoder for JPEG compression */
/************************************************************************/
/* Optimization: If camera capture is JPEG format, need not compress! */
/* instead, just data copy from capture buffer to picture buffer */
if(V4L2_PIX_FMT_MJPEG == camHal->captureFormat){
/* allocate heap memory for JPEG output */
mem_info = &camHal->pictMem.mem_info[0];
mem_info->size = camHal->curCaptureBuf.bytesused;
/* TBD: allocate_ion_memory
rc = QCameraHardwareInterface::allocate_ion_memory(mem_info,
((0x1 << CAMERA_ZSL_ION_HEAP_ID) |
(0x1 << CAMERA_ZSL_ION_FALLBACK_HEAP_ID)));
*/
if(rc)
ALOGE("%s: ION memory allocation failed", __func__);
camHal->pictMem.camera_memory[0] = camHal->get_memory(
mem_info->fd, mem_info->size, 1, camHal->cb_ctxt);
if(!camHal->pictMem.camera_memory[0])
ALOGE("%s: get_mem failed", __func__);
memcpy( camHal->pictMem.camera_memory[0]->data,
(char *)camHal->buffers[camHal->curCaptureBuf.index].data,
camHal->curCaptureBuf.bytesused);
}
/************************************************************************/
/* - If jpeg frames callback is requested, callback with jpeg buffers */
/************************************************************************/
if ((camHal->msgEnabledFlag & CAMERA_MSG_COMPRESSED_IMAGE) &&
(camHal->data_cb)){
camHal->lock.unlock();
camHal->data_cb(CAMERA_MSG_COMPRESSED_IMAGE,
camHal->pictMem.camera_memory[0],
0, NULL, camHal->cb_ctxt);
camHal->lock.lock();
}
/* release heap memory after the call back */
if(camHal->pictMem.camera_memory[0])
camHal->pictMem.camera_memory[0]->release(
camHal->pictMem.camera_memory[0]);
/* TBD: deallocate_ion_memory */
//rc = QCameraHardwareInterface::deallocate_ion_memory(mem_info);
if(rc)
ALOGE("%s: ION memory de-allocation failed", __func__);
#if CAPTURE
/************************************************************************/
/* - Enqueue capture buffer back to USB camera */
/************************************************************************/
if(0 == put_buf_to_cam(camHal)) {
ALOGD("%s: put_buf_to_cam success", __func__);
}
else
ALOGE("%s: put_buf_to_cam error", __func__);
#endif
ALOGD("%s: X, rc: %d", __func__, rc);
return rc;
}
#endif //#if 0
/******************************************************************************
* Function: cache_ops
* Description: This function calls ION ioctl for cache related operations
*
* Input parameters:
* mem_info - QCameraHalMemInfo_t structure with ION info
* buf_ptr - Buffer pointer that needs to be cache operated
* cmd - Cache command - clean/invalidate
*
* Return values:
* MM_CAMERA_OK No error
* -1 Error
*
* Notes: none
*****************************************************************************/
int cache_ops(QCameraHalMemInfo_t *mem_info,
void *buf_ptr,
unsigned int cmd)
{
struct ion_flush_data cache_inv_data;
struct ion_custom_data custom_data;
int ret = MM_CAMERA_OK;
#ifdef USE_ION
if (NULL == mem_info) {
ALOGE("%s: mem_info is NULL, return here", __func__);
return -1;
}
memset(&cache_inv_data, 0, sizeof(cache_inv_data));
memset(&custom_data, 0, sizeof(custom_data));
cache_inv_data.vaddr = buf_ptr;
cache_inv_data.fd = mem_info->fd;
cache_inv_data.handle = mem_info->handle;
cache_inv_data.length = mem_info->size;
custom_data.cmd = cmd;
custom_data.arg = (unsigned long)&cache_inv_data;
ALOGD("%s: addr = %p, fd = %d, handle = %p length = %d, ION Fd = %d",
__func__, cache_inv_data.vaddr, cache_inv_data.fd,
cache_inv_data.handle, cache_inv_data.length,
mem_info->main_ion_fd);
if(mem_info->main_ion_fd > 0) {
if(ioctl(mem_info->main_ion_fd, ION_IOC_CUSTOM, &custom_data) < 0) {
ALOGE("%s: Cache Invalidate failed\n", __func__);
ret = -1;
}
}
#endif
return ret;
}
/******************************************************************************
* Function: get_buf_from_cam
* Description: This funtions gets/acquires 1 capture buffer from the camera
* driver. The fetched buffer is stored in curCaptureBuf
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int get_buf_from_cam(camera_hardware_t *camHal)
{
int rc = -1;
ALOGD("%s: E", __func__);
{
memset(&camHal->curCaptureBuf, 0, sizeof(camHal->curCaptureBuf));
camHal->curCaptureBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
camHal->curCaptureBuf.memory = V4L2_MEMORY_MMAP;
if (-1 == ioctlLoop(camHal->fd, VIDIOC_DQBUF, &camHal->curCaptureBuf)){
switch (errno) {
case EAGAIN:
ALOGE("%s: EAGAIN error", __func__);
return 1;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
ALOGE("%s: VIDIOC_DQBUF error", __func__);
}
}
else
{
rc = 0;
ALOGD("%s: VIDIOC_DQBUF: %d successful, %d bytes",
__func__, camHal->curCaptureBuf.index,
camHal->curCaptureBuf.bytesused);
}
}
ALOGD("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: put_buf_to_cam
* Description: This funtion puts/releases 1 capture buffer back to the camera
* driver
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int put_buf_to_cam(camera_hardware_t *camHal)
{
ALOGD("%s: E", __func__);
camHal->curCaptureBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
camHal->curCaptureBuf.memory = V4L2_MEMORY_MMAP;
if (-1 == ioctlLoop(camHal->fd, VIDIOC_QBUF, &camHal->curCaptureBuf))
{
ALOGE("%s: VIDIOC_QBUF failed ", __func__);
return 1;
}
ALOGD("%s: X", __func__);
return 0;
}
/******************************************************************************
* Function: put_buf_to_cam
* Description: This funtion gets/acquires 1 display buffer from the display
* window
*
* Input parameters:
* camHal - camera HAL handle
* buffer_id - Buffer id pointer. The id of buffer obtained
* by this function is returned in this arg
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int get_buf_from_display(camera_hardware_t *camHal, int *buffer_id)
{
int err = 0;
preview_stream_ops *mPreviewWindow = NULL;
int stride = 0, cnt = 0;
buffer_handle_t *buffer_handle = NULL;
struct private_handle_t *private_buffer_handle = NULL;
ALOGD("%s: E", __func__);
if (camHal == NULL) {
ALOGE("%s: camHal = NULL", __func__);
return -1;
}
mPreviewWindow = camHal->window;
if( mPreviewWindow == NULL) {
ALOGE("%s: mPreviewWindow = NULL", __func__);
return -1;
}
err = mPreviewWindow->dequeue_buffer(mPreviewWindow,
&buffer_handle,
&stride);
if(!err) {
ALOGD("%s: dequeue buf buffer_handle: %p\n", __func__, buffer_handle);
ALOGD("%s: mPreviewWindow->lock_buffer: %p",
__func__, mPreviewWindow->lock_buffer);
if(mPreviewWindow->lock_buffer) {
err = mPreviewWindow->lock_buffer(mPreviewWindow, buffer_handle);
ALOGD("%s: mPreviewWindow->lock_buffer success", __func__);
}
ALOGD("%s: camera call genlock_lock, hdl=%p",
__func__, (*buffer_handle));
if (GENLOCK_NO_ERROR !=
genlock_lock_buffer((native_handle_t *)(*buffer_handle),
GENLOCK_WRITE_LOCK, GENLOCK_MAX_TIMEOUT)) {
ALOGE("%s: genlock_lock_buffer(WRITE) failed", __func__);
} else {
ALOGD("%s: genlock_lock_buffer hdl =%p", __func__, *buffer_handle);
}
private_buffer_handle = (struct private_handle_t *)(*buffer_handle);
ALOGD("%s: fd = %d, size = %d, offset = %d, stride = %d",
__func__, private_buffer_handle->fd,
private_buffer_handle->size, private_buffer_handle->offset, stride);
for(cnt = 0; cnt < camHal->previewMem.buffer_count + 2; cnt++) {
if(private_buffer_handle->fd ==
camHal->previewMem.private_buffer_handle[cnt]->fd) {
*buffer_id = cnt;
ALOGD("%s: deQueued fd = %d, index: %d",
__func__, private_buffer_handle->fd, cnt);
break;
}
}
}
else
ALOGE("%s: dequeue buf failed \n", __func__);
ALOGD("%s: X", __func__);
return err;
}
/******************************************************************************
* Function: put_buf_to_display
* Description: This funtion puts/enqueues 1 buffer back to the display window
*
* Input parameters:
* camHal - camera HAL handle
* buffer_id - id of the buffer that needs to be enqueued
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int put_buf_to_display(camera_hardware_t *camHal, int buffer_id)
{
int err = 0;
preview_stream_ops *mPreviewWindow;
ALOGD("%s: E", __func__);
if (camHal == NULL) {
ALOGE("%s: camHal = NULL", __func__);
return -1;
}
mPreviewWindow = camHal->window;
if( mPreviewWindow == NULL) {
ALOGE("%s: mPreviewWindow = NULL", __func__);
return -1;
}
if (GENLOCK_FAILURE ==
genlock_unlock_buffer(
(native_handle_t *)
(*(camHal->previewMem.buffer_handle[buffer_id])))) {
ALOGE("%s: genlock_unlock_buffer failed: hdl =%p",
__func__, (*(camHal->previewMem.buffer_handle[buffer_id])) );
} else {
ALOGD("%s: genlock_unlock_buffer success: hdl =%p",
__func__, (*(camHal->previewMem.buffer_handle[buffer_id])) );
}
/* Cache clean the output buffer so that cache is written back */
cache_ops(&camHal->previewMem.mem_info[buffer_id],
(void *)camHal->previewMem.camera_memory[buffer_id]->data,
ION_IOC_CLEAN_CACHES);
/*
cache_ops(&camHal->previewMem.mem_info[buffer_id],
(void *)camHal->previewMem.camera_memory[buffer_id]->data,
ION_IOC_CLEAN_INV_CACHES);
*/
err = mPreviewWindow->enqueue_buffer(mPreviewWindow,
(buffer_handle_t *)camHal->previewMem.buffer_handle[buffer_id]);
if(!err) {
ALOGD("%s: enqueue buf successful: %p\n",
__func__, camHal->previewMem.buffer_handle[buffer_id]);
}else
ALOGE("%s: enqueue buf failed: %p\n",
__func__, camHal->previewMem.buffer_handle[buffer_id]);
ALOGD("%s: X", __func__);
return err;
}
/******************************************************************************
* Function: put_buf_to_display
* Description: This funtion transfers the content from capture buffer to
* preiew display buffer after appropriate conversion
*
* Input parameters:
* camHal - camera HAL handle
* buffer_id - id of the buffer that needs to be enqueued
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int convert_data_frm_cam_to_disp(camera_hardware_t *camHal, int buffer_id)
{
int rc = -1;
if(!camHal) {
ALOGE("%s: camHal is NULL", __func__);
return -1;
}
/* If input and output are raw formats, but different color format, */
/* call color conversion routine */
if( (V4L2_PIX_FMT_YUYV == camHal->captureFormat) &&
(HAL_PIXEL_FORMAT_YCrCb_420_SP == camHal->dispFormat))
{
convert_YUYV_to_420_NV12(
(char *)camHal->buffers[camHal->curCaptureBuf.index].data,
(char *)camHal->previewMem.camera_memory[buffer_id]->data,
camHal->prevWidth,
camHal->prevHeight);
ALOGD("%s: Copied %d bytes from camera buffer %d to display buffer: %d",
__func__, camHal->curCaptureBuf.bytesused,
camHal->curCaptureBuf.index, buffer_id);
rc = 0;
}
/* If camera buffer is MJPEG encoded, call mjpeg decode call */
if(V4L2_PIX_FMT_MJPEG == camHal->captureFormat)
{
if(NULL == camHal->mjpegd)
{
rc = mjpegDecoderInit(&camHal->mjpegd);
if(rc < 0)
ALOGE("%s: mjpegDecoderInit Error: %d", __func__, rc);
}
if(camHal->mjpegd)
{
rc = mjpegDecode(
(void*)camHal->mjpegd,
(char *)camHal->buffers[camHal->curCaptureBuf.index].data,
camHal->curCaptureBuf.bytesused,
(char *)camHal->previewMem.camera_memory[buffer_id]->data,
(char *)camHal->previewMem.camera_memory[buffer_id]->data +
camHal->prevWidth * camHal->prevHeight,
getMjpegdOutputFormat(camHal->dispFormat));
if(rc < 0)
ALOGE("%s: mjpegDecode Error: %d", __func__, rc);
}
}
return rc;
}
/******************************************************************************
* Function: launch_preview_thread
* Description: This is a wrapper function to start preview thread
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int launch_preview_thread(camera_hardware_t *camHal)
{
ALOGD("%s: E", __func__);
int rc = 0;
if(!camHal) {
ALOGE("%s: camHal is NULL", __func__);
return -1;
}
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&camHal->previewThread, &attr, previewloop, camHal);
ALOGD("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: launch_preview_thread
* Description: This is thread funtion for preivew loop
*
* Input parameters:
* hcamHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static void * previewloop(void *hcamHal)
{
int rc;
int buffer_id = 0;
pid_t tid = 0;
camera_hardware_t *camHal = NULL;
int msgType = 0;
camera_memory_t *data = NULL;
camera_frame_metadata_t *metadata= NULL;
camera_memory_t *previewMem = NULL;
camHal = (camera_hardware_t *)hcamHal;
ALOGD("%s: E", __func__);
if(!camHal) {
ALOGE("%s: camHal is NULL", __func__);
return NULL ;
}
tid = gettid();
/* TBR: Set appropriate thread priority */
androidSetThreadPriority(tid, ANDROID_PRIORITY_NORMAL);
prctl(PR_SET_NAME, (unsigned long)"Camera HAL preview thread", 0, 0, 0);
/************************************************************************/
/* - Time wait (select) on camera fd for input read buffer */
/* - Check if any preview thread commands are set. If set, process */
/* - Dequeue display buffer from surface */
/* - Dequeue capture buffer from USB camera */
/* - Convert capture format to display format */
/* - If preview frames callback is requested, callback with prvw buffers*/
/* - Enqueue display buffer back to surface */
/* - Enqueue capture buffer back to USB camera */
/************************************************************************/
while(1) {
fd_set fds;
struct timeval tv;
int r = 0;
FD_ZERO(&fds);
#if CAPTURE
FD_SET(camHal->fd, &fds);
#endif /* CAPTURE */
/************************************************************************/
/* - Time wait (select) on camera fd for input read buffer */
/************************************************************************/
tv.tv_sec = 0;
tv.tv_usec = 500000;
ALOGD("%s: b4 select on camHal->fd + 1,fd: %d", __func__, camHal->fd);
#if CAPTURE
r = select(camHal->fd + 1, &fds, NULL, NULL, &tv);
#else
r = select(1, NULL, NULL, NULL, &tv);
#endif /* CAPTURE */
ALOGD("%s: after select : %d", __func__, camHal->fd);
if (-1 == r) {
if (EINTR == errno)
continue;
ALOGE("%s: FDSelect error: %d", __func__, errno);
}
if (0 == r) {
ALOGD("%s: select timeout\n", __func__);
}
/* Protect the context for one iteration of preview loop */
/* this gets unlocked at the end of the while */
Mutex::Autolock autoLock(camHal->lock);
/************************************************************************/
/* - Check if any preview thread commands are set. If set, process */
/************************************************************************/
if(camHal->prvwCmdPending)
{
/* command is serviced. Hence command pending = 0 */
camHal->prvwCmdPending--;
//sempost(ack)
if(USB_CAM_PREVIEW_EXIT == camHal->prvwCmd){
/* unlock before exiting the thread */
camHal->lock.unlock();
ALOGI("%s: Exiting coz USB_CAM_PREVIEW_EXIT", __func__);
return (void *)0;
}else if(USB_CAM_PREVIEW_TAKEPIC == camHal->prvwCmd){
rc = prvwThreadTakePictureInternal(camHal);
if(rc)
ALOGE("%s: prvwThreadTakePictureInternal returned error",
__func__);
}
}
/* Null check on preview window. If null, sleep */
if(!camHal->window) {
ALOGD("%s: sleeping coz camHal->window = NULL",__func__);
camHal->lock.unlock();
sleep(2);
continue;
}
#if DISPLAY
/************************************************************************/
/* - Dequeue display buffer from surface */
/************************************************************************/
if(0 == get_buf_from_display(camHal, &buffer_id)) {
ALOGD("%s: get_buf_from_display success: %d",
__func__, buffer_id);
}else{
ALOGE("%s: get_buf_from_display failed. Skipping the loop",
__func__);
continue;
}
#endif
#if CAPTURE
/************************************************************************/
/* - Dequeue capture buffer from USB camera */
/************************************************************************/
if (0 == get_buf_from_cam(camHal))
ALOGD("%s: get_buf_from_cam success", __func__);
else
ALOGE("%s: get_buf_from_cam error", __func__);
#endif
#if FILE_DUMP_CAMERA
/* Debug code to dump frames from camera */
{
static int frame_cnt = 0;
/* currently hardcoded for Bytes-Per-Pixel = 1.5 */
fileDump("/data/USBcam.yuv",
(char*)camHal->buffers[camHal->curCaptureBuf.index].data,
camHal->prevWidth * camHal->prevHeight * 1.5,
&frame_cnt);
}
#endif
#if MEMSET
static int color = 30;
color += 50;
if(color > 200) {
color = 30;
}
ALOGE("%s: Setting to the color: %d\n", __func__, color);
/* currently hardcoded for format of type Bytes-Per-Pixel = 1.5 */
memset(camHal->previewMem.camera_memory[buffer_id]->data,
color, camHal->dispWidth * camHal->dispHeight * 1.5 + 2 * 1024);
#else
convert_data_frm_cam_to_disp(camHal, buffer_id);
ALOGD("%s: Copied data to buffer_id: %d", __func__, buffer_id);
#endif
#if FILE_DUMP_B4_DISP
/* Debug code to dump display buffers */
{
static int frame_cnt = 0;
/* currently hardcoded for Bytes-Per-Pixel = 1.5 */
fileDump("/data/display.yuv",
(char*) camHal->previewMem.camera_memory[buffer_id]->data,
camHal->dispWidth * camHal->dispHeight * 1.5,
&frame_cnt);
ALOGD("%s: Written buf_index: %d ", __func__, buffer_id);
}
#endif
#if DISPLAY
/************************************************************************/
/* - Enqueue display buffer back to surface */
/************************************************************************/
if(0 == put_buf_to_display(camHal, buffer_id)) {
ALOGD("%s: put_buf_to_display success: %d", __func__, buffer_id);
}
else
ALOGE("%s: put_buf_to_display error", __func__);
#endif
#if CAPTURE
/************************************************************************/
/* - Enqueue capture buffer back to USB camera */
/************************************************************************/
if(0 == put_buf_to_cam(camHal)) {
ALOGD("%s: put_buf_to_cam success", __func__);
}
else
ALOGE("%s: put_buf_to_cam error", __func__);
#endif
#if CALL_BACK
/************************************************************************/
/* - If preview frames callback is requested, callback with prvw buffers*/
/************************************************************************/
/* TBD: change the 1.5 hardcoding to Bytes Per Pixel */
int previewBufSize = camHal->prevWidth * camHal->prevHeight * 1.5;
msgType |= CAMERA_MSG_PREVIEW_FRAME;
if(previewBufSize !=
camHal->previewMem.private_buffer_handle[buffer_id]->size) {
previewMem = camHal->get_memory(
camHal->previewMem.private_buffer_handle[buffer_id]->fd,
previewBufSize,
1,
camHal->cb_ctxt);
if (!previewMem || !previewMem->data) {
ALOGE("%s: get_memory failed.\n", __func__);
}
else {
data = previewMem;
ALOGD("%s: GetMemory successful. data = %p",
__func__, data);
ALOGD("%s: previewBufSize = %d, priv_buf_size: %d",
__func__, previewBufSize,
camHal->previewMem.private_buffer_handle[buffer_id]->size);
}
}
else{
data = camHal->previewMem.camera_memory[buffer_id];
ALOGD("%s: No GetMemory, no invalid fmt. data = %p, idx=%d",
__func__, data, buffer_id);
}
/* Unlock and lock around the callback. */
/* Sometimes 'disable_msg' is issued in the callback context, */
/* leading to deadlock */
camHal->lock.unlock();
if((camHal->msgEnabledFlag & CAMERA_MSG_PREVIEW_FRAME) &&
camHal->data_cb){
ALOGD("%s: before data callback", __func__);
camHal->data_cb(msgType, data, 0,metadata, camHal->cb_ctxt);
ALOGD("%s: after data callback: %p", __func__, camHal->data_cb);
}
camHal->lock.lock();
if (previewMem)
previewMem->release(previewMem);
#endif
}//while(1)
ALOGD("%s: X", __func__);
return (void *)0;
}
/******************************************************************************
* Function: get_uvc_device
* Description: This function loops through /dev/video entries and probes with
* UVCIOC query. If the device responds to the query, then it is
* detected as UVC webcam
* Input parameters:
* devname - String pointer. The function return dev entry
* name in this string
* Return values:
* 0 Success
* -1 Error
* Notes: none
*****************************************************************************/
static int get_uvc_device(char *devname)
{
char temp_devname[FILENAME_LENGTH];
FILE *fp = NULL;
int i = 0, ret = 0, fd;
ALOGD("%s: E", __func__);
#if 1
strncpy(devname, "/dev/video1", FILENAME_LENGTH);
/*
struct stat st;
strncpy(dev_name, "/dev/video1", FILENAME_LENGTH);
if (-1 == stat(dev_name, &st)) {
ALOGE("%s: Cannot identify '%s': %d, %s\n",
__func__, dev_name, errno, strerror(errno));
}
if (!S_ISCHR(st.st_mode)) {
ALOGE("%s: %s is no device\n", __func__, dev_name);
rc = -1;
}
*/
#else
*devname = '\0';
/************************************************************************/
/* - List all /dev/video* entries to a file */
/* - Open the video list file and loop through the list */
/* - Send UVC specific control query and check the response */
/* - If device responds to the query as success, device is UVC webcam */
/************************************************************************/
/************************************************************************/
/* - List all /dev/video* entries to a file */
/************************************************************************/
/* Temporarily commented out. This logic doesnt seem to be working */
//system("ls > /data/video_dev_list");
/************************************************************************/
/* - Open the video list file and loop through the list */
/************************************************************************/
/* Temporarily commented out. This logic doesnt seem to be working */
/*
fp = fopen("/data/video_dev_list", "rb");
if(!fp) {
ALOGE("%s: Error in opening /data/video_dev_list ", __func__);
return -1;
}
*/
/* Temporarily commented out. Looping logic changed due to issue in */
/* executing system("ls > /data/video_dev_list") */
//while(EOF != fscanf(fp, "%s", devname)){
while(1){
uvc_xu_control_query xqry;
sprintf(temp_devname, "/dev/video%d", i);
ALOGD("%s: Probing %s \n", __func__, temp_devname);
fd = open(temp_devname, O_RDWR /* required */ | O_NONBLOCK, 0);
if(-1 != fd){
memset(&xqry, 0, sizeof(uvc_xu_control_query));
ret = ioctl(fd, UVCIOC_CTRL_QUERY, &xqry);
ALOGD("%s: UVCIOC ret: %d, errno: %d", __func__, ret, errno);
/****************************************************************/
/* if UVCIOC is executed successfully, ret = 0 */
/* if UVCIOC is executed but Control Unit = 0 does not exist, */
/* ret = -1 and errno = ENOENT */
/* if UVCIOC doesnot execute, ret = -1 and errno = EINVAL */
/****************************************************************/
if((0 == ret) || (ret && (ENOENT == errno))){
ALOGD("%s: Found UVC node: %s\n", __func__, temp_devname);
strncpy(devname, temp_devname, FILENAME_LENGTH);
/* Exit the loop at the first UVC node detection */
break;
}
close(fd);
}
/* Temporarily logic to probe video0 to video10 nodes */
if(i++ > 10)
{
if(fp)
fclose(fp);
break;
}
}
#endif /* #if 0 */
ALOGD("%s: X", __func__);
return 0;
} /* get_uvc_device */
/******************************************************************************
* Function: fileDump
* Description: This is a utility function to dump buffers into a file
*
* Input parameters:
* fn - File name string
* data - pointer to character buffer that needs to be dumped
* length - Length of the buffer to be dumped
* frm_cnt - Pointer to frame count. This count is incremented by this
* function on successful file write
* Return values:
* 0 Success
* -1 Error
* Notes: none
*****************************************************************************/
static int fileDump(const char* fn, char* data, int length, int* frm_cnt)
{
FILE *fp = NULL;
if (0 == *frm_cnt) {
fp = fopen(fn, "wb");
if (NULL == fp) {
ALOGE("%s: Error in opening %s", __func__, fn);
}
fclose(fp);
}
fp = fopen(fn, "ab");
if (NULL == fp) {
ALOGE("%s: Error in opening %s", __func__, fn);
}
fwrite(data, 1, length, fp);
fclose(fp);
(*frm_cnt)++;
ALOGD("%s: Written %d bytes for frame:%d, in %s",
__func__, length, *frm_cnt, fn);
return 0;
}
/******************************************************************************
* Function: launchTakePictureThread
* Description: This is a wrapper function to start take picture thread
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int launchTakePictureThread(camera_hardware_t *camHal)
{
ALOGD("%s: E", __func__);
int rc = 0;
if(!camHal) {
ALOGE("%s: camHal is NULL", __func__);
return -1;
}
pthread_attr_t attr;
pthread_attr_init(&attr);
/* create the thread in detatched state, when the thread exits all */
/* memory resources are freed up */
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&camHal->takePictureThread, &attr, takePictureThread, camHal);
ALOGD("%s: X", __func__);
return rc;
}
/******************************************************************************
* Function: takePictureThread
* Description: This function is associated with take picture thread
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static void * takePictureThread(void *hcamHal)
{
int rc = 0;
int buffer_id = 0;
pid_t tid = 0;
camera_hardware_t *camHal = NULL;
int msgType = 0;
int jpegLength = 0;
QCameraHalMemInfo_t *mem_info = NULL;
camHal = (camera_hardware_t *)hcamHal;
ALOGI("%s: E", __func__);
if(!camHal) {
ALOGE("%s: camHal is NULL", __func__);
return NULL ;
}
tid = gettid();
/* TBR: Set appropriate thread priority */
androidSetThreadPriority(tid, ANDROID_PRIORITY_NORMAL);
prctl(PR_SET_NAME, (unsigned long)"Camera HAL preview thread", 0, 0, 0);
/************************************************************************/
/* - If requested for shutter notfication, notify */
/* - Initialize USB camera with snapshot parameters */
/* - Time wait (select) on camera fd for camera frame availability */
/* - Dequeue capture buffer from USB camera */
/* - Send capture buffer to JPEG encoder for JPEG compression */
/* - If jpeg frames callback is requested, callback with jpeg buffers */
/* - Enqueue capture buffer back to USB camera */
/* - Free USB camera resources and close camera */
/* - If preview was stopped for taking picture, restart the preview */
/************************************************************************/
Mutex::Autolock autoLock(camHal->lock);
/************************************************************************/
/* - If requested for shutter notfication, notify */
/************************************************************************/
#if 0 /* TBD: Temporarily commented out due to an issue. Sometimes it takes */
/* long time to get back the lock once unlocked and notify callback */
if (camHal->msgEnabledFlag & CAMERA_MSG_SHUTTER){
camHal->lock.unlock();
camHal->notify_cb(CAMERA_MSG_SHUTTER, 0, 0, camHal->cb_ctxt);
camHal->lock.lock();
}
#endif
/************************************************************************/
/* - Initialize USB camera with snapshot parameters */
/************************************************************************/
USB_CAM_OPEN(camHal);
#if JPEG_ON_USB_CAMERA
rc = initUsbCamera(camHal, camHal->pictWidth, camHal->pictHeight,
V4L2_PIX_FMT_MJPEG);
#else
rc = initUsbCamera(camHal, camHal->pictWidth, camHal->pictHeight,
V4L2_PIX_FMT_YUYV);
#endif
ERROR_CHECK_EXIT_THREAD(rc, "initUsbCamera");
rc = startUsbCamCapture(camHal);
ERROR_CHECK_EXIT_THREAD(rc, "startUsbCamCapture");
/************************************************************************/
/* - Time wait (select) on camera fd for camera frame availability */
/************************************************************************/
{
fd_set fds;
struct timeval tv;
int r = 0;
FD_ZERO(&fds);
FD_SET(camHal->fd, &fds);
tv.tv_sec = 1;
tv.tv_usec = 0;
do{
ALOGD("%s: b4 select on camHal->fd : %d", __func__, camHal->fd);
r = select(camHal->fd + 1, &fds, NULL, NULL, &tv);
ALOGD("%s: after select", __func__);
}while((0 == r) || ((-1 == r) && (EINTR == errno)));
if ((-1 == r) && (EINTR != errno)){
ALOGE("%s: FDSelect ret = %d error: %d", __func__, r, errno);
return (void *)-1;
}
}
/************************************************************************/
/* - Dequeue capture buffer from USB camera */
/************************************************************************/
if (0 == get_buf_from_cam(camHal))
ALOGD("%s: get_buf_from_cam success", __func__);
else
ALOGE("%s: get_buf_from_cam error", __func__);
/************************************************************************/
/* - Send capture buffer to JPEG encoder for JPEG compression */
/************************************************************************/
mem_info = &camHal->pictMem.mem_info[0];
mem_info->size = MAX_JPEG_BUFFER_SIZE;
rc = allocate_ion_memory(mem_info,
((0x1 << CAMERA_ZSL_ION_HEAP_ID) |
(0x1 << CAMERA_ZSL_ION_FALLBACK_HEAP_ID)));
if(rc)
ALOGE("%s: ION memory allocation failed", __func__);
camHal->pictMem.camera_memory[0] = camHal->get_memory(
mem_info->fd, mem_info->size, 1, camHal->cb_ctxt);
if(!camHal->pictMem.camera_memory[0])
ALOGE("%s: get_mem failed", __func__);
#if FREAD_JPEG_PICTURE
jpegLength = readFromFile("/data/tempVGA.jpeg",
(char*)camHal->pictMem.camera_memory[0]->data,
camHal->pictMem.camera_memory[0]->size);
camHal->pictMem.camera_memory[0]->size = jpegLength;
#elif JPEG_ON_USB_CAMERA
memcpy((char*)camHal->pictMem.camera_memory[0]->data,
(char *)camHal->buffers[camHal->curCaptureBuf.index].data,
camHal->curCaptureBuf.bytesused);
camHal->pictMem.camera_memory[0]->size = camHal->curCaptureBuf.bytesused;
jpegLength = camHal->curCaptureBuf.bytesused;
#else
rc = encodeJpeg(camHal);
ERROR_CHECK_EXIT_THREAD(rc, "jpeg_encode");
#endif
if(jpegLength <= 0)
ALOGI("%s: jpegLength : %d", __func__, jpegLength);
ALOGD("%s: jpegLength : %d", __func__, jpegLength);
/************************************************************************/
/* - If jpeg frames callback is requested, callback with jpeg buffers */
/************************************************************************/
/* TBD: CAMERA_MSG_RAW_IMAGE data call back */
if ((camHal->msgEnabledFlag & CAMERA_MSG_COMPRESSED_IMAGE) &&
(camHal->data_cb)){
/* Unlock temporarily, callback might call HAL api in turn */
camHal->lock.unlock();
camHal->data_cb(CAMERA_MSG_COMPRESSED_IMAGE,
camHal->pictMem.camera_memory[0],
0, NULL, camHal->cb_ctxt);
camHal->lock.lock();
}
/* release heap memory after the call back */
if(camHal->pictMem.camera_memory[0])
camHal->pictMem.camera_memory[0]->release(
camHal->pictMem.camera_memory[0]);
rc = deallocate_ion_memory(mem_info);
if(rc)
ALOGE("%s: ION memory de-allocation failed", __func__);
/************************************************************************/
/* - Enqueue capture buffer back to USB camera */
/************************************************************************/
if(0 == put_buf_to_cam(camHal)) {
ALOGD("%s: put_buf_to_cam success", __func__);
}
else
ALOGE("%s: put_buf_to_cam error", __func__);
/************************************************************************/
/* - Free USB camera resources and close camera */
/************************************************************************/
rc = stopUsbCamCapture(camHal);
ERROR_CHECK_EXIT_THREAD(rc, "stopUsbCamCapture");
rc = unInitV4L2mmap(camHal);
ERROR_CHECK_EXIT_THREAD(rc, "unInitV4L2mmap");
USB_CAM_CLOSE(camHal);
/************************************************************************/
/* - If preview was stopped for taking picture, restart the preview */
/************************************************************************/
if(camHal->prvwStoppedForPicture)
{
struct camera_device device;
device.priv = (void *)camHal;
USB_CAM_OPEN(camHal);
/* Unlock temporarily coz usbcam_start_preview has a lock */
camHal->lock.unlock();
rc = usbcam_start_preview(&device);
if(rc)
ALOGE("%s: start_preview error after take picture", __func__);
camHal->lock.lock();
camHal->prvwStoppedForPicture = 0;
}
/* take picture activity is done */
camHal->takePictInProgress = 0;
ALOGI("%s: X", __func__);
return (void *)0;
}
/******************************************************************************
* Function: allocate_ion_memory
* Description: This function is allocates ION memory
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int allocate_ion_memory(QCameraHalMemInfo_t *mem_info, int ion_type)
{
int rc = 0;
struct ion_handle_data handle_data;
struct ion_allocation_data alloc;
struct ion_fd_data ion_info_fd;
int main_ion_fd = 0;
main_ion_fd = open("/dev/ion", O_RDONLY);
if (main_ion_fd <= 0) {
ALOGE("Ion dev open failed %s\n", strerror(errno));
goto ION_OPEN_FAILED;
}
memset(&alloc, 0, sizeof(alloc));
alloc.len = mem_info->size;
/* to make it page size aligned */
alloc.len = (alloc.len + 4095) & (~4095);
alloc.align = 4096;
alloc.flags = ION_FLAG_CACHED;
alloc.heap_id_mask = ion_type;
rc = ioctl(main_ion_fd, ION_IOC_ALLOC, &alloc);
if (rc < 0) {
ALOGE("ION allocation failed\n");
goto ION_ALLOC_FAILED;
}
memset(&ion_info_fd, 0, sizeof(ion_info_fd));
ion_info_fd.handle = alloc.handle;
rc = ioctl(main_ion_fd, ION_IOC_SHARE, &ion_info_fd);
if (rc < 0) {
ALOGE("ION map failed %s\n", strerror(errno));
goto ION_MAP_FAILED;
}
mem_info->main_ion_fd = main_ion_fd;
mem_info->fd = ion_info_fd.fd;
mem_info->handle = ion_info_fd.handle;
mem_info->size = alloc.len;
return 0;
ION_MAP_FAILED:
memset(&handle_data, 0, sizeof(handle_data));
handle_data.handle = ion_info_fd.handle;
ioctl(main_ion_fd, ION_IOC_FREE, &handle_data);
ION_ALLOC_FAILED:
close(main_ion_fd);
ION_OPEN_FAILED:
return -1;
}
/******************************************************************************
* Function: deallocate_ion_memory
* Description: This function de allocates ION memory
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No error
* -1 Error
*
* Notes: none
*****************************************************************************/
static int deallocate_ion_memory(QCameraHalMemInfo_t *mem_info)
{
struct ion_handle_data handle_data;
int rc = 0;
if (mem_info->fd > 0) {
close(mem_info->fd);
mem_info->fd = 0;
}
if (mem_info->main_ion_fd > 0) {
memset(&handle_data, 0, sizeof(handle_data));
handle_data.handle = mem_info->handle;
ioctl(mem_info->main_ion_fd, ION_IOC_FREE, &handle_data);
close(mem_info->main_ion_fd);
mem_info->main_ion_fd = 0;
}
return rc;
}
/******************************************************************************
* Function: readFromFile
* Description: This function reads data from the given file into given buffer
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* int bytesRead
*
* Notes: none
*****************************************************************************/
static int readFromFile(char* fileName, char* buffer, int bufferSize)
{
int bytesRead = 0, fileSize = 0;
FILE *fp;
fp = fopen(fileName, "rb");
if(!fp){
ALOGE("%s: Error in opening %s ", __func__, fileName);
return bytesRead;
}
/* If file is bigger for given buffer, exit */
if (fileSize > bufferSize){
ALOGE("%s: Error %d > %d", __func__, fileSize, bufferSize);
return bytesRead;
}
bytesRead = fread(buffer, 1, bufferSize, fp);
ALOGD(" %s: bytesRead: %d", __func__, bytesRead);
return bytesRead;
}
/******************************************************************************
* Function: encodeJpeg
* Description: This function initializes Jpeg encoder and calls jpeg encoder
* call and waits for the encode to complete
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No Error
* -1 Error
*
* Notes: none
*****************************************************************************/
int encodeJpeg(camera_hardware_t *camHal)
{
int rc = 0;
mm_jpeg_ops_t mmJpegOps;
int jpegEncHdl = 0;
mm_jpeg_job mmJpegJob;
src_image_buffer_info *srcBuf = NULL;
QCameraHalMemInfo_t jpegInMemInfo;
camera_memory_t* jpegInMem;
uint32_t jobId;
ALOGI("%s: E", __func__);
/************************************************************************/
/* - Allocate Jpeg input buffer from ION memory */
/************************************************************************/
jpegInMemInfo.size = camHal->pictWidth * camHal->pictHeight * 2;
rc = allocate_ion_memory(&jpegInMemInfo,
((0x1 << CAMERA_ZSL_ION_HEAP_ID) |
(0x1 << CAMERA_ZSL_ION_FALLBACK_HEAP_ID)));
ERROR_CHECK_EXIT(rc, "allocate_ion_memory");
jpegInMem = camHal->get_memory(
jpegInMemInfo.fd, jpegInMemInfo.size, 1, camHal->cb_ctxt);
if(!jpegInMem){
ALOGE("%s: get_mem failed", __func__);
return -1;
}
rc = convert_YUYV_to_420_NV12(
(char *)camHal->buffers[camHal->curCaptureBuf.index].data,
(char *)jpegInMem->data, camHal->pictWidth, camHal->pictHeight);
ERROR_CHECK_EXIT(rc, "convert_YUYV_to_420_NV12");
/************************************************************************/
/* - Populate JPEG encoding parameters from the camHal context */
/************************************************************************/
memset(&mmJpegJob, 0, sizeof(mmJpegJob));
mmJpegJob.job_type = JPEG_JOB_TYPE_ENCODE;
mmJpegJob.encode_job.jpeg_cb = jpegEncodeCb;
mmJpegJob.encode_job.userdata = (void *)camHal;
/* TBD: Rotation to be set from settings sent from app */
mmJpegJob.encode_job.encode_parm.rotation = 0;
mmJpegJob.encode_job.encode_parm.exif_numEntries = 0;
mmJpegJob.encode_job.encode_parm.exif_data = NULL;
/* TBD: Add thumbnail support */
mmJpegJob.encode_job.encode_parm.buf_info.src_imgs.src_img_num = 1;
mmJpegJob.encode_job.encode_parm.buf_info.src_imgs.is_video_frame = 0;
/* Fill main image information */
srcBuf = &mmJpegJob.encode_job.encode_parm.buf_info.src_imgs.src_img[0];
srcBuf->type = JPEG_SRC_IMAGE_TYPE_MAIN;
srcBuf->img_fmt = JPEG_SRC_IMAGE_FMT_YUV;
/* TBD: convert from YUYV to CRCBH2V2 */
srcBuf->color_format = MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
srcBuf->num_bufs = 1;
srcBuf->src_image[0].fd = jpegInMemInfo.fd;
srcBuf->src_image[0].buf_vaddr = (uint8_t*)jpegInMem->data;
//srcBuf->src_image[0].offset = 0;
srcBuf->src_dim.width = camHal->pictWidth;
srcBuf->src_dim.height = camHal->pictHeight;
srcBuf->out_dim.width = camHal->pictWidth;
srcBuf->out_dim.height = camHal->pictHeight;
srcBuf->crop.offset_x = 0;
srcBuf->crop.offset_y = 0;
srcBuf->crop.width = srcBuf->src_dim.width;
srcBuf->crop.height = srcBuf->src_dim.height;
srcBuf->quality = camHal->pictJpegQlty;
/* TBD:Fill thumbnail image information */
/* Fill out buf information */
mmJpegJob.encode_job.encode_parm.buf_info.sink_img.buf_vaddr =
(uint8_t*)camHal->pictMem.camera_memory[0]->data;
mmJpegJob.encode_job.encode_parm.buf_info.sink_img.fd = 0;
/* TBD: hard coded for 1.5 bytes per pixel */
mmJpegJob.encode_job.encode_parm.buf_info.sink_img.buf_len =
camHal->pictWidth * camHal->pictHeight * 1.5;
/************************************************************************/
/* - Initialize jpeg encoder and call Jpeg encoder start */
/************************************************************************/
memset(&mmJpegOps, 0, sizeof(mm_jpeg_ops_t));
jpegEncHdl = jpeg_open(&mmJpegOps);
if(!jpegEncHdl){
ALOGE("%s: Failed to open Jpeg Encoder instance", __func__);
}else
ALOGD("%s: jpegEncHdl = %d", __func__, jpegEncHdl);
camHal->jpegEncInProgress = 1;
rc = mmJpegOps.start_job(jpegEncHdl, &mmJpegJob, &jobId);
/************************************************************************/
/* - Wait for JPEG encoder to complete encoding */
/************************************************************************/
pthread_mutex_init(&camHal->jpegEncMutex, NULL);
pthread_cond_init(&camHal->jpegEncCond, NULL);
pthread_mutex_lock(&camHal->jpegEncMutex);
while(camHal->jpegEncInProgress)
pthread_cond_wait(&camHal->jpegEncCond, &camHal->jpegEncMutex);
pthread_mutex_unlock(&camHal->jpegEncMutex);
/************************************************************************/
/* - De-allocate Jpeg input buffer from ION memory */
/************************************************************************/
if(jpegInMem)
jpegInMem->release(jpegInMem);
rc = deallocate_ion_memory(&jpegInMemInfo);
if(rc)
ALOGE("%s: ION memory de-allocation failed", __func__);
ALOGI("%s: X rc = %d", __func__, rc);
return rc;
}
/******************************************************************************
* Function: jpegEncodeCb
* Description: This is a call back function registered with JPEG encoder.
* Jpeg encoder calls this function on completion of encoding
*
* Input parameters:
* camHal - camera HAL handle
*
* Return values:
* 0 No Error
* -1 Error
*
* Notes: none
*****************************************************************************/
void jpegEncodeCb (jpeg_job_status_t status,
uint8_t thumbnailDroppedFlag,
uint32_t client_hdl,
uint32_t jobId,
uint8_t* out_data,
uint32_t data_size,
void *userData)
{
int rc = 0;
camera_hardware_t *camHal = NULL;
ALOGI("%s: E status = %d", __func__, status);
camHal = (camera_hardware_t*) userData;
if(JPEG_JOB_STATUS_DONE == status){
ALOGD("%s: JPEG encode successful. out_data:%p, size: %d", __func__,
out_data, data_size);
camHal->jpegEncInProgress = 0;
}
pthread_mutex_lock(&camHal->jpegEncMutex);
pthread_cond_signal(&camHal->jpegEncCond);
pthread_mutex_unlock(&camHal->jpegEncMutex);
ALOGI("%s: X", __func__);
return;
}
/******************************************************************************/
}; // namespace android