| /* 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 |