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

View File

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

View File

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

View File

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