Encoder_libjpeg.cpp revision 36e9bdd56757ff8048e08f6e52f234480c44f122
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 31#include <stdlib.h> 32#include <unistd.h> 33#include <sys/types.h> 34#include <sys/stat.h> 35#include <fcntl.h> 36#include <stdio.h> 37#include <errno.h> 38 39extern "C" { 40 #include "jpeglib.h" 41 #include "jerror.h" 42} 43 44#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0])) 45 46namespace android { 47struct string_pair { 48 const char* string1; 49 const char* string2; 50}; 51 52static string_pair degress_to_exif_lut [] = { 53 // degrees, exif_orientation 54 {"0", "1"}, 55 {"90", "6"}, 56 {"180", "3"}, 57 {"270", "8"}, 58}; 59struct libjpeg_destination_mgr : jpeg_destination_mgr { 60 libjpeg_destination_mgr(uint8_t* input, int size); 61 62 uint8_t* buf; 63 int bufsize; 64 size_t jpegsize; 65}; 66 67static void libjpeg_init_destination (j_compress_ptr cinfo) { 68 libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest; 69 70 dest->next_output_byte = dest->buf; 71 dest->free_in_buffer = dest->bufsize; 72 dest->jpegsize = 0; 73} 74 75static boolean libjpeg_empty_output_buffer(j_compress_ptr cinfo) { 76 libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest; 77 78 dest->next_output_byte = dest->buf; 79 dest->free_in_buffer = dest->bufsize; 80 return TRUE; // ? 81} 82 83static void libjpeg_term_destination (j_compress_ptr cinfo) { 84 libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest; 85 dest->jpegsize = dest->bufsize - dest->free_in_buffer; 86} 87 88libjpeg_destination_mgr::libjpeg_destination_mgr(uint8_t* input, int size) { 89 this->init_destination = libjpeg_init_destination; 90 this->empty_output_buffer = libjpeg_empty_output_buffer; 91 this->term_destination = libjpeg_term_destination; 92 93 this->buf = input; 94 this->bufsize = size; 95} 96 97/* private static functions */ 98 99static void uyvy_to_yuv(uint8_t* dst, uint32_t* src, int width) { 100 // TODO(XXX): optimize later 101 while ((width-=2) >= 0) { 102 uint8_t u0 = (src[0] >> 0) & 0xFF; 103 uint8_t y0 = (src[0] >> 8) & 0xFF; 104 uint8_t v0 = (src[0] >> 16) & 0xFF; 105 uint8_t y1 = (src[0] >> 24) & 0xFF; 106 dst[0] = y0; 107 dst[1] = u0; 108 dst[2] = v0; 109 dst[3] = y1; 110 dst[4] = u0; 111 dst[5] = v0; 112 dst += 6; 113 src++; 114 } 115} 116 117/* public static functions */ 118const char* ExifElementsTable::degreesToExifOrientation(const char* degrees) { 119 for (int i = 0; i < ARRAY_SIZE(degress_to_exif_lut); i++) { 120 if (!strcmp(degrees, degress_to_exif_lut[i].string1)) { 121 return degress_to_exif_lut[i].string2; 122 } 123 } 124 return NULL; 125} 126 127void ExifElementsTable::insertExifToJpeg(unsigned char* jpeg, size_t jpeg_size) { 128 ReadMode_t read_mode = (ReadMode_t)(READ_METADATA | READ_IMAGE); 129 130 ResetJpgfile(); 131 if (ReadJpegSectionsFromBuffer(jpeg, jpeg_size, read_mode)) { 132 jpeg_opened = true; 133 create_EXIF(table, exif_tag_count, gps_tag_count); 134 } 135} 136 137void ExifElementsTable::saveJpeg(unsigned char* jpeg, size_t jpeg_size) { 138 if (jpeg_opened) { 139 WriteJpegToBuffer(jpeg, jpeg_size); 140 DiscardData(); 141 jpeg_opened = false; 142 } 143} 144 145/* public functions */ 146ExifElementsTable::~ExifElementsTable() { 147 int num_elements = gps_tag_count + exif_tag_count; 148 149 for (int i = 0; i < num_elements; i++) { 150 if (table[i].Value) { 151 free(table[i].Value); 152 } 153 } 154 155 if (jpeg_opened) { 156 DiscardData(); 157 } 158} 159 160status_t ExifElementsTable::insertElement(const char* tag, const char* value) { 161 int value_length = 0; 162 status_t ret = NO_ERROR; 163 164 if (!value || !tag) { 165 return -EINVAL; 166 } 167 168 if (position >= MAX_EXIF_TAGS_SUPPORTED) { 169 CAMHAL_LOGEA("Max number of EXIF elements already inserted"); 170 return NO_MEMORY; 171 } 172 173 value_length = strlen(value); 174 175 if (IsGpsTag(tag)) { 176 table[position].GpsTag = TRUE; 177 table[position].Tag = GpsTagNameToValue(tag); 178 gps_tag_count++; 179 } else { 180 table[position].GpsTag = FALSE; 181 table[position].Tag = TagNameToValue(tag); 182 exif_tag_count++; 183 } 184 185 table[position].DataLength = 0; 186 table[position].Value = (char*) malloc(sizeof(char) * (value_length + 1)); 187 188 if (table[position].Value) { 189 strncpy(table[position].Value, value, value_length); 190 table[position].DataLength = value_length + 1; 191 } 192 193 position++; 194 return ret; 195} 196 197/* private member functions */ 198size_t Encoder_libjpeg::encode() { 199 jpeg_compress_struct cinfo; 200 jpeg_error_mgr jerr; 201 jpeg_destination_mgr jdest; 202 uint8_t* row_tmp = NULL; 203 uint8_t* row_src = NULL; 204 int bpp = 2; // TODO(XXX): hardcoded for uyvy 205 206 cinfo.err = jpeg_std_error(&jerr); 207 208 jpeg_create_compress(&cinfo); 209 210 libjpeg_destination_mgr dest_mgr(mDest, mDestSize); 211 212 CAMHAL_LOGDB("encoding... \n\t" 213 "width: %d \n\t" 214 "height:%d \n\t" 215 "dest %p \n\t" 216 "dest size:%d \n\t" 217 "mSrc %p", 218 mWidth, mHeight, mDest, mDestSize, mSrc); 219 220 cinfo.dest = &dest_mgr; 221 cinfo.image_width = mWidth; 222 cinfo.image_height = mHeight; 223 cinfo.input_components = 3; 224 cinfo.in_color_space = JCS_YCbCr; 225 cinfo.input_gamma = 1; 226 227 jpeg_set_defaults(&cinfo); 228 jpeg_set_quality(&cinfo, mQuality, TRUE); 229 cinfo.dct_method = JDCT_IFAST; 230 231 jpeg_start_compress(&cinfo, TRUE); 232 233 row_tmp = (uint8_t*)malloc(mWidth * 3); 234 row_src = mSrc; 235 236 while (cinfo.next_scanline < cinfo.image_height) { 237 JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */ 238 239 uyvy_to_yuv(row_tmp, (uint32_t*)row_src, mWidth); 240 row[0] = row_tmp; 241 jpeg_write_scanlines(&cinfo, row, 1); 242 row_src = row_src + mWidth*bpp; 243 } 244 245 jpeg_finish_compress(&cinfo); 246 jpeg_destroy_compress(&cinfo); 247 248 return dest_mgr.jpegsize; 249} 250 251} // namespace android 252