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 #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 
    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     }
    396 
    397     cinfo.err = jpeg_std_error(&jerr);
    398 
    399     jpeg_create_compress(&cinfo);
    400 
    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",
    407                  out_width, out_height, input->dst,
    408                  input->dst_size, src);
    409 
    410     cinfo.dest = &dest_mgr;
    411     cinfo.image_width = out_width;
    412     cinfo.image_height = out_height;
    413     cinfo.input_components = 3;
    414     cinfo.in_color_space = JCS_YCbCr;
    415     cinfo.input_gamma = 1;
    416 
    417     jpeg_set_defaults(&cinfo);
    418     jpeg_set_quality(&cinfo, input->quality, TRUE);
    419     cinfo.dct_method = JDCT_IFAST;
    420 
    421     jpeg_start_compress(&cinfo, TRUE);
    422 
    423     row_tmp = (uint8_t*)malloc(out_width * 3);
    424     row_src = src;
    425     row_uv = src + out_width * out_height * bpp;
    426 
    427     while ((cinfo.next_scanline < cinfo.image_height) && !mCancelEncoding) {
    428         JSAMPROW row[1];    /* pointer to JSAMPLE row[s] */
    429 
    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 
    437         row[0] = row_tmp;
    438         jpeg_write_scanlines(&cinfo, row, 1);
    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         }
    446     }
    447 
    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);
    452     jpeg_destroy_compress(&cinfo);
    453 
    454     if (resize_src) free(resize_src);
    455 
    456  exit:
    457     input->jpeg_size = dest_mgr.jpegsize;
    458     return dest_mgr.jpegsize;
    459 }
    460 
    461 } // namespace android
    462