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