Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 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" |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 30 | #include "NV12_resize.h" |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 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> |
Tyler Luu | c11c07d | 2011-10-12 17:39:00 -0500 | [diff] [blame] | 39 | #include <math.h> |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 40 | |
| 41 | extern "C" { |
| 42 | #include "jpeglib.h" |
| 43 | #include "jerror.h" |
| 44 | } |
| 45 | |
Tyler Luu | 36e9bdd | 2011-09-07 22:19:09 -0500 | [diff] [blame] | 46 | #define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0])) |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 47 | |
Tyler Luu | 36e9bdd | 2011-09-07 22:19:09 -0500 | [diff] [blame] | 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 | }; |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 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; |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 97 | |
| 98 | jpegsize = 0; |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | /* private static functions */ |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 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 | } |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 119 | |
| 120 | static void uyvy_to_yuv(uint8_t* dst, uint32_t* src, int width) { |
Tyler Luu | 76f0345 | 2011-09-14 11:56:52 -0500 | [diff] [blame] | 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 | ); |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 172 | } |
| 173 | } |
| 174 | |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 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 | |
Tyler Luu | 36e9bdd | 2011-09-07 22:19:09 -0500 | [diff] [blame] | 201 | /* public static functions */ |
| 202 | const char* ExifElementsTable::degreesToExifOrientation(const char* degrees) { |
Tyler Luu | 76f0345 | 2011-09-14 11:56:52 -0500 | [diff] [blame] | 203 | for (unsigned int i = 0; i < ARRAY_SIZE(degress_to_exif_lut); i++) { |
Tyler Luu | 36e9bdd | 2011-09-07 22:19:09 -0500 | [diff] [blame] | 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 | |
Tyler Luu | c11c07d | 2011-10-12 17:39:00 -0500 | [diff] [blame] | 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 | |
Tyler Luu | 36e9bdd | 2011-09-07 22:19:09 -0500 | [diff] [blame] | 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 | |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 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 | |
Tyler Luu | 36e9bdd | 2011-09-07 22:19:09 -0500 | [diff] [blame] | 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 | |
Tyler Luu | c11c07d | 2011-10-12 17:39:00 -0500 | [diff] [blame] | 320 | if (isAsciiTag(tag)) { |
| 321 | value_length = sizeof(ExifAsciiPrefix) + strlen(value + sizeof(ExifAsciiPrefix)); |
| 322 | } else { |
| 323 | value_length = strlen(value); |
| 324 | } |
Tyler Luu | 36e9bdd | 2011-09-07 22:19:09 -0500 | [diff] [blame] | 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) { |
Tyler Luu | c11c07d | 2011-10-12 17:39:00 -0500 | [diff] [blame] | 340 | memcpy(table[position].Value, value, value_length + 1); |
Tyler Luu | 36e9bdd | 2011-09-07 22:19:09 -0500 | [diff] [blame] | 341 | table[position].DataLength = value_length + 1; |
| 342 | } |
| 343 | |
| 344 | position++; |
| 345 | return ret; |
| 346 | } |
| 347 | |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 348 | /* private member functions */ |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 349 | size_t Encoder_libjpeg::encode(params* input) { |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 350 | jpeg_compress_struct cinfo; |
| 351 | jpeg_error_mgr jerr; |
| 352 | jpeg_destination_mgr jdest; |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 353 | uint8_t* src = NULL, *resize_src = NULL; |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 354 | uint8_t* row_tmp = NULL; |
| 355 | uint8_t* row_src = NULL; |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 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 | |
| 361 | if (!input) { |
| 362 | return 0; |
| 363 | } |
| 364 | |
| 365 | out_width = input->out_width; |
| 366 | in_width = input->in_width; |
| 367 | out_height = input->out_height; |
| 368 | in_height = input->in_height; |
| 369 | src = input->src; |
| 370 | input->jpeg_size = 0; |
| 371 | |
| 372 | libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size); |
| 373 | |
| 374 | // param check... |
| 375 | if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) || |
| 376 | (src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) || |
| 377 | (input->dst_size < 1) || (input->format == NULL)) { |
| 378 | goto exit; |
| 379 | } |
| 380 | |
| 381 | if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { |
| 382 | bpp = 1; |
| 383 | if ((in_width != out_width) || (in_height != out_height)) { |
| 384 | resize_src = (uint8_t*) malloc(input->dst_size); |
| 385 | resize_nv12(input, resize_src); |
| 386 | if (resize_src) src = resize_src; |
| 387 | } |
| 388 | } else if ((in_width != out_width) || (in_height != out_height)) { |
| 389 | CAMHAL_LOGEB("Encoder: resizing is not supported for this format: %s", input->format); |
| 390 | goto exit; |
| 391 | } else if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV422I)) { |
| 392 | // we currently only support yuv422i and yuv420sp |
| 393 | CAMHAL_LOGEB("Encoder: format not supported: %s", input->format); |
| 394 | goto exit; |
| 395 | } |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 396 | |
| 397 | cinfo.err = jpeg_std_error(&jerr); |
| 398 | |
| 399 | jpeg_create_compress(&cinfo); |
| 400 | |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 401 | CAMHAL_LOGDB("encoding... \n\t" |
| 402 | "width: %d \n\t" |
| 403 | "height:%d \n\t" |
| 404 | "dest %p \n\t" |
| 405 | "dest size:%d \n\t" |
| 406 | "mSrc %p", |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 407 | out_width, out_height, input->dst, |
| 408 | input->dst_size, src); |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 409 | |
| 410 | cinfo.dest = &dest_mgr; |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 411 | cinfo.image_width = out_width; |
| 412 | cinfo.image_height = out_height; |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 413 | cinfo.input_components = 3; |
| 414 | cinfo.in_color_space = JCS_YCbCr; |
| 415 | cinfo.input_gamma = 1; |
| 416 | |
| 417 | jpeg_set_defaults(&cinfo); |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 418 | jpeg_set_quality(&cinfo, input->quality, TRUE); |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 419 | cinfo.dct_method = JDCT_IFAST; |
| 420 | |
| 421 | jpeg_start_compress(&cinfo, TRUE); |
| 422 | |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 423 | row_tmp = (uint8_t*)malloc(out_width * 3); |
| 424 | row_src = src; |
| 425 | row_uv = src + out_width * out_height * bpp; |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 426 | |
Tyler Luu | 8e52e3b | 2011-10-07 11:57:42 -0500 | [diff] [blame] | 427 | while ((cinfo.next_scanline < cinfo.image_height) && !mCancelEncoding) { |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 428 | JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */ |
| 429 | |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 430 | // convert input yuv format to yuv444 |
| 431 | if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { |
| 432 | nv21_to_yuv(row_tmp, row_src, row_uv, out_width); |
| 433 | } else { |
| 434 | uyvy_to_yuv(row_tmp, (uint32_t*)row_src, out_width); |
| 435 | } |
| 436 | |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 437 | row[0] = row_tmp; |
| 438 | jpeg_write_scanlines(&cinfo, row, 1); |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 439 | row_src = row_src + out_width*bpp; |
| 440 | |
| 441 | // move uv row if input format needs it |
| 442 | if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { |
| 443 | if (!(cinfo.next_scanline % 2)) |
| 444 | row_uv = row_uv + out_width * bpp; |
| 445 | } |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 446 | } |
| 447 | |
Tyler Luu | 8e52e3b | 2011-10-07 11:57:42 -0500 | [diff] [blame] | 448 | // no need to finish encoding routine if we are prematurely stopping |
| 449 | // we will end up crashing in dest_mgr since data is incomplete |
| 450 | if (!mCancelEncoding) |
| 451 | jpeg_finish_compress(&cinfo); |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 452 | jpeg_destroy_compress(&cinfo); |
| 453 | |
Tyler Luu | c160a1f | 2011-10-04 22:27:50 +0530 | [diff] [blame] | 454 | if (resize_src) free(resize_src); |
| 455 | |
| 456 | exit: |
| 457 | input->jpeg_size = dest_mgr.jpegsize; |
Tyler Luu | ee6bb64 | 2011-08-31 21:12:17 -0500 | [diff] [blame] | 458 | return dest_mgr.jpegsize; |
| 459 | } |
| 460 | |
| 461 | } // namespace android |