Home | History | Annotate | Download | only in client2
      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(const 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 %zu",
    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. %zu bytes left in buffer",
    217             __FUNCTION__, cinfo->dest->free_in_buffer);
    218 }
    219 
    220 }; // namespace camera2
    221 }; // namespace android
    222