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