1 /* 2 * Copyright (C) Texas Instruments - http://www.ti.com/ 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" 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 #define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0])) 47 48 namespace android { 49 struct string_pair { 50 const char* string1; 51 const char* string2; 52 }; 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 @ d1 = u d5 = 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 resize_nv12(Encoder_libjpeg::params* params, uint8_t* dst_buffer) { 176 structConvImage o_img_ptr, i_img_ptr; 177 178 if (!params || !dst_buffer) { 179 return; 180 } 181 182 //input 183 i_img_ptr.uWidth = params->in_width; 184 i_img_ptr.uStride = i_img_ptr.uWidth; 185 i_img_ptr.uHeight = params->in_height; 186 i_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp; 187 i_img_ptr.imgPtr = (uint8_t*) params->src; 188 i_img_ptr.clrPtr = i_img_ptr.imgPtr + (i_img_ptr.uWidth * i_img_ptr.uHeight); 189 190 //ouput 191 o_img_ptr.uWidth = params->out_width; 192 o_img_ptr.uStride = o_img_ptr.uWidth; 193 o_img_ptr.uHeight = params->out_height; 194 o_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp; 195 o_img_ptr.imgPtr = dst_buffer; 196 o_img_ptr.clrPtr = o_img_ptr.imgPtr + (o_img_ptr.uWidth * o_img_ptr.uHeight); 197 198 VT_resizeFrame_Video_opt2_lp(&i_img_ptr, &o_img_ptr, NULL, 0); 199 } 200 201 /* public static functions */ 202 const char* ExifElementsTable::degreesToExifOrientation(const char* degrees) { 203 for (unsigned int i = 0; i < ARRAY_SIZE(degress_to_exif_lut); i++) { 204 if (!strcmp(degrees, degress_to_exif_lut[i].string1)) { 205 return degress_to_exif_lut[i].string2; 206 } 207 } 208 return NULL; 209 } 210 211 void ExifElementsTable::stringToRational(const char* str, unsigned int* num, unsigned int* den) { 212 int len; 213 char * tempVal = NULL; 214 215 if (str != NULL) { 216 len = strlen(str); 217 tempVal = (char*) malloc( sizeof(char) * (len + 1)); 218 } 219 220 if (tempVal != NULL) { 221 // convert the decimal string into a rational 222 size_t den_len; 223 char *ctx; 224 unsigned int numerator = 0; 225 unsigned int denominator = 0; 226 char* temp = NULL; 227 228 memset(tempVal, '\0', len + 1); 229 strncpy(tempVal, str, len); 230 temp = strtok_r(tempVal, ".", &ctx); 231 232 if (temp != NULL) 233 numerator = atoi(temp); 234 235 if (!numerator) 236 numerator = 1; 237 238 temp = strtok_r(NULL, ".", &ctx); 239 if (temp != NULL) { 240 den_len = strlen(temp); 241 if(HUGE_VAL == den_len ) { 242 den_len = 0; 243 } 244 245 denominator = static_cast<unsigned int>(pow(10, den_len)); 246 numerator = numerator * denominator + atoi(temp); 247 } else { 248 denominator = 1; 249 } 250 251 free(tempVal); 252 253 *num = numerator; 254 *den = denominator; 255 } 256 } 257 258 bool ExifElementsTable::isAsciiTag(const char* tag) { 259 // TODO(XXX): Add tags as necessary 260 return (strcmp(tag, TAG_GPS_PROCESSING_METHOD) == 0); 261 } 262 263 void ExifElementsTable::insertExifToJpeg(unsigned char* jpeg, size_t jpeg_size) { 264 ReadMode_t read_mode = (ReadMode_t)(READ_METADATA | READ_IMAGE); 265 266 ResetJpgfile(); 267 if (ReadJpegSectionsFromBuffer(jpeg, jpeg_size, read_mode)) { 268 jpeg_opened = true; 269 create_EXIF(table, exif_tag_count, gps_tag_count); 270 } 271 } 272 273 status_t ExifElementsTable::insertExifThumbnailImage(const char* thumb, int len) { 274 status_t ret = NO_ERROR; 275 276 if ((len > 0) && jpeg_opened) { 277 ret = ReplaceThumbnailFromBuffer(thumb, len); 278 CAMHAL_LOGDB("insertExifThumbnailImage. ReplaceThumbnail(). ret=%d", ret); 279 } 280 281 return ret; 282 } 283 284 void ExifElementsTable::saveJpeg(unsigned char* jpeg, size_t jpeg_size) { 285 if (jpeg_opened) { 286 WriteJpegToBuffer(jpeg, jpeg_size); 287 DiscardData(); 288 jpeg_opened = false; 289 } 290 } 291 292 /* public functions */ 293 ExifElementsTable::~ExifElementsTable() { 294 int num_elements = gps_tag_count + exif_tag_count; 295 296 for (int i = 0; i < num_elements; i++) { 297 if (table[i].Value) { 298 free(table[i].Value); 299 } 300 } 301 302 if (jpeg_opened) { 303 DiscardData(); 304 } 305 } 306 307 status_t ExifElementsTable::insertElement(const char* tag, const char* value) { 308 int value_length = 0; 309 status_t ret = NO_ERROR; 310 311 if (!value || !tag) { 312 return -EINVAL; 313 } 314 315 if (position >= MAX_EXIF_TAGS_SUPPORTED) { 316 CAMHAL_LOGEA("Max number of EXIF elements already inserted"); 317 return NO_MEMORY; 318 } 319 320 if (isAsciiTag(tag)) { 321 value_length = sizeof(ExifAsciiPrefix) + strlen(value + sizeof(ExifAsciiPrefix)); 322 } else { 323 value_length = strlen(value); 324 } 325 326 if (IsGpsTag(tag)) { 327 table[position].GpsTag = TRUE; 328 table[position].Tag = GpsTagNameToValue(tag); 329 gps_tag_count++; 330 } else { 331 table[position].GpsTag = FALSE; 332 table[position].Tag = TagNameToValue(tag); 333 exif_tag_count++; 334 } 335 336 table[position].DataLength = 0; 337 table[position].Value = (char*) malloc(sizeof(char) * (value_length + 1)); 338 339 if (table[position].Value) { 340 memcpy(table[position].Value, value, value_length + 1); 341 table[position].DataLength = value_length + 1; 342 } 343 344 position++; 345 return ret; 346 } 347 348 /* private member functions */ 349 size_t Encoder_libjpeg::encode(params* input) { 350 jpeg_compress_struct cinfo; 351 jpeg_error_mgr jerr; 352 jpeg_destination_mgr jdest; 353 uint8_t* src = NULL, *resize_src = NULL; 354 uint8_t* row_tmp = NULL; 355 uint8_t* row_src = NULL; 356 uint8_t* row_uv = NULL; // used only for NV12 357 int out_width = 0, in_width = 0; 358 int out_height = 0, in_height = 0; 359 int bpp = 2; // for uyvy 360 int right_crop = 0, start_offset = 0; 361 362 if (!input) { 363 return 0; 364 } 365 366 out_width = input->out_width; 367 in_width = input->in_width; 368 out_height = input->out_height; 369 in_height = input->in_height; 370 right_crop = input->right_crop; 371 start_offset = input->start_offset; 372 src = input->src; 373 input->jpeg_size = 0; 374 375 libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size); 376 377 // param check... 378 if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) || 379 (src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) || 380 (input->dst_size < 1) || (input->format == NULL)) { 381 goto exit; 382 } 383 384 if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { 385 bpp = 1; 386 if ((in_width != out_width) || (in_height != out_height)) { 387 resize_src = (uint8_t*) malloc(input->dst_size); 388 resize_nv12(input, resize_src); 389 if (resize_src) src = resize_src; 390 } 391 } else if ((in_width != out_width) || (in_height != out_height)) { 392 CAMHAL_LOGEB("Encoder: resizing is not supported for this format: %s", input->format); 393 goto exit; 394 } else if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV422I)) { 395 // we currently only support yuv422i and yuv420sp 396 CAMHAL_LOGEB("Encoder: format not supported: %s", input->format); 397 goto exit; 398 } 399 400 cinfo.err = jpeg_std_error(&jerr); 401 402 jpeg_create_compress(&cinfo); 403 404 CAMHAL_LOGDB("encoding... \n\t" 405 "width: %d \n\t" 406 "height:%d \n\t" 407 "dest %p \n\t" 408 "dest size:%d \n\t" 409 "mSrc %p", 410 out_width, out_height, input->dst, 411 input->dst_size, src); 412 413 cinfo.dest = &dest_mgr; 414 cinfo.image_width = out_width - right_crop; 415 cinfo.image_height = out_height; 416 cinfo.input_components = 3; 417 cinfo.in_color_space = JCS_YCbCr; 418 cinfo.input_gamma = 1; 419 420 jpeg_set_defaults(&cinfo); 421 jpeg_set_quality(&cinfo, input->quality, TRUE); 422 cinfo.dct_method = JDCT_IFAST; 423 424 jpeg_start_compress(&cinfo, TRUE); 425 426 row_tmp = (uint8_t*)malloc(out_width * 3); 427 row_src = src + start_offset; 428 row_uv = src + out_width * out_height * bpp; 429 430 while ((cinfo.next_scanline < cinfo.image_height) && !mCancelEncoding) { 431 JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */ 432 433 // convert input yuv format to yuv444 434 if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { 435 nv21_to_yuv(row_tmp, row_src, row_uv, out_width - right_crop); 436 } else { 437 uyvy_to_yuv(row_tmp, (uint32_t*)row_src, out_width - right_crop); 438 } 439 440 row[0] = row_tmp; 441 jpeg_write_scanlines(&cinfo, row, 1); 442 row_src = row_src + out_width*bpp; 443 444 // move uv row if input format needs it 445 if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { 446 if (!(cinfo.next_scanline % 2)) 447 row_uv = row_uv + out_width * bpp; 448 } 449 } 450 451 // no need to finish encoding routine if we are prematurely stopping 452 // we will end up crashing in dest_mgr since data is incomplete 453 if (!mCancelEncoding) 454 jpeg_finish_compress(&cinfo); 455 jpeg_destroy_compress(&cinfo); 456 457 if (resize_src) free(resize_src); 458 if (row_tmp) free(row_tmp); 459 460 exit: 461 input->jpeg_size = dest_mgr.jpegsize; 462 return dest_mgr.jpegsize; 463 } 464 465 } // namespace android 466