| /* |
| ** Copyright 2008, Google Inc. |
| ** Copyright (c) 2009, Code Aurora Forum. All rights reserved. |
| ** |
| ** Licensed under the Apache License, Version 2.0 (the "License"); |
| ** you may not use this file except in compliance with the License. |
| ** You may obtain a copy of the License at |
| ** |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| */ |
| |
| //#define LOG_NDEBUG 0 |
| #define LOG_NIDEBUG 0 |
| #define LOG_TAG "QualcommCameraHardware" |
| #include <utils/Log.h> |
| |
| #include "QualcommCameraHardware.h" |
| |
| #include <utils/Errors.h> |
| #include <utils/threads.h> |
| #include <binder/MemoryHeapPmem.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 <ui/CameraParameters.h> |
| |
| #include "linux/msm_mdp.h" |
| #include <linux/fb.h> |
| |
| #define LIKELY(exp) __builtin_expect(!!(exp), 1) |
| #define UNLIKELY(exp) __builtin_expect(!!(exp), 0) |
| |
| 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 <media/msm_camera.h> |
| |
| #include <camera.h> |
| #include <camframe.h> |
| #include <mm-still/jpeg/jpege.h> |
| #include <jpeg_encoder.h> |
| |
| #define DEFAULT_PICTURE_WIDTH 1024 |
| #define DEFAULT_PICTURE_HEIGHT 768 |
| #define THUMBNAIL_BUFFER_SIZE (THUMBNAIL_WIDTH * THUMBNAIL_HEIGHT * 3/2) |
| #define MAX_ZOOM_LEVEL 5 |
| #define NOT_FOUND -1 |
| #define JPEG_ENCODER_PADDING 8 |
| // Number of video buffers held by kernal (initially 1,2 &3) |
| #define ACTIVE_VIDEO_BUFFERS 3 |
| |
| #if DLOPEN_LIBMMCAMERA |
| #include <dlfcn.h> |
| |
| void* (*LINK_cam_conf)(void *data); |
| void* (*LINK_cam_frame)(void *data); |
| bool (*LINK_jpeg_encoder_init)(); |
| void (*LINK_jpeg_encoder_join)(); |
| bool (*LINK_jpeg_encoder_encode)(const cam_ctrl_dimension_t *dimen, |
| const uint8_t *thumbnailbuf, int thumbnailfd, |
| const uint8_t *snapshotbuf, int snapshotfd, |
| common_crop_t *scaling_parms, exif_tags_info_t *exif_data, |
| int exif_table_numEntries); |
| void (*LINK_camframe_terminate)(void); |
| //for 720p |
| // Function to add a video buffer to free Q |
| void (*LINK_camframe_free_video)(struct msm_frame *frame); |
| // Function pointer , called by camframe when a video frame is available. |
| void (**LINK_camframe_video_callback)(struct msm_frame * frame); |
| // To flush free Q in cam frame. |
| void (*LINK_cam_frame_flush_free_video)(void); |
| |
| int8_t (*LINK_jpeg_encoder_setMainImageQuality)(uint32_t quality); |
| int8_t (*LINK_jpeg_encoder_setThumbnailQuality)(uint32_t quality); |
| int8_t (*LINK_jpeg_encoder_setRotation)(uint32_t rotation); |
| int8_t (*LINK_jpeg_encoder_setLocation)(const camera_position_type *location); |
| const struct camera_size_type *(*LINK_default_sensor_get_snapshot_sizes)(int *len); |
| int (*LINK_launch_cam_conf_thread)(void); |
| int (*LINK_release_cam_conf_thread)(void); |
| int8_t (*LINK_zoom_crop_upscale)(uint32_t width, uint32_t height, |
| uint32_t cropped_width, uint32_t cropped_height, uint8_t *img_buf); |
| |
| // callbacks |
| void (**LINK_mmcamera_camframe_callback)(struct msm_frame *frame); |
| void (**LINK_mmcamera_jpegfragment_callback)(uint8_t *buff_ptr, |
| uint32_t buff_size); |
| void (**LINK_mmcamera_jpeg_callback)(jpeg_event_t status); |
| void (**LINK_mmcamera_shutter_callback)(common_crop_t *crop); |
| void (**LINK_camframe_timeout_callback)(void); |
| #else |
| #define LINK_cam_conf cam_conf |
| #define LINK_cam_frame cam_frame |
| #define LINK_jpeg_encoder_init jpeg_encoder_init |
| #define LINK_jpeg_encoder_join jpeg_encoder_join |
| #define LINK_jpeg_encoder_encode jpeg_encoder_encode |
| #define LINK_camframe_terminate camframe_terminate |
| #define LINK_jpeg_encoder_setMainImageQuality jpeg_encoder_setMainImageQuality |
| #define LINK_jpeg_encoder_setThumbnailQuality jpeg_encoder_setThumbnailQuality |
| #define LINK_jpeg_encoder_setRotation jpeg_encoder_setRotation |
| #define LINK_jpeg_encoder_setLocation jpeg_encoder_setLocation |
| #define LINK_default_sensor_get_snapshot_sizes default_sensor_get_snapshot_sizes |
| #define LINK_launch_cam_conf_thread launch_cam_conf_thread |
| #define LINK_release_cam_conf_thread release_cam_conf_thread |
| #define LINK_zoom_crop_upscale zoom_crop_upscale |
| extern void (*mmcamera_camframe_callback)(struct msm_frame *frame); |
| extern void (*mmcamera_jpegfragment_callback)(uint8_t *buff_ptr, |
| uint32_t buff_size); |
| extern void (*mmcamera_jpeg_callback)(jpeg_event_t status); |
| extern void (*mmcamera_shutter_callback)(common_crop_t *crop); |
| #endif |
| |
| } // extern "C" |
| |
| #ifndef HAVE_CAMERA_SIZE_TYPE |
| struct camera_size_type { |
| int width; |
| int height; |
| }; |
| #endif |
| |
| typedef struct crop_info_struct { |
| uint32_t x; |
| uint32_t y; |
| uint32_t w; |
| uint32_t h; |
| } zoom_crop_info; |
| |
| union zoomimage |
| { |
| char d[sizeof(struct mdp_blit_req_list) + sizeof(struct mdp_blit_req) * 1]; |
| struct mdp_blit_req_list list; |
| } zoomImage; |
| |
| //Default to WVGA |
| #define DEFAULT_PREVIEW_WIDTH 800 |
| #define DEFAULT_PREVIEW_HEIGHT 480 |
| |
| /* |
| * Modifying preview size requires modification |
| * in bitmasks for boardproperties |
| */ |
| |
| static const camera_size_type preview_sizes[] = { |
| { 1280, 720 }, // 720P, reserved |
| { 800, 480 }, // WVGA |
| { 768, 432 }, |
| { 720, 480 }, |
| { 640, 480 }, // VGA |
| { 576, 432 }, |
| { 480, 320 }, // HVGA |
| { 384, 288 }, |
| { 352, 288 }, // CIF |
| { 320, 240 }, // QVGA |
| { 240, 160 }, // SQVGA |
| { 176, 144 }, // QCIF |
| }; |
| #define PREVIEW_SIZE_COUNT (sizeof(preview_sizes)/sizeof(camera_size_type)) |
| |
| static camera_size_type supportedPreviewSizes[PREVIEW_SIZE_COUNT]; |
| static unsigned int previewSizeCount; |
| |
| board_property boardProperties[] = { |
| {TARGET_MSM7625, 0x00000fff}, |
| {TARGET_MSM7627, 0x000006ff}, |
| {TARGET_MSM7630, 0x00000fff}, |
| {TARGET_QSD8250, 0x00000fff} |
| }; |
| |
| //static const camera_size_type* picture_sizes; |
| //static int PICTURE_SIZE_COUNT; |
| /* TODO |
| * Ideally this should be a populated by lower layers. |
| * But currently this is no API to do that at lower layer. |
| * Hence populating with default sizes for now. This needs |
| * to be changed once the API is supported. |
| */ |
| //sorted on column basis |
| static const camera_size_type picture_sizes[] = { |
| { 2592, 1944 }, // 5MP |
| { 2048, 1536 }, // 3MP QXGA |
| { 1920, 1080 }, //HD1080 |
| { 1600, 1200 }, // 2MP UXGA |
| { 1280, 768 }, //WXGA |
| { 1280, 720 }, //HD720 |
| { 1024, 768}, // 1MP XGA |
| { 800, 600 }, //SVGA |
| { 800, 480 }, // WVGA |
| { 640, 480 }, // VGA |
| { 352, 288 }, //CIF |
| { 320, 240 }, // QVGA |
| { 176, 144 } // QCIF |
| }; |
| static int PICTURE_SIZE_COUNT = sizeof(picture_sizes)/sizeof(camera_size_type); |
| static const camera_size_type * picture_sizes_ptr; |
| static int supportedPictureSizesCount; |
| |
| #ifdef Q12 |
| #undef Q12 |
| #endif |
| |
| #define Q12 4096 |
| |
| static const target_map targetList [] = { |
| { "msm7625", TARGET_MSM7625 }, |
| { "msm7627", TARGET_MSM7627 }, |
| { "qsd8250", TARGET_QSD8250 }, |
| { "msm7630", TARGET_MSM7630 } |
| }; |
| static targetType mCurrentTarget = TARGET_MAX; |
| |
| typedef struct { |
| uint32_t aspect_ratio; |
| uint32_t width; |
| uint32_t height; |
| } thumbnail_size_type; |
| |
| static thumbnail_size_type thumbnail_sizes[] = { |
| { 7281, 512, 288 }, //1.777778 |
| { 6826, 480, 288 }, //1.666667 |
| { 6144, 432, 288 }, //1.5 |
| { 5461, 512, 384 }, //1.333333 |
| { 5006, 352, 288 }, //1.222222 |
| }; |
| #define THUMBNAIL_SIZE_COUNT (sizeof(thumbnail_sizes)/sizeof(thumbnail_size_type)) |
| #define DEFAULT_THUMBNAIL_SETTING 2 |
| #define THUMBNAIL_WIDTH_STR "512" |
| #define THUMBNAIL_HEIGHT_STR "384" |
| #define THUMBNAIL_SMALL_HEIGHT 144 |
| |
| static int attr_lookup(const str_map arr[], int len, const char *name) |
| { |
| if (name) { |
| for (int i = 0; i < len; i++) { |
| if (!strcmp(arr[i].desc, name)) |
| return arr[i].val; |
| } |
| } |
| return NOT_FOUND; |
| } |
| |
| // round to the next power of two |
| static inline unsigned clp2(unsigned x) |
| { |
| x = x - 1; |
| x = x | (x >> 1); |
| x = x | (x >> 2); |
| x = x | (x >> 4); |
| x = x | (x >> 8); |
| x = x | (x >>16); |
| return x + 1; |
| } |
| |
| static int exif_table_numEntries = 0; |
| #define MAX_EXIF_TABLE_ENTRIES 7 |
| exif_tags_info_t exif_data[MAX_EXIF_TABLE_ENTRIES]; |
| static zoom_crop_info zoomCropInfo; |
| static void *mLastQueuedFrame = NULL; |
| |
| namespace android { |
| |
| static const int PICTURE_FORMAT_JPEG = 1; |
| static const int PICTURE_FORMAT_RAW = 2; |
| |
| // from aeecamera.h |
| static const str_map whitebalance[] = { |
| { CameraParameters::WHITE_BALANCE_AUTO, CAMERA_WB_AUTO }, |
| { CameraParameters::WHITE_BALANCE_INCANDESCENT, CAMERA_WB_INCANDESCENT }, |
| { CameraParameters::WHITE_BALANCE_FLUORESCENT, CAMERA_WB_FLUORESCENT }, |
| { CameraParameters::WHITE_BALANCE_DAYLIGHT, CAMERA_WB_DAYLIGHT }, |
| { CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT, CAMERA_WB_CLOUDY_DAYLIGHT } |
| }; |
| |
| // from camera_effect_t. This list must match aeecamera.h |
| static const str_map effects[] = { |
| { CameraParameters::EFFECT_NONE, CAMERA_EFFECT_OFF }, |
| { CameraParameters::EFFECT_MONO, CAMERA_EFFECT_MONO }, |
| { CameraParameters::EFFECT_NEGATIVE, CAMERA_EFFECT_NEGATIVE }, |
| { CameraParameters::EFFECT_SOLARIZE, CAMERA_EFFECT_SOLARIZE }, |
| { CameraParameters::EFFECT_SEPIA, CAMERA_EFFECT_SEPIA }, |
| { CameraParameters::EFFECT_POSTERIZE, CAMERA_EFFECT_POSTERIZE }, |
| { CameraParameters::EFFECT_WHITEBOARD, CAMERA_EFFECT_WHITEBOARD }, |
| { CameraParameters::EFFECT_BLACKBOARD, CAMERA_EFFECT_BLACKBOARD }, |
| { CameraParameters::EFFECT_AQUA, CAMERA_EFFECT_AQUA } |
| }; |
| |
| // from qcamera/common/camera.h |
| static const str_map autoexposure[] = { |
| { CameraParameters::AUTO_EXPOSURE_FRAME_AVG, CAMERA_AEC_FRAME_AVERAGE }, |
| { CameraParameters::AUTO_EXPOSURE_CENTER_WEIGHTED, CAMERA_AEC_CENTER_WEIGHTED }, |
| { CameraParameters::AUTO_EXPOSURE_SPOT_METERING, CAMERA_AEC_SPOT_METERING } |
| }; |
| |
| // from qcamera/common/camera.h |
| static const str_map antibanding[] = { |
| { CameraParameters::ANTIBANDING_OFF, CAMERA_ANTIBANDING_OFF }, |
| { CameraParameters::ANTIBANDING_50HZ, CAMERA_ANTIBANDING_50HZ }, |
| { CameraParameters::ANTIBANDING_60HZ, CAMERA_ANTIBANDING_60HZ }, |
| { CameraParameters::ANTIBANDING_AUTO, CAMERA_ANTIBANDING_AUTO } |
| }; |
| |
| /* Mapping from MCC to antibanding type */ |
| struct country_map { |
| uint32_t country_code; |
| camera_antibanding_type type; |
| }; |
| |
| static struct country_map country_numeric[] = { |
| { 202, CAMERA_ANTIBANDING_50HZ }, // Greece |
| { 204, CAMERA_ANTIBANDING_50HZ }, // Netherlands |
| { 206, CAMERA_ANTIBANDING_50HZ }, // Belgium |
| { 208, CAMERA_ANTIBANDING_50HZ }, // France |
| { 212, CAMERA_ANTIBANDING_50HZ }, // Monaco |
| { 213, CAMERA_ANTIBANDING_50HZ }, // Andorra |
| { 214, CAMERA_ANTIBANDING_50HZ }, // Spain |
| { 216, CAMERA_ANTIBANDING_50HZ }, // Hungary |
| { 219, CAMERA_ANTIBANDING_50HZ }, // Croatia |
| { 220, CAMERA_ANTIBANDING_50HZ }, // Serbia |
| { 222, CAMERA_ANTIBANDING_50HZ }, // Italy |
| { 226, CAMERA_ANTIBANDING_50HZ }, // Romania |
| { 228, CAMERA_ANTIBANDING_50HZ }, // Switzerland |
| { 230, CAMERA_ANTIBANDING_50HZ }, // Czech Republic |
| { 231, CAMERA_ANTIBANDING_50HZ }, // Slovakia |
| { 232, CAMERA_ANTIBANDING_50HZ }, // Austria |
| { 234, CAMERA_ANTIBANDING_50HZ }, // United Kingdom |
| { 235, CAMERA_ANTIBANDING_50HZ }, // United Kingdom |
| { 238, CAMERA_ANTIBANDING_50HZ }, // Denmark |
| { 240, CAMERA_ANTIBANDING_50HZ }, // Sweden |
| { 242, CAMERA_ANTIBANDING_50HZ }, // Norway |
| { 244, CAMERA_ANTIBANDING_50HZ }, // Finland |
| { 246, CAMERA_ANTIBANDING_50HZ }, // Lithuania |
| { 247, CAMERA_ANTIBANDING_50HZ }, // Latvia |
| { 248, CAMERA_ANTIBANDING_50HZ }, // Estonia |
| { 250, CAMERA_ANTIBANDING_50HZ }, // Russian Federation |
| { 255, CAMERA_ANTIBANDING_50HZ }, // Ukraine |
| { 257, CAMERA_ANTIBANDING_50HZ }, // Belarus |
| { 259, CAMERA_ANTIBANDING_50HZ }, // Moldova |
| { 260, CAMERA_ANTIBANDING_50HZ }, // Poland |
| { 262, CAMERA_ANTIBANDING_50HZ }, // Germany |
| { 266, CAMERA_ANTIBANDING_50HZ }, // Gibraltar |
| { 268, CAMERA_ANTIBANDING_50HZ }, // Portugal |
| { 270, CAMERA_ANTIBANDING_50HZ }, // Luxembourg |
| { 272, CAMERA_ANTIBANDING_50HZ }, // Ireland |
| { 274, CAMERA_ANTIBANDING_50HZ }, // Iceland |
| { 276, CAMERA_ANTIBANDING_50HZ }, // Albania |
| { 278, CAMERA_ANTIBANDING_50HZ }, // Malta |
| { 280, CAMERA_ANTIBANDING_50HZ }, // Cyprus |
| { 282, CAMERA_ANTIBANDING_50HZ }, // Georgia |
| { 283, CAMERA_ANTIBANDING_50HZ }, // Armenia |
| { 284, CAMERA_ANTIBANDING_50HZ }, // Bulgaria |
| { 286, CAMERA_ANTIBANDING_50HZ }, // Turkey |
| { 288, CAMERA_ANTIBANDING_50HZ }, // Faroe Islands |
| { 290, CAMERA_ANTIBANDING_50HZ }, // Greenland |
| { 293, CAMERA_ANTIBANDING_50HZ }, // Slovenia |
| { 294, CAMERA_ANTIBANDING_50HZ }, // Macedonia |
| { 295, CAMERA_ANTIBANDING_50HZ }, // Liechtenstein |
| { 297, CAMERA_ANTIBANDING_50HZ }, // Montenegro |
| { 302, CAMERA_ANTIBANDING_60HZ }, // Canada |
| { 310, CAMERA_ANTIBANDING_60HZ }, // United States of America |
| { 311, CAMERA_ANTIBANDING_60HZ }, // United States of America |
| { 312, CAMERA_ANTIBANDING_60HZ }, // United States of America |
| { 313, CAMERA_ANTIBANDING_60HZ }, // United States of America |
| { 314, CAMERA_ANTIBANDING_60HZ }, // United States of America |
| { 315, CAMERA_ANTIBANDING_60HZ }, // United States of America |
| { 316, CAMERA_ANTIBANDING_60HZ }, // United States of America |
| { 330, CAMERA_ANTIBANDING_60HZ }, // Puerto Rico |
| { 334, CAMERA_ANTIBANDING_60HZ }, // Mexico |
| { 338, CAMERA_ANTIBANDING_50HZ }, // Jamaica |
| { 340, CAMERA_ANTIBANDING_50HZ }, // Martinique |
| { 342, CAMERA_ANTIBANDING_50HZ }, // Barbados |
| { 346, CAMERA_ANTIBANDING_60HZ }, // Cayman Islands |
| { 350, CAMERA_ANTIBANDING_60HZ }, // Bermuda |
| { 352, CAMERA_ANTIBANDING_50HZ }, // Grenada |
| { 354, CAMERA_ANTIBANDING_60HZ }, // Montserrat |
| { 362, CAMERA_ANTIBANDING_50HZ }, // Netherlands Antilles |
| { 363, CAMERA_ANTIBANDING_60HZ }, // Aruba |
| { 364, CAMERA_ANTIBANDING_60HZ }, // Bahamas |
| { 365, CAMERA_ANTIBANDING_60HZ }, // Anguilla |
| { 366, CAMERA_ANTIBANDING_50HZ }, // Dominica |
| { 368, CAMERA_ANTIBANDING_60HZ }, // Cuba |
| { 370, CAMERA_ANTIBANDING_60HZ }, // Dominican Republic |
| { 372, CAMERA_ANTIBANDING_60HZ }, // Haiti |
| { 401, CAMERA_ANTIBANDING_50HZ }, // Kazakhstan |
| { 402, CAMERA_ANTIBANDING_50HZ }, // Bhutan |
| { 404, CAMERA_ANTIBANDING_50HZ }, // India |
| { 405, CAMERA_ANTIBANDING_50HZ }, // India |
| { 410, CAMERA_ANTIBANDING_50HZ }, // Pakistan |
| { 413, CAMERA_ANTIBANDING_50HZ }, // Sri Lanka |
| { 414, CAMERA_ANTIBANDING_50HZ }, // Myanmar |
| { 415, CAMERA_ANTIBANDING_50HZ }, // Lebanon |
| { 416, CAMERA_ANTIBANDING_50HZ }, // Jordan |
| { 417, CAMERA_ANTIBANDING_50HZ }, // Syria |
| { 418, CAMERA_ANTIBANDING_50HZ }, // Iraq |
| { 419, CAMERA_ANTIBANDING_50HZ }, // Kuwait |
| { 420, CAMERA_ANTIBANDING_60HZ }, // Saudi Arabia |
| { 421, CAMERA_ANTIBANDING_50HZ }, // Yemen |
| { 422, CAMERA_ANTIBANDING_50HZ }, // Oman |
| { 424, CAMERA_ANTIBANDING_50HZ }, // United Arab Emirates |
| { 425, CAMERA_ANTIBANDING_50HZ }, // Israel |
| { 426, CAMERA_ANTIBANDING_50HZ }, // Bahrain |
| { 427, CAMERA_ANTIBANDING_50HZ }, // Qatar |
| { 428, CAMERA_ANTIBANDING_50HZ }, // Mongolia |
| { 429, CAMERA_ANTIBANDING_50HZ }, // Nepal |
| { 430, CAMERA_ANTIBANDING_50HZ }, // United Arab Emirates |
| { 431, CAMERA_ANTIBANDING_50HZ }, // United Arab Emirates |
| { 432, CAMERA_ANTIBANDING_50HZ }, // Iran |
| { 434, CAMERA_ANTIBANDING_50HZ }, // Uzbekistan |
| { 436, CAMERA_ANTIBANDING_50HZ }, // Tajikistan |
| { 437, CAMERA_ANTIBANDING_50HZ }, // Kyrgyz Rep |
| { 438, CAMERA_ANTIBANDING_50HZ }, // Turkmenistan |
| { 440, CAMERA_ANTIBANDING_60HZ }, // Japan |
| { 441, CAMERA_ANTIBANDING_60HZ }, // Japan |
| { 452, CAMERA_ANTIBANDING_50HZ }, // Vietnam |
| { 454, CAMERA_ANTIBANDING_50HZ }, // Hong Kong |
| { 455, CAMERA_ANTIBANDING_50HZ }, // Macao |
| { 456, CAMERA_ANTIBANDING_50HZ }, // Cambodia |
| { 457, CAMERA_ANTIBANDING_50HZ }, // Laos |
| { 460, CAMERA_ANTIBANDING_50HZ }, // China |
| { 466, CAMERA_ANTIBANDING_60HZ }, // Taiwan |
| { 470, CAMERA_ANTIBANDING_50HZ }, // Bangladesh |
| { 472, CAMERA_ANTIBANDING_50HZ }, // Maldives |
| { 502, CAMERA_ANTIBANDING_50HZ }, // Malaysia |
| { 505, CAMERA_ANTIBANDING_50HZ }, // Australia |
| { 510, CAMERA_ANTIBANDING_50HZ }, // Indonesia |
| { 514, CAMERA_ANTIBANDING_50HZ }, // East Timor |
| { 515, CAMERA_ANTIBANDING_60HZ }, // Philippines |
| { 520, CAMERA_ANTIBANDING_50HZ }, // Thailand |
| { 525, CAMERA_ANTIBANDING_50HZ }, // Singapore |
| { 530, CAMERA_ANTIBANDING_50HZ }, // New Zealand |
| { 535, CAMERA_ANTIBANDING_60HZ }, // Guam |
| { 536, CAMERA_ANTIBANDING_50HZ }, // Nauru |
| { 537, CAMERA_ANTIBANDING_50HZ }, // Papua New Guinea |
| { 539, CAMERA_ANTIBANDING_50HZ }, // Tonga |
| { 541, CAMERA_ANTIBANDING_50HZ }, // Vanuatu |
| { 542, CAMERA_ANTIBANDING_50HZ }, // Fiji |
| { 544, CAMERA_ANTIBANDING_60HZ }, // American Samoa |
| { 545, CAMERA_ANTIBANDING_50HZ }, // Kiribati |
| { 546, CAMERA_ANTIBANDING_50HZ }, // New Caledonia |
| { 548, CAMERA_ANTIBANDING_50HZ }, // Cook Islands |
| { 602, CAMERA_ANTIBANDING_50HZ }, // Egypt |
| { 603, CAMERA_ANTIBANDING_50HZ }, // Algeria |
| { 604, CAMERA_ANTIBANDING_50HZ }, // Morocco |
| { 605, CAMERA_ANTIBANDING_50HZ }, // Tunisia |
| { 606, CAMERA_ANTIBANDING_50HZ }, // Libya |
| { 607, CAMERA_ANTIBANDING_50HZ }, // Gambia |
| { 608, CAMERA_ANTIBANDING_50HZ }, // Senegal |
| { 609, CAMERA_ANTIBANDING_50HZ }, // Mauritania |
| { 610, CAMERA_ANTIBANDING_50HZ }, // Mali |
| { 611, CAMERA_ANTIBANDING_50HZ }, // Guinea |
| { 613, CAMERA_ANTIBANDING_50HZ }, // Burkina Faso |
| { 614, CAMERA_ANTIBANDING_50HZ }, // Niger |
| { 616, CAMERA_ANTIBANDING_50HZ }, // Benin |
| { 617, CAMERA_ANTIBANDING_50HZ }, // Mauritius |
| { 618, CAMERA_ANTIBANDING_50HZ }, // Liberia |
| { 619, CAMERA_ANTIBANDING_50HZ }, // Sierra Leone |
| { 620, CAMERA_ANTIBANDING_50HZ }, // Ghana |
| { 621, CAMERA_ANTIBANDING_50HZ }, // Nigeria |
| { 622, CAMERA_ANTIBANDING_50HZ }, // Chad |
| { 623, CAMERA_ANTIBANDING_50HZ }, // Central African Republic |
| { 624, CAMERA_ANTIBANDING_50HZ }, // Cameroon |
| { 625, CAMERA_ANTIBANDING_50HZ }, // Cape Verde |
| { 627, CAMERA_ANTIBANDING_50HZ }, // Equatorial Guinea |
| { 631, CAMERA_ANTIBANDING_50HZ }, // Angola |
| { 633, CAMERA_ANTIBANDING_50HZ }, // Seychelles |
| { 634, CAMERA_ANTIBANDING_50HZ }, // Sudan |
| { 636, CAMERA_ANTIBANDING_50HZ }, // Ethiopia |
| { 637, CAMERA_ANTIBANDING_50HZ }, // Somalia |
| { 638, CAMERA_ANTIBANDING_50HZ }, // Djibouti |
| { 639, CAMERA_ANTIBANDING_50HZ }, // Kenya |
| { 640, CAMERA_ANTIBANDING_50HZ }, // Tanzania |
| { 641, CAMERA_ANTIBANDING_50HZ }, // Uganda |
| { 642, CAMERA_ANTIBANDING_50HZ }, // Burundi |
| { 643, CAMERA_ANTIBANDING_50HZ }, // Mozambique |
| { 645, CAMERA_ANTIBANDING_50HZ }, // Zambia |
| { 646, CAMERA_ANTIBANDING_50HZ }, // Madagascar |
| { 647, CAMERA_ANTIBANDING_50HZ }, // France |
| { 648, CAMERA_ANTIBANDING_50HZ }, // Zimbabwe |
| { 649, CAMERA_ANTIBANDING_50HZ }, // Namibia |
| { 650, CAMERA_ANTIBANDING_50HZ }, // Malawi |
| { 651, CAMERA_ANTIBANDING_50HZ }, // Lesotho |
| { 652, CAMERA_ANTIBANDING_50HZ }, // Botswana |
| { 653, CAMERA_ANTIBANDING_50HZ }, // Swaziland |
| { 654, CAMERA_ANTIBANDING_50HZ }, // Comoros |
| { 655, CAMERA_ANTIBANDING_50HZ }, // South Africa |
| { 657, CAMERA_ANTIBANDING_50HZ }, // Eritrea |
| { 702, CAMERA_ANTIBANDING_60HZ }, // Belize |
| { 704, CAMERA_ANTIBANDING_60HZ }, // Guatemala |
| { 706, CAMERA_ANTIBANDING_60HZ }, // El Salvador |
| { 708, CAMERA_ANTIBANDING_60HZ }, // Honduras |
| { 710, CAMERA_ANTIBANDING_60HZ }, // Nicaragua |
| { 712, CAMERA_ANTIBANDING_60HZ }, // Costa Rica |
| { 714, CAMERA_ANTIBANDING_60HZ }, // Panama |
| { 722, CAMERA_ANTIBANDING_50HZ }, // Argentina |
| { 724, CAMERA_ANTIBANDING_60HZ }, // Brazil |
| { 730, CAMERA_ANTIBANDING_50HZ }, // Chile |
| { 732, CAMERA_ANTIBANDING_60HZ }, // Colombia |
| { 734, CAMERA_ANTIBANDING_60HZ }, // Venezuela |
| { 736, CAMERA_ANTIBANDING_50HZ }, // Bolivia |
| { 738, CAMERA_ANTIBANDING_60HZ }, // Guyana |
| { 740, CAMERA_ANTIBANDING_60HZ }, // Ecuador |
| { 742, CAMERA_ANTIBANDING_50HZ }, // French Guiana |
| { 744, CAMERA_ANTIBANDING_50HZ }, // Paraguay |
| { 746, CAMERA_ANTIBANDING_60HZ }, // Suriname |
| { 748, CAMERA_ANTIBANDING_50HZ }, // Uruguay |
| { 750, CAMERA_ANTIBANDING_50HZ }, // Falkland Islands |
| }; |
| |
| #define country_number (sizeof(country_numeric) / sizeof(country_map)) |
| |
| /* Look up pre-sorted antibanding_type table by current MCC. */ |
| static camera_antibanding_type camera_get_location(void) { |
| char value[PROP_VALUE_MAX]; |
| char country_value[PROP_VALUE_MAX]; |
| uint32_t country_code, count; |
| memset(value, 0x00, sizeof(value)); |
| memset(country_value, 0x00, sizeof(country_value)); |
| if (!__system_property_get("gsm.operator.numeric", value)) { |
| return CAMERA_ANTIBANDING_60HZ; |
| } |
| memcpy(country_value, value, 3); |
| country_code = atoi(country_value); |
| LOGD("value:%s, country value:%s, country code:%d\n", |
| value, country_value, country_code); |
| int left = 0; |
| int right = country_number - 1; |
| while (left <= right) { |
| int index = (left + right) >> 1; |
| if (country_numeric[index].country_code == country_code) |
| return country_numeric[index].type; |
| else if (country_numeric[index].country_code > country_code) |
| right = index - 1; |
| else |
| left = index + 1; |
| } |
| return CAMERA_ANTIBANDING_60HZ; |
| } |
| |
| // from camera.h, led_mode_t |
| static const str_map flash[] = { |
| { CameraParameters::FLASH_MODE_OFF, LED_MODE_OFF }, |
| { CameraParameters::FLASH_MODE_AUTO, LED_MODE_AUTO }, |
| { CameraParameters::FLASH_MODE_ON, LED_MODE_ON } |
| }; |
| |
| // from mm-camera/common/camera.h. |
| static const str_map iso[] = { |
| { CameraParameters::ISO_AUTO, CAMERA_ISO_AUTO}, |
| { CameraParameters::ISO_HJR, CAMERA_ISO_DEBLUR}, |
| { CameraParameters::ISO_100, CAMERA_ISO_100}, |
| { CameraParameters::ISO_200, CAMERA_ISO_200}, |
| { CameraParameters::ISO_400, CAMERA_ISO_400}, |
| { CameraParameters::ISO_800, CAMERA_ISO_800 } |
| }; |
| |
| |
| #define DONT_CARE 0 |
| static const str_map focus_modes[] = { |
| { CameraParameters::FOCUS_MODE_AUTO, AF_MODE_AUTO}, |
| { CameraParameters::FOCUS_MODE_INFINITY, DONT_CARE }, |
| { CameraParameters::FOCUS_MODE_NORMAL, AF_MODE_NORMAL }, |
| { CameraParameters::FOCUS_MODE_MACRO, AF_MODE_MACRO } |
| }; |
| |
| static const str_map lensshade[] = { |
| { CameraParameters::LENSSHADE_ENABLE, TRUE }, |
| { CameraParameters::LENSSHADE_DISABLE, FALSE } |
| }; |
| |
| struct SensorType { |
| const char *name; |
| int rawPictureWidth; |
| int rawPictureHeight; |
| bool hasAutoFocusSupport; |
| int max_supported_snapshot_width; |
| int max_supported_snapshot_height; |
| }; |
| |
| static SensorType sensorTypes[] = { |
| { "5mp", 2608, 1960, true, 2592, 1944 }, |
| { "3mp", 2064, 1544, false, 2048, 1536 }, |
| { "2mp", 3200, 1200, false, 1600, 1200 } }; |
| |
| |
| static SensorType * sensorType; |
| |
| static const str_map picture_formats[] = { |
| {CameraParameters::PIXEL_FORMAT_JPEG, PICTURE_FORMAT_JPEG}, |
| {CameraParameters::PIXEL_FORMAT_RAW, PICTURE_FORMAT_RAW} |
| }; |
| |
| static bool parameter_string_initialized = false; |
| static String8 preview_size_values; |
| static String8 picture_size_values; |
| static String8 antibanding_values; |
| static String8 effect_values; |
| static String8 autoexposure_values; |
| static String8 whitebalance_values; |
| static String8 flash_values; |
| static String8 focus_mode_values; |
| static String8 iso_values; |
| static String8 lensshade_values; |
| static String8 picture_format_values; |
| |
| |
| static String8 create_sizes_str(const camera_size_type *sizes, int len) { |
| String8 str; |
| char buffer[32]; |
| |
| if (len > 0) { |
| sprintf(buffer, "%dx%d", sizes[0].width, sizes[0].height); |
| str.append(buffer); |
| } |
| for (int i = 1; i < len; i++) { |
| sprintf(buffer, ",%dx%d", sizes[i].width, sizes[i].height); |
| str.append(buffer); |
| } |
| return str; |
| } |
| |
| 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; |
| } |
| |
| extern "C" { |
| //------------------------------------------------------------------------ |
| // : 720p busyQ funcitons |
| // -------------------------------------------------------------------- |
| static struct fifo_queue g_busy_frame_queue = |
| {0, 0, 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER}; |
| }; |
| /*=========================================================================== |
| * FUNCTION cam_frame_wait_video |
| * |
| * DESCRIPTION this function waits a video in the busy queue |
| * ===========================================================================*/ |
| |
| static void cam_frame_wait_video (void) |
| { |
| LOGV("cam_frame_wait_video E "); |
| if ((g_busy_frame_queue.num_of_frames) <=0){ |
| pthread_cond_wait(&(g_busy_frame_queue.wait), &(g_busy_frame_queue.mut)); |
| } |
| LOGV("cam_frame_wait_video X"); |
| return; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION cam_frame_flush_video |
| * |
| * DESCRIPTION this function deletes all the buffers in busy queue |
| * ===========================================================================*/ |
| void cam_frame_flush_video (void) |
| { |
| LOGV("cam_frame_flush_video: in n = %d\n", g_busy_frame_queue.num_of_frames); |
| pthread_mutex_lock(&(g_busy_frame_queue.mut)); |
| |
| while (g_busy_frame_queue.front) |
| { |
| //dequeue from the busy queue |
| struct fifo_node *node = dequeue (&g_busy_frame_queue); |
| if(node) |
| free(node); |
| |
| LOGV("cam_frame_flush_video: node \n"); |
| } |
| pthread_mutex_unlock(&(g_busy_frame_queue.mut)); |
| LOGV("cam_frame_flush_video: out n = %d\n", g_busy_frame_queue.num_of_frames); |
| return ; |
| } |
| /*=========================================================================== |
| * FUNCTION cam_frame_get_video |
| * |
| * DESCRIPTION this function returns a video frame from the head |
| * ===========================================================================*/ |
| static struct msm_frame * cam_frame_get_video() |
| { |
| struct msm_frame *p = NULL; |
| LOGV("cam_frame_get_video... in\n"); |
| LOGV("cam_frame_get_video... got lock\n"); |
| if (g_busy_frame_queue.front) |
| { |
| //dequeue |
| struct fifo_node *node = dequeue (&g_busy_frame_queue); |
| if (node) |
| { |
| p = (struct msm_frame *)node->f; |
| free (node); |
| } |
| LOGV("cam_frame_get_video... out = %x\n", p->buffer); |
| } |
| return p; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION cam_frame_post_video |
| * |
| * DESCRIPTION this function add a busy video frame to the busy queue tails |
| * ===========================================================================*/ |
| static void cam_frame_post_video (struct msm_frame *p) |
| { |
| if (!p) |
| { |
| LOGE("post video , buffer is null"); |
| return; |
| } |
| LOGV("cam_frame_post_video... in = %x\n", (unsigned int)(p->buffer)); |
| pthread_mutex_lock(&(g_busy_frame_queue.mut)); |
| LOGV("post_video got lock. q count before enQ %d", g_busy_frame_queue.num_of_frames); |
| //enqueue to busy queue |
| struct fifo_node *node = (struct fifo_node *)malloc (sizeof (struct fifo_node)); |
| if (node) |
| { |
| LOGV(" post video , enqueing in busy queue"); |
| node->f = p; |
| node->next = NULL; |
| enqueue (&g_busy_frame_queue, node); |
| LOGV("post_video got lock. q count after enQ %d", g_busy_frame_queue.num_of_frames); |
| } |
| else |
| { |
| LOGE("cam_frame_post_video error... out of memory\n"); |
| } |
| |
| pthread_mutex_unlock(&(g_busy_frame_queue.mut)); |
| pthread_cond_signal(&(g_busy_frame_queue.wait)); |
| |
| LOGV("cam_frame_post_video... out = %x\n", p->buffer); |
| |
| return; |
| } |
| |
| void QualcommCameraHardware::storeTargetType(void) { |
| char mDeviceName[PROPERTY_VALUE_MAX]; |
| property_get("ro.product.device",mDeviceName," "); |
| mCurrentTarget = TARGET_MAX; |
| for( int i = 0; i < TARGET_MAX ; i++) { |
| if( !strncmp(mDeviceName, targetList[i].targetStr, 7)) { |
| mCurrentTarget = targetList[i].targetEnum; |
| break; |
| } |
| } |
| LOGV(" Storing the current target type as %d ", mCurrentTarget ); |
| return; |
| } |
| |
| //------------------------------------------------------------------------------------- |
| static Mutex singleton_lock; |
| static bool singleton_releasing; |
| static Condition singleton_wait; |
| |
| static void receive_camframe_callback(struct msm_frame *frame); |
| static void receive_camframe_video_callback(struct msm_frame *frame); // 720p |
| static void receive_jpeg_fragment_callback(uint8_t *buff_ptr, uint32_t buff_size); |
| static void receive_jpeg_callback(jpeg_event_t status); |
| static void receive_shutter_callback(common_crop_t *crop); |
| static void receive_camframetimeout_callback(void); |
| static int fb_fd = -1; |
| static int32_t mMaxZoom = 0; |
| static bool native_get_maxzoom(int camfd, void *pZm); |
| |
| static int dstOffset = 0; |
| |
| static int camerafd; |
| pthread_t w_thread; |
| |
| void *opencamerafd(void *data) { |
| camerafd = open(MSM_CAMERA_CONTROL, O_RDWR); |
| return NULL; |
| } |
| |
| /* When using MDP zoom, double the preview buffers. The usage of these |
| * buffers is as follows: |
| * 1. As all the buffers comes under a single FD, and at initial registration, |
| * this FD will be passed to surface flinger, surface flinger can have access |
| * to all the buffers when needed. |
| * 2. Only "kPreviewBufferCount" buffers (SrcSet) will be registered with the |
| * camera driver to receive preview frames. The remaining buffers (DstSet), |
| * will be used at HAL and by surface flinger only when crop information |
| * is present in the frame. |
| * 3. When there is no crop information, there will be no call to MDP zoom, |
| * and the buffers in SrcSet will be passed to surface flinger to display. |
| * 4. With crop information present, MDP zoom will be called, and the final |
| * data will be placed in a buffer from DstSet, and this buffer will be given |
| * to surface flinger to display. |
| */ |
| #define NUM_MORE_BUFS 2 |
| |
| QualcommCameraHardware::QualcommCameraHardware() |
| : mParameters(), |
| mCameraRunning(false), |
| mPreviewInitialized(false), |
| mFrameThreadRunning(false), |
| mVideoThreadRunning(false), |
| mSnapshotThreadRunning(false), |
| mSnapshotFormat(0), |
| mReleasedRecordingFrame(false), |
| mPreviewFrameSize(0), |
| mRawSize(0), |
| mCameraControlFd(-1), |
| mAutoFocusThreadRunning(false), |
| mAutoFocusFd(-1), |
| mBrightness(0), |
| mInPreviewCallback(false), |
| mUseOverlay(0), |
| mOverlay(0), |
| mMsgEnabled(0), |
| mNotifyCallback(0), |
| mDataCallback(0), |
| mDataCallbackTimestamp(0), |
| mCallbackCookie(0), |
| mDebugFps(0) |
| { |
| |
| // Start opening camera device in a separate thread/ Since this |
| // initializes the sensor hardware, this can take a long time. So, |
| // start the process here so it will be ready by the time it's |
| // needed. |
| if ((pthread_create(&w_thread, NULL, opencamerafd, NULL)) != 0) { |
| LOGE("Camera open thread creation failed"); |
| } |
| |
| memset(&mDimension, 0, sizeof(mDimension)); |
| memset(&mCrop, 0, sizeof(mCrop)); |
| memset(&zoomCropInfo, 0, sizeof(zoom_crop_info)); |
| storeTargetType(); |
| char value[PROPERTY_VALUE_MAX]; |
| property_get("persist.debug.sf.showfps", value, "0"); |
| mDebugFps = atoi(value); |
| if( mCurrentTarget == TARGET_MSM7630 ) |
| kPreviewBufferCountActual = kPreviewBufferCount; |
| else |
| kPreviewBufferCountActual = kPreviewBufferCount + NUM_MORE_BUFS; |
| LOGV("constructor EX"); |
| } |
| |
| |
| void QualcommCameraHardware::filterPreviewSizes(){ |
| |
| unsigned int bitMask = 0; |
| int prop = 0; |
| for(prop=0;prop<sizeof(boardProperties)/sizeof(board_property);prop++){ |
| if(mCurrentTarget == boardProperties[prop].target){ |
| bitMask = boardProperties[prop].previewSizeMask; |
| break; |
| } |
| } |
| |
| if(bitMask){ |
| unsigned int mask = 1<<(PREVIEW_SIZE_COUNT-1); |
| previewSizeCount=0; |
| unsigned int i = 0; |
| while(mask){ |
| if(mask&bitMask) |
| supportedPreviewSizes[previewSizeCount++] = |
| preview_sizes[i]; |
| i++; |
| mask = mask >> 1; |
| } |
| } |
| } |
| |
| //filter Picture sizes based on max width and height |
| void QualcommCameraHardware::filterPictureSizes(){ |
| int i; |
| for(i=0;i<PICTURE_SIZE_COUNT;i++){ |
| if(((picture_sizes[i].width <= |
| sensorType->max_supported_snapshot_width) && |
| (picture_sizes[i].height <= |
| sensorType->max_supported_snapshot_height))){ |
| picture_sizes_ptr = picture_sizes + i; |
| supportedPictureSizesCount = PICTURE_SIZE_COUNT - i ; |
| return ; |
| } |
| } |
| } |
| |
| void QualcommCameraHardware::initDefaultParameters() |
| { |
| LOGV("initDefaultParameters E"); |
| |
| // Initialize constant parameter strings. This will happen only once in the |
| // lifetime of the mediaserver process. |
| if (!parameter_string_initialized) { |
| findSensorType(); |
| antibanding_values = create_values_str( |
| antibanding, sizeof(antibanding) / sizeof(str_map)); |
| effect_values = create_values_str( |
| effects, sizeof(effects) / sizeof(str_map)); |
| autoexposure_values = create_values_str( |
| autoexposure, sizeof(autoexposure) / sizeof(str_map)); |
| whitebalance_values = create_values_str( |
| whitebalance, sizeof(whitebalance) / sizeof(str_map)); |
| |
| //filter preview sizes |
| filterPreviewSizes(); |
| preview_size_values = create_sizes_str( |
| supportedPreviewSizes, previewSizeCount); |
| //filter picture sizes |
| filterPictureSizes(); |
| picture_size_values = create_sizes_str( |
| picture_sizes_ptr, supportedPictureSizesCount); |
| |
| flash_values = create_values_str( |
| flash, sizeof(flash) / sizeof(str_map)); |
| if(sensorType->hasAutoFocusSupport){ |
| focus_mode_values = create_values_str( |
| focus_modes, sizeof(focus_modes) / sizeof(str_map)); |
| } |
| iso_values = create_values_str( |
| iso,sizeof(iso)/sizeof(str_map)); |
| lensshade_values = create_values_str( |
| lensshade,sizeof(lensshade)/sizeof(str_map)); |
| picture_format_values = create_values_str( |
| picture_formats, sizeof(picture_formats)/sizeof(str_map)); |
| parameter_string_initialized = true; |
| } |
| |
| mParameters.setPreviewSize(DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT); |
| mDimension.display_width = DEFAULT_PREVIEW_WIDTH; |
| mDimension.display_height = DEFAULT_PREVIEW_HEIGHT; |
| |
| mParameters.setPreviewFrameRate(15); |
| mParameters.setPreviewFormat("yuv420sp"); // informative |
| |
| mParameters.setPictureSize(DEFAULT_PICTURE_WIDTH, DEFAULT_PICTURE_HEIGHT); |
| mParameters.setPictureFormat("jpeg"); // informative |
| |
| mParameters.set(CameraParameters::KEY_JPEG_QUALITY, "85"); // max quality |
| mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, |
| THUMBNAIL_WIDTH_STR); // informative |
| mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, |
| THUMBNAIL_HEIGHT_STR); // informative |
| mDimension.ui_thumbnail_width = |
| thumbnail_sizes[DEFAULT_THUMBNAIL_SETTING].width; |
| mDimension.ui_thumbnail_height = |
| thumbnail_sizes[DEFAULT_THUMBNAIL_SETTING].height; |
| mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "90"); |
| |
| mParameters.set(CameraParameters::KEY_ANTIBANDING, |
| CameraParameters::ANTIBANDING_OFF); |
| mParameters.set(CameraParameters::KEY_EFFECT, |
| CameraParameters::EFFECT_NONE); |
| mParameters.set(CameraParameters::KEY_AUTO_EXPOSURE, |
| CameraParameters::AUTO_EXPOSURE_FRAME_AVG); |
| mParameters.set(CameraParameters::KEY_WHITE_BALANCE, |
| CameraParameters::WHITE_BALANCE_AUTO); |
| mParameters.set(CameraParameters::KEY_FOCUS_MODE, |
| CameraParameters::FOCUS_MODE_AUTO); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, |
| "yuv420sp"); |
| |
| mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, |
| preview_size_values.string()); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, |
| picture_size_values.string()); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING, |
| antibanding_values); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_EFFECTS, effect_values); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_AUTO_EXPOSURE, autoexposure_values); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE, |
| whitebalance_values); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, |
| focus_mode_values); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS, |
| picture_format_values); |
| |
| if (mSensorInfo.flash_enabled) { |
| mParameters.set(CameraParameters::KEY_FLASH_MODE, |
| CameraParameters::FLASH_MODE_OFF); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, |
| flash_values); |
| } |
| |
| mParameters.set(CameraParameters::KEY_MAX_SHARPNESS, |
| CAMERA_MAX_SHARPNESS); |
| mParameters.set(CameraParameters::KEY_MAX_CONTRAST, |
| CAMERA_MAX_CONTRAST); |
| mParameters.set(CameraParameters::KEY_MAX_SATURATION, |
| CAMERA_MAX_SATURATION); |
| |
| mParameters.set("luma-adaptation", "3"); |
| mParameters.set("zoom-supported", "true"); |
| mParameters.set("max-zoom", MAX_ZOOM_LEVEL); |
| mParameters.set("zoom", 0); |
| mParameters.set(CameraParameters::KEY_PICTURE_FORMAT, |
| CameraParameters::PIXEL_FORMAT_JPEG); |
| |
| mParameters.set(CameraParameters::KEY_SHARPNESS, |
| CAMERA_DEF_SHARPNESS); |
| mParameters.set(CameraParameters::KEY_CONTRAST, |
| CAMERA_DEF_CONTRAST); |
| mParameters.set(CameraParameters::KEY_SATURATION, |
| CAMERA_DEF_SATURATION); |
| |
| mParameters.set(CameraParameters::KEY_ISO_MODE, |
| CameraParameters::ISO_AUTO); |
| mParameters.set(CameraParameters::KEY_LENSSHADE, |
| CameraParameters::LENSSHADE_ENABLE); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_ISO_MODES, |
| iso_values); |
| mParameters.set(CameraParameters::KEY_SUPPORTED_LENSSHADE_MODES, |
| lensshade_values); |
| |
| if (setParameters(mParameters) != NO_ERROR) { |
| LOGE("Failed to set default parameters?!"); |
| } |
| |
| mUseOverlay = useOverlay(); |
| |
| /* Initialize the camframe_timeout_flag*/ |
| Mutex::Autolock l(&mCamframeTimeoutLock); |
| camframe_timeout_flag = FALSE; |
| mPostViewHeap = NULL; |
| |
| LOGV("initDefaultParameters X"); |
| } |
| |
| void QualcommCameraHardware::findSensorType(){ |
| mDimension.picture_width = DEFAULT_PICTURE_WIDTH; |
| mDimension.picture_height = DEFAULT_PICTURE_HEIGHT; |
| bool ret = native_set_parm(CAMERA_SET_PARM_DIMENSION, |
| sizeof(cam_ctrl_dimension_t), &mDimension); |
| if (ret) { |
| unsigned int i; |
| for (i = 0; i < sizeof(sensorTypes) / sizeof(SensorType); i++) { |
| if (sensorTypes[i].rawPictureHeight |
| == mDimension.raw_picture_height) { |
| sensorType = sensorTypes + i; |
| return; |
| } |
| } |
| } |
| //default to 5 mp |
| sensorType = sensorTypes; |
| return; |
| } |
| |
| #define ROUND_TO_PAGE(x) (((x)+0xfff)&~0xfff) |
| |
| bool QualcommCameraHardware::startCamera() |
| { |
| LOGV("startCamera E"); |
| if( mCurrentTarget == TARGET_MAX ) { |
| LOGE(" Unable to determine the target type. Camera will not work "); |
| return false; |
| } |
| #if DLOPEN_LIBMMCAMERA |
| libmmcamera = ::dlopen("liboemcamera.so", RTLD_NOW); |
| LOGV("loading liboemcamera at %p", libmmcamera); |
| if (!libmmcamera) { |
| LOGE("FATAL ERROR: could not dlopen liboemcamera.so: %s", dlerror()); |
| return false; |
| } |
| |
| *(void **)&LINK_cam_frame = |
| ::dlsym(libmmcamera, "cam_frame"); |
| *(void **)&LINK_camframe_terminate = |
| ::dlsym(libmmcamera, "camframe_terminate"); |
| |
| *(void **)&LINK_jpeg_encoder_init = |
| ::dlsym(libmmcamera, "jpeg_encoder_init"); |
| |
| *(void **)&LINK_jpeg_encoder_encode = |
| ::dlsym(libmmcamera, "jpeg_encoder_encode"); |
| |
| *(void **)&LINK_jpeg_encoder_join = |
| ::dlsym(libmmcamera, "jpeg_encoder_join"); |
| |
| *(void **)&LINK_mmcamera_camframe_callback = |
| ::dlsym(libmmcamera, "mmcamera_camframe_callback"); |
| |
| *LINK_mmcamera_camframe_callback = receive_camframe_callback; |
| |
| *(void **)&LINK_mmcamera_jpegfragment_callback = |
| ::dlsym(libmmcamera, "mmcamera_jpegfragment_callback"); |
| |
| *LINK_mmcamera_jpegfragment_callback = receive_jpeg_fragment_callback; |
| |
| *(void **)&LINK_mmcamera_jpeg_callback = |
| ::dlsym(libmmcamera, "mmcamera_jpeg_callback"); |
| |
| *LINK_mmcamera_jpeg_callback = receive_jpeg_callback; |
| |
| *(void **)&LINK_camframe_timeout_callback = |
| ::dlsym(libmmcamera, "camframe_timeout_callback"); |
| |
| *LINK_camframe_timeout_callback = receive_camframetimeout_callback; |
| |
| // 720 p new recording functions |
| *(void **)&LINK_cam_frame_flush_free_video = ::dlsym(libmmcamera, "cam_frame_flush_free_video"); |
| |
| *(void **)&LINK_camframe_free_video = ::dlsym(libmmcamera, "cam_frame_add_free_video"); |
| |
| *(void **)&LINK_camframe_video_callback = ::dlsym(libmmcamera, "mmcamera_camframe_videocallback"); |
| *LINK_camframe_video_callback = receive_camframe_video_callback; |
| /* Disabling until support is available. |
| *(void **)&LINK_mmcamera_shutter_callback = |
| ::dlsym(libmmcamera, "mmcamera_shutter_callback"); |
| |
| *LINK_mmcamera_shutter_callback = receive_shutter_callback; |
| */ |
| *(void**)&LINK_jpeg_encoder_setMainImageQuality = |
| ::dlsym(libmmcamera, "jpeg_encoder_setMainImageQuality"); |
| |
| *(void**)&LINK_jpeg_encoder_setThumbnailQuality = |
| ::dlsym(libmmcamera, "jpeg_encoder_setThumbnailQuality"); |
| |
| *(void**)&LINK_jpeg_encoder_setRotation = |
| ::dlsym(libmmcamera, "jpeg_encoder_setRotation"); |
| |
| /* Disabling until support is available. |
| *(void**)&LINK_jpeg_encoder_setLocation = |
| ::dlsym(libmmcamera, "jpeg_encoder_setLocation"); |
| */ |
| *(void **)&LINK_cam_conf = |
| ::dlsym(libmmcamera, "cam_conf"); |
| |
| /* Disabling until support is available. |
| *(void **)&LINK_default_sensor_get_snapshot_sizes = |
| ::dlsym(libmmcamera, "default_sensor_get_snapshot_sizes"); |
| */ |
| *(void **)&LINK_launch_cam_conf_thread = |
| ::dlsym(libmmcamera, "launch_cam_conf_thread"); |
| |
| *(void **)&LINK_release_cam_conf_thread = |
| ::dlsym(libmmcamera, "release_cam_conf_thread"); |
| |
| /* Disabling until support is available. |
| *(void **)&LINK_zoom_crop_upscale = |
| ::dlsym(libmmcamera, "zoom_crop_upscale"); |
| */ |
| |
| #else |
| mmcamera_camframe_callback = receive_camframe_callback; |
| mmcamera_jpegfragment_callback = receive_jpeg_fragment_callback; |
| mmcamera_jpeg_callback = receive_jpeg_callback; |
| mmcamera_shutter_callback = receive_shutter_callback; |
| #endif // DLOPEN_LIBMMCAMERA |
| |
| /* The control thread is in libcamera itself. */ |
| if (pthread_join(w_thread, NULL) != 0) { |
| LOGE("Camera open thread exit failed"); |
| return false; |
| } |
| mCameraControlFd = camerafd; |
| |
| if (mCameraControlFd < 0) { |
| LOGE("startCamera X: %s open failed: %s!", |
| MSM_CAMERA_CONTROL, |
| strerror(errno)); |
| return false; |
| } |
| |
| if( mCurrentTarget != TARGET_MSM7630 ){ |
| fb_fd = open("/dev/graphics/fb0", O_RDWR); |
| if (fb_fd < 0) { |
| LOGE("startCamera: fb0 open failed: %s!", strerror(errno)); |
| return FALSE; |
| } |
| } |
| |
| /* This will block until the control thread is launched. After that, sensor |
| * information becomes available. |
| */ |
| |
| if (LINK_launch_cam_conf_thread()) { |
| LOGE("failed to launch the camera config thread"); |
| return false; |
| } |
| |
| memset(&mSensorInfo, 0, sizeof(mSensorInfo)); |
| if (ioctl(mCameraControlFd, |
| MSM_CAM_IOCTL_GET_SENSOR_INFO, |
| &mSensorInfo) < 0) |
| LOGW("%s: cannot retrieve sensor info!", __FUNCTION__); |
| else |
| LOGI("%s: camsensor name %s, flash %d", __FUNCTION__, |
| mSensorInfo.name, mSensorInfo.flash_enabled); |
| /* Disabling until support is available. |
| picture_sizes = LINK_default_sensor_get_snapshot_sizes(&PICTURE_SIZE_COUNT); |
| if (!picture_sizes || !PICTURE_SIZE_COUNT) { |
| LOGE("startCamera X: could not get snapshot sizes"); |
| return false; |
| } |
| */ |
| LOGV("startCamera X"); |
| return true; |
| } |
| |
| status_t QualcommCameraHardware::dump(int fd, |
| const Vector<String16>& args) const |
| { |
| const size_t SIZE = 256; |
| char buffer[SIZE]; |
| String8 result; |
| |
| // Dump internal primitives. |
| result.append("QualcommCameraHardware::dump"); |
| snprintf(buffer, 255, "mMsgEnabled (%d)\n", mMsgEnabled); |
| result.append(buffer); |
| int width, height; |
| mParameters.getPreviewSize(&width, &height); |
| snprintf(buffer, 255, "preview width(%d) x height (%d)\n", width, height); |
| result.append(buffer); |
| mParameters.getPictureSize(&width, &height); |
| snprintf(buffer, 255, "raw width(%d) x height (%d)\n", width, height); |
| result.append(buffer); |
| snprintf(buffer, 255, |
| "preview frame size(%d), raw size (%d), jpeg size (%d) " |
| "and jpeg max size (%d)\n", mPreviewFrameSize, mRawSize, |
| mJpegSize, mJpegMaxSize); |
| result.append(buffer); |
| write(fd, result.string(), result.size()); |
| |
| // Dump internal objects. |
| if (mPreviewHeap != 0) { |
| mPreviewHeap->dump(fd, args); |
| } |
| if (mRawHeap != 0) { |
| mRawHeap->dump(fd, args); |
| } |
| if (mJpegHeap != 0) { |
| mJpegHeap->dump(fd, args); |
| } |
| if(mRawSnapshotAshmemHeap != 0 ){ |
| mRawSnapshotAshmemHeap->dump(fd, args); |
| } |
| mParameters.dump(fd, args); |
| return NO_ERROR; |
| } |
| |
| static bool native_get_maxzoom(int camfd, void *pZm) |
| { |
| LOGV("native_get_maxzoom E"); |
| |
| struct msm_ctrl_cmd ctrlCmd; |
| int32_t *pZoom = (int32_t *)pZm; |
| |
| ctrlCmd.type = CAMERA_GET_PARM_MAXZOOM; |
| ctrlCmd.timeout_ms = 5000; |
| ctrlCmd.length = sizeof(int32_t); |
| ctrlCmd.value = pZoom; |
| ctrlCmd.resp_fd = camfd; |
| |
| if (ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) { |
| LOGE("native_get_maxzoom: ioctl fd %d error %s", |
| camfd, |
| strerror(errno)); |
| return false; |
| } |
| LOGD("ctrlCmd.value = %d", *(int32_t *)ctrlCmd.value); |
| memcpy(pZoom, (int32_t *)ctrlCmd.value, sizeof(int32_t)); |
| |
| LOGV("native_get_maxzoom X"); |
| return true; |
| } |
| |
| static bool native_set_afmode(int camfd, isp3a_af_mode_t af_type) |
| { |
| int rc; |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 5000; |
| ctrlCmd.type = CAMERA_SET_PARM_AUTO_FOCUS; |
| ctrlCmd.length = sizeof(af_type); |
| ctrlCmd.value = &af_type; |
| ctrlCmd.resp_fd = camfd; // FIXME: this will be put in by the kernel |
| |
| if ((rc = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) |
| LOGE("native_set_afmode: ioctl fd %d error %s\n", |
| camfd, |
| strerror(errno)); |
| |
| LOGV("native_set_afmode: ctrlCmd.status == %d\n", ctrlCmd.status); |
| return rc >= 0 && ctrlCmd.status == CAMERA_EXIT_CB_DONE; |
| } |
| |
| static bool native_cancel_afmode(int camfd, int af_fd) |
| { |
| int rc; |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 0; |
| ctrlCmd.type = CAMERA_AUTO_FOCUS_CANCEL; |
| ctrlCmd.length = 0; |
| ctrlCmd.value = NULL; |
| ctrlCmd.resp_fd = -1; // there's no response fd |
| |
| if ((rc = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND_2, &ctrlCmd)) < 0) |
| { |
| LOGE("native_cancel_afmode: ioctl fd %d error %s\n", |
| camfd, |
| strerror(errno)); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static bool native_start_preview(int camfd) |
| { |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 5000; |
| ctrlCmd.type = CAMERA_START_PREVIEW; |
| ctrlCmd.length = 0; |
| ctrlCmd.resp_fd = camfd; // FIXME: this will be put in by the kernel |
| |
| if (ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) { |
| LOGE("native_start_preview: MSM_CAM_IOCTL_CTRL_COMMAND fd %d error %s", |
| camfd, |
| strerror(errno)); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static bool native_get_picture (int camfd, common_crop_t *crop) |
| { |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 5000; |
| ctrlCmd.length = sizeof(common_crop_t); |
| ctrlCmd.value = crop; |
| |
| if(ioctl(camfd, MSM_CAM_IOCTL_GET_PICTURE, &ctrlCmd) < 0) { |
| LOGE("native_get_picture: MSM_CAM_IOCTL_GET_PICTURE fd %d error %s", |
| camfd, |
| strerror(errno)); |
| return false; |
| } |
| |
| LOGV("crop: in1_w %d", crop->in1_w); |
| LOGV("crop: in1_h %d", crop->in1_h); |
| LOGV("crop: out1_w %d", crop->out1_w); |
| LOGV("crop: out1_h %d", crop->out1_h); |
| |
| LOGV("crop: in2_w %d", crop->in2_w); |
| LOGV("crop: in2_h %d", crop->in2_h); |
| LOGV("crop: out2_w %d", crop->out2_w); |
| LOGV("crop: out2_h %d", crop->out2_h); |
| |
| LOGV("crop: update %d", crop->update_flag); |
| |
| return true; |
| } |
| |
| static bool native_stop_preview(int camfd) |
| { |
| struct msm_ctrl_cmd ctrlCmd; |
| ctrlCmd.timeout_ms = 5000; |
| ctrlCmd.type = CAMERA_STOP_PREVIEW; |
| ctrlCmd.length = 0; |
| ctrlCmd.resp_fd = camfd; // FIXME: this will be put in by the kernel |
| |
| if(ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) { |
| LOGE("native_stop_preview: ioctl fd %d error %s", |
| camfd, |
| strerror(errno)); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static bool native_prepare_snapshot(int camfd) |
| { |
| int ioctlRetVal = true; |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 1000; |
| ctrlCmd.type = CAMERA_PREPARE_SNAPSHOT; |
| ctrlCmd.length = 0; |
| ctrlCmd.value = NULL; |
| ctrlCmd.resp_fd = camfd; |
| |
| if (ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) { |
| LOGE("native_prepare_snapshot: ioctl fd %d error %s", |
| camfd, |
| strerror(errno)); |
| return false; |
| } |
| return true; |
| } |
| |
| static bool native_start_snapshot(int camfd) |
| { |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 5000; |
| ctrlCmd.type = CAMERA_START_SNAPSHOT; |
| ctrlCmd.length = 0; |
| ctrlCmd.resp_fd = camfd; // FIXME: this will be put in by the kernel |
| |
| if(ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) { |
| LOGE("native_start_snapshot: ioctl fd %d error %s", |
| camfd, |
| strerror(errno)); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static bool native_start_raw_snapshot(int camfd) |
| { |
| int ret; |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 1000; |
| ctrlCmd.type = CAMERA_START_RAW_SNAPSHOT; |
| ctrlCmd.length = 0; |
| ctrlCmd.value = NULL; |
| ctrlCmd.resp_fd = camfd; |
| |
| if ((ret = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) { |
| LOGE("native_start_raw_snapshot: ioctl failed. ioctl return value "\ |
| "is %d \n", ret); |
| return false; |
| } |
| return true; |
| } |
| |
| |
| static bool native_stop_snapshot (int camfd) |
| { |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 0; |
| ctrlCmd.type = CAMERA_STOP_SNAPSHOT; |
| ctrlCmd.length = 0; |
| ctrlCmd.resp_fd = -1; |
| |
| if (ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND_2, &ctrlCmd) < 0) { |
| LOGE("native_stop_snapshot: ioctl fd %d error %s", |
| camfd, |
| strerror(errno)); |
| return false; |
| } |
| |
| return true; |
| } |
| /*=========================================================================== |
| * FUNCTION - native_start_recording - |
| * |
| * DESCRIPTION: |
| *==========================================================================*/ |
| static bool native_start_recording(int camfd) |
| { |
| int ret; |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 1000; |
| ctrlCmd.type = CAMERA_START_RECORDING; |
| ctrlCmd.length = 0; |
| ctrlCmd.value = NULL; |
| ctrlCmd.resp_fd = camfd; |
| |
| if ((ret = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) { |
| LOGE("native_start_recording: ioctl failed. ioctl return value "\ |
| "is %d \n", ret); |
| return false; |
| } |
| LOGV("native_start_recording: ioctl good. ioctl return value is %d \n",ret); |
| |
| /* TODO: Check status of postprocessing if there is any, |
| * PP status should be in ctrlCmd */ |
| |
| return true; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION - native_stop_recording - |
| * |
| * DESCRIPTION: |
| *==========================================================================*/ |
| static bool native_stop_recording(int camfd) |
| { |
| int ret; |
| struct msm_ctrl_cmd ctrlCmd; |
| LOGV("in native_stop_recording "); |
| ctrlCmd.timeout_ms = 1000; |
| ctrlCmd.type = CAMERA_STOP_RECORDING; |
| ctrlCmd.length = 0; |
| ctrlCmd.value = NULL; |
| ctrlCmd.resp_fd = camfd; |
| |
| if ((ret = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) { |
| LOGE("native_stop_video: ioctl failed. ioctl return value is %d \n", |
| ret); |
| return false; |
| } |
| LOGV("in native_stop_recording returned %d", ret); |
| return true; |
| } |
| /*=========================================================================== |
| * FUNCTION - native_start_video - |
| * |
| * DESCRIPTION: |
| *==========================================================================*/ |
| static bool native_start_video(int camfd) |
| { |
| int ret; |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 1000; |
| ctrlCmd.type = CAMERA_START_VIDEO; |
| ctrlCmd.length = 0; |
| ctrlCmd.value = NULL; |
| ctrlCmd.resp_fd = camfd; |
| |
| if ((ret = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) { |
| LOGE("native_start_video: ioctl failed. ioctl return value is %d \n", |
| ret); |
| return false; |
| } |
| |
| /* TODO: Check status of postprocessing if there is any, |
| * PP status should be in ctrlCmd */ |
| |
| return true; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION - native_stop_video - |
| * |
| * DESCRIPTION: |
| *==========================================================================*/ |
| static bool native_stop_video(int camfd) |
| { |
| int ret; |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 1000; |
| ctrlCmd.type = CAMERA_STOP_VIDEO; |
| ctrlCmd.length = 0; |
| ctrlCmd.value = NULL; |
| ctrlCmd.resp_fd = camfd; |
| |
| if ((ret = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) { |
| LOGE("native_stop_video: ioctl failed. ioctl return value is %d \n", |
| ret); |
| return false; |
| } |
| |
| return true; |
| } |
| /*==========================================================================*/ |
| |
| static cam_frame_start_parms frame_parms; |
| static int recordingState = 0; |
| |
| static rat_t latitude[3]; |
| static rat_t longitude[3]; |
| static char lonref[2]; |
| static char latref[2]; |
| static char dateTime[20]; |
| static rat_t altitude; |
| |
| static void addExifTag(exif_tag_id_t tagid, exif_tag_type_t type, |
| uint32_t count, uint8_t copy, void *data) { |
| |
| if(exif_table_numEntries == MAX_EXIF_TABLE_ENTRIES) { |
| LOGE("Number of entries exceeded limit"); |
| return; |
| } |
| |
| int index = exif_table_numEntries; |
| exif_data[index].tag_id = tagid; |
| exif_data[index].tag_entry.type = type; |
| exif_data[index].tag_entry.count = count; |
| exif_data[index].tag_entry.copy = copy; |
| if((type == EXIF_RATIONAL) && (count > 1)) |
| exif_data[index].tag_entry.data._rats = (rat_t *)data; |
| if((type == EXIF_RATIONAL) && (count == 1)) |
| exif_data[index].tag_entry.data._rat = *(rat_t *)data; |
| else if(type == EXIF_ASCII) |
| exif_data[index].tag_entry.data._ascii = (char *)data; |
| else if(type == EXIF_BYTE) |
| exif_data[index].tag_entry.data._byte = *(uint8_t *)data; |
| |
| // Increase number of entries |
| exif_table_numEntries++; |
| } |
| |
| static void parseLatLong(const char *latlonString, int *pDegrees, |
| int *pMinutes, int *pSeconds ) { |
| |
| double value = atof(latlonString); |
| value = fabs(value); |
| int degrees = (int) value; |
| |
| double remainder = value - degrees; |
| int minutes = (int) (remainder * 60); |
| int seconds = (int) (((remainder * 60) - minutes) * 60 * 1000); |
| |
| *pDegrees = degrees; |
| *pMinutes = minutes; |
| *pSeconds = seconds; |
| } |
| |
| static void setLatLon(exif_tag_id_t tag, const char *latlonString) { |
| |
| int degrees, minutes, seconds; |
| |
| parseLatLong(latlonString, °rees, &minutes, &seconds); |
| |
| rat_t value[3] = { {degrees, 1}, |
| {minutes, 1}, |
| {seconds, 1000} }; |
| |
| if(tag == EXIFTAGID_GPS_LATITUDE) { |
| memcpy(latitude, value, sizeof(latitude)); |
| addExifTag(EXIFTAGID_GPS_LATITUDE, EXIF_RATIONAL, 3, |
| 1, (void *)latitude); |
| } else { |
| memcpy(longitude, value, sizeof(longitude)); |
| addExifTag(EXIFTAGID_GPS_LONGITUDE, EXIF_RATIONAL, 3, |
| 1, (void *)longitude); |
| } |
| } |
| |
| void QualcommCameraHardware::setGpsParameters() { |
| const char *str = NULL; |
| |
| //Set Latitude |
| str = mParameters.get(CameraParameters::KEY_GPS_LATITUDE); |
| if(str != NULL) { |
| setLatLon(EXIFTAGID_GPS_LATITUDE, str); |
| //set Latitude Ref |
| str = NULL; |
| str = mParameters.get(CameraParameters::KEY_GPS_LATITUDE_REF); |
| if(str != NULL) { |
| strncpy(latref, str, 1); |
| latref[1] = '\0'; |
| addExifTag(EXIFTAGID_GPS_LATITUDE_REF, EXIF_ASCII, 2, |
| 1, (void *)latref); |
| } |
| } |
| |
| //set Longitude |
| str = NULL; |
| str = mParameters.get(CameraParameters::KEY_GPS_LONGITUDE); |
| if(str != NULL) { |
| setLatLon(EXIFTAGID_GPS_LONGITUDE, str); |
| //set Longitude Ref |
| str = NULL; |
| str = mParameters.get(CameraParameters::KEY_GPS_LONGITUDE_REF); |
| if(str != NULL) { |
| strncpy(lonref, str, 1); |
| lonref[1] = '\0'; |
| addExifTag(EXIFTAGID_GPS_LONGITUDE_REF, EXIF_ASCII, 2, |
| 1, (void *)lonref); |
| } |
| } |
| |
| //set Altitude |
| str = NULL; |
| str = mParameters.get(CameraParameters::KEY_GPS_ALTITUDE); |
| if(str != NULL) { |
| int value = atoi(str); |
| rat_t alt_value = {value, 1000}; |
| memcpy(&altitude, &alt_value, sizeof(altitude)); |
| addExifTag(EXIFTAGID_GPS_ALTITUDE, EXIF_RATIONAL, 1, |
| 1, (void *)&altitude); |
| //set AltitudeRef |
| int ref = mParameters.getInt(CameraParameters::KEY_GPS_ALTITUDE_REF); |
| if( !(ref < 0 || ref > 1) ) |
| addExifTag(EXIFTAGID_GPS_ALTITUDE_REF, EXIF_BYTE, 1, |
| 1, (void *)&ref); |
| } |
| |
| |
| } |
| |
| bool QualcommCameraHardware::native_jpeg_encode(void) |
| { |
| int jpeg_quality = mParameters.getInt("jpeg-quality"); |
| if (jpeg_quality >= 0) { |
| LOGV("native_jpeg_encode, current jpeg main img quality =%d", |
| jpeg_quality); |
| if(!LINK_jpeg_encoder_setMainImageQuality(jpeg_quality)) { |
| LOGE("native_jpeg_encode set jpeg-quality failed"); |
| return false; |
| } |
| } |
| |
| int thumbnail_quality = mParameters.getInt("jpeg-thumbnail-quality"); |
| if (thumbnail_quality >= 0) { |
| LOGV("native_jpeg_encode, current jpeg thumbnail quality =%d", |
| thumbnail_quality); |
| if(!LINK_jpeg_encoder_setThumbnailQuality(thumbnail_quality)) { |
| LOGE("native_jpeg_encode set thumbnail-quality failed"); |
| return false; |
| } |
| } |
| |
| int rotation = mParameters.getInt("rotation"); |
| if (rotation >= 0) { |
| LOGV("native_jpeg_encode, rotation = %d", rotation); |
| if(!LINK_jpeg_encoder_setRotation(rotation)) { |
| LOGE("native_jpeg_encode set rotation failed"); |
| return false; |
| } |
| } |
| |
| // jpeg_set_location(); |
| if(mParameters.getInt(CameraParameters::KEY_GPS_STATUS) == 1) { |
| setGpsParameters(); |
| } |
| //set TimeStamp |
| const char *str = mParameters.get(CameraParameters::KEY_EXIF_DATETIME); |
| if(str != NULL) { |
| strncpy(dateTime, str, 19); |
| dateTime[19] = '\0'; |
| addExifTag(EXIFTAGID_EXIF_DATE_TIME_ORIGINAL, EXIF_ASCII, |
| 20, 1, (void *)dateTime); |
| } |
| |
| if (!LINK_jpeg_encoder_encode(&mDimension, |
| (uint8_t *)mThumbnailHeap->mHeap->base(), |
| mThumbnailHeap->mHeap->getHeapID(), |
| (uint8_t *)mRawHeap->mHeap->base(), |
| mRawHeap->mHeap->getHeapID(), |
| &mCrop, exif_data, exif_table_numEntries)) { |
| LOGE("native_jpeg_encode: jpeg_encoder_encode failed."); |
| return false; |
| } |
| return true; |
| } |
| |
| bool QualcommCameraHardware::native_set_parm( |
| cam_ctrl_type type, uint16_t length, void *value) |
| { |
| struct msm_ctrl_cmd ctrlCmd; |
| |
| ctrlCmd.timeout_ms = 5000; |
| ctrlCmd.type = (uint16_t)type; |
| ctrlCmd.length = length; |
| // FIXME: this will be put in by the kernel |
| ctrlCmd.resp_fd = mCameraControlFd; |
| ctrlCmd.value = value; |
| |
| LOGV("%s: fd %d, type %d, length %d", __FUNCTION__, |
| mCameraControlFd, type, length); |
| if (ioctl(mCameraControlFd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0 || |
| ctrlCmd.status != CAM_CTRL_SUCCESS) { |
| LOGE("%s: error (%s): fd %d, type %d, length %d, status %d", |
| __FUNCTION__, strerror(errno), |
| mCameraControlFd, type, length, ctrlCmd.status); |
| return false; |
| } |
| return true; |
| } |
| |
| void QualcommCameraHardware::jpeg_set_location() |
| { |
| bool encode_location = true; |
| camera_position_type pt; |
| |
| #define PARSE_LOCATION(what,type,fmt,desc) do { \ |
| pt.what = 0; \ |
| const char *what##_str = mParameters.get("gps-"#what); \ |
| LOGV("GPS PARM %s --> [%s]", "gps-"#what, what##_str); \ |
| if (what##_str) { \ |
| type what = 0; \ |
| if (sscanf(what##_str, fmt, &what) == 1) \ |
| pt.what = what; \ |
| else { \ |
| LOGE("GPS " #what " %s could not" \ |
| " be parsed as a " #desc, what##_str); \ |
| encode_location = false; \ |
| } \ |
| } \ |
| else { \ |
| LOGV("GPS " #what " not specified: " \ |
| "defaulting to zero in EXIF header."); \ |
| encode_location = false; \ |
| } \ |
| } while(0) |
| |
| PARSE_LOCATION(timestamp, long, "%ld", "long"); |
| if (!pt.timestamp) pt.timestamp = time(NULL); |
| PARSE_LOCATION(altitude, short, "%hd", "short"); |
| PARSE_LOCATION(latitude, double, "%lf", "double float"); |
| PARSE_LOCATION(longitude, double, "%lf", "double float"); |
| |
| #undef PARSE_LOCATION |
| |
| if (encode_location) { |
| LOGD("setting image location ALT %d LAT %lf LON %lf", |
| pt.altitude, pt.latitude, pt.longitude); |
| /* Disabling until support is available. |
| if (!LINK_jpeg_encoder_setLocation(&pt)) { |
| LOGE("jpeg_set_location: LINK_jpeg_encoder_setLocation failed."); |
| } |
| */ |
| } |
| else LOGV("not setting image location"); |
| } |
| |
| void QualcommCameraHardware::runFrameThread(void *data) |
| { |
| LOGV("runFrameThread E"); |
| |
| int cnt; |
| |
| #if DLOPEN_LIBMMCAMERA |
| // We need to maintain a reference to libqcamera.so for the duration of the |
| // frame thread, because we do not know when it will exit relative to the |
| // lifetime of this object. We do not want to dlclose() libqcamera while |
| // LINK_cam_frame is still running. |
| void *libhandle = ::dlopen("liboemcamera.so", RTLD_NOW); |
| LOGV("FRAME: loading libqcamera at %p", libhandle); |
| if (!libhandle) { |
| LOGE("FATAL ERROR: could not dlopen liboemcamera.so: %s", dlerror()); |
| } |
| if (libhandle) |
| #endif |
| { |
| LINK_cam_frame(data); |
| } |
| |
| mPreviewHeap.clear(); |
| if(( mCurrentTarget == TARGET_MSM7630 ) || (mCurrentTarget == TARGET_QSD8250)) |
| mRecordHeap.clear(); |
| |
| #if DLOPEN_LIBMMCAMERA |
| if (libhandle) { |
| ::dlclose(libhandle); |
| LOGV("FRAME: dlclose(libqcamera)"); |
| } |
| #endif |
| |
| mFrameThreadWaitLock.lock(); |
| mFrameThreadRunning = false; |
| mFrameThreadWait.signal(); |
| mFrameThreadWaitLock.unlock(); |
| |
| LOGV("runFrameThread X"); |
| } |
| |
| void QualcommCameraHardware::runVideoThread(void *data) |
| { |
| LOGD("runVideoThread E"); |
| msm_frame* vframe = NULL; |
| |
| while(true) { |
| pthread_mutex_lock(&(g_busy_frame_queue.mut)); |
| |
| LOGV("in video_thread : wait for video frame "); |
| // check if any frames are available in busyQ and give callback to |
| // services/video encoder |
| cam_frame_wait_video(); |
| LOGV("video_thread, wait over.."); |
| |
| // Exit the thread , in case of stop recording.. |
| mVideoThreadWaitLock.lock(); |
| if(mVideoThreadExit){ |
| LOGV("Exiting video thread.."); |
| mVideoThreadWaitLock.unlock(); |
| pthread_mutex_unlock(&(g_busy_frame_queue.mut)); |
| break; |
| } |
| mVideoThreadWaitLock.unlock(); |
| |
| // Get the video frame to be encoded |
| vframe = cam_frame_get_video (); |
| pthread_mutex_unlock(&(g_busy_frame_queue.mut)); |
| LOGV("in video_thread : got video frame "); |
| |
| if (UNLIKELY(mDebugFps)) { |
| debugShowVideoFPS(); |
| } |
| |
| if(vframe != NULL) { |
| // Find the offset within the heap of the current buffer. |
| LOGV("Got video frame : buffer %d base %d ", vframe->buffer, mRecordHeap->mHeap->base()); |
| ssize_t offset = |
| (ssize_t)vframe->buffer - (ssize_t)mRecordHeap->mHeap->base(); |
| LOGV("offset = %d , alignsize = %d , offset later = %d", offset, mRecordHeap->mAlignedBufferSize, (offset / mRecordHeap->mAlignedBufferSize)); |
| |
| offset /= mRecordHeap->mAlignedBufferSize; |
| |
| // dump frames for test purpose |
| #ifdef DUMP_VIDEO_FRAMES |
| static int frameCnt = 0; |
| if (frameCnt >= 11 && frameCnt <= 13 ) { |
| char buf[128]; |
| sprintf(buf, "/data/%d_v.yuv", frameCnt); |
| int file_fd = open(buf, O_RDWR | O_CREAT, 0777); |
| LOGV("dumping video frame %d", frameCnt); |
| if (file_fd < 0) { |
| LOGE("cannot open file\n"); |
| } |
| else |
| { |
| write(file_fd, (const void *)vframe->buffer, |
| vframe->cbcr_off * 3 / 2); |
| } |
| close(file_fd); |
| } |
| frameCnt++; |
| #endif |
| // Enable IF block to give frames to encoder , ELSE block for just simulation |
| #if 1 |
| LOGV("in video_thread : got video frame, before if check giving frame to services/encoder"); |
| mCallbackLock.lock(); |
| int msgEnabled = mMsgEnabled; |
| data_callback_timestamp rcb = mDataCallbackTimestamp; |
| void *rdata = mCallbackCookie; |
| mCallbackLock.unlock(); |
| |
| if(rcb != NULL && (msgEnabled & CAMERA_MSG_VIDEO_FRAME) ) { |
| LOGV("in video_thread : got video frame, giving frame to services/encoder"); |
| rcb(systemTime(), CAMERA_MSG_VIDEO_FRAME, mRecordHeap->mBuffers[offset], rdata); |
| Mutex::Autolock rLock(&mRecordFrameLock); |
| if (mReleasedRecordingFrame != true) { |
| LOGV("block waiting for frame release"); |
| mRecordWait.wait(mRecordFrameLock); |
| LOGV("video frame released, continuing"); |
| } |
| mReleasedRecordingFrame = false; |
| } |
| #else |
| // 720p output2 : simulate release frame here: |
| LOGE("in video_thread simulation , releasing the video frame"); |
| LINK_camframe_free_video(vframe); |
| #endif |
| |
| } else LOGE("in video_thread get frame returned null"); |
| |
| |
| } // end of while loop |
| |
| mVideoThreadWaitLock.lock(); |
| mVideoThreadRunning = false; |
| mVideoThreadWait.signal(); |
| mVideoThreadWaitLock.unlock(); |
| |
| LOGV("runVideoThread X"); |
| } |
| |
| void *video_thread(void *user) |
| { |
| LOGV("video_thread E"); |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->runVideoThread(user); |
| } |
| else LOGE("not starting video thread: the object went away!"); |
| LOGV("video_thread X"); |
| return NULL; |
| } |
| |
| void *frame_thread(void *user) |
| { |
| LOGD("frame_thread E"); |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->runFrameThread(user); |
| } |
| else LOGW("not starting frame thread: the object went away!"); |
| LOGD("frame_thread X"); |
| return NULL; |
| } |
| |
| bool QualcommCameraHardware::initPreview() |
| { |
| // See comments in deinitPreview() for why we have to wait for the frame |
| // thread here, and why we can't use pthread_join(). |
| int videoWidth, videoHeight; |
| mParameters.getPreviewSize(&previewWidth, &previewHeight); |
| |
| videoWidth = previewWidth; // temporary , should be configurable later |
| videoHeight = previewHeight; |
| LOGV("initPreview E: preview size=%dx%d videosize = %d x %d", previewWidth, previewHeight, videoWidth, videoHeight ); |
| |
| if( ( mCurrentTarget == TARGET_MSM7630 ) || (mCurrentTarget == TARGET_QSD8250)) { |
| mDimension.video_width = videoWidth; |
| mDimension.video_width = CEILING16(mDimension.video_width); |
| mDimension.video_height = videoHeight; |
| LOGV("initPreview : preview size=%dx%d videosize = %d x %d", previewWidth, previewHeight, mDimension.video_width, mDimension.video_height ); |
| } |
| |
| |
| mFrameThreadWaitLock.lock(); |
| while (mFrameThreadRunning) { |
| LOGV("initPreview: waiting for old frame thread to complete."); |
| mFrameThreadWait.wait(mFrameThreadWaitLock); |
| LOGV("initPreview: old frame thread completed."); |
| } |
| mFrameThreadWaitLock.unlock(); |
| |
| mSnapshotThreadWaitLock.lock(); |
| while (mSnapshotThreadRunning) { |
| LOGV("initPreview: waiting for old snapshot thread to complete."); |
| mSnapshotThreadWait.wait(mSnapshotThreadWaitLock); |
| LOGV("initPreview: old snapshot thread completed."); |
| } |
| mSnapshotThreadWaitLock.unlock(); |
| |
| int cnt = 0; |
| mPreviewFrameSize = previewWidth * previewHeight * 3/2; |
| dstOffset = 0; |
| mPreviewHeap = new PmemPool("/dev/pmem_adsp", |
| MemoryHeapBase::READ_ONLY | MemoryHeapBase::NO_CACHING, |
| mCameraControlFd, |
| MSM_PMEM_PREVIEW, //MSM_PMEM_OUTPUT2, |
| mPreviewFrameSize, |
| kPreviewBufferCountActual, |
| mPreviewFrameSize, |
| "preview"); |
| |
| if (!mPreviewHeap->initialized()) { |
| mPreviewHeap.clear(); |
| LOGE("initPreview X: could not initialize Camera preview heap."); |
| return false; |
| } |
| if( mCurrentTarget == TARGET_MSM7630 ) { |
| mPostViewHeap.clear(); |
| if(mPostViewHeap == NULL) { |
| LOGV(" Allocating Postview heap "); |
| /* mPostViewHeap should be declared only for 7630 target */ |
| mPostViewHeap = |
| new PmemPool("/dev/pmem_adsp", |
| MemoryHeapBase::READ_ONLY | MemoryHeapBase::NO_CACHING, |
| mCameraControlFd, |
| MSM_PMEM_PREVIEW, //MSM_PMEM_OUTPUT2, |
| mPreviewFrameSize, |
| 1, |
| mPreviewFrameSize, |
| "postview"); |
| |
| if (!mPostViewHeap->initialized()) { |
| mPostViewHeap.clear(); |
| LOGE(" Failed to initialize Postview Heap"); |
| return false; |
| } |
| } |
| } |
| |
| if( ( mCurrentTarget == TARGET_MSM7630 ) || (mCurrentTarget == TARGET_QSD8250) ) { |
| |
| // Allocate video buffers after allocating preview buffers. |
| initRecord(); |
| } |
| |
| // mDimension will be filled with thumbnail_width, thumbnail_height, |
| // orig_picture_dx, and orig_picture_dy after this function call. We need to |
| // keep it for jpeg_encoder_encode. |
| bool ret = native_set_parm(CAMERA_SET_PARM_DIMENSION, |
| sizeof(cam_ctrl_dimension_t), &mDimension); |
| |
| if (ret) { |
| for (cnt = 0; cnt < kPreviewBufferCount; cnt++) { |
| frames[cnt].fd = mPreviewHeap->mHeap->getHeapID(); |
| frames[cnt].buffer = |
| (uint32_t)mPreviewHeap->mHeap->base() + mPreviewHeap->mAlignedBufferSize * cnt; |
| frames[cnt].y_off = 0; |
| frames[cnt].cbcr_off = previewWidth * previewHeight; |
| frames[cnt].path = OUTPUT_TYPE_P; // MSM_FRAME_ENC; |
| } |
| |
| mFrameThreadWaitLock.lock(); |
| pthread_attr_t attr; |
| pthread_attr_init(&attr); |
| pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
| |
| frame_parms.frame = frames[kPreviewBufferCount - 1]; |
| frame_parms.video_frame = recordframes[kPreviewBufferCount - 1]; |
| |
| LOGV ("initpreview before cam_frame thread carete , video frame buffer=%lu fd=%d y_off=%d cbcr_off=%d \n", |
| (unsigned long)frame_parms.video_frame.buffer, frame_parms.video_frame.fd, frame_parms.video_frame.y_off, |
| frame_parms.video_frame.cbcr_off); |
| mFrameThreadRunning = !pthread_create(&mFrameThread, |
| &attr, |
| frame_thread, |
| (void*)&(frame_parms)); |
| ret = mFrameThreadRunning; |
| mFrameThreadWaitLock.unlock(); |
| } |
| |
| LOGV("initPreview X: %d", ret); |
| return ret; |
| } |
| |
| void QualcommCameraHardware::deinitPreview(void) |
| { |
| LOGI("deinitPreview E"); |
| |
| // When we call deinitPreview(), we signal to the frame thread that it |
| // needs to exit, but we DO NOT WAIT for it to complete here. The problem |
| // is that deinitPreview is sometimes called from the frame-thread's |
| // callback, when the refcount on the Camera client reaches zero. If we |
| // called pthread_join(), we would deadlock. So, we just call |
| // LINK_camframe_terminate() in deinitPreview(), which makes sure that |
| // after the preview callback returns, the camframe thread will exit. We |
| // could call pthread_join() in initPreview() to join the last frame |
| // thread. However, we would also have to call pthread_join() in release |
| // as well, shortly before we destroy the object; this would cause the same |
| // deadlock, since release(), like deinitPreview(), may also be called from |
| // the frame-thread's callback. This we have to make the frame thread |
| // detached, and use a separate mechanism to wait for it to complete. |
| |
| LINK_camframe_terminate(); |
| LOGI("deinitPreview X"); |
| } |
| |
| bool QualcommCameraHardware::initRawSnapshot() |
| { |
| LOGV("initRawSnapshot E"); |
| |
| //get width and height from Dimension Object |
| bool ret = native_set_parm(CAMERA_SET_PARM_DIMENSION, |
| sizeof(cam_ctrl_dimension_t), &mDimension); |
| |
| if(!ret){ |
| LOGE("initRawSnapshot X: failed to set dimension"); |
| return false; |
| } |
| int rawSnapshotSize = mDimension.raw_picture_height * |
| mDimension.raw_picture_width; |
| |
| LOGV("raw_snapshot_buffer_size = %d, raw_picture_height = %d, "\ |
| "raw_picture_width = %d", |
| rawSnapshotSize, mDimension.raw_picture_height, |
| mDimension.raw_picture_width); |
| |
| if (mRawSnapShotPmemHeap != NULL) { |
| LOGV("initRawSnapshot: clearing old mRawSnapShotPmemHeap."); |
| mRawSnapShotPmemHeap.clear(); |
| } |
| |
| //Pmem based pool for Camera Driver |
| mRawSnapShotPmemHeap = new PmemPool("/dev/pmem_adsp", |
| MemoryHeapBase::READ_ONLY, |
| mCameraControlFd, |
| MSM_PMEM_RAW_MAINIMG, |
| rawSnapshotSize, |
| 1, |
| rawSnapshotSize, |
| "raw pmem snapshot camera"); |
| |
| if (!mRawSnapShotPmemHeap->initialized()) { |
| mRawSnapShotPmemHeap.clear(); |
| LOGE("initRawSnapshot X: error initializing mRawSnapshotHeap"); |
| return false; |
| } |
| LOGV("initRawSnapshot X"); |
| return true; |
| |
| } |
| |
| bool QualcommCameraHardware::initRaw(bool initJpegHeap) |
| { |
| int rawWidth, rawHeight; |
| |
| mParameters.getPictureSize(&rawWidth, &rawHeight); |
| LOGV("initRaw E: picture size=%dx%d", rawWidth, rawHeight); |
| |
| int thumbnailBufferSize; |
| //Thumbnail height should be smaller than Picture height |
| if (rawHeight > (int)thumbnail_sizes[DEFAULT_THUMBNAIL_SETTING].height){ |
| mDimension.ui_thumbnail_width = |
| thumbnail_sizes[DEFAULT_THUMBNAIL_SETTING].width; |
| mDimension.ui_thumbnail_height = |
| thumbnail_sizes[DEFAULT_THUMBNAIL_SETTING].height; |
| uint32_t pictureAspectRatio = (uint32_t)((rawWidth * Q12) / rawHeight); |
| uint32_t i; |
| for(i = 0; i < THUMBNAIL_SIZE_COUNT; i++ ) |
| { |
| if(thumbnail_sizes[i].aspect_ratio == pictureAspectRatio) |
| { |
| mDimension.ui_thumbnail_width = thumbnail_sizes[i].width; |
| mDimension.ui_thumbnail_height = thumbnail_sizes[i].height; |
| break; |
| } |
| } |
| } |
| else{ |
| mDimension.ui_thumbnail_height = THUMBNAIL_SMALL_HEIGHT; |
| mDimension.ui_thumbnail_width = |
| (THUMBNAIL_SMALL_HEIGHT * rawWidth)/ rawHeight; |
| } |
| |
| LOGV("Thumbnail Size Width %d Height %d", |
| mDimension.ui_thumbnail_width, |
| mDimension.ui_thumbnail_height); |
| |
| thumbnailBufferSize = mDimension.ui_thumbnail_width * |
| mDimension.ui_thumbnail_height * 3 / 2; |
| |
| // mDimension will be filled with thumbnail_width, thumbnail_height, |
| // orig_picture_dx, and orig_picture_dy after this function call. We need to |
| // keep it for jpeg_encoder_encode. |
| bool ret = native_set_parm(CAMERA_SET_PARM_DIMENSION, |
| sizeof(cam_ctrl_dimension_t), &mDimension); |
| if(!ret) { |
| LOGE("initRaw X: failed to set dimension"); |
| return false; |
| } |
| |
| if (mJpegHeap != NULL) { |
| LOGV("initRaw: clearing old mJpegHeap."); |
| mJpegHeap.clear(); |
| } |
| |
| // Snapshot |
| mRawSize = rawWidth * rawHeight * 3 / 2; |
| |
| if( mCurrentTarget == TARGET_MSM7627 ) |
| mJpegMaxSize = CEILING16(rawWidth) * CEILING16(rawHeight) * 3 / 2; |
| else |
| mJpegMaxSize = rawWidth * rawHeight * 3 / 2; |
| |
| LOGV("initRaw: initializing mRawHeap."); |
| mRawHeap = |
| new PmemPool("/dev/pmem_adsp", |
| MemoryHeapBase::READ_ONLY, |
| mCameraControlFd, |
| MSM_PMEM_MAINIMG, |
| mJpegMaxSize, |
| kRawBufferCount, |
| mRawSize, |
| "snapshot camera"); |
| |
| if (!mRawHeap->initialized()) { |
| LOGE("initRaw X failed "); |
| mRawHeap.clear(); |
| LOGE("initRaw X: error initializing mRawHeap"); |
| return false; |
| } |
| |
| LOGV("do_mmap snapshot pbuf = %p, pmem_fd = %d", |
| (uint8_t *)mRawHeap->mHeap->base(), mRawHeap->mHeap->getHeapID()); |
| |
| // Jpeg |
| |
| if (initJpegHeap) { |
| LOGV("initRaw: initializing mJpegHeap."); |
| mJpegHeap = |
| new AshmemPool(mJpegMaxSize, |
| kJpegBufferCount, |
| 0, // we do not know how big the picture will be |
| "jpeg"); |
| |
| if (!mJpegHeap->initialized()) { |
| mJpegHeap.clear(); |
| mRawHeap.clear(); |
| LOGE("initRaw X failed: error initializing mJpegHeap."); |
| return false; |
| } |
| |
| // Thumbnails |
| |
| mThumbnailHeap = |
| new PmemPool("/dev/pmem_adsp", |
| MemoryHeapBase::READ_ONLY, |
| mCameraControlFd, |
| MSM_PMEM_THUMBNAIL, |
| thumbnailBufferSize, |
| 1, |
| thumbnailBufferSize, |
| "thumbnail"); |
| |
| if (!mThumbnailHeap->initialized()) { |
| mThumbnailHeap.clear(); |
| mJpegHeap.clear(); |
| mRawHeap.clear(); |
| LOGE("initRaw X failed: error initializing mThumbnailHeap."); |
| return false; |
| } |
| } |
| |
| LOGV("initRaw X"); |
| return true; |
| } |
| |
| |
| void QualcommCameraHardware::deinitRawSnapshot() |
| { |
| LOGV("deinitRawSnapshot E"); |
| mRawSnapShotPmemHeap.clear(); |
| mRawSnapshotAshmemHeap.clear(); |
| LOGV("deinitRawSnapshot X"); |
| } |
| |
| void QualcommCameraHardware::deinitRaw() |
| { |
| LOGV("deinitRaw E"); |
| |
| mThumbnailHeap.clear(); |
| mJpegHeap.clear(); |
| mRawHeap.clear(); |
| mDisplayHeap.clear(); |
| |
| LOGV("deinitRaw X"); |
| } |
| |
| void QualcommCameraHardware::release() |
| { |
| LOGD("release E"); |
| Mutex::Autolock l(&mLock); |
| |
| #if DLOPEN_LIBMMCAMERA |
| if (libmmcamera == NULL) { |
| LOGE("ERROR: multiple release!"); |
| return; |
| } |
| #else |
| #warning "Cannot detect multiple release when not dlopen()ing libqcamera!" |
| #endif |
| |
| int cnt, rc; |
| struct msm_ctrl_cmd ctrlCmd; |
| if (mCameraRunning) { |
| if(mDataCallbackTimestamp && (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)) { |
| mRecordFrameLock.lock(); |
| mReleasedRecordingFrame = true; |
| mRecordWait.signal(); |
| mRecordFrameLock.unlock(); |
| } |
| stopPreviewInternal(); |
| } |
| |
| if( mCurrentTarget == TARGET_MSM7630 ) { |
| mPostViewHeap.clear(); |
| mPostViewHeap = NULL; |
| } |
| LINK_jpeg_encoder_join(); |
| deinitRaw(); |
| deinitRawSnapshot(); |
| { |
| Mutex::Autolock l(&mCamframeTimeoutLock); |
| if(!camframe_timeout_flag) { |
| |
| ctrlCmd.timeout_ms = 5000; |
| ctrlCmd.length = 0; |
| ctrlCmd.type = (uint16_t)CAMERA_EXIT; |
| ctrlCmd.resp_fd = mCameraControlFd; // FIXME: this will be put in by the kernel |
| if (ioctl(mCameraControlFd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) |
| LOGE("ioctl CAMERA_EXIT fd %d error %s", |
| mCameraControlFd, strerror(errno)); |
| |
| } |
| } |
| LINK_release_cam_conf_thread(); |
| close(mCameraControlFd); |
| mCameraControlFd = -1; |
| if(fb_fd >= 0) { |
| close(fb_fd); |
| fb_fd = -1; |
| } |
| #if DLOPEN_LIBMMCAMERA |
| if (libmmcamera) { |
| ::dlclose(libmmcamera); |
| LOGV("dlclose(libqcamera)"); |
| libmmcamera = NULL; |
| } |
| #endif |
| |
| Mutex::Autolock lock(&singleton_lock); |
| singleton_releasing = true; |
| |
| LOGD("release X"); |
| } |
| |
| QualcommCameraHardware::~QualcommCameraHardware() |
| { |
| LOGD("~QualcommCameraHardware E"); |
| Mutex::Autolock lock(&singleton_lock); |
| singleton.clear(); |
| singleton_releasing = false; |
| singleton_wait.signal(); |
| LOGD("~QualcommCameraHardware X"); |
| } |
| |
| sp<IMemoryHeap> QualcommCameraHardware::getRawHeap() const |
| { |
| LOGV("getRawHeap"); |
| return mDisplayHeap != NULL ? mDisplayHeap->mHeap : NULL; |
| } |
| |
| sp<IMemoryHeap> QualcommCameraHardware::getPreviewHeap() const |
| { |
| LOGV("getPreviewHeap"); |
| return mPreviewHeap != NULL ? mPreviewHeap->mHeap : NULL; |
| } |
| |
| status_t QualcommCameraHardware::startPreviewInternal() |
| { |
| LOGV("in startPreviewInternal : E"); |
| if(mCameraRunning) { |
| LOGV("startPreview X: preview already running."); |
| return NO_ERROR; |
| } |
| |
| if (!mPreviewInitialized) { |
| mLastQueuedFrame = NULL; |
| mPreviewInitialized = initPreview(); |
| if (!mPreviewInitialized) { |
| LOGE("startPreview X initPreview failed. Not starting preview."); |
| return UNKNOWN_ERROR; |
| } |
| } |
| |
| if(( mCurrentTarget != TARGET_MSM7630 ) && (mCurrentTarget != TARGET_QSD8250)) |
| mCameraRunning = native_start_preview(mCameraControlFd); |
| else |
| mCameraRunning = native_start_video(mCameraControlFd); |
| |
| if(!mCameraRunning) { |
| deinitPreview(); |
| mPreviewInitialized = false; |
| mOverlay = NULL; |
| LOGE("startPreview X: native_start_preview failed!"); |
| return UNKNOWN_ERROR; |
| } |
| |
| //Reset the Gps Information |
| exif_table_numEntries = 0; |
| |
| if(native_get_maxzoom(mCameraControlFd, (void *)&mMaxZoom) == true){ |
| LOGD("Maximum zoom value is %d", mMaxZoom); |
| mParameters.set("zoom-supported", "true"); |
| } else { |
| LOGE("Failed to get maximum zoom value...setting max zoom to zero"); |
| mParameters.set("zoom-supported", "false"); |
| mMaxZoom = 0; |
| } |
| mParameters.set("max-zoom",mMaxZoom); |
| |
| //Initialize AF state to AF_NOTSTARTED |
| mAfLock.lock(); |
| mAfState = AF_NOTSTARTED; |
| mAfLock.unlock(); |
| |
| LOGV("startPreviewInternal X"); |
| return NO_ERROR; |
| } |
| |
| status_t QualcommCameraHardware::startPreview() |
| { |
| LOGV("startPreview E"); |
| Mutex::Autolock l(&mLock); |
| return startPreviewInternal(); |
| } |
| |
| void QualcommCameraHardware::stopPreviewInternal() |
| { |
| LOGV("stopPreviewInternal E: %d", mCameraRunning); |
| if (mCameraRunning) { |
| // Cancel auto focus. |
| { |
| if (mNotifyCallback && (mMsgEnabled & CAMERA_MSG_FOCUS)) { |
| cancelAutoFocusInternal(); |
| } |
| } |
| |
| Mutex::Autolock l(&mCamframeTimeoutLock); |
| if(!camframe_timeout_flag) { |
| if (( mCurrentTarget != TARGET_MSM7630 ) && (mCurrentTarget != TARGET_QSD8250)) |
| mCameraRunning = !native_stop_preview(mCameraControlFd); |
| else |
| mCameraRunning = !native_stop_video(mCameraControlFd); |
| |
| } else { |
| /* This means that the camframetimeout was issued. |
| * But we did not issue native_stop_preview(), so we |
| * need to update mCameraRunning to indicate that |
| * Camera is no longer running. */ |
| mCameraRunning = 0; |
| } |
| if (!mCameraRunning && mPreviewInitialized) { |
| deinitPreview(); |
| if( ( mCurrentTarget == TARGET_MSM7630 ) || (mCurrentTarget == TARGET_QSD8250)) { |
| mVideoThreadWaitLock.lock(); |
| LOGV("in stopPreviewInternal: making mVideoThreadExit 1"); |
| mVideoThreadExit = 1; |
| mVideoThreadWaitLock.unlock(); |
| // 720p : signal the video thread , and check in video thread if stop is called, if so exit video thread. |
| pthread_mutex_lock(&(g_busy_frame_queue.mut)); |
| pthread_cond_signal(&(g_busy_frame_queue.wait)); |
| pthread_mutex_unlock(&(g_busy_frame_queue.mut)); |
| } |
| mPreviewInitialized = false; |
| } |
| else LOGE("stopPreviewInternal: failed to stop preview"); |
| } |
| LOGV("stopPreviewInternal X: %d", mCameraRunning); |
| } |
| |
| void QualcommCameraHardware::stopPreview() |
| { |
| LOGV("stopPreview: E"); |
| Mutex::Autolock l(&mLock); |
| { |
| if (mDataCallbackTimestamp && (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)) |
| return; |
| } |
| stopPreviewInternal(); |
| LOGV("stopPreview: X"); |
| } |
| |
| void QualcommCameraHardware::runAutoFocus() |
| { |
| bool status = true; |
| void *libhandle = NULL; |
| isp3a_af_mode_t afMode; |
| |
| mAutoFocusThreadLock.lock(); |
| // Skip autofocus if focus mode is infinity. |
| if (strcmp(mParameters.get(CameraParameters::KEY_FOCUS_MODE), |
| CameraParameters::FOCUS_MODE_INFINITY) == 0) { |
| goto done; |
| } |
| |
| mAutoFocusFd = open(MSM_CAMERA_CONTROL, O_RDWR); |
| if (mAutoFocusFd < 0) { |
| LOGE("autofocus: cannot open %s: %s", |
| MSM_CAMERA_CONTROL, |
| strerror(errno)); |
| mAutoFocusThreadRunning = false; |
| mAutoFocusThreadLock.unlock(); |
| return; |
| } |
| |
| #if DLOPEN_LIBMMCAMERA |
| // We need to maintain a reference to libqcamera.so for the duration of the |
| // AF thread, because we do not know when it will exit relative to the |
| // lifetime of this object. We do not want to dlclose() libqcamera while |
| // LINK_cam_frame is still running. |
| libhandle = ::dlopen("liboemcamera.so", RTLD_NOW); |
| LOGV("AF: loading libqcamera at %p", libhandle); |
| if (!libhandle) { |
| LOGE("FATAL ERROR: could not dlopen liboemcamera.so: %s", dlerror()); |
| close(mAutoFocusFd); |
| mAutoFocusFd = -1; |
| mAutoFocusThreadRunning = false; |
| mAutoFocusThreadLock.unlock(); |
| return; |
| } |
| #endif |
| |
| afMode = (isp3a_af_mode_t)attr_lookup(focus_modes, |
| sizeof(focus_modes) / sizeof(str_map), |
| mParameters.get(CameraParameters::KEY_FOCUS_MODE)); |
| |
| /* This will block until either AF completes or is cancelled. */ |
| LOGV("af start (fd %d mode %d)", mAutoFocusFd, afMode); |
| status_t err; |
| err = mAfLock.tryLock(); |
| if(err == NO_ERROR) { |
| //Got Lock, so start AF if required. |
| if(mAfState != AF_CANCELLED) { |
| mAfState = AF_STARTED; |
| LOGV("Start AF"); |
| status = native_set_afmode(mAutoFocusFd, afMode); |
| } else { |
| status = FALSE; |
| } |
| mAfLock.unlock(); |
| } |
| else{ |
| //AF Cancel would have acquired the lock, |
| //so, no need to perform any AF |
| LOGV("Failed to obtain Lock...is busy"); |
| status = FALSE; |
| } |
| |
| LOGV("af done: %d", (int)status); |
| close(mAutoFocusFd); |
| mAutoFocusFd = -1; |
| |
| done: |
| mAutoFocusThreadRunning = false; |
| mAutoFocusThreadLock.unlock(); |
| |
| mCallbackLock.lock(); |
| bool autoFocusEnabled = mNotifyCallback && (mMsgEnabled & CAMERA_MSG_FOCUS); |
| notify_callback cb = mNotifyCallback; |
| void *data = mCallbackCookie; |
| mCallbackLock.unlock(); |
| if (autoFocusEnabled) |
| cb(CAMERA_MSG_FOCUS, status, 0, data); |
| |
| #if DLOPEN_LIBMMCAMERA |
| if (libhandle) { |
| ::dlclose(libhandle); |
| LOGV("AF: dlclose(libqcamera)"); |
| } |
| #endif |
| } |
| |
| status_t QualcommCameraHardware::cancelAutoFocusInternal() |
| { |
| LOGV("cancelAutoFocusInternal E"); |
| |
| if(!sensorType->hasAutoFocusSupport){ |
| LOGV("cancelAutoFocusInternal X"); |
| return NO_ERROR; |
| } |
| |
| #if 0 |
| if (mAutoFocusFd < 0) { |
| LOGV("cancelAutoFocusInternal X: not in progress"); |
| return NO_ERROR; |
| } |
| #endif |
| |
| status_t rc = NO_ERROR; |
| status_t err; |
| err = mAfLock.tryLock(); |
| if(err == NO_ERROR) { |
| //Got Lock, means either AF hasn't started or |
| // AF is done. So no need to cancel it, just change the state |
| LOGV("Change AF State to Cancelled"); |
| mAfState = AF_CANCELLED; |
| mAfLock.unlock(); |
| } |
| else { |
| //AF is in Progess, So cancel it |
| LOGV("Lock busy...cancel AF"); |
| rc = native_cancel_afmode(mCameraControlFd, mAutoFocusFd) ? |
| NO_ERROR : |
| UNKNOWN_ERROR; |
| } |
| |
| |
| |
| LOGV("cancelAutoFocusInternal X: %d", rc); |
| return rc; |
| } |
| |
| void *auto_focus_thread(void *user) |
| { |
| LOGV("auto_focus_thread E"); |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->runAutoFocus(); |
| } |
| else LOGW("not starting autofocus: the object went away!"); |
| LOGV("auto_focus_thread X"); |
| return NULL; |
| } |
| |
| status_t QualcommCameraHardware::autoFocus() |
| { |
| LOGV("autoFocus E"); |
| Mutex::Autolock l(&mLock); |
| |
| if(!sensorType->hasAutoFocusSupport){ |
| bool status = false; |
| mCallbackLock.lock(); |
| bool autoFocusEnabled = mNotifyCallback && (mMsgEnabled & CAMERA_MSG_FOCUS); |
| notify_callback cb = mNotifyCallback; |
| void *data = mCallbackCookie; |
| mCallbackLock.unlock(); |
| if (autoFocusEnabled) |
| cb(CAMERA_MSG_FOCUS, status, 0, data); |
| LOGV("autoFocus X"); |
| return NO_ERROR; |
| } |
| |
| if (mCameraControlFd < 0) { |
| LOGE("not starting autofocus: main control fd %d", mCameraControlFd); |
| return UNKNOWN_ERROR; |
| } |
| |
| { |
| mAutoFocusThreadLock.lock(); |
| if (!mAutoFocusThreadRunning) { |
| if (native_prepare_snapshot(mCameraControlFd) == FALSE) { |
| LOGE("native_prepare_snapshot failed!\n"); |
| mAutoFocusThreadLock.unlock(); |
| return UNKNOWN_ERROR; |
| } |
| |
| // Create a detached thread here so that we don't have to wait |
| // for it when we cancel AF. |
| pthread_t thr; |
| pthread_attr_t attr; |
| pthread_attr_init(&attr); |
| pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
| mAutoFocusThreadRunning = |
| !pthread_create(&thr, &attr, |
| auto_focus_thread, NULL); |
| if (!mAutoFocusThreadRunning) { |
| LOGE("failed to start autofocus thread"); |
| mAutoFocusThreadLock.unlock(); |
| return UNKNOWN_ERROR; |
| } |
| } |
| mAutoFocusThreadLock.unlock(); |
| } |
| |
| LOGV("autoFocus X"); |
| return NO_ERROR; |
| } |
| |
| status_t QualcommCameraHardware::cancelAutoFocus() |
| { |
| LOGV("cancelAutoFocus E"); |
| Mutex::Autolock l(&mLock); |
| |
| int rc = NO_ERROR; |
| if (mCameraRunning && mNotifyCallback && (mMsgEnabled & CAMERA_MSG_FOCUS)) { |
| rc = cancelAutoFocusInternal(); |
| } |
| |
| LOGV("cancelAutoFocus X"); |
| return rc; |
| } |
| |
| void QualcommCameraHardware::runSnapshotThread(void *data) |
| { |
| LOGV("runSnapshotThread E"); |
| if(mSnapshotFormat == PICTURE_FORMAT_JPEG){ |
| if (native_start_snapshot(mCameraControlFd)) |
| receiveRawPicture(); |
| else |
| LOGE("main: native_start_snapshot failed!"); |
| } else if(mSnapshotFormat == PICTURE_FORMAT_RAW){ |
| if(native_start_raw_snapshot(mCameraControlFd)){ |
| receiveRawSnapshot(); |
| } else { |
| LOGE("main: native_start_raw_snapshot failed!"); |
| } |
| } |
| |
| mSnapshotFormat = 0; |
| |
| mSnapshotThreadWaitLock.lock(); |
| mSnapshotThreadRunning = false; |
| mSnapshotThreadWait.signal(); |
| mSnapshotThreadWaitLock.unlock(); |
| |
| LOGV("runSnapshotThread X"); |
| } |
| |
| void *snapshot_thread(void *user) |
| { |
| LOGD("snapshot_thread E"); |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->runSnapshotThread(user); |
| } |
| else LOGW("not starting snapshot thread: the object went away!"); |
| LOGD("snapshot_thread X"); |
| return NULL; |
| } |
| |
| status_t QualcommCameraHardware::takePicture() |
| { |
| LOGV("takePicture(%d)", mMsgEnabled); |
| Mutex::Autolock l(&mLock); |
| |
| // Wait for old snapshot thread to complete. |
| mSnapshotThreadWaitLock.lock(); |
| while (mSnapshotThreadRunning) { |
| LOGV("takePicture: waiting for old snapshot thread to complete."); |
| mSnapshotThreadWait.wait(mSnapshotThreadWaitLock); |
| LOGV("takePicture: old snapshot thread completed."); |
| } |
| |
| if( mCurrentTarget == TARGET_MSM7630 ) { |
| /* Store the last frame queued for preview. This |
| * shall be used as postview */ |
| storePreviewFrameForPostview(); |
| } |
| |
| //mSnapshotFormat is protected by mSnapshotThreadWaitLock |
| if(mParameters.getPictureFormat() != 0 && |
| !strcmp(mParameters.getPictureFormat(), |
| CameraParameters::PIXEL_FORMAT_RAW)) |
| mSnapshotFormat = PICTURE_FORMAT_RAW; |
| else |
| mSnapshotFormat = PICTURE_FORMAT_JPEG; |
| |
| if(mSnapshotFormat == PICTURE_FORMAT_JPEG){ |
| if(!native_prepare_snapshot(mCameraControlFd)) { |
| mSnapshotThreadWaitLock.unlock(); |
| return UNKNOWN_ERROR; |
| } |
| } |
| |
| stopPreviewInternal(); |
| |
| if(mSnapshotFormat == PICTURE_FORMAT_JPEG){ |
| if (!initRaw(mDataCallback && (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE))) { |
| LOGE("initRaw failed. Not taking picture."); |
| mSnapshotThreadWaitLock.unlock(); |
| return UNKNOWN_ERROR; |
| } |
| } else if(mSnapshotFormat == PICTURE_FORMAT_RAW ){ |
| if(!initRawSnapshot()){ |
| LOGE("initRawSnapshot failed. Not taking picture."); |
| mSnapshotThreadWaitLock.unlock(); |
| return UNKNOWN_ERROR; |
| } |
| } |
| |
| mShutterLock.lock(); |
| mShutterPending = true; |
| mShutterLock.unlock(); |
| |
| pthread_attr_t attr; |
| pthread_attr_init(&attr); |
| pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
| mSnapshotThreadRunning = !pthread_create(&mSnapshotThread, |
| &attr, |
| snapshot_thread, |
| NULL); |
| mSnapshotThreadWaitLock.unlock(); |
| |
| LOGV("takePicture: X"); |
| return mSnapshotThreadRunning ? NO_ERROR : UNKNOWN_ERROR; |
| } |
| |
| status_t QualcommCameraHardware::cancelPicture() |
| { |
| status_t rc; |
| LOGV("cancelPicture: E"); |
| rc = native_stop_snapshot(mCameraControlFd) ? NO_ERROR : UNKNOWN_ERROR; |
| LOGV("cancelPicture: X: %d", rc); |
| return rc; |
| } |
| |
| status_t QualcommCameraHardware::setParameters(const CameraParameters& params) |
| { |
| LOGV("setParameters: E params = %p", ¶ms); |
| |
| Mutex::Autolock l(&mLock); |
| status_t rc, final_rc = NO_ERROR; |
| |
| if ((rc = setPreviewSize(params))) final_rc = rc; |
| if ((rc = setPictureSize(params))) final_rc = rc; |
| if ((rc = setJpegQuality(params))) final_rc = rc; |
| if ((rc = setAntibanding(params))) final_rc = rc; |
| if ((rc = setEffect(params))) final_rc = rc; |
| if ((rc = setAutoExposure(params))) final_rc = rc; |
| if ((rc = setWhiteBalance(params))) final_rc = rc; |
| if ((rc = setFlash(params))) final_rc = rc; |
| if ((rc = setGpsLocation(params))) final_rc = rc; |
| if ((rc = setRotation(params))) final_rc = rc; |
| if ((rc = setZoom(params))) final_rc = rc; |
| if ((rc = setFocusMode(params))) final_rc = rc; |
| if ((rc = setOrientation(params))) final_rc = rc; |
| if ((rc = setBrightness(params))) final_rc = rc; |
| if ((rc = setLensshadeValue(params))) final_rc = rc; |
| if ((rc = setISOValue(params))) final_rc = rc; |
| if ((rc = setPictureFormat(params))) final_rc = rc; |
| if ((rc = setSharpness(params))) final_rc = rc; |
| if ((rc = setContrast(params))) final_rc = rc; |
| if ((rc = setSaturation(params))) final_rc = rc; |
| |
| LOGV("setParameters: X"); |
| return final_rc; |
| } |
| |
| CameraParameters QualcommCameraHardware::getParameters() const |
| { |
| LOGV("getParameters: EX"); |
| return mParameters; |
| } |
| |
| status_t QualcommCameraHardware::sendCommand(int32_t command, int32_t arg1, |
| int32_t arg2) |
| { |
| LOGV("sendCommand: EX"); |
| return BAD_VALUE; |
| } |
| |
| extern "C" sp<CameraHardwareInterface> openCameraHardware() |
| { |
| LOGV("openCameraHardware: call createInstance"); |
| return QualcommCameraHardware::createInstance(); |
| } |
| |
| wp<QualcommCameraHardware> QualcommCameraHardware::singleton; |
| |
| // If the hardware already exists, return a strong pointer to the current |
| // object. If not, create a new hardware object, put it in the singleton, |
| // and return it. |
| sp<CameraHardwareInterface> QualcommCameraHardware::createInstance() |
| { |
| LOGD("createInstance: E"); |
| |
| Mutex::Autolock lock(&singleton_lock); |
| |
| // Wait until the previous release is done. |
| while (singleton_releasing) { |
| LOGD("Wait for previous release."); |
| singleton_wait.wait(singleton_lock); |
| } |
| |
| if (singleton != 0) { |
| sp<CameraHardwareInterface> hardware = singleton.promote(); |
| if (hardware != 0) { |
| LOGD("createInstance: X return existing hardware=%p", &(*hardware)); |
| return hardware; |
| } |
| } |
| |
| { |
| struct stat st; |
| int rc = stat("/dev/oncrpc", &st); |
| if (rc < 0) { |
| LOGD("createInstance: X failed to create hardware: %s", strerror(errno)); |
| return NULL; |
| } |
| } |
| |
| QualcommCameraHardware *cam = new QualcommCameraHardware(); |
| sp<QualcommCameraHardware> hardware(cam); |
| singleton = hardware; |
| |
| if (!cam->startCamera()) { |
| LOGE("%s: startCamera failed!", __FUNCTION__); |
| return NULL; |
| } |
| |
| cam->initDefaultParameters(); |
| LOGD("createInstance: X created hardware=%p", &(*hardware)); |
| return hardware; |
| } |
| |
| // For internal use only, hence the strong pointer to the derived type. |
| sp<QualcommCameraHardware> QualcommCameraHardware::getInstance() |
| { |
| sp<CameraHardwareInterface> hardware = singleton.promote(); |
| if (hardware != 0) { |
| // LOGV("getInstance: X old instance of hardware"); |
| return sp<QualcommCameraHardware>(static_cast<QualcommCameraHardware*>(hardware.get())); |
| } else { |
| LOGV("getInstance: X new instance of hardware"); |
| return sp<QualcommCameraHardware>(); |
| } |
| } |
| void QualcommCameraHardware::receiveRecordingFrame(struct msm_frame *frame) |
| { |
| LOGV("receiveRecordingFrame E"); |
| // post busy frame |
| if (frame) |
| { |
| cam_frame_post_video (frame); |
| } |
| else LOGE("in receiveRecordingFrame frame is NULL"); |
| LOGV("receiveRecordingFrame X"); |
| } |
| |
| |
| bool QualcommCameraHardware::native_zoom_image(int fd, int srcOffset, int dstOffSet, common_crop_t *crop) |
| { |
| int result = 0; |
| struct mdp_blit_req *e; |
| struct timeval td1, td2; |
| |
| /* Initialize yuv structure */ |
| zoomImage.list.count = 1; |
| |
| e = &zoomImage.list.req[0]; |
| |
| e->src.width = previewWidth; |
| e->src.height = previewHeight; |
| e->src.format = MDP_Y_CBCR_H2V2; |
| e->src.offset = srcOffset; |
| e->src.memory_id = fd; |
| |
| e->dst.width = previewWidth; |
| e->dst.height = previewHeight; |
| e->dst.format = MDP_Y_CBCR_H2V2; |
| e->dst.offset = dstOffSet; |
| e->dst.memory_id = fd; |
| |
| e->transp_mask = 0xffffffff; |
| e->flags = 0; |
| e->alpha = 0xff; |
| if (crop->in2_w != 0 || crop->in2_h != 0) { |
| e->src_rect.x = (crop->out2_w - crop->in2_w + 1) / 2 - 1; |
| e->src_rect.y = (crop->out2_h - crop->in2_h + 1) / 2 - 1; |
| e->src_rect.w = crop->in2_w; |
| e->src_rect.h = crop->in2_h; |
| } else { |
| e->src_rect.x = 0; |
| e->src_rect.y = 0; |
| e->src_rect.w = previewWidth; |
| e->src_rect.h = previewHeight; |
| } |
| //LOGV(" native_zoom : SRC_RECT : x,y = %d,%d \t w,h = %d, %d", |
| // e->src_rect.x, e->src_rect.y, e->src_rect.w, e->src_rect.h); |
| |
| e->dst_rect.x = 0; |
| e->dst_rect.y = 0; |
| e->dst_rect.w = previewWidth; |
| e->dst_rect.h = previewHeight; |
| |
| result = ioctl(fb_fd, MSMFB_BLIT, &zoomImage.list); |
| if (result < 0) { |
| LOGE("MSM_FBIOBLT failed! line=%d\n", __LINE__); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| void QualcommCameraHardware::debugShowPreviewFPS() const |
| { |
| static int mFrameCount; |
| static int mLastFrameCount = 0; |
| static nsecs_t mLastFpsTime = 0; |
| static float mFps = 0; |
| mFrameCount++; |
| nsecs_t now = systemTime(); |
| nsecs_t diff = now - mLastFpsTime; |
| if (diff > ms2ns(250)) { |
| mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; |
| LOGI("Preview Frames Per Second: %.4f", mFps); |
| mLastFpsTime = now; |
| mLastFrameCount = mFrameCount; |
| } |
| } |
| |
| void QualcommCameraHardware::debugShowVideoFPS() const |
| { |
| static int mFrameCount; |
| static int mLastFrameCount = 0; |
| static nsecs_t mLastFpsTime = 0; |
| static float mFps = 0; |
| mFrameCount++; |
| nsecs_t now = systemTime(); |
| nsecs_t diff = now - mLastFpsTime; |
| if (diff > ms2ns(250)) { |
| mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; |
| LOGI("Video Frames Per Second: %.4f", mFps); |
| mLastFpsTime = now; |
| mLastFrameCount = mFrameCount; |
| } |
| } |
| void QualcommCameraHardware::receivePreviewFrame(struct msm_frame *frame) |
| { |
| // LOGV("receivePreviewFrame E"); |
| |
| if (!mCameraRunning) { |
| LOGE("ignoring preview callback--camera has been stopped"); |
| return; |
| } |
| |
| if (UNLIKELY(mDebugFps)) { |
| debugShowPreviewFPS(); |
| } |
| |
| mCallbackLock.lock(); |
| int msgEnabled = mMsgEnabled; |
| data_callback pcb = mDataCallback; |
| void *pdata = mCallbackCookie; |
| data_callback_timestamp rcb = mDataCallbackTimestamp; |
| void *rdata = mCallbackCookie; |
| mCallbackLock.unlock(); |
| |
| // Find the offset within the heap of the current buffer. |
| ssize_t offset_addr = |
| (ssize_t)frame->buffer - (ssize_t)mPreviewHeap->mHeap->base(); |
| ssize_t offset = offset_addr / mPreviewHeap->mAlignedBufferSize; |
| |
| common_crop_t *crop = (common_crop_t *) (frame->cropinfo); |
| |
| mInPreviewCallback = true; |
| if(mUseOverlay) { |
| if(mOverlay != NULL) { |
| mOverlayLock.lock(); |
| mOverlay->setFd(mPreviewHeap->mHeap->getHeapID()); |
| if (crop->in2_w != 0 || crop->in2_h != 0) { |
| zoomCropInfo.x = (crop->out2_w - crop->in2_w + 1) / 2 - 1; |
| zoomCropInfo.y = (crop->out2_h - crop->in2_h + 1) / 2 - 1; |
| zoomCropInfo.w = crop->in2_w; |
| zoomCropInfo.h = crop->in2_h; |
| mOverlay->setCrop(zoomCropInfo.x, zoomCropInfo.y, |
| zoomCropInfo.w, zoomCropInfo.h); |
| } else { |
| // Reset zoomCropInfo variables. This will ensure that |
| // stale values wont be used for postview |
| zoomCropInfo.w = crop->in2_w; |
| zoomCropInfo.h = crop->in2_h; |
| } |
| mOverlay->queueBuffer((void *)offset_addr); |
| mLastQueuedFrame = (void *)frame->buffer; |
| mOverlayLock.unlock(); |
| } |
| } else { |
| if (crop->in2_w != 0 || crop->in2_h != 0) { |
| dstOffset = (dstOffset + 1) % NUM_MORE_BUFS; |
| offset = kPreviewBufferCount + dstOffset; |
| ssize_t dstOffset_addr = offset * mPreviewHeap->mAlignedBufferSize; |
| if( !native_zoom_image(mPreviewHeap->mHeap->getHeapID(), |
| offset_addr, dstOffset_addr, crop)) { |
| LOGE(" Error while doing MDP zoom "); |
| } |
| } |
| } |
| if (pcb != NULL && (msgEnabled & CAMERA_MSG_PREVIEW_FRAME)) |
| pcb(CAMERA_MSG_PREVIEW_FRAME, mPreviewHeap->mBuffers[offset], |
| pdata); |
| |
| // If output2 enabled, Start Recording if recording is enabled by Services |
| if( ((mCurrentTarget == TARGET_MSM7630) || (mCurrentTarget == TARGET_QSD8250)) && recordingEnabled() ) { |
| if(!recordingState){ |
| recordingState = 1; // recording started |
| LOGV(" in receivePreviewframe : recording enabled calling startRecording "); |
| startRecording(); |
| } |
| } |
| |
| // If output is NOT enabled (targets otherthan 7x30 currently..) |
| if( (mCurrentTarget != TARGET_MSM7630 ) && (mCurrentTarget != TARGET_QSD8250)) { |
| if(rcb != NULL && (msgEnabled & CAMERA_MSG_VIDEO_FRAME)) { |
| rcb(systemTime(), CAMERA_MSG_VIDEO_FRAME, mPreviewHeap->mBuffers[offset], rdata); |
| Mutex::Autolock rLock(&mRecordFrameLock); |
| if (mReleasedRecordingFrame != true) { |
| LOGV("block waiting for frame release"); |
| mRecordWait.wait(mRecordFrameLock); |
| LOGV("frame released, continuing"); |
| } |
| mReleasedRecordingFrame = false; |
| } |
| } |
| mInPreviewCallback = false; |
| |
| // LOGV("receivePreviewFrame X"); |
| } |
| |
| |
| bool QualcommCameraHardware::initRecord() |
| { |
| LOGV("initREcord E"); |
| |
| mRecordFrameSize = (mDimension.video_width * mDimension.video_height *3)/2; |
| mRecordHeap = new PmemPool("/dev/pmem_adsp", |
| MemoryHeapBase::READ_ONLY | MemoryHeapBase::NO_CACHING, |
| mCameraControlFd, |
| MSM_PMEM_VIDEO, |
| mRecordFrameSize, |
| kRecordBufferCount, |
| mRecordFrameSize, |
| "record"); |
| if (!mRecordHeap->initialized()) { |
| mRecordHeap.clear(); |
| LOGE("initRecord X: could not initialize record heap."); |
| return false; |
| } |
| for (int cnt = 0; cnt < kRecordBufferCount; cnt++) { |
| recordframes[cnt].fd = mRecordHeap->mHeap->getHeapID(); |
| recordframes[cnt].buffer = |
| (uint32_t)mRecordHeap->mHeap->base() + mRecordHeap->mAlignedBufferSize * cnt; |
| recordframes[cnt].y_off = 0; |
| recordframes[cnt].cbcr_off = mDimension.video_width * mDimension.video_height; |
| recordframes[cnt].path = OUTPUT_TYPE_V; |
| |
| LOGV ("initRecord : record heap , video buffers buffer=%lu fd=%d y_off=%d cbcr_off=%d \n", |
| (unsigned long)recordframes[cnt].buffer, recordframes[cnt].fd, recordframes[cnt].y_off, |
| recordframes[cnt].cbcr_off); |
| } |
| |
| // initial setup : buffers 1,2,3 with kernel , 4 with camframe , 5,6,7,8 in free Q |
| // flush the busy Q |
| cam_frame_flush_video(); |
| |
| mVideoThreadWaitLock.lock(); |
| while (mVideoThreadRunning) { |
| LOGV("initRecord: waiting for old video thread to complete."); |
| mVideoThreadWait.wait(mVideoThreadWaitLock); |
| LOGV("initRecord : old video thread completed."); |
| } |
| mVideoThreadWaitLock.unlock(); |
| |
| // flush free queue and add 5,6,7,8 buffers. |
| LINK_cam_frame_flush_free_video(); |
| for(int i=ACTIVE_VIDEO_BUFFERS+1;i <kRecordBufferCount; i++) |
| LINK_camframe_free_video(&recordframes[i]); |
| LOGV("initREcord X"); |
| |
| return true; |
| } |
| |
| status_t QualcommCameraHardware::startRecording() |
| { |
| LOGV("startRecording E"); |
| int ret; |
| Mutex::Autolock l(&mLock); |
| mReleasedRecordingFrame = false; |
| if( (ret=startPreviewInternal())== NO_ERROR){ |
| if( ( mCurrentTarget == TARGET_MSM7630 ) || (mCurrentTarget == TARGET_QSD8250)) { |
| LOGV(" in startREcording : calling native_start_recording"); |
| native_start_recording(mCameraControlFd); |
| recordingState = 1; |
| // Start video thread and wait for busy frames to be encoded, this thread |
| // should be closed in stopRecording |
| mVideoThreadWaitLock.lock(); |
| mVideoThreadExit = 0; |
| pthread_attr_t attr; |
| pthread_attr_init(&attr); |
| pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
| mVideoThreadRunning = pthread_create(&mVideoThread, |
| &attr, |
| video_thread, |
| NULL); |
| mVideoThreadWaitLock.unlock(); |
| // Remove the left out frames in busy Q and them in free Q. |
| LOGV("frames in busy Q = %d", g_busy_frame_queue.num_of_frames); |
| while((g_busy_frame_queue.num_of_frames) >0){ |
| msm_frame* vframe = cam_frame_get_video (); |
| LINK_camframe_free_video(vframe); |
| } |
| LOGV("frames in busy Q = %d after deQueing", g_busy_frame_queue.num_of_frames); |
| } |
| } |
| return ret; |
| } |
| |
| void QualcommCameraHardware::stopRecording() |
| { |
| LOGV("stopRecording: E"); |
| Mutex::Autolock l(&mLock); |
| { |
| mRecordFrameLock.lock(); |
| mReleasedRecordingFrame = true; |
| mRecordWait.signal(); |
| mRecordFrameLock.unlock(); |
| |
| if(mDataCallback && !(mCurrentTarget == TARGET_QSD8250) && |
| (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)) { |
| LOGV("stopRecording: X, preview still in progress"); |
| return; |
| } |
| } |
| // If output2 enabled, exit video thread, invoke stop recording ioctl |
| if( ( mCurrentTarget == TARGET_MSM7630 ) || (mCurrentTarget == TARGET_QSD8250)) { |
| mVideoThreadWaitLock.lock(); |
| mVideoThreadExit = 1; |
| mVideoThreadWaitLock.unlock(); |
| native_stop_recording(mCameraControlFd); |
| } |
| else // for other targets where output2 is not enabled |
| stopPreviewInternal(); |
| |
| recordingState = 0; // recording not started |
| LOGV("stopRecording: X"); |
| } |
| |
| void QualcommCameraHardware::releaseRecordingFrame( |
| const sp<IMemory>& mem __attribute__((unused))) |
| { |
| LOGV("releaseRecordingFrame E"); |
| Mutex::Autolock rLock(&mRecordFrameLock); |
| mReleasedRecordingFrame = true; |
| mRecordWait.signal(); |
| |
| // Ff 7x30 : add the frame to the free camframe queue |
| if( (mCurrentTarget == TARGET_MSM7630 ) || (mCurrentTarget == TARGET_QSD8250)) { |
| ssize_t offset; |
| size_t size; |
| sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); |
| msm_frame* releaseframe = NULL; |
| LOGV(" in release recording frame : heap base %d offset %d buffer %d ", heap->base(), offset, heap->base() + offset ); |
| int cnt; |
| for (cnt = 0; cnt < kRecordBufferCount; cnt++) { |
| if((unsigned int)recordframes[cnt].buffer == (unsigned int)(heap->base()+ offset)){ |
| LOGV("in release recording frame found match , releasing buffer %d", (unsigned int)recordframes[cnt].buffer); |
| releaseframe = &recordframes[cnt]; |
| break; |
| } |
| } |
| if(cnt < kRecordBufferCount) { |
| // do this only if frame thread is running |
| mFrameThreadWaitLock.lock(); |
| if(mFrameThreadRunning ) |
| LINK_camframe_free_video(releaseframe); |
| |
| mFrameThreadWaitLock.unlock(); |
| } else { |
| LOGE("in release recordingframe XXXXX error , buffer not found"); |
| for (int i=0; i< kRecordBufferCount; i++) { |
| LOGE(" recordframes[%d].buffer = %d", i, (unsigned int)recordframes[i].buffer); |
| } |
| } |
| } |
| |
| LOGV("releaseRecordingFrame X"); |
| } |
| |
| bool QualcommCameraHardware::recordingEnabled() |
| { |
| return mCameraRunning && mDataCallbackTimestamp && (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME); |
| } |
| |
| void QualcommCameraHardware::notifyShutter(common_crop_t *crop) |
| { |
| mShutterLock.lock(); |
| image_rect_type size; |
| |
| if (mShutterPending && mNotifyCallback && (mMsgEnabled & CAMERA_MSG_SHUTTER)) { |
| LOGV("out2_w=%d, out2_h=%d, in2_w=%d, in2_h=%d", |
| crop->out2_w, crop->out2_h, crop->in2_w, crop->in2_h); |
| LOGV("out1_w=%d, out1_h=%d, in1_w=%d, in1_h=%d", |
| crop->out1_w, crop->out1_h, crop->in1_w, crop->in1_h); |
| |
| // To workaround a bug in MDP which happens if either |
| // dimension > 2048, we display the thumbnail instead. |
| mDisplayHeap = mRawHeap; |
| if (crop->in1_w == 0 || crop->in1_h == 0) { |
| // Full size |
| size.width = mDimension.picture_width; |
| size.height = mDimension.picture_height; |
| if (size.width > 2048 || size.height > 2048) { |
| size.width = mDimension.ui_thumbnail_width; |
| size.height = mDimension.ui_thumbnail_height; |
| mDisplayHeap = mThumbnailHeap; |
| } |
| } else { |
| // Cropped |
| size.width = (crop->in2_w + JPEG_ENCODER_PADDING) & ~1; |
| size.height = (crop->in2_h + JPEG_ENCODER_PADDING) & ~1; |
| if (size.width > 2048 || size.height > 2048) { |
| size.width = (crop->in1_w + JPEG_ENCODER_PADDING) & ~1; |
| size.height = (crop->in1_h + JPEG_ENCODER_PADDING) & ~1; |
| mDisplayHeap = mThumbnailHeap; |
| } |
| } |
| |
| mNotifyCallback(CAMERA_MSG_SHUTTER, (int32_t)&size, 0, |
| mCallbackCookie); |
| mShutterPending = false; |
| } |
| mShutterLock.unlock(); |
| } |
| |
| static void receive_shutter_callback(common_crop_t *crop) |
| { |
| LOGV("receive_shutter_callback: E"); |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->notifyShutter(crop); |
| } |
| LOGV("receive_shutter_callback: X"); |
| } |
| |
| // Crop the picture in place. |
| static void crop_yuv420(uint32_t width, uint32_t height, |
| uint32_t cropped_width, uint32_t cropped_height, |
| uint8_t *image) |
| { |
| uint32_t i, x, y; |
| uint8_t* chroma_src, *chroma_dst; |
| |
| // Calculate the start position of the cropped area. |
| x = (width - cropped_width) / 2; |
| y = (height - cropped_height) / 2; |
| x &= ~1; |
| y &= ~1; |
| |
| // Copy luma component. |
| for(i = 0; i < cropped_height; i++) |
| memcpy(image + i * cropped_width, |
| image + width * (y + i) + x, |
| cropped_width); |
| |
| chroma_src = image + width * height; |
| chroma_dst = image + cropped_width * cropped_height; |
| |
| // Copy chroma components. |
| cropped_height /= 2; |
| y /= 2; |
| for(i = 0; i < cropped_height; i++) |
| memcpy(chroma_dst + i * cropped_width, |
| chroma_src + width * (y + i) + x, |
| cropped_width); |
| } |
| |
| |
| void QualcommCameraHardware::receiveRawSnapshot(){ |
| LOGV("receiveRawSnapshot E"); |
| |
| Mutex::Autolock cbLock(&mCallbackLock); |
| |
| notifyShutter(&mCrop); |
| |
| if (mDataCallback && (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE)) { |
| |
| if(native_get_picture(mCameraControlFd, &mCrop) == false) { |
| LOGE("receiveRawSnapshot X: native_get_picture failed!"); |
| return; |
| } |
| |
| //Create a Ashmem heap to copy data from PMem heap for application layer |
| if(mRawSnapshotAshmemHeap != NULL){ |
| LOGV("receiveRawSnapshot: clearing old mRawSnapShotAshmemHeap."); |
| mRawSnapshotAshmemHeap.clear(); |
| } |
| mRawSnapshotAshmemHeap = new AshmemPool( |
| mRawSnapShotPmemHeap->mBufferSize, |
| mRawSnapShotPmemHeap->mNumBuffers, |
| mRawSnapShotPmemHeap->mFrameSize, |
| "raw ashmem snapshot camera" |
| ); |
| |
| if(!mRawSnapshotAshmemHeap->initialized()){ |
| LOGE("receiveRawSnapshot X: error initializing mRawSnapshotHeap"); |
| deinitRawSnapshot(); |
| return; |
| } |
| |
| memcpy(mRawSnapshotAshmemHeap->mHeap->base(), |
| mRawSnapShotPmemHeap->mHeap->base(), |
| mRawSnapShotPmemHeap->mHeap->getSize()); |
| |
| mDataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mRawSnapshotAshmemHeap->mBuffers[0], |
| mCallbackCookie); |
| |
| } |
| |
| //cleanup |
| deinitRawSnapshot(); |
| |
| LOGV("receiveRawSnapshot X"); |
| } |
| |
| void QualcommCameraHardware::receiveRawPicture() |
| { |
| LOGV("receiveRawPicture: E"); |
| |
| Mutex::Autolock cbLock(&mCallbackLock); |
| if (mDataCallback && (mMsgEnabled & CAMERA_MSG_RAW_IMAGE)) { |
| if(native_get_picture(mCameraControlFd, &mCrop) == false) { |
| LOGE("getPicture failed!"); |
| return; |
| } |
| mCrop.in1_w &= ~1; |
| mCrop.in1_h &= ~1; |
| mCrop.in2_w &= ~1; |
| mCrop.in2_h &= ~1; |
| |
| // By the time native_get_picture returns, picture is taken. Call |
| // shutter callback if cam config thread has not done that. |
| notifyShutter(&mCrop); |
| |
| // Crop the image if zoomed. |
| if (mCrop.in2_w != 0 && mCrop.in2_h != 0) { |
| crop_yuv420(mCrop.out2_w, mCrop.out2_h, (mCrop.in2_w + JPEG_ENCODER_PADDING), (mCrop.in2_h + JPEG_ENCODER_PADDING), |
| (uint8_t *)mRawHeap->mHeap->base()); |
| crop_yuv420(mCrop.out1_w, mCrop.out1_h, (mCrop.in1_w + JPEG_ENCODER_PADDING), (mCrop.in1_h + JPEG_ENCODER_PADDING), |
| (uint8_t *)mThumbnailHeap->mHeap->base()); |
| // We do not need jpeg encoder to upscale the image. Set the new |
| // dimension for encoder. |
| mDimension.orig_picture_dx = mCrop.in2_w + JPEG_ENCODER_PADDING; |
| mDimension.orig_picture_dy = mCrop.in2_h + JPEG_ENCODER_PADDING; |
| mDimension.thumbnail_width = mCrop.in1_w + JPEG_ENCODER_PADDING; |
| mDimension.thumbnail_height = mCrop.in1_h + JPEG_ENCODER_PADDING; |
| } |
| |
| if( mUseOverlay && (mOverlay != NULL) ) { |
| mOverlay->setFd(mPostViewHeap->mHeap->getHeapID()); |
| if( zoomCropInfo.w !=0 && zoomCropInfo.h !=0) { |
| LOGD(" zoomCropInfo non-zero, setting crop "); |
| mOverlay->setCrop(zoomCropInfo.x, zoomCropInfo.y, |
| zoomCropInfo.w, zoomCropInfo.h); |
| } |
| LOGD(" Queueing Postview for display "); |
| mOverlay->queueBuffer((void *)0); |
| } |
| |
| mDataCallback(CAMERA_MSG_RAW_IMAGE, mDisplayHeap->mBuffers[0], |
| mCallbackCookie); |
| } |
| else LOGV("Raw-picture callback was canceled--skipping."); |
| |
| if (mDataCallback && (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE)) { |
| mJpegSize = 0; |
| if (LINK_jpeg_encoder_init()) { |
| if(native_jpeg_encode()) { |
| LOGV("receiveRawPicture: X (success)"); |
| return; |
| } |
| LOGE("jpeg encoding failed"); |
| } |
| else LOGE("receiveRawPicture X: jpeg_encoder_init failed."); |
| } |
| else LOGV("JPEG callback is NULL, not encoding image."); |
| deinitRaw(); |
| LOGV("receiveRawPicture: X"); |
| } |
| |
| void QualcommCameraHardware::receiveJpegPictureFragment( |
| uint8_t *buff_ptr, uint32_t buff_size) |
| { |
| uint32_t remaining = mJpegHeap->mHeap->virtualSize(); |
| remaining -= mJpegSize; |
| uint8_t *base = (uint8_t *)mJpegHeap->mHeap->base(); |
| |
| LOGV("receiveJpegPictureFragment size %d", buff_size); |
| if (buff_size > remaining) { |
| LOGE("receiveJpegPictureFragment: size %d exceeds what " |
| "remains in JPEG heap (%d), truncating", |
| buff_size, |
| remaining); |
| buff_size = remaining; |
| } |
| memcpy(base + mJpegSize, buff_ptr, buff_size); |
| mJpegSize += buff_size; |
| } |
| |
| void QualcommCameraHardware::receiveJpegPicture(void) |
| { |
| LOGV("receiveJpegPicture: E image (%d uint8_ts out of %d)", |
| mJpegSize, mJpegHeap->mBufferSize); |
| Mutex::Autolock cbLock(&mCallbackLock); |
| |
| int index = 0, rc; |
| |
| if (mDataCallback && (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE)) { |
| // The reason we do not allocate into mJpegHeap->mBuffers[offset] is |
| // that the JPEG image's size will probably change from one snapshot |
| // to the next, so we cannot reuse the MemoryBase object. |
| sp<MemoryBase> buffer = new |
| MemoryBase(mJpegHeap->mHeap, |
| index * mJpegHeap->mBufferSize + |
| 0, |
| mJpegSize); |
| mDataCallback(CAMERA_MSG_COMPRESSED_IMAGE, buffer, mCallbackCookie); |
| buffer = NULL; |
| } |
| else LOGV("JPEG callback was cancelled--not delivering image."); |
| |
| LINK_jpeg_encoder_join(); |
| deinitRaw(); |
| |
| LOGV("receiveJpegPicture: X callback done."); |
| } |
| |
| bool QualcommCameraHardware::previewEnabled() |
| { |
| return mCameraRunning && mDataCallback && (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME); |
| } |
| |
| status_t QualcommCameraHardware::setPreviewSize(const CameraParameters& params) |
| { |
| int width, height; |
| params.getPreviewSize(&width, &height); |
| LOGV("requested preview size %d x %d", width, height); |
| |
| // Validate the preview size |
| for (size_t i = 0; i < previewSizeCount; ++i) { |
| if (width == supportedPreviewSizes[i].width |
| && height == supportedPreviewSizes[i].height) { |
| mParameters.setPreviewSize(width, height); |
| mDimension.display_width = width; |
| mDimension.display_height = height; |
| return NO_ERROR; |
| } |
| } |
| LOGE("Invalid preview size requested: %dx%d", width, height); |
| return BAD_VALUE; |
| } |
| |
| status_t QualcommCameraHardware::setPictureSize(const CameraParameters& params) |
| { |
| int width, height; |
| params.getPictureSize(&width, &height); |
| LOGV("requested picture size %d x %d", width, height); |
| |
| // Validate the picture size |
| for (int i = 0; i < supportedPictureSizesCount; ++i) { |
| if (width == picture_sizes_ptr[i].width |
| && height == picture_sizes_ptr[i].height) { |
| mParameters.setPictureSize(width, height); |
| mDimension.picture_width = width; |
| mDimension.picture_height = height; |
| return NO_ERROR; |
| } |
| } |
| /* Dimension not among the ones in the list. Check if |
| * its a valid dimension, if it is, then configure the |
| * camera accordingly. else reject it. |
| */ |
| if( isValidDimension(width, height) ) { |
| mParameters.setPictureSize(width, height); |
| mDimension.picture_width = width; |
| mDimension.picture_height = height; |
| return NO_ERROR; |
| } else |
| LOGE("Invalid picture size requested: %dx%d", width, height); |
| return BAD_VALUE; |
| } |
| |
| status_t QualcommCameraHardware::setJpegQuality(const CameraParameters& params) { |
| status_t rc = NO_ERROR; |
| int quality = params.getInt(CameraParameters::KEY_JPEG_QUALITY); |
| if (quality > 0 && quality <= 100) { |
| mParameters.set(CameraParameters::KEY_JPEG_QUALITY, quality); |
| } else { |
| LOGE("Invalid jpeg quality=%d", quality); |
| rc = BAD_VALUE; |
| } |
| |
| quality = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); |
| if (quality > 0 && quality <= 100) { |
| mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, quality); |
| } else { |
| LOGE("Invalid jpeg thumbnail quality=%d", quality); |
| rc = BAD_VALUE; |
| } |
| return rc; |
| } |
| |
| status_t QualcommCameraHardware::setEffect(const CameraParameters& params) |
| { |
| const char *str = params.get(CameraParameters::KEY_EFFECT); |
| if (str != NULL) { |
| int32_t value = attr_lookup(effects, sizeof(effects) / sizeof(str_map), str); |
| if (value != NOT_FOUND) { |
| if(!strcmp(sensorType->name, "2mp") && (value != CAMERA_EFFECT_OFF) |
| &&(value != CAMERA_EFFECT_MONO) && (value != CAMERA_EFFECT_NEGATIVE) |
| &&(value != CAMERA_EFFECT_SOLARIZE) && (value != CAMERA_EFFECT_SEPIA)) { |
| LOGE("Special effect parameter is not supported for this sensor"); |
| return NO_ERROR; |
| } |
| mParameters.set(CameraParameters::KEY_EFFECT, str); |
| bool ret = native_set_parm(CAMERA_SET_PARM_EFFECT, sizeof(value), |
| (void *)&value); |
| return ret ? NO_ERROR : UNKNOWN_ERROR; |
| } |
| } |
| LOGE("Invalid effect value: %s", (str == NULL) ? "NULL" : str); |
| return BAD_VALUE; |
| } |
| |
| status_t QualcommCameraHardware::setAutoExposure(const CameraParameters& params) |
| { |
| if(!strcmp(sensorType->name, "2mp")) { |
| LOGE("Auto Exposure not supported for this sensor"); |
| return NO_ERROR; |
| } |
| const char *str = params.get(CameraParameters::KEY_AUTO_EXPOSURE); |
| if (str != NULL) { |
| int32_t value = attr_lookup(autoexposure, sizeof(autoexposure) / sizeof(str_map), str); |
| if (value != NOT_FOUND) { |
| mParameters.set(CameraParameters::KEY_AUTO_EXPOSURE, str); |
| bool ret = native_set_parm(CAMERA_SET_PARM_EXPOSURE, sizeof(value), |
| (void *)&value); |
| return ret ? NO_ERROR : UNKNOWN_ERROR; |
| } |
| } |
| LOGE("Invalid auto exposure value: %s", (str == NULL) ? "NULL" : str); |
| return BAD_VALUE; |
| } |
| |
| status_t QualcommCameraHardware::setSharpness(const CameraParameters& params) |
| { |
| if(!strcmp(sensorType->name, "2mp")) { |
| LOGE("Sharpness not supported for this sensor"); |
| return NO_ERROR; |
| } |
| int sharpness = params.getInt(CameraParameters::KEY_SHARPNESS); |
| if((sharpness < CAMERA_MIN_SHARPNESS |
| || sharpness > CAMERA_MAX_SHARPNESS)) |
| return UNKNOWN_ERROR; |
| |
| LOGV("setting sharpness %d", sharpness); |
| mParameters.set(CameraParameters::KEY_SHARPNESS, sharpness); |
| bool ret = native_set_parm(CAMERA_SET_PARM_SHARPNESS, sizeof(sharpness), |
| (void *)&sharpness); |
| return ret ? NO_ERROR : UNKNOWN_ERROR; |
| } |
| |
| status_t QualcommCameraHardware::setContrast(const CameraParameters& params) |
| { |
| if(!strcmp(sensorType->name, "2mp")) { |
| LOGE("Contrast not supported for this sensor"); |
| return NO_ERROR; |
| } |
| int contrast = params.getInt(CameraParameters::KEY_CONTRAST); |
| if((contrast < CAMERA_MIN_CONTRAST) |
| || (contrast > CAMERA_MAX_CONTRAST)) |
| return UNKNOWN_ERROR; |
| |
| LOGV("setting contrast %d", contrast); |
| mParameters.set(CameraParameters::KEY_CONTRAST, contrast); |
| bool ret = native_set_parm(CAMERA_SET_PARM_CONTRAST, sizeof(contrast), |
| (void *)&contrast); |
| return ret ? NO_ERROR : UNKNOWN_ERROR; |
| } |
| |
| status_t QualcommCameraHardware::setSaturation(const CameraParameters& params) |
| { |
| if(!strcmp(sensorType->name, "2mp")) { |
| LOGE("Saturation not supported for this sensor"); |
| return NO_ERROR; |
| } |
| |
| const char *str = params.get(CameraParameters::KEY_EFFECT); |
| int32_t value = attr_lookup(effects, sizeof(effects) / sizeof(str_map), str); |
| |
| if( (value != CAMERA_EFFECT_MONO) && (value != CAMERA_EFFECT_NEGATIVE) |
| && (value != CAMERA_EFFECT_AQUA) && (value != CAMERA_EFFECT_SEPIA)) { |
| |
| int saturation = params.getInt(CameraParameters::KEY_SATURATION); |
| if((saturation < CAMERA_MIN_SATURATION) |
| || (saturation > CAMERA_MAX_SATURATION)) |
| return UNKNOWN_ERROR; |
| |
| LOGV("setting saturation %d", saturation); |
| mParameters.set(CameraParameters::KEY_SATURATION, saturation); |
| bool ret = native_set_parm(CAMERA_SET_PARM_SATURATION, sizeof(saturation), |
| (void *)&saturation); |
| return ret ? NO_ERROR : UNKNOWN_ERROR; |
| } else { |
| LOGE(" Saturation value will not be set " \ |
| "when the effect selected is %s", str); |
| return NO_ERROR; |
| } |
| } |
| |
| status_t QualcommCameraHardware::setBrightness(const CameraParameters& params) { |
| int brightness = params.getInt("luma-adaptation"); |
| if (mBrightness != brightness) { |
| LOGV(" new brightness value : %d ", brightness); |
| mBrightness = brightness; |
| |
| bool ret = native_set_parm(CAMERA_SET_PARM_BRIGHTNESS, sizeof(mBrightness), |
| (void *)&mBrightness); |
| return ret ? NO_ERROR : UNKNOWN_ERROR; |
| } else { |
| return NO_ERROR; |
| } |
| } |
| |
| status_t QualcommCameraHardware::setWhiteBalance(const CameraParameters& params) |
| { |
| const char *str = params.get(CameraParameters::KEY_WHITE_BALANCE); |
| if (str != NULL) { |
| int32_t value = attr_lookup(whitebalance, sizeof(whitebalance) / sizeof(str_map), str); |
| if (value != NOT_FOUND) { |
| mParameters.set(CameraParameters::KEY_WHITE_BALANCE, str); |
| bool ret = native_set_parm(CAMERA_SET_PARM_WB, sizeof(value), |
| (void *)&value); |
| return ret ? NO_ERROR : UNKNOWN_ERROR; |
| } |
| } |
| LOGE("Invalid whitebalance value: %s", (str == NULL) ? "NULL" : str); |
| return BAD_VALUE; |
| } |
| |
| status_t QualcommCameraHardware::setFlash(const CameraParameters& params) |
| { |
| if (!mSensorInfo.flash_enabled) { |
| LOGV("%s: flash not supported", __FUNCTION__); |
| return NO_ERROR; |
| } |
| |
| const char *str = params.get(CameraParameters::KEY_FLASH_MODE); |
| if (str != NULL) { |
| int32_t value = attr_lookup(flash, sizeof(flash) / sizeof(str_map), str); |
| if (value != NOT_FOUND) { |
| mParameters.set(CameraParameters::KEY_FLASH_MODE, str); |
| bool ret = native_set_parm(CAMERA_SET_PARM_LED_MODE, |
| sizeof(value), (void *)&value); |
| return ret ? NO_ERROR : UNKNOWN_ERROR; |
| } |
| } |
| LOGE("Invalid flash mode value: %s", (str == NULL) ? "NULL" : str); |
| return BAD_VALUE; |
| } |
| |
| status_t QualcommCameraHardware::setAntibanding(const CameraParameters& params) |
| { |
| if(!strcmp(sensorType->name, "2mp")) { |
| LOGE("Parameter AntiBanding is not supported for this sensor"); |
| return NO_ERROR; |
| } |
| const char *str = params.get(CameraParameters::KEY_ANTIBANDING); |
| if (str != NULL) { |
| int value = (camera_antibanding_type)attr_lookup( |
| antibanding, sizeof(antibanding) / sizeof(str_map), str); |
| if (value != NOT_FOUND) { |
| camera_antibanding_type temp = (camera_antibanding_type) value; |
| mParameters.set(CameraParameters::KEY_ANTIBANDING, str); |
| bool ret; |
| if (temp == CAMERA_ANTIBANDING_AUTO) { |
| ret = native_set_parm(CAMERA_ENABLE_AFD, |
| 0, NULL); |
| } else { |
| ret = native_set_parm(CAMERA_SET_PARM_ANTIBANDING, |
| sizeof(camera_antibanding_type), (void *)&temp); |
| } |
| return ret ? NO_ERROR : UNKNOWN_ERROR; |
| } |
| } |
| LOGE("Invalid antibanding value: %s", (str == NULL) ? "NULL" : str); |
| return BAD_VALUE; |
| } |
| |
| status_t QualcommCameraHardware::setLensshadeValue(const CameraParameters& params) |
| { |
| if(!strcmp(sensorType->name, "2mp")) { |
| LOGE("Parameter Rolloff is not supported for this sensor"); |
| return NO_ERROR; |
| } |
| const char *str = params.get(CameraParameters::KEY_LENSSHADE); |
| if (str != NULL) { |
| int value = attr_lookup(lensshade, |
| sizeof(lensshade) / sizeof(str_map), str); |
| if (value != NOT_FOUND) { |
| int8_t temp = (int8_t)value; |
| mParameters.set(CameraParameters::KEY_LENSSHADE, str); |
| native_set_parm(CAMERA_SET_PARM_ROLLOFF, sizeof(int8_t), (void *)&temp); |
| return NO_ERROR; |
| } |
| } |
| LOGE("Invalid lensShade value: %s", (str == NULL) ? "NULL" : str); |
| return BAD_VALUE; |
| } |
| |
| status_t QualcommCameraHardware::setISOValue(const CameraParameters& params) { |
| const char *str = params.get(CameraParameters::KEY_ISO_MODE); |
| if (str != NULL) { |
| int value = (camera_iso_mode_type)attr_lookup( |
| iso, sizeof(iso) / sizeof(str_map), str); |
| if (value != NOT_FOUND) { |
| camera_iso_mode_type temp = (camera_iso_mode_type) value; |
| mParameters.set(CameraParameters::KEY_ISO_MODE, str); |
| native_set_parm(CAMERA_SET_PARM_ISO, sizeof(camera_iso_mode_type), (void *)&temp); |
| return NO_ERROR; |
| } |
| } |
| LOGE("Invalid Iso value: %s", (str == NULL) ? "NULL" : str); |
| return BAD_VALUE; |
| } |
| |
| |
| status_t QualcommCameraHardware::setGpsLocation(const CameraParameters& params) |
| { |
| const char *latitude = params.get(CameraParameters::KEY_GPS_LATITUDE); |
| if (latitude) { |
| mParameters.set(CameraParameters::KEY_GPS_LATITUDE, latitude); |
| } |
| |
| const char *latitudeRef = params.get(CameraParameters::KEY_GPS_LATITUDE_REF); |
| if (latitudeRef) { |
| mParameters.set(CameraParameters::KEY_GPS_LATITUDE_REF, latitudeRef); |
| } |
| |
| const char *longitude = params.get(CameraParameters::KEY_GPS_LONGITUDE); |
| if (longitude) { |
| mParameters.set(CameraParameters::KEY_GPS_LONGITUDE, longitude); |
| } |
| |
| const char *longitudeRef = params.get(CameraParameters::KEY_GPS_LONGITUDE_REF); |
| if (longitudeRef) { |
| mParameters.set(CameraParameters::KEY_GPS_LONGITUDE_REF, longitudeRef); |
| } |
| |
| const char *altitudeRef = params.get(CameraParameters::KEY_GPS_ALTITUDE_REF); |
| if (altitudeRef) { |
| mParameters.set(CameraParameters::KEY_GPS_ALTITUDE_REF, altitudeRef); |
| } |
| |
| const char *altitude = params.get(CameraParameters::KEY_GPS_ALTITUDE); |
| if (altitude) { |
| mParameters.set(CameraParameters::KEY_GPS_ALTITUDE, altitude); |
| } |
| |
| const char *status = params.get(CameraParameters::KEY_GPS_STATUS); |
| if (status) { |
| mParameters.set(CameraParameters::KEY_GPS_STATUS, status); |
| } |
| |
| const char *dateTime = params.get(CameraParameters::KEY_EXIF_DATETIME); |
| if (dateTime) { |
| mParameters.set(CameraParameters::KEY_EXIF_DATETIME, dateTime); |
| } |
| |
| const char *timestamp = params.get(CameraParameters::KEY_GPS_TIMESTAMP); |
| if (timestamp) { |
| mParameters.set(CameraParameters::KEY_GPS_TIMESTAMP, timestamp); |
| } |
| return NO_ERROR; |
| } |
| |
| status_t QualcommCameraHardware::setRotation(const CameraParameters& params) |
| { |
| status_t rc = NO_ERROR; |
| int rotation = params.getInt(CameraParameters::KEY_ROTATION); |
| if (rotation != NOT_FOUND) { |
| if (rotation == 0 || rotation == 90 || rotation == 180 |
| || rotation == 270) { |
| mParameters.set(CameraParameters::KEY_ROTATION, rotation); |
| } else { |
| LOGE("Invalid rotation value: %d", rotation); |
| rc = BAD_VALUE; |
| } |
| } |
| return rc; |
| } |
| |
| status_t QualcommCameraHardware::setZoom(const CameraParameters& params) |
| { |
| status_t rc = NO_ERROR; |
| // No matter how many different zoom values the driver can provide, HAL |
| // provides applictations the same number of zoom levels. The maximum driver |
| // zoom value depends on sensor output (VFE input) and preview size (VFE |
| // output) because VFE can only crop and cannot upscale. If the preview size |
| // is bigger, the maximum zoom ratio is smaller. However, we want the |
| // zoom ratio of each zoom level is always the same whatever the preview |
| // size is. Ex: zoom level 1 is always 1.2x, zoom level 2 is 1.44x, etc. So, |
| // we need to have a fixed maximum zoom value and do read it from the |
| // driver. |
| static const int ZOOM_STEP = 1; |
| int32_t zoom_level = params.getInt("zoom"); |
| |
| LOGV("Set zoom=%d", zoom_level); |
| if(zoom_level >= 0 && zoom_level <= mMaxZoom) { |
| mParameters.set("zoom", zoom_level); |
| int32_t zoom_value = ZOOM_STEP * zoom_level; |
| bool ret = native_set_parm(CAMERA_SET_PARM_ZOOM, |
| sizeof(zoom_value), (void *)&zoom_value); |
| rc = ret ? NO_ERROR : UNKNOWN_ERROR; |
| } else { |
| rc = BAD_VALUE; |
| } |
| |
| return rc; |
| } |
| |
| status_t QualcommCameraHardware::setFocusMode(const CameraParameters& params) |
| { |
| const char *str = params.get(CameraParameters::KEY_FOCUS_MODE); |
| if (str != NULL) { |
| int32_t value = attr_lookup(focus_modes, |
| sizeof(focus_modes) / sizeof(str_map), str); |
| if (value != NOT_FOUND) { |
| mParameters.set(CameraParameters::KEY_FOCUS_MODE, str); |
| // Focus step is reset to infinity when preview is started. We do |
| // not need to do anything now. |
| return NO_ERROR; |
| } |
| } |
| LOGE("Invalid focus mode value: %s", (str == NULL) ? "NULL" : str); |
| return BAD_VALUE; |
| } |
| |
| status_t QualcommCameraHardware::setOrientation(const CameraParameters& params) |
| { |
| const char *str = params.get("orientation"); |
| |
| if (str != NULL) { |
| if (strcmp(str, "portrait") == 0 || strcmp(str, "landscape") == 0) { |
| // Camera service needs this to decide if the preview frames and raw |
| // pictures should be rotated. |
| mParameters.set("orientation", str); |
| } else { |
| LOGE("Invalid orientation value: %s", str); |
| return BAD_VALUE; |
| } |
| } |
| return NO_ERROR; |
| } |
| |
| status_t QualcommCameraHardware::setPictureFormat(const CameraParameters& params) |
| { |
| const char * str = params.get(CameraParameters::KEY_PICTURE_FORMAT); |
| |
| if(str != NULL){ |
| int32_t value = attr_lookup(picture_formats, |
| sizeof(picture_formats) / sizeof(str_map), str); |
| if(value != NOT_FOUND){ |
| mParameters.set(CameraParameters::KEY_PICTURE_FORMAT, str); |
| } else { |
| LOGE("Invalid Picture Format value: %s", str); |
| return BAD_VALUE; |
| } |
| } |
| return NO_ERROR; |
| } |
| |
| QualcommCameraHardware::MemPool::MemPool(int buffer_size, int num_buffers, |
| int frame_size, |
| const char *name) : |
| mBufferSize(buffer_size), |
| mNumBuffers(num_buffers), |
| mFrameSize(frame_size), |
| mBuffers(NULL), mName(name) |
| { |
| int page_size_minus_1 = getpagesize() - 1; |
| mAlignedBufferSize = (buffer_size + page_size_minus_1) & (~page_size_minus_1); |
| } |
| |
| void QualcommCameraHardware::MemPool::completeInitialization() |
| { |
| // If we do not know how big the frame will be, we wait to allocate |
| // the buffers describing the individual frames until we do know their |
| // size. |
| |
| if (mFrameSize > 0) { |
| mBuffers = new sp<MemoryBase>[mNumBuffers]; |
| for (int i = 0; i < mNumBuffers; i++) { |
| mBuffers[i] = new |
| MemoryBase(mHeap, |
| i * mAlignedBufferSize, |
| mFrameSize); |
| } |
| } |
| } |
| |
| QualcommCameraHardware::AshmemPool::AshmemPool(int buffer_size, int num_buffers, |
| int frame_size, |
| const char *name) : |
| QualcommCameraHardware::MemPool(buffer_size, |
| num_buffers, |
| frame_size, |
| name) |
| { |
| LOGV("constructing MemPool %s backed by ashmem: " |
| "%d frames @ %d uint8_ts, " |
| "buffer size %d", |
| mName, |
| num_buffers, frame_size, buffer_size); |
| |
| int page_mask = getpagesize() - 1; |
| int ashmem_size = buffer_size * num_buffers; |
| ashmem_size += page_mask; |
| ashmem_size &= ~page_mask; |
| |
| mHeap = new MemoryHeapBase(ashmem_size); |
| |
| completeInitialization(); |
| } |
| |
| static bool register_buf(int camfd, |
| int size, |
| int frame_size, |
| int pmempreviewfd, |
| uint32_t offset, |
| uint8_t *buf, |
| int pmem_type, |
| bool vfe_can_write, |
| bool register_buffer = true); |
| |
| QualcommCameraHardware::PmemPool::PmemPool(const char *pmem_pool, |
| int flags, |
| int camera_control_fd, |
| int pmem_type, |
| int buffer_size, int num_buffers, |
| int frame_size, |
| const char *name) : |
| QualcommCameraHardware::MemPool(buffer_size, |
| num_buffers, |
| frame_size, |
| name), |
| mPmemType(pmem_type), |
| mCameraControlFd(dup(camera_control_fd)) |
| { |
| LOGV("constructing MemPool %s backed by pmem pool %s: " |
| "%d frames @ %d bytes, buffer size %d", |
| mName, |
| pmem_pool, num_buffers, frame_size, |
| buffer_size); |
| |
| LOGV("%s: duplicating control fd %d --> %d", |
| __FUNCTION__, |
| camera_control_fd, mCameraControlFd); |
| |
| // Make a new mmap'ed heap that can be shared across processes. |
| // mAlignedBufferSize is already in 4k aligned. (do we need total size necessary to be in power of 2??) |
| mAlignedSize = mAlignedBufferSize * num_buffers; |
| |
| sp<MemoryHeapBase> masterHeap = |
| new MemoryHeapBase(pmem_pool, mAlignedSize, flags); |
| |
| if (masterHeap->getHeapID() < 0) { |
| LOGE("failed to construct master heap for pmem pool %s", pmem_pool); |
| masterHeap.clear(); |
| return; |
| } |
| |
| sp<MemoryHeapPmem> pmemHeap = new MemoryHeapPmem(masterHeap, flags); |
| if (pmemHeap->getHeapID() >= 0) { |
| pmemHeap->slap(); |
| masterHeap.clear(); |
| mHeap = pmemHeap; |
| pmemHeap.clear(); |
| |
| mFd = mHeap->getHeapID(); |
| if (::ioctl(mFd, PMEM_GET_SIZE, &mSize)) { |
| LOGE("pmem pool %s ioctl(PMEM_GET_SIZE) error %s (%d)", |
| pmem_pool, |
| ::strerror(errno), errno); |
| mHeap.clear(); |
| return; |
| } |
| |
| LOGV("pmem pool %s ioctl(fd = %d, PMEM_GET_SIZE) is %ld", |
| pmem_pool, |
| mFd, |
| mSize.len); |
| LOGD("mBufferSize=%d, mAlignedBufferSize=%d\n", mBufferSize, mAlignedBufferSize); |
| // Unregister preview buffers with the camera drivers. Allow the VFE to write |
| // to all preview buffers except for the last one. |
| // Only Register the preview, snapshot and thumbnail buffers with the kernel. |
| if( (strcmp("postview", mName) != 0) ){ |
| int num_buf = num_buffers; |
| if(!strcmp("preview", mName)) num_buf = kPreviewBufferCount; |
| LOGD("num_buffers = %d", num_buf); |
| for (int cnt = 0; cnt < num_buf; ++cnt) { |
| int active = 1; |
| if(pmem_type == MSM_PMEM_VIDEO){ |
| active = (cnt<ACTIVE_VIDEO_BUFFERS); |
| LOGV(" pmempool creating video buffers : active %d ", active); |
| } |
| else if (pmem_type == MSM_PMEM_PREVIEW){ |
| active = (cnt < (num_buf-1)); |
| } |
| register_buf(mCameraControlFd, |
| mBufferSize, |
| mFrameSize, |
| mHeap->getHeapID(), |
| mAlignedBufferSize * cnt, |
| (uint8_t *)mHeap->base() + mAlignedBufferSize * cnt, |
| pmem_type, |
| active); |
| } |
| } |
| |
| completeInitialization(); |
| } |
| else LOGE("pmem pool %s error: could not create master heap!", |
| pmem_pool); |
| } |
| |
| QualcommCameraHardware::PmemPool::~PmemPool() |
| { |
| LOGV("%s: %s E", __FUNCTION__, mName); |
| if (mHeap != NULL) { |
| // Unregister preview buffers with the camera drivers. |
| // Only Unregister the preview, snapshot and thumbnail |
| // buffers with the kernel. |
| if( (strcmp("postview", mName) != 0) ){ |
| int num_buffers = mNumBuffers; |
| if(!strcmp("preview", mName)) num_buffers = kPreviewBufferCount; |
| for (int cnt = 0; cnt < num_buffers; ++cnt) { |
| register_buf(mCameraControlFd, |
| mBufferSize, |
| mFrameSize, |
| mHeap->getHeapID(), |
| mAlignedBufferSize * cnt, |
| (uint8_t *)mHeap->base() + mAlignedBufferSize * cnt, |
| mPmemType, |
| false, |
| false /* unregister */); |
| } |
| } |
| } |
| LOGV("destroying PmemPool %s: closing control fd %d", |
| mName, |
| mCameraControlFd); |
| close(mCameraControlFd); |
| LOGV("%s: %s X", __FUNCTION__, mName); |
| } |
| |
| QualcommCameraHardware::MemPool::~MemPool() |
| { |
| LOGV("destroying MemPool %s", mName); |
| if (mFrameSize > 0) |
| delete [] mBuffers; |
| mHeap.clear(); |
| LOGV("destroying MemPool %s completed", mName); |
| } |
| |
| static bool register_buf(int camfd, |
| int size, |
| int frame_size, |
| int pmempreviewfd, |
| uint32_t offset, |
| uint8_t *buf, |
| int pmem_type, |
| bool vfe_can_write, |
| bool register_buffer) |
| { |
| struct msm_pmem_info pmemBuf; |
| |
| pmemBuf.type = pmem_type; |
| pmemBuf.fd = pmempreviewfd; |
| pmemBuf.offset = offset; |
| pmemBuf.len = size; |
| pmemBuf.vaddr = buf; |
| pmemBuf.y_off = 0; |
| |
| if(pmem_type == MSM_PMEM_RAW_MAINIMG) |
| pmemBuf.cbcr_off = 0; |
| else |
| pmemBuf.cbcr_off = PAD_TO_WORD(frame_size * 2 / 3); |
| |
| pmemBuf.active = vfe_can_write; |
| |
| LOGV("register_buf: camfd = %d, reg = %d buffer = %p", |
| camfd, !register_buffer, buf); |
| if (ioctl(camfd, |
| register_buffer ? |
| MSM_CAM_IOCTL_REGISTER_PMEM : |
| MSM_CAM_IOCTL_UNREGISTER_PMEM, |
| &pmemBuf) < 0) { |
| LOGE("register_buf: MSM_CAM_IOCTL_(UN)REGISTER_PMEM fd %d error %s", |
| camfd, |
| strerror(errno)); |
| return false; |
| } |
| return true; |
| } |
| |
| status_t QualcommCameraHardware::MemPool::dump(int fd, const Vector<String16>& args) const |
| { |
| const size_t SIZE = 256; |
| char buffer[SIZE]; |
| String8 result; |
| snprintf(buffer, 255, "QualcommCameraHardware::AshmemPool::dump\n"); |
| result.append(buffer); |
| if (mName) { |
| snprintf(buffer, 255, "mem pool name (%s)\n", mName); |
| result.append(buffer); |
| } |
| if (mHeap != 0) { |
| snprintf(buffer, 255, "heap base(%p), size(%d), flags(%d), device(%s)\n", |
| mHeap->getBase(), mHeap->getSize(), |
| mHeap->getFlags(), mHeap->getDevice()); |
| result.append(buffer); |
| } |
| snprintf(buffer, 255, |
| "buffer size (%d), number of buffers (%d), frame size(%d)", |
| mBufferSize, mNumBuffers, mFrameSize); |
| result.append(buffer); |
| write(fd, result.string(), result.size()); |
| return NO_ERROR; |
| } |
| |
| static void receive_camframe_callback(struct msm_frame *frame) |
| { |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->receivePreviewFrame(frame); |
| } |
| } |
| |
| static void receive_jpeg_fragment_callback(uint8_t *buff_ptr, uint32_t buff_size) |
| { |
| LOGV("receive_jpeg_fragment_callback E"); |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->receiveJpegPictureFragment(buff_ptr, buff_size); |
| } |
| LOGV("receive_jpeg_fragment_callback X"); |
| } |
| |
| static void receive_jpeg_callback(jpeg_event_t status) |
| { |
| LOGV("receive_jpeg_callback E (completion status %d)", status); |
| if (status == JPEG_EVENT_DONE) { |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->receiveJpegPicture(); |
| } |
| } |
| LOGV("receive_jpeg_callback X"); |
| } |
| // 720p : video frame calbback from camframe |
| static void receive_camframe_video_callback(struct msm_frame *frame) |
| { |
| LOGV("receive_camframe_video_callback E"); |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->receiveRecordingFrame(frame); |
| } |
| LOGV("receive_camframe_video_callback X"); |
| } |
| |
| void QualcommCameraHardware::setCallbacks(notify_callback notify_cb, |
| data_callback data_cb, |
| data_callback_timestamp data_cb_timestamp, |
| void* user) |
| { |
| Mutex::Autolock lock(mLock); |
| mNotifyCallback = notify_cb; |
| mDataCallback = data_cb; |
| mDataCallbackTimestamp = data_cb_timestamp; |
| mCallbackCookie = user; |
| } |
| |
| void QualcommCameraHardware::enableMsgType(int32_t msgType) |
| { |
| Mutex::Autolock lock(mLock); |
| mMsgEnabled |= msgType; |
| } |
| |
| void QualcommCameraHardware::disableMsgType(int32_t msgType) |
| { |
| Mutex::Autolock lock(mLock); |
| mMsgEnabled &= ~msgType; |
| } |
| |
| bool QualcommCameraHardware::msgTypeEnabled(int32_t msgType) |
| { |
| return (mMsgEnabled & msgType); |
| } |
| |
| bool QualcommCameraHardware::useOverlay(void) |
| { |
| if( mCurrentTarget == TARGET_MSM7630 ) { |
| /* Only 7x30 supports Overlay */ |
| mUseOverlay = TRUE; |
| } else |
| mUseOverlay = FALSE; |
| |
| LOGV(" Using Overlay : %s ", mUseOverlay ? "YES" : "NO" ); |
| return mUseOverlay; |
| } |
| |
| status_t QualcommCameraHardware::setOverlay(const sp<Overlay> &Overlay) |
| { |
| if( Overlay != NULL) { |
| LOGV(" Valid overlay object "); |
| mOverlayLock.lock(); |
| mOverlay = Overlay; |
| mOverlayLock.unlock(); |
| } else { |
| LOGE(" Overlay object NULL. returning "); |
| mOverlay = NULL; |
| return UNKNOWN_ERROR; |
| } |
| return NO_ERROR; |
| } |
| |
| void QualcommCameraHardware::receive_camframetimeout(void) { |
| LOGV("receive_camframetimeout: E"); |
| Mutex::Autolock l(&mCamframeTimeoutLock); |
| LOGD(" Camframe timed out. Not receiving any frames from camera driver "); |
| camframe_timeout_flag = TRUE; |
| LOGV("receive_camframetimeout: X"); |
| } |
| |
| static void receive_camframetimeout_callback(void) { |
| sp<QualcommCameraHardware> obj = QualcommCameraHardware::getInstance(); |
| if (obj != 0) { |
| obj->receive_camframetimeout(); |
| } |
| } |
| |
| void QualcommCameraHardware::storePreviewFrameForPostview(void) { |
| LOGV(" storePreviewFrameForPostview : E "); |
| |
| /* Since there is restriction on the maximum overlay dimensions |
| * that can be created, we use the last preview frame as postview |
| * for 7x30. */ |
| LOGV(" Copying the preview buffer to postview buffer %d ", |
| mPreviewFrameSize); |
| if( mPostViewHeap != NULL && mLastQueuedFrame != NULL) { |
| memcpy(mPostViewHeap->mHeap->base(), |
| (uint8_t *)mLastQueuedFrame, mPreviewFrameSize ); |
| } else |
| LOGE(" Failed to store Preview frame. No Postview "); |
| |
| LOGV(" storePreviewFrameForPostview : X "); |
| } |
| |
| bool QualcommCameraHardware::isValidDimension(int width, int height) { |
| bool retVal = FALSE; |
| /* This function checks if a given resolution is valid or not. |
| * A particular resolution is considered valid if it satisfies |
| * the following conditions: |
| * 1. width & height should be multiple of 16. |
| * 2. width & height should be less than/equal to the dimensions |
| * supported by the camera sensor. |
| * 3. the aspect ratio is a valid aspect ratio and is among the |
| * commonly used aspect ratio as determined by the thumbnail_sizes |
| * data structure. |
| */ |
| |
| if( (width == CEILING16(width)) && (height == CEILING16(height)) |
| && (width <= sensorType->max_supported_snapshot_width) |
| && (height <= sensorType->max_supported_snapshot_height) ) |
| { |
| uint32_t pictureAspectRatio = (uint32_t)((width * Q12)/height); |
| for(int i = 0; i < THUMBNAIL_SIZE_COUNT; i++ ) { |
| if(thumbnail_sizes[i].aspect_ratio == pictureAspectRatio) { |
| retVal = TRUE; |
| break; |
| } |
| } |
| } |
| return retVal; |
| } |
| |
| }; // namespace android |