X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fandroid%2Fcamera%2Ffake-pipeline2%2FJpegCompressor.cpp;fp=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fandroid%2Fcamera%2Ffake-pipeline2%2FJpegCompressor.cpp;h=d0dce269cd14dff6cb1d8a99d3710db896be0ba9;hb=e26c1ec581be598521517829adba8c8dd23a768f;hp=0000000000000000000000000000000000000000;hpb=6699c1aea74eeb0eb400e6299079f0c7576f716f;p=iec.git diff --git a/src/type3_AndroidCloud/anbox-master/android/camera/fake-pipeline2/JpegCompressor.cpp b/src/type3_AndroidCloud/anbox-master/android/camera/fake-pipeline2/JpegCompressor.cpp new file mode 100644 index 0000000..d0dce26 --- /dev/null +++ b/src/type3_AndroidCloud/anbox-master/android/camera/fake-pipeline2/JpegCompressor.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "EmulatedCamera2_JpegCompressor" + +#include +#include + +#include "JpegCompressor.h" +#include "../EmulatedFakeCamera2.h" +#include "../EmulatedFakeCamera3.h" + +namespace android { + +JpegCompressor::JpegCompressor(): + Thread(false), + mIsBusy(false), + mSynchronous(false), + mBuffers(NULL), + mListener(NULL) { +} + +JpegCompressor::~JpegCompressor() { + Mutex::Autolock lock(mMutex); +} + +status_t JpegCompressor::start(Buffers *buffers, JpegListener *listener) { + if (listener == NULL) { + ALOGE("%s: NULL listener not allowed!", __FUNCTION__); + return BAD_VALUE; + } + Mutex::Autolock lock(mMutex); + { + Mutex::Autolock busyLock(mBusyMutex); + + if (mIsBusy) { + ALOGE("%s: Already processing a buffer!", __FUNCTION__); + return INVALID_OPERATION; + } + + mIsBusy = true; + mSynchronous = false; + mBuffers = buffers; + mListener = listener; + } + + status_t res; + res = run("EmulatedFakeCamera2::JpegCompressor"); + if (res != OK) { + ALOGE("%s: Unable to start up compression thread: %s (%d)", + __FUNCTION__, strerror(-res), res); + delete mBuffers; + } + return res; +} + +status_t JpegCompressor::compressSynchronous(Buffers *buffers) { + status_t res; + + Mutex::Autolock lock(mMutex); + { + Mutex::Autolock busyLock(mBusyMutex); + + if (mIsBusy) { + ALOGE("%s: Already processing a buffer!", __FUNCTION__); + return INVALID_OPERATION; + } + + mIsBusy = true; + mSynchronous = true; + mBuffers = buffers; + } + + res = compress(); + + cleanUp(); + + return res; +} + +status_t JpegCompressor::cancel() { + requestExitAndWait(); + return OK; +} + +status_t JpegCompressor::readyToRun() { + return OK; +} + +bool JpegCompressor::threadLoop() { + status_t res; + ALOGV("%s: Starting compression thread", __FUNCTION__); + + res = compress(); + + mListener->onJpegDone(mJpegBuffer, res == OK); + + cleanUp(); + + return false; +} + +status_t JpegCompressor::compress() { + // Find source and target buffers. Assumes only one buffer matches + // each condition! + + bool foundJpeg = false, mFoundAux = false; + for (size_t i = 0; i < mBuffers->size(); i++) { + const StreamBuffer &b = (*mBuffers)[i]; + if (b.format == HAL_PIXEL_FORMAT_BLOB) { + mJpegBuffer = b; + mFoundJpeg = true; + } else if (b.streamId <= 0) { + mAuxBuffer = b; + mFoundAux = true; + } + if (mFoundJpeg && mFoundAux) break; + } + if (!mFoundJpeg || !mFoundAux) { + ALOGE("%s: Unable to find buffers for JPEG source/destination", + __FUNCTION__); + return BAD_VALUE; + } + + // Set up error management + + mJpegErrorInfo = NULL; + JpegError error; + error.parent = this; + + mCInfo.err = jpeg_std_error(&error); + mCInfo.err->error_exit = jpegErrorHandler; + + jpeg_create_compress(&mCInfo); + if (checkError("Error initializing compression")) return NO_INIT; + + // Route compressed data straight to output stream buffer + + JpegDestination jpegDestMgr; + jpegDestMgr.parent = this; + jpegDestMgr.init_destination = jpegInitDestination; + jpegDestMgr.empty_output_buffer = jpegEmptyOutputBuffer; + jpegDestMgr.term_destination = jpegTermDestination; + + mCInfo.dest = &jpegDestMgr; + + // Set up compression parameters + + mCInfo.image_width = mAuxBuffer.width; + mCInfo.image_height = mAuxBuffer.height; + mCInfo.input_components = 3; + mCInfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&mCInfo); + if (checkError("Error configuring defaults")) return NO_INIT; + + // Do compression + + jpeg_start_compress(&mCInfo, TRUE); + if (checkError("Error starting compression")) return NO_INIT; + + size_t rowStride = mAuxBuffer.stride * 3; + const size_t kChunkSize = 32; + while (mCInfo.next_scanline < mCInfo.image_height) { + JSAMPROW chunk[kChunkSize]; + for (size_t i = 0 ; i < kChunkSize; i++) { + chunk[i] = (JSAMPROW) + (mAuxBuffer.img + (i + mCInfo.next_scanline) * rowStride); + } + jpeg_write_scanlines(&mCInfo, chunk, kChunkSize); + if (checkError("Error while compressing")) return NO_INIT; + if (exitPending()) { + ALOGV("%s: Cancel called, exiting early", __FUNCTION__); + return TIMED_OUT; + } + } + + jpeg_finish_compress(&mCInfo); + if (checkError("Error while finishing compression")) return NO_INIT; + + // All done + + return OK; +} + +bool JpegCompressor::isBusy() { + Mutex::Autolock busyLock(mBusyMutex); + return mIsBusy; +} + +bool JpegCompressor::isStreamInUse(uint32_t id) { + Mutex::Autolock lock(mBusyMutex); + + if (mBuffers && mIsBusy) { + for (size_t i = 0; i < mBuffers->size(); i++) { + if ( (*mBuffers)[i].streamId == (int)id ) return true; + } + } + return false; +} + +bool JpegCompressor::waitForDone(nsecs_t timeout) { + Mutex::Autolock lock(mBusyMutex); + status_t res = OK; + if (mIsBusy) { + res = mDone.waitRelative(mBusyMutex, timeout); + } + return (res == OK); +} + +bool JpegCompressor::checkError(const char *msg) { + if (mJpegErrorInfo) { + char errBuffer[JMSG_LENGTH_MAX]; + mJpegErrorInfo->err->format_message(mJpegErrorInfo, errBuffer); + ALOGE("%s: %s: %s", + __FUNCTION__, msg, errBuffer); + mJpegErrorInfo = NULL; + return true; + } + return false; +} + +void JpegCompressor::cleanUp() { + status_t res; + jpeg_destroy_compress(&mCInfo); + Mutex::Autolock lock(mBusyMutex); + + if (mFoundAux) { + if (mAuxBuffer.streamId == 0) { + delete[] mAuxBuffer.img; + } else if (!mSynchronous) { + mListener->onJpegInputDone(mAuxBuffer); + } + } + if (!mSynchronous) { + delete mBuffers; + } + + mBuffers = NULL; + + mIsBusy = false; + mDone.signal(); +} + +void JpegCompressor::jpegErrorHandler(j_common_ptr cinfo) { + JpegError *error = static_cast(cinfo->err); + error->parent->mJpegErrorInfo = cinfo; +} + +void JpegCompressor::jpegInitDestination(j_compress_ptr cinfo) { + JpegDestination *dest= static_cast(cinfo->dest); + ALOGV("%s: Setting destination to %p, size %zu", + __FUNCTION__, dest->parent->mJpegBuffer.img, kMaxJpegSize); + dest->next_output_byte = (JOCTET*)(dest->parent->mJpegBuffer.img); + dest->free_in_buffer = kMaxJpegSize; +} + +boolean JpegCompressor::jpegEmptyOutputBuffer(j_compress_ptr cinfo) { + ALOGE("%s: JPEG destination buffer overflow!", + __FUNCTION__); + return true; +} + +void JpegCompressor::jpegTermDestination(j_compress_ptr cinfo) { + ALOGV("%s: Done writing JPEG data. %zu bytes left in buffer", + __FUNCTION__, cinfo->dest->free_in_buffer); +} + +JpegCompressor::JpegListener::~JpegListener() { +} + +} // namespace android