am 97438d24: Merge "EmulatedCamera2: Improve thread sequencing" into jb-mr1-dev

* commit '97438d2456b3972f8d54bfa927a672b6032adc98':
  EmulatedCamera2: Improve thread sequencing
This commit is contained in:
Eino-Ville Talvala
2012-08-20 14:05:26 -07:00
committed by Android Git Automerger
4 changed files with 98 additions and 34 deletions

View File

@@ -31,11 +31,11 @@
namespace android {
const uint32_t EmulatedFakeCamera2::kAvailableFormats[5] = {
const uint32_t EmulatedFakeCamera2::kAvailableFormats[4] = {
HAL_PIXEL_FORMAT_RAW_SENSOR,
HAL_PIXEL_FORMAT_BLOB,
HAL_PIXEL_FORMAT_RGBA_8888,
HAL_PIXEL_FORMAT_YV12,
// HAL_PIXEL_FORMAT_YV12,
HAL_PIXEL_FORMAT_YCrCb_420_SP
};
@@ -355,7 +355,7 @@ int EmulatedFakeCamera2::allocateStream(
*stream_id = mNextStreamId;
if (format_actual) *format_actual = format;
*usage = GRALLOC_USAGE_HW_CAMERA_WRITE;
*max_buffers = 4;
*max_buffers = kMaxBufferCount;
ALOGV("Stream allocated: %d, %d x %d, 0x%x. U: %x, B: %d",
*stream_id, width, height, format, *usage, *max_buffers);
@@ -630,7 +630,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
if (mRequest == NULL) {
Mutex::Autolock il(mInternalsMutex);
ALOGV("Getting next request");
ALOGV("Configure: Getting next request");
res = mParent->mRequestQueueSrc->dequeue_request(
mParent->mRequestQueueSrc,
&mRequest);
@@ -640,7 +640,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
return false;
}
if (mRequest == NULL) {
ALOGV("Request queue empty, going inactive");
ALOGV("Configure: Request queue empty, going inactive");
// No requests available, go into inactive mode
Mutex::Autolock lock(mInputMutex);
mActive = false;
@@ -665,7 +665,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
mNextBuffers = new Buffers;
mNextNeedsJpeg = false;
ALOGV("Setting up buffers for capture");
ALOGV("Configure: Setting up buffers for capture");
for (size_t i = 0; i < streams.count; i++) {
int streamId = streams.data.u8[i];
const Stream &s = mParent->getStreamInfo(streamId);
@@ -682,7 +682,8 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
b.format = s.format;
b.stride = s.stride;
mNextBuffers->push_back(b);
ALOGV(" Buffer %d: Stream %d, %d x %d, format 0x%x, stride %d",
ALOGV("Configure: Buffer %d: Stream %d, %d x %d, format 0x%x, "
"stride %d",
i, b.streamId, b.width, b.height, b.format, b.stride);
if (b.format == HAL_PIXEL_FORMAT_BLOB) {
mNextNeedsJpeg = true;
@@ -744,12 +745,22 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
mParent->mSensor->getScene().setHour(*e.data.i32);
}
// Start waiting on sensor or JPEG block
if (mNextNeedsJpeg) {
ALOGV("Waiting for JPEG compressor");
} else {
ALOGV("Waiting for sensor");
// Start waiting on readout thread
mWaitingForReadout = true;
ALOGV("Configure: Waiting for readout thread");
}
if (mWaitingForReadout) {
bool readoutDone;
readoutDone = mParent->mReadoutThread->waitForReady(kWaitPerLoop);
if (!readoutDone) return true;
if (mNextNeedsJpeg) {
ALOGV("Configure: Waiting for JPEG compressor");
} else {
ALOGV("Configure: Waiting for sensor");
}
mWaitingForReadout = false;
}
if (mNextNeedsJpeg) {
@@ -757,7 +768,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
jpegDone = mParent->mJpegCompressor->waitForDone(kWaitPerLoop);
if (!jpegDone) return true;
ALOGV("Waiting for sensor");
ALOGV("Configure: Waiting for sensor");
mNextNeedsJpeg = false;
}
bool vsync = mParent->mSensor->waitForVSync(kWaitPerLoop);
@@ -765,7 +776,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
if (!vsync) return true;
Mutex::Autolock il(mInternalsMutex);
ALOGV("Configuring sensor for frame %d", mNextFrameNumber);
ALOGV("Configure: Configuring sensor for frame %d", mNextFrameNumber);
mParent->mSensor->setExposureTime(mNextExposureTime);
mParent->mSensor->setFrameDuration(mNextFrameDuration);
mParent->mSensor->setSensitivity(mNextSensitivity);
@@ -775,7 +786,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
StreamBuffer &b = mNextBuffers->editItemAt(i);
Stream s = mParent->getStreamInfo(b.streamId);
ALOGV("Configure: Dequeing buffer from stream %d", b.streamId);
res = s.ops->dequeue_buffer(s.ops, &(b.buffer) );
if (res != NO_ERROR || b.buffer == NULL) {
ALOGE("%s: Unable to dequeue buffer from stream %d: %s (%d)",
@@ -801,7 +812,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
return false;
}
}
ALOGV("Configure: Done configure for frame %d", mNextFrameNumber);
mParent->mReadoutThread->setNextCapture(mRequest, mNextBuffers);
mParent->mSensor->setDestinationBuffers(mNextBuffers);
@@ -848,11 +859,30 @@ status_t EmulatedFakeCamera2::ReadoutThread::waitUntilRunning() {
return OK;
}
bool EmulatedFakeCamera2::ReadoutThread::waitForReady(nsecs_t timeout) {
status_t res;
Mutex::Autolock lock(mInputMutex);
while (!readyForNextCapture()) {
res = mReadySignal.waitRelative(mInputMutex, timeout);
if (res == TIMED_OUT) return false;
if (res != OK) {
ALOGE("%s: Error waiting for ready: %s (%d)", __FUNCTION__,
strerror(-res), res);
return false;
}
}
return true;
}
bool EmulatedFakeCamera2::ReadoutThread::readyForNextCapture() {
return (mInFlightTail + 1) % kInFlightQueueSize != mInFlightHead;
}
void EmulatedFakeCamera2::ReadoutThread::setNextCapture(
camera_metadata_t *request,
Buffers *buffers) {
Mutex::Autolock lock(mInputMutex);
if ( (mInFlightTail + 1) % kInFlightQueueSize == mInFlightHead) {
if ( !readyForNextCapture() ) {
ALOGE("In flight queue full, dropping captures");
mParent->signalError();
return;
@@ -900,6 +930,7 @@ int EmulatedFakeCamera2::ReadoutThread::getInProgressCount() {
bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
static const nsecs_t kWaitPerLoop = 10000000L; // 10 ms
status_t res;
int32_t frameNumber;
// Check if we're currently processing or just waiting
{
@@ -924,6 +955,7 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
return true;
} else {
Mutex::Autolock iLock(mInternalsMutex);
mReadySignal.signal();
mRequest = mInFlightQueue[mInFlightHead].request;
mBuffers = mInFlightQueue[mInFlightHead].buffers;
mInFlightQueue[mInFlightHead].request = NULL;
@@ -945,17 +977,36 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
if (!gotFrame) return true;
// Got sensor data, construct frame and send it out
ALOGV("Readout: Constructing metadata and frames");
Mutex::Autolock iLock(mInternalsMutex);
camera_metadata_entry_t metadataMode;
camera_metadata_entry_t entry;
res = find_camera_metadata_entry(mRequest,
ANDROID_REQUEST_FRAME_COUNT,
&entry);
if (res != NO_ERROR) {
ALOGE("%s: error reading frame count tag: %s (%d)",
__FUNCTION__, strerror(-res), res);
mParent->signalError();
return false;
}
frameNumber = *entry.data.i32;
res = find_camera_metadata_entry(mRequest,
ANDROID_REQUEST_METADATA_MODE,
&metadataMode);
&entry);
if (res != NO_ERROR) {
ALOGE("%s: error reading metadata mode tag: %s (%d)",
__FUNCTION__, strerror(-res), res);
mParent->signalError();
return false;
}
if (*metadataMode.data.u8 == ANDROID_REQUEST_METADATA_FULL) {
ALOGV("Metadata requested, constructing");
// Got sensor data and request, construct frame and send it out
ALOGV("Readout: Constructing metadata and frames for request %d",
frameNumber);
if (*entry.data.u8 == ANDROID_REQUEST_METADATA_FULL) {
ALOGV("Readout: Metadata requested, constructing");
camera_metadata_t *frame = NULL;
@@ -991,7 +1042,6 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
EMULATOR_SCENE_HOUROFDAY,
&requestedHour);
if (res == NAME_NOT_FOUND) {
ALOGV("Adding vendor tag");
res = add_camera_metadata_entry(frame,
EMULATOR_SCENE_HOUROFDAY,
&hourOfDay, 1);
@@ -999,19 +1049,18 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
ALOGE("Unable to add vendor tag");
}
} else if (res == OK) {
ALOGV("Replacing value in vendor tag");
*requestedHour.data.i32 = hourOfDay;
} else {
ALOGE("Error looking up vendor tag");
ALOGE("%s: Error looking up vendor tag", __FUNCTION__);
}
collectStatisticsMetadata(frame);
// TODO: Collect all final values used from sensor in addition to timestamp
ALOGV("Readout: Enqueue frame %d", frameNumber);
mParent->mFrameQueueDst->enqueue_frame(mParent->mFrameQueueDst,
frame);
}
ALOGV("Readout: Free request");
res = mParent->mRequestQueueSrc->free_request(mParent->mRequestQueueSrc, mRequest);
if (res != NO_ERROR) {
ALOGE("%s: Unable to return request buffer to queue: %d",
@@ -1022,17 +1071,17 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
mRequest = NULL;
int compressedBufferIndex = -1;
ALOGV("Processing %d buffers", mBuffers->size());
ALOGV("Readout: Processing %d buffers", mBuffers->size());
for (size_t i = 0; i < mBuffers->size(); i++) {
const StreamBuffer &b = (*mBuffers)[i];
ALOGV(" Buffer %d: Stream %d, %d x %d, format 0x%x, stride %d",
ALOGV("Readout: Buffer %d: Stream %d, %d x %d, format 0x%x, stride %d",
i, b.streamId, b.width, b.height, b.format, b.stride);
if (b.streamId >= 0) {
if (b.format == HAL_PIXEL_FORMAT_BLOB) {
// Assumes only one BLOB buffer type per capture
compressedBufferIndex = i;
} else {
ALOGV("Sending image buffer %d to output stream %d",
ALOGV("Readout: Sending image buffer %d to output stream %d",
i, b.streamId);
GraphicBufferMapper::get().unlock(*(b.buffer));
const Stream &s = mParent->getStreamInfo(b.streamId);
@@ -1050,7 +1099,7 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
delete mBuffers;
mBuffers = NULL;
} else {
ALOGV("Starting JPEG compression for buffer %d, stream %d",
ALOGV("Readout: Starting JPEG compression for buffer %d, stream %d",
compressedBufferIndex,
(*mBuffers)[compressedBufferIndex].streamId);
mParent->mJpegCompressor->start(mBuffers, captureTime);
@@ -1059,14 +1108,14 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
Mutex::Autolock l(mInputMutex);
mRequestCount--;
ALOGV("Readout: Done with request %d", frameNumber);
return true;
}
status_t EmulatedFakeCamera2::ReadoutThread::collectStatisticsMetadata(
camera_metadata_t *frame) {
// Completely fake face rectangles, don't correspond to real faces in scene
ALOGV("Collecting statistics metadata");
ALOGV("Readout: Collecting statistics metadata");
status_t res;
camera_metadata_entry_t entry;

View File

@@ -193,6 +193,7 @@ private:
camera_metadata_t *mRequest;
Mutex mInternalsMutex; // Lock before accessing below members.
bool mWaitingForReadout;
bool mNextNeedsJpeg;
int32_t mNextFrameNumber;
int64_t mNextExposureTime;
@@ -210,6 +211,7 @@ private:
// Input
status_t waitUntilRunning();
bool waitForReady(nsecs_t timeout);
void setNextCapture(camera_metadata_t *request,
Buffers *buffers);
@@ -221,11 +223,14 @@ private:
bool mRunning;
bool threadLoop();
bool readyForNextCapture();
status_t collectStatisticsMetadata(camera_metadata_t *frame);
// Inputs
Mutex mInputMutex; // Protects mActive, mInFlightQueue, mRequestCount
Condition mInputSignal;
Condition mReadySignal;
bool mActive;
static const int kInFlightQueueSize = 4;
@@ -327,6 +332,7 @@ private:
static const uint32_t kMaxRawStreamCount = 1;
static const uint32_t kMaxProcessedStreamCount = 3;
static const uint32_t kMaxJpegStreamCount = 1;
static const uint32_t kMaxBufferCount = 4;
static const uint32_t kAvailableFormats[];
static const uint32_t kAvailableRawSizes[];
static const uint64_t kAvailableRawMinDurations[];

View File

@@ -188,14 +188,17 @@ bool Sensor::waitForNewFrame(nsecs_t reltime,
uint8_t *ret;
if (mCapturedBuffers == NULL) {
int res;
res = mReadoutComplete.waitRelative(mReadoutMutex, reltime);
res = mReadoutAvailable.waitRelative(mReadoutMutex, reltime);
if (res == TIMED_OUT) {
return false;
} else if (res != OK || mCapturedBuffers == NULL) {
ALOGE("Error waiting for sensor readout signal: %d", res);
return false;
}
} else {
mReadoutComplete.signal();
}
*captureTime = mCaptureTime;
mCapturedBuffers = NULL;
return true;
@@ -267,9 +270,14 @@ bool Sensor::threadLoop() {
if (capturedBuffers != NULL) {
ALOGVV("Sensor readout complete");
Mutex::Autolock lock(mReadoutMutex);
if (mCapturedBuffers != NULL) {
ALOGV("Waiting for readout thread to catch up!");
mReadoutComplete.wait(mReadoutMutex);
}
mCapturedBuffers = capturedBuffers;
mCaptureTime = captureTime;
mReadoutComplete.signal();
mReadoutAvailable.signal();
capturedBuffers = NULL;
}

View File

@@ -187,6 +187,7 @@ class Sensor: private Thread, public virtual RefBase {
Mutex mReadoutMutex; // Lock before accessing readout variables
// Start of readout variables
Condition mReadoutAvailable;
Condition mReadoutComplete;
Buffers *mCapturedBuffers;
nsecs_t mCaptureTime;