diff options
author | Prateek Chaubey <chaubeyprateek@gmail.com> | 2018-01-07 20:55:14 +0530 |
---|---|---|
committer | Davide Garberi <dade.garberi@gmail.com> | 2018-01-19 14:09:15 +0100 |
commit | 6616278131edd80a12545085e06ee6b0e0a0a788 (patch) | |
tree | 0aef88ed11809a9d67f6abe4dc2ff782a14737e2 /camera/usbcamcore | |
parent | cc4ccf34871da343111bf68d16ba4e4c67cac1dc (diff) |
msm8996-common: zuk: Import OSS Camera HAL
Tag: LA.HB.1.3.2-32600-8x96.0
Signed-off-by: Davide Garberi <dade.garberi@gmail.com>
Diffstat (limited to 'camera/usbcamcore')
-rwxr-xr-x | camera/usbcamcore/inc/QCameraMjpegDecode.h | 49 | ||||
-rwxr-xr-x | camera/usbcamcore/inc/QCameraUsbParm.h | 178 | ||||
-rwxr-xr-x | camera/usbcamcore/inc/QCameraUsbPriv.h | 202 | ||||
-rwxr-xr-x | camera/usbcamcore/inc/QualcommUsbCamera.h | 243 | ||||
-rwxr-xr-x | camera/usbcamcore/src/QCameraMjpegDecode.cpp | 701 | ||||
-rwxr-xr-x | camera/usbcamcore/src/QCameraUsbParm.cpp | 683 | ||||
-rwxr-xr-x | camera/usbcamcore/src/QualcommUsbCamera.cpp | 2963 |
7 files changed, 5019 insertions, 0 deletions
diff --git a/camera/usbcamcore/inc/QCameraMjpegDecode.h b/camera/usbcamcore/inc/QCameraMjpegDecode.h new file mode 100755 index 0000000..b04182b --- /dev/null +++ b/camera/usbcamcore/inc/QCameraMjpegDecode.h @@ -0,0 +1,49 @@ +/* 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. + */ + +#ifndef __QCAMERA_MJPEG_DECODE_H +#define __QCAMERA_MJPEG_DECODE_H + +typedef int MJPEGD_ERR; +#define MJPEGD_NO_ERROR 0 +#define MJPEGD_ERROR -1 +#define MJPEGD_INSUFFICIENT_MEM -2 + +MJPEGD_ERR mjpegDecoderInit(void**); + +MJPEGD_ERR mjpegDecoderDestroy(void* mjpegd); + +MJPEGD_ERR mjpegDecode( + void* mjpegd, + char* mjpegBuffer, + int mjpegBufferSize, + char* outputYptr, + char* outputUVptr, + int outputFormat); + +#endif /* __QCAMERA_MJPEG_DECODE_H */ diff --git a/camera/usbcamcore/inc/QCameraUsbParm.h b/camera/usbcamcore/inc/QCameraUsbParm.h new file mode 100755 index 0000000..595bf42 --- /dev/null +++ b/camera/usbcamcore/inc/QCameraUsbParm.h @@ -0,0 +1,178 @@ +/* Copyright (c) 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. + */ + +#ifndef ANDROID_HARDWARE_QCAMERA_USB_PARM_H +#define ANDROID_HARDWARE_QCAMERA_USB_PARM_H + + +#include <utils/threads.h> +#include <hardware/camera.h> +#include <binder/MemoryBase.h> +#include <binder/MemoryHeapBase.h> +#include <utils/threads.h> +#include <cutils/properties.h> +#include <camera/Camera.h> +#include <camera/QCameraParameters.h> +#include <system/window.h> +#include <system/camera.h> +#include <hardware/camera.h> +#include <gralloc_priv.h> +#include <hardware/power.h> + +extern "C" { +#include <linux/android_pmem.h> +#include <linux/msm_ion.h> +#include <camera.h> +#include <camera_defs_i.h> +} //extern C + +//Error codes +#define NOT_FOUND -1 + +/****************************************************************************** +* Macro definitions +******************************************************************************/ +/* enum definitions for picture formats */ +static const int PICTURE_FORMAT_JPEG = 1; +static const int PICTURE_FORMAT_RAW = 2; + +/* Default preview width in pixels */ +#define DEFAULT_USBCAM_PRVW_WD 1280//640 + +/* Default preview height in pixels */ +#define DEFAULT_USBCAM_PRVW_HT 720//480 + +/* Default picture format */ +#define DEFAULT_USBCAM_PICT_FMT PICTURE_FORMAT_JPEG + +/* Default picture width in pixels */ +#define DEFAULT_USBCAM_PICT_WD 640 + +/* Default picture height in pixels */ +#define DEFAULT_USBCAM_PICT_HT 480 + +/* Default picture JPEG quality 0-100 */ +#define DEFAULT_USBCAM_PICT_QLTY 85 + +/* Default thumbnail width in pixels */ +#define DEFAULT_USBCAM_THUMBNAIL_WD 432 + +/* Default thumbnail height in pixels */ +#define DEFAULT_USBCAM_THUMBNAIL_HT 288 + +/* Default thumbnail JPEG quality 0-100 */ +#define DEFAULT_USBCAM_THUMBNAIL_QLTY 85 + +/* Default preview format */ +#define DEFAULT_USBCAM_PRVW_FMT HAL_PIXEL_FORMAT_YCrCb_420_SP + +/* minimum of the default preview fps range in milli-Hz */ +#define MIN_PREV_FPS 5000 + +/* maximum of the default preview fps range in milli-Hz */ +#define MAX_PREV_FPS 121000 + +//for histogram stats +#define HISTOGRAM_STATS_SIZE 257 +#define NUM_HISTOGRAM_BUFFERS 3 + +namespace android { + +/****************************************************************************** +* Structure definitions +******************************************************************************/ +typedef struct { + uint32_t aspect_ratio; + uint32_t width; + uint32_t height; +} thumbnail_size_type; + +/****************************************************************************** + * Function: usbCamInitDefaultParameters + * Description: This function sets default parameters to camera HAL context + * + * Input parameters: + * camHal - camera HAL handle + * + * Return values: + * 0 No error + * -1 Error + * + * Notes: none + *****************************************************************************/ +int usbCamInitDefaultParameters(camera_hardware_t *camHal); + +/****************************************************************************** + * Function: usbCamSetParameters + * Description: This function parses the parameter string and stores the + * parameters in the camera HAL handle + * + * Input parameters: + * camHal - camera HAL handle + * params - pointer to parameter string + * + * Return values: + * 0 Success + * -1 Error + * Notes: none + *****************************************************************************/ +int usbCamSetParameters(camera_hardware_t *camHal, const char *params); + +/****************************************************************************** + * Function: usbCamGetParameters + * Description: This function allocates memory for parameter string, + * composes and returns the parameter string + * + * Input parameters: + * camHal - camera HAL handle + * + * Return values: + * Address to the parameter string + * + * Notes: none + *****************************************************************************/ +char* usbCamGetParameters(camera_hardware_t *camHal); + +/****************************************************************************** + * Function: usbCamPutParameters + * Description: This function frees the memory allocated for parameter string + * + * Input parameters: + * camHal - camera HAL handle + * parms - Parameter string + * + * Return values: + * 0 Success + * -1 Error + * Notes: none + *****************************************************************************/ +void usbCamPutParameters(camera_hardware_t *camHal, char *parms); + +}; // namespace android + +#endif /* ANDROID_HARDWARE_QCAMERA_USB_PARM_H */ diff --git a/camera/usbcamcore/inc/QCameraUsbPriv.h b/camera/usbcamcore/inc/QCameraUsbPriv.h new file mode 100755 index 0000000..9b60c11 --- /dev/null +++ b/camera/usbcamcore/inc/QCameraUsbPriv.h @@ -0,0 +1,202 @@ +/* Copyright (c) 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. + */ + +#ifndef ANDROID_HARDWARE_QCAMERA_USB_PRIV_H +#define ANDROID_HARDWARE_QCAMERA_USB_PRIV_H + +namespace android { + +/* File name length in number of characters */ +#define FILENAME_LENGTH (256) + +/* Number of display buffers (in addition to minimum number of undequed buffers */ +#define PRVW_DISP_BUF_CNT 2 + +/* Number of V4L2 capture buffers. */ +#define PRVW_CAP_BUF_CNT 4 + +/* Maximum buffer size for JPEG output in number of bytes */ +#define MAX_JPEG_BUFFER_SIZE (1024 * 1024) + +/* Preview loop commands */ +#define USB_CAM_PREVIEW_EXIT (0x100) +#define USB_CAM_PREVIEW_PAUSE (0x101) +#define USB_CAM_PREVIEW_TAKEPIC (0x200) + +/****************************************************************************** + * Macro function to input validate device handle + *****************************************************************************/ +#define VALIDATE_DEVICE_HDL(camHal, device, ret_err_code) {\ + if(device && device->priv){\ + camHal = (camera_hardware_t *)device->priv;\ + }else{\ + ALOGE("%s: Null device or device->priv", __func__);\ + return ret_err_code;\ + }\ +}\ + +/****************************************************************************** + * Macro function to check return status of a function, log and exit the thread + *****************************************************************************/ +#define ERROR_CHECK_EXIT_THREAD(rc, string) {\ + if(rc < 0) {\ + ALOGE("%s: Error %s", __func__, string);\ + return (void *)-1;\ + }\ +} + +/****************************************************************************** + * Macro function to check return status of a function, log and exit + *****************************************************************************/ +#define ERROR_CHECK_EXIT(rc, string) {\ + if(rc < 0) {\ + ALOGE("%s: Error %s", __func__, string);\ + return -1;\ + }\ +} + +/****************************************************************************** +* Macro function to Print the parameter string 1000 characters at a time +******************************************************************************/ +#define PRINT_PARAM_STR(parms) {\ + char temp[1001] = {0};\ + int n=0;\ + while(1) {\ + strlcpy(temp,parms+n,1000);\ + ALOGD("parms = %s", temp);\ + if (strlen(temp) < 1000) break;\ + n += 1000;\ + }\ + }\ + +/****************************************************************************** + * Macro function to open camera + *****************************************************************************/ +#define USB_CAM_OPEN(camHal) {\ + camHal->fd = open(camHal->dev_name, O_RDWR | O_NONBLOCK, 0);\ + if(!camHal->fd)\ + ALOGE("%s: Error in open", __func__);\ + else\ + ALOGD("%s: Successfully opened", __func__);\ + }\ + +/****************************************************************************** + * Macro function to close camera + *****************************************************************************/ +#define USB_CAM_CLOSE(camHal) {\ + int rc;\ + if(camHal->fd){\ + rc = close(camHal->fd);\ + if(0 > rc){\ + ALOGE("%s: close failed ", __func__);\ + }\ + else{\ + camHal->fd = 0;\ + ALOGD("%s: close successful", __func__);\ + }\ + }\ + }\ + +struct bufObj { + void *data; + int len; +}; + +typedef struct { + camera_device hw_dev; + Mutex lock; + int previewEnabledFlag; + int prvwStoppedForPicture; + int msgEnabledFlag; + volatile int prvwCmdPending; + volatile int prvwCmd; + pthread_t previewThread; + pthread_t takePictureThread; + + camera_notify_callback notify_cb; + camera_data_callback data_cb; + camera_data_timestamp_callback data_cb_timestamp; + camera_request_memory get_memory; + void* cb_ctxt; + + /* capture related members */ + /* prevFormat is pixel format of preview buffers that are exported */ + int prevFormat; + int prevFps; + int prevWidth; + int prevHeight; + /* captureFormat is internal setting for USB camera buffers */ + int captureFormat; + char dev_name[FILENAME_LENGTH]; + int fd; + unsigned int n_buffers; + struct v4l2_buffer curCaptureBuf; + struct bufObj *buffers; + + /* Display related members */ + preview_stream_ops* window; + QCameraHalMemory_t previewMem; + /* dispFormat is preview display format.Same as preview buffer format*/ + int dispFormat; + int dispWidth; + int dispHeight; + + /* MJPEG decoder related members */ + /* MJPEG decoder object */ + void* mjpegd; + + /* JPEG picture and thumbnail related members */ + int pictFormat; + int pictWidth; + int pictHeight; + int pictJpegQlty; + int thumbnailWidth; + int thumbnailHeight; + int thumbnailJpegQlty; + QCameraHalMemory_t pictMem; + int takePictInProgress; + int jpegEncInProgress; + pthread_mutex_t jpegEncMutex; + pthread_cond_t jpegEncCond; + + /* */ + QCameraParameters qCamParams; + String8 prevSizeValues; + String8 pictSizeValues; + String8 thumbnailSizeValues; + String8 vidSizeValues; + String8 pictFormatValues; + String8 prevFormatValues; + String8 prevFpsRangesValues; + +} camera_hardware_t; + + +}; // namespace android + +#endif /* ANDROID_HARDWARE_QCAMERA_USB_PRIV_H */ diff --git a/camera/usbcamcore/inc/QualcommUsbCamera.h b/camera/usbcamcore/inc/QualcommUsbCamera.h new file mode 100755 index 0000000..e389c76 --- /dev/null +++ b/camera/usbcamcore/inc/QualcommUsbCamera.h @@ -0,0 +1,243 @@ +/* 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. + */ + +#ifndef ANDROID_HARDWARE_QUALCOMM_CAMERA_USBCAM_H +#define ANDROID_HARDWARE_QUALCOMM_CAMERA_USBCAM_H + +extern "C" { +#include <sys/time.h> +} + +#include "QCameraHWI.h" + +extern "C" { + +/*#include <hardware/camera.h>*/ + + int usbcam_get_number_of_cameras(); + int usbcam_get_camera_info(int camera_id, struct camera_info *info); + + int usbcam_camera_device_open(const struct hw_module_t* module, const char* id, + struct hw_device_t** device); + + hw_device_t * usbcam_open_camera_device(int cameraId); + + int usbcam_close_camera_device( hw_device_t *); + +namespace android { + + /** Set the ANativeWindow to which preview frames are sent */ + int usbcam_set_preview_window(struct camera_device *, + struct preview_stream_ops *window); + + /** Set the notification and data callbacks */ + void usbcam_set_CallBacks(struct camera_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); + + /** + * The following three functions all take a msg_type, which is a bitmask of + * the messages defined in include/ui/Camera.h + */ + + /** + * Enable a message, or set of messages. + */ + void usbcam_enable_msg_type(struct camera_device *, int32_t msg_type); + + /** + * Disable a message, or a set of messages. + * + * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera + * HAL should not rely on its client to call releaseRecordingFrame() to + * release video recording frames sent out by the cameral HAL before and + * after the disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera HAL + * clients must not modify/access any video recording frame after calling + * disableMsgType(CAMERA_MSG_VIDEO_FRAME). + */ + void usbcam_disable_msg_type(struct camera_device *, int32_t msg_type); + + /** + * Query whether a message, or a set of messages, is enabled. Note that + * this is operates as an AND, if any of the messages queried are off, this + * will return false. + */ + int usbcam_msg_type_enabled(struct camera_device *, int32_t msg_type); + + /** + * Start preview mode. + */ + int usbcam_start_preview(struct camera_device *); + + /** + * Stop a previously started preview. + */ + void usbcam_stop_preview(struct camera_device *); + + /** + * Returns true if preview is enabled. + */ + int usbcam_preview_enabled(struct camera_device *); + + /** + * Request the camera HAL to store meta data or real YUV data in the video + * buffers sent out via CAMERA_MSG_VIDEO_FRAME for a recording session. If + * it is not called, the default camera HAL behavior is to store real YUV + * data in the video buffers. + * + * This method should be called before startRecording() in order to be + * effective. + * + * If meta data is stored in the video buffers, it is up to the receiver of + * the video buffers to interpret the contents and to find the actual frame + * data with the help of the meta data in the buffer. How this is done is + * outside of the scope of this method. + * + * Some camera HALs may not support storing meta data in the video buffers, + * but all camera HALs should support storing real YUV data in the video + * buffers. If the camera HAL does not support storing the meta data in the + * video buffers when it is requested to do do, INVALID_OPERATION must be + * returned. It is very useful for the camera HAL to pass meta data rather + * than the actual frame data directly to the video encoder, since the + * amount of the uncompressed frame data can be very large if video size is + * large. + * + * @param enable if true to instruct the camera HAL to store + * meta data in the video buffers; false to instruct + * the camera HAL to store real YUV data in the video + * buffers. + * + * @return OK on success. + */ + int usbcam_store_meta_data_in_buffers(struct camera_device *, int enable); + + /** + * Start record mode. When a record image is available, a + * CAMERA_MSG_VIDEO_FRAME message is sent with the corresponding + * frame. Every record frame must be released by a camera HAL client via + * releaseRecordingFrame() before the client calls + * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls + * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's + * responsibility to manage the life-cycle of the video recording frames, + * and the client must not modify/access any video recording frames. + */ + int usbcam_start_recording(struct camera_device *); + + /** + * Stop a previously started recording. + */ + void usbcam_stop_recording(struct camera_device *); + + /** + * Returns true if recording is enabled. + */ + int usbcam_recording_enabled(struct camera_device *); + + /** + * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME. + * + * It is camera HAL client's responsibility to release video recording + * frames sent out by the camera HAL before the camera HAL receives a call + * to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives the call to + * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's + * responsibility to manage the life-cycle of the video recording frames. + */ + void usbcam_release_recording_frame(struct camera_device *, + const void *opaque); + + /** + * Start auto focus, the notification callback routine is called with + * CAMERA_MSG_FOCUS once when focusing is complete. autoFocus() will be + * called again if another auto focus is needed. + */ + int usbcam_auto_focus(struct camera_device *); + + /** + * Cancels auto-focus function. If the auto-focus is still in progress, + * this function will cancel it. Whether the auto-focus is in progress or + * not, this function will return the focus position to the default. If + * the camera does not support auto-focus, this is a no-op. + */ + int usbcam_cancel_auto_focus(struct camera_device *); + + /** + * Take a picture. + */ + int usbcam_take_picture(struct camera_device *); + + /** + * Cancel a picture that was started with takePicture. Calling this method + * when no picture is being taken is a no-op. + */ + int usbcam_cancel_picture(struct camera_device *); + + /** + * Set the camera parameters. This returns BAD_VALUE if any parameter is + * invalid or not supported. + */ + int usbcam_set_parameters(struct camera_device *, const char *parms); + + //status_t setParameters(const QCameraParameters& params); + /** Retrieve the camera parameters. The buffer returned by the camera HAL + must be returned back to it with put_parameters, if put_parameters + is not NULL. + */ + char* usbcam_get_parameters(struct camera_device *); + + /** The camera HAL uses its own memory to pass us the parameters when we + call get_parameters. Use this function to return the memory back to + the camera HAL, if put_parameters is not NULL. If put_parameters + is NULL, then you have to use free() to release the memory. + */ + void usbcam_put_parameters(struct camera_device *, char *); + + /** + * Send command to camera driver. + */ + int usbcam_send_command(struct camera_device *, + int32_t cmd, int32_t arg1, int32_t arg2); + + /** + * Release the hardware resources owned by this object. Note that this is + * *not* done in the destructor. + */ + void usbcam_release(struct camera_device *); + + /** + * Dump state of the camera hardware + */ + int usbcam_dump(struct camera_device *, int fd); + +}; // namespace android + +} //extern "C" + +#endif diff --git a/camera/usbcamcore/src/QCameraMjpegDecode.cpp b/camera/usbcamcore/src/QCameraMjpegDecode.cpp new file mode 100755 index 0000000..dcf0aa2 --- /dev/null +++ b/camera/usbcamcore/src/QCameraMjpegDecode.cpp @@ -0,0 +1,701 @@ +/* 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. + */ + +//#define ALOG_NDEBUG 0 +#define ALOG_NIDEBUG 0 +#define LOG_TAG "QCameraMjpegDecode" +#include <utils/Log.h> + +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> + +extern "C" { +#include "jpeg_buffer.h" +#include "jpeg_common.h" +#include "jpegd.h" +} + +#include "QCameraMjpegDecode.h" + +/* TBDJ: Can be removed */ +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +// Abstract the return type of the function to be run as a thread +#define OS_THREAD_FUNC_RET_T void * + +// Abstract the argument type to the thread function +#define OS_THREAD_FUNC_ARG_T void * + +// Helpful constants for return values in the thread functions +#define OS_THREAD_FUNC_RET_SUCCEEDED (OS_THREAD_FUNC_RET_T)0 +#define OS_THREAD_FUNC_RET_FAILED (OS_THREAD_FUNC_RET_T)1 + +// Abstract the function modifier placed in the beginning of the thread +// declaration (empty for Linux) +#define OS_THREAD_FUNC_MODIFIER + +#define os_mutex_init(a) pthread_mutex_init(a, NULL) +#define os_cond_init(a) pthread_cond_init(a, NULL) +#define os_mutex_lock pthread_mutex_lock +#define os_mutex_unlock pthread_mutex_unlock +#define os_cond_wait pthread_cond_wait +#define os_cond_signal pthread_cond_signal + +const char event_to_string[4][14] = +{ + "EVENT_DONE", + "EVENT_WARNING", + "EVENT_ERROR", +}; + +typedef struct +{ + uint32_t width; + uint32_t height; + uint32_t format; + uint32_t preference; + uint32_t abort_time; + uint16_t back_to_back_count; + /* TBDJ: Is this required */ + int32_t rotation; + /* TBDJ: Is this required */ + jpeg_rectangle_t region; + /* TBDJ: Is this required */ + jpegd_scale_type_t scale_factor; + uint32_t hw_rotation; + + char* inputMjpegBuffer; + int inputMjpegBufferSize; + char* outputYptr; + char* outputUVptr; + +} test_args_t; + +typedef struct +{ + int tid; + pthread_t thread; + jpegd_obj_t decoder; + uint8_t decoding; + uint8_t decode_success; + pthread_mutex_t mutex; + pthread_cond_t cond; + test_args_t *p_args; + jpegd_output_buf_t *p_whole_output_buf; + +} thread_ctrl_blk_t; + +OS_THREAD_FUNC_RET_T OS_THREAD_FUNC_MODIFIER decoder_test(OS_THREAD_FUNC_ARG_T p_thread_args); +void decoder_event_handler(void *p_user_data, + jpeg_event_t event, + void *p_arg); +int decoder_output_handler(void *p_user_data, + jpegd_output_buf_t *p_output_buffer, + uint32_t first_row_id, + uint8_t is_last_buffer); +uint32_t decoder_input_req_handler(void *p_user_data, + jpeg_buffer_t buffer, + uint32_t start_offset, + uint32_t length); +static void* insertHuffmanTable(void *p, int size); + +static int mjpegd_timer_start(timespec *p_timer); +static int mjpegd_timer_get_elapsed(timespec *p_timer, int *elapsed_in_ms, uint8_t reset_start); +static int mjpegd_cond_timedwait(pthread_cond_t *p_cond, pthread_mutex_t *p_mutex, uint32_t ms); + +// Global variables +/* TBDJ: can be removed */ +thread_ctrl_blk_t *thread_ctrl_blks = NULL; + +/* + * This function initializes the mjpeg decoder and returns the object + */ +MJPEGD_ERR mjpegDecoderInit(void** mjpegd_obj) +{ + test_args_t* mjpegd; + + ALOGD("%s: E", __func__); + + mjpegd = (test_args_t *)malloc(sizeof(test_args_t)); + if(!mjpegd) + return MJPEGD_INSUFFICIENT_MEM; + + memset(mjpegd, 0, sizeof(test_args_t)); + + /* Defaults */ + /* Due to current limitation, s/w decoder is selected always */ + mjpegd->preference = JPEG_DECODER_PREF_HW_ACCELERATED_PREFERRED; + mjpegd->back_to_back_count = 1; + mjpegd->rotation = 0; + mjpegd->hw_rotation = 0; + mjpegd->scale_factor = (jpegd_scale_type_t)1; + + /* TBDJ: can be removed */ + mjpegd->width = 640; + mjpegd->height = 480; + mjpegd->abort_time = 0; + + *mjpegd_obj = (void *)mjpegd; + + ALOGD("%s: X", __func__); + return MJPEGD_NO_ERROR; +} + +MJPEGD_ERR mjpegDecode( + void* mjpegd_obj, + char* inputMjpegBuffer, + int inputMjpegBufferSize, + char* outputYptr, + char* outputUVptr, + int outputFormat) +{ + int rc, c, i; + test_args_t* mjpegd; + test_args_t test_args; + + ALOGD("%s: E", __func__); + /* store input arguments in the context */ + mjpegd = (test_args_t*) mjpegd_obj; + mjpegd->inputMjpegBuffer = inputMjpegBuffer; + mjpegd->inputMjpegBufferSize = inputMjpegBufferSize; + mjpegd->outputYptr = outputYptr; + mjpegd->outputUVptr = outputUVptr; + mjpegd->format = outputFormat; + + /* TBDJ: can be removed */ + memcpy(&test_args, mjpegd, sizeof(test_args_t)); + + // check the formats + if (((test_args.format == YCRCBLP_H1V2) || (test_args.format == YCBCRLP_H1V2) || + (test_args.format == YCRCBLP_H1V1) || (test_args.format == YCBCRLP_H1V1)) && + !(test_args.preference == JPEG_DECODER_PREF_HW_ACCELERATED_ONLY)) { + ALOGE("%s:These formats are not supported by SW format %d", __func__, test_args.format); + return 1; + } + + // Create thread control blocks + thread_ctrl_blks = (thread_ctrl_blk_t *)malloc( sizeof(thread_ctrl_blk_t)); + if (!thread_ctrl_blks) + { + ALOGE("%s: decoder_test failed: insufficient memory in creating thread control blocks", __func__); + return 1; + } + memset(thread_ctrl_blks, 0, sizeof(thread_ctrl_blk_t)); + // Initialize the blocks and kick off the threads + thread_ctrl_blks[i].tid = i; + thread_ctrl_blks[i].p_args = &test_args; + os_mutex_init(&thread_ctrl_blks[i].mutex); + os_cond_init(&thread_ctrl_blks[i].cond); + + rc = (int)decoder_test(&thread_ctrl_blks[i]); + + if (!rc) + ALOGD("%s: decoder_test finished successfully ", __func__); + else + ALOGE("%s: decoder_test failed",__func__); + + ALOGD("%s: X rc: %d", __func__, rc); + + return rc; +} + +OS_THREAD_FUNC_RET_T OS_THREAD_FUNC_MODIFIER decoder_test(OS_THREAD_FUNC_ARG_T arg) +{ + int rc, i; + jpegd_obj_t decoder; + jpegd_src_t source; + jpegd_dst_t dest; + jpegd_cfg_t config; + jpeg_hdr_t header; + jpegd_output_buf_t p_output_buffers; + uint32_t output_buffers_count = 1; // currently only 1 buffer a time is supported + uint8_t use_pmem = true; + timespec os_timer; + thread_ctrl_blk_t *p_thread_arg = (thread_ctrl_blk_t *)arg; + test_args_t *p_args = p_thread_arg->p_args; + uint32_t output_width; + uint32_t output_height; + uint32_t total_time = 0; + + ALOGD("%s: E", __func__); + + // Determine whether pmem should be used (useful for pc environment testing where + // pmem is not available) + if ((jpegd_preference_t)p_args->preference == JPEG_DECODER_PREF_SOFTWARE_PREFERRED || + (jpegd_preference_t)p_args->preference == JPEG_DECODER_PREF_SOFTWARE_ONLY) { + use_pmem = false; + } + + if (((jpegd_preference_t)p_args->preference != + JPEG_DECODER_PREF_HW_ACCELERATED_ONLY) && + ((jpegd_preference_t)p_args->scale_factor > 0)) { + ALOGI("%s: Setting scale factor to 1x", __func__); + } + + ALOGD("%s: before jpegd_init p_thread_arg: %p", __func__, p_thread_arg); + + // Initialize decoder + rc = jpegd_init(&decoder, + &decoder_event_handler, + &decoder_output_handler, + p_thread_arg); + + if (JPEG_FAILED(rc)) { + ALOGE("%s: decoder_test: jpegd_init failed", __func__); + goto fail; + } + p_thread_arg->decoder = decoder; + + // Set source information + source.p_input_req_handler = &decoder_input_req_handler; + source.total_length = p_args->inputMjpegBufferSize & 0xffffffff; + + rc = jpeg_buffer_init(&source.buffers[0]); + if (JPEG_SUCCEEDED(rc)) { + /* TBDJ: why buffer [1] */ + rc = jpeg_buffer_init(&source.buffers[1]); + } + if (JPEG_SUCCEEDED(rc)) { +#if 1 + rc = jpeg_buffer_allocate(source.buffers[0], 0xA000, use_pmem); +#else + rc = jpeg_buffer_use_external_buffer(source.buffers[0], + (uint8_t *)p_args->inputMjpegBuffer, + p_args->inputMjpegBufferSize, + 0); +#endif + ALOGD("%s: source.buffers[0]:%p compressed buffer ptr = %p", __func__, + source.buffers[0], p_args->inputMjpegBuffer); + } + if (JPEG_SUCCEEDED(rc)) { +#if 1 + rc = jpeg_buffer_allocate(source.buffers[1], 0xA000, use_pmem); +#else + rc = jpeg_buffer_use_external_buffer(source.buffers[1], + (uint8_t *)p_args->inputMjpegBuffer, + p_args->inputMjpegBufferSize, + 0); +#endif + ALOGD("%s: source.buffers[1]:%p compressed buffer ptr = %p", __func__, + source.buffers[1], p_args->inputMjpegBuffer); + } + if (JPEG_FAILED(rc)) { + jpeg_buffer_destroy(&source.buffers[0]); + jpeg_buffer_destroy(&source.buffers[1]); + goto fail; + } + + ALOGI("%s: *** Starting back-to-back decoding of %d frame(s)***\n", + __func__, p_args->back_to_back_count); + + // Loop to perform n back-to-back decoding (to the same output file) + for(i = 0; i < p_args->back_to_back_count; i++) { + if(mjpegd_timer_start(&os_timer) < 0) { + ALOGE("%s: failed to get start time", __func__); + } + + /* TBDJ: Every frame? */ + ALOGD("%s: before jpegd_set_source source.p_arg:%p", __func__, source.p_arg); + rc = jpegd_set_source(decoder, &source); + if (JPEG_FAILED(rc)) + { + ALOGE("%s: jpegd_set_source failed", __func__); + goto fail; + } + + rc = jpegd_read_header(decoder, &header); + if (JPEG_FAILED(rc)) + { + ALOGE("%s: jpegd_read_header failed", __func__); + goto fail; + } + p_args->width = header.main.width; + p_args->height = header.main.height; + ALOGD("%s: main dimension: (%dx%d) subsampling: (%d)", __func__, + header.main.width, header.main.height, (int)header.main.subsampling); + + // main image decoding: + // Set destination information + dest.width = (p_args->width) ? (p_args->width) : header.main.width; + dest.height = (p_args->height) ? (p_args->height) : header.main.height; + dest.output_format = (jpeg_color_format_t) p_args->format; + dest.region = p_args->region; + + // if region is defined, re-assign the output width/height + output_width = dest.width; + output_height = dest.height; + + if (p_args->region.right || p_args->region.bottom) + { + if (0 == p_args->rotation || 180 == p_args->rotation) + { + output_width = MIN((dest.width), + (uint32_t)(dest.region.right - dest.region.left + 1)); + output_height = MIN((dest.height), + (uint32_t)(dest.region.bottom - dest.region.top + 1)); + } + // Swap output width/height for 90/270 rotation cases + else if (90 == p_args->rotation || 270 == p_args->rotation) + { + output_height = MIN((dest.height), + (uint32_t)(dest.region.right - dest.region.left + 1)); + output_width = MIN((dest.width), + (uint32_t)(dest.region.bottom - dest.region.top + 1)); + } + // Unsupported rotation cases + else + { + goto fail; + } + } + + if (dest.output_format == YCRCBLP_H2V2 || dest.output_format == YCBCRLP_H2V2 || + dest.output_format == YCRCBLP_H2V1 || dest.output_format == YCBCRLP_H2V1 || + dest.output_format == YCRCBLP_H1V2 || dest.output_format == YCBCRLP_H1V2 || + dest.output_format == YCRCBLP_H1V1 || dest.output_format == YCBCRLP_H1V1) { + jpeg_buffer_init(&p_output_buffers.data.yuv.luma_buf); + jpeg_buffer_init(&p_output_buffers.data.yuv.chroma_buf); + } else { + jpeg_buffer_init(&p_output_buffers.data.rgb.rgb_buf); + + } + + { + // Assign 0 to tile width and height + // to indicate that no tiling is requested. + p_output_buffers.tile_width = 0; + p_output_buffers.tile_height = 0; + } + p_output_buffers.is_in_q = 0; + + switch (dest.output_format) + { + case YCRCBLP_H2V2: + case YCBCRLP_H2V2: +// case YCRCBLP_H2V1: +// case YCBCRLP_H2V1: +// case YCRCBLP_H1V2: +// case YCBCRLP_H1V2: +// case YCRCBLP_H1V1: +// case YCBCRLP_H1V1: + jpeg_buffer_use_external_buffer( + p_output_buffers.data.yuv.luma_buf, + (uint8_t*)p_args->outputYptr, + p_args->width * p_args->height * SQUARE(p_args->scale_factor), + 0); + jpeg_buffer_use_external_buffer( + p_output_buffers.data.yuv.chroma_buf, + (uint8_t*)p_args->outputUVptr, + p_args->width * p_args->height / 2 * SQUARE(p_args->scale_factor), + 0); + break; + + default: + ALOGE("%s: decoder_test: unsupported output format", __func__); + goto fail; + } + + // Set up configuration + memset(&config, 0, sizeof(jpegd_cfg_t)); + config.preference = (jpegd_preference_t) p_args->preference; + config.decode_from = JPEGD_DECODE_FROM_AUTO; + config.rotation = p_args->rotation; + config.scale_factor = p_args->scale_factor; + config.hw_rotation = p_args->hw_rotation; + dest.back_to_back_count = p_args->back_to_back_count; + + // Start decoding + p_thread_arg->decoding = true; + + rc = jpegd_start(decoder, &config, &dest, &p_output_buffers, output_buffers_count); + dest.back_to_back_count--; + + if(JPEG_FAILED(rc)) { + ALOGE("%s: decoder_test: jpegd_start failed (rc=%d)\n", + __func__, rc); + goto fail; + } + + ALOGD("%s: decoder_test: jpegd_start succeeded", __func__); + + // Do abort + if (p_args->abort_time) { + os_mutex_lock(&p_thread_arg->mutex); + while (p_thread_arg->decoding) + { + rc = mjpegd_cond_timedwait(&p_thread_arg->cond, &p_thread_arg->mutex, p_args->abort_time); + if (rc == JPEGERR_ETIMEDOUT) + { + // Do abort + os_mutex_unlock(&p_thread_arg->mutex); + rc = jpegd_abort(decoder); + if (rc) + { + ALOGE("%s: decoder_test: jpegd_abort failed: %d", __func__, rc); + goto fail; + } + break; + } + } + if (p_thread_arg->decoding) + os_mutex_unlock(&p_thread_arg->mutex); + } else { + // Wait until decoding is done or stopped due to error + os_mutex_lock(&p_thread_arg->mutex); + while (p_thread_arg->decoding) + { + os_cond_wait(&p_thread_arg->cond, &p_thread_arg->mutex); + } + os_mutex_unlock(&p_thread_arg->mutex); + } + + int diff; + // Display the time elapsed + if (mjpegd_timer_get_elapsed(&os_timer, &diff, 0) < 0) { + ALOGE("%s: decoder_test: failed to get elapsed time", __func__); + } else { + if(p_args->abort_time) { + if(p_thread_arg->decoding) { + ALOGI("%s: decoder_test: decoding aborted successfully after %d ms", __func__, diff); + goto buffer_clean_up; + } + else + { + ALOGI("%s: decoder_test: decoding stopped before abort is issued. " + "decode time: %d ms", __func__, diff); + } + } + else { + if(p_thread_arg->decode_success) { + total_time += diff; + ALOGI("%s: decode time: %d ms (%d frame(s), total=%dms, avg=%dms/frame)", + __func__, diff, i+1, total_time, total_time/(i+1)); + } + else + { + fprintf(stderr, "decoder_test: decode failed\n"); + } + } + } + } + + if(p_thread_arg->decode_success) { + ALOGD("%s: Frame(s) = %d, Total Time = %dms, Avg. decode time = %dms/frame)\n", + __func__, p_args->back_to_back_count, total_time, total_time/p_args->back_to_back_count); + } + +buffer_clean_up: + // Clean up decoder and allocate buffers + jpeg_buffer_destroy(&source.buffers[0]); + jpeg_buffer_destroy(&source.buffers[1]); + switch (dest.output_format) + { + case YCRCBLP_H2V2: + case YCBCRLP_H2V2: + case YCRCBLP_H2V1: + case YCBCRLP_H2V1: + case YCRCBLP_H1V2: + case YCBCRLP_H1V2: + case YCRCBLP_H1V1: + case YCBCRLP_H1V1: + jpeg_buffer_destroy(&p_output_buffers.data.yuv.luma_buf); + jpeg_buffer_destroy(&p_output_buffers.data.yuv.chroma_buf); + break; + default: + break; + } + jpegd_destroy(&decoder); + + if (!p_thread_arg->decode_success) + { + goto fail; + } + + ALOGD("%s: X", __func__); + return OS_THREAD_FUNC_RET_SUCCEEDED; +fail: + + ALOGD("%s: X", __func__); + return OS_THREAD_FUNC_RET_FAILED; +} + +void decoder_event_handler(void *p_user_data, + jpeg_event_t event, + void *p_arg) +{ + thread_ctrl_blk_t *p_thread_arg = (thread_ctrl_blk_t *)p_user_data; + + ALOGD("%s: E", __func__); + + ALOGD("%s: Event: %s\n", __func__, event_to_string[event]); + if (event == JPEG_EVENT_DONE) + { + p_thread_arg->decode_success = true; + ALOGD("%s: decode_success: %d\n", __func__, p_thread_arg->decode_success); + } + // If it is not a warning event, decoder has stopped; Signal + // main thread to clean up + if (event != JPEG_EVENT_WARNING) + { + os_mutex_lock(&p_thread_arg->mutex); + p_thread_arg->decoding = false; + os_cond_signal(&p_thread_arg->cond); + os_mutex_unlock(&p_thread_arg->mutex); + } + ALOGD("%s: X", __func__); + +} + +// consumes the output buffer. +/*TBDJ: Can be removed. Is this related to tiling */ +int decoder_output_handler(void *p_user_data, + jpegd_output_buf_t *p_output_buffer, + uint32_t first_row_id, + uint8_t is_last_buffer) +{ + uint8_t* whole_output_buf_ptr, *tiling_buf_ptr; + + ALOGD("%s: E", __func__); + + thread_ctrl_blk_t *p_thread_arg = (thread_ctrl_blk_t *)p_user_data; + + jpeg_buffer_get_addr(p_thread_arg->p_whole_output_buf->data.rgb.rgb_buf, &whole_output_buf_ptr); + jpeg_buffer_get_addr(p_output_buffer->data.rgb.rgb_buf, &tiling_buf_ptr); + + if (p_output_buffer->tile_height != 1) + return JPEGERR_EUNSUPPORTED; + + // testing purpose only + // This is to simulate that the user needs to bail out when error happens + // in the middle of decoding + //if (first_row_id == 162) + // return JPEGERR_EFAILED; + + // do not enqueue any buffer if it reaches the last buffer + if (!is_last_buffer) + { + jpegd_enqueue_output_buf(p_thread_arg->decoder, p_output_buffer, 1); + } + ALOGD("%s: X", __func__); + + return JPEGERR_SUCCESS; +} + +// p_reader->p_input_req_handler(p_reader->decoder, +// p_reader->p_input_buf, +// p_reader->next_byte_offset, +// MAX_BYTES_TO_FETCH); + +uint32_t decoder_input_req_handler(void *p_user_data, + jpeg_buffer_t buffer, + uint32_t start_offset, + uint32_t length) +{ + uint32_t buf_size; + uint8_t *buf_ptr; + int bytes_to_read, bytes_read, rc; + thread_ctrl_blk_t *p_thread_arg = (thread_ctrl_blk_t *)p_user_data; + thread_ctrl_blk_t *thread_ctrl_blk = (thread_ctrl_blk_t *)p_user_data; + test_args_t* mjpegd = (test_args_t*) thread_ctrl_blk->p_args; + + ALOGD("%s: E", __func__); + + jpeg_buffer_get_max_size(buffer, &buf_size); + jpeg_buffer_get_addr(buffer, &buf_ptr); + bytes_to_read = (length < buf_size) ? length : buf_size; + bytes_read = 0; + + ALOGD("%s: buf_ptr = %p, start_offset = %d, length = %d buf_size = %d bytes_to_read = %d", __func__, buf_ptr, start_offset, length, buf_size, bytes_to_read); + if (bytes_to_read) + { + /* TBDJ: Should avoid this Mem copy */ +#if 1 + memcpy(buf_ptr, (char *)mjpegd->inputMjpegBuffer + start_offset, bytes_to_read); +#else + if(JPEGERR_SUCCESS != jpeg_buffer_set_start_offset(buffer, start_offset)) + ALOGE("%s: jpeg_buffer_set_start_offset failed", __func__); +#endif + bytes_read = bytes_to_read; + } + + ALOGD("%s: X", __func__); + return bytes_read; +} + +static int mjpegd_timer_start(timespec *p_timer) +{ + if (!p_timer) + return JPEGERR_ENULLPTR; + + if (clock_gettime(CLOCK_REALTIME, p_timer)) + return JPEGERR_EFAILED; + + return JPEGERR_SUCCESS; +} + +static int mjpegd_timer_get_elapsed(timespec *p_timer, int *elapsed_in_ms, uint8_t reset_start) +{ + timespec now; + long diff; + int rc = mjpegd_timer_start(&now); + + if (JPEG_FAILED(rc)) + return rc; + + diff = (long)(now.tv_sec - p_timer->tv_sec) * 1000; + diff += (long)(now.tv_nsec - p_timer->tv_nsec) / 1000000; + *elapsed_in_ms = (int)diff; + + if (reset_start) + *p_timer = now; + + return JPEGERR_SUCCESS; +} + +int mjpegd_cond_timedwait(pthread_cond_t *p_cond, pthread_mutex_t *p_mutex, uint32_t ms) +{ + struct timespec ts; + int rc = clock_gettime(CLOCK_REALTIME, &ts); + if (rc < 0) return rc; + + if (ms >= 1000) { + ts.tv_sec += (ms/1000); + ts.tv_nsec += ((ms%1000) * 1000000); + } else { + ts.tv_nsec += (ms * 1000000); + } + + rc = pthread_cond_timedwait(p_cond, p_mutex, &ts); + if (rc == ETIMEDOUT) + { + rc = JPEGERR_ETIMEDOUT; + } + return rc; +} + diff --git a/camera/usbcamcore/src/QCameraUsbParm.cpp b/camera/usbcamcore/src/QCameraUsbParm.cpp new file mode 100755 index 0000000..fda6e9d --- /dev/null +++ b/camera/usbcamcore/src/QCameraUsbParm.cpp @@ -0,0 +1,683 @@ +/* Copyright (c) 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. + */ + +//#define ALOG_NDEBUG 0 +#define ALOG_NIDEBUG 0 +#define LOG_TAG "QCameraUsbParm" +#include <utils/Log.h> + +#include <utils/Errors.h> +#include <utils/threads.h> +#include <utils/String16.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <cutils/properties.h> +#include <math.h> +#if HAVE_ANDROID_OS +#include <linux/android_pmem.h> +#endif +#include <linux/ioctl.h> +#include <camera/QCameraParameters.h> +#include <media/mediarecorder.h> +#include <gralloc_priv.h> + +#include "linux/msm_mdp.h" +#include <linux/fb.h> +#include <limits.h> + + +extern "C" { +#include <fcntl.h> +#include <time.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <assert.h> +#include <stdlib.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/mman.h> +#include <sys/system_properties.h> +#include <sys/time.h> +#include <stdlib.h> +#include <linux/msm_ion.h> +#include <camera.h> +#include <cam_fifo.h> +#include <jpege.h> + +} // extern "C" + +#include "QCameraHWI.h" +#include "QualcommUsbCamera.h" +#include "QCameraUsbPriv.h" +#include "QCameraUsbParm.h" + +namespace android { + +/********************************************************************/ +static const str_map preview_formats[] = { + {QCameraParameters::PIXEL_FORMAT_YUV420SP, HAL_PIXEL_FORMAT_YCrCb_420_SP}, +}; + +static const preview_format_info_t preview_format_info_list[] = { + {HAL_PIXEL_FORMAT_YV12, CAMERA_YUV_420_YV12, CAMERA_PAD_TO_WORD, 3} +}; + +static struct camera_size_type previewSizes[] = { + { 1920, 1088}, //1080p + { 1280, 720}, // 720P, + { 640, 480}, // VGA + { 512, 384}, + { 480, 320}, + { 320, 240}, // QVGA +}; + +// All fps ranges which can be supported. This list will be filtered according +// to the min and max fps supported by hardware +// this list must be sorted first by max_fps and then min_fps +// fps values are multiplied by 1000 +static android::FPSRange prevFpsRanges[] = { + android::FPSRange(5000, 121000), +}; + +/* TBR: Is frame rate mode mandatory */ +static const str_map frame_rate_modes[] = { + {QCameraParameters::KEY_QC_PREVIEW_FRAME_RATE_AUTO_MODE, FPS_MODE_AUTO}, + {QCameraParameters::KEY_QC_PREVIEW_FRAME_RATE_FIXED_MODE, FPS_MODE_FIXED} +}; + +static const str_map picture_formats[] = { + {QCameraParameters::PIXEL_FORMAT_JPEG, PICTURE_FORMAT_JPEG}, + //{QCameraParameters::PIXEL_FORMAT_RAW, PICTURE_FORMAT_RAW} +}; + +static camera_size_type picture_sizes[] = { + { 1920, 1088}, //HD1080 + { 1280, 720}, //HD720 + { 640, 480}, // VGA + { 320, 240}, // QVGA +}; + +/* aspect ratio removed */ +static camera_size_type thumbnail_sizes[] = { + { 512, 288 }, //1.777778 + { 480, 288 }, //1.666667 + { 256, 154 }, //1.66233 + { 432, 288 }, //1.5 + { 512, 384 }, //1.333333 + { 352, 288 }, //1.222222 + { 320, 240 }, //1.33333 + { 176, 144 }, //1.222222 +}; + +static const str_map recording_Hints[] = { + {"false", FALSE}, + {"true", TRUE} +}; + +/* Static functions list */ +static String8 create_sizes_str(const camera_size_type *sizes, int len); +static String8 create_values_str(const str_map *values, int len); +static String8 create_fps_str(const android:: FPSRange* fps, int len); +static String8 create_values_range_str(int min, int max); +static int usbCamSetPrvwSize( camera_hardware_t *camHal, + const QCameraParameters& params); +static int usbCamSetPictSize( camera_hardware_t *camHal, + const QCameraParameters& params); +static int usbCamSetThumbnailSize( camera_hardware_t *camHal, + const QCameraParameters& params); +static int usbCamSetJpegQlty( camera_hardware_t *camHal, + const QCameraParameters& params); + +/****************************************************************************** + * Function: usbCamInitDefaultParameters + * Description: This function sets default parameters to camera HAL context + * + * Input parameters: + * camHal - camera HAL handle + * + * Return values: + * None + * + * Notes: none + *****************************************************************************/ +int usbCamInitDefaultParameters(camera_hardware_t *camHal) +{ + ALOGD("%s: E", __func__); + int rc = 0; + char tempStr[FILENAME_LENGTH]; + + /* Default initializations */ + camHal->prevFormat = DEFAULT_USBCAM_PRVW_FMT; + camHal->prevWidth = DEFAULT_USBCAM_PRVW_WD; + camHal->prevHeight = DEFAULT_USBCAM_PRVW_HT; + camHal->dispFormat = camHal->prevFormat; + camHal->dispWidth = camHal->prevWidth; + camHal->dispHeight = camHal->prevHeight; + camHal->pictFormat = DEFAULT_USBCAM_PICT_FMT; + camHal->pictWidth = DEFAULT_USBCAM_PICT_WD; + camHal->pictHeight = DEFAULT_USBCAM_PICT_HT; + camHal->pictJpegQlty = DEFAULT_USBCAM_PICT_QLTY; + camHal->thumbnailWidth = DEFAULT_USBCAM_THUMBNAIL_WD; + camHal->thumbnailHeight = DEFAULT_USBCAM_THUMBNAIL_HT; + camHal->thumbnailJpegQlty = DEFAULT_USBCAM_THUMBNAIL_QLTY; + camHal->previewEnabledFlag = 0; + camHal->prvwStoppedForPicture = 0; + camHal->prvwCmdPending = 0; + camHal->takePictInProgress = 0; + + //Set picture size values + camHal->pictSizeValues = create_sizes_str( + picture_sizes, sizeof(picture_sizes) / sizeof(camera_size_type)); + camHal->qCamParams.set(QCameraParameters::KEY_SUPPORTED_PICTURE_SIZES, + camHal->pictSizeValues.string()); + camHal->qCamParams.setPictureSize(camHal->pictWidth, camHal->pictHeight); + + //Set picture format + camHal->pictFormatValues = create_values_str( + picture_formats, sizeof(picture_formats) / sizeof(str_map)); + camHal->qCamParams.set(QCameraParameters::KEY_SUPPORTED_PICTURE_FORMATS, + camHal->pictFormatValues.string()); + if(PICTURE_FORMAT_JPEG == camHal->pictFormat) + camHal->qCamParams.setPictureFormat(QCameraParameters::PIXEL_FORMAT_JPEG); + + //Set picture quality + sprintf(tempStr, "%d", camHal->pictJpegQlty); + camHal->qCamParams.set(QCameraParameters::KEY_JPEG_QUALITY, tempStr); + + //Set Thumbnail size + camHal->thumbnailSizeValues = create_sizes_str( + thumbnail_sizes, sizeof(thumbnail_sizes) /sizeof(camera_size_type)); + camHal->qCamParams.set(QCameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, + camHal->thumbnailSizeValues.string()); + sprintf(tempStr, "%d", camHal->thumbnailWidth); + camHal->qCamParams.set(QCameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, + tempStr); + sprintf(tempStr, "%d", camHal->thumbnailHeight); + camHal->qCamParams.set(QCameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, + tempStr); + + //Set Thumbnail quality + sprintf(tempStr, "%d", camHal->thumbnailJpegQlty); + camHal->qCamParams.set(QCameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, + tempStr); + + //Set Preview Format + camHal->prevFormatValues = create_values_str( + preview_formats, sizeof(preview_formats) / sizeof(str_map)); + camHal->qCamParams.set(QCameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, + camHal->prevFormatValues.string()); + if(HAL_PIXEL_FORMAT_YCrCb_420_SP == camHal->prevFormat) + camHal->qCamParams.setPreviewFormat(QCameraParameters::PIXEL_FORMAT_YUV420SP); + + //Set Preview size + camHal->prevSizeValues = create_sizes_str( + previewSizes, sizeof(previewSizes) / sizeof(camera_size_type)); + camHal->qCamParams.set(QCameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, + camHal->prevSizeValues.string()); + camHal->qCamParams.setPreviewSize(camHal->prevWidth, camHal->prevHeight); + + //Set Preivew fps range + camHal->prevFpsRangesValues = create_fps_str( + prevFpsRanges, sizeof(prevFpsRanges) / sizeof(android::FPSRange)); + + camHal->qCamParams.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, + camHal->prevFpsRangesValues); + camHal->qCamParams.setPreviewFpsRange(MIN_PREV_FPS, MAX_PREV_FPS); + + ALOGD("%s: X", __func__); + + return rc; +} /* usbCamInitDefaultParameters */ + +/****************************************************************************** + * Function: usbCamSetParameters + * Description: This function parses the parameter string and stores the + * parameters in the camera HAL handle + * + * Input parameters: + * camHal - camera HAL handle + * params - pointer to parameter string + * + * Return values: + * 0 Success + * -1 Error + * Notes: none + *****************************************************************************/ +int usbCamSetParameters(camera_hardware_t *camHal, const char *params) +{ + int rc = 0; + String8 str = String8(params); + QCameraParameters qParam; + + ALOGD("%s: E", __func__); + + if(params) + PRINT_PARAM_STR(params); + + qParam.unflatten(str); + + if(usbCamSetPrvwSize(camHal, qParam)) + rc = -1; + if(usbCamSetPictSize(camHal, qParam)) + rc = -1; + if(usbCamSetThumbnailSize(camHal, qParam)) + rc = -1; + if(usbCamSetJpegQlty(camHal, qParam)) + rc = -1; + + ALOGD("%s: X", __func__); + return rc; +} /* usbCamSetParameters */ + +/****************************************************************************** + * Function: usbCamGetParameters + * Description: This function allocates memory for parameter string, + * composes and returns the parameter string + * + * Input parameters: + * camHal - camera HAL handle + * + * Return values: + * Address to the parameter string + * + * Notes: none + *****************************************************************************/ +char* usbCamGetParameters(camera_hardware_t *camHal) +{ + ALOGD("%s: E", __func__); + char *parms = NULL; + char* rc = NULL; + String8 str; + + QCameraParameters qParam = camHal->qCamParams; + //qParam.dump(); + str = qParam.flatten( ); + rc = (char *)malloc(sizeof(char)*(str.length()+1)); + if(rc != NULL){ + memset(rc, 0, sizeof(char)*(str.length()+1)); + strncpy(rc, str.string(), str.length()); + rc[str.length()] = 0; + parms = rc; + } + + PRINT_PARAM_STR(parms); + + ALOGD("%s: X", __func__); + return (parms); +} /* usbCamGetParameters */ + +/****************************************************************************** + * Function: usbCamPutParameters + * Description: This function frees the memory allocated for parameter string + * + * Input parameters: + * camHal - camera HAL handle + * parms - Parameter string + * + * Return values: + * None + * + * Notes: none + *****************************************************************************/ +void usbCamPutParameters(camera_hardware_t *camHal, char *parms) +{ + ALOGD("%s: E", __func__); + if(parms) + free(parms); + parms = NULL; + ALOGD("%s: X", __func__); +} /* usbCamPutParameters */ + +/****************************************************************************** + * Function: create_sizes_str + * 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 String8 create_sizes_str(const camera_size_type *sizes, int len) { + String8 str; + char buffer[32]; + + if (len > 0) { + snprintf(buffer, sizeof(buffer), "%dx%d", sizes[0].width, sizes[0].height); + str.append(buffer); + } + for (int i = 1; i < len; i++) { + snprintf(buffer, sizeof(buffer), ",%dx%d", sizes[i].width, sizes[i].height); + str.append(buffer); + } + return str; +} + +/****************************************************************************** + * Function: create_values_str + * 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 String8 create_values_str(const str_map *values, int len) { + String8 str; + + if (len > 0) { + str.append(values[0].desc); + } + for (int i = 1; i < len; i++) { + str.append(","); + str.append(values[i].desc); + } + return str; +} + +/****************************************************************************** + * Function: create_fps_str + * 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 String8 create_fps_str(const android:: FPSRange* fps, int len) { + String8 str; + char buffer[32]; + + if (len > 0) { + snprintf(buffer, sizeof(buffer), "(%d,%d)", fps[0].minFPS, fps[0].maxFPS); + str.append(buffer); + } + for (int i = 1; i < len; i++) { + snprintf(buffer, sizeof(buffer), ",(%d,%d)", fps[i].minFPS, fps[i].maxFPS); + str.append(buffer); + } + return str; +} + +/****************************************************************************** + * Function: create_values_range_str + * 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 String8 create_values_range_str(int min, int max){ + String8 str; + char buffer[32]; + + if(min <= max){ + snprintf(buffer, sizeof(buffer), "%d", min); + str.append(buffer); + + for (int i = min + 1; i <= max; i++) { + snprintf(buffer, sizeof(buffer), ",%d", i); + str.append(buffer); + } + } + return str; +} + +/****************************************************************************** + * Function: usbCamSetPrvwSize + * Description: This function parses preview width and height from the input + * parameters and stores into the context + * + * Input parameters: + * camHal - camera HAL handle + * params - QCameraParameters reference + * + * Return values: + * 0 If parameters are valid + * -1 If parameters are invalid + * + * Notes: none + *****************************************************************************/ +static int usbCamSetPrvwSize( camera_hardware_t *camHal, + const QCameraParameters& params) +{ + int rc = 0, width, height, i, numPrvwSizes, validSize; + ALOGD("%s: E", __func__); + + params.getPreviewSize(&width, &height); + ALOGI("%s: Requested preview size %d x %d", __func__, width, height); + + // Validate the preview size + numPrvwSizes = sizeof(previewSizes) / sizeof(camera_size_type); + for (i = 0, validSize = 0; i < numPrvwSizes; i++) { + if (width == previewSizes[i].width + && height == previewSizes[i].height) { + validSize = 1; + + camHal->qCamParams.setPreviewSize(width, height); + ALOGD("%s: setPreviewSize: width: %d height: %d", + __func__, width, height); + + camHal->prevWidth = width; + camHal->prevHeight = height; + camHal->dispWidth = width; + camHal->dispHeight = height; + + /* TBD: restrict pictures size and video to preview size */ + } + } + if(!validSize) + ALOGE("%s: Invalid preview size %dx%d requested", __func__, + width, height); + + rc = (validSize == 0)? -1:0; + ALOGD("%s: X", __func__); + + return rc; +} /* usbCamSetPrvwSize */ + +/****************************************************************************** + * Function: usbCamSetPictSize + * Description: This function parses picture width and height from the input + * parameters and stores into the context + * + * Input parameters: + * camHal - camera HAL handle + * params - QCameraParameters reference + * + * Return values: + * 0 If parameters are valid + * -1 If parameters are invalid + * + * Notes: none + *****************************************************************************/ +static int usbCamSetPictSize( camera_hardware_t *camHal, + const QCameraParameters& params) +{ + int rc = 0, width, height, i, numPictSizes, validSize; + ALOGD("%s: E", __func__); + + /* parse for picture width and height */ + params.getPictureSize(&width, &height); + ALOGI("%s: Requested picture size %d x %d", __func__, width, height); + + // Validate the picture size + numPictSizes = sizeof(picture_sizes) / sizeof(camera_size_type); + for (i = 0, validSize = 0; i < numPictSizes; i++) { + if (width == picture_sizes[i].width + && height == picture_sizes[i].height) { + validSize = 1; + + camHal->qCamParams.setPictureSize(width, height); + ALOGD("%s: setPictureSize: width: %d height: %d", + __func__, width, height); + + /* TBD: If new pictSize is different from old size, restart prvw */ + camHal->pictWidth = width; + camHal->pictHeight = height; + } + } + if(!validSize) + ALOGE("%s: Invalid picture size %dx%d requested", __func__, + width, height); + rc = (validSize == 0)? -1:0; + ALOGD("%s: X", __func__); + + return rc; +} /* usbCamSetPictSize */ + +/****************************************************************************** + * Function: usbCamSetThumbnailSize + * Description: This function parses picture width and height from the input + * parameters and stores into the context + * + * Input parameters: + * camHal - camera HAL handle + * params - QCameraParameters reference + * + * Return values: + * 0 If parameters are valid + * -1 If parameters are invalid + * + * Notes: none + *****************************************************************************/ +static int usbCamSetThumbnailSize( camera_hardware_t *camHal, + const QCameraParameters& params) +{ + int rc = 0, width, height, i, numThumbnailSizes, validSize; + char tempStr[FILENAME_LENGTH]; + ALOGD("%s: E", __func__); + + /* parse for thumbnail width and height */ + width = params.getInt(QCameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); + height = params.getInt(QCameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); + ALOGI("%s: Requested thumbnail size %d x %d", __func__, width, height); + + // Validate the thumbnail size + numThumbnailSizes = sizeof(thumbnail_sizes) / sizeof(camera_size_type); + for (i = 0, validSize = 0; i < numThumbnailSizes; i++) { + if (width == thumbnail_sizes[i].width + && height == thumbnail_sizes[i].height) { + validSize = 1; + + camHal->thumbnailWidth = width; + camHal->thumbnailHeight = height; + sprintf(tempStr, "%d", camHal->thumbnailWidth); + camHal->qCamParams.set(QCameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, + width); + sprintf(tempStr, "%d", camHal->thumbnailHeight); + camHal->qCamParams.set(QCameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, + height); + + } + } + if(!validSize) + ALOGE("%s: Invalid picture size %dx%d requested", __func__, + width, height); + rc = (validSize == 0)? -1:0; + ALOGD("%s: X", __func__); + + return rc; +} /* usbCamSetThumbnailSize */ + +/****************************************************************************** + * Function: usbCamSetJpegQlty + * Description: This function parses picture and thumbnail JPEG quality and + * validates before storing in the context + * + * Input parameters: + * camHal - camera HAL handle + * params - QCameraParameters reference + * + * Return values: + * 0 If parameters are valid + * -1 If parameters are invalid + * + * Notes: none + *****************************************************************************/ +static int usbCamSetJpegQlty( camera_hardware_t *camHal, + const QCameraParameters& params) +{ + int rc = 0, quality = 0; + char tempStr[FILENAME_LENGTH]; + ALOGD("%s: E", __func__); + + /**/ + quality = params.getInt(QCameraParameters::KEY_JPEG_QUALITY); + ALOGI("%s: Requested picture qlty %d", __func__, quality); + + if (quality >= 0 && quality <= 100) { + camHal->pictJpegQlty = quality; + sprintf(tempStr, "%d", camHal->pictJpegQlty); + camHal->qCamParams.set(QCameraParameters::KEY_JPEG_QUALITY, quality); + } else { + ALOGE("Invalid jpeg quality=%d", quality); + rc = -1; + } + + quality = params.getInt(QCameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); + ALOGI("%s: Requested thumbnail qlty %d", __func__, quality); + + if (quality >= 0 && quality <= 100) { + camHal->thumbnailJpegQlty = quality; + sprintf(tempStr, "%d", camHal->thumbnailJpegQlty); + camHal->qCamParams.set(QCameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, + tempStr); + } else { + ALOGE("Invalid jpeg thumbnail quality=%d", quality); + rc = -1; + } + + ALOGD("%s: X rc:%d", __func__, rc); + + return rc; +} + +}; /*namespace android */ diff --git a/camera/usbcamcore/src/QualcommUsbCamera.cpp b/camera/usbcamcore/src/QualcommUsbCamera.cpp new file mode 100755 index 0000000..b274626 --- /dev/null +++ b/camera/usbcamcore/src/QualcommUsbCamera.cpp @@ -0,0 +1,2963 @@ +/* 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 |