/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ // System dependencies #include <pthread.h> #include <string.h> #include <math.h> // JPEG dependencies #include "mm_jpeg_dbg.h" #include "mm_jpeg.h" #define LOWER(a) ((a) & 0xFFFF) #define UPPER(a) (((a)>>16) & 0xFFFF) #define CHANGE_ENDIAN_16(a) ((0x00FF & ((a)>>8)) | (0xFF00 & ((a)<<8))) #define ROUND(a) \ ((a >= 0) ? (uint32_t)(a + 0.5) : (uint32_t)(a - 0.5)) /** addExifEntry: * * Arguments: * @exif_info : Exif info struct * @p_session: job session * @tagid : exif tag ID * @type : data type * @count : number of data in uint of its type * @data : input data ptr * * Retrun : int32_t type of status * 0 -- success * none-zero failure code * * Description: * Function to add an entry to exif data * **/ int32_t addExifEntry(QOMX_EXIF_INFO *p_exif_info, exif_tag_id_t tagid, exif_tag_type_t type, uint32_t count, void *data) { int32_t rc = 0; uint32_t numOfEntries = (uint32_t)p_exif_info->numOfEntries; QEXIF_INFO_DATA *p_info_data = p_exif_info->exif_data; if(numOfEntries >= MAX_EXIF_TABLE_ENTRIES) { LOGE("Number of entries exceeded limit"); return -1; } p_info_data[numOfEntries].tag_id = tagid; p_info_data[numOfEntries].tag_entry.type = type; p_info_data[numOfEntries].tag_entry.count = count; p_info_data[numOfEntries].tag_entry.copy = 1; switch (type) { case EXIF_BYTE: { if (count > 1) { uint8_t *values = (uint8_t *)malloc(count); if (values == NULL) { LOGE("No memory for byte array"); rc = -1; } else { memcpy(values, data, count); p_info_data[numOfEntries].tag_entry.data._bytes = values; } } else { p_info_data[numOfEntries].tag_entry.data._byte = *(uint8_t *)data; } } break; case EXIF_ASCII: { char *str = NULL; str = (char *)malloc(count + 1); if (str == NULL) { LOGE("No memory for ascii string"); rc = -1; } else { memset(str, 0, count + 1); memcpy(str, data, count); p_info_data[numOfEntries].tag_entry.data._ascii = str; } } break; case EXIF_SHORT: { if (count > 1) { uint16_t *values = (uint16_t *)malloc(count * sizeof(uint16_t)); if (values == NULL) { LOGE("No memory for short array"); rc = -1; } else { memcpy(values, data, count * sizeof(uint16_t)); p_info_data[numOfEntries].tag_entry.data._shorts = values; } } else { p_info_data[numOfEntries].tag_entry.data._short = *(uint16_t *)data; } } break; case EXIF_LONG: { if (count > 1) { uint32_t *values = (uint32_t *)malloc(count * sizeof(uint32_t)); if (values == NULL) { LOGE("No memory for long array"); rc = -1; } else { memcpy(values, data, count * sizeof(uint32_t)); p_info_data[numOfEntries].tag_entry.data._longs = values; } } else { p_info_data[numOfEntries].tag_entry.data._long = *(uint32_t *)data; } } break; case EXIF_RATIONAL: { if (count > 1) { rat_t *values = (rat_t *)malloc(count * sizeof(rat_t)); if (values == NULL) { LOGE("No memory for rational array"); rc = -1; } else { memcpy(values, data, count * sizeof(rat_t)); p_info_data[numOfEntries].tag_entry.data._rats = values; } } else { p_info_data[numOfEntries].tag_entry.data._rat = *(rat_t *)data; } } break; case EXIF_UNDEFINED: { uint8_t *values = (uint8_t *)malloc(count); if (values == NULL) { LOGE("No memory for undefined array"); rc = -1; } else { memcpy(values, data, count); p_info_data[numOfEntries].tag_entry.data._undefined = values; } } break; case EXIF_SLONG: { if (count > 1) { int32_t *values = (int32_t *)malloc(count * sizeof(int32_t)); if (values == NULL) { LOGE("No memory for signed long array"); rc = -1; } else { memcpy(values, data, count * sizeof(int32_t)); p_info_data[numOfEntries].tag_entry.data._slongs = values; } } else { p_info_data[numOfEntries].tag_entry.data._slong = *(int32_t *)data; } } break; case EXIF_SRATIONAL: { if (count > 1) { srat_t *values = (srat_t *)malloc(count * sizeof(srat_t)); if (values == NULL) { LOGE("No memory for signed rational array"); rc = -1; } else { memcpy(values, data, count * sizeof(srat_t)); p_info_data[numOfEntries].tag_entry.data._srats = values; } } else { p_info_data[numOfEntries].tag_entry.data._srat = *(srat_t *)data; } } break; } // Increase number of entries p_exif_info->numOfEntries++; return rc; } /** releaseExifEntry * * Arguments: * @p_exif_data : Exif info struct * * Retrun : int32_t type of status * 0 -- success * none-zero failure code * * Description: * Function to release an entry from exif data * **/ int32_t releaseExifEntry(QEXIF_INFO_DATA *p_exif_data) { switch (p_exif_data->tag_entry.type) { case EXIF_BYTE: { if (p_exif_data->tag_entry.count > 1 && p_exif_data->tag_entry.data._bytes != NULL) { free(p_exif_data->tag_entry.data._bytes); p_exif_data->tag_entry.data._bytes = NULL; } } break; case EXIF_ASCII: { if (p_exif_data->tag_entry.data._ascii != NULL) { free(p_exif_data->tag_entry.data._ascii); p_exif_data->tag_entry.data._ascii = NULL; } } break; case EXIF_SHORT: { if (p_exif_data->tag_entry.count > 1 && p_exif_data->tag_entry.data._shorts != NULL) { free(p_exif_data->tag_entry.data._shorts); p_exif_data->tag_entry.data._shorts = NULL; } } break; case EXIF_LONG: { if (p_exif_data->tag_entry.count > 1 && p_exif_data->tag_entry.data._longs != NULL) { free(p_exif_data->tag_entry.data._longs); p_exif_data->tag_entry.data._longs = NULL; } } break; case EXIF_RATIONAL: { if (p_exif_data->tag_entry.count > 1 && p_exif_data->tag_entry.data._rats != NULL) { free(p_exif_data->tag_entry.data._rats); p_exif_data->tag_entry.data._rats = NULL; } } break; case EXIF_UNDEFINED: { if (p_exif_data->tag_entry.data._undefined != NULL) { free(p_exif_data->tag_entry.data._undefined); p_exif_data->tag_entry.data._undefined = NULL; } } break; case EXIF_SLONG: { if (p_exif_data->tag_entry.count > 1 && p_exif_data->tag_entry.data._slongs != NULL) { free(p_exif_data->tag_entry.data._slongs); p_exif_data->tag_entry.data._slongs = NULL; } } break; case EXIF_SRATIONAL: { if (p_exif_data->tag_entry.count > 1 && p_exif_data->tag_entry.data._srats != NULL) { free(p_exif_data->tag_entry.data._srats); p_exif_data->tag_entry.data._srats = NULL; } } break; } /*end of switch*/ return 0; } /** process_sensor_data: * * Arguments: * @p_sensor_params : ptr to sensor data * * Return : int32_t type of status * NO_ERROR -- success * none-zero failure code * * Description: * process sensor data * * Notes: this needs to be filled for the metadata **/ int process_sensor_data(cam_sensor_params_t *p_sensor_params, QOMX_EXIF_INFO *exif_info) { int rc = 0; rat_t val_rat; if (NULL == p_sensor_params) { LOGE("Sensor params are null"); return 0; } LOGD("From metadata aperture = %f ", p_sensor_params->aperture_value ); if (p_sensor_params->aperture_value >= 1.0) { double apex_value; apex_value = (double)2.0 * log(p_sensor_params->aperture_value) / log(2.0); val_rat.num = (uint32_t)(apex_value * 100); val_rat.denom = 100; rc = addExifEntry(exif_info, EXIFTAGID_APERTURE, EXIF_RATIONAL, 1, &val_rat); if (rc) { LOGE(": Error adding Exif Entry"); } val_rat.num = (uint32_t)(p_sensor_params->aperture_value * 100); val_rat.denom = 100; rc = addExifEntry(exif_info, EXIFTAGID_F_NUMBER, EXIF_RATIONAL, 1, &val_rat); if (rc) { LOGE(": Error adding Exif Entry"); } } /*Flash*/ short val_short = 0; int flash_mode_exif, flash_fired; if (p_sensor_params->flash_state == CAM_FLASH_STATE_FIRED) { flash_fired = 1; } else { flash_fired = 0; } LOGD("Flash mode %d flash state %d", p_sensor_params->flash_mode, p_sensor_params->flash_state); switch(p_sensor_params->flash_mode) { case CAM_FLASH_MODE_OFF: flash_mode_exif = MM_JPEG_EXIF_FLASH_MODE_OFF; break; case CAM_FLASH_MODE_ON: flash_mode_exif = MM_JPEG_EXIF_FLASH_MODE_ON; break; case CAM_FLASH_MODE_AUTO: flash_mode_exif = MM_JPEG_EXIF_FLASH_MODE_AUTO; break; default: flash_mode_exif = MM_JPEG_EXIF_FLASH_MODE_AUTO; LOGE(": Unsupported flash mode"); } val_short = (short)(flash_fired | (flash_mode_exif << 3)); rc = addExifEntry(exif_info, EXIFTAGID_FLASH, EXIF_SHORT, 1, &val_short); if (rc) { LOGE(": Error adding flash exif entry"); } /* Sensing Method */ val_short = (short) p_sensor_params->sensing_method; rc = addExifEntry(exif_info, EXIFTAGID_SENSING_METHOD, EXIF_SHORT, sizeof(val_short)/2, &val_short); if (rc) { LOGE(": Error adding flash Exif Entry"); } /* Focal Length in 35 MM Film */ val_short = (short) ((p_sensor_params->focal_length * p_sensor_params->crop_factor) + 0.5f); rc = addExifEntry(exif_info, EXIFTAGID_FOCAL_LENGTH_35MM, EXIF_SHORT, 1, &val_short); if (rc) { LOGE(": Error adding Exif Entry"); } /* F Number */ val_rat.num = (uint32_t)(p_sensor_params->f_number * 100); val_rat.denom = 100; rc = addExifEntry(exif_info, EXIFTAGTYPE_F_NUMBER, EXIF_RATIONAL, 1, &val_rat); if (rc) { LOGE(": Error adding Exif Entry"); } return rc; } /** process_3a_data: * * Arguments: * @p_3a_params : ptr to 3a data * @exif_info : Exif info struct * * Return : int32_t type of status * NO_ERROR -- success * none-zero failure code * * Description: * process 3a data * * Notes: this needs to be filled for the metadata **/ int process_3a_data(cam_3a_params_t *p_3a_params, QOMX_EXIF_INFO *exif_info) { int rc = 0; srat_t val_srat; rat_t val_rat; double shutter_speed_value; if (NULL == p_3a_params) { LOGE("3A params are null"); return 0; } LOGD("exp_time %f, iso_value %d, wb_mode %d", p_3a_params->exp_time, p_3a_params->iso_value, p_3a_params->wb_mode); /* Exposure time */ if (p_3a_params->exp_time <= 0.0f) { val_rat.num = 0; val_rat.denom = 0; } else if (p_3a_params->exp_time < 1.0f) { val_rat.num = 1; val_rat.denom = ROUND(1.0/p_3a_params->exp_time); } else { val_rat.num = ROUND(p_3a_params->exp_time); val_rat.denom = 1; } LOGD("numer %d denom %d %zd", val_rat.num, val_rat.denom, sizeof(val_rat) / (8)); rc = addExifEntry(exif_info, EXIFTAGID_EXPOSURE_TIME, EXIF_RATIONAL, (sizeof(val_rat)/(8)), &val_rat); if (rc) { LOGE(": Error adding Exif Entry Exposure time"); } /* Shutter Speed*/ if (p_3a_params->exp_time > 0) { shutter_speed_value = log10(1/p_3a_params->exp_time)/log10(2); val_srat.num = (int32_t)(shutter_speed_value * 1000); val_srat.denom = 1000; } else { val_srat.num = 0; val_srat.denom = 0; } rc = addExifEntry(exif_info, EXIFTAGID_SHUTTER_SPEED, EXIF_SRATIONAL, (sizeof(val_srat)/(8)), &val_srat); if (rc) { LOGE(": Error adding Exif Entry"); } /*ISO*/ short val_short; val_short = (short)p_3a_params->iso_value; rc = addExifEntry(exif_info, EXIFTAGID_ISO_SPEED_RATING, EXIF_SHORT, sizeof(val_short)/2, &val_short); if (rc) { LOGE(": Error adding Exif Entry"); } /*WB mode*/ if (p_3a_params->wb_mode == CAM_WB_MODE_AUTO) val_short = 0; else val_short = 1; rc = addExifEntry(exif_info, EXIFTAGID_WHITE_BALANCE, EXIF_SHORT, sizeof(val_short)/2, &val_short); if (rc) { LOGE(": Error adding Exif Entry"); } /* Metering Mode */ val_short = (short) p_3a_params->metering_mode; rc = addExifEntry(exif_info,EXIFTAGID_METERING_MODE, EXIF_SHORT, sizeof(val_short)/2, &val_short); if (rc) { LOGE(": Error adding Exif Entry"); } /*Exposure Program*/ val_short = (short) p_3a_params->exposure_program; rc = addExifEntry(exif_info,EXIFTAGID_EXPOSURE_PROGRAM, EXIF_SHORT, sizeof(val_short)/2, &val_short); if (rc) { LOGE(": Error adding Exif Entry"); } /*Exposure Mode */ val_short = (short) p_3a_params->exposure_mode; rc = addExifEntry(exif_info,EXIFTAGID_EXPOSURE_MODE, EXIF_SHORT, sizeof(val_short)/2, &val_short); if (rc) { LOGE(": Error adding Exif Entry"); } /*Scenetype*/ uint8_t val_undef; val_undef = (uint8_t) p_3a_params->scenetype; rc = addExifEntry(exif_info,EXIFTAGID_SCENE_TYPE, EXIF_UNDEFINED, sizeof(val_undef), &val_undef); if (rc) { LOGE(": Error adding Exif Entry"); } LOGD("brightness %f", p_3a_params->brightness); /* Brightness Value*/ val_srat.num = (int32_t) (p_3a_params->brightness * 100.0f); val_srat.denom = 100; rc = addExifEntry(exif_info,EXIFTAGID_BRIGHTNESS, EXIF_SRATIONAL, (sizeof(val_srat)/(8)), &val_srat); if (rc) { LOGE(": Error adding Exif Entry"); } return rc; } /** process_meta_data * * Arguments: * @p_meta : ptr to metadata * @exif_info: Exif info struct * @mm_jpeg_exif_params: exif params * * Return : int32_t type of status * NO_ERROR -- success * none-zero failure code * * Description: * Extract exif data from the metadata **/ int process_meta_data(metadata_buffer_t *p_meta, QOMX_EXIF_INFO *exif_info, mm_jpeg_exif_params_t *p_cam_exif_params, cam_hal_version_t hal_version) { int rc = 0; cam_sensor_params_t p_sensor_params; cam_3a_params_t p_3a_params; bool is_3a_meta_valid = false, is_sensor_meta_valid = false; memset(&p_3a_params, 0, sizeof(cam_3a_params_t)); memset(&p_sensor_params, 0, sizeof(cam_sensor_params_t)); if (p_meta) { /* for HAL V1*/ if (hal_version == CAM_HAL_V1) { IF_META_AVAILABLE(cam_3a_params_t, l_3a_params, CAM_INTF_META_AEC_INFO, p_meta) { p_3a_params = *l_3a_params; is_3a_meta_valid = true; } IF_META_AVAILABLE(int32_t, wb_mode, CAM_INTF_PARM_WHITE_BALANCE, p_meta) { p_3a_params.wb_mode = *wb_mode; } IF_META_AVAILABLE(cam_sensor_params_t, l_sensor_params, CAM_INTF_META_SENSOR_INFO, p_meta) { p_sensor_params = *l_sensor_params; is_sensor_meta_valid = true; } } else { /* HAL V3 */ IF_META_AVAILABLE(int32_t, iso, CAM_INTF_META_SENSOR_SENSITIVITY, p_meta) { p_3a_params.iso_value= *iso; } else { LOGE("Cannot extract Iso value"); } IF_META_AVAILABLE(int64_t, sensor_exposure_time, CAM_INTF_META_SENSOR_EXPOSURE_TIME, p_meta) { p_3a_params.exp_time = (float)((double)(*sensor_exposure_time) / 1000000000.0); } else { LOGE("Cannot extract Exp time value"); } IF_META_AVAILABLE(int32_t, wb_mode, CAM_INTF_PARM_WHITE_BALANCE, p_meta) { p_3a_params.wb_mode = *wb_mode; } else { LOGE("Cannot extract white balance mode"); } /* Process sensor data */ IF_META_AVAILABLE(float, aperture, CAM_INTF_META_LENS_APERTURE, p_meta) { p_sensor_params.aperture_value = *aperture; } else { LOGE("Cannot extract Aperture value"); } IF_META_AVAILABLE(uint32_t, flash_mode, CAM_INTF_META_FLASH_MODE, p_meta) { p_sensor_params.flash_mode = *flash_mode; } else { LOGE("Cannot extract flash mode value"); } IF_META_AVAILABLE(int32_t, flash_state, CAM_INTF_META_FLASH_STATE, p_meta) { p_sensor_params.flash_state = (cam_flash_state_t) *flash_state; } else { LOGE("Cannot extract flash state value"); } } } /* take the cached values if meta is invalid */ if ((!is_3a_meta_valid) && (hal_version == CAM_HAL_V1)) { p_3a_params = p_cam_exif_params->cam_3a_params; LOGW("Warning using cached values for 3a"); } if ((!is_sensor_meta_valid) && (hal_version == CAM_HAL_V1)) { p_sensor_params = p_cam_exif_params->sensor_params; LOGW("Warning using cached values for sensor"); } if ((hal_version != CAM_HAL_V1) || (p_sensor_params.sens_type != CAM_SENSOR_YUV)) { rc = process_3a_data(&p_3a_params, exif_info); if (rc) { LOGE("Failed to add 3a exif params"); } } rc = process_sensor_data(&p_sensor_params, exif_info); if (rc) { LOGE("Failed to extract sensor params"); } if (p_meta) { short val_short = 0; cam_asd_decision_t *scene_info = NULL; IF_META_AVAILABLE(cam_asd_decision_t, scene_cap_type, CAM_INTF_META_ASD_SCENE_INFO, p_meta) { scene_info = (cam_asd_decision_t*)scene_cap_type; val_short = (short) scene_info->detected_scene; } rc = addExifEntry(exif_info, EXIFTAGID_SCENE_CAPTURE_TYPE, EXIF_SHORT, sizeof(val_short)/2, &val_short); if (rc) { LOGE(": Error adding ASD Exif Entry"); } } else { LOGE(": Error adding ASD Exif Entry, no meta"); } return rc; }