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 | |
38 | const size_t MARKER_LENGTH = 2; // length of a marker |
39 | const uint8_t MARK = 0xFF; |
40 | const uint8_t EOI = 0xD9; |
41 | bool checkJpegEnd(uint8_t *buf) { |
42 | return buf[0] == MARK && buf[1] == EOI; |
43 | } |
44 | int 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 */ |
70 | static const unsigned int image_data_offset = 20; |
71 | |
72 | /* raw EXIF header data */ |
73 | static const unsigned char exif_header[] = { |
74 | 0xff, 0xd8, 0xff, 0xe1 |
75 | }; |
76 | /* length of data in exif_header */ |
77 | static const unsigned int exif_header_len = sizeof(exif_header); |
78 | |
79 | |
80 | namespace android { |
81 | |
82 | struct string_pair { |
83 | const char* string1; |
84 | const char* string2; |
85 | }; |
86 | static string_pair degress_to_exif_lut [] = { |
87 | {"0", "1"}, |
88 | {"90", "6"}, |
89 | {"180", "3"}, |
90 | {"270", "8"}, |
91 | }; |
92 | |
93 | struct 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 | |
107 | enum format { |
108 | YUV420SP, |
109 | YUV422I, |
110 | RGB24, |
111 | }; |
112 | |
113 | JpegCompressor::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 | |
129 | JpegCompressor::~JpegCompressor() { |
130 | Mutex::Autolock lock(mMutex); |
131 | } |
132 | |
133 | void 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 | |
148 | status_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 | |
158 | status_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 | |
179 | status_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 | |
203 | status_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 | |
219 | status_t JpegCompressor::readyToRun() { |
220 | return OK; |
221 | } |
222 | |
223 | status_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 | |
271 | status_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 | |
381 | bool 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 | |
474 | struct 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 | |
481 | static 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 | |
489 | static 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 | |
497 | static 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 | |
502 | libjpeg_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 | |
511 | static 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 | |
539 | static 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 */ |
559 | static 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 | |
577 | static 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 | |
634 | static 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 | |
654 | size_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 | |
810 | status_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 | |
839 | status_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 | } |
861 | bool JpegCompressor::isBusy() { |
862 | Mutex::Autolock busyLock(mBusyMutex); |
863 | return mIsBusy; |
864 | } |
865 | |
866 | bool 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 | |
877 | bool 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 | |
886 | bool 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 | |
898 | void 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 | |
927 | JpegCompressor::JpegListener::~JpegListener() { |
928 | } |
929 | |
930 | void JpegCompressor::SetMaxJpegBufferSize(ssize_t size) |
931 | { |
932 | mMaxbufsize = size; |
933 | } |
934 | ssize_t JpegCompressor::GetMaxJpegBufferSize() |
935 | { |
936 | return mMaxbufsize; |
937 | } |
938 | void JpegCompressor::SetExifInfo(struct ExifInfo info) |
939 | { |
940 | memcpy(&mInfo, &info, sizeof(struct ExifInfo)); |
941 | } |
942 | int 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(×); |
995 | struct tm tmstruct; |
996 | tmstruct = *(localtime(×)); //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(×); |
1028 | struct tm tmstruct; |
1029 | tmstruct = *(localtime(×)); //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(×));//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 | |
1103 | void 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 | |
1124 | void 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 | |
1142 | void 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 | |
1160 | void 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 | |
1178 | void 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 */ |
1205 | ExifEntry* 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 | */ |
1238 | ExifEntry *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 | |
1272 | void 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 | |
1295 | void 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 | |
1314 | void 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 | |
1333 | void 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 | |
1352 | exif_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(×); |
1409 | tmstruct = *(localtime(×)); //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(×));//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 | |
1563 | EXIT: |
1564 | if (sEb != NULL) |
1565 | free(sEb); |
1566 | |
1567 | return NULL; |
1568 | } |
1569 | |
1570 | const 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 | } |
1578 | void 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 | } |
1614 | bool ExifElementsTable::isAsciiTag(const char* tag) { |
1615 | return (strcmp(tag, TAG_GPS_PROCESSING_METHOD) == 0); |
1616 | } |
1617 | status_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 | } |
1650 | void 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 | } |
1659 | void 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 | } |
1667 | status_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 | } |
1675 | ExifElementsTable::~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 |