blob: d6d779ab443abfeb76ee08be72a2c32a4bf02466 [file] [log] [blame]
Chirayu Desai0a336cc2012-07-12 14:37:05 +05301/*
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 * JPEG DRIVER MODULE (JpegEncoder.cpp)
18 * Author : ge.lee -- initial version
19 * Date : 03 June 2010
20 * Purpose : This file implements the JPEG encoder APIs as needed by Camera HAL
21 */
22#define LOG_TAG "JpegEncoder"
23#define MAIN_DUMP 0
24#define THUMB_DUMP 0
25
26#include <utils/Log.h>
27#include <sys/mman.h>
28#include <fcntl.h>
rogersb11dbf394e2015-10-12 22:03:21 -040029#include <string.h>
Chirayu Desai0a336cc2012-07-12 14:37:05 +053030
31#include "JpegEncoder.h"
32
33static const char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };
34
35namespace android {
36JpegEncoder::JpegEncoder() : available(false)
37{
38 mArgs.mmapped_addr = (char *)MAP_FAILED;
39 mArgs.enc_param = NULL;
40 mArgs.thumb_enc_param = NULL;
41
42 mDevFd = open(JPG_DRIVER_NAME, O_RDWR);
43 if (mDevFd < 0) {
44 ALOGE("Failed to open the device");
45 return;
46 }
47
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +070048 // Must be exactly 0, legacy kernel will return 1 despite
49 // the IOCTL being invalid
50 if (ioctl(mDevFd, IOCTL_JPG_GET_INFO, &mInfo) != 0) {
51#ifdef LEGACY_SUPPORT
52 ALOGW("Unable to read driver info. Using legacy values.");
53 mInfo.frame_buf_size = JPG_FRAME_BUF_SIZE;
54 mInfo.thumb_frame_buf_size = JPG_FRAME_THUMB_BUF_SIZE;
55 mInfo.stream_buf_size = JPG_STREAM_BUF_SIZE;
56 mInfo.thumb_stream_buf_size = JPG_STREAM_THUMB_BUF_SIZE;
57 mInfo.total_buf_size = JPG_TOTAL_BUF_SIZE;
58 mInfo.max_width = MAX_JPG_WIDTH;
59 mInfo.max_height = MAX_JPG_HEIGHT;
60 mInfo.max_thumb_width = MAX_JPG_THUMBNAIL_WIDTH;
61 mInfo.max_thumb_height = MAX_JPG_THUMBNAIL_HEIGHT;
62#else
63 ALOGE("Unable to read driver info.");
64 return;
65#endif
66 }
67
Chirayu Desai0a336cc2012-07-12 14:37:05 +053068 mArgs.mmapped_addr = (char *)mmap(0,
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +070069 mInfo.total_buf_size,
Chirayu Desai0a336cc2012-07-12 14:37:05 +053070 PROT_READ | PROT_WRITE,
71 MAP_SHARED,
72 mDevFd,
73 0);
74
75 if (mArgs.mmapped_addr == MAP_FAILED) {
76 ALOGE("Failed to mmap");
77 return;
78 }
79
80 mArgs.enc_param = new jpg_enc_proc_param;
81 if (mArgs.enc_param == NULL) {
82 ALOGE("Failed to allocate the memory for enc_param");
83 return;
84 }
85 memset(mArgs.enc_param, 0, sizeof(jpg_enc_proc_param));
86
87 mArgs.thumb_enc_param = new jpg_enc_proc_param;
88 if (mArgs.thumb_enc_param == NULL) {
89 ALOGE("Failed to allocate the memory for thumb_enc_param");
90 delete mArgs.enc_param;
91 return;
92 }
93 memset(mArgs.thumb_enc_param, 0, sizeof(jpg_enc_proc_param));
94
95 mArgs.enc_param->sample_mode = JPG_420;
96 mArgs.enc_param->enc_type = JPG_MAIN;
97 mArgs.thumb_enc_param->sample_mode = JPG_420;
98 mArgs.thumb_enc_param->enc_type = JPG_THUMBNAIL;
99
100 available = true;
101}
102
103JpegEncoder::~JpegEncoder()
104{
105 if (mArgs.mmapped_addr != (char*)MAP_FAILED)
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +0700106 munmap(mArgs.mmapped_addr, mInfo.total_buf_size);
Chirayu Desai0a336cc2012-07-12 14:37:05 +0530107
108 delete mArgs.enc_param;
109
110 delete mArgs.thumb_enc_param;
111
112 if (mDevFd > 0)
113 close(mDevFd);
114}
115
116jpg_return_status JpegEncoder::setConfig(jpeg_conf type, int32_t value)
117{
118 if (!available)
119 return JPG_FAIL;
120
121 jpg_return_status ret = JPG_SUCCESS;
122
123 switch (type) {
124 case JPEG_SET_ENCODE_WIDTH:
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +0700125 if (value < 0 || value > mInfo.max_width)
Chirayu Desai0a336cc2012-07-12 14:37:05 +0530126 ret = JPG_FAIL;
127 else
128 mArgs.enc_param->width = value;
129 break;
130
131 case JPEG_SET_ENCODE_HEIGHT:
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +0700132 if (value < 0 || value > mInfo.max_height)
Chirayu Desai0a336cc2012-07-12 14:37:05 +0530133 ret = JPG_FAIL;
134 else
135 mArgs.enc_param->height = value;
136 break;
137
138 case JPEG_SET_ENCODE_QUALITY:
139 if (value < JPG_QUALITY_LEVEL_1 || value > JPG_QUALITY_LEVEL_4)
140 ret = JPG_FAIL;
141 else
142 mArgs.enc_param->quality = (image_quality_type_t)value;
143 break;
144
145 case JPEG_SET_ENCODE_IN_FORMAT:
146 if (value != JPG_MODESEL_YCBCR && value != JPG_MODESEL_RGB) {
147 ret = JPG_FAIL;
148 } else {
149 mArgs.enc_param->in_format = (in_mode_t)value;
150 mArgs.thumb_enc_param->in_format = (in_mode_t)value;
151 }
152 break;
153
154 case JPEG_SET_SAMPING_MODE:
155 if (value != JPG_420 && value != JPG_422) {
156 ret = JPG_FAIL;
157 } else {
158 mArgs.enc_param->sample_mode = (sample_mode_t)value;
159 mArgs.thumb_enc_param->sample_mode = (sample_mode_t)value;
160 }
161 break;
162
163 case JPEG_SET_THUMBNAIL_WIDTH:
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +0700164 if (value < 0 || value > mInfo.max_thumb_width)
Chirayu Desai0a336cc2012-07-12 14:37:05 +0530165 ret = JPG_FAIL;
166 else
167 mArgs.thumb_enc_param->width = value;
168 break;
169
170 case JPEG_SET_THUMBNAIL_HEIGHT:
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +0700171 if (value < 0 || value > mInfo.max_thumb_height)
Chirayu Desai0a336cc2012-07-12 14:37:05 +0530172 ret = JPG_FAIL;
173 else
174 mArgs.thumb_enc_param->height = value;
175 break;
176
177 default:
178 ALOGE("Invalid Config type");
179 ret = ERR_UNKNOWN;
180 }
181
182 if (ret == JPG_FAIL)
183 ALOGE("Invalid value(%d) for %d type", value, type);
184
185 return ret;
186}
187
188void* JpegEncoder::getInBuf(uint64_t size)
189{
190 if (!available)
191 return NULL;
192
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +0700193 if (size > mInfo.frame_buf_size) {
Chirayu Desai0a336cc2012-07-12 14:37:05 +0530194 ALOGE("The buffer size requested is too large");
195 return NULL;
196 }
197 mArgs.in_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_FRMBUF, mArgs.mmapped_addr);
198 return (void *)(mArgs.in_buf);
199}
200
201void* JpegEncoder::getOutBuf(uint64_t *size)
202{
203 if (!available)
204 return NULL;
205
206 if (mArgs.enc_param->file_size <= 0) {
207 ALOGE("The buffer requested doesn't have data");
208 return NULL;
209 }
210 mArgs.out_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_STRBUF, mArgs.mmapped_addr);
211 *size = mArgs.enc_param->file_size;
212 return (void *)(mArgs.out_buf);
213}
214
215void* JpegEncoder::getThumbInBuf(uint64_t size)
216{
217 if (!available)
218 return NULL;
219
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +0700220 if (size > mInfo.thumb_frame_buf_size) {
Chirayu Desai0a336cc2012-07-12 14:37:05 +0530221 ALOGE("The buffer size requested is too large");
222 return NULL;
223 }
224 mArgs.in_thumb_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_THUMB_FRMBUF, mArgs.mmapped_addr);
225 return (void *)(mArgs.in_thumb_buf);
226}
227
228void* JpegEncoder::getThumbOutBuf(uint64_t *size)
229{
230 if (!available)
231 return NULL;
232
233 if (mArgs.thumb_enc_param->file_size <= 0) {
234 ALOGE("The buffer requested doesn't have data");
235 return NULL;
236 }
237 mArgs.out_thumb_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_THUMB_STRBUF, mArgs.mmapped_addr);
238 *size = mArgs.thumb_enc_param->file_size;
239 return (void *)(mArgs.out_thumb_buf);
240}
241
242jpg_return_status JpegEncoder::encode(unsigned int *size, exif_attribute_t *exifInfo)
243{
244 if (!available)
245 return JPG_FAIL;
246
247 ALOGD("encode E");
248
249 jpg_return_status ret = JPG_FAIL;
250 unsigned char *exifOut = NULL;
251 jpg_enc_proc_param *param = mArgs.enc_param;
252
253 ret = checkMcu(param->sample_mode, param->width, param->height, false);
254 if (ret != JPG_SUCCESS)
255 return ret;
256
257 param->enc_type = JPG_MAIN;
258 ret = (jpg_return_status)ioctl(mDevFd, IOCTL_JPG_ENCODE, &mArgs);
259 if (ret != JPG_SUCCESS) {
260 ALOGE("Failed to encode main image");
261 return ret;
262 }
263
264 mArgs.out_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_STRBUF, mArgs.mmapped_addr);
265
266 if (exifInfo) {
267 unsigned int thumbLen, exifLen;
268
269 uint_t bufSize = 0;
270 if (exifInfo->enableThumb) {
271 ret = encodeThumbImg(&thumbLen);
272 if (ret != JPG_SUCCESS) {
273 ALOGE("Failed to encode for thumbnail image");
274 bufSize = EXIF_FILE_SIZE;
275 exifInfo->enableThumb = false;
276 } else {
277 bufSize = EXIF_FILE_SIZE + thumbLen;
278 }
279 } else {
280 bufSize = EXIF_FILE_SIZE;
281 }
282
Pawit Pornkitprasan674a4f12014-01-03 19:13:37 +0700283 if (mArgs.enc_param->file_size + bufSize > mInfo.total_buf_size)
Chirayu Desai0a336cc2012-07-12 14:37:05 +0530284 return ret;
285
286 exifOut = new unsigned char[bufSize];
287 if (exifOut == NULL) {
288 ALOGE("Failed to allocate for exifOut");
289 return ret;
290 }
291 memset(exifOut, 0, bufSize);
292
293 ret = makeExif (exifOut, exifInfo, &exifLen);
294 if (ret != JPG_SUCCESS) {
295 ALOGE("Failed to make EXIF");
296 delete[] exifOut;
297 return ret;
298 }
299
300 memmove(&mArgs.out_buf[exifLen + 2], &mArgs.out_buf[2], param->file_size - 2);
301 memcpy(&mArgs.out_buf[2], exifOut, exifLen);
302 param->file_size += exifLen;
303 }
304
305 delete[] exifOut;
306
307 *size = param->file_size;
308
309#if MAIN_DUMP
310 FILE *fout = NULL;
311 char file_name[50] = "/data/main.jpg";
312 fout = fopen(file_name, "wb");
313 if (!fout)
314 perror(&file_name[0]);
315 size_t nwrite = fwrite(mArgs.out_buf, sizeof(char), param->file_size, fout);
316 fclose(fout);
317#endif
318
319 ALOGD("encode X");
320
321 return ret;
322}
323
324jpg_return_status JpegEncoder::encodeThumbImg(unsigned int *size, bool useMain)
325{
326 if (!available)
327 return JPG_FAIL;
328
329 ALOGD("encodeThumbImg E");
330
331 jpg_return_status ret = JPG_FAIL;
332 jpg_enc_proc_param *param = mArgs.thumb_enc_param;
333
334 if (useMain) {
335 mArgs.in_thumb_buf = (char *)getThumbInBuf(param->width*param->height*2);
336 if (mArgs.in_thumb_buf == NULL) {
337 ALOGE("Failed to get the buffer for thumbnail");
338 return JPG_FAIL;
339 }
340
341 ret = (jpg_return_status)scaleDownYuv422(mArgs.in_buf,
342 mArgs.enc_param->width,
343 mArgs.enc_param->height,
344 mArgs.in_thumb_buf,
345 param->width,
346 param->height);
347 if (ret != JPG_SUCCESS)
348 return JPG_FAIL;
349 }
350
351 ret = checkMcu(param->sample_mode, param->width, param->height, true);
352 if (ret != JPG_SUCCESS)
353 return JPG_FAIL;
354
355 mArgs.enc_param->enc_type = JPG_THUMBNAIL;
356 ret = (jpg_return_status)ioctl(mDevFd, IOCTL_JPG_ENCODE, &mArgs);
357 if (ret != JPG_SUCCESS) {
358 ALOGE("Failed to encode for thumbnail");
359 return JPG_FAIL;
360 }
361
362 mArgs.out_thumb_buf = (char *)ioctl(mDevFd, IOCTL_JPG_GET_THUMB_STRBUF, mArgs.mmapped_addr);
363
364#if THUMB_DUMP
365 FILE *fout = NULL;
366 char file_name[50] = "/data/thumb.jpg";
367 fout = fopen(file_name, "wb");
368 if (!fout)
369 perror(&file_name[0]);
370 size_t nwrite = fwrite(mArgs.out_thumb_buf, sizeof(char), param->file_size, fout);
371 fclose(fout);
372#endif
373
374 ALOGD("encodeThumbImg X");
375
376 return JPG_SUCCESS;
377}
378
379jpg_return_status JpegEncoder::makeExif (unsigned char *exifOut,
380 exif_attribute_t *exifInfo,
381 unsigned int *size,
382 bool useMainbufForThumb)
383{
384 if (!available)
385 return JPG_FAIL;
386
387 ALOGD("makeExif E");
388
389 unsigned char *pCur, *pApp1Start, *pIfdStart, *pGpsIfdPtr, *pNextIfdOffset;
390 unsigned int tmp, LongerTagOffest = 0;
391 pApp1Start = pCur = exifOut;
392
393 //2 Exif Identifier Code & TIFF Header
394 pCur += 4; // Skip 4 Byte for APP1 marker and length
395 unsigned char ExifIdentifierCode[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
396 memcpy(pCur, ExifIdentifierCode, 6);
397 pCur += 6;
398
399 /* Byte Order - little endian, Offset of IFD - 0x00000008.H */
400 unsigned char TiffHeader[8] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 };
401 memcpy(pCur, TiffHeader, 8);
402 pIfdStart = pCur;
403 pCur += 8;
404
405 //2 0th IFD TIFF Tags
406 if (exifInfo->enableGps)
407 tmp = NUM_0TH_IFD_TIFF;
408 else
409 tmp = NUM_0TH_IFD_TIFF - 1;
410
411 memcpy(pCur, &tmp, NUM_SIZE);
412 pCur += NUM_SIZE;
413
414 LongerTagOffest += 8 + NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE;
415
416 writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG,
417 1, exifInfo->width);
418 writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG,
419 1, exifInfo->height);
420 writeExifIfd(&pCur, EXIF_TAG_MAKE, EXIF_TYPE_ASCII,
421 strlen((char *)exifInfo->maker) + 1, exifInfo->maker, &LongerTagOffest, pIfdStart);
422 writeExifIfd(&pCur, EXIF_TAG_MODEL, EXIF_TYPE_ASCII,
423 strlen((char *)exifInfo->model) + 1, exifInfo->model, &LongerTagOffest, pIfdStart);
424 writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT,
425 1, exifInfo->orientation);
426 writeExifIfd(&pCur, EXIF_TAG_SOFTWARE, EXIF_TYPE_ASCII,
427 strlen((char *)exifInfo->software) + 1, exifInfo->software, &LongerTagOffest, pIfdStart);
428 writeExifIfd(&pCur, EXIF_TAG_DATE_TIME, EXIF_TYPE_ASCII,
429 20, exifInfo->date_time, &LongerTagOffest, pIfdStart);
430 writeExifIfd(&pCur, EXIF_TAG_YCBCR_POSITIONING, EXIF_TYPE_SHORT,
431 1, exifInfo->ycbcr_positioning);
432 writeExifIfd(&pCur, EXIF_TAG_EXIF_IFD_POINTER, EXIF_TYPE_LONG,
433 1, LongerTagOffest);
434 if (exifInfo->enableGps) {
435 pGpsIfdPtr = pCur;
436 pCur += IFD_SIZE; // Skip a ifd size for gps IFD pointer
437 }
438
439 pNextIfdOffset = pCur; // Skip a offset size for next IFD offset
440 pCur += OFFSET_SIZE;
441
442 //2 0th IFD Exif Private Tags
443 pCur = pIfdStart + LongerTagOffest;
444
445 tmp = NUM_0TH_IFD_EXIF;
446 memcpy(pCur, &tmp , NUM_SIZE);
447 pCur += NUM_SIZE;
448
449 LongerTagOffest += NUM_SIZE + NUM_0TH_IFD_EXIF*IFD_SIZE + OFFSET_SIZE;
450
451 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_TIME, EXIF_TYPE_RATIONAL,
452 1, &exifInfo->exposure_time, &LongerTagOffest, pIfdStart);
453 writeExifIfd(&pCur, EXIF_TAG_FNUMBER, EXIF_TYPE_RATIONAL,
454 1, &exifInfo->fnumber, &LongerTagOffest, pIfdStart);
455 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_PROGRAM, EXIF_TYPE_SHORT,
456 1, exifInfo->exposure_program);
457 writeExifIfd(&pCur, EXIF_TAG_ISO_SPEED_RATING, EXIF_TYPE_SHORT,
458 1, exifInfo->iso_speed_rating);
459 writeExifIfd(&pCur, EXIF_TAG_EXIF_VERSION, EXIF_TYPE_UNDEFINED,
460 4, exifInfo->exif_version);
461 writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_ORG, EXIF_TYPE_ASCII,
462 20, exifInfo->date_time, &LongerTagOffest, pIfdStart);
463 writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_TYPE_ASCII,
464 20, exifInfo->date_time, &LongerTagOffest, pIfdStart);
465 writeExifIfd(&pCur, EXIF_TAG_SHUTTER_SPEED, EXIF_TYPE_SRATIONAL,
466 1, (rational_t *)&exifInfo->shutter_speed, &LongerTagOffest, pIfdStart);
467 writeExifIfd(&pCur, EXIF_TAG_APERTURE, EXIF_TYPE_RATIONAL,
468 1, &exifInfo->aperture, &LongerTagOffest, pIfdStart);
469 writeExifIfd(&pCur, EXIF_TAG_BRIGHTNESS, EXIF_TYPE_SRATIONAL,
470 1, (rational_t *)&exifInfo->brightness, &LongerTagOffest, pIfdStart);
471 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_BIAS, EXIF_TYPE_SRATIONAL,
472 1, (rational_t *)&exifInfo->exposure_bias, &LongerTagOffest, pIfdStart);
473 writeExifIfd(&pCur, EXIF_TAG_MAX_APERTURE, EXIF_TYPE_RATIONAL,
474 1, &exifInfo->max_aperture, &LongerTagOffest, pIfdStart);
475 writeExifIfd(&pCur, EXIF_TAG_METERING_MODE, EXIF_TYPE_SHORT,
476 1, exifInfo->metering_mode);
477 writeExifIfd(&pCur, EXIF_TAG_FLASH, EXIF_TYPE_SHORT,
478 1, exifInfo->flash);
479 writeExifIfd(&pCur, EXIF_TAG_FOCAL_LENGTH, EXIF_TYPE_RATIONAL,
480 1, &exifInfo->focal_length, &LongerTagOffest, pIfdStart);
481 char code[8] = { 0x00, 0x00, 0x00, 0x49, 0x49, 0x43, 0x53, 0x41 };
482 int commentsLen = strlen((char *)exifInfo->user_comment) + 1;
483 memmove(exifInfo->user_comment + sizeof(code), exifInfo->user_comment, commentsLen);
484 memcpy(exifInfo->user_comment, code, sizeof(code));
485 writeExifIfd(&pCur, EXIF_TAG_USER_COMMENT, EXIF_TYPE_UNDEFINED,
486 commentsLen + sizeof(code), exifInfo->user_comment, &LongerTagOffest, pIfdStart);
487 writeExifIfd(&pCur, EXIF_TAG_COLOR_SPACE, EXIF_TYPE_SHORT,
488 1, exifInfo->color_space);
489 writeExifIfd(&pCur, EXIF_TAG_PIXEL_X_DIMENSION, EXIF_TYPE_LONG,
490 1, exifInfo->width);
491 writeExifIfd(&pCur, EXIF_TAG_PIXEL_Y_DIMENSION, EXIF_TYPE_LONG,
492 1, exifInfo->height);
493 writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_MODE, EXIF_TYPE_LONG,
494 1, exifInfo->exposure_mode);
495 writeExifIfd(&pCur, EXIF_TAG_WHITE_BALANCE, EXIF_TYPE_LONG,
496 1, exifInfo->white_balance);
497 writeExifIfd(&pCur, EXIF_TAG_SCENCE_CAPTURE_TYPE, EXIF_TYPE_LONG,
498 1, exifInfo->scene_capture_type);
499 tmp = 0;
500 memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset
501 pCur += OFFSET_SIZE;
502
503 //2 0th IFD GPS Info Tags
504 if (exifInfo->enableGps) {
505 writeExifIfd(&pGpsIfdPtr, EXIF_TAG_GPS_IFD_POINTER, EXIF_TYPE_LONG,
506 1, LongerTagOffest); // GPS IFD pointer skipped on 0th IFD
507
508 pCur = pIfdStart + LongerTagOffest;
509
510 if (exifInfo->gps_processing_method[0] == 0) {
511 // don't create GPS_PROCESSING_METHOD tag if there isn't any
512 tmp = NUM_0TH_IFD_GPS - 1;
513 } else {
514 tmp = NUM_0TH_IFD_GPS;
515 }
516 memcpy(pCur, &tmp, NUM_SIZE);
517 pCur += NUM_SIZE;
518
519 LongerTagOffest += NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE;
520
521 writeExifIfd(&pCur, EXIF_TAG_GPS_VERSION_ID, EXIF_TYPE_BYTE,
522 4, exifInfo->gps_version_id);
523 writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE_REF, EXIF_TYPE_ASCII,
524 2, exifInfo->gps_latitude_ref);
525 writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE, EXIF_TYPE_RATIONAL,
526 3, exifInfo->gps_latitude, &LongerTagOffest, pIfdStart);
527 writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_TYPE_ASCII,
528 2, exifInfo->gps_longitude_ref);
529 writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE, EXIF_TYPE_RATIONAL,
530 3, exifInfo->gps_longitude, &LongerTagOffest, pIfdStart);
531 writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_TYPE_BYTE,
532 1, exifInfo->gps_altitude_ref);
533 writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE, EXIF_TYPE_RATIONAL,
534 1, &exifInfo->gps_altitude, &LongerTagOffest, pIfdStart);
535 writeExifIfd(&pCur, EXIF_TAG_GPS_TIMESTAMP, EXIF_TYPE_RATIONAL,
536 3, exifInfo->gps_timestamp, &LongerTagOffest, pIfdStart);
537 tmp = strlen((char*)exifInfo->gps_processing_method);
538 if (tmp > 0) {
539 if (tmp > 100) {
540 tmp = 100;
541 }
542 unsigned char tmp_buf[100+sizeof(ExifAsciiPrefix)];
543 memcpy(tmp_buf, ExifAsciiPrefix, sizeof(ExifAsciiPrefix));
544 memcpy(&tmp_buf[sizeof(ExifAsciiPrefix)], exifInfo->gps_processing_method, tmp);
545 writeExifIfd(&pCur, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_TYPE_UNDEFINED,
546 tmp+sizeof(ExifAsciiPrefix), tmp_buf, &LongerTagOffest, pIfdStart);
547 }
548 writeExifIfd(&pCur, EXIF_TAG_GPS_DATESTAMP, EXIF_TYPE_ASCII,
549 11, exifInfo->gps_datestamp, &LongerTagOffest, pIfdStart);
550 tmp = 0;
551 memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset
552 pCur += OFFSET_SIZE;
553 }
554
555 //2 1th IFD TIFF Tags
556 char *thumbBuf;
557 int thumbSize;
558
559 if (useMainbufForThumb) {
560 thumbBuf = mArgs.out_buf;
561 thumbSize = mArgs.enc_param->file_size;
562 } else {
563 thumbBuf = mArgs.out_thumb_buf;
564 thumbSize = mArgs.thumb_enc_param->file_size;
565 }
566
567 if (exifInfo->enableThumb && (thumbBuf != NULL) && (thumbSize > 0)) {
568 tmp = LongerTagOffest;
569 memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD
570
571 pCur = pIfdStart + LongerTagOffest;
572
573 tmp = NUM_1TH_IFD_TIFF;
574 memcpy(pCur, &tmp, NUM_SIZE);
575 pCur += NUM_SIZE;
576
577 LongerTagOffest += NUM_SIZE + NUM_1TH_IFD_TIFF*IFD_SIZE + OFFSET_SIZE;
578
579 writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG,
580 1, exifInfo->widthThumb);
581 writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG,
582 1, exifInfo->heightThumb);
583 writeExifIfd(&pCur, EXIF_TAG_COMPRESSION_SCHEME, EXIF_TYPE_SHORT,
584 1, exifInfo->compression_scheme);
585 writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT,
586 1, exifInfo->orientation);
587 writeExifIfd(&pCur, EXIF_TAG_X_RESOLUTION, EXIF_TYPE_RATIONAL,
588 1, &exifInfo->x_resolution, &LongerTagOffest, pIfdStart);
589 writeExifIfd(&pCur, EXIF_TAG_Y_RESOLUTION, EXIF_TYPE_RATIONAL,
590 1, &exifInfo->y_resolution, &LongerTagOffest, pIfdStart);
591 writeExifIfd(&pCur, EXIF_TAG_RESOLUTION_UNIT, EXIF_TYPE_SHORT,
592 1, exifInfo->resolution_unit);
593 writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_TYPE_LONG,
594 1, LongerTagOffest);
595 writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN, EXIF_TYPE_LONG,
596 1, thumbSize);
597
598 tmp = 0;
599 memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset
600 pCur += OFFSET_SIZE;
601
602 memcpy(pIfdStart + LongerTagOffest,
603 thumbBuf, thumbSize);
604 LongerTagOffest += thumbSize;
605 } else {
606 tmp = 0;
607 memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD
608 }
609
610 unsigned char App1Marker[2] = { 0xff, 0xe1 };
611 memcpy(pApp1Start, App1Marker, 2);
612 pApp1Start += 2;
613
614 *size = 10 + LongerTagOffest;
615 tmp = *size - 2; // APP1 Maker isn't counted
616 unsigned char size_mm[2] = {(tmp >> 8) & 0xFF, tmp & 0xFF};
617 memcpy(pApp1Start, size_mm, 2);
618
619 ALOGD("makeExif X");
620
621 return JPG_SUCCESS;
622}
623
624jpg_return_status JpegEncoder::checkMcu(sample_mode_t sampleMode,
625 uint32_t width, uint32_t height, bool isThumb)
626{
627 if (!available)
628 return JPG_FAIL;
629
630 uint32_t expectedWidth = width;
631 uint32_t expectedHeight = height;
632
633 switch (sampleMode){
634 case JPG_422:
635 if (width % 16 != 0)
636 expectedWidth = width + 16 - (width % 16);
637 if (height % 8 != 0)
638 expectedHeight = height + 8 - (height % 8);
639 break;
640
641 case JPG_420:
642 if (width % 16 != 0)
643 expectedWidth = width + 16 - (width % 16);
644 if (height % 16 != 0)
645 expectedHeight = height + 16 - (height % 16);
646 break;
647
648 default:
649 ALOGE("Invaild sample mode");
650 return JPG_FAIL;
651 }
652
653 if (expectedWidth == width && expectedHeight == height)
654 return JPG_SUCCESS;
655
656 ALOGW("The image is not matched for MCU");
657
658 uint32_t size = width*height * 2;
659 char *srcBuf, *dstBuf;
660
661 if ((srcBuf = new char[size]) == NULL) {
662 ALOGE("Failed to allocate for srcBuf");
663 return JPG_FAIL;
664 }
665
666 if (!isThumb)
667 dstBuf = mArgs.in_buf;
668 else
669 dstBuf = mArgs.in_thumb_buf;
670
671 memcpy(srcBuf, dstBuf, size);
672 bool ret = pad(srcBuf, width, height, dstBuf, expectedWidth, expectedHeight);
673
674 delete[] srcBuf;
675
676 return JPG_SUCCESS;
677}
678
679bool JpegEncoder::pad(char *srcBuf, uint32_t srcWidth, uint32_t srcHight,
680 char *dstBuf, uint32_t dstWidth, uint32_t dstHight)
681{
682 if (!available)
683 return false;
684
685 if (srcBuf == NULL || dstBuf == NULL) {
686 ALOGE("srcBuf or dstBuf is NULL");
687 return false;
688 }
689
690 int padW = dstWidth - srcWidth;
691 int padH = dstHight - srcHight;
692
693 if ((int)(dstWidth - srcWidth) < 0 ||
694 (int)(dstHight - srcHight) < 0) {
695 ALOGE("dstSize is smaller than srcSize");
696 return false;
697 }
698 memset(dstBuf, 0, dstWidth*dstHight * 2);
699
700 for (uint32_t i = 0; i < srcHight; i++)
701 memcpy(dstBuf + i * dstWidth * 2, srcBuf + i * srcWidth * 2, srcWidth * 2);
702
703 return true;
704}
705
706bool JpegEncoder::scaleDownYuv422(char *srcBuf, uint32_t srcWidth, uint32_t srcHight,
707 char *dstBuf, uint32_t dstWidth, uint32_t dstHight)
708{
709 if (!available)
710 return false;
711
712 int32_t step_x, step_y;
713 int32_t iXsrc, iXdst;
714 int32_t x, y, src_y_start_pos, dst_pos, src_pos;
715
716 if (dstWidth % 2 != 0 || dstHight % 2 != 0){
717 ALOGE("scale_down_yuv422: invalid width, height for scaling");
718 return false;
719 }
720
721 step_x = srcWidth / dstWidth;
722 step_y = srcHight / dstHight;
723
724 dst_pos = 0;
725 for (uint32_t y = 0; y < dstHight; y++) {
726 src_y_start_pos = (y * step_y * (srcWidth * 2));
727
728 for (uint32_t x = 0; x < dstWidth; x += 2) {
729 src_pos = src_y_start_pos + (x * (step_x * 2));
730
731 dstBuf[dst_pos++] = srcBuf[src_pos ];
732 dstBuf[dst_pos++] = srcBuf[src_pos + 1];
733 dstBuf[dst_pos++] = srcBuf[src_pos + 2];
734 dstBuf[dst_pos++] = srcBuf[src_pos + 3];
735 }
736 }
737
738 return true;
739}
740
741inline void JpegEncoder::writeExifIfd(unsigned char **pCur,
742 unsigned short tag,
743 unsigned short type,
744 unsigned int count,
745 uint32_t value)
746{
747 memcpy(*pCur, &tag, 2);
748 *pCur += 2;
749 memcpy(*pCur, &type, 2);
750 *pCur += 2;
751 memcpy(*pCur, &count, 4);
752 *pCur += 4;
753 memcpy(*pCur, &value, 4);
754 *pCur += 4;
755}
756
757inline void JpegEncoder::writeExifIfd(unsigned char **pCur,
758 unsigned short tag,
759 unsigned short type,
760 unsigned int count,
761 unsigned char *pValue)
762{
763 char buf[4] = { 0,};
764
765 memcpy(buf, pValue, count);
766 memcpy(*pCur, &tag, 2);
767 *pCur += 2;
768 memcpy(*pCur, &type, 2);
769 *pCur += 2;
770 memcpy(*pCur, &count, 4);
771 *pCur += 4;
772 memcpy(*pCur, buf, 4);
773 *pCur += 4;
774}
775
776
777inline void JpegEncoder::writeExifIfd(unsigned char **pCur,
778 unsigned short tag,
779 unsigned short type,
780 unsigned int count,
781 unsigned char *pValue,
782 unsigned int *offset,
783 unsigned char *start)
784{
785 memcpy(*pCur, &tag, 2);
786 *pCur += 2;
787 memcpy(*pCur, &type, 2);
788 *pCur += 2;
789 memcpy(*pCur, &count, 4);
790 *pCur += 4;
791 memcpy(*pCur, offset, 4);
792 *pCur += 4;
793 memcpy(start + *offset, pValue, count);
794 *offset += count;
795}
796
797inline void JpegEncoder::writeExifIfd(unsigned char **pCur,
798 unsigned short tag,
799 unsigned short type,
800 unsigned int count,
801 rational_t *pValue,
802 unsigned int *offset,
803 unsigned char *start)
804{
805 memcpy(*pCur, &tag, 2);
806 *pCur += 2;
807 memcpy(*pCur, &type, 2);
808 *pCur += 2;
809 memcpy(*pCur, &count, 4);
810 *pCur += 4;
811 memcpy(*pCur, offset, 4);
812 *pCur += 4;
813 memcpy(start + *offset, pValue, 8 * count);
814 *offset += 8 * count;
815}
816
817};