blob: 8b57aca879c8a13d01af9408597e6fa9a87f476c
1 | /* |
2 | * Copyright (C) 2011 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 | /** |
18 | * @file Encoder_libjpeg.cpp |
19 | * |
20 | * This file encodes a YUV422I buffer to a jpeg |
21 | * TODO(XXX): Need to support formats other than yuv422i |
22 | * Change interface to pre/post-proc algo framework |
23 | * |
24 | */ |
25 | |
26 | #define LOG_TAG "CameraHAL_Encderlibjpeg" |
27 | |
28 | #include "CameraHal.h" |
29 | #include "Encoder_libjpeg.h" |
30 | #include "NV12_resize.h" |
31 | |
32 | #include <stdlib.h> |
33 | #include <unistd.h> |
34 | #include <sys/types.h> |
35 | #include <sys/stat.h> |
36 | #include <fcntl.h> |
37 | #include <stdio.h> |
38 | #include <errno.h> |
39 | #include <math.h> |
40 | |
41 | extern "C" { |
42 | #include "jpeglib.h" |
43 | #include "jerror.h" |
44 | } |
45 | |
46 | |
47 | #define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0])) |
48 | |
49 | namespace android { |
50 | struct string_pair { |
51 | const char* string1; |
52 | const char* string2; |
53 | }; |
54 | static string_pair degress_to_exif_lut [] = { |
55 | // degrees, exif_orientation |
56 | {"0", "1"}, |
57 | {"90", "6"}, |
58 | {"180", "3"}, |
59 | {"270", "8"}, |
60 | }; |
61 | struct libjpeg_destination_mgr : jpeg_destination_mgr { |
62 | libjpeg_destination_mgr(uint8_t* input, int size); |
63 | |
64 | uint8_t* buf; |
65 | int bufsize; |
66 | size_t jpegsize; |
67 | }; |
68 | |
69 | static void libjpeg_init_destination (j_compress_ptr cinfo) { |
70 | libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest; |
71 | |
72 | dest->next_output_byte = dest->buf; |
73 | dest->free_in_buffer = dest->bufsize; |
74 | dest->jpegsize = 0; |
75 | } |
76 | |
77 | static boolean libjpeg_empty_output_buffer(j_compress_ptr cinfo) { |
78 | libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest; |
79 | |
80 | dest->next_output_byte = dest->buf; |
81 | dest->free_in_buffer = dest->bufsize; |
82 | return TRUE; // ? |
83 | } |
84 | |
85 | static void libjpeg_term_destination (j_compress_ptr cinfo) { |
86 | libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest; |
87 | dest->jpegsize = dest->bufsize - dest->free_in_buffer; |
88 | } |
89 | |
90 | libjpeg_destination_mgr::libjpeg_destination_mgr(uint8_t* input, int size) { |
91 | this->init_destination = libjpeg_init_destination; |
92 | this->empty_output_buffer = libjpeg_empty_output_buffer; |
93 | this->term_destination = libjpeg_term_destination; |
94 | |
95 | this->buf = input; |
96 | this->bufsize = size; |
97 | |
98 | jpegsize = 0; |
99 | } |
100 | |
101 | /* private static functions */ |
102 | static void nv21_to_yuv(uint8_t* dst, uint8_t* y, uint8_t* uv, int width) { |
103 | if (!dst || !y || !uv) { |
104 | return; |
105 | } |
106 | |
107 | while ((width--) > 0) { |
108 | uint8_t y0 = y[0]; |
109 | uint8_t v0 = uv[0]; |
110 | uint8_t u0 = *(uv+1); |
111 | dst[0] = y0; |
112 | dst[1] = u0; |
113 | dst[2] = v0; |
114 | dst += 3; |
115 | y++; |
116 | if(!(width % 2)) uv+=2; |
117 | } |
118 | } |
119 | |
120 | static void uyvy_to_yuv(uint8_t* dst, uint32_t* src, int width) { |
121 | if (!dst || !src) { |
122 | return; |
123 | } |
124 | |
125 | if (width % 2) { |
126 | return; // not supporting odd widths |
127 | } |
128 | |
129 | // currently, neon routine only supports multiple of 16 width |
130 | if (width % 16) { |
131 | while ((width-=2) >= 0) { |
132 | uint8_t u0 = (src[0] >> 0) & 0xFF; |
133 | uint8_t y0 = (src[0] >> 8) & 0xFF; |
134 | uint8_t v0 = (src[0] >> 16) & 0xFF; |
135 | uint8_t y1 = (src[0] >> 24) & 0xFF; |
136 | dst[0] = y0; |
137 | dst[1] = u0; |
138 | dst[2] = v0; |
139 | dst[3] = y1; |
140 | dst[4] = u0; |
141 | dst[5] = v0; |
142 | dst += 6; |
143 | src++; |
144 | } |
145 | } else { |
146 | int n = width; |
147 | asm volatile ( |
148 | " pld [%[src], %[src_stride], lsl #2] \n\t" |
149 | " cmp %[n], #16 \n\t" |
150 | " blt 5f \n\t" |
151 | "0: @ 16 pixel swap \n\t" |
152 | " vld2.8 {q0, q1} , [%[src]]! @ q0 = uv q1 = y \n\t" |
153 | " vuzp.8 q0, q2 @ d0 = u d4 = v \n\t" |
154 | " vmov d1, d0 @ q0 = u0u1u2..u0u1u2... \n\t" |
155 | " vmov d5, d4 @ q2 = v0v1v2..v0v1v2... \n\t" |
156 | " vzip.8 d0, d1 @ q0 = u0u0u1u1u2u2... \n\t" |
157 | " vzip.8 d4, d5 @ q2 = v0v0v1v1v2v2... \n\t" |
158 | " vswp q0, q1 @ now q0 = y q1 = u q2 = v \n\t" |
159 | " vst3.8 {d0,d2,d4},[%[dst]]! \n\t" |
160 | " vst3.8 {d1,d3,d5},[%[dst]]! \n\t" |
161 | " sub %[n], %[n], #16 \n\t" |
162 | " cmp %[n], #16 \n\t" |
163 | " bge 0b \n\t" |
164 | "5: @ end \n\t" |
165 | #ifdef NEEDS_ARM_ERRATA_754319_754320 |
166 | " vmov s0,s0 @ add noop for errata item \n\t" |
167 | #endif |
168 | : [dst] "+r" (dst), [src] "+r" (src), [n] "+r" (n) |
169 | : [src_stride] "r" (width) |
170 | : "cc", "memory", "q0", "q1", "q2" |
171 | ); |
172 | } |
173 | } |
174 | |
175 | static void yuyv_to_yuv(uint8_t* dst, uint32_t* src, int width) { |
176 | if (!dst || !src) { |
177 | return; |
178 | } |
179 | |
180 | if (width % 2) { |
181 | return; // not supporting odd widths |
182 | } |
183 | |
184 | // currently, neon routine only supports multiple of 16 width |
185 | if (width % 16) { |
186 | while ((width-=2) >= 0) { |
187 | uint8_t y0 = (src[0] >> 0) & 0xFF; |
188 | uint8_t u0 = (src[0] >> 8) & 0xFF; |
189 | uint8_t y1 = (src[0] >> 16) & 0xFF; |
190 | uint8_t v0 = (src[0] >> 24) & 0xFF; |
191 | dst[0] = y0; |
192 | dst[1] = u0; |
193 | dst[2] = v0; |
194 | dst[3] = y1; |
195 | dst[4] = u0; |
196 | dst[5] = v0; |
197 | dst += 6; |
198 | src++; |
199 | } |
200 | } else { |
201 | int n = width; |
202 | asm volatile ( |
203 | " pld [%[src], %[src_stride], lsl #2] \n\t" |
204 | " cmp %[n], #16 \n\t" |
205 | " blt 5f \n\t" |
206 | "0: @ 16 pixel swap \n\t" |
207 | " vld2.8 {q0, q1} , [%[src]]! @ q0 = y q1 = uv \n\t" |
208 | " vuzp.8 q1, q2 @ d2 = u d4 = v \n\t" |
209 | " vmov d3, d2 @ q1 = u0u1u2..u0u1u2... \n\t" |
210 | " vmov d5, d4 @ q2 = v0v1v2..v0v1v2... \n\t" |
211 | " vzip.8 d2, d3 @ q1 = u0u0u1u1u2u2... \n\t" |
212 | " vzip.8 d4, d5 @ q2 = v0v0v1v1v2v2... \n\t" |
213 | " vst3.8 {d0,d2,d4},[%[dst]]! \n\t" |
214 | " vst3.8 {d1,d3,d5},[%[dst]]! \n\t" |
215 | " sub %[n], %[n], #16 \n\t" |
216 | " cmp %[n], #16 \n\t" |
217 | " bge 0b \n\t" |
218 | "5: @ end \n\t" |
219 | #ifdef NEEDS_ARM_ERRATA_754319_754320 |
220 | " vmov s0,s0 @ add noop for errata item \n\t" |
221 | #endif |
222 | : [dst] "+r" (dst), [src] "+r" (src), [n] "+r" (n) |
223 | : [src_stride] "r" (width) |
224 | : "cc", "memory", "q0", "q1", "q2" |
225 | ); |
226 | } |
227 | } |
228 | |
229 | int extraSmallImg(unsigned char* SrcImg,int SrcW,int SrcH, |
230 | unsigned char* DstImg,int DstW,int DstH) |
231 | { |
232 | int skipW = SrcW/DstW; |
233 | int skipH = SrcH/DstH; |
234 | |
235 | unsigned char* dst = DstImg; |
236 | unsigned char* srcrow = SrcImg; |
237 | unsigned char* srcrowidx = srcrow; |
238 | |
239 | int i = 0,j = 0; |
240 | for(;i<DstH;i++) |
241 | { |
242 | //LOGD("srcrow = %d,dst = %d",srcrow-SrcImg,dst-DstImg); |
243 | for(j = 0;j<DstW;j++) |
244 | { |
245 | dst[0] = srcrowidx[0]; |
246 | dst[1] = srcrowidx[1]; |
247 | dst[2] = srcrowidx[2]; |
248 | dst+=3; |
249 | srcrowidx+=3*skipW; |
250 | } |
251 | // LOGD("srcrowidx end = %d",srcrowidx-SrcImg); |
252 | |
253 | srcrow += skipH*SrcW*3; |
254 | srcrowidx = srcrow; |
255 | } |
256 | |
257 | return 1; |
258 | } |
259 | |
260 | static void resize_nv12(Encoder_libjpeg::params* params, uint8_t* dst_buffer) { |
261 | structConvImage o_img_ptr, i_img_ptr; |
262 | |
263 | if (!params || !dst_buffer) { |
264 | return; |
265 | } |
266 | |
267 | //input |
268 | i_img_ptr.uWidth = params->in_width; |
269 | i_img_ptr.uStride = i_img_ptr.uWidth; |
270 | i_img_ptr.uHeight = params->in_height; |
271 | i_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp; |
272 | i_img_ptr.imgPtr = (uint8_t*) params->src; |
273 | i_img_ptr.clrPtr = i_img_ptr.imgPtr + (i_img_ptr.uWidth * i_img_ptr.uHeight); |
274 | |
275 | //ouput |
276 | o_img_ptr.uWidth = params->out_width; |
277 | o_img_ptr.uStride = o_img_ptr.uWidth; |
278 | o_img_ptr.uHeight = params->out_height; |
279 | o_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp; |
280 | o_img_ptr.imgPtr = dst_buffer; |
281 | o_img_ptr.clrPtr = o_img_ptr.imgPtr + (o_img_ptr.uWidth * o_img_ptr.uHeight); |
282 | |
283 | VT_resizeFrame_Video_opt2_lp(&i_img_ptr, &o_img_ptr, NULL, 0); |
284 | } |
285 | |
286 | /* public static functions */ |
287 | const char* ExifElementsTable::degreesToExifOrientation(const char* degrees) { |
288 | for (unsigned int i = 0; i < ARRAY_SIZE(degress_to_exif_lut); i++) { |
289 | if (!strcmp(degrees, degress_to_exif_lut[i].string1)) { |
290 | return degress_to_exif_lut[i].string2; |
291 | } |
292 | } |
293 | return NULL; |
294 | } |
295 | |
296 | void ExifElementsTable::stringToRational(const char* str, unsigned int* num, unsigned int* den) { |
297 | int len; |
298 | char * tempVal = NULL; |
299 | |
300 | if (str != NULL) { |
301 | len = strlen(str); |
302 | tempVal = (char*) malloc( sizeof(char) * (len + 1)); |
303 | } |
304 | |
305 | if (tempVal != NULL) { |
306 | // convert the decimal string into a rational |
307 | size_t den_len; |
308 | char *ctx; |
309 | unsigned int numerator = 0; |
310 | unsigned int denominator = 0; |
311 | char* temp = NULL; |
312 | |
313 | memset(tempVal, '\0', len + 1); |
314 | strncpy(tempVal, str, len); |
315 | temp = strtok_r(tempVal, ".", &ctx); |
316 | |
317 | if (temp != NULL) |
318 | numerator = atoi(temp); |
319 | |
320 | if (!numerator) |
321 | numerator = 1; |
322 | |
323 | temp = strtok_r(NULL, ".", &ctx); |
324 | if (temp != NULL) { |
325 | den_len = strlen(temp); |
326 | if(HUGE_VAL == den_len ) { |
327 | den_len = 0; |
328 | } |
329 | |
330 | denominator = static_cast<unsigned int>(pow(10, den_len)); |
331 | numerator = numerator * denominator + atoi(temp); |
332 | } else { |
333 | denominator = 1; |
334 | } |
335 | |
336 | free(tempVal); |
337 | |
338 | *num = numerator; |
339 | *den = denominator; |
340 | } |
341 | } |
342 | |
343 | bool ExifElementsTable::isAsciiTag(const char* tag) { |
344 | // TODO(XXX): Add tags as necessary |
345 | return (strcmp(tag, TAG_GPS_PROCESSING_METHOD) == 0); |
346 | } |
347 | |
348 | void ExifElementsTable::insertExifToJpeg(unsigned char* jpeg, size_t jpeg_size) { |
349 | ReadMode_t read_mode = (ReadMode_t)(READ_METADATA | READ_IMAGE); |
350 | |
351 | ResetJpgfile(); |
352 | if (ReadJpegSectionsFromBuffer(jpeg, jpeg_size, read_mode)) { |
353 | jpeg_opened = true; |
354 | create_EXIF(table, exif_tag_count, gps_tag_count,true); |
355 | } |
356 | } |
357 | |
358 | status_t ExifElementsTable::insertExifThumbnailImage(const char* thumb, int len) { |
359 | status_t ret = NO_ERROR; |
360 | |
361 | if ((len > 0) && jpeg_opened) { |
362 | ret = ReplaceThumbnailFromBuffer(thumb, len); |
363 | CAMHAL_LOGDB("insertExifThumbnailImage. ReplaceThumbnail(). ret=%d", ret); |
364 | } |
365 | |
366 | return ret; |
367 | } |
368 | |
369 | void ExifElementsTable::saveJpeg(unsigned char* jpeg, size_t jpeg_size) { |
370 | if (jpeg_opened) { |
371 | WriteJpegToBuffer(jpeg, jpeg_size); |
372 | DiscardData(); |
373 | jpeg_opened = false; |
374 | } |
375 | } |
376 | |
377 | /* public functions */ |
378 | ExifElementsTable::~ExifElementsTable() { |
379 | int num_elements = gps_tag_count + exif_tag_count; |
380 | |
381 | for (int i = 0; i < num_elements; i++) { |
382 | if (table[i].Value) { |
383 | free(table[i].Value); |
384 | } |
385 | } |
386 | |
387 | if (jpeg_opened) { |
388 | DiscardData(); |
389 | } |
390 | } |
391 | |
392 | status_t ExifElementsTable::insertElement(const char* tag, const char* value) { |
393 | int value_length = 0; |
394 | status_t ret = NO_ERROR; |
395 | |
396 | if (!value || !tag) { |
397 | return -EINVAL; |
398 | } |
399 | |
400 | if (position >= MAX_EXIF_TAGS_SUPPORTED) { |
401 | CAMHAL_LOGEA("Max number of EXIF elements already inserted"); |
402 | return NO_MEMORY; |
403 | } |
404 | |
405 | if (isAsciiTag(tag)) { |
406 | value_length = sizeof(ExifAsciiPrefix) + strlen(value + sizeof(ExifAsciiPrefix)); |
407 | } else { |
408 | value_length = strlen(value); |
409 | } |
410 | |
411 | if (IsGpsTag(tag)) { |
412 | table[position].GpsTag = TRUE; |
413 | table[position].Tag = GpsTagNameToValue(tag); |
414 | gps_tag_count++; |
415 | } else { |
416 | table[position].GpsTag = FALSE; |
417 | table[position].Tag = TagNameToValue(tag); |
418 | exif_tag_count++; |
419 | } |
420 | |
421 | table[position].DataLength = 0; |
422 | table[position].Value = (char*) malloc(sizeof(char) * (value_length + 1)); |
423 | |
424 | if (table[position].Value) { |
425 | memcpy(table[position].Value, value, value_length + 1); |
426 | table[position].DataLength = value_length + 1; |
427 | } |
428 | |
429 | position++; |
430 | return ret; |
431 | } |
432 | |
433 | /* private member functions */ |
434 | size_t Encoder_libjpeg::encode(params* input) { |
435 | jpeg_compress_struct cinfo; |
436 | jpeg_error_mgr jerr; |
437 | jpeg_destination_mgr jdest; |
438 | uint8_t* src = NULL, *resize_src = NULL; |
439 | uint8_t* row_tmp = NULL; |
440 | uint8_t* row_src = NULL; |
441 | uint8_t* row_uv = NULL; // used only for NV12 |
442 | int row_stride; |
443 | int out_width = 0, in_width = 0; |
444 | int out_height = 0, in_height = 0; |
445 | int bpp = 2; // for uyvy |
446 | |
447 | Encoder_libjpeg::format informat = Encoder_libjpeg::YUV422I; |
448 | |
449 | if (!input) { |
450 | return 0; |
451 | } |
452 | |
453 | out_width = input->out_width; |
454 | in_width = input->in_width; |
455 | out_height = input->out_height; |
456 | in_height = input->in_height; |
457 | src = input->src; |
458 | input->jpeg_size = 0; |
459 | libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size); |
460 | |
461 | #ifdef AMLOGIC_HW_JPEGENC |
462 | if((out_width == in_width)&&(out_height == in_height) |
463 | &&(out_height%16 == 0)&&(out_width%16 == 0)){ |
464 | goto HW_CASE; |
465 | } |
466 | SOFTWARE_ENC: |
467 | #endif |
468 | |
469 | // param check... |
470 | if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) || |
471 | (src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) || |
472 | (input->dst_size < 1) || (input->format == NULL)) { |
473 | goto exit; |
474 | } |
475 | |
476 | if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { |
477 | informat = Encoder_libjpeg::YUV420SP; |
478 | bpp = 1; |
479 | if ((in_width != out_width) || (in_height != out_height)) { |
480 | resize_src = (uint8_t*) malloc(input->dst_size); |
481 | resize_nv12(input, resize_src); |
482 | if (resize_src) src = resize_src; |
483 | } |
484 | } else if (strcmp(input->format, CameraProperties::PIXEL_FORMAT_RGB24) == 0) { |
485 | informat = Encoder_libjpeg::RGB24; |
486 | bpp = 1; |
487 | if ((in_width != out_width) || (in_height != out_height)) { |
488 | resize_src = (uint8_t*) malloc(input->dst_size); |
489 | if(NULL != resize_src){ |
490 | extraSmallImg(input->src, in_width, in_height, |
491 | resize_src, out_width, out_height); |
492 | src = resize_src; |
493 | }else{ |
494 | CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n"); |
495 | goto exit; |
496 | } |
497 | } |
498 | } else if ((in_width != out_width) || (in_height != out_height)) { |
499 | CAMHAL_LOGEB("Encoder: resizing is not supported for this format: %s", input->format); |
500 | goto exit; |
501 | } else if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV422I)) { |
502 | // we currently only support yuv422i and yuv420sp |
503 | CAMHAL_LOGEB("Encoder: format not supported: %s", input->format); |
504 | goto exit; |
505 | } |
506 | |
507 | cinfo.err = jpeg_std_error(&jerr); |
508 | |
509 | jpeg_create_compress(&cinfo); |
510 | |
511 | CAMHAL_LOGDB("software encoding... \n\t" |
512 | "width: %d \n\t" |
513 | "height:%d \n\t" |
514 | "dest %p \n\t" |
515 | "dest size:%d \n\t" |
516 | "mSrc %p", |
517 | out_width, out_height, input->dst, |
518 | input->dst_size, src); |
519 | |
520 | cinfo.dest = &dest_mgr; |
521 | cinfo.image_width = out_width; |
522 | cinfo.image_height = out_height; |
523 | cinfo.input_components = 3; |
524 | if (informat == Encoder_libjpeg::RGB24) |
525 | cinfo.in_color_space = JCS_RGB; |
526 | else |
527 | cinfo.in_color_space = JCS_YCbCr; |
528 | cinfo.input_gamma = 1; |
529 | |
530 | jpeg_set_defaults(&cinfo); |
531 | jpeg_set_quality(&cinfo, input->quality, TRUE); |
532 | cinfo.dct_method = JDCT_IFAST; |
533 | |
534 | jpeg_start_compress(&cinfo, TRUE); |
535 | |
536 | row_tmp = (uint8_t*)malloc(out_width * 3); |
537 | row_src = src; |
538 | row_uv = src + out_width * out_height * bpp; |
539 | row_stride = out_width * 3; |
540 | |
541 | while ((cinfo.next_scanline < cinfo.image_height) && !mCancelEncoding) { |
542 | JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */ |
543 | |
544 | if (informat == Encoder_libjpeg::RGB24) { |
545 | row[0] = &src[cinfo.next_scanline * row_stride]; |
546 | (void) jpeg_write_scanlines(&cinfo, row, 1); |
547 | } else { |
548 | // convert input yuv format to yuv444 |
549 | if (informat == Encoder_libjpeg::YUV420SP) { |
550 | nv21_to_yuv(row_tmp, row_src, row_uv, out_width); |
551 | } else if (informat == Encoder_libjpeg::YUV422I) { |
552 | //uyvy_to_yuv(row_tmp, (uint32_t*)row_src, out_width); |
553 | yuyv_to_yuv(row_tmp, (uint32_t*)row_src, out_width); |
554 | } |
555 | |
556 | row[0] = row_tmp; |
557 | jpeg_write_scanlines(&cinfo, row, 1); |
558 | row_src = row_src + out_width*bpp; |
559 | |
560 | // move uv row if input format needs it |
561 | if (informat == Encoder_libjpeg::YUV420SP) { |
562 | if (!(cinfo.next_scanline % 2)) |
563 | row_uv = row_uv + out_width * bpp; |
564 | } |
565 | } |
566 | } |
567 | |
568 | // no need to finish encoding routine if we are prematurely stopping |
569 | // we will end up crashing in dest_mgr since data is incomplete |
570 | if (!mCancelEncoding) |
571 | jpeg_finish_compress(&cinfo); |
572 | jpeg_destroy_compress(&cinfo); |
573 | |
574 | if (resize_src) free(resize_src); |
575 | if (row_tmp) free(row_tmp); |
576 | |
577 | exit: |
578 | input->jpeg_size = dest_mgr.jpegsize; |
579 | return dest_mgr.jpegsize; |
580 | |
581 | #ifdef AMLOGIC_HW_JPEGENC |
582 | HW_CASE: |
583 | size_t jpeg_size = 0; |
584 | memset(&hw_info,0, sizeof(hw_info)); |
585 | if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { |
586 | hw_info.in_format = FMT_NV21; |
587 | } else if (strcmp(input->format, CameraProperties::PIXEL_FORMAT_RGB24) == 0) { |
588 | hw_info.in_format = FMT_RGB888; |
589 | } else if(strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV422I)== 0){ |
590 | hw_info.in_format = FMT_YUV422_SINGLE; |
591 | } else{ |
592 | hw_info.in_format = FMT_NV21; |
593 | } |
594 | hw_info.fd = -1; |
595 | hw_info.width = out_width; |
596 | hw_info.height = out_height; |
597 | hw_info.src = input->src; |
598 | hw_info.src_size= input->src_size; |
599 | hw_info.dst= input->dst; |
600 | hw_info.dst_size= input->dst_size; |
601 | hw_info.quality = input->quality; |
602 | |
603 | CAMHAL_LOGDB("hardware encoding... \n\t" |
604 | "width: %d \n\t" |
605 | "height:%d \n\t" |
606 | "dest %p \n\t" |
607 | "dest size:%d \n\t" |
608 | "mSrc %p", |
609 | out_width, out_height, input->dst, |
610 | input->dst_size, input->src); |
611 | jpeg_size = hw_encode(&hw_info); |
612 | if(jpeg_size<=0){ |
613 | CAMHAL_LOGEA("HW Encode fail, re-encode with software."); |
614 | goto SOFTWARE_ENC; |
615 | } |
616 | input->jpeg_size = jpeg_size; |
617 | return jpeg_size; |
618 | #endif |
619 | } |
620 | |
621 | } // namespace android |
622 |