Home | History | Annotate | Download | only in fake-pipeline2
      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 "EmulatedCamera2_JpegCompressor"
     19 
     20 #include <utils/Log.h>
     21 
     22 #include "JpegCompressor.h"
     23 #include "../EmulatedFakeCamera2.h"
     24 #include "../EmulatedFakeCamera3.h"
     25 
     26 namespace android {
     27 
     28 JpegCompressor::JpegCompressor():
     29         Thread(false),
     30         mIsBusy(false),
     31         mSynchronous(false),
     32         mBuffers(NULL),
     33         mListener(NULL) {
     34 }
     35 
     36 JpegCompressor::~JpegCompressor() {
     37     Mutex::Autolock lock(mMutex);
     38 }
     39 
     40 status_t JpegCompressor::reserve() {
     41     Mutex::Autolock busyLock(mBusyMutex);
     42     if (mIsBusy) {
     43         ALOGE("%s: Already processing a buffer!", __FUNCTION__);
     44         return INVALID_OPERATION;
     45     }
     46     mIsBusy = true;
     47     return OK;
     48 }
     49 
     50 status_t JpegCompressor::start(Buffers *buffers, JpegListener *listener) {
     51     if (listener == NULL) {
     52         ALOGE("%s: NULL listener not allowed!", __FUNCTION__);
     53         return BAD_VALUE;
     54     }
     55     Mutex::Autolock lock(mMutex);
     56     {
     57         Mutex::Autolock busyLock(mBusyMutex);
     58 
     59         if (!mIsBusy) {
     60             ALOGE("Called start without reserve() first!");
     61             return INVALID_OPERATION;
     62         }
     63         mSynchronous = false;
     64         mBuffers = buffers;
     65         mListener = listener;
     66     }
     67 
     68     status_t res;
     69     res = run("EmulatedFakeCamera2::JpegCompressor");
     70     if (res != OK) {
     71         ALOGE("%s: Unable to start up compression thread: %s (%d)",
     72                 __FUNCTION__, strerror(-res), res);
     73         delete mBuffers;
     74     }
     75     return res;
     76 }
     77 
     78 status_t JpegCompressor::compressSynchronous(Buffers *buffers) {
     79     status_t res;
     80 
     81     Mutex::Autolock lock(mMutex);
     82     {
     83         Mutex::Autolock busyLock(mBusyMutex);
     84 
     85         if (mIsBusy) {
     86             ALOGE("%s: Already processing a buffer!", __FUNCTION__);
     87             return INVALID_OPERATION;
     88         }
     89 
     90         mIsBusy = true;
     91         mSynchronous = true;
     92         mBuffers = buffers;
     93     }
     94 
     95     res = compress();
     96 
     97     cleanUp();
     98 
     99     return res;
    100 }
    101 
    102 status_t JpegCompressor::cancel() {
    103     requestExitAndWait();
    104     return OK;
    105 }
    106 
    107 status_t JpegCompressor::readyToRun() {
    108     return OK;
    109 }
    110 
    111 bool JpegCompressor::threadLoop() {
    112     status_t res;
    113     ALOGV("%s: Starting compression thread", __FUNCTION__);
    114 
    115     res = compress();
    116 
    117     mListener->onJpegDone(mJpegBuffer, res == OK);
    118 
    119     cleanUp();
    120 
    121     return false;
    122 }
    123 
    124 status_t JpegCompressor::compress() {
    125     // Find source and target buffers. Assumes only one buffer matches
    126     // each condition!
    127     bool foundJpeg = false, mFoundAux = false;
    128     for (size_t i = 0; i < mBuffers->size(); i++) {
    129         const StreamBuffer &b = (*mBuffers)[i];
    130         if (b.format == HAL_PIXEL_FORMAT_BLOB) {
    131             mJpegBuffer = b;
    132             mFoundJpeg = true;
    133         } else if (b.streamId <= 0) {
    134             mAuxBuffer = b;
    135             mFoundAux = true;
    136         }
    137         if (mFoundJpeg && mFoundAux) break;
    138     }
    139     if (!mFoundJpeg || !mFoundAux) {
    140         ALOGE("%s: Unable to find buffers for JPEG source/destination",
    141                 __FUNCTION__);
    142         return BAD_VALUE;
    143     }
    144 
    145     // Set up error management
    146 
    147     mJpegErrorInfo = NULL;
    148     JpegError error;
    149     error.parent = this;
    150 
    151     mCInfo.err = jpeg_std_error(&error);
    152     mCInfo.err->error_exit = jpegErrorHandler;
    153 
    154     jpeg_create_compress(&mCInfo);
    155     if (checkError("Error initializing compression")) return NO_INIT;
    156 
    157     // Route compressed data straight to output stream buffer
    158 
    159     JpegDestination jpegDestMgr;
    160     jpegDestMgr.parent = this;
    161     jpegDestMgr.init_destination = jpegInitDestination;
    162     jpegDestMgr.empty_output_buffer = jpegEmptyOutputBuffer;
    163     jpegDestMgr.term_destination = jpegTermDestination;
    164 
    165     mCInfo.dest = &jpegDestMgr;
    166 
    167     // Set up compression parameters
    168 
    169     mCInfo.image_width = mAuxBuffer.width;
    170     mCInfo.image_height = mAuxBuffer.height;
    171     mCInfo.input_components = 3;
    172     mCInfo.in_color_space = JCS_RGB;
    173 
    174     jpeg_set_defaults(&mCInfo);
    175     if (checkError("Error configuring defaults")) return NO_INIT;
    176 
    177     // Do compression
    178 
    179     jpeg_start_compress(&mCInfo, TRUE);
    180     if (checkError("Error starting compression")) return NO_INIT;
    181 
    182     size_t rowStride = mAuxBuffer.stride * 3;
    183     const size_t kChunkSize = 32;
    184     while (mCInfo.next_scanline < mCInfo.image_height) {
    185         JSAMPROW chunk[kChunkSize];
    186         for (size_t i = 0 ; i < kChunkSize; i++) {
    187             chunk[i] = (JSAMPROW)
    188                     (mAuxBuffer.img + (i + mCInfo.next_scanline) * rowStride);
    189         }
    190         jpeg_write_scanlines(&mCInfo, chunk, kChunkSize);
    191         if (checkError("Error while compressing")) return NO_INIT;
    192         if (exitPending()) {
    193             ALOGV("%s: Cancel called, exiting early", __FUNCTION__);
    194             return TIMED_OUT;
    195         }
    196     }
    197 
    198     jpeg_finish_compress(&mCInfo);
    199     if (checkError("Error while finishing compression")) return NO_INIT;
    200 
    201     // All done
    202 
    203     return OK;
    204 }
    205 
    206 bool JpegCompressor::isBusy() {
    207     Mutex::Autolock busyLock(mBusyMutex);
    208     return mIsBusy;
    209 }
    210 
    211 bool JpegCompressor::isStreamInUse(uint32_t id) {
    212     Mutex::Autolock lock(mBusyMutex);
    213 
    214     if (mBuffers && mIsBusy) {
    215         for (size_t i = 0; i < mBuffers->size(); i++) {
    216             if ( (*mBuffers)[i].streamId == (int)id ) return true;
    217         }
    218     }
    219     return false;
    220 }
    221 
    222 bool JpegCompressor::waitForDone(nsecs_t timeout) {
    223     Mutex::Autolock lock(mBusyMutex);
    224     while (mIsBusy) {
    225         status_t res = mDone.waitRelative(mBusyMutex, timeout);
    226         if (res != OK) return false;
    227     }
    228     return true;
    229 }
    230 
    231 bool JpegCompressor::checkError(const char *msg) {
    232     if (mJpegErrorInfo) {
    233         char errBuffer[JMSG_LENGTH_MAX];
    234         mJpegErrorInfo->err->format_message(mJpegErrorInfo, errBuffer);
    235         ALOGE("%s: %s: %s",
    236                 __FUNCTION__, msg, errBuffer);
    237         mJpegErrorInfo = NULL;
    238         return true;
    239     }
    240     return false;
    241 }
    242 
    243 void JpegCompressor::cleanUp() {
    244     status_t res;
    245     jpeg_destroy_compress(&mCInfo);
    246     Mutex::Autolock lock(mBusyMutex);
    247 
    248     if (mFoundAux) {
    249         if (mAuxBuffer.streamId == 0) {
    250             delete[] mAuxBuffer.img;
    251         } else if (!mSynchronous) {
    252             mListener->onJpegInputDone(mAuxBuffer);
    253         }
    254     }
    255     if (!mSynchronous) {
    256         delete mBuffers;
    257     }
    258 
    259     mBuffers = NULL;
    260 
    261     mIsBusy = false;
    262     mDone.signal();
    263 }
    264 
    265 void JpegCompressor::jpegErrorHandler(j_common_ptr cinfo) {
    266     JpegError *error = static_cast<JpegError*>(cinfo->err);
    267     error->parent->mJpegErrorInfo = cinfo;
    268 }
    269 
    270 void JpegCompressor::jpegInitDestination(j_compress_ptr cinfo) {
    271     JpegDestination *dest= static_cast<JpegDestination*>(cinfo->dest);
    272     ALOGV("%s: Setting destination to %p, size %zu",
    273             __FUNCTION__, dest->parent->mJpegBuffer.img, kMaxJpegSize);
    274     dest->next_output_byte = (JOCTET*)(dest->parent->mJpegBuffer.img);
    275     dest->free_in_buffer = kMaxJpegSize;
    276 }
    277 
    278 boolean JpegCompressor::jpegEmptyOutputBuffer(j_compress_ptr cinfo) {
    279     ALOGE("%s: JPEG destination buffer overflow!",
    280             __FUNCTION__);
    281     return true;
    282 }
    283 
    284 void JpegCompressor::jpegTermDestination(j_compress_ptr cinfo) {
    285     ALOGV("%s: Done writing JPEG data. %zu bytes left in buffer",
    286             __FUNCTION__, cinfo->dest->free_in_buffer);
    287 }
    288 
    289 JpegCompressor::JpegListener::~JpegListener() {
    290 }
    291 
    292 } // namespace android
    293