2 * Copyright Samsung Electronics Co.,LTD.
3 * Copyright (C) 2010 The Android Open Source Project
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #define LOG_TAG "ExynosJpegForCamera"
19 #include <utils/Log.h>
21 #include "ExynosJpegEncoderForCamera.h"
23 static const char ExifAsciiPrefix
[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };
25 #define JPEG_ERROR_LOG ALOGE
26 #define JPEG_WARNING_LOG ALOGW
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)
34 #define MAX_INPUT_BUFFER_PLANE_NUM (1)
35 #define MAX_OUTPUT_BUFFER_PLANE_NUM (1)
37 ExynosJpegEncoderForCamera::ExynosJpegEncoderForCamera()
44 m_thumbnailQuality
= JPEG_THUMBNAIL_QUALITY
;
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
);
52 ExynosJpegEncoderForCamera::~ExynosJpegEncoderForCamera()
54 if (m_flagCreate
== true) {
59 bool ExynosJpegEncoderForCamera::flagCreate(void)
64 int ExynosJpegEncoderForCamera::create(void)
67 if (m_flagCreate
== true) {
68 return ERROR_ALREADY_CREATE
;
71 if (m_jpegMain
== NULL
) {
72 m_jpegMain
= new ExynosJpegEncoder
;
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
;
79 ret
= m_jpegMain
->create();
84 ret
= m_jpegMain
->setCache(JPEG_CACHE_ON
);
87 m_jpegMain
->destroy();
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
;
107 int ExynosJpegEncoderForCamera::destroy(void)
109 if (m_flagCreate
== false) {
110 return ERROR_ALREADY_DESTROY
;
113 if (m_jpegMain
!= NULL
) {
114 m_jpegMain
->destroy();
119 if (m_jpegThumb
!= NULL
) {
120 int iSize
= sizeof(char)*m_thumbnailW
*m_thumbnailH
*4;
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
);
127 m_stMainOutBuf
.ionClient
=
128 m_stMainInBuf
.ionClient
=
129 m_stThumbInBuf
.ionClient
=
130 m_stThumbOutBuf
.ionClient
=
131 deleteIonClient(m_ionJpegClient
);
132 m_jpegThumb
->destroy();
136 if (m_ionJpegClient
>= 0) {
137 JPEG_WARNING_LOG("WARNING(%s):Ion Client created outside of m_jpegThumb\n", __func__
);
139 m_stMainOutBuf
.ionClient
=
140 m_stMainInBuf
.ionClient
=
141 m_stThumbInBuf
.ionClient
=
142 m_stThumbOutBuf
.ionClient
=
143 deleteIonClient(m_ionJpegClient
);
146 m_flagCreate
= false;
149 m_thumbnailQuality
= JPEG_THUMBNAIL_QUALITY
;
153 int ExynosJpegEncoderForCamera::setSize(int w
, int h
)
155 if (m_flagCreate
== false) {
156 return ERROR_NOT_YET_CREATED
;
159 return m_jpegMain
->setSize(w
, h
);
163 int ExynosJpegEncoderForCamera::setQuality(int quality
)
165 if (m_flagCreate
== false) {
166 return ERROR_NOT_YET_CREATED
;
169 return m_jpegMain
->setQuality(quality
);
172 int ExynosJpegEncoderForCamera::setColorFormat(int colorFormat
)
174 if (m_flagCreate
== false) {
175 return ERROR_NOT_YET_CREATED
;
178 return m_jpegMain
->setColorFormat(colorFormat
);
181 int ExynosJpegEncoderForCamera::setJpegFormat(int jpegFormat
)
183 if (m_flagCreate
== false) {
184 return ERROR_NOT_YET_CREATED
;
187 return m_jpegMain
->setJpegFormat(jpegFormat
);
190 int ExynosJpegEncoderForCamera::updateConfig(void)
192 if (m_flagCreate
== false) {
193 return ERROR_NOT_YET_CREATED
;
196 return m_jpegMain
->updateConfig();
199 int ExynosJpegEncoderForCamera::setInBuf(int *buf
, char** vBuf
, int *size
)
201 if (m_flagCreate
== false) {
202 return ERROR_NOT_YET_CREATED
;
206 return ERROR_BUFFR_IS_NULL
;
210 return ERROR_BUFFR_IS_NULL
;
213 int ret
= ERROR_NONE
;
215 ret
= m_jpegMain
->setInBuf(buf
, size
);
217 JPEG_ERROR_LOG("%s::Fail to JPEG input buffer!!\n", __func__
);
220 m_stMainInBuf
.ionBuffer
[0] = buf
[0];
221 m_stMainInBuf
.iSize
[0] = size
[0];
222 m_stMainInBuf
.pcBuf
[0] = vBuf
[0];
227 int ExynosJpegEncoderForCamera::setOutBuf(int buf
, char* vBuf
, int size
)
229 if (m_flagCreate
== false) {
230 return ERROR_NOT_YET_CREATED
;
234 return ERROR_BUFFR_IS_NULL
;
238 return ERROR_BUFFER_TOO_SMALL
;
241 int ret
= ERROR_NONE
;
242 ret
= m_jpegMain
->setOutBuf(buf
, size
);
244 JPEG_ERROR_LOG("%s::Fail to JPEG output buffer!!\n", __func__
);
247 m_stMainOutBuf
.ionBuffer
[0] = buf
;
248 m_stMainOutBuf
.iSize
[0] = size
;
249 m_stMainOutBuf
.pcBuf
[0] = vBuf
;
254 int ExynosJpegEncoderForCamera::encode(int *size
, exif_attribute_t
*exifInfo
)
256 int ret
= ERROR_NONE
;
257 unsigned char *exifOut
= NULL
;
259 if (m_flagCreate
== false) {
260 return ERROR_NOT_YET_CREATED
;
264 ret
= m_jpegMain
->encode();
266 JPEG_ERROR_LOG("encode failed\n");
270 int iJpegSize
= m_jpegMain
->getJpegSize();
273 JPEG_ERROR_LOG("%s:: output_size is too small(%d)!!\n", __func__
, iJpegSize
);
274 return ERROR_OUT_BUFFER_SIZE_TOO_SMALL
;
277 int iOutputSize
= m_stMainOutBuf
.iSize
[0];
278 int iJpegBuffer
= m_stMainOutBuf
.ionBuffer
[0];
279 char *pcJpegBuffer
= m_stMainOutBuf
.pcBuf
[0];
281 if (!pcJpegBuffer
[0]) {
282 JPEG_ERROR_LOG("%s::pcJpegBuffer[0] is null!!\n", __func__
);
283 return ERROR_OUT_BUFFER_CREATE_FAIL
;
286 if (exifInfo
!= NULL
) {
287 unsigned int thumbLen
, exifLen
;
289 unsigned int bufSize
= 0;
290 if (exifInfo
->enableThumb
) {
291 if (encodeThumbnail(&thumbLen
)) {
292 bufSize
= EXIF_FILE_SIZE
;
293 exifInfo
->enableThumb
= false;
295 if (thumbLen
> EXIF_LIMIT_SIZE
) {
296 bufSize
= EXIF_FILE_SIZE
;
297 exifInfo
->enableThumb
= false;
300 bufSize
= EXIF_FILE_SIZE
+ thumbLen
;
304 bufSize
= EXIF_FILE_SIZE
;
305 exifInfo
->enableThumb
= false;
308 exifOut
= new unsigned char[bufSize
];
309 if (exifOut
== NULL
) {
310 JPEG_ERROR_LOG("%s::Failed to allocate for exifOut\n", __func__
);
312 return ERROR_EXIFOUT_ALLOC_FAIL
;
314 memset(exifOut
, 0, bufSize
);
316 if (makeExif (exifOut
, exifInfo
, &exifLen
)) {
317 JPEG_ERROR_LOG("%s::Failed to make EXIF\n", __func__
);
319 return ERROR_MAKE_EXIF_FAIL
;
322 if (exifLen
<= EXIF_LIMIT_SIZE
) {
323 memmove(pcJpegBuffer
+exifLen
+2, pcJpegBuffer
+2, iJpegSize
- 2);
324 memcpy(pcJpegBuffer
+2, exifOut
, exifLen
);
325 iJpegSize
+= exifLen
;
336 int ExynosJpegEncoderForCamera::makeExif (unsigned char *exifOut
,
337 exif_attribute_t
*exifInfo
,
339 bool useMainbufForThumb
)
341 unsigned char *pCur
, *pApp1Start
, *pIfdStart
, *pGpsIfdPtr
, *pNextIfdOffset
;
342 unsigned int tmp
, LongerTagOffest
= 0, exifSizeExceptThumb
;
343 pApp1Start
= pCur
= exifOut
;
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);
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);
357 //2 0th IFD TIFF Tags
358 if (exifInfo
->enableGps
)
359 tmp
= NUM_0TH_IFD_TIFF
;
361 tmp
= NUM_0TH_IFD_TIFF
- 1;
363 memcpy(pCur
, &tmp
, NUM_SIZE
);
366 LongerTagOffest
+= 8 + NUM_SIZE
+ tmp
*IFD_SIZE
+ OFFSET_SIZE
;
368 writeExifIfd(&pCur
, EXIF_TAG_IMAGE_WIDTH
, EXIF_TYPE_LONG
,
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
,
388 if (exifInfo
->enableGps
) {
390 pCur
+= IFD_SIZE
; // Skip a ifd size for gps IFD pointer
393 pNextIfdOffset
= pCur
; // Skip a offset size for next IFD offset
396 //2 0th IFD Exif Private Tags
397 pCur
= pIfdStart
+ LongerTagOffest
;
399 tmp
= NUM_0TH_IFD_EXIF
;
400 memcpy(pCur
, &tmp
, NUM_SIZE
);
403 LongerTagOffest
+= NUM_SIZE
+ NUM_0TH_IFD_EXIF
*IFD_SIZE
+ OFFSET_SIZE
;
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
,
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
,
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
);
458 memcpy(pCur
, &tmp
, OFFSET_SIZE
); // next IFD offset
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
466 pCur
= pIfdStart
+ LongerTagOffest
;
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;
472 tmp
= NUM_0TH_IFD_GPS
;
474 memcpy(pCur
, &tmp
, NUM_SIZE
);
477 LongerTagOffest
+= NUM_SIZE
+ tmp
*IFD_SIZE
+ OFFSET_SIZE
;
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
);
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
);
506 writeExifIfd(&pCur
, EXIF_TAG_GPS_DATESTAMP
, EXIF_TYPE_ASCII
,
507 11, exifInfo
->gps_datestamp
, &LongerTagOffest
, pIfdStart
);
509 memcpy(pCur
, &tmp
, OFFSET_SIZE
); // next IFD offset
513 //2 1th IFD TIFF Tags
515 char *thumbBuf
= NULL
;
516 unsigned int thumbSize
= 0;
517 int thumbBufSize
= 0;
518 int ret
= ERROR_NONE
;
520 if (useMainbufForThumb
) {
522 ret
= m_jpegMain
->getOutBuf((int *)&iThumbFd
, (int *)&thumbBufSize
);
523 if (ret
!= ERROR_NONE
) {
526 thumbSize
= (unsigned int)m_jpegMain
->getJpegSize();
527 thumbBuf
= m_stMainOutBuf
.pcBuf
[0];
531 ret
= m_jpegThumb
->getOutBuf((int *)&iThumbFd
, (int *)&thumbBufSize
);
532 if (ret
!= ERROR_NONE
) {
535 thumbSize
= (unsigned int)m_jpegThumb
->getJpegSize();
536 thumbBuf
= m_stThumbOutBuf
.pcBuf
[0];
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
544 pCur
= pIfdStart
+ LongerTagOffest
;
546 tmp
= NUM_1TH_IFD_TIFF
;
547 memcpy(pCur
, &tmp
, NUM_SIZE
);
550 LongerTagOffest
+= NUM_SIZE
+ NUM_1TH_IFD_TIFF
*IFD_SIZE
+ OFFSET_SIZE
;
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
,
568 writeExifIfd(&pCur
, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN
, EXIF_TYPE_LONG
,
572 memcpy(pCur
, &tmp
, OFFSET_SIZE
); // next IFD offset
575 memcpy(pIfdStart
+ LongerTagOffest
,
576 thumbBuf
, thumbSize
);
577 LongerTagOffest
+= thumbSize
;
578 if (LongerTagOffest
> EXIF_LIMIT_SIZE
) {
579 LongerTagOffest
= exifSizeExceptThumb
;
581 memcpy(pNextIfdOffset
, &tmp
, OFFSET_SIZE
); // NEXT IFD offset skipped on 0th IFD
585 memcpy(pNextIfdOffset
, &tmp
, OFFSET_SIZE
); // NEXT IFD offset skipped on 0th IFD
588 *(pApp1Start
++) = 0xff;
589 *(pApp1Start
++) = 0xe1;
591 *size
= 10 + LongerTagOffest
;
592 tmp
= *size
- 2; // APP1 Maker isn't counted
593 *(pApp1Start
++) = (tmp
>> 8) & 0xFF;
594 *(pApp1Start
++) = tmp
& 0xFF;
600 * private member functions
602 inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur
,
608 memcpy(*pCur
, &tag
, 2);
610 memcpy(*pCur
, &type
, 2);
612 memcpy(*pCur
, &count
, 4);
614 memcpy(*pCur
, &value
, 4);
618 inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur
,
622 unsigned char *pValue
)
626 memcpy(buf
, pValue
, count
);
627 memcpy(*pCur
, &tag
, 2);
629 memcpy(*pCur
, &type
, 2);
631 memcpy(*pCur
, &count
, 4);
633 memcpy(*pCur
, buf
, 4);
637 inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur
,
641 unsigned char *pValue
,
642 unsigned int *offset
,
643 unsigned char *start
)
645 memcpy(*pCur
, &tag
, 2);
647 memcpy(*pCur
, &type
, 2);
649 memcpy(*pCur
, &count
, 4);
651 memcpy(*pCur
, offset
, 4);
653 memcpy(start
+ *offset
, pValue
, count
);
657 inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur
,
662 unsigned int *offset
,
663 unsigned char *start
)
665 memcpy(*pCur
, &tag
, 2);
667 memcpy(*pCur
, &type
, 2);
669 memcpy(*pCur
, &count
, 4);
671 memcpy(*pCur
, offset
, 4);
673 memcpy(start
+ *offset
, pValue
, 8 * count
);
674 *offset
+= 8 * count
;
677 int ExynosJpegEncoderForCamera::scaleDownYuv422(char **srcBuf
, unsigned int srcW
, unsigned int srcH
, char **dstBuf
, unsigned int dstW
, unsigned int dstH
)
680 int src_y_start_pos
, dst_pos
, src_pos
;
681 char *src_buf
= srcBuf
[0];
682 char *dst_buf
= dstBuf
[0];
684 if (dstW
& 0x01 || dstH
& 0x01) {
685 return ERROR_INVALID_SCALING_WIDTH_HEIGHT
;
688 step_x
= srcW
/ dstW
;
689 step_y
= srcH
/ dstH
;
691 unsigned int srcWStride
= srcW
* 2;
692 unsigned int stepXStride
= step_x
* 2;
695 for (unsigned int y
= 0; y
< dstH
; y
++) {
696 src_y_start_pos
= srcWStride
* step_y
* y
;
698 for (unsigned int x
= 0; x
< dstW
; x
+= 2) {
699 src_pos
= src_y_start_pos
+ (stepXStride
* x
);
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];
711 int ExynosJpegEncoderForCamera::scaleDownYuv422_2p(char **srcBuf
, unsigned int srcW
, unsigned int srcH
, char **dstBuf
, unsigned int dstW
, unsigned int dstH
)
713 int32_t step_x
, step_y
;
714 int32_t src_y_start_pos
, dst_pos
, src_pos
;
715 int32_t src_Y_offset
;
719 if (dstW
% 2 != 0 || dstH
% 2 != 0) {
720 return ERROR_INVALID_SCALING_WIDTH_HEIGHT
;
723 step_x
= srcW
/ dstW
;
724 step_y
= srcH
/ dstH
;
730 for (uint32_t y
= 0; y
< dstH
; y
++) {
731 src_y_start_pos
= y
* step_y
* srcW
;
733 for (uint32_t x
= 0; x
< dstW
; x
++) {
734 src_pos
= src_y_start_pos
+ (x
* step_x
);
736 dst_buf
[dst_pos
++] = src_buf
[src_pos
];
741 for (uint32_t i
= 0; i
< dstH
; i
++) {
742 src_y_start_pos
= i
* step_y
* srcW
+ (srcW
*srcH
);
744 for (uint32_t j
= 0; j
< dstW
; j
+= 2) {
745 src_pos
= src_y_start_pos
+ (j
* step_x
);
747 dst_buf
[dst_pos
++] = src_buf
[src_pos
];
748 dst_buf
[dst_pos
++] = src_buf
[src_pos
+ 1];
756 int ExynosJpegEncoderForCamera::setThumbnailSize(int w
, int h
)
758 if (m_flagCreate
== false) {
759 return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL
;
762 if (w
< 0 || MAX_JPG_WIDTH
< w
) {
766 if (h
< 0 || MAX_JPG_HEIGHT
< h
) {
775 int ExynosJpegEncoderForCamera::setThumbnailQuality(int quality
)
777 if (m_flagCreate
== false) {
778 return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL
;
781 if (quality
< 1 || 100 < quality
) {
785 m_thumbnailQuality
= quality
;
789 int ExynosJpegEncoderForCamera::encodeThumbnail(unsigned int *size
, bool useMain
)
791 int ret
= ERROR_NONE
;
793 if (m_flagCreate
== false) {
794 return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL
;
797 // create jpeg thumbnail class
798 if (m_jpegThumb
== NULL
) {
799 m_jpegThumb
= new ExynosJpegEncoder
;
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
;
807 ret
= m_jpegThumb
->create();
809 JPEG_ERROR_LOG("ERR(%s):Fail create\n", __func__
);
813 ret
= m_jpegThumb
->setCache(JPEG_CACHE_ON
);
815 JPEG_ERROR_LOG("ERR(%s):Fail cache set\n", __func__
);
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
;
825 ret
= m_jpegThumb
->setJpegConfig(pConfig
);
827 JPEG_ERROR_LOG("ERR(%s):Fail setJpegConfig\n", __func__
);
831 /* TODO: Currently we fix the thumbnail quality */
832 ret
= m_jpegThumb
->setQuality(JPEG_THUMBNAIL_QUALITY
);
834 JPEG_ERROR_LOG("ERR(%s):Fail setQuality\n", __func__
);
838 ret
= m_jpegThumb
->setSize(m_thumbnailW
, m_thumbnailH
);
840 JPEG_ERROR_LOG("ERR(%s):Fail setSize\n", __func__
);
844 freeJpegMemory(&m_stThumbInBuf
, MAX_IMAGE_PLANE_NUM
);
845 freeJpegMemory(&m_stThumbOutBuf
, MAX_IMAGE_PLANE_NUM
);
847 if (m_jpegThumb
->setColorBufSize(m_stThumbInBuf
.iSize
, MAX_IMAGE_PLANE_NUM
) != ERROR_NONE
) {
848 return ERROR_INVALID_COLOR_FORMAT
;
850 m_stThumbOutBuf
.iSize
[0] = sizeof(char)*m_thumbnailW
*m_thumbnailH
*THUMBNAIL_IMAGE_PIXEL_SIZE
;
853 if (allocJpegMemory(&m_stThumbInBuf
, MAX_IMAGE_PLANE_NUM
) != ERROR_NONE
) {
854 return ERROR_MEM_ALLOC_FAIL
;
857 if (allocJpegMemory(&m_stThumbOutBuf
, MAX_IMAGE_PLANE_NUM
) != ERROR_NONE
) {
858 return ERROR_MEM_ALLOC_FAIL
;
861 ret
= m_jpegThumb
->setInBuf(m_stThumbInBuf
.ionBuffer
, m_stThumbInBuf
.iSize
);
863 JPEG_ERROR_LOG("ERR(%s):Fail setInBuf\n", __func__
);
867 ret
= m_jpegThumb
->setOutBuf(m_stThumbOutBuf
.ionBuffer
[0], m_stThumbOutBuf
.iSize
[0]);
869 JPEG_ERROR_LOG("ERR(%s):Fail setOutBuf\n", __func__
);
873 ret
= m_jpegThumb
->updateConfig();
875 JPEG_ERROR_LOG("update config failed\n");
882 int iTempColorformat
= 0;
884 iTempColorformat
= m_jpegMain
->getColorFormat();
886 ret
= m_jpegMain
->getSize(&iTempWidth
, &iTempHeight
);
888 JPEG_ERROR_LOG("ERR(%s):Fail getSize\n", __func__
);
892 switch (iTempColorformat
) {
893 case V4L2_PIX_FMT_YUYV
:
894 ret
= scaleDownYuv422(m_stMainInBuf
.pcBuf
,
897 m_stThumbInBuf
.pcBuf
,
901 case V4L2_PIX_FMT_NV16
:
902 ret
= scaleDownYuv422_2p(m_stMainInBuf
.pcBuf
,
905 m_stThumbInBuf
.pcBuf
,
910 return ERROR_INVALID_COLOR_FORMAT
;
915 JPEG_ERROR_LOG("%s::scaleDown(%d, %d, %d, %d) fail", __func__
, iTempWidth
, iTempHeight
, m_thumbnailW
, m_thumbnailH
);
920 return ERROR_IMPLEMENT_NOT_YET
;
925 ret
= m_jpegThumb
->encode();
927 JPEG_ERROR_LOG("encode failed\n");
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
;
937 *size
= (unsigned int)iOutSizeThumb
;
943 int ExynosJpegEncoderForCamera::createIonClient(ion_client ionClient
)
946 ionClient
= ion_client_create();
948 JPEG_ERROR_LOG("[%s]src ion client create failed, value = %d\n", __func__
, ionClient
);
955 int ExynosJpegEncoderForCamera::deleteIonClient(ion_client ionClient
)
957 if (ionClient
>= 0) {
958 ion_client_destroy(ionClient
);
964 int ExynosJpegEncoderForCamera::allocJpegMemory(struct stJpegMem
*pstMem
, int iMemoryNum
)
966 int ret
= ERROR_NONE
;
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
;
974 for (i
=0;i
<iMemoryNum
;i
++) {
975 if (pstMem
->iSize
[i
] == 0) {
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
;
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
;
1001 void ExynosJpegEncoderForCamera::freeJpegMemory(struct stJpegMem
*pstMem
, int iMemoryNum
)
1004 if (pstMem
->ionClient
< 0) {
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
]);
1014 ion_free(pstMem
->ionBuffer
[i
]);
1016 pstMem
->ionBuffer
[i
] = -1;
1017 pstMem
->pcBuf
[i
] = (char *)MAP_FAILED
;
1018 pstMem
->iSize
[i
] = 0;
1022 void ExynosJpegEncoderForCamera::initJpegMemory(struct stJpegMem
*pstMem
, int iMemoryNum
)
1025 for (i
=0;i
<iMemoryNum
;i
++) {
1026 pstMem
->pcBuf
[i
] = (char *)MAP_FAILED
;
1027 pstMem
->ionBuffer
[i
] = -1;
1028 pstMem
->iSize
[i
] = 0;
1030 pstMem
->ionClient
= -1;