1 /* 2 * Copyright (C) 2012 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 //#define LOG_NDEBUG 0 18 #define LOG_TAG "Camera2-JpegCompressor" 19 20 #include <utils/Log.h> 21 #include <ui/GraphicBufferMapper.h> 22 23 #include "JpegCompressor.h" 24 25 namespace android { 26 namespace camera2 { 27 28 JpegCompressor::JpegCompressor(): 29 Thread(false), 30 mIsBusy(false), 31 mCaptureTime(0) { 32 } 33 34 JpegCompressor::~JpegCompressor() { 35 ALOGV("%s", __FUNCTION__); 36 Mutex::Autolock lock(mMutex); 37 } 38 39 status_t JpegCompressor::start(Vector<CpuConsumer::LockedBuffer*> buffers, 40 nsecs_t captureTime) { 41 ALOGV("%s", __FUNCTION__); 42 Mutex::Autolock busyLock(mBusyMutex); 43 44 if (mIsBusy) { 45 ALOGE("%s: Already processing a buffer!", __FUNCTION__); 46 return INVALID_OPERATION; 47 } 48 49 mIsBusy = true; 50 51 mBuffers = buffers; 52 mCaptureTime = captureTime; 53 54 status_t res; 55 res = run("JpegCompressor"); 56 if (res != OK) { 57 ALOGE("%s: Unable to start up compression thread: %s (%d)", 58 __FUNCTION__, strerror(-res), res); 59 //delete mBuffers; // necessary? 60 } 61 return res; 62 } 63 64 status_t JpegCompressor::cancel() { 65 ALOGV("%s", __FUNCTION__); 66 requestExitAndWait(); 67 return OK; 68 } 69 70 status_t JpegCompressor::readyToRun() { 71 ALOGV("%s", __FUNCTION__); 72 return OK; 73 } 74 75 bool JpegCompressor::threadLoop() { 76 ALOGV("%s", __FUNCTION__); 77 78 mAuxBuffer = mBuffers[0]; // input 79 mJpegBuffer = mBuffers[1]; // output 80 81 // Set up error management 82 mJpegErrorInfo = NULL; 83 JpegError error; 84 error.parent = this; 85 86 mCInfo.err = jpeg_std_error(&error); 87 mCInfo.err->error_exit = jpegErrorHandler; 88 89 jpeg_create_compress(&mCInfo); 90 if (checkError("Error initializing compression")) return false; 91 92 // Route compressed data straight to output stream buffer 93 JpegDestination jpegDestMgr; 94 jpegDestMgr.parent = this; 95 jpegDestMgr.init_destination = jpegInitDestination; 96 jpegDestMgr.empty_output_buffer = jpegEmptyOutputBuffer; 97 jpegDestMgr.term_destination = jpegTermDestination; 98 99 mCInfo.dest = &jpegDestMgr; 100 101 // Set up compression parameters 102 mCInfo.image_width = mAuxBuffer->width; 103 mCInfo.image_height = mAuxBuffer->height; 104 mCInfo.input_components = 1; // 3; 105 mCInfo.in_color_space = JCS_GRAYSCALE; // JCS_RGB 106 107 ALOGV("%s: image_width = %d, image_height = %d", __FUNCTION__, mCInfo.image_width, mCInfo.image_height); 108 109 jpeg_set_defaults(&mCInfo); 110 if (checkError("Error configuring defaults")) return false; 111 112 // Do compression 113 jpeg_start_compress(&mCInfo, TRUE); 114 if (checkError("Error starting compression")) return false; 115 116 size_t rowStride = mAuxBuffer->stride;// * 3; 117 const size_t kChunkSize = 32; 118 while (mCInfo.next_scanline < mCInfo.image_height) { 119 JSAMPROW chunk[kChunkSize]; 120 for (size_t i = 0 ; i < kChunkSize; i++) { 121 chunk[i] = (JSAMPROW) 122 (mAuxBuffer->data + (i + mCInfo.next_scanline) * rowStride); 123 } 124 jpeg_write_scanlines(&mCInfo, chunk, kChunkSize); 125 if (checkError("Error while compressing")) return false; 126 if (exitPending()) { 127 ALOGV("%s: Cancel called, exiting early", __FUNCTION__); 128 cleanUp(); 129 return false; 130 } 131 } 132 133 jpeg_finish_compress(&mCInfo); 134 if (checkError("Error while finishing compression")) return false; 135 136 cleanUp(); 137 return false; 138 } 139 140 bool JpegCompressor::isBusy() { 141 ALOGV("%s", __FUNCTION__); 142 Mutex::Autolock busyLock(mBusyMutex); 143 return mIsBusy; 144 } 145 146 // old function -- TODO: update for new buffer type 147 bool JpegCompressor::isStreamInUse(uint32_t /*id*/) { 148 ALOGV("%s", __FUNCTION__); 149 Mutex::Autolock lock(mBusyMutex); 150 151 if (mBuffers.size() && mIsBusy) { 152 for (size_t i = 0; i < mBuffers.size(); i++) { 153 // if ( mBuffers[i].streamId == (int)id ) return true; 154 } 155 } 156 return false; 157 } 158 159 bool JpegCompressor::waitForDone(nsecs_t timeout) { 160 ALOGV("%s", __FUNCTION__); 161 Mutex::Autolock lock(mBusyMutex); 162 status_t res = OK; 163 if (mIsBusy) { 164 res = mDone.waitRelative(mBusyMutex, timeout); 165 } 166 return (res == OK); 167 } 168 169 bool JpegCompressor::checkError(const char *msg) { 170 ALOGV("%s", __FUNCTION__); 171 if (mJpegErrorInfo) { 172 char errBuffer[JMSG_LENGTH_MAX]; 173 mJpegErrorInfo->err->format_message(mJpegErrorInfo, errBuffer); 174 ALOGE("%s: %s: %s", 175 __FUNCTION__, msg, errBuffer); 176 cleanUp(); 177 mJpegErrorInfo = NULL; 178 return true; 179 } 180 return false; 181 } 182 183 void JpegCompressor::cleanUp() { 184 ALOGV("%s", __FUNCTION__); 185 jpeg_destroy_compress(&mCInfo); 186 Mutex::Autolock lock(mBusyMutex); 187 mIsBusy = false; 188 mDone.signal(); 189 } 190 191 void JpegCompressor::jpegErrorHandler(j_common_ptr cinfo) { 192 ALOGV("%s", __FUNCTION__); 193 JpegError *error = static_cast<JpegError*>(cinfo->err); 194 error->parent->mJpegErrorInfo = cinfo; 195 } 196 197 void JpegCompressor::jpegInitDestination(j_compress_ptr cinfo) { 198 ALOGV("%s", __FUNCTION__); 199 JpegDestination *dest= static_cast<JpegDestination*>(cinfo->dest); 200 ALOGV("%s: Setting destination to %p, size %d", 201 __FUNCTION__, dest->parent->mJpegBuffer->data, kMaxJpegSize); 202 dest->next_output_byte = (JOCTET*)(dest->parent->mJpegBuffer->data); 203 dest->free_in_buffer = kMaxJpegSize; 204 } 205 206 boolean JpegCompressor::jpegEmptyOutputBuffer(j_compress_ptr /*cinfo*/) { 207 ALOGV("%s", __FUNCTION__); 208 ALOGE("%s: JPEG destination buffer overflow!", 209 __FUNCTION__); 210 return true; 211 } 212 213 void JpegCompressor::jpegTermDestination(j_compress_ptr cinfo) { 214 (void) cinfo; // TODO: clean up 215 ALOGV("%s", __FUNCTION__); 216 ALOGV("%s: Done writing JPEG data. %d bytes left in buffer", 217 __FUNCTION__, cinfo->dest->free_in_buffer); 218 } 219 220 }; // namespace camera2 221 }; // namespace android 222