summaryrefslogtreecommitdiff
authorGuosong Zhou <guosong.zhou@amlogic.com>2015-02-27 08:31:44 (GMT)
committer Guosong Zhou <guosong.zhou@amlogic.com>2015-03-02 11:45:54 (GMT)
commit57e73e516c7bf40138c7e625e63e58b535c60332 (patch)
tree194ba9feeae6891afde1e4acb06b0bd90d7b36b6
parent913a86dc1a234ce60c87a2cd285f790de9e7aa3f (diff)
downloadcamera-57e73e516c7bf40138c7e625e63e58b535c60332.zip
camera-57e73e516c7bf40138c7e625e63e58b535c60332.tar.gz
camera-57e73e516c7bf40138c7e625e63e58b535c60332.tar.bz2
redesign jpeg encoding flow
Change-Id: I58977c84d5d1964f1e57aa342d23633b170b36ae Signed-off-by: Guosong Zhou <guosong.zhou@amlogic.com>
Diffstat
-rwxr-xr-xv3/EmulatedFakeCamera3.cpp227
-rwxr-xr-xv3/EmulatedFakeCamera3.h13
-rwxr-xr-xv3/fake-pipeline2/JpegCompressor.cpp1157
-rwxr-xr-xv3/fake-pipeline2/JpegCompressor.h59
-rwxr-xr-xv3/fake-pipeline2/Sensor.cpp31
5 files changed, 925 insertions, 562 deletions
diff --git a/v3/EmulatedFakeCamera3.cpp b/v3/EmulatedFakeCamera3.cpp
index 060f6f0..5617702 100755
--- a/v3/EmulatedFakeCamera3.cpp
+++ b/v3/EmulatedFakeCamera3.cpp
@@ -258,10 +258,19 @@ status_t EmulatedFakeCamera3::connectCamera(hw_device_t** device) {
if (mSupportCap & IOCTL_MASK_ROTATE) {
mSupportRotate = true;
}
-
+
mReadoutThread = new ReadoutThread(this);
mJpegCompressor = new JpegCompressor();
+ res = mReadoutThread->setJpegCompressorListener(this);
+ if (res != NO_ERROR) {
+ return res;
+ }
+ res = mReadoutThread->startJpegCompressor(this);
+ if (res != NO_ERROR) {
+ return res;
+ }
+
res = mReadoutThread->run("EmuCam3::readoutThread");
if (res != NO_ERROR) return res;
@@ -330,6 +339,12 @@ status_t EmulatedFakeCamera3::closeCamera() {
}
mSensor.clear();
+ res = mReadoutThread->shutdownJpegCompressor(this);
+ if (res != OK) {
+ ALOGE("%s: Unable to shut down JpegCompressor: %d", __FUNCTION__, res);
+ return res;
+ }
+
mReadoutThread->requestExit();
}
@@ -828,11 +843,11 @@ const camera_metadata_t* EmulatedFakeCamera3::constructDefaultRequestSettings(
settings.update(ANDROID_EDGE_STRENGTH, &edgeStrength, 1);
/** android.scaler */
- static const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
+ static const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
settings.update(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
-
+
static const int32_t cropRegion[] = {
- 0, 0, (int32_t)Sensor::kResolution[0], (int32_t)Sensor::kResolution[1],
+ 0, 0, (int32_t)Sensor::kResolution[0], (int32_t)Sensor::kResolution[1],
};
settings.update(ANDROID_SCALER_CROP_REGION, cropRegion, 4);
@@ -841,7 +856,7 @@ const camera_metadata_t* EmulatedFakeCamera3::constructDefaultRequestSettings(
settings.update(ANDROID_JPEG_QUALITY, &jpegQuality, 1);
static const int32_t thumbnailSize[2] = {
- 640, 480
+ 160, 120
};
settings.update(ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2);
@@ -1199,9 +1214,10 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
nsecs_t frameDuration;
uint32_t sensitivity;
bool needJpeg = false;
- struct ExifInfo info;
+ struct ExifInfo info;
ssize_t jpegbuffersize;
uint32_t jpegpixelfmt;
+ bool mHaveThumbnail = false;
exposureTime = settings.find(ANDROID_SENSOR_EXPOSURE_TIME).data.i64[0];
frameDuration = settings.find(ANDROID_SENSOR_FRAME_DURATION).data.i64[0];
@@ -1228,29 +1244,27 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
destBuf.buffer = srcBuf.buffer;
destBuf.share_fd = privBuffer->share_fd;
- //ALOGI("%s, i:%d format for this usage: %d x %d, usage %x, format=%x, returned\n",
- // __FUNCTION__, i, destBuf.width, destBuf.height, privBuffer->usage, privBuffer->format);
if (destBuf.format == HAL_PIXEL_FORMAT_BLOB) {
needJpeg = true;
- memset(&info,0,sizeof(struct ExifInfo));
- info.orientation = settings.find(ANDROID_JPEG_ORIENTATION).data.i32[0];
+ memset(&info,0,sizeof(struct ExifInfo));
+ info.orientation = settings.find(ANDROID_JPEG_ORIENTATION).data.i32[0];
jpegpixelfmt = mSensor->getOutputFormat();
if (!mSupportRotate) {
info.mainwidth = srcBuf.stream->width;
info.mainheight = srcBuf.stream->height;
} else {
- if ((info.orientation==90)||(info.orientation==270)) {
- info.mainwidth = srcBuf.stream->height;
- info.mainheight = srcBuf.stream->width;
- } else {
- info.mainwidth = srcBuf.stream->width;
- info.mainheight = srcBuf.stream->height;
- }
+ if ((info.orientation == 90) || (info.orientation == 270)) {
+ info.mainwidth = srcBuf.stream->height;
+ info.mainheight = srcBuf.stream->width;
+ } else {
+ info.mainwidth = srcBuf.stream->width;
+ info.mainheight = srcBuf.stream->height;
+ }
}
if ((jpegpixelfmt == V4L2_PIX_FMT_MJPEG)||(jpegpixelfmt == V4L2_PIX_FMT_YUYV)) {
mSensor->setOutputFormat(info.mainwidth,info.mainheight,jpegpixelfmt,1);
} else {
- mSensor->setOutputFormat(info.mainwidth,info.mainheight,V4L2_PIX_FMT_RGB24,1);
+ mSensor->setOutputFormat(info.mainwidth,info.mainheight,V4L2_PIX_FMT_RGB24,1);
}
}
@@ -1308,57 +1322,60 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
buffers->push_back(srcBuf);
}
- if (needJpeg){
+ if (needJpeg) {
if (!mSupportRotate) {
info.thumbwidth = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[0];
info.thumbheight = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[1];
} else {
- if ((info.orientation==90)||(info.orientation==270)) {
- info.thumbwidth = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[1];
- info.thumbheight = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[0];
- } else {
- info.thumbwidth = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[0];
- info.thumbheight = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[1];
- }
+ if ((info.orientation == 90) || (info.orientation == 270)) {
+ info.thumbwidth = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[1];
+ info.thumbheight = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[0];
+ } else {
+ info.thumbwidth = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[0];
+ info.thumbheight = settings.find(ANDROID_JPEG_THUMBNAIL_SIZE).data.i32[1];
+ }
+ }
+ if (settings.exists(ANDROID_JPEG_GPS_COORDINATES)) {
+ info.latitude = settings.find(ANDROID_JPEG_GPS_COORDINATES).data.d[0];
+ info.longitude = settings.find(ANDROID_JPEG_GPS_COORDINATES).data.d[1];
+ info.altitude = settings.find(ANDROID_JPEG_GPS_COORDINATES).data.d[2];
+ info.has_latitude = true;
+ info.has_longitude = true;
+ info.has_altitude = true;
+ } else {
+ info.has_latitude = false;
+ info.has_longitude = false;
+ info.has_altitude = false;
+ }
+ if (settings.exists(ANDROID_JPEG_GPS_PROCESSING_METHOD)) {
+ info.gpsProcessingMethod = settings.find(ANDROID_JPEG_GPS_PROCESSING_METHOD).data.u8;
+ info.has_gpsProcessingMethod = true;
+ } else {
+ info.has_gpsProcessingMethod = false;
+ }
+ if (settings.exists(ANDROID_JPEG_GPS_TIMESTAMP)) {
+ info.gpsTimestamp = settings.find(ANDROID_JPEG_GPS_TIMESTAMP).data.i64[0];
+ info.has_gpsTimestamp = true;
+ } else {
+ info.has_gpsTimestamp = false;
+ }
+ if (settings.exists(ANDROID_LENS_FOCAL_LENGTH)) {
+ info.focallen = settings.find(ANDROID_LENS_FOCAL_LENGTH).data.f[0];
+ info.has_focallen = true;
+ } else {
+ info.has_focallen = false;
}
- if (settings.exists(ANDROID_JPEG_GPS_COORDINATES)) {
- info.latitude = settings.find(ANDROID_JPEG_GPS_COORDINATES).data.d[0];
- info.longitude = settings.find(ANDROID_JPEG_GPS_COORDINATES).data.d[1];
- info.altitude = settings.find(ANDROID_JPEG_GPS_COORDINATES).data.d[2];
- info.has_latitude = true;
- info.has_longitude = true;
- info.has_altitude = true;
- } else {
- info.has_latitude = false;
- info.has_longitude = false;
- info.has_altitude = false;
- }
- if (settings.exists(ANDROID_JPEG_GPS_PROCESSING_METHOD)) {
- info.gpsProcessingMethod = settings.find(ANDROID_JPEG_GPS_PROCESSING_METHOD).data.u8;
- info.has_gpsProcessingMethod = true;
- } else {
- info.has_gpsProcessingMethod = false;
- }
- if (settings.exists(ANDROID_JPEG_GPS_TIMESTAMP)) {
- info.gpsTimestamp = settings.find(ANDROID_JPEG_GPS_TIMESTAMP).data.i64[0];
- info.has_gpsTimestamp = true;
- } else {
- info.has_gpsTimestamp = false;
- }
- if (settings.exists(ANDROID_LENS_FOCAL_LENGTH)) {
- info.focallen = settings.find(ANDROID_LENS_FOCAL_LENGTH).data.f[0];
- info.has_focallen = true;
- } else {
- info.has_focallen = false;
- }
jpegbuffersize = getJpegBufferSize(info.mainwidth,info.mainheight);
-
+
mJpegCompressor->SetMaxJpegBufferSize(jpegbuffersize);
- mJpegCompressor->SetExifInfo(info);
- mSensor->setPictureRotate(info.orientation);
- DBG_LOGB("%s::thumbnailSize_width=%d,thumbnailSize_height=%d,mainsize_width=%d,mainsize_height=%d,jpegOrientation=%d",__FUNCTION__,
- info.thumbwidth,info.thumbheight,info.mainwidth,info.mainheight,info.orientation);
- }
+ mJpegCompressor->SetExifInfo(info);
+ mSensor->setPictureRotate(info.orientation);
+ if ((info.thumbwidth > 0) && (info.thumbheight > 0)) {
+ mHaveThumbnail = true;
+ }
+ DBG_LOGB("%s::thumbnailSize_width=%d,thumbnailSize_height=%d,mainsize_width=%d,mainsize_height=%d,jpegOrientation=%d",__FUNCTION__,
+ info.thumbwidth,info.thumbheight,info.mainwidth,info.mainheight,info.orientation);
+ }
/**
* Wait for JPEG compressor to not be busy, if needed
*/
@@ -1372,10 +1389,11 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
}
}
#else
- while (needJpeg) {
+ while (needJpeg) {
bool ready = mJpegCompressor->waitForDone(kFenceTimeoutMs);
- if (ready)
- break;
+ if (ready) {
+ break;
+ }
}
#endif
/**
@@ -1421,6 +1439,7 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
r.settings = settings;
r.sensorBuffers = sensorBuffers;
r.buffers = buffers;
+ r.havethumbnail = mHaveThumbnail;
mReadoutThread->queueCaptureRequest(r);
ALOGVV("%s: Queued frame %d", __FUNCTION__, request->frame_number);
@@ -2616,9 +2635,35 @@ status_t EmulatedFakeCamera3::ReadoutThread::waitForReadout() {
return OK;
}
-bool EmulatedFakeCamera3::ReadoutThread::threadLoop() {
+status_t EmulatedFakeCamera3::ReadoutThread::setJpegCompressorListener(EmulatedFakeCamera3 *parent) {
status_t res;
+ res = mParent->mJpegCompressor->setlistener(this);
+ if (res != NO_ERROR) {
+ ALOGE("%s: set JpegCompressor Listner failed",__FUNCTION__);
+ }
+ return res;
+}
+status_t EmulatedFakeCamera3::ReadoutThread::startJpegCompressor(EmulatedFakeCamera3 *parent) {
+ status_t res;
+ res = mParent->mJpegCompressor->start();
+ if (res != NO_ERROR) {
+ ALOGE("%s: JpegCompressor start failed",__FUNCTION__);
+ }
+ return res;
+}
+
+status_t EmulatedFakeCamera3::ReadoutThread::shutdownJpegCompressor(EmulatedFakeCamera3 *parent) {
+ status_t res;
+ res = mParent->mJpegCompressor->cancel();
+ if (res != OK) {
+ ALOGE("%s: JpegCompressor cancel failed",__FUNCTION__);
+ }
+ return res;
+}
+
+bool EmulatedFakeCamera3::ReadoutThread::threadLoop() {
+ status_t res;
ALOGVV("%s: ReadoutThread waiting for request", __FUNCTION__);
// First wait for a request from the in-flight queue
@@ -2641,6 +2686,7 @@ bool EmulatedFakeCamera3::ReadoutThread::threadLoop() {
mCurrentRequest.settings.acquire(mInFlightQueue.begin()->settings);
mCurrentRequest.buffers = mInFlightQueue.begin()->buffers;
mCurrentRequest.sensorBuffers = mInFlightQueue.begin()->sensorBuffers;
+ mCurrentRequest.havethumbnail = mInFlightQueue.begin()->havethumbnail;
mInFlightQueue.erase(mInFlightQueue.begin());
mInFlightSignal.signal();
mThreadActive = true;
@@ -2668,40 +2714,22 @@ bool EmulatedFakeCamera3::ReadoutThread::threadLoop() {
// compression if so. Otherwise prepare the buffer for return.
bool needJpeg = false;
HalBufferVector::iterator buf = mCurrentRequest.buffers->begin();
- while(buf != mCurrentRequest.buffers->end()) {
+ while (buf != mCurrentRequest.buffers->end()) {
bool goodBuffer = true;
if ( buf->stream->format ==
HAL_PIXEL_FORMAT_BLOB) {
Mutex::Autolock jl(mJpegLock);
- if (mJpegWaiting) {
-
- // This shouldn't happen, because processCaptureRequest should
- // be stalling until JPEG compressor is free.
- //
- ALOGE("%s: Already processing a JPEG!", __FUNCTION__);
- goodBuffer = false;
- }
- if (goodBuffer) {
- // Compressor takes ownership of sensorBuffers here
- res = mParent->mJpegCompressor->start(mCurrentRequest.sensorBuffers,
- this);
- goodBuffer = (res == OK);
- }
- if (goodBuffer) {
- needJpeg = true;
-
- mJpegHalBuffer = *buf;
- mJpegFrameNumber = mCurrentRequest.frameNumber;
- mJpegWaiting = true;
-
- mCurrentRequest.sensorBuffers = NULL;
- buf = mCurrentRequest.buffers->erase(buf);
-
- continue;
- }
- ALOGE("%s: Error compressing output buffer: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- // fallthrough for cleanup
+ needJpeg = true;
+ CaptureRequest currentcapture;
+ currentcapture.frameNumber = mCurrentRequest.frameNumber;
+ currentcapture.sensorBuffers = mCurrentRequest.sensorBuffers;
+ currentcapture.buf = buf;
+ currentcapture.mNeedThumbnail = mCurrentRequest.havethumbnail;
+ mParent->mJpegCompressor->queueRequest(currentcapture);
+ //this sensorBuffers delete in the jpegcompress;
+ mCurrentRequest.sensorBuffers = NULL;
+ buf = mCurrentRequest.buffers->erase(buf);
+ continue;
}
GraphicBufferMapper::get().unlock(*(buf->buffer));
@@ -2758,11 +2786,11 @@ bool EmulatedFakeCamera3::ReadoutThread::threadLoop() {
}
void EmulatedFakeCamera3::ReadoutThread::onJpegDone(
- const StreamBuffer &jpegBuffer, bool success) {
+ const StreamBuffer &jpegBuffer, bool success , CaptureRequest &r) {
Mutex::Autolock jl(mJpegLock);
-
GraphicBufferMapper::get().unlock(*(jpegBuffer.buffer));
+ mJpegHalBuffer = *(r.buf);
mJpegHalBuffer.status = success ?
CAMERA3_BUFFER_STATUS_OK : CAMERA3_BUFFER_STATUS_ERROR;
mJpegHalBuffer.acquire_fence = -1;
@@ -2770,7 +2798,7 @@ void EmulatedFakeCamera3::ReadoutThread::onJpegDone(
mJpegWaiting = false;
camera3_capture_result result;
- result.frame_number = mJpegFrameNumber;
+ result.frame_number = r.frameNumber;
result.result = NULL;
result.num_output_buffers = 1;
result.output_buffers = &mJpegHalBuffer;
@@ -2785,6 +2813,7 @@ void EmulatedFakeCamera3::ReadoutThread::onJpegDone(
}
mParent->sendCaptureResult(&result);
+
}
void EmulatedFakeCamera3::ReadoutThread::onJpegInputDone(
diff --git a/v3/EmulatedFakeCamera3.h b/v3/EmulatedFakeCamera3.h
index 1762232..6061fb2 100755
--- a/v3/EmulatedFakeCamera3.h
+++ b/v3/EmulatedFakeCamera3.h
@@ -31,6 +31,7 @@
#include <utils/List.h>
#include <utils/Mutex.h>
+
namespace android {
/**
@@ -43,9 +44,10 @@ namespace android {
* response to hw_module_methods_t::open, and camera_device::close callbacks.
*/
struct jpegsize {
- uint32_t width;
- uint32_t height;
+ uint32_t width;
+ uint32_t height;
};
+
class EmulatedFakeCamera3 : public EmulatedCamera3,
private Sensor::SensorListener {
public:
@@ -261,6 +263,7 @@ private:
CameraMetadata settings;
HalBufferVector *buffers;
Buffers *sensorBuffers;
+ bool havethumbnail;
};
/**
@@ -269,13 +272,15 @@ private:
// Place request in the in-flight queue to wait for sensor capture
void queueCaptureRequest(const Request &r);
-
// Test if the readout thread is idle (no in-flight requests, not
// currently reading out anything
bool isIdle();
// Wait until isIdle is true
status_t waitForReadout();
+ status_t setJpegCompressorListener(EmulatedFakeCamera3 *parent);
+ status_t startJpegCompressor(EmulatedFakeCamera3 *parent);
+ status_t shutdownJpegCompressor(EmulatedFakeCamera3 * parent);
private:
static const nsecs_t kWaitPerLoop = 10000000L; // 10 ms
@@ -301,7 +306,7 @@ private:
bool mJpegWaiting;
camera3_stream_buffer mJpegHalBuffer;
uint32_t mJpegFrameNumber;
- virtual void onJpegDone(const StreamBuffer &jpegBuffer, bool success);
+ virtual void onJpegDone(const StreamBuffer &jpegBuffer, bool success, CaptureRequest &r);
virtual void onJpegInputDone(const StreamBuffer &inputBuffer);
};
diff --git a/v3/fake-pipeline2/JpegCompressor.cpp b/v3/fake-pipeline2/JpegCompressor.cpp
index 9629070..6678116 100755
--- a/v3/fake-pipeline2/JpegCompressor.cpp
+++ b/v3/fake-pipeline2/JpegCompressor.cpp
@@ -27,6 +27,7 @@
#include <math.h>
#include <sys/time.h>
#include <cutils/properties.h>
+#include "NV12_resize.h"
#define EXIF_MAKE_DEFAULT "default_make"
@@ -43,25 +44,25 @@ int extraSmallImg(unsigned char* SrcImg,int SrcW,int SrcH,
unsigned char* DstImg,int DstW,int DstH)
{
int skipW = SrcW/DstW;
- int skipH = SrcH/DstH;
- unsigned char* dst = DstImg;
- unsigned char* srcrow = SrcImg;
- unsigned char* srcrowidx = srcrow;
- int i = 0,j = 0;
- for(;i<DstH;i++)
- {
- for(j = 0;j<DstW;j++)
- {
- dst[0] = srcrowidx[0];
- dst[1] = srcrowidx[1];
- dst[2] = srcrowidx[2];
- dst+=3;
- srcrowidx+=3*skipW;
- }
- srcrow += skipH*SrcW*3;
- srcrowidx = srcrow;
- }
- return 1;
+ int skipH = SrcH/DstH;
+ unsigned char* dst = DstImg;
+ unsigned char* srcrow = SrcImg;
+ unsigned char* srcrowidx = srcrow;
+ int i = 0,j = 0;
+ for (; i<DstH; i++)
+ {
+ for (j = 0; j<DstW; j++)
+ {
+ dst[0] = srcrowidx[0];
+ dst[1] = srcrowidx[1];
+ dst[2] = srcrowidx[2];
+ dst += 3;
+ srcrowidx += 3*skipW;
+ }
+ srcrow += skipH*SrcW*3;
+ srcrowidx = srcrow;
+ }
+ return 1;
}
namespace android {
@@ -75,17 +76,39 @@ static string_pair degress_to_exif_lut [] = {
{"180", "3"},
{"270", "8"},
};
+
+struct params {
+ uint8_t* src;
+ int src_size;
+ uint8_t* dst;
+ int dst_size;
+ int quality;
+ int in_width;
+ int in_height;
+ int out_width;
+ int out_height;
+ int format;
+ size_t jpeg_size;
+};
+
+enum format {
+ YUV420SP,
+ YUV422I,
+ RGB24,
+};
+
JpegCompressor::JpegCompressor():
Thread(false),
mIsBusy(false),
mSynchronous(false),
+ mExitJpegThread(false),
mNeedexif(true),
- mNeedThumbnail(false),
mMainJpegSize(0),
mThumbJpegSize(0),
mSrcThumbBuffer(NULL),
- mDstThumbBuffer(NULL),
+ mDstThumbBuffer(NULL),
mBuffers(NULL),
+ mPendingrequest(0),
mListener(NULL) {
memset(&mInfo,0,sizeof(struct ExifInfo));
}
@@ -94,7 +117,33 @@ JpegCompressor::~JpegCompressor() {
Mutex::Autolock lock(mMutex);
}
-status_t JpegCompressor::start(Buffers *buffers, JpegListener *listener) {
+void JpegCompressor::queueRequest(CaptureRequest &r) {
+ Mutex::Autolock lock(mMutex);
+
+ CaptureRequest* ri = new CaptureRequest();
+ ri->buf = new camera3_stream_buffer();
+ memcpy(ri->buf,r.buf,sizeof(camera3_stream_buffer_t));
+ ri->frameNumber = r.frameNumber;
+ ri->sensorBuffers = r.sensorBuffers;
+ ri->mNeedThumbnail = r.mNeedThumbnail;
+ mInJpegRequestQueue.push_back(ri);
+
+ mPendingrequest++;
+ mInJpegRequestSignal.signal();
+}
+
+status_t JpegCompressor::start() {
+ status_t res;
+ res = run("EmulatedFakeCamera2::JpegCompressor");
+ if (res != OK) {
+ ALOGE("%s: Unable to start up compression thread: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+ return res;
+}
+
+status_t JpegCompressor::setlistener(JpegListener *listener) {
+ status_t res = NO_ERROR;
if (listener == NULL) {
ALOGE("%s: NULL listener not allowed!", __FUNCTION__);
return BAD_VALUE;
@@ -108,19 +157,9 @@ status_t JpegCompressor::start(Buffers *buffers, JpegListener *listener) {
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;
}
@@ -149,7 +188,18 @@ status_t JpegCompressor::compressSynchronous(Buffers *buffers) {
}
status_t JpegCompressor::cancel() {
+ mMutex.lock();
+ mExitJpegThread = true;
+ mPendingrequest++;
+ mInJpegRequestSignal.signal();
+ mMutex.unlock();
requestExitAndWait();
+ for (List<CaptureRequest*>::iterator i = mInJpegRequestQueue.begin();
+ i != mInJpegRequestQueue.end(); i++) {
+ delete (*i)->buf;
+ delete (*i)->sensorBuffers;
+ }
+
return OK;
}
@@ -159,67 +209,49 @@ status_t JpegCompressor::readyToRun() {
bool JpegCompressor::threadLoop() {
status_t res;
- struct timeval mTimeStart,mTimeend;
- int intreval;
- ExifElementsTable* exiftable = NULL;
- struct camera2_jpeg_blob blob;
- int offset;
- ALOGV("%s: Starting compression thread", __FUNCTION__);
+ CaptureRequest* ri = NULL;
+ {
+ mMutex.lock();
+ if (mExitJpegThread) {
+ mMutex.unlock();
+ ALOGE("JpegCompressor Thread : exiting on request0");
+ return false;
+ }
- gettimeofday(&mTimeStart, NULL);
- res = compress();
- if (mNeedexif) {
- memset(&blob,0,sizeof(struct camera2_jpeg_blob));
- exiftable = new ExifElementsTable();
- GenExif(exiftable);
- }
- if (mNeedThumbnail) {
- res = thumbcompress();
- }
-
- if (exiftable) {
- uint32_t realjpegsize = 0;
- Section_t* exif_section = NULL;
- ExifElementsTable* exif = exiftable;
- exif->insertExifToJpeg((unsigned char*)mJpegBuffer.img,mMainJpegSize);
- if ((mNeedThumbnail)&&(mDstThumbBuffer != NULL)) {
- exif->insertExifThumbnailImage((const char*)mDstThumbBuffer,mThumbJpegSize);
- }
- exif_section = FindSection(M_EXIF);
- if (exif_section) {
- exif->saveJpeg((unsigned char*) mJpegBuffer.img, mMainJpegSize + exif_section->Size);
- }
- for (uint32_t size = (mMainJpegSize + exif_section->Size - 2); size > 0; size--) {
- if (checkJpegEnd(mJpegBuffer.img + size)) {
- realjpegsize = (size + MARKER_LENGTH);
- break;
+ while (mPendingrequest == 0) {
+ res = mInJpegRequestSignal.wait(mMutex);
+ }
+ mPendingrequest--;
+ if (mInJpegRequestQueue.size() > 0) {
+ List<CaptureRequest*>::iterator i = mInJpegRequestQueue.begin();
+ mJpegRequest.frameNumber = (*i)->frameNumber;
+ mJpegRequest.buf = (*i)->buf;
+ mJpegRequest.sensorBuffers = (*i)->sensorBuffers;
+ mJpegRequest.mNeedThumbnail = (*i)->mNeedThumbnail;
+ ri = *mInJpegRequestQueue.begin();
+ mInJpegRequestQueue.erase(mInJpegRequestQueue.begin());
+ mBuffers = mJpegRequest.sensorBuffers;
+ } else {
+ mMutex.unlock();
+ return true;
+ }
+ if (mExitJpegThread) {
+ mMutex.unlock();
+ ALOGE("JpegCompressor Thread : exiting on request1");
+ if (mBuffers != NULL) {
+ delete mBuffers;
+ mBuffers = NULL;
+ }
+ if (ri != NULL) {
+ if (ri->buf != NULL) {
+ delete ri->buf;
+ }
+ delete ri;
}
+ return false;
}
- int offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
- blob.jpeg_blob_id = 0x00FF;
- blob.jpeg_size = realjpegsize;
- memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
- }
- mListener->onJpegDone(mJpegBuffer, res == OK);
-
- if (mNeedexif) {
- if (exiftable != NULL) {
- delete exiftable;
- exiftable = NULL;
- }
- }
- gettimeofday(&mTimeend, NULL);
- intreval = (mTimeend.tv_sec - mTimeStart.tv_sec) * 1000 + ((mTimeend.tv_usec - mTimeStart.tv_usec))/1000;
- ALOGD("jpeg compress cost time =%d ms",intreval);
- cleanUp();
-
- return false;
-}
-
-status_t JpegCompressor::compress() {
- // Find source and target buffers. Assumes only one buffer matches
- // each condition!
- //Mutex::Autolock lock(mMutex);
+ mMutex.unlock();
+ }
bool foundJpeg = false, mFoundAux = false;
for (size_t i = 0; i < mBuffers->size(); i++) {
const StreamBuffer &b = (*mBuffers)[i];
@@ -238,132 +270,453 @@ status_t JpegCompressor::compress() {
return BAD_VALUE;
}
- if (mNeedThumbnail == true) {
- if (mSrcThumbBuffer == NULL) {
- mSrcThumbBuffer = (uint8_t*)malloc(mInfo.thumbwidth*mInfo.thumbheight*3);
- }
- if (mDstThumbBuffer == NULL) {
- mDstThumbBuffer = (uint8_t*)malloc(mInfo.thumbwidth*mInfo.thumbheight*3);
- }
- if (mSrcThumbBuffer) {
- if (mAuxBuffer.format == HAL_PIXEL_FORMAT_RGB_888)
- extraSmallImg(mAuxBuffer.img,mAuxBuffer.width,mAuxBuffer.height,
- mSrcThumbBuffer,mInfo.thumbwidth,mInfo.thumbheight);
- }
- }
+ struct timeval mTimeStart,mTimeend;
+ int intreval;
+ ExifElementsTable* exiftable = NULL;
+ struct camera2_jpeg_blob blob;
+ int offset;
+ ALOGV("%s: Starting compression thread", __FUNCTION__);
+
+ gettimeofday(&mTimeStart, NULL);
+ res = compress();
+ if (mNeedexif) {
+ memset(&blob,0,sizeof(struct camera2_jpeg_blob));
+ exiftable = new ExifElementsTable();
+ GenExif(exiftable);
+ }
+
+ if (mJpegRequest.mNeedThumbnail) {
+ res = thumbcompress();
+ }
+
+ if (exiftable) {
+ uint32_t realjpegsize = 0;
+ Section_t* exif_section = NULL;
+ ExifElementsTable* exif = exiftable;
+ exif->insertExifToJpeg((unsigned char*)mJpegBuffer.img,mMainJpegSize);
+ if ((mJpegRequest.mNeedThumbnail) && (mDstThumbBuffer != NULL)) {
+ exif->insertExifThumbnailImage((const char*)mDstThumbBuffer,mThumbJpegSize);
+ }
+ exif_section = FindSection(M_EXIF);
+ if (exif_section) {
+ exif->saveJpeg((unsigned char*) mJpegBuffer.img, mMainJpegSize + exif_section->Size);
+ }
+ for (uint32_t size = (mMainJpegSize + exif_section->Size - 2); size > 0; size--) {
+ if (checkJpegEnd(mJpegBuffer.img + size)) {
+ realjpegsize = (size + MARKER_LENGTH);
+ break;
+ }
+ }
+ int offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
+ blob.jpeg_blob_id = 0x00FF;
+ blob.jpeg_size = realjpegsize;
+ memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
+ }
+ mListener->onJpegDone(mJpegBuffer, res == OK, mJpegRequest);
+ if (ri != NULL) {
+ if (ri->buf != NULL) {
+ delete ri->buf;
+ }
+ delete ri;
+ }
+
+ if (mNeedexif) {
+ if (exiftable != NULL) {
+ delete exiftable;
+ exiftable = NULL;
+ }
+ }
+
+ gettimeofday(&mTimeend, NULL);
+ intreval = (mTimeend.tv_sec - mTimeStart.tv_sec) * 1000 + ((mTimeend.tv_usec - mTimeStart.tv_usec))/1000;
+ ALOGD("jpeg compress cost time =%d ms",intreval);
+ cleanUp();
+
+ return true;
+}
+
+struct libjpeg_destination_mgr : jpeg_destination_mgr {
+ libjpeg_destination_mgr(uint8_t* input, int size);
+ uint8_t* buf;
+ int bufsize;
+ size_t jpegsize;
+};
+
+static void libjpeg_init_destination (j_compress_ptr cinfo) {
+ libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest;
+
+ dest->next_output_byte = dest->buf;
+ dest->free_in_buffer = dest->bufsize;
+ dest->jpegsize = 0;
+}
+
+static boolean libjpeg_empty_output_buffer(j_compress_ptr cinfo) {
+ libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest;
- // Set up error management
+ dest->next_output_byte = dest->buf;
+ dest->free_in_buffer = dest->bufsize;
+ return TRUE; // ?
+}
- mJpegErrorInfo = NULL;
- JpegError error;
- error.parent = this;
+static void libjpeg_term_destination (j_compress_ptr cinfo) {
+ libjpeg_destination_mgr* dest = (libjpeg_destination_mgr*)cinfo->dest;
+ dest->jpegsize = dest->bufsize - dest->free_in_buffer;
+}
- mCInfo.err = jpeg_std_error(&error);
- mCInfo.err->error_exit = MainJpegErrorHandler;
+libjpeg_destination_mgr::libjpeg_destination_mgr(uint8_t* input, int size) {
+ this->init_destination = libjpeg_init_destination;
+ this->empty_output_buffer = libjpeg_empty_output_buffer;
+ this->term_destination = libjpeg_term_destination;
+ this->buf = input;
+ this->bufsize = size;
+ jpegsize = 0;
+}
- jpeg_create_compress(&mCInfo);
- if (checkError("Error initializing compression")) return NO_INIT;
+static void resize_nv12(params* params, uint8_t* dst_buffer) {
+ structConvImage o_img_ptr, i_img_ptr;
- // Route compressed data straight to output stream buffer
+ if (!params || !dst_buffer) {
+ return;
+ }
- JpegDestination jpegDestMgr;
- jpegDestMgr.parent = this;
- jpegDestMgr.init_destination = MainJpegInitDestination;
- jpegDestMgr.empty_output_buffer = MainJpegEmptyOutputBuffer;
- jpegDestMgr.term_destination = MainJpegTermDestination;
+ //input
+ i_img_ptr.uWidth = (mmInt32)params->in_width;
+ i_img_ptr.uStride = (mmInt32)i_img_ptr.uWidth;
+ i_img_ptr.uHeight = (mmInt32)params->in_height;
+ i_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp;
+ i_img_ptr.imgPtr = (mmByte *) params->src;
+ i_img_ptr.clrPtr = (mmByte *)i_img_ptr.imgPtr + (i_img_ptr.uWidth * i_img_ptr.uHeight);
+ i_img_ptr.uOffset = 0;
+
+ //ouput
+ o_img_ptr.uWidth = (mmInt32)params->out_width;
+ o_img_ptr.uStride = (mmInt32)o_img_ptr.uWidth;
+ o_img_ptr.uHeight = (mmInt32)params->out_height;
+ o_img_ptr.eFormat = IC_FORMAT_YCbCr420_lp;
+ o_img_ptr.imgPtr = (mmByte *)dst_buffer;
+ o_img_ptr.clrPtr = (mmByte *)o_img_ptr.imgPtr + (o_img_ptr.uWidth * o_img_ptr.uHeight);
+ o_img_ptr.uOffset = 0;
+
+ VT_resizeFrame_Video_opt2_lp(&i_img_ptr, &o_img_ptr, NULL, 0);
+}
- mCInfo.dest = &jpegDestMgr;
+static void resize_yuyv(params* params, uint8_t* dst_buffer) {
+ int step_x, step_y;
+ int dst_pos, src_pos;
+ int src_y_start_pos;
+ step_x = params->in_width / params->out_width;
+ step_y = params->in_height / params->out_height;
+ dst_pos = 0;
+ for (int y = 0; y < params->out_height; y++) {
+ src_y_start_pos = (y * step_y * (params->in_width * 2));
+ for (int x = 0; x < params->out_width; x += 2) {
+ src_pos = src_y_start_pos + (x * (step_x * 2));
+ dst_buffer[dst_pos++] = params->src[src_pos];
+ dst_buffer[dst_pos++] = params->src[src_pos + 1];
+ dst_buffer[dst_pos++] = params->src[src_pos + 2];
+ dst_buffer[dst_pos++] = params->src[src_pos + 3];
+ }
+ }
+}
- // Set up compression parameters
+/* private static functions */
+static void nv21_to_yuv(uint8_t* dst, uint8_t* y, uint8_t* uv, int width) {
+ if (!dst || !y || !uv) {
+ return;
+ }
- mCInfo.image_width = mAuxBuffer.width;
- mCInfo.image_height = mAuxBuffer.height;
- mCInfo.input_components = 3;
- mCInfo.in_color_space = JCS_RGB;
+ while ((width--) > 0) {
+ uint8_t y0 = y[0];
+ uint8_t v0 = uv[0];
+ uint8_t u0 = *(uv+1);
+ dst[0] = y0;
+ dst[1] = u0;
+ dst[2] = v0;
+ dst += 3;
+ y++;
+ if (!(width % 2)) uv+=2;
+ }
+}
- jpeg_set_defaults(&mCInfo);
- if (checkError("Error configuring defaults")) return NO_INIT;
+static void yuyv_to_yuv(uint8_t* dst, uint32_t* src, int width) {
+ if (!dst || !src) {
+ return;
+ }
- // Do compression
+ if (width % 2) {
+ return; // not supporting odd widths
+ }
- jpeg_start_compress(&mCInfo, TRUE);
- if (checkError("Error starting compression")) return NO_INIT;
+ // currently, neon routine only supports multiple of 16 width
+ if (width % 16) {
+ while ((width-=2) >= 0) {
+ uint8_t y0 = (src[0] >> 0) & 0xFF;
+ uint8_t u0 = (src[0] >> 8) & 0xFF;
+ uint8_t y1 = (src[0] >> 16) & 0xFF;
+ uint8_t v0 = (src[0] >> 24) & 0xFF;
+ dst[0] = y0;
+ dst[1] = u0;
+ dst[2] = v0;
+ dst[3] = y1;
+ dst[4] = u0;
+ dst[5] = v0;
+ dst += 6;
+ src++;
+ }
+ } else {
+ int n = width;
+ asm volatile (
+ " pld [%[src], %[src_stride], lsl #2] \n\t"
+ " cmp %[n], #16 \n\t"
+ " blt 5f \n\t"
+ "0: @ 16 pixel swap \n\t"
+ " vld2.8 {q0, q1} , [%[src]]! @ q0 = y q1 = uv \n\t"
+ " vuzp.8 q1, q2 @ d2 = u d4 = v \n\t"
+ " vmov d3, d2 @ q1 = u0u1u2..u0u1u2... \n\t"
+ " vmov d5, d4 @ q2 = v0v1v2..v0v1v2... \n\t"
+ " vzip.8 d2, d3 @ q1 = u0u0u1u1u2u2... \n\t"
+ " vzip.8 d4, d5 @ q2 = v0v0v1v1v2v2... \n\t"
+ " vst3.8 {d0,d2,d4},[%[dst]]! \n\t"
+ " vst3.8 {d1,d3,d5},[%[dst]]! \n\t"
+ " sub %[n], %[n], #16 \n\t"
+ " cmp %[n], #16 \n\t"
+ " bge 0b \n\t"
+ "5: @ end \n\t"
+#ifdef NEEDS_ARM_ERRATA_754319_754320
+ " vmov s0,s0 @ add noop for errata item \n\t"
+#endif
+ : [dst] "+r" (dst), [src] "+r" (src), [n] "+r" (n)
+ : [src_stride] "r" (width)
+ : "cc", "memory", "q0", "q1", "q2"
+ );
+ }
+}
- 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);
+static uint32_t calc_frame_length(int format, uint32_t width, uint32_t height)
+{
+ uint32_t length;
+ switch (format) {
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ length = width * height * 3/2;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ length = width * height * 3;
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ length = width * height * 2;
+ break;
+ default:
+ length = width * height * 3/2;
+ break;
+ }
+ return length;
+}
+
+size_t encode(params* input) {
+ jpeg_compress_struct cinfo;
+ jpeg_error_mgr jerr;
+ jpeg_destination_mgr jdest;
+ uint8_t* src = NULL;
+ uint8_t* resize_src = NULL;
+ uint8_t* row_tmp = NULL;
+ uint8_t* row_src = NULL;
+ uint8_t* row_uv = NULL; // used only for NV12
+ int row_stride;
+ int out_width = 0, in_width = 0;
+ int out_height = 0, in_height = 0;
+ int bpp = 2; // for uyvy
+
+ format informat = YUV422I;
+
+ if (!input) {
+ return 0;
+ }
+
+ out_width = input->out_width;
+ in_width = input->in_width;
+ out_height = input->out_height;
+ in_height = input->in_height;
+ src = input->src;
+ input->jpeg_size = 0;
+ libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size);
+
+ // param check...
+ if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) ||
+ (src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) ||
+ (input->dst_size < 1) ) {
+ goto exit;
+ }
+
+ if (input->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+ informat = YUV420SP;
+ bpp = 1;
+ if ((in_width != out_width) || (in_height != out_height)) {
+ resize_src = (uint8_t*) malloc(out_width * out_height *3);
+ if (NULL != resize_src) {
+ resize_nv12(input, resize_src);
+ if (resize_src) src = resize_src;
+ } else {
+ CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
+ goto exit;
+ }
+ }
+ } else if ((input->format == HAL_PIXEL_FORMAT_RGB_888)) {
+ informat = RGB24;
+ bpp = 1;
+ if ((in_width != out_width) || (in_height != out_height)) {
+ resize_src = (uint8_t*) malloc(out_width * out_height *3);
+ if (NULL != resize_src) {
+ extraSmallImg(input->src, in_width, in_height,
+ resize_src, out_width, out_height);
+ src = resize_src;
+ } else {
+ CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
+ goto exit;
+ }
}
- 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;
+ } else if (input->format == HAL_PIXEL_FORMAT_YCbCr_422_I) {
+ informat = YUV422I;
+ bpp = 2;
+ if ((in_width != out_width) || (in_height != out_height)) {
+ resize_src = (uint8_t*) malloc(out_width * out_height *3);
+ if (NULL != resize_src) {
+ resize_yuyv(input,resize_src);
+ if (resize_src) src = resize_src;
+ } else {
+ CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
+ goto exit;
+ }
+ }
+ } else if ((in_width != out_width) || (in_height != out_height)) {
+ CAMHAL_LOGEB("Encoder: resizing is not supported for this format: %d", input->format);
+ goto exit;
+ } else if ((input->format != HAL_PIXEL_FORMAT_YCbCr_422_I)) {
+ // we currently only support yuv422i and yuv420sp
+ CAMHAL_LOGEB("Encoder: format not supported: %d", input->format);
+ goto exit;
+ }
+
+ cinfo.err = jpeg_std_error(&jerr);
+
+ jpeg_create_compress(&cinfo);
+
+ CAMHAL_LOGDB("software encoding... \n\t"
+ "width: %d \n\t"
+ "height:%d \n\t"
+ "dest %p \n\t"
+ "dest size:%d \n\t"
+ "mSrc %p",
+ out_width, out_height, input->dst,
+ input->dst_size, src);
+
+ cinfo.dest = &dest_mgr;
+ cinfo.image_width = out_width;
+ cinfo.image_height = out_height;
+ cinfo.input_components = 3;
+ if (informat == RGB24)
+ cinfo.in_color_space = JCS_RGB;
+ else
+ cinfo.in_color_space = JCS_YCbCr;
+ cinfo.input_gamma = 1;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, input->quality, TRUE);
+ cinfo.dct_method = JDCT_IFAST;
+
+ jpeg_start_compress(&cinfo, TRUE);
+
+ row_tmp = (uint8_t*)malloc(out_width * 3);
+ row_src = src;
+ row_uv = src + out_width * out_height * bpp;
+ row_stride = out_width * 3;
+
+ while ((cinfo.next_scanline < cinfo.image_height)) {
+ JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */
+
+ if (informat == RGB24) {
+ row[0] = &src[cinfo.next_scanline * row_stride];
+ (void) jpeg_write_scanlines(&cinfo, row, 1);
+ } else {
+ // convert input yuv format to yuv444
+ if (informat == YUV420SP) {
+ nv21_to_yuv(row_tmp, row_src, row_uv, out_width);
+ } else if (informat == YUV422I) {
+ //uyvy_to_yuv(row_tmp, (uint32_t*)row_src, out_width);
+ yuyv_to_yuv(row_tmp, (uint32_t*)row_src, out_width);
+ }
+
+ row[0] = row_tmp;
+ jpeg_write_scanlines(&cinfo, row, 1);
+ row_src = row_src + out_width*bpp;
+
+ // move uv row if input format needs it
+ if (informat == YUV420SP) {
+ if (!(cinfo.next_scanline % 2))
+ row_uv = row_uv + out_width * bpp;
+ }
}
}
- jpeg_finish_compress(&mCInfo);
- if (checkError("Error while finishing compression")) return NO_INIT;
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ if (resize_src) free(resize_src);
+ if (row_tmp) free(row_tmp);
- // All done
- mMainJpegSize = kMaxJpegSize - mCInfo.dest->free_in_buffer;
- ALOGD("mMainJpegSize = %d",mMainJpegSize);
+ exit:
+ input->jpeg_size = dest_mgr.jpegsize;
+ return dest_mgr.jpegsize;
+}
+status_t JpegCompressor::compress() {
+ // Find source and target buffers. Assumes only one buffer matches
+ // each condition!
+ if (mJpegRequest.mNeedThumbnail == true) {
+ mSrcThumbBuffer = mAuxBuffer.img;
+ if (mDstThumbBuffer == NULL) {
+ mDstThumbBuffer = (uint8_t*)malloc(mInfo.thumbwidth * mInfo.thumbheight * 3);
+ }
+ }
+
+ params enc_params;
+ enc_params.src = mAuxBuffer.img;
+ enc_params.src_size = calc_frame_length(mAuxBuffer.format, mAuxBuffer.width, mAuxBuffer.height);
+ enc_params.dst = mJpegBuffer.img;
+ enc_params.dst_size = kMaxJpegSize;
+ enc_params.quality = 80;
+ enc_params.in_width = mAuxBuffer.width;
+ enc_params.in_height = mAuxBuffer.height;
+ enc_params.out_width= mAuxBuffer.width;
+ enc_params.out_height = mAuxBuffer.height;
+ enc_params.format = mAuxBuffer.format;
+ enc_params.jpeg_size = 0;
+
+ mMainJpegSize = encode(&enc_params);
+ ALOGD("mMainJpegSize = %d",mMainJpegSize);
return OK;
}
status_t JpegCompressor::thumbcompress() {
- if ((mSrcThumbBuffer == NULL)||(mDstThumbBuffer == NULL))
- return 0;
- //Mutex::Autolock lock(mMutex);
- mJpegErrorInfo = NULL;
- JpegError error;
- error.parent = this;
- mCInfo.err = jpeg_std_error(&error);
- mCInfo.err->error_exit = ThumbJpegErrorHandler;
-
- jpeg_create_compress(&mCInfo);
- if (checkError("Error initializing compression")) return NO_INIT;
- JpegDestination jpegDestMgr;
- jpegDestMgr.parent = this;
- jpegDestMgr.init_destination = ThumbJpegInitDestination;
- jpegDestMgr.empty_output_buffer = ThumbJpegEmptyOutputBuffer;
- jpegDestMgr.term_destination = ThumbJpegTermDestination;
- mCInfo.dest = &jpegDestMgr;
-
- // Set up compression parameters
-
- mCInfo.image_width = mInfo.thumbwidth;
- mCInfo.image_height = mInfo.thumbheight;
- mCInfo.input_components = 3;
- mCInfo.in_color_space = JCS_RGB;
- jpeg_set_defaults(&mCInfo);
- if (checkError("Error configuring defaults")) return NO_INIT;
- jpeg_start_compress(&mCInfo, TRUE);
- if (checkError("Error starting compression")) return NO_INIT;
- size_t rowStride = mInfo.thumbwidth* 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)
- (mSrcThumbBuffer + (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;
- mThumbJpegSize = kMaxJpegSize - mCInfo.dest->free_in_buffer;
- ALOGD("mThumbJpegSize = %d",mThumbJpegSize);
+ if ((mSrcThumbBuffer == NULL) || (mDstThumbBuffer == NULL))
+ return 0;
+
+ params enc_params;
+ enc_params.src = mSrcThumbBuffer;
+ enc_params.dst = mDstThumbBuffer;
+ enc_params.dst_size = kMaxJpegSize;
+ enc_params.quality = 70;
+ enc_params.src_size = calc_frame_length(mAuxBuffer.format, mAuxBuffer.width, mAuxBuffer.height);
+ enc_params.in_width = mAuxBuffer.width;
+ enc_params.in_height = mAuxBuffer.height;
+ enc_params.out_width= mInfo.thumbwidth;
+ enc_params.out_height = mInfo.thumbheight;
+ enc_params.format = mAuxBuffer.format;
+ enc_params.jpeg_size = 0;
+
+ mThumbJpegSize = encode(&enc_params);
+ ALOGD("mThumbJpegSize = %d",mThumbJpegSize);
+
return OK;
}
bool JpegCompressor::isBusy() {
@@ -405,19 +758,16 @@ bool JpegCompressor::checkError(const char *msg) {
void JpegCompressor::cleanUp() {
status_t res;
- jpeg_destroy_compress(&mCInfo);
Mutex::Autolock lock(mBusyMutex);
- if (mNeedThumbnail == true) {
- mNeedThumbnail = false;
- if (mSrcThumbBuffer != NULL) {
- free(mSrcThumbBuffer);
- mSrcThumbBuffer = NULL;
- }
- if (mDstThumbBuffer != NULL) {
- free(mDstThumbBuffer);
- mDstThumbBuffer = NULL;
- }
- }
+ if (mJpegRequest.mNeedThumbnail == true) {
+ if (mSrcThumbBuffer != NULL) {
+ mSrcThumbBuffer = NULL;
+ }
+ if (mDstThumbBuffer != NULL) {
+ free(mDstThumbBuffer);
+ mDstThumbBuffer = NULL;
+ }
+ }
if (mFoundAux) {
if (mAuxBuffer.streamId == 0) {
delete[] mAuxBuffer.img;
@@ -435,50 +785,6 @@ void JpegCompressor::cleanUp() {
mDone.signal();
}
-void JpegCompressor::MainJpegErrorHandler(j_common_ptr cinfo) {
- JpegError *error = static_cast<JpegError*>(cinfo->err);
- error->parent->mJpegErrorInfo = cinfo;
-}
-
-void JpegCompressor::MainJpegInitDestination(j_compress_ptr cinfo) {
- JpegDestination *dest= static_cast<JpegDestination*>(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::MainJpegEmptyOutputBuffer(j_compress_ptr cinfo) {
- ALOGE("%s: JPEG destination buffer overflow!",
- __FUNCTION__);
- return true;
-}
-
-void JpegCompressor::MainJpegTermDestination(j_compress_ptr cinfo) {
- ALOGV("%s: Done writing JPEG data. %zu bytes left in buffer",
- __FUNCTION__, cinfo->dest->free_in_buffer);
-}
-
-void JpegCompressor::ThumbJpegErrorHandler(j_common_ptr cinfo) {
- JpegError *error = static_cast<JpegError*>(cinfo->err);
- error->parent->mJpegErrorInfo = cinfo;
-}
-void JpegCompressor::ThumbJpegInitDestination(j_compress_ptr cinfo) {
- JpegDestination *dest= static_cast<JpegDestination*>(cinfo->dest);
- ALOGV("%s: Setting destination to %p, size %zu",
- __FUNCTION__, dest->parent->mDstThumbBuffer, kMaxJpegSize);
- dest->next_output_byte = (JOCTET*)(dest->parent->mDstThumbBuffer);
- dest->free_in_buffer = kMaxJpegSize;
-}
-boolean JpegCompressor::ThumbJpegEmptyOutputBuffer(j_compress_ptr cinfo) {
- ALOGE("%s: Thumb JPEG destination buffer overflow!",
- __FUNCTION__);
- return true;
-}
-void JpegCompressor::ThumbJpegTermDestination(j_compress_ptr cinfo) {
- ALOGV("%s: Done writing JPEG data. %zu bytes left in buffer",
- __FUNCTION__, cinfo->dest->free_in_buffer);
-}
JpegCompressor::JpegListener::~JpegListener() {
}
@@ -492,187 +798,184 @@ ssize_t JpegCompressor::GetMaxJpegBufferSize()
}
void JpegCompressor::SetExifInfo(struct ExifInfo info)
{
- mInfo.mainwidth = info.mainwidth;
- mInfo.mainheight = info.mainheight;
- mInfo.thumbwidth = info.thumbwidth;
- mInfo.thumbheight = info.thumbheight;
- mInfo.gpsTimestamp = info.gpsTimestamp;
- mInfo.latitude = info.latitude;
- mInfo.longitude = info.longitude;
- mInfo.altitude = info.altitude;
- mInfo.gpsProcessingMethod = info.gpsProcessingMethod;
- mInfo.focallen = info.focallen;
- mInfo.orientation = info.orientation;
- mInfo.has_latitude = info.has_latitude;
- mInfo.has_longitude = info.has_longitude;
- mInfo.has_altitude = info.has_altitude;
- mInfo.has_gpsProcessingMethod = info.has_gpsProcessingMethod;
- mInfo.has_gpsTimestamp = info.has_gpsTimestamp;
- mInfo.has_focallen = info.has_focallen;
- if ((mInfo.thumbwidth>0)&&(mInfo.thumbheight>0)) {
- mNeedThumbnail = true;
- }
+ mInfo.mainwidth = info.mainwidth;
+ mInfo.mainheight = info.mainheight;
+ mInfo.thumbwidth = info.thumbwidth;
+ mInfo.thumbheight = info.thumbheight;
+ mInfo.gpsTimestamp = info.gpsTimestamp;
+ mInfo.latitude = info.latitude;
+ mInfo.longitude = info.longitude;
+ mInfo.altitude = info.altitude;
+ mInfo.gpsProcessingMethod = info.gpsProcessingMethod;
+ mInfo.focallen = info.focallen;
+ mInfo.orientation = info.orientation;
+ mInfo.has_latitude = info.has_latitude;
+ mInfo.has_longitude = info.has_longitude;
+ mInfo.has_altitude = info.has_altitude;
+ mInfo.has_gpsProcessingMethod = info.has_gpsProcessingMethod;
+ mInfo.has_gpsTimestamp = info.has_gpsTimestamp;
+ mInfo.has_focallen = info.has_focallen;
+
}
int JpegCompressor::GenExif(ExifElementsTable* exiftable)
{
- char exifcontent[256];
- int width,height;
-
- bool newexif = true; //add new exif tag for cts
- float exposuretime = 1.0;
- float ApertureValue = 1.0;
- int flash = 0;
- int whitebalance = 1;
- int iso = 100;
- char SubSecTime[10] = "63";
- char SubSecTimeOrig[10]= "63";
- char SubSecTimeDig[10]= "63";
- char property[PROPERTY_VALUE_MAX];
+ char exifcontent[256];
+ int width,height;
+ bool newexif = true; //add new exif tag for cts
+ float exposuretime = 1.0;
+ float ApertureValue = 1.0;
+ int flash = 0;
+ int whitebalance = 1;
+ int iso = 100;
+ char SubSecTime[10] = "63";
+ char SubSecTimeOrig[10]= "63";
+ char SubSecTimeDig[10]= "63";
+ char property[PROPERTY_VALUE_MAX];
property_get("ro.product.manufacturer", property, EXIF_MAKE_DEFAULT);
- exiftable->insertElement("Make",property);
+ exiftable->insertElement("Make",property);
property_get("ro.product.model", property, EXIF_MODEL_DEFAULT);
- exiftable->insertElement("Model",property);
-// int orientation = mInfo.orientation;
- width = mInfo.mainwidth;
- height = mInfo.mainheight;
+ exiftable->insertElement("Model",property);
+// int orientation = mInfo.orientation;
+ width = mInfo.mainwidth;
+ height = mInfo.mainheight;
#if 0
- if(orientation == 0)
- orientation = 1;
- else if(orientation == 90)
- orientation = 6;
- else if(orientation == 180)
- orientation = 3;
- else if(orientation == 270)
- orientation = 8;
- sprintf(exifcontent,"%d",orientation);
- exiftable->insertElement("Orientation",(const char*)exifcontent);
+ if (orientation == 0)
+ orientation = 1;
+ else if (orientation == 90)
+ orientation = 6;
+ else if (orientation == 180)
+ orientation = 3;
+ else if (orientation == 270)
+ orientation = 8;
+ sprintf(exifcontent,"%d",orientation);
+ exiftable->insertElement("Orientation",(const char*)exifcontent);
#endif
- sprintf(exifcontent,"%d",width);
- exiftable->insertElement("ImageWidth",(const char*)exifcontent);
- sprintf(exifcontent,"%d",height);
- exiftable->insertElement("ImageLength",(const char*)exifcontent);
-
- sprintf(exifcontent,"%f",exposuretime);
- exiftable->insertElement("ExposureTime",(const char*)exifcontent);
- sprintf(exifcontent,"%f",ApertureValue);
- exiftable->insertElement("ApertureValue",(const char*)exifcontent);
- sprintf(exifcontent,"%d",flash);
- exiftable->insertElement("Flash",(const char*)exifcontent);
- sprintf(exifcontent,"%d",whitebalance);
- exiftable->insertElement("WhiteBalance",(const char*)exifcontent);
- sprintf(exifcontent,"%d",iso);
- exiftable->insertElement("ISOSpeedRatings",(const char*)exifcontent);
- if (newexif) {
- time_t times;
- {
- time(&times);
- struct tm tmstruct;
- tmstruct = *(localtime(&times)); //convert to local time
- strftime(exifcontent, 30, "%Y:%m:%d %H:%M:%S", &tmstruct);
- exiftable->insertElement("DateTimeDigitized",(const char*)exifcontent);
- }
- {
- sprintf(exifcontent, "%s", SubSecTime);
- exiftable->insertElement("SubSecTime",(const char*)exifcontent);
- }
- {
-
- sprintf(exifcontent, "%s", SubSecTimeOrig);
- exiftable->insertElement("SubSecTimeOriginal",(const char*)exifcontent);
- }
- {
-
- sprintf(exifcontent, "%s", SubSecTimeDig);
- exiftable->insertElement("SubSecTimeDigitized",(const char*)exifcontent);
- }
- }
-
- if (mInfo.has_focallen) {
- float focallen = mInfo.focallen;
- if(focallen >= 0){
- int focalNum = focallen*1000;
- int focalDen = 1000;
- sprintf(exifcontent,"%d/%d",focalNum,focalDen);
- exiftable->insertElement("FocalLength",(const char*)exifcontent);
- }
- }
- time_t times;
- {
- time(&times);
- struct tm tmstruct;
- tmstruct = *(localtime(&times)); //convert to local time
- strftime(exifcontent, 30, "%Y:%m:%d %H:%M:%S", &tmstruct);
- exiftable->insertElement("DateTime",(const char*)exifcontent);
- }
- if (mInfo.has_gpsTimestamp) {
- times = mInfo.gpsTimestamp;
- if(times != -1){
- struct tm tmstruct;
- tmstruct = *(gmtime(&times));//convert to standard time
- strftime(exifcontent, 20, "%Y:%m:%d", &tmstruct);
- exiftable->insertElement("GPSDateStamp",(const char*)exifcontent);
- sprintf(exifcontent,"%d/%d,%d/%d,%d/%d",tmstruct.tm_hour,1,tmstruct.tm_min,1,tmstruct.tm_sec,1);
- exiftable->insertElement("GPSTimeStamp",(const char*)exifcontent);
- }
- }
- if (mInfo.has_latitude) {
- int offset = 0;
- float latitude = mInfo.latitude;
- if(latitude < 0.0){
- offset = 1;
- latitude*= (float)(-1);
- }
- int latitudedegree = latitude;
- float latitudeminuts = (latitude-(float)latitudedegree)*60;
- int latitudeminuts_int = latitudeminuts;
- float latituseconds = (latitudeminuts-(float)latitudeminuts_int)*60+0.5;
- int latituseconds_int = latituseconds;
- sprintf(exifcontent,"%d/%d,%d/%d,%d/%d",latitudedegree,1,latitudeminuts_int,1,latituseconds_int,1);
- exiftable->insertElement("GPSLatitude",(const char*)exifcontent);
- exiftable->insertElement("GPSLatitudeRef",(offset==1)?"S":"N");
- }
- if (mInfo.has_longitude) {
- int offset = 0;
- float longitude = mInfo.longitude;
- if(longitude < 0.0){
- offset = 1;
- longitude*= (float)(-1);
- }
- int longitudedegree = longitude;
- float longitudeminuts = (longitude-(float)longitudedegree)*60;
- int longitudeminuts_int = longitudeminuts;
- float longitudeseconds = (longitudeminuts-(float)longitudeminuts_int)*60+0.5;
- int longitudeseconds_int = longitudeseconds;
- sprintf(exifcontent,"%d/%d,%d/%d,%d/%d",longitudedegree,1,longitudeminuts_int,1,longitudeseconds_int,1);
- exiftable->insertElement("GPSLongitude",(const char*)exifcontent);
- exiftable->insertElement("GPSLongitudeRef",(offset==1)?"S":"N");
- }
- if (mInfo.has_altitude) {
- int offset = 0;
- float altitude = mInfo.altitude;
- if(altitude < 0.0){
- offset = 1;
- altitude*= (float)(-1);
- }
- int altitudenum = altitude*1000;
- int altitudedec= 1000;
- sprintf(exifcontent,"%d/%d",altitudenum,altitudedec);
- exiftable->insertElement("GPSAltitude",(const char*)exifcontent);
- sprintf(exifcontent,"%d",offset);
- exiftable->insertElement("GPSAltitudeRef",(const char*)exifcontent);
- }
- if (mInfo.has_gpsProcessingMethod) {
- char* processmethod = (char*)mInfo.gpsProcessingMethod;
- if(processmethod!=NULL){
- memset(exifcontent,0,sizeof(exifcontent));
- char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };//asicii
- memcpy(exifcontent,ExifAsciiPrefix,8);
- memcpy(exifcontent+8,processmethod,strlen(processmethod));
- exiftable->insertElement("GPSProcessingMethod",(const char*)exifcontent);
- }
- }
- return 1;
+ sprintf(exifcontent,"%d",width);
+ exiftable->insertElement("ImageWidth",(const char*)exifcontent);
+ sprintf(exifcontent,"%d",height);
+ exiftable->insertElement("ImageLength",(const char*)exifcontent);
+
+ sprintf(exifcontent,"%f",exposuretime);
+ exiftable->insertElement("ExposureTime",(const char*)exifcontent);
+ sprintf(exifcontent,"%f",ApertureValue);
+ exiftable->insertElement("ApertureValue",(const char*)exifcontent);
+ sprintf(exifcontent,"%d",flash);
+ exiftable->insertElement("Flash",(const char*)exifcontent);
+ sprintf(exifcontent,"%d",whitebalance);
+ exiftable->insertElement("WhiteBalance",(const char*)exifcontent);
+ sprintf(exifcontent,"%d",iso);
+ exiftable->insertElement("ISOSpeedRatings",(const char*)exifcontent);
+ if (newexif) {
+ time_t times;
+ {
+ time(&times);
+ struct tm tmstruct;
+ tmstruct = *(localtime(&times)); //convert to local time
+ strftime(exifcontent, 30, "%Y:%m:%d %H:%M:%S", &tmstruct);
+ exiftable->insertElement("DateTimeDigitized",(const char*)exifcontent);
+ }
+ {
+ sprintf(exifcontent, "%s", SubSecTime);
+ exiftable->insertElement("SubSecTime",(const char*)exifcontent);
+ }
+ {
+
+ sprintf(exifcontent, "%s", SubSecTimeOrig);
+ exiftable->insertElement("SubSecTimeOriginal",(const char*)exifcontent);
+ }
+ {
+
+ sprintf(exifcontent, "%s", SubSecTimeDig);
+ exiftable->insertElement("SubSecTimeDigitized",(const char*)exifcontent);
+ }
+ }
+
+ if (mInfo.has_focallen) {
+ float focallen = mInfo.focallen;
+ if (focallen >= 0) {
+ int focalNum = focallen*1000;
+ int focalDen = 1000;
+ sprintf(exifcontent,"%d/%d",focalNum,focalDen);
+ exiftable->insertElement("FocalLength",(const char*)exifcontent);
+ }
+ }
+ time_t times;
+ {
+ time(&times);
+ struct tm tmstruct;
+ tmstruct = *(localtime(&times)); //convert to local time
+ strftime(exifcontent, 30, "%Y:%m:%d %H:%M:%S", &tmstruct);
+ exiftable->insertElement("DateTime",(const char*)exifcontent);
+ }
+ if (mInfo.has_gpsTimestamp) {
+ times = mInfo.gpsTimestamp;
+ if (times != -1) {
+ struct tm tmstruct;
+ tmstruct = *(gmtime(&times));//convert to standard time
+ strftime(exifcontent, 20, "%Y:%m:%d", &tmstruct);
+ exiftable->insertElement("GPSDateStamp",(const char*)exifcontent);
+ sprintf(exifcontent,"%d/%d,%d/%d,%d/%d",tmstruct.tm_hour,1,tmstruct.tm_min,1,tmstruct.tm_sec,1);
+ exiftable->insertElement("GPSTimeStamp",(const char*)exifcontent);
+ }
+ }
+ if (mInfo.has_latitude) {
+ int offset = 0;
+ float latitude = mInfo.latitude;
+ if (latitude < 0.0) {
+ offset = 1;
+ latitude*= (float)(-1);
+ }
+ int latitudedegree = latitude;
+ float latitudeminuts = (latitude-(float)latitudedegree)*60;
+ int latitudeminuts_int = latitudeminuts;
+ float latituseconds = (latitudeminuts-(float)latitudeminuts_int)*60+0.5;
+ int latituseconds_int = latituseconds;
+ sprintf(exifcontent,"%d/%d,%d/%d,%d/%d",latitudedegree,1,latitudeminuts_int,1,latituseconds_int,1);
+ exiftable->insertElement("GPSLatitude",(const char*)exifcontent);
+ exiftable->insertElement("GPSLatitudeRef",(offset==1)?"S":"N");
+ }
+ if (mInfo.has_longitude) {
+ int offset = 0;
+ float longitude = mInfo.longitude;
+ if (longitude < 0.0) {
+ offset = 1;
+ longitude*= (float)(-1);
+ }
+ int longitudedegree = longitude;
+ float longitudeminuts = (longitude-(float)longitudedegree)*60;
+ int longitudeminuts_int = longitudeminuts;
+ float longitudeseconds = (longitudeminuts-(float)longitudeminuts_int)*60+0.5;
+ int longitudeseconds_int = longitudeseconds;
+ sprintf(exifcontent,"%d/%d,%d/%d,%d/%d",longitudedegree,1,longitudeminuts_int,1,longitudeseconds_int,1);
+ exiftable->insertElement("GPSLongitude",(const char*)exifcontent);
+ exiftable->insertElement("GPSLongitudeRef",(offset==1)?"S":"N");
+ }
+ if (mInfo.has_altitude) {
+ int offset = 0;
+ float altitude = mInfo.altitude;
+ if (altitude < 0.0) {
+ offset = 1;
+ altitude*= (float)(-1);
+ }
+ int altitudenum = altitude*1000;
+ int altitudedec= 1000;
+ sprintf(exifcontent,"%d/%d",altitudenum,altitudedec);
+ exiftable->insertElement("GPSAltitude",(const char*)exifcontent);
+ sprintf(exifcontent,"%d",offset);
+ exiftable->insertElement("GPSAltitudeRef",(const char*)exifcontent);
+ }
+ if (mInfo.has_gpsProcessingMethod) {
+ char* processmethod = (char*)mInfo.gpsProcessingMethod;
+ if (processmethod != NULL) {
+ memset(exifcontent,0,sizeof(exifcontent));
+ char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };//asicii
+ memcpy(exifcontent,ExifAsciiPrefix,8);
+ memcpy(exifcontent+8,processmethod,strlen(processmethod));
+ exiftable->insertElement("GPSProcessingMethod",(const char*)exifcontent);
+ }
+ }
+ return 1;
}
const char* ExifElementsTable::degreesToExifOrientation(const char* degrees) {
for (unsigned int i = 0; i < ARRAY_SIZE(degress_to_exif_lut); i++) {
@@ -755,12 +1058,12 @@ status_t ExifElementsTable::insertElement(const char* tag, const char* value) {
return ret;
}
void ExifElementsTable::saveJpeg(unsigned char* jpeg, size_t jpeg_size) {
- int ret;
- if (jpeg_opened) {
- ret = WriteJpegToBuffer(jpeg, jpeg_size);
- ALOGD("saveJpeg :: ret =%d",ret);
- DiscardData();
- jpeg_opened = false;
+ int ret;
+ if (jpeg_opened) {
+ ret = WriteJpegToBuffer(jpeg, jpeg_size);
+ ALOGD("saveJpeg :: ret =%d",ret);
+ DiscardData();
+ jpeg_opened = false;
}
}
void ExifElementsTable::insertExifToJpeg(unsigned char* jpeg, size_t jpeg_size) {
diff --git a/v3/fake-pipeline2/JpegCompressor.h b/v3/fake-pipeline2/JpegCompressor.h
index 9bb6cb7..affac67 100755
--- a/v3/fake-pipeline2/JpegCompressor.h
+++ b/v3/fake-pipeline2/JpegCompressor.h
@@ -27,9 +27,9 @@
#include "utils/Thread.h"
#include "utils/Mutex.h"
#include "utils/Timers.h"
-
#include "Base.h"
-
+#include <hardware/camera3.h>
+#include <utils/List.h>
#include <stdio.h>
extern "C" {
@@ -68,6 +68,12 @@ static const char TAG_SUBSEC_TIME[] = "SubSecTime";
static const char TAG_SUBSEC_TIME_ORIG[] = "SubSecTimeOriginal";
static const char TAG_SUBSEC_TIME_DIG[] = "SubSecTimeDigitized";
+struct CaptureRequest {
+ uint32_t frameNumber;
+ camera3_stream_buffer *buf;
+ Buffers *sensorBuffers;
+ bool mNeedThumbnail;
+};
class ExifElementsTable {
public:
@@ -99,7 +105,7 @@ class JpegCompressor: private Thread, public virtual RefBase {
struct JpegListener {
// Called when JPEG compression has finished, or encountered an error
virtual void onJpegDone(const StreamBuffer &jpegBuffer,
- bool success) = 0;
+ bool success, CaptureRequest &r) = 0;
// Called when the input buffer for JPEG is not needed any more,
// if the buffer came from the framework.
virtual void onJpegInputDone(const StreamBuffer &inputBuffer) = 0;
@@ -108,7 +114,9 @@ class JpegCompressor: private Thread, public virtual RefBase {
// Start compressing COMPRESSED format buffers; JpegCompressor takes
// ownership of the Buffers vector.
- status_t start(Buffers *buffers, JpegListener *listener);
+ status_t start();
+ status_t setlistener(JpegListener *listener);
+ void queueRequest(CaptureRequest &r);
// Compress and block until buffer is complete.
status_t compressSynchronous(Buffers *buffers);
@@ -119,14 +127,14 @@ class JpegCompressor: private Thread, public virtual RefBase {
bool isStreamInUse(uint32_t id);
bool waitForDone(nsecs_t timeout);
- ssize_t GetMaxJpegBufferSize();
- void SetMaxJpegBufferSize(ssize_t size);
- void SetExifInfo(struct ExifInfo info);
- int GenExif(ExifElementsTable* exiftable);
+ ssize_t GetMaxJpegBufferSize();
+ void SetMaxJpegBufferSize(ssize_t size);
+ void SetExifInfo(struct ExifInfo info);
+ int GenExif(ExifElementsTable* exiftable);
// TODO: Measure this
static const size_t kMaxJpegSize = 300000;
- ssize_t mMaxbufsize;
+ ssize_t mMaxbufsize;
private:
Mutex mBusyMutex;
@@ -135,18 +143,23 @@ class JpegCompressor: private Thread, public virtual RefBase {
bool mSynchronous;
Mutex mMutex;
-
- bool mNeedexif;
- bool mNeedThumbnail;
- int mMainJpegSize, mThumbJpegSize;
- uint8_t *mSrcThumbBuffer;
- uint8_t *mDstThumbBuffer;
+
+ List<CaptureRequest*> mInJpegRequestQueue;
+ Condition mInJpegRequestSignal;
+ camera3_stream_buffer *tempHalbuffers;
+ Buffers *tempBuffers;
+ CaptureRequest mJpegRequest;
+ bool mExitJpegThread;
+ bool mNeedexif;
+ int mMainJpegSize, mThumbJpegSize;
+ uint8_t *mSrcThumbBuffer;
+ uint8_t *mDstThumbBuffer;
Buffers *mBuffers;
+ int mPendingrequest;
JpegListener *mListener;
- struct ExifInfo mInfo;
+ struct ExifInfo mInfo;
StreamBuffer mJpegBuffer, mAuxBuffer;
bool mFoundJpeg, mFoundAux;
-
jpeg_compress_struct mCInfo;
struct JpegError : public jpeg_error_mgr {
@@ -158,20 +171,10 @@ class JpegCompressor: private Thread, public virtual RefBase {
JpegCompressor *parent;
};
- static void MainJpegErrorHandler(j_common_ptr cinfo);
- static void MainJpegInitDestination(j_compress_ptr cinfo);
- static boolean MainJpegEmptyOutputBuffer(j_compress_ptr cinfo);
- static void MainJpegTermDestination(j_compress_ptr cinfo);
-
- static void ThumbJpegErrorHandler(j_common_ptr cinfo);
- static void ThumbJpegInitDestination(j_compress_ptr cinfo);
- static boolean ThumbJpegEmptyOutputBuffer(j_compress_ptr cinfo);
- static void ThumbJpegTermDestination(j_compress_ptr cinfo);
-
bool checkError(const char *msg);
status_t compress();
- status_t thumbcompress();
+ status_t thumbcompress();
void cleanUp();
/**
diff --git a/v3/fake-pipeline2/Sensor.cpp b/v3/fake-pipeline2/Sensor.cpp
index cf54b5d..abce83b 100755
--- a/v3/fake-pipeline2/Sensor.cpp
+++ b/v3/fake-pipeline2/Sensor.cpp
@@ -41,6 +41,7 @@
#include <sys/time.h>
+
#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
namespace android {
@@ -1129,16 +1130,35 @@ int Sensor::captureNewImage() {
// Add auxillary buffer of the right size
// Assumes only one BLOB (JPEG) buffer in
// mNextCapturedBuffers
- isjpeg = true;
StreamBuffer bAux;
int orientation;
orientation = getPictureRotate();
ALOGD("bAux orientation=%d",orientation);
+ uint32_t pixelfmt;
+ if ((b.width == vinfo->preview.format.fmt.pix.width &&
+ b.height == vinfo->preview.format.fmt.pix.height) && (orientation == 0)) {
+
+ pixelfmt = getOutputFormat();
+ if (pixelfmt == V4L2_PIX_FMT_YVU420) {
+ pixelfmt = HAL_PIXEL_FORMAT_YV12;
+ } else if (pixelfmt == V4L2_PIX_FMT_NV21) {
+ DBG_LOGA("");
+ pixelfmt = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ } else if (pixelfmt == V4L2_PIX_FMT_YUYV) {
+ pixelfmt = HAL_PIXEL_FORMAT_YCbCr_422_I;
+ } else {
+ pixelfmt = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ }
+ } else {
+ isjpeg = true;
+ pixelfmt = HAL_PIXEL_FORMAT_RGB_888;
+ }
+
if (!msupportrotate) {
bAux.streamId = 0;
bAux.width = b.width;
bAux.height = b.height;
- bAux.format = HAL_PIXEL_FORMAT_RGB_888;
+ bAux.format = pixelfmt;
bAux.stride = b.width;
bAux.buffer = NULL;
} else {
@@ -1146,14 +1166,14 @@ int Sensor::captureNewImage() {
bAux.streamId = 0;
bAux.width = b.height;
bAux.height = b.width;
- bAux.format = HAL_PIXEL_FORMAT_RGB_888;
+ bAux.format = pixelfmt;
bAux.stride = b.height;
bAux.buffer = NULL;
} else {
bAux.streamId = 0;
bAux.width = b.width;
bAux.height = b.height;
- bAux.format = HAL_PIXEL_FORMAT_RGB_888;
+ bAux.format = pixelfmt;
bAux.stride = b.width;
bAux.buffer = NULL;
}
@@ -1831,6 +1851,9 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) {
rgb24_memcpy(img, src, width, height);
}
break;
+ } else if (vinfo->picture.format.fmt.pix.pixelformat == V4L2_PIX_FMT_NV21) {
+ memcpy(img, src, vinfo->picture.buf.length);
+ break;
}
}
}