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 | |
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_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 | |
333 | bool 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 | |
422 | struct 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 | |
429 | static 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 | |
437 | static 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 | |
445 | static 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 | |
450 | libjpeg_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 | |
459 | static 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 | |
487 | static 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 */ |
507 | static 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 | |
525 | static 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 | |
582 | static 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 | |
602 | size_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 | |
758 | status_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 | |
787 | status_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 | } |
809 | bool JpegCompressor::isBusy() { |
810 | Mutex::Autolock busyLock(mBusyMutex); |
811 | return mIsBusy; |
812 | } |
813 | |
814 | bool 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 | |
825 | bool 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 | |
834 | bool 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 | |
846 | void 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 | |
875 | JpegCompressor::JpegListener::~JpegListener() { |
876 | } |
877 | |
878 | void JpegCompressor::SetMaxJpegBufferSize(ssize_t size) |
879 | { |
880 | mMaxbufsize = size; |
881 | } |
882 | ssize_t JpegCompressor::GetMaxJpegBufferSize() |
883 | { |
884 | return mMaxbufsize; |
885 | } |
886 | void JpegCompressor::SetExifInfo(struct ExifInfo info) |
887 | { |
888 | memcpy(&mInfo, &info, sizeof(struct ExifInfo)); |
889 | } |
890 | |
891 | void 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 | |
912 | void 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 | |
930 | void 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 | |
948 | void 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 | |
966 | void 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 */ |
993 | ExifEntry* 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 | */ |
1026 | ExifEntry *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 | |
1060 | void 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 | |
1083 | void 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 | |
1102 | void 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 | |
1121 | void 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 | |
1140 | exif_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(×); |
1197 | tmstruct = *(localtime(×)); //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(×));//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 | |
1351 | EXIT: |
1352 | if (sEb != NULL) |
1353 | free(sEb); |
1354 | |
1355 | return NULL; |
1356 | } |
1357 | |
1358 | } // namespace android |
1359 |