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