summaryrefslogtreecommitdiff
path: root/v3/fake-pipeline2/JpegCompressor.cpp (plain)
blob: 2ef5c8b86fc45052fb7850a1bf580fba95f5919a
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_Libexif() {
224 struct camera2_jpeg_blob blob;
225 int offset;
226 status_t res;
227 memset(&blob,0,sizeof(struct camera2_jpeg_blob));
228 if (mNeedexif) {
229 uint32_t realjpegsize = 0;
230 if (mJpegRequest.mNeedThumbnail) {
231 res = thumbcompress();
232 }
233
234 exif_buffer *sEb = get_exif_buffer();
235 if (sEb != NULL) {
236 if (mJpegRequest.mNeedThumbnail) {
237 uint8_t * mTempJpegBuffer = (uint8_t *)malloc(mMainJpegSize + sEb->size + mThumbJpegSize);
238 memset(mTempJpegBuffer, 0, sizeof(char) * (mMainJpegSize + sEb->size + mThumbJpegSize));
239 memcpy(mTempJpegBuffer, exif_header, exif_header_len);
240 mTempJpegBuffer[exif_header_len] = (sEb->size + mThumbJpegSize + 2) >> 8;
241 mTempJpegBuffer[exif_header_len + 1] = ((sEb->size + mThumbJpegSize + 2) & 0xff);
242 memcpy(mTempJpegBuffer + exif_header_len + 2, sEb->data, sEb->size);
243 memcpy(mTempJpegBuffer + exif_header_len + sEb->size + 2, mDstThumbBuffer, mThumbJpegSize);
244 memcpy(mTempJpegBuffer + exif_header_len + sEb->size + mThumbJpegSize+ 2,
245 mJpegBuffer.img + image_data_offset, mMainJpegSize - image_data_offset);
246 memcpy(mJpegBuffer.img, mTempJpegBuffer, mMainJpegSize + sEb->size + mThumbJpegSize);
247 if (mTempJpegBuffer != NULL) {
248 free(mTempJpegBuffer);
249 mTempJpegBuffer = NULL;
250 }
251 for (uint32_t size = (mMainJpegSize + sEb->size + mThumbJpegSize); size > 0; size--) {
252 if (checkJpegEnd(mJpegBuffer.img + size)) {
253 realjpegsize = (size + MARKER_LENGTH);
254 break;
255 }
256 }
257 offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
258 blob.jpeg_blob_id = 0x00FF;
259 blob.jpeg_size = realjpegsize;
260 memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
261 if (sEb != NULL) {
262 if (sEb->data) {
263 free(sEb->data);
264 sEb->data = NULL;
265 }
266 free(sEb);
267 sEb = NULL;
268 CAMHAL_LOGDA("free malloc sEb buffer");
269 }
270 } else {
271 uint8_t * mTempJpegBuffer = (uint8_t *)malloc(mMainJpegSize + sEb->size);
272 memset(mTempJpegBuffer, 0, sizeof(char) * (mMainJpegSize + sEb->size));
273 memcpy(mTempJpegBuffer, exif_header, exif_header_len);
274 mTempJpegBuffer[exif_header_len] = (sEb->size+2) >> 8;
275 mTempJpegBuffer[exif_header_len + 1] = ((sEb->size+2) & 0xff);
276 memcpy(mTempJpegBuffer + exif_header_len + 2, sEb->data, sEb->size);
277 memcpy(mTempJpegBuffer + exif_header_len + sEb->size + 2, mJpegBuffer.img + image_data_offset,
278 mMainJpegSize - image_data_offset);
279 memcpy(mJpegBuffer.img, mTempJpegBuffer, mMainJpegSize + sEb->size);
280 if (mTempJpegBuffer != NULL) {
281 free(mTempJpegBuffer);
282 mTempJpegBuffer = NULL;
283 }
284 for (uint32_t size = (mMainJpegSize + sEb->size); size > 0; size--) {
285 if (checkJpegEnd(mJpegBuffer.img + size)) {
286 realjpegsize = (size + MARKER_LENGTH);
287 break;
288 }
289 }
290 offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
291 blob.jpeg_blob_id = 0x00FF;
292 blob.jpeg_size = realjpegsize;
293 memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
294 if (sEb != NULL) {
295 if (sEb->data) {
296 free(sEb->data);
297 sEb->data = NULL;
298 }
299 free(sEb);
300 sEb = NULL;
301 CAMHAL_LOGDA("free malloc sEb buffer");
302 }
303 }
304 } else {
305 DBG_LOGA("get exif buffer failed, so only callback Main JPEG data");
306 for (uint32_t size = (mMainJpegSize + sEb->size); size > 0; size--) {
307 if (checkJpegEnd(mJpegBuffer.img + size)) {
308 realjpegsize = (size + MARKER_LENGTH);
309 break;
310 }
311 }
312 offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
313 blob.jpeg_blob_id = 0x00FF;
314 blob.jpeg_size = realjpegsize;
315 memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
316 }
317 } else {
318 uint32_t realjpegsize = 0;
319 for (uint32_t size = (mMainJpegSize); size > 0; size--) {
320 if (checkJpegEnd(mJpegBuffer.img + size)) {
321 realjpegsize = (size + MARKER_LENGTH);
322 break;
323 }
324 }
325 int offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
326 blob.jpeg_blob_id = 0x00FF;
327 blob.jpeg_size = realjpegsize;
328 memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
329 }
330 return res;
331}
332
333bool JpegCompressor::threadLoop() {
334 status_t res;
335 CaptureRequest* ri = NULL;
336 {
337 mMutex.lock();
338 if (mExitJpegThread) {
339 mMutex.unlock();
340 ALOGE("JpegCompressor Thread : exiting on request0");
341 return false;
342 }
343
344 while (mPendingrequest == 0) {
345 res = mInJpegRequestSignal.wait(mMutex);
346 }
347 mPendingrequest--;
348 if (mInJpegRequestQueue.size() > 0) {
349 List<CaptureRequest*>::iterator i = mInJpegRequestQueue.begin();
350 mJpegRequest.frameNumber = (*i)->frameNumber;
351 mJpegRequest.buf = (*i)->buf;
352 mJpegRequest.sensorBuffers = (*i)->sensorBuffers;
353 mJpegRequest.mNeedThumbnail = (*i)->mNeedThumbnail;
354 ri = *mInJpegRequestQueue.begin();
355 mInJpegRequestQueue.erase(mInJpegRequestQueue.begin());
356 mBuffers = mJpegRequest.sensorBuffers;
357 } else {
358 mMutex.unlock();
359 return true;
360 }
361 if (mExitJpegThread) {
362 mMutex.unlock();
363 ALOGE("JpegCompressor Thread : exiting on request1");
364 if (mBuffers != NULL) {
365 delete mBuffers;
366 mBuffers = NULL;
367 }
368 if (ri != NULL) {
369 if (ri->buf != NULL) {
370 delete ri->buf;
371 }
372 delete ri;
373 }
374 return false;
375 }
376 mMutex.unlock();
377 }
378 mFoundJpeg = false;
379 mFoundAux = false;
380 for (size_t i = 0; i < mBuffers->size(); i++) {
381 const StreamBuffer &b = (*mBuffers)[i];
382 if (b.format == HAL_PIXEL_FORMAT_BLOB) {
383 mJpegBuffer = b;
384 mFoundJpeg = true;
385 } else if (b.streamId <= 0) {
386 mAuxBuffer = b;
387 mFoundAux = true;
388 }
389 if (mFoundJpeg && mFoundAux) break;
390 }
391 if (!mFoundJpeg || !mFoundAux) {
392 ALOGE("%s: Unable to find buffers for JPEG source/destination",
393 __FUNCTION__);
394 return BAD_VALUE;
395 }
396
397 struct timeval mTimeStart,mTimeend;
398 int intreval;
399 ALOGV("%s: Starting compression thread", __FUNCTION__);
400 gettimeofday(&mTimeStart, NULL);
401
402 res = compress();
403
404 Create_Exif_Use_Libexif();
405
406 mListener->onJpegDone(mJpegBuffer, res == OK, mJpegRequest);
407
408 if (ri != NULL) {
409 if (ri->buf != NULL) {
410 delete ri->buf;
411 }
412 delete ri;
413 }
414 gettimeofday(&mTimeend, NULL);
415 intreval = (mTimeend.tv_sec - mTimeStart.tv_sec) * 1000 + ((mTimeend.tv_usec - mTimeStart.tv_usec))/1000;
416 ALOGD("jpeg compress cost time =%d ms",intreval);
417 cleanUp();
418
419 return true;
420}
421
422struct libjpeg_destination_mgr : jpeg_destination_mgr {
423 libjpeg_destination_mgr(uint8_t* input, int size);
424 uint8_t* buf;
425 int bufsize;
426 size_t jpegsize;
427};
428
429static void libjpeg_init_destination (j_compress_ptr cinfo) {
430 libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest;
431
432 dest->next_output_byte = dest->buf;
433 dest->free_in_buffer = dest->bufsize;
434 dest->jpegsize = 0;
435}
436
437static boolean libjpeg_empty_output_buffer(j_compress_ptr cinfo) {
438 libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest;
439
440 dest->next_output_byte = dest->buf;
441 dest->free_in_buffer = dest->bufsize;
442 return TRUE; // ?
443}
444
445static void libjpeg_term_destination (j_compress_ptr cinfo) {
446 libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest;
447 dest->jpegsize = dest->bufsize - dest->free_in_buffer;
448}
449
450libjpeg_destination_mgr::libjpeg_destination_mgr(uint8_t* input, int size) {
451 this->init_destination = libjpeg_init_destination;
452 this->empty_output_buffer = libjpeg_empty_output_buffer;
453 this->term_destination = libjpeg_term_destination;
454 this->buf = input;
455 this->bufsize = size;
456 jpegsize = 0;
457}
458
459static void resize_nv12(params* params, uint8_t* dst_buffer) {
460 structConvImage o_img_ptr, i_img_ptr;
461
462 if (!params || !dst_buffer) {
463 return;
464 }
465
466 //input
467 i_img_ptr.uWidth = (mmInt32)params->in_width;
468 i_img_ptr.uStride = (mmInt32)i_img_ptr.uWidth;
469 i_img_ptr.uHeight = (mmInt32)params->in_height;
470 i_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp;
471 i_img_ptr.imgPtr = (mmByte *) params->src;
472 i_img_ptr.clrPtr = (mmByte *)i_img_ptr.imgPtr + (i_img_ptr.uWidth * i_img_ptr.uHeight);
473 i_img_ptr.uOffset = 0;
474
475 //ouput
476 o_img_ptr.uWidth = (mmInt32)params->out_width;
477 o_img_ptr.uStride = (mmInt32)o_img_ptr.uWidth;
478 o_img_ptr.uHeight = (mmInt32)params->out_height;
479 o_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp;
480 o_img_ptr.imgPtr = (mmByte *)dst_buffer;
481 o_img_ptr.clrPtr = (mmByte *)o_img_ptr.imgPtr + (o_img_ptr.uWidth * o_img_ptr.uHeight);
482 o_img_ptr.uOffset = 0;
483
484 VT_resizeFrame_Video_opt2_lp(&i_img_ptr, &o_img_ptr, NULL, 0);
485}
486
487static void resize_yuyv(params* params, uint8_t* dst_buffer) {
488 int step_x, step_y;
489 int dst_pos, src_pos;
490 int src_y_start_pos;
491 step_x = params->in_width / params->out_width;
492 step_y = params->in_height / params->out_height;
493 dst_pos = 0;
494 for (int y = 0; y < params->out_height; y++) {
495 src_y_start_pos = (y * step_y * (params->in_width * 2));
496 for (int x = 0; x < params->out_width; x += 2) {
497 src_pos = src_y_start_pos + (x * (step_x * 2));
498 dst_buffer[dst_pos++] = params->src[src_pos];
499 dst_buffer[dst_pos++] = params->src[src_pos + 1];
500 dst_buffer[dst_pos++] = params->src[src_pos + 2];
501 dst_buffer[dst_pos++] = params->src[src_pos + 3];
502 }
503 }
504}
505
506/* private static functions */
507static void nv21_to_yuv(uint8_t* dst, uint8_t* y, uint8_t* uv, int width) {
508 if (!dst || !y || !uv) {
509 return;
510 }
511
512 while ((width--) > 0) {
513 uint8_t y0 = y[0];
514 uint8_t v0 = uv[0];
515 uint8_t u0 = *(uv+1);
516 dst[0] = y0;
517 dst[1] = u0;
518 dst[2] = v0;
519 dst += 3;
520 y++;
521 if (!(width % 2)) uv+=2;
522 }
523}
524
525static void yuyv_to_yuv(uint8_t* dst, uint32_t* src, int width) {
526 if (!dst || !src) {
527 return;
528 }
529
530 if (width % 2) {
531 return; // not supporting odd widths
532 }
533
534 // currently, neon routine only supports multiple of 16 width
535 if (width % 16) {
536 while ((width-=2) >= 0) {
537 uint8_t y0 = (src[0] >> 0) & 0xFF;
538 uint8_t u0 = (src[0] >> 8) & 0xFF;
539 uint8_t y1 = (src[0] >> 16) & 0xFF;
540 uint8_t v0 = (src[0] >> 24) & 0xFF;
541 dst[0] = y0;
542 dst[1] = u0;
543 dst[2] = v0;
544 dst[3] = y1;
545 dst[4] = u0;
546 dst[5] = v0;
547 dst += 6;
548 src++;
549 }
550 } else {
551 int n = width;
552#if defined(__arm__)
553 asm volatile (
554 " pld [%[src], %[src_stride], lsl #2] \n\t"
555 " cmp %[n], #16 \n\t"
556 " blt 5f \n\t"
557 "0: @ 16 pixel swap \n\t"
558 " vld2.8 {q0, q1} , [%[src]]! @ q0 = y q1 = uv \n\t"
559 " vuzp.8 q1, q2 @ d2 = u d4 = v \n\t"
560 " vmov d3, d2 @ q1 = u0u1u2..u0u1u2... \n\t"
561 " vmov d5, d4 @ q2 = v0v1v2..v0v1v2... \n\t"
562 " vzip.8 d2, d3 @ q1 = u0u0u1u1u2u2... \n\t"
563 " vzip.8 d4, d5 @ q2 = v0v0v1v1v2v2... \n\t"
564 " vst3.8 {d0,d2,d4},[%[dst]]! \n\t"
565 " vst3.8 {d1,d3,d5},[%[dst]]! \n\t"
566 " sub %[n], %[n], #16 \n\t"
567 " cmp %[n], #16 \n\t"
568 " bge 0b \n\t"
569 "5: @ end \n\t"
570#ifdef NEEDS_ARM_ERRATA_754319_754320
571 " vmov s0,s0 @ add noop for errata item \n\t"
572#endif
573 : [dst] "+r" (dst), [src] "+r" (src), [n] "+r" (n)
574 : [src_stride] "r" (width)
575 : "cc", "memory", "q0", "q1", "q2"
576 );
577#elif defined(__aarch64__)
578#endif
579 }
580}
581
582static uint32_t calc_frame_length(int format, uint32_t width, uint32_t height)
583{
584 uint32_t length;
585 switch (format) {
586 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
587 length = width * height * 3/2;
588 break;
589 case HAL_PIXEL_FORMAT_RGB_888:
590 length = width * height * 3;
591 break;
592 case HAL_PIXEL_FORMAT_YCbCr_422_I:
593 length = width * height * 2;
594 break;
595 default:
596 length = width * height * 3/2;
597 break;
598 }
599 return length;
600}
601
602size_t encode(params* input) {
603 jpeg_compress_struct cinfo;
604 jpeg_error_mgr jerr;
605 jpeg_destination_mgr jdest;
606 uint8_t* src = NULL;
607 uint8_t* resize_src = NULL;
608 uint8_t* row_tmp = NULL;
609 uint8_t* row_src = NULL;
610 uint8_t* row_uv = NULL; // used only for NV12
611 int row_stride;
612 int out_width = 0, in_width = 0;
613 int out_height = 0, in_height = 0;
614 int bpp = 2; // for uyvy
615
616 format informat = YUV422I;
617
618 if (!input) {
619 return 0;
620 }
621
622 out_width = input->out_width;
623 in_width = input->in_width;
624 out_height = input->out_height;
625 in_height = input->in_height;
626 src = input->src;
627 input->jpeg_size = 0;
628 libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size);
629
630 // param check...
631 if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) ||
632 (src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) ||
633 (input->dst_size < 1) ) {
634 goto exit;
635 }
636
637 if (input->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
638 informat = YUV420SP;
639 bpp = 1;
640 if ((in_width != out_width) || (in_height != out_height)) {
641 resize_src = (uint8_t*) malloc(out_width * out_height *3);
642 if (NULL != resize_src) {
643 resize_nv12(input, resize_src);
644 if (resize_src) src = resize_src;
645 } else {
646 CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
647 goto exit;
648 }
649 }
650 } else if ((input->format == HAL_PIXEL_FORMAT_RGB_888)) {
651 informat = RGB24;
652 bpp = 1;
653 if ((in_width != out_width) || (in_height != out_height)) {
654 resize_src = (uint8_t*) malloc(out_width * out_height *3);
655 if (NULL != resize_src) {
656 extraSmallImg(input->src, in_width, in_height,
657 resize_src, out_width, out_height);
658 src = resize_src;
659 } else {
660 CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
661 goto exit;
662 }
663 }
664 } else if (input->format == HAL_PIXEL_FORMAT_YCbCr_422_I) {
665 informat = YUV422I;
666 bpp = 2;
667 if ((in_width != out_width) || (in_height != out_height)) {
668 resize_src = (uint8_t*) malloc(out_width * out_height *3);
669 if (NULL != resize_src) {
670 resize_yuyv(input,resize_src);
671 if (resize_src) src = resize_src;
672 } else {
673 CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
674 goto exit;
675 }
676 }
677 } else if ((in_width != out_width) || (in_height != out_height)) {
678 CAMHAL_LOGEB("Encoder: resizing is not supported for this format: %d", input->format);
679 goto exit;
680 } else if ((input->format != HAL_PIXEL_FORMAT_YCbCr_422_I)) {
681 // we currently only support yuv422i and yuv420sp
682 CAMHAL_LOGEB("Encoder: format not supported: %d", input->format);
683 goto exit;
684 }
685
686 cinfo.err = jpeg_std_error(&jerr);
687
688 jpeg_create_compress(&cinfo);
689
690 CAMHAL_LOGDB("software encoding... \n\t"
691 "width: %d \n\t"
692 "height:%d \n\t"
693 "dest %p \n\t"
694 "dest size:%d \n\t"
695 "mSrc %p",
696 out_width, out_height, input->dst,
697 input->dst_size, src);
698
699 cinfo.dest = &dest_mgr;
700 cinfo.image_width = out_width;
701 cinfo.image_height = out_height;
702 cinfo.input_components = 3;
703 if (informat == RGB24)
704 cinfo.in_color_space = JCS_RGB;
705 else
706 cinfo.in_color_space = JCS_YCbCr;
707 cinfo.input_gamma = 1;
708
709 jpeg_set_defaults(&cinfo);
710 jpeg_set_quality(&cinfo, input->quality, TRUE);
711 cinfo.dct_method = JDCT_IFAST;
712
713 jpeg_start_compress(&cinfo, TRUE);
714
715 row_tmp = (uint8_t*)malloc(out_width * 3);
716 row_src = src;
717 row_uv = src + out_width * out_height * bpp;
718 row_stride = out_width * 3;
719
720 while ((cinfo.next_scanline < cinfo.image_height)) {
721 JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */
722
723 if (informat == RGB24) {
724 row[0] = &src[cinfo.next_scanline * row_stride];
725 (void) jpeg_write_scanlines(&cinfo, row, 1);
726 } else {
727 // convert input yuv format to yuv444
728 if (informat == YUV420SP) {
729 nv21_to_yuv(row_tmp, row_src, row_uv, out_width);
730 } else if (informat == YUV422I) {
731 //uyvy_to_yuv(row_tmp, (uint32_t*)row_src, out_width);
732 yuyv_to_yuv(row_tmp, (uint32_t*)row_src, out_width);
733 }
734
735 row[0] = row_tmp;
736 jpeg_write_scanlines(&cinfo, row, 1);
737 row_src = row_src + out_width*bpp;
738
739 // move uv row if input format needs it
740 if (informat == YUV420SP) {
741 if (!(cinfo.next_scanline % 2))
742 row_uv = row_uv + out_width * bpp;
743 }
744 }
745 }
746
747 jpeg_finish_compress(&cinfo);
748 jpeg_destroy_compress(&cinfo);
749
750 if (resize_src) free(resize_src);
751 if (row_tmp) free(row_tmp);
752
753 exit:
754 input->jpeg_size = dest_mgr.jpegsize;
755 return dest_mgr.jpegsize;
756}
757
758status_t JpegCompressor::compress() {
759 // Find source and target buffers. Assumes only one buffer matches
760 // each condition!
761 if (mJpegRequest.mNeedThumbnail == true) {
762 mSrcThumbBuffer = mAuxBuffer.img;
763 if (mDstThumbBuffer == NULL) {
764 mDstThumbBuffer = (uint8_t*)malloc(mInfo.thumbwidth * mInfo.thumbheight * 3);
765 }
766 }
767
768 params enc_params;
769 enc_params.src = mAuxBuffer.img;
770 enc_params.src_size = calc_frame_length(mAuxBuffer.format, mAuxBuffer.width, mAuxBuffer.height);
771 enc_params.dst = mJpegBuffer.img;
772 enc_params.dst_size = mMaxbufsize;
773 enc_params.quality = 80;
774 enc_params.in_width = mAuxBuffer.width;
775 enc_params.in_height = mAuxBuffer.height;
776 enc_params.out_width= mAuxBuffer.width;
777 enc_params.out_height = mAuxBuffer.height;
778 enc_params.format = mAuxBuffer.format;
779 enc_params.jpeg_size = 0;
780
781 mMainJpegSize = encode(&enc_params);
782 ALOGD("mMainJpegSize = %d",mMainJpegSize);
783
784 return OK;
785}
786
787status_t JpegCompressor::thumbcompress() {
788 if ((mSrcThumbBuffer == NULL) || (mDstThumbBuffer == NULL))
789 return 0;
790
791 params enc_params;
792 enc_params.src = mSrcThumbBuffer;
793 enc_params.dst = mDstThumbBuffer;
794 enc_params.dst_size = mInfo.thumbwidth * mInfo.thumbheight * 3;
795 enc_params.quality = 70;
796 enc_params.src_size = calc_frame_length(mAuxBuffer.format, mAuxBuffer.width, mAuxBuffer.height);
797 enc_params.in_width = mAuxBuffer.width;
798 enc_params.in_height = mAuxBuffer.height;
799 enc_params.out_width= mInfo.thumbwidth;
800 enc_params.out_height = mInfo.thumbheight;
801 enc_params.format = mAuxBuffer.format;
802 enc_params.jpeg_size = 0;
803
804 mThumbJpegSize = encode(&enc_params);
805 ALOGD("mThumbJpegSize = %d",mThumbJpegSize);
806
807 return OK;
808}
809bool JpegCompressor::isBusy() {
810 Mutex::Autolock busyLock(mBusyMutex);
811 return mIsBusy;
812}
813
814bool JpegCompressor::isStreamInUse(uint32_t id) {
815 Mutex::Autolock lock(mBusyMutex);
816
817 if (mBuffers && mIsBusy) {
818 for (size_t i = 0; i < mBuffers->size(); i++) {
819 if ( (*mBuffers)[i].streamId == (int)id ) return true;
820 }
821 }
822 return false;
823}
824
825bool JpegCompressor::waitForDone(nsecs_t timeout) {
826 Mutex::Autolock lock(mBusyMutex);
827 status_t res = OK;
828 if (mIsBusy) {
829 res = mDone.waitRelative(mBusyMutex, timeout);
830 }
831 return (res == OK);
832}
833
834bool JpegCompressor::checkError(const char *msg) {
835 if (mJpegErrorInfo) {
836 char errBuffer[JMSG_LENGTH_MAX];
837 mJpegErrorInfo->err->format_message(mJpegErrorInfo, errBuffer);
838 ALOGE("%s: %s: %s",
839 __FUNCTION__, msg, errBuffer);
840 mJpegErrorInfo = NULL;
841 return true;
842 }
843 return false;
844}
845
846void JpegCompressor::cleanUp() {
847 status_t res;
848 Mutex::Autolock lock(mBusyMutex);
849 if (mJpegRequest.mNeedThumbnail == true) {
850 if (mSrcThumbBuffer != NULL) {
851 mSrcThumbBuffer = NULL;
852 }
853 if (mDstThumbBuffer != NULL) {
854 free(mDstThumbBuffer);
855 mDstThumbBuffer = NULL;
856 }
857 }
858 if (mFoundAux) {
859 if (mAuxBuffer.streamId == 0) {
860 delete[] mAuxBuffer.img;
861 } else if (!mSynchronous) {
862 mListener->onJpegInputDone(mAuxBuffer);
863 }
864 }
865 if (!mSynchronous) {
866 delete mBuffers;
867 }
868
869 mBuffers = NULL;
870
871 mIsBusy = false;
872 mDone.signal();
873}
874
875JpegCompressor::JpegListener::~JpegListener() {
876}
877
878void JpegCompressor::SetMaxJpegBufferSize(ssize_t size)
879{
880 mMaxbufsize = size;
881}
882ssize_t JpegCompressor::GetMaxJpegBufferSize()
883{
884 return mMaxbufsize;
885}
886void JpegCompressor::SetExifInfo(struct ExifInfo info)
887{
888 memcpy(&mInfo, &info, sizeof(struct ExifInfo));
889}
890
891void JpegCompressor::exif_entry_set_string (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, const char *s)
892{
893 ExifEntry *pE;
894
895 pE = exif_entry_new ();
896 exif_content_add_entry (pEdata->ifd[eEifd], pE);
897 exif_entry_initialize (pE, eEtag);
898 if (pE->data)
899 free (pE->data);
900 pE->components = strlen (s) + 1;
901 pE->size = sizeof (char) * pE->components;
902 pE->data = (unsigned char *) malloc (pE->size);
903 if (!pE->data) {
904 DBG_LOGB("Cannot allocate %d bytes.\nTerminating.\n", (int) pE->size);
905 exit (1);
906 }
907 strcpy ((char *) pE->data, (char *) s);
908 exif_entry_fix (pE);
909 exif_entry_unref (pE);
910}
911
912void JpegCompressor::exif_entry_set_short (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifShort n)
913{
914 ExifEntry *pE;
915 ExifByteOrder eO;
916
917 pE = exif_entry_new ();
918 exif_content_add_entry (pEdata->ifd[eEifd], pE);
919 exif_entry_initialize (pE, eEtag);
920 eO = exif_data_get_byte_order (pE->parent->parent);
921 if (pE->data) {
922 exif_set_short (pE->data, eO, n);
923 } else {
924 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
925 }
926 exif_entry_fix (pE);
927 exif_entry_unref (pE);
928}
929
930void JpegCompressor::exif_entry_set_long (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifLong n)
931{
932 ExifEntry *pE;
933 ExifByteOrder eO;
934
935 pE = exif_entry_new ();
936 exif_content_add_entry (pEdata->ifd[eEifd], pE);
937 exif_entry_initialize (pE, eEtag);
938 eO = exif_data_get_byte_order (pE->parent->parent);
939 if (pE->data) {
940 exif_set_long (pE->data, eO, n);
941 } else {
942 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
943 }
944 exif_entry_fix (pE);
945 exif_entry_unref (pE);
946}
947
948void JpegCompressor::exif_entry_set_rational (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifRational r)
949{
950 ExifEntry *pE;
951 ExifByteOrder eO;
952
953 pE = exif_entry_new ();
954 exif_content_add_entry (pEdata->ifd[eEifd], pE);
955 exif_entry_initialize (pE, eEtag);
956 eO = exif_data_get_byte_order (pE->parent->parent);
957 if (pE->data) {
958 exif_set_rational (pE->data, eO, r);
959 } else {
960 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
961 }
962 exif_entry_fix (pE);
963 exif_entry_unref (pE);
964}
965
966void JpegCompressor::exif_entry_set_undefined (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, exif_buffer * buf)
967{
968 ExifEntry *pE;
969 pE = exif_entry_new ();
970 exif_content_add_entry (pEdata->ifd[eEifd], pE);
971 exif_entry_initialize (pE, eEtag);
972 if (buf != NULL) {
973 if (pE->data)
974 free (pE->data);
975 pE->components = buf->size;
976 pE->size = buf->size;
977 pE->data = (unsigned char *) malloc (pE->size);
978 if (!pE->data) {
979 DBG_LOGB("Cannot allocate %d bytes.\nTerminating.\n", (int) pE->size);
980 exit (1);
981 }
982 memcpy ((void *) pE->data, (void *) buf->data, buf->size);
983 }
984 exif_entry_fix (pE);
985 exif_entry_unref (pE);
986}
987
988/****************************************************************************
989 * Public API
990 ***************************************************************************/
991
992/* Get an existing tag, or create one if it doesn't exist */
993ExifEntry* JpegCompressor::init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag)
994{
995 ExifEntry *entry;
996 /* Return an existing tag if one exists */
997 if (!((entry = exif_content_get_entry (exif->ifd[ifd], tag)))) {
998 /* Allocate a new entry */
999 entry = exif_entry_new ();
1000 assert(entry != NULL); /* catch an out of memory condition */
1001 entry->tag = tag; /* tag must be set before calling
1002 exif_content_add_entry */
1003
1004 /* Attach the ExifEntry to an IFD */
1005 exif_content_add_entry (exif->ifd[ifd], entry);
1006
1007 /* Allocate memory for the entry and fill with default data */
1008 exif_entry_initialize (entry, tag);
1009
1010 /* Ownership of the ExifEntry has now been passed to the IFD.
1011 * One must be very careful in accessing a structure after
1012 * unref'ing it; in this case, we know "entry" won't be freed
1013 * because the reference count was bumped when it was added to
1014 * the IFD.
1015 */
1016 exif_entry_unref(entry);
1017 }
1018 return entry;
1019}
1020
1021/* Create a brand-new tag with a data field of the given length, in the
1022 * given IFD. This is needed when exif_entry_initialize() isn't able to create
1023 * this type of tag itself, or the default data length it creates isn't the
1024 * correct length.
1025 */
1026ExifEntry *JpegCompressor::create_tag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len)
1027{
1028 void *buf;
1029 ExifEntry *entry;
1030
1031 /* Create a memory allocator to manage this ExifEntry */
1032 ExifMem *mem = exif_mem_new_default();
1033 assert(mem != NULL); /* catch an out of memory condition */
1034
1035 /* Create a new ExifEntry using our allocator */
1036 entry = exif_entry_new_mem (mem);
1037 assert(entry != NULL);
1038
1039 /* Allocate memory to use for holding the tag data */
1040 buf = exif_mem_alloc(mem, len);
1041 assert(buf != NULL);
1042
1043 /* Fill in the entry */
1044 entry->data = (unsigned char*)buf;
1045 entry->size = len;
1046 entry->tag = tag;
1047 entry->components = len;
1048 entry->format = EXIF_FORMAT_UNDEFINED;
1049
1050 /* Attach the ExifEntry to an IFD */
1051 exif_content_add_entry (exif->ifd[ifd], entry);
1052
1053 /* The ExifMem and ExifEntry are now owned elsewhere */
1054 exif_mem_unref(mem);
1055 exif_entry_unref(entry);
1056
1057 return entry;
1058}
1059
1060void JpegCompressor::exif_entry_set_gps_coord(ExifData * pEdata, ExifTag eEtag,
1061 ExifRational r1, ExifRational r2, ExifRational r3)
1062{
1063 ExifEntry *pE;
1064 ExifByteOrder eO;
1065
1066 pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
1067 3 * exif_format_get_size(EXIF_FORMAT_RATIONAL));
1068
1069 pE->components = 3;
1070 pE->format = EXIF_FORMAT_RATIONAL;
1071
1072 eO = exif_data_get_byte_order (pE->parent->parent);
1073
1074 if (pE->data) {
1075 exif_set_rational (pE->data, eO, r1);
1076 exif_set_rational (pE->data + exif_format_get_size (pE->format), eO, r2);
1077 exif_set_rational (pE->data + 2 * exif_format_get_size (pE->format), eO, r3);
1078 } else {
1079 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1080 }
1081}
1082
1083void JpegCompressor::exif_entry_set_gps_altitude(ExifData * pEdata, ExifTag eEtag, ExifRational r1)
1084{
1085 ExifEntry *pE;
1086 ExifByteOrder eO;
1087
1088 pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
1089 1 * exif_format_get_size(EXIF_FORMAT_RATIONAL));
1090
1091 pE->components = 1;
1092 pE->format = EXIF_FORMAT_RATIONAL;
1093
1094 eO = exif_data_get_byte_order (pE->parent->parent);
1095 if (pE->data) {
1096 exif_set_rational (pE->data, eO, r1);
1097 } else {
1098 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1099 }
1100}
1101
1102void JpegCompressor::exif_entry_set_gps_coord_ref(ExifData * pEdata, ExifTag eEtag, const char *s)
1103{
1104 ExifEntry *pE;
1105 ExifByteOrder eO;
1106
1107 pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
1108 (strlen (s) + 1) * exif_format_get_size(EXIF_FORMAT_ASCII));
1109
1110 pE->components = strlen (s) + 1;
1111 pE->format = EXIF_FORMAT_ASCII;
1112
1113 eO = exif_data_get_byte_order (pE->parent->parent);
1114 if (pE->data) {
1115 strcpy ((char *) pE->data, s);
1116 } else {
1117 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1118 }
1119}
1120
1121void JpegCompressor::exif_entry_set_gps_altitude_ref(ExifData * pEdata, ExifTag eEtag, ExifByte n)
1122{
1123 ExifEntry *pE;
1124 ExifByteOrder eO;
1125
1126 pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
1127 1 * exif_format_get_size(EXIF_FORMAT_BYTE));
1128
1129 pE->components = 1;
1130 pE->format = EXIF_FORMAT_BYTE;
1131
1132 eO = exif_data_get_byte_order (pE->parent->parent);
1133 if (pE->data) {
1134 *(pE->data) = n;
1135 } else {
1136 DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
1137 }
1138}
1139
1140exif_buffer * JpegCompressor::get_exif_buffer() {
1141
1142 char exifcontent[256];
1143 ExifData *pEd;
1144 ExifEntry *entry;
1145 exif_buffer *sEb;
1146 ExifRational sR;
1147 int res;
1148 int orientation;
1149 struct timeval sTv;
1150 time_t times;
1151 struct tm tmstruct;
1152 char property[PROPERTY_VALUE_MAX];
1153
1154 sEb = (exif_buffer *) malloc (sizeof (exif_buffer));
1155
1156 pEd = exif_data_new ();
1157
1158 if (pEd == NULL)
1159 goto EXIT;
1160
1161 /* Set the image options */
1162 exif_data_set_option(pEd, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
1163 exif_data_set_data_type(pEd, EXIF_DATA_TYPE_COMPRESSED);
1164 exif_data_set_byte_order(pEd, FILE_BYTE_ORDER);
1165
1166 property_get("ro.product.manufacturer", property, EXIF_MAKE_DEFAULT);
1167 exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_MAKE, property);
1168 property_get("ro.product.model", property, EXIF_MODEL_DEFAULT);
1169 exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_MODEL, property);
1170
1171 switch (mInfo.orientation) {
1172 case 180:
1173 orientation = 3;
1174 //orientation = 1;
1175 break;
1176 case 90:
1177 orientation = 6;
1178 //orientation = 8;
1179 break;
1180 case 270:
1181 orientation = 8;
1182 break;
1183 default:
1184 orientation = 1;
1185 break;
1186 }
1187
1188 exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_ORIENTATION, (ExifShort)orientation);
1189
1190 sR.numerator = 1;
1191 sR.denominator = 629;
1192 exif_entry_set_rational (pEd, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, sR);
1193
1194 /* time */
1195 /* this sould be last resort */
1196 time(&times);
1197 tmstruct = *(localtime(&times)); //convert to local time
1198 res = gettimeofday (&sTv, NULL);
1199 strftime(exifcontent, 20, "%Y:%m:%d %H:%M:%S", &tmstruct);
1200 exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_DATE_TIME, exifcontent);
1201 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, exifcontent);
1202 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, exifcontent);
1203
1204 sR.numerator = 28;
1205 sR.denominator = 10;
1206 exif_entry_set_rational (pEd, EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, sR);//android 6 is EXIF_TAG_APERTURE_VALUE
1207
1208 exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_FLASH, 0);
1209
1210 sR.numerator = 3299;
1211 sR.denominator = 1000;
1212 exif_entry_set_rational(pEd, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, sR);
1213
1214 memset(exifcontent, 0, sizeof(exifcontent));
1215 snprintf(exifcontent, 20, "%06d", (int) sTv.tv_usec);
1216 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, exifcontent);
1217 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, exifcontent);
1218 exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, exifcontent);
1219
1220 exif_entry_set_short (pEd, EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, 0);
1221
1222 if (mInfo.has_latitude) {
1223 ExifRational r1, r2, r3;
1224 int offset = 0;
1225 /* gps data */
1226 r1.denominator = 1;
1227 r2.denominator = 1;
1228 r3.denominator = 1;
1229
1230 float latitude = mInfo.latitude;
1231 if (latitude < 0.0) {
1232 latitude*= (float)(-1);
1233 offset = 1;
1234 }
1235 r1.numerator = (uint32_t)latitude;
1236 float latitudeminuts = (latitude-(float)(r1.numerator))*60;
1237 r2.numerator = (uint32_t)latitudeminuts;
1238 float latituseconds = (latitudeminuts-(float)(r2.numerator))*60+0.5;
1239 r3.numerator = (uint32_t)latituseconds;
1240 exif_entry_set_gps_coord(pEd, (ExifTag) EXIF_TAG_GPS_LATITUDE, r1, r2, r3);
1241 exif_entry_set_gps_coord_ref(pEd, (ExifTag) EXIF_TAG_GPS_LATITUDE_REF, offset == 1 ? "S":"N");
1242 }
1243
1244 if (mInfo.has_longitude) {
1245 ExifRational r1, r2, r3;
1246 int offset = 0;
1247 /* gps data */
1248 r1.denominator = 1;
1249 r2.denominator = 1;
1250 r3.denominator = 1;
1251
1252 float longitude = mInfo.longitude;
1253 if (longitude < 0.0) {
1254 longitude*= (float)(-1);
1255 offset = 1;
1256 }
1257 r1.numerator = (uint32_t)longitude;
1258 float longitudeminuts = (longitude-(float)(r1.numerator))*60;
1259 r2.numerator = (uint32_t)longitudeminuts;
1260 float longitudeseconds = (longitudeminuts-(float)(r2.numerator))*60+0.5;
1261 r3.numerator = (uint32_t)longitudeseconds;
1262 exif_entry_set_gps_coord(pEd, (ExifTag) EXIF_TAG_GPS_LONGITUDE, r1, r2, r3);
1263 exif_entry_set_gps_coord_ref(pEd, (ExifTag) EXIF_TAG_GPS_LONGITUDE_REF, offset == 1 ? "W":"E");
1264 }
1265
1266 if (mInfo.has_altitude) {
1267 ExifRational r1;
1268 int offset = 0;
1269 float altitude = mInfo.altitude;
1270 if (altitude < 0.0) {
1271 altitude*= (float)(-1);
1272 offset = 1;
1273 }
1274 r1.denominator = 1;
1275 r1.numerator = (uint32_t)altitude;
1276 exif_entry_set_gps_altitude(pEd, (ExifTag) EXIF_TAG_GPS_ALTITUDE, r1);
1277 exif_entry_set_gps_altitude_ref(pEd, (ExifTag) EXIF_TAG_GPS_ALTITUDE_REF, (ExifByte)offset);
1278 }
1279
1280 if (mInfo.has_gpsTimestamp) {
1281 ExifRational r1, r2, r3;
1282 time_t times;
1283 struct tm tmstruct;
1284 times = mInfo.gpsTimestamp;
1285
1286 r1.denominator = 1;
1287 r2.denominator = 1;
1288 r3.denominator = 1;
1289 memset(exifcontent, 0, sizeof(exifcontent));
1290 if (times != -1) {
1291 tmstruct = *(gmtime(&times));//convert to standard time
1292 strftime(exifcontent, 20, "%Y:%m:%d", &tmstruct);
1293 exif_entry_set_gps_coord_ref(pEd, (ExifTag) EXIF_TAG_GPS_DATE_STAMP, exifcontent);
1294
1295 r1.numerator = tmstruct.tm_hour;
1296 r2.numerator = tmstruct.tm_min;
1297 r3.numerator = tmstruct.tm_sec;
1298 exif_entry_set_gps_coord(pEd, (ExifTag) EXIF_TAG_GPS_TIME_STAMP, r1, r2, r3);
1299 }
1300 }
1301
1302 if (mInfo.has_gpsProcessingMethod) {
1303 char* processmethod = (char*)mInfo.gpsProcessingMethod;
1304 if (processmethod != NULL) {
1305 const char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };//asicii
1306 unsigned char* data = (unsigned char*)malloc(strlen(processmethod) + sizeof(ExifAsciiPrefix));
1307 exif_buffer buffer;
1308 if (data != NULL)
1309 {
1310 memcpy(data, ExifAsciiPrefix, sizeof(ExifAsciiPrefix));
1311 memcpy(data+sizeof(ExifAsciiPrefix), processmethod, strlen(processmethod));
1312 buffer.data = data;
1313 buffer.size = strlen(processmethod)+sizeof(ExifAsciiPrefix);
1314 exif_entry_set_undefined (pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_PROCESSING_METHOD, &buffer);
1315 free(data);
1316 }
1317 }
1318 }
1319
1320 //write IDF1 for thumbnail
1321 if (mJpegRequest.mNeedThumbnail) {
1322 exif_entry_set_short(pEd, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH, mInfo.thumbwidth);
1323 exif_entry_set_short(pEd, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH, mInfo.thumbheight);
1324 exif_entry_set_short(pEd, EXIF_IFD_1, EXIF_TAG_ORIENTATION, (ExifShort)orientation);
1325 //fan say need check
1326 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_EXIF_IFD_POINTER);
1327 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
1328 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
1329 exif_set_long(entry->data, FILE_BYTE_ORDER, (long)mThumbJpegSize);
1330 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_COMPRESSION);
1331 exif_set_short (entry->data, FILE_BYTE_ORDER, 6);
1332 }
1333
1334 /* copy data to our buffer */
1335 exif_data_save_data (pEd, &sEb->data, &sEb->size);
1336 assert(sEb->data != NULL);
1337
1338 if (mJpegRequest.mNeedThumbnail) {
1339 entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
1340 exif_set_long(entry->data, FILE_BYTE_ORDER, (long)(sEb->size + 6 - 0x0c));
1341
1342 exif_data_save_data(pEd, &sEb->data, &sEb->size);
1343 assert(sEb->data != NULL);
1344 }
1345 DBG_LOGB("total exif data length = %d\n", sEb->size);
1346 /* destroy exif structure */
1347 exif_data_unref(pEd);
1348
1349 return sEb;
1350
1351EXIT:
1352 if (sEb != NULL)
1353 free(sEb);
1354
1355 return NULL;
1356}
1357
1358} // namespace android
1359