blob: 0ceac31f064e0efad7524c5f761e96ad679d3708 [file] [log] [blame]
codeworkx62f02ba2012-05-20 12:00:36 +02001/*
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#include <utils/Log.h>
19
20#include "SecJpegEncoder.h"
21
22static const char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };
23
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +020024#define JPEG_ERROR_ALOG(fmt,...)
codeworkx62f02ba2012-05-20 12:00:36 +020025
26#define JPEG_MAIN_DUMP (0)
27#define JPEG_THUMB_DUMP (0)
28
29SecJpegEncoder::SecJpegEncoder()
30{
31 m_flagCreate = false;
32 m_jpegMain = NULL;
33 m_jpegThumb = NULL;
34 m_thumbnailW = 0;
35 m_thumbnailH = 0;
36 m_pThumbInputBuffer = NULL;
37 m_pThumbOutputBuffer = NULL;
38#ifdef JPEG_WA_FOR_PAGEFAULT
39 m_pJpegInputBuffer = 0;
40 m_pExtInBuf = NULL;
41 m_iInBufSize = 0;
42#endif // JPEG_WA_FOR_PAGEFAULT
43 m_ionJpegClient = 0;;
44 m_ionThumbInBuffer = 0;
45 m_ionThumbOutBuffer = 0;
46#ifdef JPEG_WA_FOR_PAGEFAULT
47 m_ionJpegInBuffer = 0;;
48#endif // JPEG_WA_FOR_PAGEFAULT
49}
50
51SecJpegEncoder::~SecJpegEncoder()
52{
53 if (m_flagCreate == true) {
54 this->destroy();
55 }
56}
57
58bool SecJpegEncoder::flagCreate(void)
59{
60 return m_flagCreate;
61}
62
63int SecJpegEncoder::create(void)
64{
65 int ret = ERROR_NONE;
66 if (m_flagCreate == true) {
67 return ERROR_ALREADY_CREATE;
68 }
69
70 if (m_jpegMain == NULL) {
71 m_jpegMain = new SecJpegEncoderHal;
72
73 if (m_jpegMain == NULL) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +020074 JPEG_ERROR_ALOG("ERR(%s):Cannot create SecJpegEncoderHal class\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +020075 return ERROR_CANNOT_CREATE_SEC_JPEG_ENC_HAL;
76 }
77
78 ret = m_jpegMain->create();
79 if (ret) {
80 return ret;
81 }
82
83 ret = m_jpegMain->setCache(JPEG_CACHE_ON);
84
85 if (ret) {
86 m_jpegMain->destroy();
87 return ret;
88 }
89 }
90
91 m_flagCreate = true;
92
93 return ERROR_NONE;
94}
95
96int SecJpegEncoder::destroy(void)
97{
98 if (m_flagCreate == false) {
99 return ERROR_ALREADY_DESTROY;
100 }
101
102 if (m_jpegMain != NULL) {
103 m_jpegMain->destroy();
104 delete m_jpegMain;
105 m_jpegMain = NULL;
106 }
107
108 if (m_jpegThumb != NULL) {
109 int iSize = sizeof(char)*m_thumbnailW*m_thumbnailH*4;
110
111#ifdef JPEG_WA_FOR_PAGEFAULT
112 iSize += JPEG_WA_BUFFER_SIZE;
113
114 freeJpegIonMemory(m_ionJpegClient, &m_ionJpegInBuffer, &m_pJpegInputBuffer, m_iInBufSize);
115#endif //JPEG_WA_FOR_PAGEFAULT
116
117 freeJpegIonMemory(m_ionJpegClient, &m_ionThumbInBuffer, &m_pThumbInputBuffer, iSize);
118 freeJpegIonMemory(m_ionJpegClient, &m_ionThumbOutBuffer, &m_pThumbOutputBuffer, iSize);
119
120 if (m_ionJpegClient != 0) {
121 ion_client_destroy(m_ionJpegClient);
122 m_ionJpegClient = 0;
123 }
124
125 m_jpegThumb->destroy();
126 delete m_jpegThumb;
127 m_jpegThumb = NULL;
128 }
129
130 m_flagCreate = false;
131 m_thumbnailW = 0;
132 m_thumbnailH = 0;
133 return ERROR_NONE;
134}
135
136int SecJpegEncoder::setSize(int w, int h)
137{
138 if (m_flagCreate == false) {
139 return ERROR_NOT_YET_CREATED;
140 }
141
142 return m_jpegMain->setSize(w, h);
143}
144
145
146int SecJpegEncoder::setQuality(int quality)
147{
148 if (m_flagCreate == false) {
149 return ERROR_NOT_YET_CREATED;
150 }
151
152 return m_jpegMain->setQuality(quality);
153}
154
155int SecJpegEncoder::setColorFormat(int colorFormat)
156{
157 if (m_flagCreate == false) {
158 return ERROR_NOT_YET_CREATED;
159 }
160
161 return m_jpegMain->setColorFormat(colorFormat);
162}
163
164int SecJpegEncoder::setJpegFormat(int jpegFormat)
165{
166 if (m_flagCreate == false) {
167 return ERROR_NOT_YET_CREATED;
168 }
169
170 return m_jpegMain->setJpegFormat(jpegFormat);
171}
172
173int SecJpegEncoder::updateConfig(void)
174{
175 if (m_flagCreate == false) {
176 return ERROR_NOT_YET_CREATED;
177 }
178
179 return m_jpegMain->updateConfig();
180}
181
182char *SecJpegEncoder::getInBuf(int *input_size)
183{
184 if (m_flagCreate == false) {
185 return NULL;
186 }
187
188 int inSize = 0;
189 char *inBuf = *(m_jpegMain->getInBuf(&inSize));
190
191 if (inBuf == NULL) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200192 JPEG_ERROR_ALOG("%s::Fail to JPEG input buffer!!\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200193 return NULL;
194 }
195
196 *input_size = inSize;
197
198 return inBuf;
199}
200
201char *SecJpegEncoder::getOutBuf(int *output_size)
202{
203 if (m_flagCreate == false) {
204 return NULL;
205 }
206
207 int outSize = 0;
208 char *outBuf = m_jpegMain->getOutBuf(&outSize);
209
210 if (outBuf == NULL) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200211 JPEG_ERROR_ALOG("%s::Fail to JPEG input buffer!!\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200212 return NULL;
213 }
214
215 *output_size = outSize;
216
217 return outBuf;
218}
219
220int SecJpegEncoder::setInBuf(char *buf, int size)
221{
222 if (m_flagCreate == false) {
223 return ERROR_NOT_YET_CREATED;
224 }
225
226 if (buf == NULL) {
227 return ERROR_BUFFR_IS_NULL;
228 }
229
230 if (size<=0) {
231 return ERROR_BUFFER_TOO_SMALL;
232 }
233
234 int ret = ERROR_NONE;
235
236#ifdef JPEG_WA_FOR_PAGEFAULT
237 size += JPEG_WA_BUFFER_SIZE;
238
239 freeJpegIonMemory(m_ionJpegClient, &m_ionJpegInBuffer, &m_pJpegInputBuffer, size);
240
241 if (m_ionJpegClient == 0) {
242 m_ionJpegClient = ion_client_create();
243 if (m_ionJpegClient < 0) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200244 JPEG_ERROR_ALOG("[%s]src ion client create failed, value = %d\n", __func__, size);
codeworkx62f02ba2012-05-20 12:00:36 +0200245 m_ionJpegClient = 0;
246 return ret;
247 }
248 }
249
250 ret = allocJpegIonMemory(m_ionJpegClient, &m_ionJpegInBuffer, &m_pJpegInputBuffer, size);
251 if (ret != ERROR_NONE) {
252 return ret;
253 }
254
255 ret = m_jpegMain->setInBuf(&m_pJpegInputBuffer, &size);
256 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200257 JPEG_ERROR_ALOG("%s::Fail to JPEG input buffer!!\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200258 return ret;
259 }
260 m_iInBufSize = size;
261
262 m_pExtInBuf = buf;
263
264#else // NO JPEG_WA_FOR_PAGEFAULT
265 ret = m_jpegMain->setInBuf(&buf, &size);
266 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200267 JPEG_ERROR_ALOG("%s::Fail to JPEG input buffer!!\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200268 return ret;
269 }
270#endif // JPEG_WA_FOR_PAGEFAULT
271
272 return ERROR_NONE;
273}
274
275int SecJpegEncoder::setOutBuf(char *buf, int size)
276{
277 if (m_flagCreate == false) {
278 return ERROR_NOT_YET_CREATED;
279 }
280
281 if (buf == NULL) {
282 return ERROR_BUFFR_IS_NULL;
283 }
284
285 if (size<=0) {
286 return ERROR_BUFFER_TOO_SMALL;
287 }
288
289 int ret = ERROR_NONE;
290 ret = m_jpegMain->setOutBuf(buf, size);
291 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200292 JPEG_ERROR_ALOG("%s::Fail to JPEG output buffer!!\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200293 return ret;
294 }
295
296 return ERROR_NONE;
297}
298
299int SecJpegEncoder::encode(int *size, exif_attribute_t *exifInfo)
300{
301 int ret = ERROR_NONE;
302 unsigned char *exifOut = NULL;
303
304 if (m_flagCreate == false) {
305 return ERROR_NOT_YET_CREATED;
306 }
307
308#ifdef JPEG_WA_FOR_PAGEFAULT
309 memcpy(m_pJpegInputBuffer, m_pExtInBuf, m_iInBufSize-JPEG_WA_BUFFER_SIZE);
310#endif // JPEG_WA_FOR_PAGEFAULT
311
312 ret = m_jpegMain->encode();
313 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200314 JPEG_ERROR_ALOG("encode failed\n");
codeworkx62f02ba2012-05-20 12:00:36 +0200315 return ret;
316 }
317
318 int iJpegSize = m_jpegMain->getJpegSize();
319
320 if (iJpegSize<=0) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200321 JPEG_ERROR_ALOG("%s:: output_size is too small(%d)!!\n", __func__, iJpegSize);
codeworkx62f02ba2012-05-20 12:00:36 +0200322 return ERROR_OUT_BUFFER_SIZE_TOO_SMALL;
323 }
324
325 int iOutputSize = 0;
326 char *pcJpegBuffer = m_jpegMain->getOutBuf(&iOutputSize);
327
328 if (pcJpegBuffer == NULL) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200329 JPEG_ERROR_ALOG("%s::buffer is null!!\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200330 return ERROR_OUT_BUFFER_CREATE_FAIL;
331 }
332
333 if (exifInfo != NULL) {
334 unsigned int thumbLen, exifLen;
335
336 unsigned int bufSize = 0;
337 if (exifInfo->enableThumb) {
338 if (encodeThumbnail(&thumbLen)) {
339 bufSize = EXIF_FILE_SIZE;
340 exifInfo->enableThumb = false;
341 } else {
342 if (thumbLen > EXIF_LIMIT_SIZE) {
343 bufSize = EXIF_FILE_SIZE;
344 exifInfo->enableThumb = false;
345 }
346 else {
347 bufSize = EXIF_FILE_SIZE + thumbLen;
348 }
349 }
350 } else {
351 bufSize = EXIF_FILE_SIZE;
352 exifInfo->enableThumb = false;
353 }
354
355 exifOut = new unsigned char[bufSize];
356 if (exifOut == NULL) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200357 JPEG_ERROR_ALOG("%s::Failed to allocate for exifOut", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200358 delete[] exifOut;
359 return ERROR_EXIFOUT_ALLOC_FAIL;
360 }
361 memset(exifOut, 0, bufSize);
362
363 if (makeExif (exifOut, exifInfo, &exifLen)) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200364 JPEG_ERROR_ALOG("%s::Failed to make EXIF", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200365 delete[] exifOut;
366 return ERROR_MAKE_EXIF_FAIL;
367 }
368
369 if (exifLen <= EXIF_LIMIT_SIZE) {
370 memmove(pcJpegBuffer+exifLen+2, pcJpegBuffer+2, iJpegSize - 2);
371 memcpy(pcJpegBuffer+2, exifOut, exifLen);
372 iJpegSize += exifLen;
373 }
374
375 delete[] exifOut;
376 }
377
378 *size = iJpegSize;
379
380 return ERROR_NONE;
381}
382
383int SecJpegEncoder::makeExif (unsigned char *exifOut,
384 exif_attribute_t *exifInfo,
385 unsigned int *size,
386 bool useMainbufForThumb)
387{
388 unsigned char *pCur, *pApp1Start, *pIfdStart, *pGpsIfdPtr, *pNextIfdOffset;
389 unsigned int tmp, LongerTagOffest = 0, exifSizeExceptThumb;
390 pApp1Start = pCur = exifOut;
391
392 //2 Exif Identifier Code & TIFF Header
393 pCur += 4; // Skip 4 Byte for APP1 marker and length
394 unsigned char ExifIdentifierCode[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
395 memcpy(pCur, ExifIdentifierCode, 6);
396 pCur += 6;
397
398 /* Byte Order - little endian, Offset of IFD - 0x00000008.H */
399 unsigned char TiffHeader[8] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 };
400 memcpy(pCur, TiffHeader, 8);
401 pIfdStart = pCur;
402 pCur += 8;
403
404 //2 0th IFD TIFF Tags
405 if (exifInfo->enableGps)
406 tmp = NUM_0TH_IFD_TIFF;
407 else
408 tmp = NUM_0TH_IFD_TIFF - 1;
409
410 memcpy(pCur, &tmp, NUM_SIZE);
411 pCur += NUM_SIZE;
412
413 LongerTagOffest += 8 + NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE;
414
415 writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG,
416 1, exifInfo->width);
417 writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG,
418 1, exifInfo->height);
419 writeExifIfd(&pCur, EXIF_TAG_MAKE, EXIF_TYPE_ASCII,
420 strlen((char *)exifInfo->maker) + 1, exifInfo->maker, &LongerTagOffest, pIfdStart);
421 writeExifIfd(&pCur, EXIF_TAG_MODEL, EXIF_TYPE_ASCII,
422 strlen((char *)exifInfo->model) + 1, exifInfo->model, &LongerTagOffest, pIfdStart);
423 writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT,
424 1, exifInfo->orientation);
425 writeExifIfd(&pCur, EXIF_TAG_SOFTWARE, EXIF_TYPE_ASCII,
426 strlen((char *)exifInfo->software) + 1, exifInfo->software, &LongerTagOffest, pIfdStart);
427 writeExifIfd(&pCur, EXIF_TAG_DATE_TIME, EXIF_TYPE_ASCII,
428 20, exifInfo->date_time, &LongerTagOffest, pIfdStart);
429 writeExifIfd(&pCur, EXIF_TAG_YCBCR_POSITIONING, EXIF_TYPE_SHORT,
430 1, exifInfo->ycbcr_positioning);
431 writeExifIfd(&pCur, EXIF_TAG_EXIF_IFD_POINTER, EXIF_TYPE_LONG,
432 1, LongerTagOffest);
433 if (exifInfo->enableGps) {
434 pGpsIfdPtr = pCur;
435 pCur += IFD_SIZE; // Skip a ifd size for gps IFD pointer
436 }
437
438 pNextIfdOffset = pCur; // Skip a offset size for next IFD offset
439 pCur += OFFSET_SIZE;
440
441 //2 0th IFD Exif Private Tags
442 pCur = pIfdStart + LongerTagOffest;
443
444 tmp = NUM_0TH_IFD_EXIF;
445 memcpy(pCur, &tmp , NUM_SIZE);
446 pCur += NUM_SIZE;
447
448 LongerTagOffest += NUM_SIZE + NUM_0TH_IFD_EXIF*IFD_SIZE + OFFSET_SIZE;
449
450 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_TIME, EXIF_TYPE_RATIONAL,
451 1, &exifInfo->exposure_time, &LongerTagOffest, pIfdStart);
452 writeExifIfd(&pCur, EXIF_TAG_FNUMBER, EXIF_TYPE_RATIONAL,
453 1, &exifInfo->fnumber, &LongerTagOffest, pIfdStart);
454 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_PROGRAM, EXIF_TYPE_SHORT,
455 1, exifInfo->exposure_program);
456 writeExifIfd(&pCur, EXIF_TAG_ISO_SPEED_RATING, EXIF_TYPE_SHORT,
457 1, exifInfo->iso_speed_rating);
458 writeExifIfd(&pCur, EXIF_TAG_EXIF_VERSION, EXIF_TYPE_UNDEFINED,
459 4, exifInfo->exif_version);
460 writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_ORG, EXIF_TYPE_ASCII,
461 20, exifInfo->date_time, &LongerTagOffest, pIfdStart);
462 writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_TYPE_ASCII,
463 20, exifInfo->date_time, &LongerTagOffest, pIfdStart);
464 writeExifIfd(&pCur, EXIF_TAG_SHUTTER_SPEED, EXIF_TYPE_SRATIONAL,
465 1, (rational_t *)&exifInfo->shutter_speed, &LongerTagOffest, pIfdStart);
466 writeExifIfd(&pCur, EXIF_TAG_APERTURE, EXIF_TYPE_RATIONAL,
467 1, &exifInfo->aperture, &LongerTagOffest, pIfdStart);
468 writeExifIfd(&pCur, EXIF_TAG_BRIGHTNESS, EXIF_TYPE_SRATIONAL,
469 1, (rational_t *)&exifInfo->brightness, &LongerTagOffest, pIfdStart);
470 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_BIAS, EXIF_TYPE_SRATIONAL,
471 1, (rational_t *)&exifInfo->exposure_bias, &LongerTagOffest, pIfdStart);
472 writeExifIfd(&pCur, EXIF_TAG_MAX_APERTURE, EXIF_TYPE_RATIONAL,
473 1, &exifInfo->max_aperture, &LongerTagOffest, pIfdStart);
474 writeExifIfd(&pCur, EXIF_TAG_METERING_MODE, EXIF_TYPE_SHORT,
475 1, exifInfo->metering_mode);
476 writeExifIfd(&pCur, EXIF_TAG_FLASH, EXIF_TYPE_SHORT,
477 1, exifInfo->flash);
478 writeExifIfd(&pCur, EXIF_TAG_FOCAL_LENGTH, EXIF_TYPE_RATIONAL,
479 1, &exifInfo->focal_length, &LongerTagOffest, pIfdStart);
480 char code[8] = { 0x00, 0x00, 0x00, 0x49, 0x49, 0x43, 0x53, 0x41 };
481 int commentsLen = strlen((char *)exifInfo->user_comment) + 1;
482 memmove(exifInfo->user_comment + sizeof(code), exifInfo->user_comment, commentsLen);
483 memcpy(exifInfo->user_comment, code, sizeof(code));
484 writeExifIfd(&pCur, EXIF_TAG_USER_COMMENT, EXIF_TYPE_UNDEFINED,
485 commentsLen + sizeof(code), exifInfo->user_comment, &LongerTagOffest, pIfdStart);
486 writeExifIfd(&pCur, EXIF_TAG_COLOR_SPACE, EXIF_TYPE_SHORT,
487 1, exifInfo->color_space);
488 writeExifIfd(&pCur, EXIF_TAG_PIXEL_X_DIMENSION, EXIF_TYPE_LONG,
489 1, exifInfo->width);
490 writeExifIfd(&pCur, EXIF_TAG_PIXEL_Y_DIMENSION, EXIF_TYPE_LONG,
491 1, exifInfo->height);
492 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_MODE, EXIF_TYPE_LONG,
493 1, exifInfo->exposure_mode);
494 writeExifIfd(&pCur, EXIF_TAG_WHITE_BALANCE, EXIF_TYPE_LONG,
495 1, exifInfo->white_balance);
496 writeExifIfd(&pCur, EXIF_TAG_SCENCE_CAPTURE_TYPE, EXIF_TYPE_LONG,
497 1, exifInfo->scene_capture_type);
498 tmp = 0;
499 memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset
500 pCur += OFFSET_SIZE;
501
502 //2 0th IFD GPS Info Tags
503 if (exifInfo->enableGps) {
504 writeExifIfd(&pGpsIfdPtr, EXIF_TAG_GPS_IFD_POINTER, EXIF_TYPE_LONG,
505 1, LongerTagOffest); // GPS IFD pointer skipped on 0th IFD
506
507 pCur = pIfdStart + LongerTagOffest;
508
509 if (exifInfo->gps_processing_method[0] == 0) {
510 // don't create GPS_PROCESSING_METHOD tag if there isn't any
511 tmp = NUM_0TH_IFD_GPS - 1;
512 } else {
513 tmp = NUM_0TH_IFD_GPS;
514 }
515 memcpy(pCur, &tmp, NUM_SIZE);
516 pCur += NUM_SIZE;
517
518 LongerTagOffest += NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE;
519
520 writeExifIfd(&pCur, EXIF_TAG_GPS_VERSION_ID, EXIF_TYPE_BYTE,
521 4, exifInfo->gps_version_id);
522 writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE_REF, EXIF_TYPE_ASCII,
523 2, exifInfo->gps_latitude_ref);
524 writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE, EXIF_TYPE_RATIONAL,
525 3, exifInfo->gps_latitude, &LongerTagOffest, pIfdStart);
526 writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_TYPE_ASCII,
527 2, exifInfo->gps_longitude_ref);
528 writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE, EXIF_TYPE_RATIONAL,
529 3, exifInfo->gps_longitude, &LongerTagOffest, pIfdStart);
530 writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_TYPE_BYTE,
531 1, exifInfo->gps_altitude_ref);
532 writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE, EXIF_TYPE_RATIONAL,
533 1, &exifInfo->gps_altitude, &LongerTagOffest, pIfdStart);
534 writeExifIfd(&pCur, EXIF_TAG_GPS_TIMESTAMP, EXIF_TYPE_RATIONAL,
535 3, exifInfo->gps_timestamp, &LongerTagOffest, pIfdStart);
536 tmp = strlen((char*)exifInfo->gps_processing_method);
537 if (tmp > 0) {
538 if (tmp > 100) {
539 tmp = 100;
540 }
541 unsigned char tmp_buf[100+sizeof(ExifAsciiPrefix)];
542 memcpy(tmp_buf, ExifAsciiPrefix, sizeof(ExifAsciiPrefix));
543 memcpy(&tmp_buf[sizeof(ExifAsciiPrefix)], exifInfo->gps_processing_method, tmp);
544 writeExifIfd(&pCur, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_TYPE_UNDEFINED,
545 tmp+sizeof(ExifAsciiPrefix), tmp_buf, &LongerTagOffest, pIfdStart);
546 }
547 writeExifIfd(&pCur, EXIF_TAG_GPS_DATESTAMP, EXIF_TYPE_ASCII,
548 11, exifInfo->gps_datestamp, &LongerTagOffest, pIfdStart);
549 tmp = 0;
550 memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset
551 pCur += OFFSET_SIZE;
552 }
553
554 //2 1th IFD TIFF Tags
555 char *thumbBuf = NULL;
556 unsigned int thumbSize = 0;
557
558 if (useMainbufForThumb) {
559 if (m_jpegMain) {
560 thumbBuf = m_jpegMain->getOutBuf((int *)&thumbSize);
561 thumbSize = m_jpegMain->getJpegSize();
562 }
563 } else {
564 if (m_jpegThumb) {
565 thumbBuf = m_jpegThumb->getOutBuf((int *)&thumbSize);
566 thumbSize = m_jpegThumb->getJpegSize();
567 }
568 }
569
570 if (exifInfo->enableThumb && (thumbBuf != NULL) && (thumbSize != 0)) {
571 exifSizeExceptThumb = tmp = LongerTagOffest;
572 memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD
573
574 pCur = pIfdStart + LongerTagOffest;
575
576 tmp = NUM_1TH_IFD_TIFF;
577 memcpy(pCur, &tmp, NUM_SIZE);
578 pCur += NUM_SIZE;
579
580 LongerTagOffest += NUM_SIZE + NUM_1TH_IFD_TIFF*IFD_SIZE + OFFSET_SIZE;
581
582 writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG,
583 1, exifInfo->widthThumb);
584 writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG,
585 1, exifInfo->heightThumb);
586 writeExifIfd(&pCur, EXIF_TAG_COMPRESSION_SCHEME, EXIF_TYPE_SHORT,
587 1, exifInfo->compression_scheme);
588 writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT,
589 1, exifInfo->orientation);
590 writeExifIfd(&pCur, EXIF_TAG_X_RESOLUTION, EXIF_TYPE_RATIONAL,
591 1, &exifInfo->x_resolution, &LongerTagOffest, pIfdStart);
592 writeExifIfd(&pCur, EXIF_TAG_Y_RESOLUTION, EXIF_TYPE_RATIONAL,
593 1, &exifInfo->y_resolution, &LongerTagOffest, pIfdStart);
594 writeExifIfd(&pCur, EXIF_TAG_RESOLUTION_UNIT, EXIF_TYPE_SHORT,
595 1, exifInfo->resolution_unit);
596 writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_TYPE_LONG,
597 1, LongerTagOffest);
598 writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN, EXIF_TYPE_LONG,
599 1, thumbSize);
600
601 tmp = 0;
602 memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset
603 pCur += OFFSET_SIZE;
604
605 memcpy(pIfdStart + LongerTagOffest,
606 thumbBuf, thumbSize);
607 LongerTagOffest += thumbSize;
608 if (LongerTagOffest > EXIF_LIMIT_SIZE) {
609 LongerTagOffest = exifSizeExceptThumb;
610 tmp = 0;
611 memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD
612 }
613 } else {
614 tmp = 0;
615 memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD
616 }
617
618 unsigned char App1Marker[2] = { 0xff, 0xe1 };
619 memcpy(pApp1Start, App1Marker, 2);
620 pApp1Start += 2;
621
622 *size = 10 + LongerTagOffest;
623 tmp = *size - 2; // APP1 Maker isn't counted
624 unsigned char size_mm[2] = {(tmp >> 8) & 0xFF, tmp & 0xFF};
625 memcpy(pApp1Start, size_mm, 2);
626
627 return ERROR_NONE;
628}
629
630/*
631 * private member functions
632*/
633inline void SecJpegEncoder::writeExifIfd(unsigned char **pCur,
634 unsigned short tag,
635 unsigned short type,
636 unsigned int count,
637 unsigned int value)
638{
639 memcpy(*pCur, &tag, 2);
640 *pCur += 2;
641 memcpy(*pCur, &type, 2);
642 *pCur += 2;
643 memcpy(*pCur, &count, 4);
644 *pCur += 4;
645 memcpy(*pCur, &value, 4);
646 *pCur += 4;
647}
648
649inline void SecJpegEncoder::writeExifIfd(unsigned char **pCur,
650 unsigned short tag,
651 unsigned short type,
652 unsigned int count,
653 unsigned char *pValue)
654{
655 char buf[4] = { 0,};
656
657 memcpy(buf, pValue, count);
658 memcpy(*pCur, &tag, 2);
659 *pCur += 2;
660 memcpy(*pCur, &type, 2);
661 *pCur += 2;
662 memcpy(*pCur, &count, 4);
663 *pCur += 4;
664 memcpy(*pCur, buf, 4);
665 *pCur += 4;
666}
667
668inline void SecJpegEncoder::writeExifIfd(unsigned char **pCur,
669 unsigned short tag,
670 unsigned short type,
671 unsigned int count,
672 unsigned char *pValue,
673 unsigned int *offset,
674 unsigned char *start)
675{
676 memcpy(*pCur, &tag, 2);
677 *pCur += 2;
678 memcpy(*pCur, &type, 2);
679 *pCur += 2;
680 memcpy(*pCur, &count, 4);
681 *pCur += 4;
682 memcpy(*pCur, offset, 4);
683 *pCur += 4;
684 memcpy(start + *offset, pValue, count);
685 *offset += count;
686}
687
688inline void SecJpegEncoder::writeExifIfd(unsigned char **pCur,
689 unsigned short tag,
690 unsigned short type,
691 unsigned int count,
692 rational_t *pValue,
693 unsigned int *offset,
694 unsigned char *start)
695{
696 memcpy(*pCur, &tag, 2);
697 *pCur += 2;
698 memcpy(*pCur, &type, 2);
699 *pCur += 2;
700 memcpy(*pCur, &count, 4);
701 *pCur += 4;
702 memcpy(*pCur, offset, 4);
703 *pCur += 4;
704 memcpy(start + *offset, pValue, 8 * count);
705 *offset += 8 * count;
706}
707
708int SecJpegEncoder::m_scaleDownYuv422(char *srcBuf, unsigned int srcW, unsigned int srcH,
709 char *dstBuf, unsigned int dstW, unsigned int dstH)
710{
711 int step_x, step_y;
712 int iXsrc, iXdst;
713 int x, y, src_y_start_pos, dst_pos, src_pos;
714
715 if (dstW & 0x01 || dstH & 0x01) {
716 return ERROR_INVALID_SCALING_WIDTH_HEIGHT;
717 }
718
719 step_x = srcW / dstW;
720 step_y = srcH / dstH;
721
722 unsigned int srcWStride = srcW * 2;
723 unsigned int stepXStride = step_x * 2;
724
725 dst_pos = 0;
726 for (unsigned int y = 0; y < dstH; y++) {
727 src_y_start_pos = srcWStride * step_y * y;
728
729 for (unsigned int x = 0; x < dstW; x += 2) {
730 src_pos = src_y_start_pos + (stepXStride * x);
731
732 dstBuf[dst_pos++] = srcBuf[src_pos ];
733 dstBuf[dst_pos++] = srcBuf[src_pos + 1];
734 dstBuf[dst_pos++] = srcBuf[src_pos + 2];
735 dstBuf[dst_pos++] = srcBuf[src_pos + 3];
736 }
737 }
738
739 return ERROR_NONE;
740}
741
742// thumbnail
743int SecJpegEncoder::setThumbnailSize(int w, int h)
744{
745 if (m_flagCreate == false) {
746 return ERROR_CANNOT_CREATE_SEC_JPEG_ENC_HAL;
747 }
748
749 if (w < 0 || MAX_JPG_WIDTH < w) {
750 return false;
751 }
752
753 if (h < 0 || MAX_JPG_HEIGHT < h) {
754 return false;
755 }
756
757 m_thumbnailW = w;
758 m_thumbnailH = h;
759 return ERROR_NONE;
760}
761
762
763int SecJpegEncoder::encodeThumbnail(unsigned int *size, bool useMain)
764{
765 int ret = ERROR_NONE;
766
767 if (m_flagCreate == false) {
768 return ERROR_CANNOT_CREATE_SEC_JPEG_ENC_HAL;
769 }
770
771 // create jpeg thumbnail class
772 if (m_jpegThumb == NULL) {
773 m_jpegThumb = new SecJpegEncoderHal;
774
775 if (m_jpegThumb == NULL) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200776 JPEG_ERROR_ALOG("ERR(%s):Cannot open a jpeg device file\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200777 return ERROR_CANNOT_CREATE_SEC_THUMB;
778 }
779 }
780
781 ret = m_jpegThumb->create();
782 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200783 JPEG_ERROR_ALOG("ERR(%s):Fail create\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200784 return ret;
785 }
786
787 ret = m_jpegThumb->setCache(JPEG_CACHE_ON);
788 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200789 JPEG_ERROR_ALOG("ERR(%s):Fail cache set\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200790 return ret;
791 }
792
793 void *pConfig = m_jpegMain->getJpegConfig();
794 if (pConfig == NULL) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200795 JPEG_ERROR_ALOG("ERR(%s):Fail getJpegConfig\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200796 return ERROR_BUFFR_IS_NULL;
797 }
798
799 ret = m_jpegThumb->setJpegConfig(pConfig);
800 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200801 JPEG_ERROR_ALOG("ERR(%s):Fail setJpegConfig\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200802 return ret;
803 }
804
805 ret = m_jpegThumb->setQuality(JPEG_THUMBNAIL_QUALITY);
806 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200807 JPEG_ERROR_ALOG("ERR(%s):Fail setQuality\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200808 return ret;
809 }
810
811 ret = m_jpegThumb->setSize(m_thumbnailW, m_thumbnailH);
812 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200813 JPEG_ERROR_ALOG("ERR(%s):Fail setSize\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200814 return ret;
815 }
816
817 int iThumbSize = sizeof(char)*m_thumbnailW*m_thumbnailH*4;
818#ifdef JPEG_WA_FOR_PAGEFAULT
819 iThumbSize += JPEG_WA_BUFFER_SIZE;
820#endif //JPEG_WA_FOR_PAGEFAULT
821
822 freeJpegIonMemory(m_ionJpegClient, &m_ionThumbInBuffer, &m_pThumbInputBuffer, iThumbSize);
823 freeJpegIonMemory(m_ionJpegClient, &m_ionThumbOutBuffer, &m_pThumbOutputBuffer, iThumbSize);
824
825 if (m_ionJpegClient == 0) {
826 m_ionJpegClient = ion_client_create();
827 if (m_ionJpegClient < 0) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200828 JPEG_ERROR_ALOG("[%s]src ion client create failed, value = %d\n", __func__, m_ionJpegClient);
codeworkx62f02ba2012-05-20 12:00:36 +0200829 m_ionJpegClient = 0;
830 return ret;
831 }
832 }
833
834 ret = allocJpegIonMemory(m_ionJpegClient, &m_ionThumbInBuffer, &m_pThumbInputBuffer, iThumbSize);
835 if (ret != ERROR_NONE) {
836 return ret;
837 }
838
839 ret = m_jpegThumb->setInBuf(&m_pThumbInputBuffer, &iThumbSize);
840 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200841 JPEG_ERROR_ALOG("ERR(%s):Fail setInBuf\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200842 return ret;
843 }
844
845 ret = allocJpegIonMemory(m_ionJpegClient, &m_ionThumbOutBuffer, &m_pThumbOutputBuffer, iThumbSize);
846 if (ret != ERROR_NONE) {
847 return ret;
848 }
849
850 ret = m_jpegThumb->setOutBuf((char *)m_pThumbOutputBuffer, iThumbSize);
851 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200852 JPEG_ERROR_ALOG("ERR(%s):Fail setOutBuf\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200853 return ret;
854 }
855
856 ret = m_jpegThumb->updateConfig();
857 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200858 JPEG_ERROR_ALOG("update config failed\n");
codeworkx62f02ba2012-05-20 12:00:36 +0200859 return ret;
860 }
861
862 if (useMain) {
863
864 int iW=0, iH=0;
865 int input_sizeMain=0, input_sizeThumb=0;
866
867 ret = m_jpegMain->getSize(&iW, &iH);
868 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200869 JPEG_ERROR_ALOG("ERR(%s):Fail setJpegConfig\n", __func__);
codeworkx62f02ba2012-05-20 12:00:36 +0200870 return ret;
871 }
872
873 ret = m_scaleDownYuv422(*(m_jpegMain->getInBuf(&input_sizeMain)),
874 iW,
875 iH,
876 *(m_jpegThumb->getInBuf(&input_sizeThumb)),
877 m_thumbnailW,
878 m_thumbnailH);
879 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200880 JPEG_ERROR_ALOG("%s::m_scaleDownYuv422(%d, %d, %d, %d) fail", __func__, iW, iH, m_thumbnailW, m_thumbnailH);
codeworkx62f02ba2012-05-20 12:00:36 +0200881 return ret;
882 }
883 }
884 else {
885 return ERROR_IMPLEMENT_NOT_YET;
886 }
887
888 int outSizeThumb;
889
890 ret = m_jpegThumb->encode();
891 if (ret) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200892 JPEG_ERROR_ALOG("encode failed\n");
codeworkx62f02ba2012-05-20 12:00:36 +0200893 return ret;
894 }
895
896 outSizeThumb = m_jpegThumb->getJpegSize();
897 if (outSizeThumb<=0) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200898 JPEG_ERROR_ALOG("jpeg size is too small\n");
codeworkx62f02ba2012-05-20 12:00:36 +0200899 return ERROR_THUMB_JPEG_SIZE_TOO_SMALL;
900 }
901
902 *size = (unsigned int)outSizeThumb;
903
904 return ERROR_NONE;
905
906}
907
908int SecJpegEncoder::allocJpegIonMemory(ion_client ionClient, ion_buffer *ionBuffer, char **buffer, int size)
909{
910 int ret = ERROR_NONE;
911
912 if (ionClient == 0) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200913 JPEG_ERROR_ALOG("[%s]ionClient is zero (%d)\n", __func__, ionClient);
codeworkx62f02ba2012-05-20 12:00:36 +0200914 return ERROR_BUFFR_IS_NULL;
915 }
916
917 *ionBuffer = ion_alloc(ionClient, size, 0, ION_HEAP_SYSTEM_MASK);
918 if (*ionBuffer == -1) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200919 JPEG_ERROR_ALOG("[%s]ion_alloc(%d) failed\n", __func__, size);
codeworkx62f02ba2012-05-20 12:00:36 +0200920 *ionBuffer = 0;
921 return ret;
922 }
923
924 *buffer = (char *)ion_map(*ionBuffer, size, 0);
925 if (*buffer == MAP_FAILED) {
Daniel Hillenbrand0fdadca2012-07-22 15:45:33 +0200926 JPEG_ERROR_ALOG("[%s]src ion map failed(%d)\n", __func__, size);
codeworkx62f02ba2012-05-20 12:00:36 +0200927 ion_free(*ionBuffer);
928 *ionBuffer = 0;
929 *buffer = NULL;
930 return ret;
931 }
932
933 return ret;
934}
935
936void SecJpegEncoder::freeJpegIonMemory(ion_client ionClient, ion_buffer *ionBuffer, char **buffer, int size)
937{
938 if (ionClient == 0) {
939 return;
940 }
941
942 if (*buffer != NULL) {
943 ion_unmap(*buffer, size);
944 *buffer = NULL;
945 }
946
947 if (*ionBuffer != 0) {
948 ion_free(*ionBuffer);
949 *ionBuffer = 0;
950 }
951}
952