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