1/* 2 * Copyright Samsung Electronics Co.,LTD. 3 * Copyright (C) 2010 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18#define LOG_TAG "ExynosJpegForCamera" 19#include <utils/Log.h> 20 21#include "ExynosJpegEncoderForCamera.h" 22 23static const char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; 24 25#define JPEG_ERROR_LOG ALOGE 26#define JPEG_WARNING_LOG ALOGW 27 28#define JPEG_THUMBNAIL_QUALITY (60) 29#define EXIF_LIMIT_SIZE (64*1024) 30#define THUMBNAIL_IMAGE_PIXEL_SIZE (4) 31#define MAX_JPG_WIDTH (8192) 32#define MAX_JPG_HEIGHT (8192) 33 34#define MAX_INPUT_BUFFER_PLANE_NUM (1) 35#define MAX_OUTPUT_BUFFER_PLANE_NUM (1) 36 37ExynosJpegEncoderForCamera::ExynosJpegEncoderForCamera() 38{ 39 m_flagCreate = false; 40 m_jpegMain = NULL; 41 m_jpegThumb = NULL; 42 m_thumbnailW = 0; 43 m_thumbnailH = 0; 44 m_thumbnailQuality = JPEG_THUMBNAIL_QUALITY; 45 m_ionJpegClient = -1; 46 initJpegMemory(&m_stThumbInBuf, MAX_IMAGE_PLANE_NUM); 47 initJpegMemory(&m_stThumbOutBuf, MAX_IMAGE_PLANE_NUM); 48 initJpegMemory(&m_stMainInBuf, MAX_IMAGE_PLANE_NUM); 49 initJpegMemory(&m_stMainOutBuf, MAX_IMAGE_PLANE_NUM); 50} 51 52ExynosJpegEncoderForCamera::~ExynosJpegEncoderForCamera() 53{ 54 if (m_flagCreate == true) { 55 this->destroy(); 56 } 57} 58 59bool ExynosJpegEncoderForCamera::flagCreate(void) 60{ 61 return m_flagCreate; 62} 63 64int ExynosJpegEncoderForCamera::create(void) 65{ 66 int ret = ERROR_NONE; 67 if (m_flagCreate == true) { 68 return ERROR_ALREADY_CREATE; 69 } 70 71 if (m_jpegMain == NULL) { 72 m_jpegMain = new ExynosJpegEncoder; 73 74 if (m_jpegMain == NULL) { 75 JPEG_ERROR_LOG("ERR(%s):Cannot create ExynosJpegEncoder class\n", __func__); 76 return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL; 77 } 78 79 ret = m_jpegMain->create(); 80 if (ret) { 81 return ret; 82 } 83 84 ret = m_jpegMain->setCache(JPEG_CACHE_ON); 85 86 if (ret) { 87 m_jpegMain->destroy(); 88 return ret; 89 } 90 } 91 92 m_ionJpegClient = 93 m_stMainOutBuf.ionClient = 94 m_stMainInBuf.ionClient = 95 m_stThumbInBuf.ionClient = 96 m_stThumbOutBuf.ionClient = 97 createIonClient(m_ionJpegClient); 98 if(m_ionJpegClient < 0) { 99 return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL; 100 } 101 102 m_flagCreate = true; 103 104 return ERROR_NONE; 105} 106 107int ExynosJpegEncoderForCamera::destroy(void) 108{ 109 if (m_flagCreate == false) { 110 return ERROR_ALREADY_DESTROY; 111 } 112 113 if (m_jpegMain != NULL) { 114 m_jpegMain->destroy(); 115 delete m_jpegMain; 116 m_jpegMain = NULL; 117 } 118 119 if (m_jpegThumb != NULL) { 120 int iSize = sizeof(char)*m_thumbnailW*m_thumbnailH*4; 121 122 freeJpegMemory(&m_stThumbInBuf, MAX_IMAGE_PLANE_NUM); 123 freeJpegMemory(&m_stThumbOutBuf, MAX_IMAGE_PLANE_NUM); 124 initJpegMemory(&m_stMainInBuf, MAX_IMAGE_PLANE_NUM); 125 initJpegMemory(&m_stMainOutBuf, MAX_IMAGE_PLANE_NUM); 126 m_ionJpegClient = 127 m_stMainOutBuf.ionClient = 128 m_stMainInBuf.ionClient = 129 m_stThumbInBuf.ionClient = 130 m_stThumbOutBuf.ionClient = 131 deleteIonClient(m_ionJpegClient); 132 m_jpegThumb->destroy(); 133 delete m_jpegThumb; 134 m_jpegThumb = NULL; 135 } 136 if (m_ionJpegClient >= 0) { 137 JPEG_WARNING_LOG("WARNING(%s):Ion Client created outside of m_jpegThumb\n", __func__); 138 m_ionJpegClient = 139 m_stMainOutBuf.ionClient = 140 m_stMainInBuf.ionClient = 141 m_stThumbInBuf.ionClient = 142 m_stThumbOutBuf.ionClient = 143 deleteIonClient(m_ionJpegClient); 144 } 145 146 m_flagCreate = false; 147 m_thumbnailW = 0; 148 m_thumbnailH = 0; 149 m_thumbnailQuality = JPEG_THUMBNAIL_QUALITY; 150 return ERROR_NONE; 151} 152 153int ExynosJpegEncoderForCamera::setSize(int w, int h) 154{ 155 if (m_flagCreate == false) { 156 return ERROR_NOT_YET_CREATED; 157 } 158 159 return m_jpegMain->setSize(w, h); 160} 161 162 163int ExynosJpegEncoderForCamera::setQuality(int quality) 164{ 165 if (m_flagCreate == false) { 166 return ERROR_NOT_YET_CREATED; 167 } 168 169 return m_jpegMain->setQuality(quality); 170} 171 172int ExynosJpegEncoderForCamera::setColorFormat(int colorFormat) 173{ 174 if (m_flagCreate == false) { 175 return ERROR_NOT_YET_CREATED; 176 } 177 178 return m_jpegMain->setColorFormat(colorFormat); 179} 180 181int ExynosJpegEncoderForCamera::setJpegFormat(int jpegFormat) 182{ 183 if (m_flagCreate == false) { 184 return ERROR_NOT_YET_CREATED; 185 } 186 187 return m_jpegMain->setJpegFormat(jpegFormat); 188} 189 190int ExynosJpegEncoderForCamera::updateConfig(void) 191{ 192 if (m_flagCreate == false) { 193 return ERROR_NOT_YET_CREATED; 194 } 195 196 return m_jpegMain->updateConfig(); 197} 198 199int ExynosJpegEncoderForCamera::setInBuf(int *buf, char** vBuf, int *size) 200{ 201 if (m_flagCreate == false) { 202 return ERROR_NOT_YET_CREATED; 203 } 204 205 if (buf == NULL) { 206 return ERROR_BUFFR_IS_NULL; 207 } 208 209 if (size == NULL) { 210 return ERROR_BUFFR_IS_NULL; 211 } 212 213 int ret = ERROR_NONE; 214 215 ret = m_jpegMain->setInBuf(buf, size); 216 if (ret) { 217 JPEG_ERROR_LOG("%s::Fail to JPEG input buffer!!\n", __func__); 218 return ret; 219 } 220 m_stMainInBuf.ionBuffer[0] = buf[0]; 221 m_stMainInBuf.iSize[0] = size[0]; 222 m_stMainInBuf.pcBuf[0] = vBuf[0]; 223 224 return ERROR_NONE; 225} 226 227int ExynosJpegEncoderForCamera::setOutBuf(int buf, char* vBuf, int size) 228{ 229 if (m_flagCreate == false) { 230 return ERROR_NOT_YET_CREATED; 231 } 232 233 if (!buf) { 234 return ERROR_BUFFR_IS_NULL; 235 } 236 237 if (size<=0) { 238 return ERROR_BUFFER_TOO_SMALL; 239 } 240 241 int ret = ERROR_NONE; 242 ret = m_jpegMain->setOutBuf(buf, size); 243 if (ret) { 244 JPEG_ERROR_LOG("%s::Fail to JPEG output buffer!!\n", __func__); 245 return ret; 246 } 247 m_stMainOutBuf.ionBuffer[0] = buf; 248 m_stMainOutBuf.iSize[0] = size; 249 m_stMainOutBuf.pcBuf[0] = vBuf; 250 251 return ERROR_NONE; 252} 253 254int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo) 255{ 256 int ret = ERROR_NONE; 257 unsigned char *exifOut = NULL; 258 259 if (m_flagCreate == false) { 260 return ERROR_NOT_YET_CREATED; 261 } 262 263 264 ret = m_jpegMain->encode(); 265 if (ret) { 266 JPEG_ERROR_LOG("encode failed\n"); 267 return ret; 268 } 269 270 int iJpegSize = m_jpegMain->getJpegSize(); 271 272 if (iJpegSize<=0) { 273 JPEG_ERROR_LOG("%s:: output_size is too small(%d)!!\n", __func__, iJpegSize); 274 return ERROR_OUT_BUFFER_SIZE_TOO_SMALL; 275 } 276 277 int iOutputSize = m_stMainOutBuf.iSize[0]; 278 int iJpegBuffer = m_stMainOutBuf.ionBuffer[0]; 279 char *pcJpegBuffer = m_stMainOutBuf.pcBuf[0]; 280 281 if (!pcJpegBuffer[0]) { 282 JPEG_ERROR_LOG("%s::pcJpegBuffer[0] is null!!\n", __func__); 283 return ERROR_OUT_BUFFER_CREATE_FAIL; 284 } 285 286 if (exifInfo != NULL) { 287 unsigned int thumbLen, exifLen; 288 289 unsigned int bufSize = 0; 290 if (exifInfo->enableThumb) { 291 if (encodeThumbnail(&thumbLen)) { 292 bufSize = EXIF_FILE_SIZE; 293 exifInfo->enableThumb = false; 294 } else { 295 if (thumbLen > EXIF_LIMIT_SIZE) { 296 bufSize = EXIF_FILE_SIZE; 297 exifInfo->enableThumb = false; 298 } 299 else { 300 bufSize = EXIF_FILE_SIZE + thumbLen; 301 } 302 } 303 } else { 304 bufSize = EXIF_FILE_SIZE; 305 exifInfo->enableThumb = false; 306 } 307 308 exifOut = new unsigned char[bufSize]; 309 if (exifOut == NULL) { 310 JPEG_ERROR_LOG("%s::Failed to allocate for exifOut\n", __func__); 311 delete[] exifOut; 312 return ERROR_EXIFOUT_ALLOC_FAIL; 313 } 314 memset(exifOut, 0, bufSize); 315 316 if (makeExif (exifOut, exifInfo, &exifLen)) { 317 JPEG_ERROR_LOG("%s::Failed to make EXIF\n", __func__); 318 delete[] exifOut; 319 return ERROR_MAKE_EXIF_FAIL; 320 } 321 322 if (exifLen <= EXIF_LIMIT_SIZE) { 323 memmove(pcJpegBuffer+exifLen+2, pcJpegBuffer+2, iJpegSize - 2); 324 memcpy(pcJpegBuffer+2, exifOut, exifLen); 325 iJpegSize += exifLen; 326 } 327 328 delete[] exifOut; 329 } 330 331 *size = iJpegSize; 332 333 return ERROR_NONE; 334} 335 336int ExynosJpegEncoderForCamera::makeExif (unsigned char *exifOut, 337 exif_attribute_t *exifInfo, 338 unsigned int *size, 339 bool useMainbufForThumb) 340{ 341 unsigned char *pCur, *pApp1Start, *pIfdStart, *pGpsIfdPtr, *pNextIfdOffset; 342 unsigned int tmp, LongerTagOffest = 0, exifSizeExceptThumb; 343 pApp1Start = pCur = exifOut; 344 345 //2 Exif Identifier Code & TIFF Header 346 pCur += 4; // Skip 4 Byte for APP1 marker and length 347 unsigned char ExifIdentifierCode[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; 348 memcpy(pCur, ExifIdentifierCode, 6); 349 pCur += 6; 350 351 /* Byte Order - little endian, Offset of IFD - 0x00000008.H */ 352 unsigned char TiffHeader[8] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 }; 353 memcpy(pCur, TiffHeader, 8); 354 pIfdStart = pCur; 355 pCur += 8; 356 357 //2 0th IFD TIFF Tags 358 if (exifInfo->enableGps) 359 tmp = NUM_0TH_IFD_TIFF; 360 else 361 tmp = NUM_0TH_IFD_TIFF - 1; 362 363 memcpy(pCur, &tmp, NUM_SIZE); 364 pCur += NUM_SIZE; 365 366 LongerTagOffest += 8 + NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE; 367 368 writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG, 369 1, exifInfo->width); 370 writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG, 371 1, exifInfo->height); 372 writeExifIfd(&pCur, EXIF_TAG_MAKE, EXIF_TYPE_ASCII, 373 strlen((char *)exifInfo->maker) + 1, exifInfo->maker, &LongerTagOffest, pIfdStart); 374 writeExifIfd(&pCur, EXIF_TAG_MODEL, EXIF_TYPE_ASCII, 375 strlen((char *)exifInfo->model) + 1, exifInfo->model, &LongerTagOffest, pIfdStart); 376 writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, 377 1, exifInfo->orientation); 378 writeExifIfd(&pCur, EXIF_TAG_SOFTWARE, EXIF_TYPE_ASCII, 379 strlen((char *)exifInfo->software) + 1, exifInfo->software, &LongerTagOffest, pIfdStart); 380 writeExifIfd(&pCur, EXIF_TAG_DATE_TIME, EXIF_TYPE_ASCII, 381 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); 382 writeExifIfd(&pCur, EXIF_TAG_SUBSEC_TIME, EXIF_TYPE_ASCII, 383 sizeof(exifInfo->sub_sec), exifInfo->sub_sec); 384 writeExifIfd(&pCur, EXIF_TAG_YCBCR_POSITIONING, EXIF_TYPE_SHORT, 385 1, exifInfo->ycbcr_positioning); 386 writeExifIfd(&pCur, EXIF_TAG_EXIF_IFD_POINTER, EXIF_TYPE_LONG, 387 1, LongerTagOffest); 388 if (exifInfo->enableGps) { 389 pGpsIfdPtr = pCur; 390 pCur += IFD_SIZE; // Skip a ifd size for gps IFD pointer 391 } 392 393 pNextIfdOffset = pCur; // Skip a offset size for next IFD offset 394 pCur += OFFSET_SIZE; 395 396 //2 0th IFD Exif Private Tags 397 pCur = pIfdStart + LongerTagOffest; 398 399 tmp = NUM_0TH_IFD_EXIF; 400 memcpy(pCur, &tmp , NUM_SIZE); 401 pCur += NUM_SIZE; 402 403 LongerTagOffest += NUM_SIZE + NUM_0TH_IFD_EXIF*IFD_SIZE + OFFSET_SIZE; 404 405 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_TIME, EXIF_TYPE_RATIONAL, 406 1, &exifInfo->exposure_time, &LongerTagOffest, pIfdStart); 407 writeExifIfd(&pCur, EXIF_TAG_FNUMBER, EXIF_TYPE_RATIONAL, 408 1, &exifInfo->fnumber, &LongerTagOffest, pIfdStart); 409 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_PROGRAM, EXIF_TYPE_SHORT, 410 1, exifInfo->exposure_program); 411 writeExifIfd(&pCur, EXIF_TAG_ISO_SPEED_RATING, EXIF_TYPE_SHORT, 412 1, exifInfo->iso_speed_rating); 413 writeExifIfd(&pCur, EXIF_TAG_EXIF_VERSION, EXIF_TYPE_UNDEFINED, 414 4, exifInfo->exif_version); 415 writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_ORG, EXIF_TYPE_ASCII, 416 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); 417 writeExifIfd(&pCur, EXIF_TAG_SUBSEC_TIME_ORG, EXIF_TYPE_ASCII, 418 sizeof(exifInfo->sub_sec), exifInfo->sub_sec); 419 writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_TYPE_ASCII, 420 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); 421 writeExifIfd(&pCur, EXIF_TAG_SUBSEC_TIME_DIGITIZE, EXIF_TYPE_ASCII, 422 sizeof(exifInfo->sub_sec), exifInfo->sub_sec); 423 writeExifIfd(&pCur, EXIF_TAG_SHUTTER_SPEED, EXIF_TYPE_SRATIONAL, 424 1, (rational_t *)&exifInfo->shutter_speed, &LongerTagOffest, pIfdStart); 425 writeExifIfd(&pCur, EXIF_TAG_APERTURE, EXIF_TYPE_RATIONAL, 426 1, &exifInfo->aperture, &LongerTagOffest, pIfdStart); 427 writeExifIfd(&pCur, EXIF_TAG_BRIGHTNESS, EXIF_TYPE_SRATIONAL, 428 1, (rational_t *)&exifInfo->brightness, &LongerTagOffest, pIfdStart); 429 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_BIAS, EXIF_TYPE_SRATIONAL, 430 1, (rational_t *)&exifInfo->exposure_bias, &LongerTagOffest, pIfdStart); 431 writeExifIfd(&pCur, EXIF_TAG_MAX_APERTURE, EXIF_TYPE_RATIONAL, 432 1, &exifInfo->max_aperture, &LongerTagOffest, pIfdStart); 433 writeExifIfd(&pCur, EXIF_TAG_METERING_MODE, EXIF_TYPE_SHORT, 434 1, exifInfo->metering_mode); 435 writeExifIfd(&pCur, EXIF_TAG_FLASH, EXIF_TYPE_SHORT, 436 1, exifInfo->flash); 437 writeExifIfd(&pCur, EXIF_TAG_FOCAL_LENGTH, EXIF_TYPE_RATIONAL, 438 1, &exifInfo->focal_length, &LongerTagOffest, pIfdStart); 439 char code[8] = { 0x00, 0x00, 0x00, 0x49, 0x49, 0x43, 0x53, 0x41 }; 440 int commentsLen = strlen((char *)exifInfo->user_comment) + 1; 441 memmove(exifInfo->user_comment + sizeof(code), exifInfo->user_comment, commentsLen); 442 memcpy(exifInfo->user_comment, code, sizeof(code)); 443 writeExifIfd(&pCur, EXIF_TAG_USER_COMMENT, EXIF_TYPE_UNDEFINED, 444 commentsLen + sizeof(code), exifInfo->user_comment, &LongerTagOffest, pIfdStart); 445 writeExifIfd(&pCur, EXIF_TAG_COLOR_SPACE, EXIF_TYPE_SHORT, 446 1, exifInfo->color_space); 447 writeExifIfd(&pCur, EXIF_TAG_PIXEL_X_DIMENSION, EXIF_TYPE_LONG, 448 1, exifInfo->width); 449 writeExifIfd(&pCur, EXIF_TAG_PIXEL_Y_DIMENSION, EXIF_TYPE_LONG, 450 1, exifInfo->height); 451 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_MODE, EXIF_TYPE_LONG, 452 1, exifInfo->exposure_mode); 453 writeExifIfd(&pCur, EXIF_TAG_WHITE_BALANCE, EXIF_TYPE_LONG, 454 1, exifInfo->white_balance); 455 writeExifIfd(&pCur, EXIF_TAG_SCENCE_CAPTURE_TYPE, EXIF_TYPE_LONG, 456 1, exifInfo->scene_capture_type); 457 tmp = 0; 458 memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset 459 pCur += OFFSET_SIZE; 460 461 //2 0th IFD GPS Info Tags 462 if (exifInfo->enableGps) { 463 writeExifIfd(&pGpsIfdPtr, EXIF_TAG_GPS_IFD_POINTER, EXIF_TYPE_LONG, 464 1, LongerTagOffest); // GPS IFD pointer skipped on 0th IFD 465 466 pCur = pIfdStart + LongerTagOffest; 467 468 if (exifInfo->gps_processing_method[0] == 0) { 469 // don't create GPS_PROCESSING_METHOD tag if there isn't any 470 tmp = NUM_0TH_IFD_GPS - 1; 471 } else { 472 tmp = NUM_0TH_IFD_GPS; 473 } 474 memcpy(pCur, &tmp, NUM_SIZE); 475 pCur += NUM_SIZE; 476 477 LongerTagOffest += NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE; 478 479 writeExifIfd(&pCur, EXIF_TAG_GPS_VERSION_ID, EXIF_TYPE_BYTE, 480 4, exifInfo->gps_version_id); 481 writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE_REF, EXIF_TYPE_ASCII, 482 2, exifInfo->gps_latitude_ref); 483 writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE, EXIF_TYPE_RATIONAL, 484 3, exifInfo->gps_latitude, &LongerTagOffest, pIfdStart); 485 writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_TYPE_ASCII, 486 2, exifInfo->gps_longitude_ref); 487 writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE, EXIF_TYPE_RATIONAL, 488 3, exifInfo->gps_longitude, &LongerTagOffest, pIfdStart); 489 writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_TYPE_BYTE, 490 1, exifInfo->gps_altitude_ref); 491 writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE, EXIF_TYPE_RATIONAL, 492 1, &exifInfo->gps_altitude, &LongerTagOffest, pIfdStart); 493 writeExifIfd(&pCur, EXIF_TAG_GPS_TIMESTAMP, EXIF_TYPE_RATIONAL, 494 3, exifInfo->gps_timestamp, &LongerTagOffest, pIfdStart); 495 tmp = strlen((char*)exifInfo->gps_processing_method); 496 if (tmp > 0) { 497 if (tmp > 100) { 498 tmp = 100; 499 } 500 unsigned char tmp_buf[100+sizeof(ExifAsciiPrefix)]; 501 memcpy(tmp_buf, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)); 502 memcpy(&tmp_buf[sizeof(ExifAsciiPrefix)], exifInfo->gps_processing_method, tmp); 503 writeExifIfd(&pCur, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_TYPE_UNDEFINED, 504 tmp+sizeof(ExifAsciiPrefix), tmp_buf, &LongerTagOffest, pIfdStart); 505 } 506 writeExifIfd(&pCur, EXIF_TAG_GPS_DATESTAMP, EXIF_TYPE_ASCII, 507 11, exifInfo->gps_datestamp, &LongerTagOffest, pIfdStart); 508 tmp = 0; 509 memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset 510 pCur += OFFSET_SIZE; 511 } 512 513 //2 1th IFD TIFF Tags 514 int iThumbFd = 0; 515 char *thumbBuf = NULL; 516 unsigned int thumbSize = 0; 517 int thumbBufSize = 0; 518 int ret = ERROR_NONE; 519 520 if (useMainbufForThumb) { 521 if (m_jpegMain) { 522 ret = m_jpegMain->getOutBuf((int *)&iThumbFd, (int *)&thumbBufSize); 523 if (ret != ERROR_NONE) { 524 iThumbFd = -1; 525 } 526 thumbSize = (unsigned int)m_jpegMain->getJpegSize(); 527 thumbBuf = m_stMainOutBuf.pcBuf[0]; 528 } 529 } else { 530 if (m_jpegThumb) { 531 ret = m_jpegThumb->getOutBuf((int *)&iThumbFd, (int *)&thumbBufSize); 532 if (ret != ERROR_NONE) { 533 iThumbFd = -1; 534 } 535 thumbSize = (unsigned int)m_jpegThumb->getJpegSize(); 536 thumbBuf = m_stThumbOutBuf.pcBuf[0]; 537 } 538 } 539 540 if (exifInfo->enableThumb && (thumbBuf != NULL) && (thumbSize != 0)) { 541 exifSizeExceptThumb = tmp = LongerTagOffest; 542 memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD 543 544 pCur = pIfdStart + LongerTagOffest; 545 546 tmp = NUM_1TH_IFD_TIFF; 547 memcpy(pCur, &tmp, NUM_SIZE); 548 pCur += NUM_SIZE; 549 550 LongerTagOffest += NUM_SIZE + NUM_1TH_IFD_TIFF*IFD_SIZE + OFFSET_SIZE; 551 552 writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG, 553 1, exifInfo->widthThumb); 554 writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG, 555 1, exifInfo->heightThumb); 556 writeExifIfd(&pCur, EXIF_TAG_COMPRESSION_SCHEME, EXIF_TYPE_SHORT, 557 1, exifInfo->compression_scheme); 558 writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, 559 1, exifInfo->orientation); 560 writeExifIfd(&pCur, EXIF_TAG_X_RESOLUTION, EXIF_TYPE_RATIONAL, 561 1, &exifInfo->x_resolution, &LongerTagOffest, pIfdStart); 562 writeExifIfd(&pCur, EXIF_TAG_Y_RESOLUTION, EXIF_TYPE_RATIONAL, 563 1, &exifInfo->y_resolution, &LongerTagOffest, pIfdStart); 564 writeExifIfd(&pCur, EXIF_TAG_RESOLUTION_UNIT, EXIF_TYPE_SHORT, 565 1, exifInfo->resolution_unit); 566 writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_TYPE_LONG, 567 1, LongerTagOffest); 568 writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN, EXIF_TYPE_LONG, 569 1, thumbSize); 570 571 tmp = 0; 572 memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset 573 pCur += OFFSET_SIZE; 574 575 memcpy(pIfdStart + LongerTagOffest, 576 thumbBuf, thumbSize); 577 LongerTagOffest += thumbSize; 578 if (LongerTagOffest > EXIF_LIMIT_SIZE) { 579 LongerTagOffest = exifSizeExceptThumb; 580 tmp = 0; 581 memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD 582 } 583 } else { 584 tmp = 0; 585 memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD 586 } 587 588 *(pApp1Start++) = 0xff; 589 *(pApp1Start++) = 0xe1; 590 591 *size = 10 + LongerTagOffest; 592 tmp = *size - 2; // APP1 Maker isn't counted 593 *(pApp1Start++) = (tmp >> 8) & 0xFF; 594 *(pApp1Start++) = tmp & 0xFF; 595 596 return ERROR_NONE; 597} 598 599/* 600 * private member functions 601*/ 602inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur, 603 unsigned short tag, 604 unsigned short type, 605 unsigned int count, 606 unsigned int value) 607{ 608 memcpy(*pCur, &tag, 2); 609 *pCur += 2; 610 memcpy(*pCur, &type, 2); 611 *pCur += 2; 612 memcpy(*pCur, &count, 4); 613 *pCur += 4; 614 memcpy(*pCur, &value, 4); 615 *pCur += 4; 616} 617 618inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur, 619 unsigned short tag, 620 unsigned short type, 621 unsigned int count, 622 unsigned char *pValue) 623{ 624 char buf[4] = { 0,}; 625 626 memcpy(buf, pValue, count); 627 memcpy(*pCur, &tag, 2); 628 *pCur += 2; 629 memcpy(*pCur, &type, 2); 630 *pCur += 2; 631 memcpy(*pCur, &count, 4); 632 *pCur += 4; 633 memcpy(*pCur, buf, 4); 634 *pCur += 4; 635} 636 637inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur, 638 unsigned short tag, 639 unsigned short type, 640 unsigned int count, 641 unsigned char *pValue, 642 unsigned int *offset, 643 unsigned char *start) 644{ 645 memcpy(*pCur, &tag, 2); 646 *pCur += 2; 647 memcpy(*pCur, &type, 2); 648 *pCur += 2; 649 memcpy(*pCur, &count, 4); 650 *pCur += 4; 651 memcpy(*pCur, offset, 4); 652 *pCur += 4; 653 memcpy(start + *offset, pValue, count); 654 *offset += count; 655} 656 657inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur, 658 unsigned short tag, 659 unsigned short type, 660 unsigned int count, 661 rational_t *pValue, 662 unsigned int *offset, 663 unsigned char *start) 664{ 665 memcpy(*pCur, &tag, 2); 666 *pCur += 2; 667 memcpy(*pCur, &type, 2); 668 *pCur += 2; 669 memcpy(*pCur, &count, 4); 670 *pCur += 4; 671 memcpy(*pCur, offset, 4); 672 *pCur += 4; 673 memcpy(start + *offset, pValue, 8 * count); 674 *offset += 8 * count; 675} 676 677int ExynosJpegEncoderForCamera::scaleDownYuv422(char **srcBuf, unsigned int srcW, unsigned int srcH, char **dstBuf, unsigned int dstW, unsigned int dstH) 678{ 679 int step_x, step_y; 680 int src_y_start_pos, dst_pos, src_pos; 681 char *src_buf = srcBuf[0]; 682 char *dst_buf = dstBuf[0]; 683 684 if (dstW & 0x01 || dstH & 0x01) { 685 return ERROR_INVALID_SCALING_WIDTH_HEIGHT; 686 } 687 688 step_x = srcW / dstW; 689 step_y = srcH / dstH; 690 691 unsigned int srcWStride = srcW * 2; 692 unsigned int stepXStride = step_x * 2; 693 694 dst_pos = 0; 695 for (unsigned int y = 0; y < dstH; y++) { 696 src_y_start_pos = srcWStride * step_y * y; 697 698 for (unsigned int x = 0; x < dstW; x += 2) { 699 src_pos = src_y_start_pos + (stepXStride * x); 700 701 dst_buf[dst_pos++] = src_buf[src_pos ]; 702 dst_buf[dst_pos++] = src_buf[src_pos + 1]; 703 dst_buf[dst_pos++] = src_buf[src_pos + 2]; 704 dst_buf[dst_pos++] = src_buf[src_pos + 3]; 705 } 706 } 707 708 return ERROR_NONE; 709} 710 711int ExynosJpegEncoderForCamera::scaleDownYuv422_2p(char **srcBuf, unsigned int srcW, unsigned int srcH, char **dstBuf, unsigned int dstW, unsigned int dstH) 712{ 713 int32_t step_x, step_y; 714 int32_t src_y_start_pos, dst_pos, src_pos; 715 int32_t src_Y_offset; 716 char *src_buf; 717 char *dst_buf; 718 719 if (dstW % 2 != 0 || dstH % 2 != 0) { 720 return ERROR_INVALID_SCALING_WIDTH_HEIGHT; 721 } 722 723 step_x = srcW / dstW; 724 step_y = srcH / dstH; 725 726 // Y scale down 727 src_buf = srcBuf[0]; 728 dst_buf = dstBuf[0]; 729 dst_pos = 0; 730 for (uint32_t y = 0; y < dstH; y++) { 731 src_y_start_pos = y * step_y * srcW; 732 733 for (uint32_t x = 0; x < dstW; x++) { 734 src_pos = src_y_start_pos + (x * step_x); 735 736 dst_buf[dst_pos++] = src_buf[src_pos]; 737 } 738 } 739 740 // UV scale down 741 for (uint32_t i = 0; i < dstH; i++) { 742 src_y_start_pos = i * step_y * srcW + (srcW*srcH); 743 744 for (uint32_t j = 0; j < dstW; j += 2) { 745 src_pos = src_y_start_pos + (j * step_x); 746 747 dst_buf[dst_pos++] = src_buf[src_pos ]; 748 dst_buf[dst_pos++] = src_buf[src_pos + 1]; 749 } 750 } 751 752 return ERROR_NONE; 753} 754 755// thumbnail 756int ExynosJpegEncoderForCamera::setThumbnailSize(int w, int h) 757{ 758 if (m_flagCreate == false) { 759 return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL; 760 } 761 762 if (w < 0 || MAX_JPG_WIDTH < w) { 763 return false; 764 } 765 766 if (h < 0 || MAX_JPG_HEIGHT < h) { 767 return false; 768 } 769 770 m_thumbnailW = w; 771 m_thumbnailH = h; 772 return ERROR_NONE; 773} 774 775int ExynosJpegEncoderForCamera::setThumbnailQuality(int quality) 776{ 777 if (m_flagCreate == false) { 778 return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL; 779 } 780 781 if (quality < 1 || 100 < quality) { 782 return false; 783 } 784 785 m_thumbnailQuality = quality; 786 return ERROR_NONE; 787} 788 789int ExynosJpegEncoderForCamera::encodeThumbnail(unsigned int *size, bool useMain) 790{ 791 int ret = ERROR_NONE; 792 793 if (m_flagCreate == false) { 794 return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL; 795 } 796 797 // create jpeg thumbnail class 798 if (m_jpegThumb == NULL) { 799 m_jpegThumb = new ExynosJpegEncoder; 800 801 if (m_jpegThumb == NULL) { 802 JPEG_ERROR_LOG("ERR(%s):Cannot open a jpeg device file\n", __func__); 803 return ERROR_CANNOT_CREATE_SEC_THUMB; 804 } 805 } 806 807 ret = m_jpegThumb->create(); 808 if (ret) { 809 JPEG_ERROR_LOG("ERR(%s):Fail create\n", __func__); 810 return ret; 811 } 812 813 ret = m_jpegThumb->setCache(JPEG_CACHE_ON); 814 if (ret) { 815 JPEG_ERROR_LOG("ERR(%s):Fail cache set\n", __func__); 816 return ret; 817 } 818 819 void *pConfig = m_jpegMain->getJpegConfig(); 820 if (pConfig == NULL) { 821 JPEG_ERROR_LOG("ERR(%s):Fail getJpegConfig\n", __func__); 822 return ERROR_BUFFR_IS_NULL; 823 } 824 825 ret = m_jpegThumb->setJpegConfig(pConfig); 826 if (ret) { 827 JPEG_ERROR_LOG("ERR(%s):Fail setJpegConfig\n", __func__); 828 return ret; 829 } 830 831 /* TODO: Currently we fix the thumbnail quality */ 832 ret = m_jpegThumb->setQuality(JPEG_THUMBNAIL_QUALITY); 833 if (ret) { 834 JPEG_ERROR_LOG("ERR(%s):Fail setQuality\n", __func__); 835 return ret; 836 } 837 838 ret = m_jpegThumb->setSize(m_thumbnailW, m_thumbnailH); 839 if (ret) { 840 JPEG_ERROR_LOG("ERR(%s):Fail setSize\n", __func__); 841 return ret; 842 } 843 844 freeJpegMemory(&m_stThumbInBuf, MAX_IMAGE_PLANE_NUM); 845 freeJpegMemory(&m_stThumbOutBuf, MAX_IMAGE_PLANE_NUM); 846 847 if (m_jpegThumb->setColorBufSize(m_stThumbInBuf.iSize, MAX_IMAGE_PLANE_NUM) != ERROR_NONE) { 848 return ERROR_INVALID_COLOR_FORMAT; 849 } 850 m_stThumbOutBuf.iSize[0] = sizeof(char)*m_thumbnailW*m_thumbnailH*THUMBNAIL_IMAGE_PIXEL_SIZE; 851 852 853 if (allocJpegMemory(&m_stThumbInBuf, MAX_IMAGE_PLANE_NUM) != ERROR_NONE) { 854 return ERROR_MEM_ALLOC_FAIL; 855 } 856 857 if (allocJpegMemory(&m_stThumbOutBuf, MAX_IMAGE_PLANE_NUM) != ERROR_NONE) { 858 return ERROR_MEM_ALLOC_FAIL; 859 } 860 861 ret = m_jpegThumb->setInBuf(m_stThumbInBuf.ionBuffer, m_stThumbInBuf.iSize); 862 if (ret) { 863 JPEG_ERROR_LOG("ERR(%s):Fail setInBuf\n", __func__); 864 return ret; 865 } 866 867 ret = m_jpegThumb->setOutBuf(m_stThumbOutBuf.ionBuffer[0], m_stThumbOutBuf.iSize[0]); 868 if (ret) { 869 JPEG_ERROR_LOG("ERR(%s):Fail setOutBuf\n", __func__); 870 return ret; 871 } 872 873 ret = m_jpegThumb->updateConfig(); 874 if (ret) { 875 JPEG_ERROR_LOG("update config failed\n"); 876 return ret; 877 } 878 879 if (useMain) { 880 int iTempWidth=0; 881 int iTempHeight=0; 882 int iTempColorformat = 0; 883 884 iTempColorformat = m_jpegMain->getColorFormat(); 885 886 ret = m_jpegMain->getSize(&iTempWidth, &iTempHeight); 887 if (ret) { 888 JPEG_ERROR_LOG("ERR(%s):Fail getSize\n", __func__); 889 return ret; 890 } 891 892 switch (iTempColorformat) { 893 case V4L2_PIX_FMT_YUYV: 894 ret = scaleDownYuv422(m_stMainInBuf.pcBuf, 895 iTempWidth, 896 iTempHeight, 897 m_stThumbInBuf.pcBuf, 898 m_thumbnailW, 899 m_thumbnailH); 900 break; 901 case V4L2_PIX_FMT_NV16: 902 ret = scaleDownYuv422_2p(m_stMainInBuf.pcBuf, 903 iTempWidth, 904 iTempHeight, 905 m_stThumbInBuf.pcBuf, 906 m_thumbnailW, 907 m_thumbnailH); 908 break; 909 default: 910 return ERROR_INVALID_COLOR_FORMAT; 911 break; 912 } 913 914 if (ret) { 915 JPEG_ERROR_LOG("%s::scaleDown(%d, %d, %d, %d) fail", __func__, iTempWidth, iTempHeight, m_thumbnailW, m_thumbnailH); 916 return ret; 917 } 918 } 919 else { 920 return ERROR_IMPLEMENT_NOT_YET; 921 } 922 923 int iOutSizeThumb; 924 925 ret = m_jpegThumb->encode(); 926 if (ret) { 927 JPEG_ERROR_LOG("encode failed\n"); 928 return ret; 929 } 930 931 iOutSizeThumb = m_jpegThumb->getJpegSize(); 932 if (iOutSizeThumb<=0) { 933 JPEG_ERROR_LOG("jpeg size is too small\n"); 934 return ERROR_THUMB_JPEG_SIZE_TOO_SMALL; 935 } 936 937 *size = (unsigned int)iOutSizeThumb; 938 939 return ERROR_NONE; 940 941} 942 943int ExynosJpegEncoderForCamera::createIonClient(ion_client ionClient) 944{ 945 if (ionClient < 0) { 946 ionClient = ion_client_create(); 947 if (ionClient < 0) { 948 JPEG_ERROR_LOG("[%s]src ion client create failed, value = %d\n", __func__, ionClient); 949 } 950 } 951 952 return ionClient; 953} 954 955int ExynosJpegEncoderForCamera::deleteIonClient(ion_client ionClient) 956{ 957 if (ionClient >= 0) { 958 ion_client_destroy(ionClient); 959 } 960 ionClient = -1; 961 return ionClient; 962} 963 964int ExynosJpegEncoderForCamera::allocJpegMemory(struct stJpegMem *pstMem, int iMemoryNum) 965{ 966 int ret = ERROR_NONE; 967 int i = 0; 968 969 if (pstMem->ionClient < 0) { 970 JPEG_ERROR_LOG("[%s] i = %d , ionClient is closed (%d)\n", __func__, i, pstMem->ionClient); 971 return ERROR_BUFFR_IS_NULL; 972 } 973 974 for (i=0;i<iMemoryNum;i++) { 975 if (pstMem->iSize[i] == 0) { 976 break; 977 } 978 979 pstMem->ionBuffer[i] = ion_alloc(pstMem->ionClient, \ 980 pstMem->iSize[i], 0, ION_HEAP_SYSTEM_MASK, 0); 981 if ((pstMem->ionBuffer[i] == -1) ||(pstMem->ionBuffer[i] == 0)) { 982 JPEG_ERROR_LOG("[%s]ion_alloc(%d) failed\n", __func__, pstMem->iSize[i]); 983 pstMem->ionBuffer[i] = -1; 984 freeJpegMemory(pstMem, iMemoryNum); 985 return ERROR_MEM_ALLOC_FAIL; 986 } 987 988 pstMem->pcBuf[i] = (char *)ion_map(pstMem->ionBuffer[i], \ 989 pstMem->iSize[i], 0); 990 if ((pstMem->pcBuf[i] == (char *)MAP_FAILED) || (pstMem->pcBuf[i] == NULL)) { 991 JPEG_ERROR_LOG("[%s]src ion map failed(%d)\n", __func__, pstMem->iSize[i]); 992 pstMem->pcBuf[i] = (char *)MAP_FAILED; 993 freeJpegMemory(pstMem, iMemoryNum); 994 return ERROR_MEM_ALLOC_FAIL; 995 } 996 } 997 998 return ERROR_NONE; 999} 1000 1001void ExynosJpegEncoderForCamera::freeJpegMemory(struct stJpegMem *pstMem, int iMemoryNum) 1002{ 1003 int i = 0; 1004 if (pstMem->ionClient < 0) { 1005 return; 1006 } 1007 1008 1009 for (i=0;i<iMemoryNum;i++) { 1010 if (pstMem->ionBuffer[i] != -1) { 1011 if (pstMem->pcBuf[i] != (char *)MAP_FAILED) { 1012 ion_unmap(pstMem->pcBuf[i], pstMem->iSize[i]); 1013 } 1014 ion_free(pstMem->ionBuffer[i]); 1015 } 1016 pstMem->ionBuffer[i] = -1; 1017 pstMem->pcBuf[i] = (char *)MAP_FAILED; 1018 pstMem->iSize[i] = 0; 1019 } 1020} 1021 1022void ExynosJpegEncoderForCamera::initJpegMemory(struct stJpegMem *pstMem, int iMemoryNum) 1023{ 1024 int i =0 ; 1025 for (i=0;i<iMemoryNum;i++) { 1026 pstMem->pcBuf[i] = (char *)MAP_FAILED; 1027 pstMem->ionBuffer[i] = -1; 1028 pstMem->iSize[i] = 0; 1029 } 1030 pstMem->ionClient = -1; 1031} 1032 1033