Merge "EmulatedCamera2: Improve thread sequencing" into jb-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
97438d2456
@@ -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
|
||||
// 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("Waiting for JPEG compressor");
|
||||
ALOGV("Configure: Waiting for JPEG compressor");
|
||||
} else {
|
||||
ALOGV("Waiting for sensor");
|
||||
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;
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user