summaryrefslogtreecommitdiff
path: root/v3/fake-pipeline2/JpegCompressor.cpp (plain)
blob: 6a24882ffb60b9d8d6cb55ea651807e4286d8f09
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "EmulatedCamera3_JpegCompressor"
19
20#include <utils/Log.h>
21#include <ui/GraphicBufferMapper.h>
22
23#include "JpegCompressor.h"
24#include "../EmulatedFakeCamera2.h"
25#include "../EmulatedFakeCamera3.h"
26#include <stdlib.h>
27#include <math.h>
28#include <sys/time.h>
29#include <cutils/properties.h>
30#include "NV12_resize.h"
31
32
33#define EXIF_MAKE_DEFAULT "default_make"
34#define EXIF_MODEL_DEFAULT "default_model"
35#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0]))
36#define FILE_BYTE_ORDER EXIF_BYTE_ORDER_INTEL
37
38const size_t MARKER_LENGTH = 2; // length of a marker
39const uint8_t MARK = 0xFF;
40const uint8_t EOI = 0xD9;
41bool checkJpegEnd(uint8_t *buf) {
42 return buf[0] == MARK && buf[1] == EOI;
43}
44int extraSmallImg(unsigned char* SrcImg,int SrcW,int SrcH,
45 unsigned char* DstImg,int DstW,int DstH)
46{
47 int skipW = SrcW/DstW;
48 int skipH = SrcH/DstH;
49 unsigned char* dst = DstImg;
50 unsigned char* srcrow = SrcImg;
51 unsigned char* srcrowidx = srcrow;
52 int i = 0,j = 0;
53 for (; i<DstH; i++)
54 {
55 for (j = 0; j<DstW; j++)
56 {
57 dst[0] = srcrowidx[0];
58 dst[1] = srcrowidx[1];
59 dst[2] = srcrowidx[2];
60 dst += 3;
61 srcrowidx += 3*skipW;
62 }
63 srcrow += skipH*SrcW*3;
64 srcrowidx = srcrow;
65 }
66 return 1;
67}
68
69/* start of JPEG image data section */
70static const unsigned int image_data_offset = 20;
71
72/* raw EXIF header data */
73static const unsigned char exif_header[] = {
74 0xff, 0xd8, 0xff, 0xe1
75};
76/* length of data in exif_header */
77static const unsigned int exif_header_len = sizeof(exif_header);
78
79
80namespace android {
81
82struct string_pair {
83 const char* string1;
84 const char* string2;
85};
86static string_pair degress_to_exif_lut [] = {
87 {"0", "1"},
88 {"90", "6"},
89 {"180", "3"},
90 {"270", "8"},
91};
92
93struct params {
94 uint8_t* src;
95 int src_size;
96 uint8_t* dst;
97 int dst_size;
98 int quality;
99 int in_width;
100 int in_height;
101 int out_width;
102 int out_height;
103 int format;
104 size_t jpeg_size;
105};
106
107enum format {
108 YUV420SP,
109 YUV422I,
110 RGB24,
111};
112
113JpegCompressor::JpegCompressor():
114 Thread(false),
115 mIsBusy(false),
116 mSynchronous(false),
117 mExitJpegThread(false),
118 mNeedexif(true),
119 mMainJpegSize(0),
120 mThumbJpegSize(0),
121 mSrcThumbBuffer(NULL),
122 mDstThumbBuffer(NULL),
123 mBuffers(NULL),
124 mPendingrequest(0),
125 mListener(NULL) {
126 memset(&mInfo,0,sizeof(struct ExifInfo));
127}
128
129JpegCompressor::~JpegCompressor() {
130 Mutex::Autolock lock(mMutex);
131}
132
133void JpegCompressor::queueRequest(CaptureRequest &r) {
134 Mutex::Autolock lock(mMutex);
135
136 CaptureRequest* ri = new CaptureRequest();
137 ri->buf = new camera3_stream_buffer();
138 memcpy(ri->buf,r.buf,sizeof(camera3_stream_buffer_t));
139 ri->frameNumber = r.frameNumber;
140 ri->sensorBuffers = r.sensorBuffers;
141 ri->mNeedThumbnail = r.mNeedThumbnail;
142 mInJpegRequestQueue.push_back(ri);
143
144 mPendingrequest++;
145 mInJpegRequestSignal.signal();
146}
147
148status_t JpegCompressor::start() {
149 status_t res;
150 res = run("EmulatedFakeCamera2::JpegCompressor");
151 if (res != OK) {
152 ALOGE("%s: Unable to start up compression thread: %s (%d)",
153 __FUNCTION__, strerror(-res), res);
154 }
155 return res;
156}
157
158status_t JpegCompressor::setlistener(JpegListener *listener) {
159 status_t res = NO_ERROR;
160 if (listener == NULL) {
161 ALOGE("%s: NULL listener not allowed!", __FUNCTION__);
162 return BAD_VALUE;
163 }
164 Mutex::Autolock lock(mMutex);
165 {
166 Mutex::Autolock busyLock(mBusyMutex);
167
168 if (mIsBusy) {
169 ALOGE("%s: Already processing a buffer!", __FUNCTION__);
170 return INVALID_OPERATION;
171 }
172
173 mSynchronous = false;
174 mListener = listener;
175 }
176 return res;
177}
178
179status_t JpegCompressor::compressSynchronous(Buffers *buffers) {
180 status_t res;
181
182 Mutex::Autolock lock(mMutex);
183 {
184 Mutex::Autolock busyLock(mBusyMutex);
185
186 if (mIsBusy) {
187 ALOGE("%s: Already processing a buffer!", __FUNCTION__);
188 return INVALID_OPERATION;
189 }
190
191 mIsBusy = true;
192 mSynchronous = true;
193 mBuffers = buffers;
194 }
195
196 res = compress();
197
198 cleanUp();
199
200 return res;
201}
202
203status_t JpegCompressor::cancel() {
204 mMutex.lock();
205 mExitJpegThread = true;
206 mPendingrequest++;
207 mInJpegRequestSignal.signal();
208 mMutex.unlock();
209 requestExitAndWait();
210 for (List<CaptureRequest*>::iterator i = mInJpegRequestQueue.begin();
211 i != mInJpegRequestQueue.end(); i++) {
212 delete (*i)->buf;
213 delete (*i)->sensorBuffers;
214 }
215
216 return OK;
217}
218
219status_t JpegCompressor::readyToRun() {
220 return OK;
221}
222
223status_t JpegCompressor::Create_Exif_Use_Libjpeg() {
224 ExifElementsTable* exiftable = NULL;
225 struct camera2_jpeg_blob blob;
226 int offset;
227 status_t res;
228 if (mNeedexif) {
229 memset(&blob,0,sizeof(struct camera2_jpeg_blob));
230 exiftable = new ExifElementsTable();
231 GenExif(exiftable);
232 }
233
234 if (mJpegRequest.mNeedThumbnail) {
235 res = thumbcompress();
236 }
237
238 if (exiftable) {
239 uint32_t realjpegsize = 0;
240 Section_t* exif_section = NULL;
241 ExifElementsTable* exif = exiftable;
242 exif->insertExifToJpeg((unsigned char*)mJpegBuffer.img,mMainJpegSize);
243 if ((mJpegRequest.mNeedThumbnail) && (mDstThumbBuffer != NULL)) {
244 exif->insertExifThumbnailImage((const char*)mDstThumbBuffer,mThumbJpegSize);
245 }
246 exif_section = FindSection(M_EXIF);
247 if (exif_section) {
248 exif->saveJpeg((unsigned char*) mJpegBuffer.img, mMainJpegSize + exif_section->Size);
249 }
250 for (uint32_t size = (mMainJpegSize + exif_section->Size - 2); size > 0; size--) {
251 if (checkJpegEnd(mJpegBuffer.img + size)) {
252 realjpegsize = (size + MARKER_LENGTH);
253 break;
254 }
255 }
256 offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
257 blob.jpeg_blob_id = 0x00FF;
258 blob.jpeg_size = realjpegsize;
259 memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
260 }
261
262 if (mNeedexif) {
263 if (exiftable != NULL) {
264 delete exiftable;
265 exiftable = NULL;
266 }
267 }
268 return res;
269}
270
271status_t JpegCompressor::Create_Exif_Use_Libexif() {
272 struct camera2_jpeg_blob blob;
273 int offset;
274 status_t res;
275 memset(&blob,0,sizeof(struct camera2_jpeg_blob));
276 if (mNeedexif) {
277 uint32_t realjpegsize = 0;
278 if (mJpegRequest.mNeedThumbnail) {
279 res = thumbcompress();
280 }
281
282 exif_buffer *sEb = get_exif_buffer();
283 if (sEb != NULL) {
284 if (mJpegRequest.mNeedThumbnail) {
285 uint8_t * mTempJpegBuffer = (uint8_t *)malloc(mMainJpegSize + sEb->size + mThumbJpegSize);
286 memset(mTempJpegBuffer, 0, sizeof(char) * (mMainJpegSize + sEb->size + mThumbJpegSize));
287 memcpy(mTempJpegBuffer, exif_header, exif_header_len);
288 mTempJpegBuffer[exif_header_len] = (sEb->size + mThumbJpegSize + 2) >> 8;
289 mTempJpegBuffer[exif_header_len + 1] = ((sEb->size + mThumbJpegSize + 2) & 0xff);
290 memcpy(mTempJpegBuffer + exif_header_len + 2, sEb->data, sEb->size);
291 memcpy(mTempJpegBuffer + exif_header_len + sEb->size + 2, mDstThumbBuffer, mThumbJpegSize);
292 memcpy(mTempJpegBuffer + exif_header_len + sEb->size + mThumbJpegSize+ 2,
293 mJpegBuffer.img + image_data_offset, mMainJpegSize - image_data_offset);
294 memcpy(mJpegBuffer.img, mTempJpegBuffer, mMainJpegSize + sEb->size + mThumbJpegSize);
295 if (mTempJpegBuffer != NULL) {
296 free(mTempJpegBuffer);
297 mTempJpegBuffer = NULL;
298 }
299 for (uint32_t size = (mMainJpegSize + sEb->size + mThumbJpegSize); size > 0; size--) {
300 if (checkJpegEnd(mJpegBuffer.img + size)) {
301 realjpegsize = (size + MARKER_LENGTH);
302 break;
303 }
304 }
305 offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
306 blob.jpeg_blob_id = 0x00FF;
307 blob.jpeg_size = realjpegsize;
308 memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
309 if (sEb != NULL) {
310 if (sEb->data) {
311 free(sEb->data);
312 sEb->data = NULL;
313 }
314 free(sEb);
315 sEb = NULL;
316 CAMHAL_LOGDA("free malloc sEb buffer");
317 }
318 } else {
319 uint8_t * mTempJpegBuffer = (uint8_t *)malloc(mMainJpegSize + sEb->size);
320 memset(mTempJpegBuffer, 0, sizeof(char) * (mMainJpegSize + sEb->size));
321 memcpy(mTempJpegBuffer, exif_header, exif_header_len);
322 mTempJpegBuffer[exif_header_len] = (sEb->size+2) >> 8;
323 mTempJpegBuffer[exif_header_len + 1] = ((sEb->size+2) & 0xff);
324 memcpy(mTempJpegBuffer + exif_header_len + 2, sEb->data, sEb->size);
325 memcpy(mTempJpegBuffer + exif_header_len + sEb->size + 2, mJpegBuffer.img + image_data_offset,
326 mMainJpegSize - image_data_offset);
327 memcpy(mJpegBuffer.img, mTempJpegBuffer, mMainJpegSize + sEb->size);
328 if (mTempJpegBuffer != NULL) {
329 free(mTempJpegBuffer);
330 mTempJpegBuffer = NULL;
331 }
332 for (uint32_t size = (mMainJpegSize + sEb->size); size > 0; size--) {
333 if (checkJpegEnd(mJpegBuffer.img + size)) {
334 realjpegsize = (size + MARKER_LENGTH);
335 break;
336 }
337 }
338 offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
339 blob.jpeg_blob_id = 0x00FF;
340 blob.jpeg_size = realjpegsize;
341 memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
342 if (sEb != NULL) {
343 if (sEb->data) {
344 free(sEb->data);
345 sEb->data = NULL;
346 }
347 free(sEb);
348 sEb = NULL;
349 CAMHAL_LOGDA("free malloc sEb buffer");
350 }
351 }
352 } else {
353 DBG_LOGA("get exif buffer failed, so only callback Main JPEG data");
354 for (uint32_t size = (mMainJpegSize + sEb->size); size > 0; size--) {
355 if (checkJpegEnd(mJpegBuffer.img + size)) {
356 realjpegsize = (size + MARKER_LENGTH);
357 break;
358 }
359 }
360 offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
361 blob.jpeg_blob_id = 0x00FF;
362 blob.jpeg_size = realjpegsize;
363 memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
364 }
365 } else {
366 uint32_t realjpegsize = 0;
367 for (uint32_t size = (mMainJpegSize); size > 0; size--) {
368 if (checkJpegEnd(mJpegBuffer.img + size)) {
369 realjpegsize = (size + MARKER_LENGTH);
370 break;
371 }
372 }
373 int offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
374 blob.jpeg_blob_id = 0x00FF;
375 blob.jpeg_size = realjpegsize;
376 memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
377 }
378 return res;
379}
380
381bool JpegCompressor::threadLoop() {
382 status_t res;
383 CaptureRequest* ri = NULL;
384 {
385 mMutex.lock();
386 if (mExitJpegThread) {
387 mMutex.unlock();
388 ALOGE("JpegCompressor Thread : exiting on request0");
389 return false;
390 }
391
392 while (mPendingrequest == 0) {
393 res = mInJpegRequestSignal.wait(mMutex);
394 }
395 mPendingrequest--;
396 if (mInJpegRequestQueue.size() > 0) {
397 List<CaptureRequest*>::iterator i = mInJpegRequestQueue.begin();
398 mJpegRequest.frameNumber = (*i)->frameNumber;
399 mJpegRequest.buf = (*i)->buf;
400 mJpegRequest.sensorBuffers = (*i)->sensorBuffers;
401 mJpegRequest.mNeedThumbnail = (*i)->mNeedThumbnail;
402 ri = *mInJpegRequestQueue.begin();
403 mInJpegRequestQueue.erase(mInJpegRequestQueue.begin());
404 mBuffers = mJpegRequest.sensorBuffers;
405 } else {
406 mMutex.unlock();
407 return true;
408 }
409 if (mExitJpegThread) {
410 mMutex.unlock();
411 ALOGE("JpegCompressor Thread : exiting on request1");
412 if (mBuffers != NULL) {
413 delete mBuffers;
414 mBuffers = NULL;
415 }
416 if (ri != NULL) {
417 if (ri->buf != NULL) {
418 delete ri->buf;
419 }
420 delete ri;
421 }
422 return false;
423 }
424 mMutex.unlock();
425 }
426 mFoundJpeg = false;
427 mFoundAux = false;
428 for (size_t i = 0; i < mBuffers->size(); i++) {
429 const StreamBuffer &b = (*mBuffers)[i];
430 if (b.format == HAL_PIXEL_FORMAT_BLOB) {
431 mJpegBuffer = b;
432 mFoundJpeg = true;
433 } else if (b.streamId <= 0) {
434 mAuxBuffer = b;
435 mFoundAux = true;
436 }
437 if (mFoundJpeg && mFoundAux) break;
438 }
439 if (!mFoundJpeg || !mFoundAux) {
440 ALOGE("%s: Unable to find buffers for JPEG source/destination",
441 __FUNCTION__);
442 return BAD_VALUE;
443 }
444
445 struct timeval mTimeStart,mTimeend;
446 int intreval;
447 ALOGV("%s: Starting compression thread", __FUNCTION__);
448 gettimeofday(&mTimeStart, NULL);
449
450 res = compress();
451
452#if PLATFORM_SDK_VERSION <= 22
453 Create_Exif_Use_Libjpeg();
454#else
455 Create_Exif_Use_Libexif();
456#endif
457
458 mListener->onJpegDone(mJpegBuffer, res == OK, mJpegRequest);
459
460 if (ri != NULL) {
461 if (ri->buf != NULL) {
462 delete ri->buf;
463 }
464 delete ri;
465 }
466 gettimeofday(&mTimeend, NULL);
467 intreval = (mTimeend.tv_sec - mTimeStart.tv_sec) * 1000 + ((mTimeend.tv_usec - mTimeStart.tv_usec))/1000;
468 ALOGD("jpeg compress cost time =%d ms",intreval);
469 cleanUp();
470
471 return true;
472}
473
474struct libjpeg_destination_mgr : jpeg_destination_mgr {
475 libjpeg_destination_mgr(uint8_t* input, int size);
476 uint8_t* buf;
477 int bufsize;
478 size_t jpegsize;
479};
480
481static void libjpeg_init_destination (j_compress_ptr cinfo) {
482 libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest;
483
484 dest->next_output_byte = dest->buf;
485 dest->free_in_buffer = dest->bufsize;
486 dest->jpegsize = 0;
487}
488
489static boolean libjpeg_empty_output_buffer(j_compress_ptr cinfo) {
490 libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest;
491
492 dest->next_output_byte = dest->buf;
493 dest->free_in_buffer = dest->bufsize;
494 return TRUE; // ?
495}
496
497static void libjpeg_term_destination (j_compress_ptr cinfo) {
498 libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest;
499 dest->jpegsize = dest->bufsize - dest->free_in_buffer;
500}
501
502libjpeg_destination_mgr::libjpeg_destination_mgr(uint8_t* input, int size) {
503 this->init_destination = libjpeg_init_destination;
504 this->empty_output_buffer = libjpeg_empty_output_buffer;
505 this->term_destination = libjpeg_term_destination;
506 this->buf = input;
507 this->bufsize = size;
508 jpegsize = 0;
509}
510
511static void resize_nv12(params* params, uint8_t* dst_buffer) {
512 structConvImage o_img_ptr, i_img_ptr;
513
514 if (!params || !dst_buffer) {
515 return;
516 }
517
518 //input
519 i_img_ptr.uWidth = (mmInt32)params->in_width;
520 i_img_ptr.uStride = (mmInt32)i_img_ptr.uWidth;
521 i_img_ptr.uHeight = (mmInt32)params->in_height;
522 i_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp;
523 i_img_ptr.imgPtr = (mmByte *) params->src;
524 i_img_ptr.clrPtr = (mmByte *)i_img_ptr.imgPtr + (i_img_ptr.uWidth * i_img_ptr.uHeight);
525 i_img_ptr.uOffset = 0;
526
527 //ouput
528 o_img_ptr.uWidth = (mmInt32)params->out_width;
529 o_img_ptr.uStride = (mmInt32)o_img_ptr.uWidth;
530 o_img_ptr.uHeight = (mmInt32)params->out_height;
531 o_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp;
532 o_img_ptr.imgPtr = (mmByte *)dst_buffer;
533 o_img_ptr.clrPtr = (mmByte *)o_img_ptr.imgPtr + (o_img_ptr.uWidth * o_img_ptr.uHeight);
534 o_img_ptr.uOffset = 0;
535
536 VT_resizeFrame_Video_opt2_lp(&i_img_ptr, &o_img_ptr, NULL, 0);
537}
538
539static void resize_yuyv(params* params, uint8_t* dst_buffer) {
540 int step_x, step_y;
541 int dst_pos, src_pos;
542 int src_y_start_pos;
543 step_x = params->in_width / params->out_width;
544 step_y = params->in_height / params->out_height;
545 dst_pos = 0;
546 for (int y = 0; y < params->out_height; y++) {
547 src_y_start_pos = (y * step_y * (params->in_width * 2));
548 for (int x = 0; x < params->out_width; x += 2) {
549 src_pos = src_y_start_pos + (x * (step_x * 2));
550 dst_buffer[dst_pos++] = params->src[src_pos];
551 dst_buffer[dst_pos++] = params->src[src_pos + 1];
552 dst_buffer[dst_pos++] = params->src[src_pos + 2];
553 dst_buffer[dst_pos++] = params->src[src_pos + 3];
554 }
555 }
556}
557
558/* private static functions */
559static void nv21_to_yuv(uint8_t* dst, uint8_t* y, uint8_t* uv, int width) {
560 if (!dst || !y || !uv) {
561 return;
562 }
563
564 while ((width--) > 0) {
565 uint8_t y0 = y[0];
566 uint8_t v0 = uv[0];
567 uint8_t u0 = *(uv+1);
568 dst[0] = y0;
569 dst[1] = u0;
570 dst[2] = v0;
571 dst += 3;
572 y++;
573 if (!(width % 2)) uv+=2;
574 }
575}
576
577static void yuyv_to_yuv(uint8_t* dst, uint32_t* src, int width) {
578 if (!dst || !src) {
579 return;
580 }
581
582 if (width % 2) {
583 return; // not supporting odd widths
584 }
585
586 // currently, neon routine only supports multiple of 16 width
587 if (width % 16) {
588 while ((width-=2) >= 0) {
589 uint8_t y0 = (src[0] >> 0) & 0xFF;
590 uint8_t u0 = (src[0] >> 8) & 0xFF;
591 uint8_t y1 = (src[0] >> 16) & 0xFF;
592 uint8_t v0 = (src[0] >> 24) & 0xFF;
593 dst[0] = y0;
594 dst[1] = u0;
595 dst[2] = v0;
596 dst[3] = y1;
597 dst[4] = u0;
598 dst[5] = v0;
599 dst += 6;
600 src++;
601 }
602 } else {
603 int n = width;
604#if defined(__arm__)
605 asm volatile (
606 " pld [%[src], %[src_stride], lsl #2] \n\t"
607 " cmp %[n], #16 \n\t"
608 " blt 5f \n\t"
609 "0: @ 16 pixel swap \n\t"
610 " vld2.8 {q0, q1} , [%[src]]! @ q0 = y q1 = uv \n\t"
611 " vuzp.8 q1, q2 @ d2 = u d4 = v \n\t"
612 " vmov d3, d2 @ q1 = u0u1u2..u0u1u2... \n\t"
613 " vmov d5, d4 @ q2 = v0v1v2..v0v1v2... \n\t"
614 " vzip.8 d2, d3 @ q1 = u0u0u1u1u2u2... \n\t"
615 " vzip.8 d4, d5 @ q2 = v0v0v1v1v2v2... \n\t"
616 " vst3.8 {d0,d2,d4},[%[dst]]! \n\t"
617 " vst3.8 {d1,d3,d5},[%[dst]]! \n\t"
618 " sub %[n], %[n], #16 \n\t"
619 " cmp %[n], #16 \n\t"
620 " bge 0b \n\t"
621 "5: @ end \n\t"
622#ifdef NEEDS_ARM_ERRATA_754319_754320
623 " vmov s0,s0 @ add noop for errata item \n\t"
624#endif
625 : [dst] "+r" (dst), [src] "+r" (src), [n] "+r" (n)
626 : [src_stride] "r" (width)
627 : "cc", "memory", "q0", "q1", "q2"
628 );
629#elif defined(__aarch64__)
630#endif
631 }
632}
633
634static uint32_t calc_frame_length(int format, uint32_t width, uint32_t height)
635{
636 uint32_t length;
637 switch (format) {
638 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
639 length = width * height * 3/2;
640 break;
641 case HAL_PIXEL_FORMAT_RGB_888:
642 length = width * height * 3;
643 break;
644 case HAL_PIXEL_FORMAT_YCbCr_422_I:
645 length = width * height * 2;
646 break;
647 default:
648 length = width * height * 3/2;
649 break;
650 }
651 return length;
652}
653
654size_t encode(params* input) {
655 jpeg_compress_struct cinfo;
656 jpeg_error_mgr jerr;
657 jpeg_destination_mgr jdest;
658 uint8_t* src = NULL;
659 uint8_t* resize_src = NULL;
660 uint8_t* row_tmp = NULL;
661 uint8_t* row_src = NULL;
662 uint8_t* row_uv = NULL; // used only for NV12
663 int row_stride;
664 int out_width = 0, in_width = 0;
665 int out_height = 0, in_height = 0;
666 int bpp = 2; // for uyvy
667
668 format informat = YUV422I;
669
670 if (!input) {
671 return 0;
672 }
673
674 out_width = input->out_width;
675 in_width = input->in_width;
676 out_height = input->out_height;
677 in_height = input->in_height;
678 src = input->src;
679 input->jpeg_size = 0;
680 libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size);
681
682 // param check...
683 if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) ||
684 (src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) ||
685 (input->dst_size < 1) ) {
686 goto exit;
687 }
688
689 if (input->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
690 informat = YUV420SP;
691 bpp = 1;
692 if ((in_width != out_width) || (in_height != out_height)) {
693 resize_src = (uint8_t*) malloc(out_width * out_height *3);
694 if (NULL != resize_src) {
695 resize_nv12(input, resize_src);
696 if (resize_src) src = resize_src;
697 } else {
698 CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
699 goto exit;
700 }
701 }
702 } else if ((input->format == HAL_PIXEL_FORMAT_RGB_888)) {
703 informat = RGB24;
704 bpp = 1;
705 if ((in_width != out_width) || (in_height != out_height)) {
706 resize_src = (uint8_t*) malloc(out_width * out_height *3);
707 if (NULL != resize_src) {
708 extraSmallImg(input->src, in_width, in_height,
709 resize_src, out_width, out_height);
710 src = resize_src;
711 } else {
712 CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
713 goto exit;
714 }
715 }
716 } else if (input->format == HAL_PIXEL_FORMAT_YCbCr_422_I) {
717 informat = YUV422I;
718 bpp = 2;
719 if ((in_width != out_width) || (in_height != out_height)) {
720 resize_src = (uint8_t*) malloc(out_width * out_height *3);
721 if (NULL != resize_src) {
722 resize_yuyv(input,resize_src);
723 if (resize_src) src = resize_src;
724 } else {
725 CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
726 goto exit;
727 }
728 }
729 } else if ((in_width != out_width) || (in_height != out_height)) {
730 CAMHAL_LOGEB("Encoder: resizing is not supported for this format: %d", input->format);
731 goto exit;
732 } else if ((input->format != HAL_PIXEL_FORMAT_YCbCr_422_I)) {
733 // we currently only support yuv422i and yuv420sp
734 CAMHAL_LOGEB("Encoder: format not supported: %d", input->format);
735 goto exit;
736 }
737
738 cinfo.err = jpeg_std_error(&jerr);
739
740 jpeg_create_compress(&cinfo);
741
742 CAMHAL_LOGDB("software encoding... \n\t"
743 "width: %d \n\t"
744 "height:%d \n\t"
745 "dest %p \n\t"
746 "dest size:%d \n\t"
747 "mSrc %p",
748 out_width, out_height, input->dst,
749 input->dst_size, src);
750
751 cinfo.dest = &dest_mgr;
752 cinfo.image_width = out_width;
753 cinfo.image_height = out_height;
754 cinfo.input_components = 3;
755 if (informat == RGB24)
756 cinfo.in_color_space = JCS_RGB;
757 else
758 cinfo.in_color_space = JCS_YCbCr;
759 cinfo.input_gamma = 1;
760
761 jpeg_set_defaults(&cinfo);
762 jpeg_set_quality(&cinfo, input->quality, TRUE);
763 cinfo.dct_method = JDCT_IFAST;
764
765 jpeg_start_compress(&cinfo, TRUE);
766
767 row_tmp = (uint8_t*)malloc(out_width * 3);
768 row_src = src;
769 row_uv = src + out_width * out_height * bpp;
770 row_stride = out_width * 3;
771
772 while ((cinfo.next_scanline < cinfo.image_height)) {
773 JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */
774
775 if (informat == RGB24) {
776 row[0] = &src[cinfo.next_scanline * row_stride];
777 (void) jpeg_write_scanlines(&cinfo, row, 1);
778 } else {
779 // convert input yuv format to yuv444
780 if (informat == YUV420SP) {
781 nv21_to_yuv(row_tmp, row_src, row_uv, out_width);
782 } else if (informat == YUV422I) {
783 //uyvy_to_yuv(row_tmp, (uint32_t*)row_src, out_width);
784 yuyv_to_yuv(row_tmp, (uint32_t*)row_src, out_width);
785 }
786
787 row[0] = row_tmp;
788 jpeg_write_scanlines(&cinfo, row, 1);
789 row_src = row_src + out_width*bpp;
790
791 // move uv row if input format needs it
792 if (informat == YUV420SP) {
793 if (!(cinfo.next_scanline % 2))
794 row_uv = row_uv + out_width * bpp;
795 }
796 }
797 }
798
799 jpeg_finish_compress(&cinfo);
800 jpeg_destroy_compress(&cinfo);
801
802 if (resize_src) free(resize_src);
803 if (row_tmp) free(row_tmp);
804
805 exit:
806 input->jpeg_size = dest_mgr.jpegsize;
807 return dest_mgr.jpegsize;
808}
809
810status_t JpegCompressor::compress() {
811 // Find source and target buffers. Assumes only one buffer matches
812 // each condition!
813 if (mJpegRequest.mNeedThumbnail == true) {
814 mSrcThumbBuffer = mAuxBuffer.img;
815 if (mDstThumbBuffer == NULL) {
816 mDstThumbBuffer = (uint8_t*)malloc(mInfo.thumbwidth * mInfo.thumbheight * 3);
817 }
818 }
819
820 params enc_params;
821 enc_params.src = mAuxBuffer.img;
822 enc_params.src_size = calc_frame_length(mAuxBuffer.format, mAuxBuffer.width, mAuxBuffer.height);
823 enc_params.dst = mJpegBuffer.img;
824 enc_params.dst_size = mMaxbufsize;
825 enc_params.quality = 80;
826 enc_params.in_width = mAuxBuffer.width;
827 enc_params.in_height = mAuxBuffer.height;
828 enc_params.out_width= mAuxBuffer.width;
829 enc_params.out_height = mAuxBuffer.height;
830 enc_params.format = mAuxBuffer.format;
831 enc_params.jpeg_size = 0;
832
833 mMainJpegSize = encode(&enc_params);
834 ALOGD("mMainJpegSize = %d",mMainJpegSize);
835
836 return OK;
837}
838
839status_t JpegCompressor::thumbcompress() {
840 if ((mSrcThumbBuffer == NULL) || (mDstThumbBuffer == NULL))
841 return 0;
842
843 params enc_params;
844 enc_params.src = mSrcThumbBuffer;
845 enc_params.dst = mDstThumbBuffer;
846 enc_params.dst_size = mInfo.thumbwidth * mInfo.thumbheight * 3;
847 enc_params.quality = 70;
848 enc_params.src_size = calc_frame_length(mAuxBuffer.format, mAuxBuffer.width, mAuxBuffer.height);
849 enc_params.in_width = mAuxBuffer.width;
850 enc_params.in_height = mAuxBuffer.height;
851 enc_params.out_width= mInfo.thumbwidth;
852 enc_params.out_height = mInfo.thumbheight;
853 enc_params.format = mAuxBuffer.format;
854 enc_params.jpeg_size = 0;
855
856 mThumbJpegSize = encode(&enc_params);
857 ALOGD("mThumbJpegSize = %d",mThumbJpegSize);
858
859 return OK;
860}
861bool JpegCompressor::isBusy() {
862 Mutex::Autolock busyLock(mBusyMutex);
863 return mIsBusy;
864}
865
866bool JpegCompressor::isStreamInUse(uint32_t id) {
867 Mutex::Autolock lock(mBusyMutex);
868
869 if (mBuffers && mIsBusy) {
870 for (size_t i = 0; i < mBuffers->size(); i++) {
871 if ( (*mBuffers)[i].streamId == (int)id ) return true;
872 }
873 }
874 return false;
875}
876
877bool JpegCompressor::waitForDone(nsecs_t timeout) {
878 Mutex::Autolock lock(mBusyMutex);
879 status_t res = OK;
880 if (mIsBusy) {
881 res = mDone.waitRelative(mBusyMutex, timeout);
882 }
883 return (res == OK);
884}
885
886bool JpegCompressor::checkError(const char *msg) {
887 if (mJpegErrorInfo) {
888 char errBuffer[JMSG_LENGTH_MAX];
889 mJpegErrorInfo->err->format_message(mJpegErrorInfo, errBuffer);
890 ALOGE("%s: %s: %s",
891 __FUNCTION__, msg, errBuffer);
892 mJpegErrorInfo = NULL;
893 return true;
894 }
895 return false;
896}
897
898void JpegCompressor::cleanUp() {
899 status_t res;
900 Mutex::Autolock lock(mBusyMutex);
901 if (mJpegRequest.mNeedThumbnail == true) {
902 if (mSrcThumbBuffer != NULL) {
903 mSrcThumbBuffer = NULL;
904 }
905 if (mDstThumbBuffer != NULL) {
906 free(mDstThumbBuffer);
907 mDstThumbBuffer = NULL;
908 }
909 }
910 if (mFoundAux) {
911 if (mAuxBuffer.streamId == 0) {
912 delete[] mAuxBuffer.img;
913 } else if (!mSynchronous) {
914 mListener->onJpegInputDone(mAuxBuffer);
915 }
916 }
917 if (!mSynchronous) {
918 delete mBuffers;
919 }
920
921 mBuffers = NULL;
922
923 mIsBusy = false;
924 mDone.signal();
925}
926
927JpegCompressor::JpegListener::~JpegListener() {
928}
929
930void JpegCompressor::SetMaxJpegBufferSize(ssize_t size)
931{
932 mMaxbufsize = size;
933}
934ssize_t JpegCompressor::GetMaxJpegBufferSize()
935{
936 return mMaxbufsize;
937}
938void JpegCompressor::SetExifInfo(struct ExifInfo info)
939{
940 memcpy(&mInfo, &info, sizeof(struct ExifInfo));
941}
942int JpegCompressor::GenExif(ExifElementsTable* exiftable)
943{
944 char exifcontent[256];
945 int width,height;
946 bool newexif = true; //add new exif tag for cts
947 float exposuretime = 1.0;
948 float ApertureValue = 1.0;
949 int flash = 0;
950 int whitebalance = 1;
951 int iso = 100;
952 char SubSecTime[10] = "63";
953 char SubSecTimeOrig[10]= "63";
954 char SubSecTimeDig[10]= "63";
955 char property[PROPERTY_VALUE_MAX];
956
957 property_get("ro.product.manufacturer", property, EXIF_MAKE_DEFAULT);
958 exiftable->insertElement("Make",property);
959 property_get("ro.product.model", property, EXIF_MODEL_DEFAULT);
960 exiftable->insertElement("Model",property);
961// int orientation = mInfo.orientation;
962 width = mInfo.mainwidth;
963 height = mInfo.mainheight;
964#if 0
965 if (orientation == 0)
966 orientation = 1;
967 else if (orientation == 90)
968 orientation = 6;
969 else if (orientation == 180)
970 orientation = 3;
971 else if (orientation == 270)
972 orientation = 8;
973 sprintf(exifcontent,"%d",orientation);
974 exiftable->insertElement("Orientation",(const char*)exifcontent);
975#endif
976 sprintf(exifcontent,"%d",width);
977 exiftable->insertElement("ImageWidth",(const char*)exifcontent);
978 sprintf(exifcontent,"%d",height);
979 exiftable->insertElement("ImageLength",(const char*)exifcontent);
980
981 sprintf(exifcontent,"%f",exposuretime);
982 exiftable->insertElement("ExposureTime",(const char*)exifcontent);
983 sprintf(exifcontent,"%f",ApertureValue);
984 exiftable->insertElement("ApertureValue",(const char*)exifcontent);
985 sprintf(exifcontent,"%d",flash);
986 exiftable->insertElement("Flash",(const char*)exifcontent);
987 sprintf(exifcontent,"%d",whitebalance);
988 exiftable->insertElement("WhiteBalance",(const char*)exifcontent);
989 sprintf(exifcontent,"%d",iso);
990 exiftable->insertElement("ISOSpeedRatings",(const char*)exifcontent);
991 if (newexif) {
992 time_t times;
993 {
994 time(&times);
995 struct tm tmstruct;
996 tmstruct = *(localtime(&times)); //convert to local time
997 strftime(exifcontent, 30, "%Y:%m:%d %H:%M:%S", &tmstruct);
998 exiftable->insertElement("DateTimeDigitized",(const char*)exifcontent);
999 }
1000 {
1001 sprintf(exifcontent, "%s", SubSecTime);
1002 exiftable->insertElement("SubSecTime",(const char*)exifcontent);
1003 }
1004 {
1005
1006 sprintf(exifcontent, "%s", SubSecTimeOrig);
1007 exiftable->insertElement("SubSecTimeOriginal",(const char*)exifcontent);
1008 }
1009 {
1010
1011 sprintf(exifcontent, "%s", SubSecTimeDig);
1012 exiftable->insertElement("SubSecTimeDigitized",(const char*)exifcontent);
1013 }
1014 }
1015
1016 if (mInfo.has_focallen) {
1017 float focallen = mInfo.focallen;
1018 if (focallen >= 0) {
1019 int focalNum = focallen*1000;
1020 int focalDen = 1000;
1021 sprintf(exifcontent,"%d/%d",focalNum,focalDen);
1022 exiftable->insertElement("FocalLength",(const char*)exifcontent);
1023 }
1024 }
1025 time_t times;
1026 {
1027 time(&times);
1028 struct tm tmstruct;
1029 tmstruct = *(localtime(&times)); //convert to local time
1030 strftime(exifcontent, 30, "%Y:%m:%d %H:%M:%S", &tmstruct);
1031 exiftable->insertElement("DateTime",(const char*)exifcontent);
1032 }
1033 if (mInfo.has_gpsTimestamp) {
1034 times = mInfo.gpsTimestamp;
1035 if (times != -1) {
1036 struct tm tmstruct;
1037 tmstruct = *(gmtime(&times));//convert to standard time
1038 strftime(exifcontent, 20, "%Y:%m:%d", &tmstruct);
1039 exiftable->insertElement("GPSDateStamp",(const char*)exifcontent);
1040 sprintf(exifcontent,"%d/%d,%d/%d,%d/%d",tmstruct.tm_hour,1,tmstruct.tm_min,1,tmstruct.tm_sec,1);
1041 exiftable->insertElement("GPSTimeStamp",(const char*)exifcontent);
1042 }
1043 }
1044 if (mInfo.has_latitude) {
1045 int offset = 0;
1046 float latitude = mInfo.latitude;
1047 if (latitude < 0.0) {
1048 offset = 1;
1049 latitude*= (float)(-1);
1050 }
1051 int latitudedegree = latitude;
1052 float latitudeminuts = (latitude-(float)latitudedegree)*60;
1053 int latitudeminuts_int = latitudeminuts;
1054 float latituseconds = (latitudeminuts-(float)latitudeminuts_int)*60+0.5;
1055 int latituseconds_int = latituseconds;
1056 sprintf(exifcontent,"%d/%d,%d/%d,%d/%d",latitudedegree,1,latitudeminuts_int,1,latituseconds_int,1);
1057 exiftable->insertElement("GPSLatitude",(const char*)exifcontent);
1058 exiftable->insertElement("GPSLatitudeRef",(offset==1)?"S":"N");
1059 }
1060 if (mInfo.has_longitude) {
1061 int offset = 0;
1062 float longitude = mInfo.longitude;
1063 if (longitude < 0.0) {
1064 offset = 1;
1065 longitude*= (float)(-1);
1066 }
1067 int longitudedegree = longitude;
1068 float longitudeminuts = (longitude-(float)longitudedegree)*60;
1069 int longitudeminuts_int = longitudeminuts;
1070 float longitudeseconds = (longitudeminuts-(float)longitudeminuts_int)*60+0.5;
1071 int longitudeseconds_int = longitudeseconds;
1072 sprintf(exifcontent,"%d/%d,%d/%d,%d/%d",longitudedegree,1,longitudeminuts_int,1,longitudeseconds_int,1);
1073 exiftable->insertElement("GPSLongitude",(const char*)exifcontent);
1074 exiftable->insertElement("GPSLongitudeRef",(offset==1)?"S":"N");
1075 }
1076 if (mInfo.has_altitude) {
1077 int offset = 0;
1078 float altitude = mInfo.altitude;
1079 if (altitude < 0.0) {
1080 offset = 1;
1081 altitude*= (float)(-1);
1082 }
1083 int altitudenum = altitude*1000;
1084 int altitudedec= 1000;
1085 sprintf(exifcontent,"%d/%d",altitudenum,altitudedec);
1086 exiftable->insertElement("GPSAltitude",(const char*)exifcontent);
1087 sprintf(exifcontent,"%d",offset);
1088 exiftable->insertElement("GPSAltitudeRef",(const char*)exifcontent);
1089 }
1090 if (mInfo.has_gpsProcessingMethod) {
1091 char* processmethod = (char*)mInfo.gpsProcessingMethod;
1092 if (processmethod != NULL) {
1093 memset(exifcontent,0,sizeof(exifcontent));
1094 char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };//asicii
1095 memcpy(exifcontent,ExifAsciiPrefix,8);
1096 memcpy(exifcontent+8,processmethod,strlen(processmethod));
1097 exiftable->insertElement("GPSProcessingMethod",(const char*)exifcontent);
1098 }
1099 }
1100 return 1;
1101}
1102
1103void JpegCompressor::exif_entry_set_string (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, const char *s)
1104{
1105 ExifEntry *pE;
1106
1107 pE = exif_entry_new ();
1108 exif_content_add_entry (pEdata->ifd[eEifd], pE);
1109 exif_entry_initialize (pE, eEtag);
1110 if (pE->data)
1111 free (pE->data);
1112 pE->components = strlen (s) + 1;
1113 pE->size = sizeof (char) * pE->components;
1114 pE->data = (unsigned char *) malloc (pE->size);
1115 if (!pE->data) {
1116 DBG_LOGB("Cannot allocate %d bytes.\nTerminating.\n", (int) pE->size);
1117 exit (1);
1118 }
1119 strcpy ((char *) pE->data, (char *) s);
1120 exif_entry_fix (pE);
1121 exif_entry_unref (pE);
1122}
1123
1124void JpegCompressor::exif_entry_set_short (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifShort n)
1125{
1126 ExifEntry *pE;
1127 ExifByteOrder eO;
1128
1129 pE = exif_entry_new ();
1130 exif_content_add_entry (pEdata->ifd[eEifd], pE);
1131 exif_entry_initialize (pE, eEtag);
1132 eO = exif_data_get_byte_order (pE->parent->parent);
1133 if (pE->data) {
1134 exif_set_short (pE->data, eO, n);
1135 } else {
1136 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1137 }
1138 exif_entry_fix (pE);
1139 exif_entry_unref (pE);
1140}
1141
1142void JpegCompressor::exif_entry_set_long (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifLong n)
1143{
1144 ExifEntry *pE;
1145 ExifByteOrder eO;
1146
1147 pE = exif_entry_new ();
1148 exif_content_add_entry (pEdata->ifd[eEifd], pE);
1149 exif_entry_initialize (pE, eEtag);
1150 eO = exif_data_get_byte_order (pE->parent->parent);
1151 if (pE->data) {
1152 exif_set_long (pE->data, eO, n);
1153 } else {
1154 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1155 }
1156 exif_entry_fix (pE);
1157 exif_entry_unref (pE);
1158}
1159
1160void JpegCompressor::exif_entry_set_rational (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifRational r)
1161{
1162 ExifEntry *pE;
1163 ExifByteOrder eO;
1164
1165 pE = exif_entry_new ();
1166 exif_content_add_entry (pEdata->ifd[eEifd], pE);
1167 exif_entry_initialize (pE, eEtag);
1168 eO = exif_data_get_byte_order (pE->parent->parent);
1169 if (pE->data) {
1170 exif_set_rational (pE->data, eO, r);
1171 } else {
1172 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1173 }
1174 exif_entry_fix (pE);
1175 exif_entry_unref (pE);
1176}
1177
1178void JpegCompressor::exif_entry_set_undefined (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, exif_buffer * buf)
1179{
1180 ExifEntry *pE;
1181 pE = exif_entry_new ();
1182 exif_content_add_entry (pEdata->ifd[eEifd], pE);
1183 exif_entry_initialize (pE, eEtag);
1184 if (buf != NULL) {
1185 if (pE->data)
1186 free (pE->data);
1187 pE->components = buf->size;
1188 pE->size = buf->size;
1189 pE->data = (unsigned char *) malloc (pE->size);
1190 if (!pE->data) {
1191 DBG_LOGB("Cannot allocate %d bytes.\nTerminating.\n", (int) pE->size);
1192 exit (1);
1193 }
1194 memcpy ((void *) pE->data, (void *) buf->data, buf->size);
1195 }
1196 exif_entry_fix (pE);
1197 exif_entry_unref (pE);
1198}
1199
1200/****************************************************************************
1201 * Public API
1202 ***************************************************************************/
1203
1204/* Get an existing tag, or create one if it doesn't exist */
1205ExifEntry* JpegCompressor::init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag)
1206{
1207 ExifEntry *entry;
1208 /* Return an existing tag if one exists */
1209 if (!((entry = exif_content_get_entry (exif->ifd[ifd], tag)))) {
1210 /* Allocate a new entry */
1211 entry = exif_entry_new ();
1212 assert(entry != NULL); /* catch an out of memory condition */
1213 entry->tag = tag; /* tag must be set before calling
1214 exif_content_add_entry */
1215
1216 /* Attach the ExifEntry to an IFD */
1217 exif_content_add_entry (exif->ifd[ifd], entry);
1218
1219 /* Allocate memory for the entry and fill with default data */
1220 exif_entry_initialize (entry, tag);
1221
1222 /* Ownership of the ExifEntry has now been passed to the IFD.
1223 * One must be very careful in accessing a structure after
1224 * unref'ing it; in this case, we know "entry" won't be freed
1225 * because the reference count was bumped when it was added to
1226 * the IFD.
1227 */
1228 exif_entry_unref(entry);
1229 }
1230 return entry;
1231}
1232
1233/* Create a brand-new tag with a data field of the given length, in the
1234 * given IFD. This is needed when exif_entry_initialize() isn't able to create
1235 * this type of tag itself, or the default data length it creates isn't the
1236 * correct length.
1237 */
1238ExifEntry *JpegCompressor::create_tag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len)
1239{
1240 void *buf;
1241 ExifEntry *entry;
1242
1243 /* Create a memory allocator to manage this ExifEntry */
1244 ExifMem *mem = exif_mem_new_default();
1245 assert(mem != NULL); /* catch an out of memory condition */
1246
1247 /* Create a new ExifEntry using our allocator */
1248 entry = exif_entry_new_mem (mem);
1249 assert(entry != NULL);
1250
1251 /* Allocate memory to use for holding the tag data */
1252 buf = exif_mem_alloc(mem, len);
1253 assert(buf != NULL);
1254
1255 /* Fill in the entry */
1256 entry->data = (unsigned char*)buf;
1257 entry->size = len;
1258 entry->tag = tag;
1259 entry->components = len;
1260 entry->format = EXIF_FORMAT_UNDEFINED;
1261
1262 /* Attach the ExifEntry to an IFD */
1263 exif_content_add_entry (exif->ifd[ifd], entry);
1264
1265 /* The ExifMem and ExifEntry are now owned elsewhere */
1266 exif_mem_unref(mem);
1267 exif_entry_unref(entry);
1268
1269 return entry;
1270}
1271
1272void JpegCompressor::exif_entry_set_gps_coord(ExifData * pEdata, ExifTag eEtag,
1273 ExifRational r1, ExifRational r2, ExifRational r3)
1274{
1275 ExifEntry *pE;
1276 ExifByteOrder eO;
1277
1278 pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
1279 3 * exif_format_get_size(EXIF_FORMAT_RATIONAL));
1280
1281 pE->components = 3;
1282 pE->format = EXIF_FORMAT_RATIONAL;
1283
1284 eO = exif_data_get_byte_order (pE->parent->parent);
1285
1286 if (pE->data) {
1287 exif_set_rational (pE->data, eO, r1);
1288 exif_set_rational (pE->data + exif_format_get_size (pE->format), eO, r2);
1289 exif_set_rational (pE->data + 2 * exif_format_get_size (pE->format), eO, r3);
1290 } else {
1291 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1292 }
1293}
1294
1295void JpegCompressor::exif_entry_set_gps_altitude(ExifData * pEdata, ExifTag eEtag, ExifRational r1)
1296{
1297 ExifEntry *pE;
1298 ExifByteOrder eO;
1299
1300 pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
1301 1 * exif_format_get_size(EXIF_FORMAT_RATIONAL));
1302
1303 pE->components = 1;
1304 pE->format = EXIF_FORMAT_RATIONAL;
1305
1306 eO = exif_data_get_byte_order (pE->parent->parent);
1307 if (pE->data) {
1308 exif_set_rational (pE->data, eO, r1);
1309 } else {
1310 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1311 }
1312}
1313
1314void JpegCompressor::exif_entry_set_gps_coord_ref(ExifData * pEdata, ExifTag eEtag, const char *s)
1315{
1316 ExifEntry *pE;
1317 ExifByteOrder eO;
1318
1319 pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
1320 (strlen (s) + 1) * exif_format_get_size(EXIF_FORMAT_ASCII));
1321
1322 pE->components = strlen (s) + 1;
1323 pE->format = EXIF_FORMAT_ASCII;
1324
1325 eO = exif_data_get_byte_order (pE->parent->parent);
1326 if (pE->data) {
1327 strcpy ((char *) pE->data, s);
1328 } else {
1329 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1330 }
1331}
1332
1333void JpegCompressor::exif_entry_set_gps_altitude_ref(ExifData * pEdata, ExifTag eEtag, ExifByte n)
1334{
1335 ExifEntry *pE;
1336 ExifByteOrder eO;
1337
1338 pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
1339 1 * exif_format_get_size(EXIF_FORMAT_BYTE));
1340
1341 pE->components = 1;
1342 pE->format = EXIF_FORMAT_BYTE;
1343
1344 eO = exif_data_get_byte_order (pE->parent->parent);
1345 if (pE->data) {
1346 *(pE->data) = n;
1347 } else {
1348 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1349 }
1350}
1351
1352exif_buffer * JpegCompressor::get_exif_buffer() {
1353
1354 char exifcontent[256];
1355 ExifData *pEd;
1356 ExifEntry *entry;
1357 exif_buffer *sEb;
1358 ExifRational sR;
1359 int res;
1360 int orientation;
1361 struct timeval sTv;
1362 time_t times;
1363 struct tm tmstruct;
1364 char property[PROPERTY_VALUE_MAX];
1365
1366 sEb = (exif_buffer *) malloc (sizeof (exif_buffer));
1367
1368 pEd = exif_data_new ();
1369
1370 if (pEd == NULL)
1371 goto EXIT;
1372
1373 /* Set the image options */
1374 exif_data_set_option(pEd, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
1375 exif_data_set_data_type(pEd, EXIF_DATA_TYPE_COMPRESSED);
1376 exif_data_set_byte_order(pEd, FILE_BYTE_ORDER);
1377
1378 property_get("ro.product.manufacturer", property, EXIF_MAKE_DEFAULT);
1379 exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_MAKE, property);
1380 property_get("ro.product.model", property, EXIF_MODEL_DEFAULT);
1381 exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_MODEL, property);
1382
1383 switch (mInfo.orientation) {
1384 case 180:
1385 orientation = 3;
1386 //orientation = 1;
1387 break;
1388 case 90:
1389 orientation = 6;
1390 //orientation = 8;
1391 break;
1392 case 270:
1393 orientation = 8;
1394 break;
1395 default:
1396 orientation = 1;
1397 break;
1398 }
1399
1400 exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_ORIENTATION, (ExifShort)orientation);
1401
1402 sR.numerator = 1;
1403 sR.denominator = 629;
1404 exif_entry_set_rational (pEd, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, sR);
1405
1406 /* time */
1407 /* this sould be last resort */
1408 time(&times);
1409 tmstruct = *(localtime(&times)); //convert to local time
1410 res = gettimeofday (&sTv, NULL);
1411 strftime(exifcontent, 20, "%Y:%m:%d %H:%M:%S", &tmstruct);
1412 exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_DATE_TIME, exifcontent);
1413 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, exifcontent);
1414 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, exifcontent);
1415
1416 sR.numerator = 28;
1417 sR.denominator = 10;
1418 exif_entry_set_rational (pEd, EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, sR);//android 6 is EXIF_TAG_APERTURE_VALUE
1419
1420 exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_FLASH, 0);
1421
1422 sR.numerator = 3299;
1423 sR.denominator = 1000;
1424 exif_entry_set_rational(pEd, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, sR);
1425
1426 memset(exifcontent, 0, sizeof(exifcontent));
1427 snprintf(exifcontent, 20, "%06d", (int) sTv.tv_usec);
1428 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, exifcontent);
1429 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, exifcontent);
1430 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, exifcontent);
1431
1432 exif_entry_set_short (pEd, EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, 0);
1433
1434 if (mInfo.has_latitude) {
1435 ExifRational r1, r2, r3;
1436 int offset = 0;
1437 /* gps data */
1438 r1.denominator = 1;
1439 r2.denominator = 1;
1440 r3.denominator = 1;
1441
1442 float latitude = mInfo.latitude;
1443 if (latitude < 0.0) {
1444 latitude*= (float)(-1);
1445 offset = 1;
1446 }
1447 r1.numerator = (uint32_t)latitude;
1448 float latitudeminuts = (latitude-(float)(r1.numerator))*60;
1449 r2.numerator = (uint32_t)latitudeminuts;
1450 float latituseconds = (latitudeminuts-(float)(r2.numerator))*60+0.5;
1451 r3.numerator = (uint32_t)latituseconds;
1452 exif_entry_set_gps_coord(pEd, (ExifTag) EXIF_TAG_GPS_LATITUDE, r1, r2, r3);
1453 exif_entry_set_gps_coord_ref(pEd, (ExifTag) EXIF_TAG_GPS_LATITUDE_REF, offset == 1 ? "S":"N");
1454 }
1455
1456 if (mInfo.has_longitude) {
1457 ExifRational r1, r2, r3;
1458 int offset = 0;
1459 /* gps data */
1460 r1.denominator = 1;
1461 r2.denominator = 1;
1462 r3.denominator = 1;
1463
1464 float longitude = mInfo.longitude;
1465 if (longitude < 0.0) {
1466 longitude*= (float)(-1);
1467 offset = 1;
1468 }
1469 r1.numerator = (uint32_t)longitude;
1470 float longitudeminuts = (longitude-(float)(r1.numerator))*60;
1471 r2.numerator = (uint32_t)longitudeminuts;
1472 float longitudeseconds = (longitudeminuts-(float)(r2.numerator))*60+0.5;
1473 r3.numerator = (uint32_t)longitudeseconds;
1474 exif_entry_set_gps_coord(pEd, (ExifTag) EXIF_TAG_GPS_LONGITUDE, r1, r2, r3);
1475 exif_entry_set_gps_coord_ref(pEd, (ExifTag) EXIF_TAG_GPS_LONGITUDE_REF, offset == 1 ? "W":"E");
1476 }
1477
1478 if (mInfo.has_altitude) {
1479 ExifRational r1;
1480 int offset = 0;
1481 float altitude = mInfo.altitude;
1482 if (altitude < 0.0) {
1483 altitude*= (float)(-1);
1484 offset = 1;
1485 }
1486 r1.denominator = 1;
1487 r1.numerator = (uint32_t)altitude;
1488 exif_entry_set_gps_altitude(pEd, (ExifTag) EXIF_TAG_GPS_ALTITUDE, r1);
1489 exif_entry_set_gps_altitude_ref(pEd, (ExifTag) EXIF_TAG_GPS_ALTITUDE_REF, (ExifByte)offset);
1490 }
1491
1492 if (mInfo.has_gpsTimestamp) {
1493 ExifRational r1, r2, r3;
1494 time_t times;
1495 struct tm tmstruct;
1496 times = mInfo.gpsTimestamp;
1497
1498 r1.denominator = 1;
1499 r2.denominator = 1;
1500 r3.denominator = 1;
1501 memset(exifcontent, 0, sizeof(exifcontent));
1502 if (times != -1) {
1503 tmstruct = *(gmtime(&times));//convert to standard time
1504 strftime(exifcontent, 20, "%Y:%m:%d", &tmstruct);
1505 exif_entry_set_gps_coord_ref(pEd, (ExifTag) EXIF_TAG_GPS_DATE_STAMP, exifcontent);
1506
1507 r1.numerator = tmstruct.tm_hour;
1508 r2.numerator = tmstruct.tm_min;
1509 r3.numerator = tmstruct.tm_sec;
1510 exif_entry_set_gps_coord(pEd, (ExifTag) EXIF_TAG_GPS_TIME_STAMP, r1, r2, r3);
1511 }
1512 }
1513
1514 if (mInfo.has_gpsProcessingMethod) {
1515 char* processmethod = (char*)mInfo.gpsProcessingMethod;
1516 if (processmethod != NULL) {
1517 const char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };//asicii
1518 unsigned char* data = (unsigned char*)malloc(strlen(processmethod) + sizeof(ExifAsciiPrefix));
1519 exif_buffer buffer;
1520 if (data != NULL)
1521 {
1522 memcpy(data, ExifAsciiPrefix, sizeof(ExifAsciiPrefix));
1523 memcpy(data+sizeof(ExifAsciiPrefix), processmethod, strlen(processmethod));
1524 buffer.data = data;
1525 buffer.size = strlen(processmethod)+sizeof(ExifAsciiPrefix);
1526 exif_entry_set_undefined (pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_PROCESSING_METHOD, &buffer);
1527 free(data);
1528 }
1529 }
1530 }
1531
1532 //write IDF1 for thumbnail
1533 if (mJpegRequest.mNeedThumbnail) {
1534 exif_entry_set_short(pEd, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH, mInfo.thumbwidth);
1535 exif_entry_set_short(pEd, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH, mInfo.thumbheight);
1536 exif_entry_set_short(pEd, EXIF_IFD_1, EXIF_TAG_ORIENTATION, (ExifShort)orientation);
1537 //fan say need check
1538 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_EXIF_IFD_POINTER);
1539 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
1540 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
1541 exif_set_long(entry->data, FILE_BYTE_ORDER, (long)mThumbJpegSize);
1542 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_COMPRESSION);
1543 exif_set_short (entry->data, FILE_BYTE_ORDER, 6);
1544 }
1545
1546 /* copy data to our buffer */
1547 exif_data_save_data (pEd, &sEb->data, &sEb->size);
1548 assert(sEb->data != NULL);
1549
1550 if (mJpegRequest.mNeedThumbnail) {
1551 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
1552 exif_set_long(entry->data, FILE_BYTE_ORDER, (long)(sEb->size + 6 - 0x0c));
1553
1554 exif_data_save_data(pEd, &sEb->data, &sEb->size);
1555 assert(sEb->data != NULL);
1556 }
1557 DBG_LOGB("total exif data length = %d\n", sEb->size);
1558 /* destroy exif structure */
1559 exif_data_unref(pEd);
1560
1561 return sEb;
1562
1563EXIT:
1564 if (sEb != NULL)
1565 free(sEb);
1566
1567 return NULL;
1568}
1569
1570const char* ExifElementsTable::degreesToExifOrientation(const char* degrees) {
1571 for (unsigned int i = 0; i < ARRAY_SIZE(degress_to_exif_lut); i++) {
1572 if (!strcmp(degrees, degress_to_exif_lut[i].string1)) {
1573 return degress_to_exif_lut[i].string2;
1574 }
1575 }
1576 return NULL;
1577}
1578void ExifElementsTable::stringToRational(const char* str, unsigned int* num, unsigned int* den) {
1579 int len;
1580 char * tempVal = NULL;
1581 if (str != NULL) {
1582 len = strlen(str);
1583 tempVal = (char*) malloc( sizeof(char) * (len + 1));
1584 }
1585 if (tempVal != NULL) {
1586 size_t den_len;
1587 char *ctx;
1588 unsigned int numerator = 0;
1589 unsigned int denominator = 0;
1590 char* temp = NULL;
1591 memset(tempVal, '\0', len + 1);
1592 strncpy(tempVal, str, len);
1593 temp = strtok_r(tempVal, ".", &ctx);
1594 if (temp != NULL)
1595 numerator = atoi(temp);
1596 if (!numerator)
1597 numerator = 1;
1598 temp = strtok_r(NULL, ".", &ctx);
1599 if (temp != NULL) {
1600 den_len = strlen(temp);
1601 if(HUGE_VAL == den_len ) {
1602 den_len = 0;
1603 }
1604 denominator = static_cast<unsigned int>(pow(10, den_len));
1605 numerator = numerator * denominator + atoi(temp);
1606 } else {
1607 denominator = 1;
1608 }
1609 free(tempVal);
1610 *num = numerator;
1611 *den = denominator;
1612 }
1613}
1614bool ExifElementsTable::isAsciiTag(const char* tag) {
1615 return (strcmp(tag, TAG_GPS_PROCESSING_METHOD) == 0);
1616}
1617status_t ExifElementsTable::insertElement(const char* tag, const char* value) {
1618 int value_length = 0;
1619 status_t ret = NO_ERROR;
1620 if (!value || !tag) {
1621 return -EINVAL;
1622 }
1623 if (position >= MAX_EXIF_TAGS_SUPPORTED) {
1624 CAMHAL_LOGEA("Max number of EXIF elements already inserted");
1625 return NO_MEMORY;
1626 }
1627 if (isAsciiTag(tag)) {
1628 value_length = sizeof(ExifAsciiPrefix) + strlen(value + sizeof(ExifAsciiPrefix));
1629 } else {
1630 value_length = strlen(value);
1631 }
1632 if (IsGpsTag(tag)) {
1633 table[position].GpsTag = TRUE;
1634 table[position].Tag = GpsTagNameToValue(tag);
1635 gps_tag_count++;
1636 } else {
1637 table[position].GpsTag = FALSE;
1638 table[position].Tag = TagNameToValue(tag);
1639 exif_tag_count++;
1640 }
1641 table[position].DataLength = 0;
1642 table[position].Value = (char*) malloc(sizeof(char) * (value_length + 1));
1643 if (table[position].Value) {
1644 memcpy(table[position].Value, value, value_length + 1);
1645 table[position].DataLength = value_length + 1;
1646 }
1647 position++;
1648 return ret;
1649}
1650void ExifElementsTable::saveJpeg(unsigned char* jpeg, size_t jpeg_size) {
1651 int ret;
1652 if (jpeg_opened) {
1653 ret = WriteJpegToBuffer(jpeg, jpeg_size);
1654 ALOGD("saveJpeg :: ret =%d",ret);
1655 DiscardData();
1656 jpeg_opened = false;
1657 }
1658}
1659void ExifElementsTable::insertExifToJpeg(unsigned char* jpeg, size_t jpeg_size) {
1660 ReadMode_t read_mode = (ReadMode_t)(READ_METADATA | READ_IMAGE);
1661 ResetJpgfile();
1662 if (ReadJpegSectionsFromBuffer(jpeg, jpeg_size, read_mode)) {
1663 jpeg_opened = true;
1664 create_EXIF(table, exif_tag_count, gps_tag_count,true);
1665 }
1666}
1667status_t ExifElementsTable::insertExifThumbnailImage(const char* thumb, int len) {
1668 status_t ret = NO_ERROR;
1669 if ((len > 0) && jpeg_opened) {
1670 ret = ReplaceThumbnailFromBuffer(thumb, len);
1671 CAMHAL_LOGDB("insertExifThumbnailImage. ReplaceThumbnail(). ret=%d", ret);
1672 }
1673 return ret;
1674}
1675ExifElementsTable::~ExifElementsTable() {
1676 int num_elements = gps_tag_count + exif_tag_count;
1677 for (int i = 0; i < num_elements; i++) {
1678 if (table[i].Value) {
1679 free(table[i].Value);
1680 }
1681 }
1682 if (jpeg_opened) {
1683 DiscardData();
1684 }
1685}
1686} // namespace android
1687