summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2012-06-15 15:41:44 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-07-13 12:31:01 -0700
commit9cca4c6d976d2d4127286e9eaa54d1b99880c25c (patch)
tree47231eca97c6ad4f51f32247f61bd863078bfa51
parent04cd0186305e2b59d23c9147787046c6662029cc (diff)
downloadframeworks_av-9cca4c6d976d2d4127286e9eaa54d1b99880c25c.zip
frameworks_av-9cca4c6d976d2d4127286e9eaa54d1b99880c25c.tar.gz
frameworks_av-9cca4c6d976d2d4127286e9eaa54d1b99880c25c.tar.bz2
Camera2: Add recording support
- Support startRecording/stopRecording - Support lock/unlock/connect - Some rearrangement of class definitions for clarity/consistency Bug: 6243944 Change-Id: I00c600a798572d2f69bb3f2bab3d79e4bd9a91e5
-rw-r--r--services/camera/libcameraservice/Camera2Client.cpp404
-rw-r--r--services/camera/libcameraservice/Camera2Client.h114
-rw-r--r--services/camera/libcameraservice/Camera2Device.cpp30
-rw-r--r--services/camera/libcameraservice/Camera2Device.h4
4 files changed, 487 insertions, 65 deletions
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index c90f81a..8d4add4 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -55,7 +55,9 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
mPreviewStreamId(NO_STREAM),
mPreviewRequest(NULL),
mCaptureStreamId(NO_STREAM),
- mCaptureRequest(NULL)
+ mCaptureRequest(NULL),
+ mRecordingStreamId(NO_STREAM),
+ mRecordingRequest(NULL)
{
ATRACE_CALL();
@@ -341,23 +343,59 @@ void Camera2Client::disconnect() {
status_t Camera2Client::connect(const sp<ICameraClient>& client) {
ATRACE_CALL();
+
Mutex::Autolock icl(mICameraLock);
- return BAD_VALUE;
+ if (mClientPid != 0 && getCallingPid() != mClientPid) {
+ ALOGE("%s: Camera %d: Connection attempt from pid %d; "
+ "current locked to pid %d", __FUNCTION__,
+ mCameraId, getCallingPid(), mClientPid);
+ return BAD_VALUE;
+ }
+
+ mClientPid = getCallingPid();
+ mCameraClient = client;
+
+ return OK;
}
status_t Camera2Client::lock() {
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
+ ALOGV("%s: Camera %d: Lock call from pid %d; current client pid %d",
+ __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
- return BAD_VALUE;
+ if (mClientPid == 0) {
+ mClientPid = getCallingPid();
+ return OK;
+ }
+
+ if (mClientPid != getCallingPid()) {
+ ALOGE("%s: Camera %d: Lock call from pid %d; currently locked to pid %d",
+ __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+ return EBUSY;
+ }
+
+ return OK;
}
status_t Camera2Client::unlock() {
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
+ ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d",
+ __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
- return BAD_VALUE;
+ // TODO: Check for uninterruptable conditions
+
+ if (mClientPid == getCallingPid()) {
+ mClientPid = 0;
+ mCameraClient.clear();
+ return OK;
+ }
+
+ ALOGE("%s: Camera %d: Unlock call from pid %d; currently locked to pid %d",
+ __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+ return EBUSY;
}
status_t Camera2Client::setPreviewDisplay(
@@ -365,8 +403,6 @@ status_t Camera2Client::setPreviewDisplay(
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
- if (mState >= PREVIEW) return INVALID_OPERATION;
-
sp<IBinder> binder;
sp<ANativeWindow> window;
if (surface != 0) {
@@ -382,8 +418,6 @@ status_t Camera2Client::setPreviewTexture(
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
- if (mState >= PREVIEW) return INVALID_OPERATION;
-
sp<IBinder> binder;
sp<ANativeWindow> window;
if (surfaceTexture != 0) {
@@ -402,6 +436,27 @@ status_t Camera2Client::setPreviewWindowLocked(const sp<IBinder>& binder,
return NO_ERROR;
}
+ switch (mState) {
+ case NOT_INITIALIZED:
+ case RECORD:
+ case STILL_CAPTURE:
+ case VIDEO_SNAPSHOT:
+ ALOGE("%s: Camera %d: Cannot set preview display while in state %s",
+ __FUNCTION__, mCameraId, getStateName(mState));
+ return INVALID_OPERATION;
+ case STOPPED:
+ case WAITING_FOR_PREVIEW_WINDOW:
+ // OK
+ break;
+ case PREVIEW:
+ // Already running preview - need to stop and create a new stream
+ // TODO: Optimize this so that we don't wait for old stream to drain
+ // before spinning up new stream
+ mDevice->setStreamingRequest(NULL);
+ mState = WAITING_FOR_PREVIEW_WINDOW;
+ break;
+ }
+
if (mPreviewStreamId != NO_STREAM) {
res = mDevice->waitUntilDrained();
if (res != OK) {
@@ -454,6 +509,8 @@ status_t Camera2Client::startPreviewLocked() {
}
mState = STOPPED;
+ Mutex::Autolock pl(mParamsLock);
+
res = updatePreviewStream();
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update preview stream: %s (%d)",
@@ -544,23 +601,125 @@ status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
status_t Camera2Client::startRecording() {
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
- return BAD_VALUE;
+ status_t res;
+ switch (mState) {
+ case STOPPED:
+ res = startPreviewLocked();
+ if (res != OK) return res;
+ break;
+ case PREVIEW:
+ // Ready to go
+ break;
+ case RECORD:
+ case VIDEO_SNAPSHOT:
+ // OK to call this when recording is already on
+ return OK;
+ break;
+ default:
+ ALOGE("%s: Camera %d: Can't start recording in state %s",
+ __FUNCTION__, mCameraId, getStateName(mState));
+ return INVALID_OPERATION;
+ };
+
+ Mutex::Autolock pl(mParamsLock);
+
+ res = updateRecordingStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ if (mRecordingRequest == NULL) {
+ res = updateRecordingRequest();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create recording request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ uint8_t outputStreams[2] = { mPreviewStreamId, mRecordingStreamId };
+ res = updateEntry(mRecordingRequest,
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ outputStreams, 2);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set up recording request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ res = sort_camera_metadata(mRecordingRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error sorting recording request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ res = mDevice->setStreamingRequest(mRecordingRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set recording request to start "
+ "recording: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ mState = RECORD;
+
+ return OK;
}
void Camera2Client::stopRecording() {
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
+ status_t res;
+ switch (mState) {
+ case RECORD:
+ // OK to stop
+ break;
+ case STOPPED:
+ case PREVIEW:
+ case STILL_CAPTURE:
+ case VIDEO_SNAPSHOT:
+ default:
+ ALOGE("%s: Camera %d: Can't stop recording in state %s",
+ __FUNCTION__, mCameraId, getStateName(mState));
+ return;
+ };
+
+ // Back to preview. Since record can only be reached through preview,
+ // all preview stream setup should be up to date.
+ res = mDevice->setStreamingRequest(mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to switch back to preview request: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return;
+ }
+
+ // TODO: Should recording heap be freed? Can't do it yet since requests
+ // could still be in flight.
+
+ mState = PREVIEW;
}
bool Camera2Client::recordingEnabled() {
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
- return BAD_VALUE;
+ return (mState == RECORD || mState == VIDEO_SNAPSHOT);
}
void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
+ // Make sure this is for the current heap
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) {
+ ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release "
+ "(got %x, expected %x)", __FUNCTION__, mCameraId,
+ heap->getHeapID(), mRecordingHeap->mHeap->getHeapID());
+ return;
+ }
+ mRecordingHeapFree++;
}
status_t Camera2Client::autoFocus() {
@@ -616,11 +775,18 @@ status_t Camera2Client::takePicture(int msgType) {
}
}
- // TODO: For video snapshot, will need 3 streams here
camera_metadata_entry_t outputStreams;
- uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
- res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
- &streamIds, 2);
+ if (mState == PREVIEW) {
+ uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
+ res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
+ &streamIds, 2);
+ } else if (mState == RECORD) {
+ uint8_t streamIds[3] = { mPreviewStreamId, mRecordingStreamId,
+ mCaptureStreamId };
+ res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
+ &streamIds, 3);
+ }
+
if (res != OK) {
ALOGE("%s: Camera %d: Unable to set up still image capture request: "
"%s (%d)",
@@ -650,7 +816,7 @@ status_t Camera2Client::takePicture(int msgType) {
return res;
}
}
-
+ // TODO: Capture should be atomic with setStreamingRequest here
res = mDevice->capture(captureCopy);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to submit still image capture request: "
@@ -699,7 +865,10 @@ status_t Camera2Client::setParameters(const String8& params) {
previewHeight != mParameters.previewHeight) {
if (mState >= PREVIEW) {
ALOGE("%s: Preview size cannot be updated when preview "
- "is active!", __FUNCTION__);
+ "is active! (Currently %d x %d, requested %d x %d",
+ __FUNCTION__,
+ mParameters.previewWidth, mParameters.previewHeight,
+ previewWidth, previewHeight);
return BAD_VALUE;
}
camera_metadata_entry_t availablePreviewSizes =
@@ -1127,6 +1296,7 @@ status_t Camera2Client::setParameters(const String8& params) {
}
/** Update internal parameters */
+
mParameters.previewWidth = previewWidth;
mParameters.previewHeight = previewHeight;
mParameters.previewFpsRange[0] = previewFpsRange[0];
@@ -1183,6 +1353,13 @@ status_t Camera2Client::setParameters(const String8& params) {
return res;
}
+ res = updateRecordingRequest();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
if (mState == PREVIEW) {
res = mDevice->setStreamingRequest(mPreviewRequest);
if (res != OK) {
@@ -1190,8 +1367,17 @@ status_t Camera2Client::setParameters(const String8& params) {
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+ } else if (mState == RECORD || mState == VIDEO_SNAPSHOT) {
+ res = mDevice->setStreamingRequest(mRecordingRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error streaming new record request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
}
+ mParamsFlattened = params;
+
return OK;
}
@@ -1240,6 +1426,8 @@ void Camera2Client::onCaptureAvailable() {
ATRACE_CALL();
status_t res;
sp<ICameraClient> currentClient;
+ ALOGV("%s: Camera %d: Still capture available", __FUNCTION__, mCameraId);
+
CpuConsumer::LockedBuffer imgBuffer;
{
Mutex::Autolock icl(mICameraLock);
@@ -1268,8 +1456,8 @@ void Camera2Client::onCaptureAvailable() {
}
// TODO: Optimize this to avoid memcopy
- void* captureMemory = mCaptureHeap->getBase();
- size_t size = mCaptureHeap->getSize();
+ void* captureMemory = mCaptureHeap->mHeap->getBase();
+ size_t size = mCaptureHeap->mHeap->getSize();
memcpy(captureMemory, imgBuffer.data, size);
mCaptureConsumer->unlockBuffer(imgBuffer);
@@ -1291,7 +1479,100 @@ void Camera2Client::onCaptureAvailable() {
// Call outside mICameraLock to allow re-entrancy from notification
if (currentClient != 0) {
currentClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
- mCaptureMemory, NULL);
+ mCaptureHeap->mBuffers[0], NULL);
+ }
+}
+
+void Camera2Client::onRecordingFrameAvailable() {
+ ATRACE_CALL();
+ status_t res;
+ sp<ICameraClient> currentClient;
+ size_t heapIdx = 0;
+ nsecs_t timestamp;
+ {
+ Mutex::Autolock icl(mICameraLock);
+ // TODO: Signal errors here upstream
+ if (mState != RECORD && mState != VIDEO_SNAPSHOT) {
+ ALOGE("%s: Camera %d: Recording image buffer produced unexpectedly!",
+ __FUNCTION__, mCameraId);
+ return;
+ }
+
+ CpuConsumer::LockedBuffer imgBuffer;
+ res = mRecordingConsumer->lockNextBuffer(&imgBuffer);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return;
+ }
+
+ if (imgBuffer.format != (int)kRecordingFormat) {
+ ALOGE("%s: Camera %d: Unexpected recording format: %x",
+ __FUNCTION__, mCameraId, imgBuffer.format);
+ mRecordingConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+ size_t bufferSize = imgBuffer.width * imgBuffer.height * 3 / 2;
+
+ if (mRecordingHeap == 0 ||
+ bufferSize >
+ mRecordingHeap->mHeap->getSize() / kRecordingHeapCount) {
+ ALOGV("%s: Camera %d: Creating recording heap with %d buffers of "
+ "size %d bytes", __FUNCTION__, mCameraId,
+ kRecordingHeapCount, bufferSize);
+ if (mRecordingHeap != 0) {
+ ALOGV("%s: Camera %d: Previous heap has size %d "
+ "(new will be %d) bytes", __FUNCTION__, mCameraId,
+ mRecordingHeap->mHeap->getSize(),
+ bufferSize * kRecordingHeapCount);
+ }
+ // Need to allocate memory for heap
+ mRecordingHeap.clear();
+
+ mRecordingHeap = new Camera2Heap(bufferSize, kRecordingHeapCount,
+ "Camera2Client::RecordingHeap");
+ if (mRecordingHeap->mHeap->getSize() == 0) {
+ ALOGE("%s: Camera %d: Unable to allocate memory for recording",
+ __FUNCTION__, mCameraId);
+ mRecordingConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+ mRecordingHeapHead = 0;
+ mRecordingHeapFree = kRecordingHeapCount;
+ }
+
+ // TODO: Optimize this to avoid memcopy
+ if ( mRecordingHeapFree == 0) {
+ ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
+ __FUNCTION__, mCameraId);
+ mRecordingConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+ heapIdx = mRecordingHeapHead;
+ timestamp = imgBuffer.timestamp;
+ mRecordingHeapHead = (mRecordingHeapHead + 1) % kRecordingHeapCount;
+ mRecordingHeapFree--;
+
+ ALOGV("%s: Camera %d: Timestamp %lld",
+ __FUNCTION__, mCameraId, timestamp);
+
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap =
+ mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset,
+ &size);
+
+ memcpy((uint8_t*)heap->getBase() + offset, imgBuffer.data, size);
+
+ mRecordingConsumer->unlockBuffer(imgBuffer);
+
+ currentClient = mCameraClient;
+ }
+ // Call outside mICameraLock to allow re-entrancy from notification
+ if (currentClient != 0) {
+ currentClient->dataCallbackTimestamp(timestamp,
+ CAMERA_MSG_VIDEO_FRAME,
+ mRecordingHeap->mBuffers[heapIdx]);
}
}
@@ -1999,7 +2280,7 @@ status_t Camera2Client::buildDefaultParameters() {
0);
params.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
- formatEnumToString(HAL_PIXEL_FORMAT_YCrCb_420_SP));
+ formatEnumToString(kRecordingFormat));
params.set(CameraParameters::KEY_RECORDING_HINT,
CameraParameters::FALSE);
@@ -2126,15 +2407,13 @@ status_t Camera2Client::updateCaptureStream() {
mCaptureWindow = new SurfaceTextureClient(
mCaptureConsumer->getProducerInterface());
// Create memory for API consumption
- mCaptureHeap = new MemoryHeapBase(maxJpegSize.data.i32[0], 0,
- "Camera2Client::CaptureHeap");
- if (mCaptureHeap->getSize() == 0) {
+ mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1,
+ "Camera2Client::CaptureHeap");
+ if (mCaptureHeap->mHeap->getSize() == 0) {
ALOGE("%s: Camera %d: Unable to allocate memory for capture",
__FUNCTION__, mCameraId);
return NO_MEMORY;
}
- mCaptureMemory = new MemoryBase(mCaptureHeap,
- 0, maxJpegSize.data.i32[0]);
}
if (mCaptureStreamId != NO_STREAM) {
@@ -2243,6 +2522,81 @@ status_t Camera2Client::updateCaptureRequest() {
return OK;
}
+status_t Camera2Client::updateRecordingRequest() {
+ ATRACE_CALL();
+ status_t res;
+ if (mRecordingRequest == NULL) {
+ res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_VIDEO_RECORD,
+ &mRecordingRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create default recording request:"
+ " %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = updateRequestCommon(mRecordingRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update common entries of recording "
+ "request: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t Camera2Client::updateRecordingStream() {
+ status_t res;
+
+ if (mRecordingConsumer == 0) {
+ // Create CPU buffer queue endpoint
+ mRecordingConsumer = new CpuConsumer(1);
+ mRecordingConsumer->setFrameAvailableListener(new RecordingWaiter(this));
+ mRecordingConsumer->setName(String8("Camera2Client::RecordingConsumer"));
+ mRecordingWindow = new SurfaceTextureClient(
+ mRecordingConsumer->getProducerInterface());
+ // Allocate memory later, since we don't know buffer size until receipt
+ }
+
+ if (mRecordingStreamId != NO_STREAM) {
+ // Check if stream parameters have to change
+ uint32_t currentWidth, currentHeight;
+ res = mDevice->getStreamInfo(mRecordingStreamId,
+ &currentWidth, &currentHeight, 0);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error querying recording output stream info: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ if (currentWidth != (uint32_t)mParameters.videoWidth ||
+ currentHeight != (uint32_t)mParameters.videoHeight) {
+ // TODO: Should wait to be sure previous recording has finished
+ res = mDevice->deleteStream(mRecordingStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete old output stream "
+ "for recording: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ mRecordingStreamId = NO_STREAM;
+ }
+ }
+
+ if (mRecordingStreamId == NO_STREAM) {
+ res = mDevice->createStream(mRecordingWindow,
+ mParameters.videoWidth, mParameters.videoHeight,
+ kRecordingFormat, 0, &mRecordingStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't create output stream for recording: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ return OK;
+}
+
status_t Camera2Client::updateRequestCommon(camera_metadata_t *request) {
ATRACE_CALL();
status_t res;
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 2dc02bc..8d410f1 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -174,39 +174,109 @@ private:
/** Camera device-related private members */
- // Simple listener that forwards frame available notifications from
- // a CPU consumer to the capture notification
- class CaptureWaiter: public CpuConsumer::FrameAvailableListener {
- public:
- CaptureWaiter(Camera2Client *parent) : mParent(parent) {}
- void onFrameAvailable() { mParent->onCaptureAvailable(); }
- private:
- Camera2Client *mParent;
- };
-
- void onCaptureAvailable();
+ class Camera2Heap;
// Number of zoom steps to simulate
static const unsigned int NUM_ZOOM_STEPS = 10;
- // Used with mPreviewStreamId, mCaptureStreamId
+ // Used with stream IDs
static const int NO_STREAM = -1;
- sp<IBinder> mPreviewSurface;
- sp<ANativeWindow> mPreviewWindow;
+ /* Preview related members */
int mPreviewStreamId;
camera_metadata_t *mPreviewRequest;
+ sp<IBinder> mPreviewSurface;
+ sp<ANativeWindow> mPreviewWindow;
+ // Update preview request based on mParameters
+ status_t updatePreviewRequest();
+ // Update preview stream based on mParameters
+ status_t updatePreviewStream();
+
+ /* Still image capture related members */
int mCaptureStreamId;
sp<CpuConsumer> mCaptureConsumer;
sp<ANativeWindow> mCaptureWindow;
+ // Simple listener that forwards frame available notifications from
+ // a CPU consumer to the capture notification
+ class CaptureWaiter: public CpuConsumer::FrameAvailableListener {
+ public:
+ CaptureWaiter(Camera2Client *parent) : mParent(parent) {}
+ void onFrameAvailable() { mParent->onCaptureAvailable(); }
+ private:
+ Camera2Client *mParent;
+ };
sp<CaptureWaiter> mCaptureWaiter;
camera_metadata_t *mCaptureRequest;
- sp<MemoryHeapBase> mCaptureHeap;
- sp<MemoryBase> mCaptureMemory;
+ sp<Camera2Heap> mCaptureHeap;
+ // Handle captured image buffers
+ void onCaptureAvailable();
+ // Update capture request based on mParameters
+ status_t updateCaptureRequest();
+ // Update capture stream based on mParameters
+ status_t updateCaptureStream();
+
+ /* Recording related members */
+
+ int mRecordingStreamId;
+ sp<CpuConsumer> mRecordingConsumer;
+ sp<ANativeWindow> mRecordingWindow;
+ // Simple listener that forwards frame available notifications from
+ // a CPU consumer to the recording notification
+ class RecordingWaiter: public CpuConsumer::FrameAvailableListener {
+ public:
+ RecordingWaiter(Camera2Client *parent) : mParent(parent) {}
+ void onFrameAvailable() { mParent->onRecordingFrameAvailable(); }
+ private:
+ Camera2Client *mParent;
+ };
+ sp<RecordingWaiter> mRecordingWaiter;
+ camera_metadata_t *mRecordingRequest;
+ sp<Camera2Heap> mRecordingHeap;
+
+ // TODO: This needs to be queried from somewhere, or the BufferQueue needs
+ // to be passed all the way to stagefright
+ static const size_t kRecordingHeapCount = 4;
+ static const uint32_t kRecordingFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ size_t mRecordingHeapHead, mRecordingHeapFree;
+ // Handle new recording image buffers
+ void onRecordingFrameAvailable();
+ // Update recording request based on mParameters
+ status_t updateRecordingRequest();
+ // Update recording stream based on mParameters
+ status_t updateRecordingStream();
+
+ /** Camera2Device instance wrapping HAL2 entry */
sp<Camera2Device> mDevice;
+ /** Utility members */
+
+ // Utility class for managing a set of IMemory blocks
+ class Camera2Heap : public RefBase {
+ public:
+ Camera2Heap(size_t buf_size, uint_t num_buffers = 1,
+ const char *name = NULL) :
+ mBufSize(buf_size),
+ mNumBufs(num_buffers) {
+ mHeap = new MemoryHeapBase(buf_size * num_buffers, 0, name);
+ mBuffers = new sp<MemoryBase>[mNumBufs];
+ for (uint_t i = 0; i < mNumBufs; i++)
+ mBuffers[i] = new MemoryBase(mHeap,
+ i * mBufSize,
+ mBufSize);
+ }
+
+ virtual ~Camera2Heap()
+ {
+ delete [] mBuffers;
+ }
+
+ size_t mBufSize;
+ uint_t mNumBufs;
+ sp<MemoryHeapBase> mHeap;
+ sp<MemoryBase> *mBuffers;
+ };
// Get values for static camera info entry. min/maxCount are used for error
// checking the number of values in the entry. 0 for max/minCount means to
@@ -215,22 +285,10 @@ private:
camera_metadata_entry_t staticInfo(uint32_t tag,
size_t minCount=0, size_t maxCount=0);
- /** Utility methods */
-
// Convert static camera info from a camera2 device to the
// old API parameter map.
status_t buildDefaultParameters();
- // Update preview request based on mParameters
- status_t updatePreviewRequest();
- // Update preview stream based on mParameters
- status_t updatePreviewStream();
-
- // Update capture request based on mParameters
- status_t updateCaptureRequest();
- // Update capture stream based on mParameters
- status_t updateCaptureStream();
-
// Update parameters all requests use, based on mParameters
status_t updateRequestCommon(camera_metadata_t *request);
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 8d07eee..54dde80 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -239,9 +239,9 @@ status_t Camera2Device::deleteStream(int id) {
for (StreamList::iterator streamI = mStreams.begin();
streamI != mStreams.end(); streamI++) {
if ((*streamI)->getId() == id) {
- status_t res = (*streamI)->disconnect();
+ status_t res = (*streamI)->release();
if (res != OK) {
- ALOGE("%s: Unable to disconnect stream %d from HAL device: "
+ ALOGE("%s: Unable to release stream %d from HAL device: "
"%s (%d)", __FUNCTION__, id, strerror(-res), res);
return res;
}
@@ -615,7 +615,7 @@ int Camera2Device::MetadataQueue::producer_enqueue(
#endif
Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
- mState(DISCONNECTED),
+ mState(RELEASED),
mDevice(d),
mId(-1),
mWidth(0), mHeight(0), mFormat(0), mSize(0), mUsage(0),
@@ -633,7 +633,9 @@ Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
}
Camera2Device::StreamAdapter::~StreamAdapter() {
- disconnect();
+ if (mState != RELEASED) {
+ release();
+ }
}
status_t Camera2Device::StreamAdapter::connectToDevice(
@@ -641,12 +643,15 @@ status_t Camera2Device::StreamAdapter::connectToDevice(
uint32_t width, uint32_t height, int format, size_t size) {
status_t res;
- if (mState != DISCONNECTED) return INVALID_OPERATION;
+ if (mState != RELEASED) return INVALID_OPERATION;
if (consumer == NULL) {
ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__);
return BAD_VALUE;
}
+ ALOGV("%s: New stream parameters %d x %d, format 0x%x, size %d",
+ __FUNCTION__, width, height, format, size);
+
mConsumerInterface = consumer;
mWidth = width;
mHeight = height;
@@ -668,6 +673,10 @@ status_t Camera2Device::StreamAdapter::connectToDevice(
return res;
}
+ ALOGV("%s: Allocated stream id %d, actual format 0x%x, "
+ "usage 0x%x, producer wants %d buffers", __FUNCTION__,
+ id, formatActual, usage, maxBuffers);
+
mId = id;
mFormat = formatActual;
mUsage = usage;
@@ -737,8 +746,8 @@ status_t Camera2Device::StreamAdapter::connectToDevice(
}
mMaxConsumerBuffers = maxConsumerBuffers;
- ALOGV("%s: Producer wants %d buffers, consumer wants %d", __FUNCTION__,
- mMaxProducerBuffers, mMaxConsumerBuffers);
+ ALOGV("%s: Consumer wants %d buffers", __FUNCTION__,
+ mMaxConsumerBuffers);
mTotalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers;
mActiveBuffers = 0;
@@ -761,7 +770,7 @@ status_t Camera2Device::StreamAdapter::connectToDevice(
res = native_window_dequeue_buffer_and_wait(mConsumerInterface.get(),
&anwBuffers[bufferIdx]);
if (res != OK) {
- ALOGE("%s: Unable to dequeue buffer %d for initial registration for"
+ ALOGE("%s: Unable to dequeue buffer %d for initial registration for "
"stream %d", __FUNCTION__, bufferIdx, mId);
goto cleanUpBuffers;
}
@@ -795,8 +804,9 @@ cleanUpBuffers:
return res;
}
-status_t Camera2Device::StreamAdapter::disconnect() {
+status_t Camera2Device::StreamAdapter::release() {
status_t res;
+ ALOGV("%s: Releasing stream %d", __FUNCTION__, mId);
if (mState >= ALLOCATED) {
res = mDevice->ops->release_stream(mDevice, mId);
if (res != OK) {
@@ -815,7 +825,7 @@ status_t Camera2Device::StreamAdapter::disconnect() {
}
}
mId = -1;
- mState = DISCONNECTED;
+ mState = RELEASED;
return OK;
}
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
index 1116be0..4ac63df 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -219,7 +219,7 @@ class Camera2Device : public virtual RefBase {
status_t connectToDevice(sp<ANativeWindow> consumer,
uint32_t width, uint32_t height, int format, size_t size);
- status_t disconnect();
+ status_t release();
status_t setTransform(int transform);
@@ -236,7 +236,7 @@ class Camera2Device : public virtual RefBase {
private:
enum {
ERROR = -1,
- DISCONNECTED = 0,
+ RELEASED = 0,
ALLOCATED,
CONNECTED,
ACTIVE