1 /* 2 * Copyright (C) 2016 The Android Open Source Project 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 #include "Compressor.h" 18 19 #define LOG_NDEBUG 0 20 #define LOG_TAG "EmulatedCamera_JPEGStub_Compressor" 21 #include <cutils/log.h> 22 #include <libexif/exif-data.h> 23 24 Compressor::Compressor() { 25 26 } 27 28 bool Compressor::compress(const unsigned char* data, 29 int width, int height, int quality, 30 ExifData* exifData) { 31 if (!configureCompressor(width, height, quality)) { 32 // The method will have logged a more detailed error message than we can 33 // provide here so just return. 34 return false; 35 } 36 37 return compressData(data, exifData); 38 } 39 40 const std::vector<uint8_t>& Compressor::getCompressedData() const { 41 return mDestManager.mBuffer; 42 } 43 44 bool Compressor::configureCompressor(int width, int height, int quality) { 45 mCompressInfo.err = jpeg_std_error(&mErrorManager); 46 // NOTE! DANGER! Do not construct any non-trivial objects below setjmp! 47 // The compiler will not generate code to destroy them during the return 48 // below so they will leak. Additionally, do not place any calls to libjpeg 49 // that can fail above this line or any error will cause undefined behavior. 50 if (setjmp(mErrorManager.mJumpBuffer)) { 51 // This is where the error handler will jump in case setup fails 52 // The error manager will ALOG an appropriate error message 53 return false; 54 } 55 56 jpeg_create_compress(&mCompressInfo); 57 58 mCompressInfo.image_width = width; 59 mCompressInfo.image_height = height; 60 mCompressInfo.input_components = 3; 61 mCompressInfo.in_color_space = JCS_YCbCr; 62 jpeg_set_defaults(&mCompressInfo); 63 64 jpeg_set_quality(&mCompressInfo, quality, TRUE); 65 // It may seem weird to set color space here again but this will also set 66 // other fields. These fields might be overwritten by jpeg_set_defaults 67 jpeg_set_colorspace(&mCompressInfo, JCS_YCbCr); 68 mCompressInfo.raw_data_in = TRUE; 69 mCompressInfo.dct_method = JDCT_IFAST; 70 // Set sampling factors 71 mCompressInfo.comp_info[0].h_samp_factor = 2; 72 mCompressInfo.comp_info[0].v_samp_factor = 2; 73 mCompressInfo.comp_info[1].h_samp_factor = 1; 74 mCompressInfo.comp_info[1].v_samp_factor = 1; 75 mCompressInfo.comp_info[2].h_samp_factor = 1; 76 mCompressInfo.comp_info[2].v_samp_factor = 1; 77 78 mCompressInfo.dest = &mDestManager; 79 80 return true; 81 } 82 83 static void deinterleave(const uint8_t* vuPlanar, std::vector<uint8_t>& uRows, 84 std::vector<uint8_t>& vRows, int rowIndex, int width, 85 int height, int stride) { 86 int numRows = (height - rowIndex) / 2; 87 if (numRows > 8) numRows = 8; 88 for (int row = 0; row < numRows; ++row) { 89 int offset = ((rowIndex >> 1) + row) * stride; 90 const uint8_t* vu = vuPlanar + offset; 91 for (int i = 0; i < (width >> 1); ++i) { 92 int index = row * (width >> 1) + i; 93 uRows[index] = vu[1]; 94 vRows[index] = vu[0]; 95 vu += 2; 96 } 97 } 98 } 99 100 101 bool Compressor::compressData(const unsigned char* data, ExifData* exifData) { 102 const uint8_t* y[16]; 103 const uint8_t* cb[8]; 104 const uint8_t* cr[8]; 105 const uint8_t** planes[3] = { y, cb, cr }; 106 107 int i, offset; 108 int width = mCompressInfo.image_width; 109 int height = mCompressInfo.image_height; 110 const uint8_t* yPlanar = data; 111 const uint8_t* vuPlanar = data + (width * height); 112 std::vector<uint8_t> uRows(8 * (width >> 1)); 113 std::vector<uint8_t> vRows(8 * (width >> 1)); 114 115 // NOTE! DANGER! Do not construct any non-trivial objects below setjmp! 116 // The compiler will not generate code to destroy them during the return 117 // below so they will leak. Additionally, do not place any calls to libjpeg 118 // that can fail above this line or any error will cause undefined behavior. 119 if (setjmp(mErrorManager.mJumpBuffer)) { 120 // This is where the error handler will jump in case compression fails 121 // The error manager will ALOG an appropriate error message 122 return false; 123 } 124 125 jpeg_start_compress(&mCompressInfo, TRUE); 126 127 attachExifData(exifData); 128 129 // process 16 lines of Y and 8 lines of U/V each time. 130 while (mCompressInfo.next_scanline < mCompressInfo.image_height) { 131 //deinterleave u and v 132 deinterleave(vuPlanar, uRows, vRows, mCompressInfo.next_scanline, 133 width, height, width); 134 135 // Jpeg library ignores the rows whose indices are greater than height. 136 for (i = 0; i < 16; i++) { 137 // y row 138 y[i] = yPlanar + (mCompressInfo.next_scanline + i) * width; 139 140 // construct u row and v row 141 if ((i & 1) == 0) { 142 // height and width are both halved because of downsampling 143 offset = (i >> 1) * (width >> 1); 144 cb[i/2] = &uRows[offset]; 145 cr[i/2] = &vRows[offset]; 146 } 147 } 148 jpeg_write_raw_data(&mCompressInfo, const_cast<JSAMPIMAGE>(planes), 16); 149 } 150 151 jpeg_finish_compress(&mCompressInfo); 152 jpeg_destroy_compress(&mCompressInfo); 153 154 return true; 155 } 156 157 bool Compressor::attachExifData(ExifData* exifData) { 158 if (exifData == nullptr) { 159 // This is not an error, we don't require EXIF data 160 return true; 161 } 162 163 // Save the EXIF data to memory 164 unsigned char* rawData = nullptr; 165 unsigned int size = 0; 166 exif_data_save_data(exifData, &rawData, &size); 167 if (rawData == nullptr) { 168 ALOGE("Failed to create EXIF data block"); 169 return false; 170 } 171 172 jpeg_write_marker(&mCompressInfo, JPEG_APP0 + 1, rawData, size); 173 free(rawData); 174 return true; 175 } 176 177 Compressor::ErrorManager::ErrorManager() { 178 error_exit = &onJpegError; 179 } 180 181 void Compressor::ErrorManager::onJpegError(j_common_ptr cinfo) { 182 // NOTE! Do not construct any non-trivial objects in this method at the top 183 // scope. Their destructors will not be called. If you do need such an 184 // object create a local scope that does not include the longjmp call, 185 // that ensures the object is destroyed before longjmp is called. 186 ErrorManager* errorManager = reinterpret_cast<ErrorManager*>(cinfo->err); 187 188 // Format and log error message 189 char errorMessage[JMSG_LENGTH_MAX]; 190 (*errorManager->format_message)(cinfo, errorMessage); 191 errorMessage[sizeof(errorMessage) - 1] = '\0'; 192 ALOGE("JPEG compression error: %s", errorMessage); 193 jpeg_destroy(cinfo); 194 195 // And through the looking glass we go 196 longjmp(errorManager->mJumpBuffer, 1); 197 } 198 199 Compressor::DestinationManager::DestinationManager() { 200 init_destination = &initDestination; 201 empty_output_buffer = &emptyOutputBuffer; 202 term_destination = &termDestination; 203 } 204 205 void Compressor::DestinationManager::initDestination(j_compress_ptr cinfo) { 206 auto manager = reinterpret_cast<DestinationManager*>(cinfo->dest); 207 208 // Start out with some arbitrary but not too large buffer size 209 manager->mBuffer.resize(16 * 1024); 210 manager->next_output_byte = &manager->mBuffer[0]; 211 manager->free_in_buffer = manager->mBuffer.size(); 212 } 213 214 boolean Compressor::DestinationManager::emptyOutputBuffer( 215 j_compress_ptr cinfo) { 216 auto manager = reinterpret_cast<DestinationManager*>(cinfo->dest); 217 218 // Keep doubling the size of the buffer for a very low, amortized 219 // performance cost of the allocations 220 size_t oldSize = manager->mBuffer.size(); 221 manager->mBuffer.resize(oldSize * 2); 222 manager->next_output_byte = &manager->mBuffer[oldSize]; 223 manager->free_in_buffer = manager->mBuffer.size() - oldSize; 224 return manager->free_in_buffer != 0; 225 } 226 227 void Compressor::DestinationManager::termDestination(j_compress_ptr cinfo) { 228 auto manager = reinterpret_cast<DestinationManager*>(cinfo->dest); 229 230 // Resize down to the exact size of the output, that is remove as many 231 // bytes as there are left in the buffer 232 manager->mBuffer.resize(manager->mBuffer.size() - manager->free_in_buffer); 233 } 234 235