summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2012-09-26 10:45:47 -0700
committerEino-Ville Talvala <etalvala@google.com>2012-09-28 17:56:48 -0700
commit73bbd1f1c493835f191ea2b0b72439292496b40a (patch)
tree136a98ae9ea18efb4de1dc43c6be4a5fc5422eb6
parent0517e304d0cce25653a033e3cb00172d54ba251d (diff)
Camera2: Refactor preview/recording management to separate class.
Untangle preview/recording management from main class to simplify callpaths; in preparation for fixing several HAL/app interactions bugs. Bug: 7172543 Bug: 7159577 Bug: 7107220 Change-Id: Iab5503f66b35d88a1524111536a484c9e33fd934
-rw-r--r--services/camera/libcameraservice/Android.mk1
-rw-r--r--services/camera/libcameraservice/Camera2Client.cpp566
-rw-r--r--services/camera/libcameraservice/Camera2Client.h44
-rw-r--r--services/camera/libcameraservice/camera2/JpegProcessor.cpp2
-rw-r--r--services/camera/libcameraservice/camera2/JpegProcessor.h2
-rw-r--r--services/camera/libcameraservice/camera2/StreamingProcessor.cpp604
-rw-r--r--services/camera/libcameraservice/camera2/StreamingProcessor.h108
7 files changed, 794 insertions, 533 deletions
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index c7927fe3..eff47c84 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -14,6 +14,7 @@ LOCAL_SRC_FILES:= \
camera2/CameraMetadata.cpp \
camera2/Parameters.cpp \
camera2/FrameProcessor.cpp \
+ camera2/StreamingProcessor.cpp \
camera2/JpegProcessor.cpp \
camera2/CallbackProcessor.cpp \
camera2/ZslProcessor.cpp \
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index d315abbd..33e0b56a 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -24,7 +24,6 @@
#include <cutils/properties.h>
#include <gui/SurfaceTextureClient.h>
#include <gui/Surface.h>
-#include <media/hardware/MetadataBufferType.h>
#include "camera2/Parameters.h"
#include "Camera2Client.h"
@@ -52,10 +51,7 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
Client(cameraService, cameraClient,
cameraId, cameraFacing, clientPid),
mSharedCameraClient(cameraClient),
- mParameters(cameraId, cameraFacing),
- mPreviewStreamId(NO_STREAM),
- mRecordingStreamId(NO_STREAM),
- mRecordingHeapCount(kDefaultRecordingHeapCount)
+ mParameters(cameraId, cameraFacing)
{
ATRACE_CALL();
ALOGI("Camera %d: Opened", cameraId);
@@ -101,6 +97,8 @@ status_t Camera2Client::initialize(camera_module_t *module)
String8 threadName;
+ mStreamingProcessor = new StreamingProcessor(this);
+
mFrameProcessor = new FrameProcessor(this);
threadName = String8::format("C2-%d-FrameProc",
mCameraId);
@@ -140,9 +138,12 @@ Camera2Client::~Camera2Client() {
mDestructionStarted = true;
- // Rewrite mClientPid to allow shutdown by CameraService
- mClientPid = getCallingPid();
- disconnect();
+ SharedParameters::Lock l(mParameters);
+ if (l.mParameters.state != Parameters::DISCONNECTED) {
+ // Rewrite mClientPid to allow shutdown by CameraService
+ mClientPid = getCallingPid();
+ disconnect();
+ }
ALOGI("Camera %d: Closed", mCameraId);
}
@@ -314,25 +315,9 @@ status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
getCaptureStreamId());
result.appendFormat(" Recording stream ID: %d\n",
getRecordingStreamId());
+ write(fd, result.string(), result.size());
- result.append(" Current requests:\n");
- if (mPreviewRequest.entryCount() != 0) {
- result.append(" Preview request:\n");
- write(fd, result.string(), result.size());
- mPreviewRequest.dump(fd, 2, 6);
- } else {
- result.append(" Preview request: undefined\n");
- write(fd, result.string(), result.size());
- }
-
- if (mRecordingRequest.entryCount() != 0) {
- result = " Recording request:\n";
- write(fd, result.string(), result.size());
- mRecordingRequest.dump(fd, 2, 6);
- } else {
- result = " Recording request: undefined\n";
- write(fd, result.string(), result.size());
- }
+ mStreamingProcessor->dump(fd, args);
mCaptureSequencer->dump(fd, args);
@@ -373,20 +358,10 @@ void Camera2Client::disconnect() {
l.mParameters.state = Parameters::DISCONNECTED;
}
- if (mPreviewStreamId != NO_STREAM) {
- mDevice->deleteStream(mPreviewStreamId);
- mPreviewStreamId = NO_STREAM;
- }
-
+ mStreamingProcessor->deletePreviewStream();
+ mStreamingProcessor->deleteRecordingStream();
mJpegProcessor->deleteStream();
-
- if (mRecordingStreamId != NO_STREAM) {
- mDevice->deleteStream(mRecordingStreamId);
- mRecordingStreamId = NO_STREAM;
- }
-
mCallbackProcessor->deleteStream();
-
mZslProcessor->deleteStream();
mFrameProcessor->requestExit();
@@ -546,24 +521,13 @@ status_t Camera2Client::setPreviewWindowL(const sp<IBinder>& binder,
break;
}
- if (mPreviewStreamId != NO_STREAM) {
- res = mDevice->waitUntilDrained();
- if (res != OK) {
- ALOGE("%s: Error waiting for preview to drain: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- res = mDevice->deleteStream(mPreviewStreamId);
- if (res != OK) {
- ALOGE("%s: Unable to delete old preview stream: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- mPreviewStreamId = NO_STREAM;
- }
-
mPreviewSurface = binder;
- mPreviewWindow = window;
+ res = mStreamingProcessor->setPreviewWindow(window);
+ if (res != OK) {
+ ALOGE("%s: Unable to set new preview window: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
if (l.mParameters.state == Parameters::WAITING_FOR_PREVIEW_WINDOW) {
return startPreviewL(l.mParameters, false);
@@ -637,18 +601,20 @@ status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
return INVALID_OPERATION;
}
- if (mPreviewWindow == 0) {
+ if (!mStreamingProcessor->haveValidPreviewWindow()) {
params.state = Parameters::WAITING_FOR_PREVIEW_WINDOW;
return OK;
}
params.state = Parameters::STOPPED;
- res = updatePreviewStream(params);
+ res = mStreamingProcessor->updatePreviewStream(params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update preview stream: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+
+ Vector<uint8_t> outputStreams;
bool callbacksEnabled = params.previewCallbackFlags &
CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
if (callbacksEnabled) {
@@ -658,6 +624,7 @@ status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+ outputStreams.push(getCallbackStreamId());
}
if (params.zslMode && !params.recordingHint) {
res = mZslProcessor->updateStream(params);
@@ -666,38 +633,28 @@ status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+ outputStreams.push(getZslStreamId());
}
- CameraMetadata *request;
+ outputStreams.push(getPreviewStreamId());
+
if (!params.recordingHint) {
- if (mPreviewRequest.entryCount() == 0) {
- res = updatePreviewRequest(params);
+ if (!restart) {
+ res = mStreamingProcessor->updatePreviewRequest(params);
if (res != OK) {
- ALOGE("%s: Camera %d: Unable to create preview request: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
+ ALOGE("%s: Camera %d: Can't set up preview request: "
+ "%s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
return res;
}
}
- request = &mPreviewRequest;
+ res = mStreamingProcessor->startStream(StreamingProcessor::PREVIEW,
+ outputStreams);
} else {
// With recording hint set, we're going to be operating under the
// assumption that the user will record video. To optimize recording
// startup time, create the necessary output streams for recording and
// video snapshot now if they don't already exist.
- if (mRecordingRequest.entryCount() == 0) {
- res = updateRecordingRequest(params);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to create recording preview "
- "request: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- }
- request = &mRecordingRequest;
-
- // TODO: Re-enable recording stream creation/update here once issues are
- // resolved
-
res = mJpegProcessor->updateStream(params);
if (res != OK) {
ALOGE("%s: Camera %d: Can't pre-configure still image "
@@ -705,43 +662,26 @@ status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
- }
-
- Vector<uint8_t> outputStreams;
- outputStreams.push(getPreviewStreamId());
-
- if (callbacksEnabled) {
- outputStreams.push(getCallbackStreamId());
- }
- if (params.zslMode && !params.recordingHint) {
- outputStreams.push(getZslStreamId());
- }
-
- res = request->update(
- ANDROID_REQUEST_OUTPUT_STREAMS,
- outputStreams);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
+ if (!restart) {
+ res = mStreamingProcessor->updateRecordingRequest(params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't set up preview request with "
+ "record hint: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ }
+ res = mStreamingProcessor->startStream(StreamingProcessor::RECORD,
+ outputStreams);
}
- res = request->sort();
if (res != OK) {
- ALOGE("%s: Camera %d: Error sorting preview request: %s (%d)",
+ ALOGE("%s: Camera %d: Unable to start streaming preview: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
- res = mDevice->setStreamingRequest(*request);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to set preview request to start preview: "
- "%s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
params.state = Parameters::PREVIEW;
-
return OK;
}
@@ -776,8 +716,7 @@ void Camera2Client::stopPreviewL() {
case Parameters::RECORD:
// no break - identical to preview
case Parameters::PREVIEW:
- mDevice->clearStreamingRequest();
- mDevice->waitUntilDrained();
+ mStreamingProcessor->stopStream();
// no break
case Parameters::WAITING_FOR_PREVIEW_WINDOW: {
SharedParameters::Lock l(mParameters);
@@ -866,14 +805,24 @@ status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
return INVALID_OPERATION;
}
- mCameraService->playSound(CameraService::SOUND_RECORDING);
+ if (!restart) {
+ mCameraService->playSound(CameraService::SOUND_RECORDING);
+ mStreamingProcessor->updateRecordingRequest(params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
- res = updateRecordingStream(params);
+ res = mStreamingProcessor->updateRecordingStream(params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+
+ Vector<uint8_t> outputStreams;
bool callbacksEnabled = params.previewCallbackFlags &
CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
if (callbacksEnabled) {
@@ -883,54 +832,19 @@ status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+ outputStreams.push(getCallbackStreamId());
}
+ outputStreams.push(getPreviewStreamId());
+ outputStreams.push(getRecordingStreamId());
- if (mRecordingRequest.entryCount() == 0) {
- res = updateRecordingRequest(params);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to create recording request: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- }
-
- if (callbacksEnabled) {
- uint8_t outputStreams[3] ={
- getPreviewStreamId(),
- getRecordingStreamId(),
- getCallbackStreamId()
- };
- res = mRecordingRequest.update(
- ANDROID_REQUEST_OUTPUT_STREAMS,
- outputStreams, 3);
- } else {
- uint8_t outputStreams[2] = {
- getPreviewStreamId(),
- getRecordingStreamId()
- };
- res = mRecordingRequest.update(
- 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 = mRecordingRequest.sort();
+ res = mStreamingProcessor->startStream(StreamingProcessor::RECORD,
+ outputStreams);
if (res != OK) {
- ALOGE("%s: Camera %d: Error sorting recording request: %s (%d)",
+ ALOGE("%s: Camera %d: Unable to start recording stream: %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;
- }
if (params.state < Parameters::RECORD) {
params.state = Parameters::RECORD;
}
@@ -991,60 +905,9 @@ bool Camera2Client::recordingEnabledL() {
void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
ATRACE_CALL();
Mutex::Autolock icl(mICameraLock);
- status_t res;
if ( checkPid(__FUNCTION__) != OK) return;
- SharedParameters::Lock l(mParameters);
-
- // 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;
- }
- uint8_t *data = (uint8_t*)heap->getBase() + offset;
- uint32_t type = *(uint32_t*)data;
- if (type != kMetadataBufferTypeGrallocSource) {
- ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)",
- __FUNCTION__, mCameraId, type, kMetadataBufferTypeGrallocSource);
- return;
- }
-
- // Release the buffer back to the recording queue
-
- buffer_handle_t imgHandle = *(buffer_handle_t*)(data + 4);
-
- size_t itemIndex;
- for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
- const BufferItemConsumer::BufferItem item = mRecordingBuffers[itemIndex];
- if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT &&
- item.mGraphicBuffer->handle == imgHandle) {
- break;
- }
- }
- if (itemIndex == mRecordingBuffers.size()) {
- ALOGE("%s: Camera %d: Can't find buffer_handle_t %p in list of "
- "outstanding buffers", __FUNCTION__, mCameraId, imgHandle);
- return;
- }
-
- ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__, mCameraId,
- imgHandle);
-
- res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to free recording frame (buffer_handle_t: %p):"
- "%s (%d)",
- __FUNCTION__, mCameraId, imgHandle, strerror(-res), res);
- return;
- }
- mRecordingBuffers.replaceAt(itemIndex);
-
- mRecordingHeapFree++;
+ mStreamingProcessor->releaseRecordingFrame(mem);
}
status_t Camera2Client::autoFocus() {
@@ -1222,8 +1085,8 @@ status_t Camera2Client::commandSetDisplayOrientationL(int degrees) {
}
SharedParameters::Lock l(mParameters);
if (transform != l.mParameters.previewTransform &&
- mPreviewStreamId != NO_STREAM) {
- mDevice->setStreamTransform(mPreviewStreamId, transform);
+ getPreviewStreamId() != NO_STREAM) {
+ mDevice->setStreamTransform(getPreviewStreamId(), transform);
}
l.mParameters.previewTransform = transform;
return OK;
@@ -1336,23 +1199,7 @@ status_t Camera2Client::commandSetVideoBufferCountL(size_t count) {
return INVALID_OPERATION;
}
- // 32 is the current upper limit on the video buffer count for BufferQueue
- if (count > 32) {
- ALOGE("%s: Camera %d: Error setting %d as video buffer count value",
- __FUNCTION__, mCameraId, count);
- return BAD_VALUE;
- }
-
- // Need to reallocate memory for heap
- if (mRecordingHeapCount != count) {
- if (mRecordingHeap != 0) {
- mRecordingHeap.clear();
- mRecordingHeap = NULL;
- }
- mRecordingHeapCount = count;
- }
-
- return OK;
+ return mStreamingProcessor->setRecordingBufferCount(count);
}
/** Device-related methods */
@@ -1503,7 +1350,7 @@ camera2::SharedParameters& Camera2Client::getParameters() {
}
int Camera2Client::getPreviewStreamId() const {
- return mPreviewStreamId;
+ return mStreamingProcessor->getPreviewStreamId();
}
int Camera2Client::getCaptureStreamId() const {
@@ -1515,7 +1362,7 @@ int Camera2Client::getCallbackStreamId() const {
}
int Camera2Client::getRecordingStreamId() const {
- return mRecordingStreamId;
+ return mStreamingProcessor->getRecordingStreamId();
}
int Camera2Client::getZslStreamId() const {
@@ -1561,117 +1408,18 @@ const int32_t Camera2Client::kPreviewRequestId;
const int32_t Camera2Client::kRecordRequestId;
const int32_t Camera2Client::kFirstCaptureRequestId;
-void Camera2Client::onRecordingFrameAvailable() {
- ATRACE_CALL();
- status_t res;
- sp<Camera2Heap> recordingHeap;
- size_t heapIdx = 0;
- nsecs_t timestamp;
- {
- SharedParameters::Lock l(mParameters);
-
- BufferItemConsumer::BufferItem imgBuffer;
- res = mRecordingConsumer->acquireBuffer(&imgBuffer);
- if (res != OK) {
- ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return;
- }
- timestamp = imgBuffer.mTimestamp;
-
- mRecordingFrameCount++;
- ALOGV("OnRecordingFrame: Frame %d", mRecordingFrameCount);
-
- // TODO: Signal errors here upstream
- if (l.mParameters.state != Parameters::RECORD &&
- l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
- ALOGV("%s: Camera %d: Discarding recording image buffers received after "
- "recording done",
- __FUNCTION__, mCameraId);
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return;
- }
-
- if (mRecordingHeap == 0) {
- const size_t bufferSize = 4 + sizeof(buffer_handle_t);
- ALOGV("%s: Camera %d: Creating recording heap with %d buffers of "
- "size %d bytes", __FUNCTION__, mCameraId,
- mRecordingHeapCount, bufferSize);
-
- mRecordingHeap = new Camera2Heap(bufferSize, mRecordingHeapCount,
- "Camera2Client::RecordingHeap");
- if (mRecordingHeap->mHeap->getSize() == 0) {
- ALOGE("%s: Camera %d: Unable to allocate memory for recording",
- __FUNCTION__, mCameraId);
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return;
- }
- for (size_t i = 0; i < mRecordingBuffers.size(); i++) {
- if (mRecordingBuffers[i].mBuf !=
- BufferItemConsumer::INVALID_BUFFER_SLOT) {
- ALOGE("%s: Camera %d: Non-empty recording buffers list!",
- __FUNCTION__, mCameraId);
- }
- }
- mRecordingBuffers.clear();
- mRecordingBuffers.setCapacity(mRecordingHeapCount);
- mRecordingBuffers.insertAt(0, mRecordingHeapCount);
-
- mRecordingHeapHead = 0;
- mRecordingHeapFree = mRecordingHeapCount;
- }
-
- if ( mRecordingHeapFree == 0) {
- ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
- __FUNCTION__, mCameraId);
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return;
- }
-
- heapIdx = mRecordingHeapHead;
- mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount;
- 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);
-
- uint8_t *data = (uint8_t*)heap->getBase() + offset;
- uint32_t type = kMetadataBufferTypeGrallocSource;
- *((uint32_t*)data) = type;
- *((buffer_handle_t*)(data + 4)) = imgBuffer.mGraphicBuffer->handle;
- ALOGV("%s: Camera %d: Sending out buffer_handle_t %p",
- __FUNCTION__, mCameraId, imgBuffer.mGraphicBuffer->handle);
- mRecordingBuffers.replaceAt(imgBuffer, heapIdx);
- recordingHeap = mRecordingHeap;
- }
-
- // Call outside locked parameters to allow re-entrancy from notification
- SharedCameraClient::Lock l(mSharedCameraClient);
- if (l.mCameraClient != 0) {
- l.mCameraClient->dataCallbackTimestamp(timestamp,
- CAMERA_MSG_VIDEO_FRAME,
- recordingHeap->mBuffers[heapIdx]);
- }
-}
-
/** Utility methods */
status_t Camera2Client::updateRequests(Parameters &params) {
status_t res;
- res = updatePreviewRequest(params);
+ res = mStreamingProcessor->updatePreviewRequest(params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
- res = updateRecordingRequest(params);
+ res = mStreamingProcessor->updateRecordingRequest(params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -1687,7 +1435,7 @@ status_t Camera2Client::updateRequests(Parameters &params) {
}
} else if (params.state == Parameters::RECORD ||
params.state == Parameters::VIDEO_SNAPSHOT) {
- res = mDevice->setStreamingRequest(mRecordingRequest);
+ res = startRecordingL(params, true);
if (res != OK) {
ALOGE("%s: Camera %d: Error streaming new record request: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -1697,172 +1445,6 @@ status_t Camera2Client::updateRequests(Parameters &params) {
return res;
}
-status_t Camera2Client::updatePreviewStream(const Parameters &params) {
- ATRACE_CALL();
- status_t res;
-
- if (mPreviewStreamId != NO_STREAM) {
- // Check if stream parameters have to change
- uint32_t currentWidth, currentHeight;
- res = mDevice->getStreamInfo(mPreviewStreamId,
- &currentWidth, &currentHeight, 0);
- if (res != OK) {
- ALOGE("%s: Camera %d: Error querying preview stream info: "
- "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- if (currentWidth != (uint32_t)params.previewWidth ||
- currentHeight != (uint32_t)params.previewHeight) {
- ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d",
- __FUNCTION__, mCameraId, currentWidth, currentHeight,
- params.previewWidth, params.previewHeight);
- res = mDevice->waitUntilDrained();
- if (res != OK) {
- ALOGE("%s: Camera %d: Error waiting for preview to drain: "
- "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- res = mDevice->deleteStream(mPreviewStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to delete old output stream "
- "for preview: %s (%d)", __FUNCTION__, mCameraId,
- strerror(-res), res);
- return res;
- }
- mPreviewStreamId = NO_STREAM;
- }
- }
-
- if (mPreviewStreamId == NO_STREAM) {
- res = mDevice->createStream(mPreviewWindow,
- params.previewWidth, params.previewHeight,
- CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0,
- &mPreviewStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- }
-
- res = mDevice->setStreamTransform(mPreviewStreamId,
- params.previewTransform);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to set preview stream transform: "
- "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
-
- return OK;
-}
-
-status_t Camera2Client::updatePreviewRequest(const Parameters &params) {
- ATRACE_CALL();
- status_t res;
- if (mPreviewRequest.entryCount() == 0) {
- res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
- &mPreviewRequest);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to create default preview request: "
- "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- }
-
- res = params.updateRequest(&mPreviewRequest);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update common entries of preview "
- "request: %s (%d)", __FUNCTION__, mCameraId,
- strerror(-res), res);
- return res;
- }
-
- res = mPreviewRequest.update(ANDROID_REQUEST_ID,
- &kPreviewRequestId, 1);
-
- return OK;
-}
-
-status_t Camera2Client::updateRecordingRequest(const Parameters &params) {
- ATRACE_CALL();
- status_t res;
- if (mRecordingRequest.entryCount() == 0) {
- 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 = params.updateRequest(&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(const Parameters &params) {
- status_t res;
-
- if (mRecordingConsumer == 0) {
- // Create CPU buffer queue endpoint. We need one more buffer here so that we can
- // always acquire and free a buffer when the heap is full; otherwise the consumer
- // will have buffers in flight we'll never clear out.
- mRecordingConsumer = new BufferItemConsumer(
- GRALLOC_USAGE_HW_VIDEO_ENCODER,
- mRecordingHeapCount + 1,
- true);
- 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)params.videoWidth ||
- currentHeight != (uint32_t)params.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) {
- mRecordingFrameCount = 0;
- res = mDevice->createStream(mRecordingWindow,
- params.videoWidth, params.videoHeight,
- CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 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;
-}
size_t Camera2Client::calculateBufferSize(int width, int height,
int format, int stride) {
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 1eb024a5..3a9d3072 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -21,17 +21,15 @@
#include "CameraService.h"
#include "camera2/Parameters.h"
#include "camera2/FrameProcessor.h"
+#include "camera2/StreamingProcessor.h"
#include "camera2/JpegProcessor.h"
#include "camera2/ZslProcessor.h"
#include "camera2/CaptureSequencer.h"
#include "camera2/CallbackProcessor.h"
-#include <binder/MemoryBase.h>
-#include <binder/MemoryHeapBase.h>
-#include <gui/CpuConsumer.h>
-#include <gui/BufferItemConsumer.h>
namespace android {
+class IMemory;
/**
* Implements the android.hardware.camera API on top of
* camera device HAL version 2.
@@ -184,15 +182,10 @@ private:
sp<camera2::FrameProcessor> mFrameProcessor;
- /* Preview related members */
+ /* Preview/Recording related members */
- int mPreviewStreamId;
- CameraMetadata mPreviewRequest;
sp<IBinder> mPreviewSurface;
- sp<ANativeWindow> mPreviewWindow;
-
- status_t updatePreviewRequest(const Parameters &params);
- status_t updatePreviewStream(const Parameters &params);
+ sp<camera2::StreamingProcessor> mStreamingProcessor;
/** Preview callback related members */
@@ -204,35 +197,6 @@ private:
sp<camera2::JpegProcessor> mJpegProcessor;
sp<camera2::ZslProcessor> mZslProcessor;
- /* Recording related members */
-
- int mRecordingStreamId;
- int mRecordingFrameCount;
- sp<BufferItemConsumer> mRecordingConsumer;
- sp<ANativeWindow> mRecordingWindow;
- // Simple listener that forwards frame available notifications from
- // a CPU consumer to the recording notification
- class RecordingWaiter: public BufferItemConsumer::FrameAvailableListener {
- public:
- RecordingWaiter(Camera2Client *parent) : mParent(parent) {}
- void onFrameAvailable() { mParent->onRecordingFrameAvailable(); }
- private:
- Camera2Client *mParent;
- };
- sp<RecordingWaiter> mRecordingWaiter;
- CameraMetadata mRecordingRequest;
- sp<camera2::Camera2Heap> mRecordingHeap;
-
- static const size_t kDefaultRecordingHeapCount = 8;
- size_t mRecordingHeapCount;
- Vector<BufferItemConsumer::BufferItem> mRecordingBuffers;
- size_t mRecordingHeapHead, mRecordingHeapFree;
- // Handle new recording image buffers
- void onRecordingFrameAvailable();
-
- status_t updateRecordingRequest(const Parameters &params);
- status_t updateRecordingStream(const Parameters &params);
-
/** Notification-related members */
bool mAfInMotion;
diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.cpp b/services/camera/libcameraservice/camera2/JpegProcessor.cpp
index a40ddcc4..7b368fa8 100644
--- a/services/camera/libcameraservice/camera2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/JpegProcessor.cpp
@@ -20,6 +20,8 @@
#include <netinet/in.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
#include <utils/Log.h>
#include <utils/Trace.h>
diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.h b/services/camera/libcameraservice/camera2/JpegProcessor.h
index 54645194..836bd02b 100644
--- a/services/camera/libcameraservice/camera2/JpegProcessor.h
+++ b/services/camera/libcameraservice/camera2/JpegProcessor.h
@@ -25,11 +25,11 @@
#include <gui/CpuConsumer.h>
#include "Parameters.h"
#include "CameraMetadata.h"
-#include "Camera2Heap.h"
namespace android {
class Camera2Client;
+class MemoryHeapBase;
namespace camera2 {
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
new file mode 100644
index 00000000..140138d6
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera2-StreamingProcessor"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <gui/SurfaceTextureClient.h>
+#include <media/hardware/MetadataBufferType.h>
+
+#include "StreamingProcessor.h"
+#include "Camera2Heap.h"
+#include "../Camera2Client.h"
+#include "../Camera2Device.h"
+
+namespace android {
+namespace camera2 {
+
+StreamingProcessor::StreamingProcessor(wp<Camera2Client> client):
+ mClient(client),
+ mPreviewStreamId(NO_STREAM),
+ mRecordingStreamId(NO_STREAM),
+ mRecordingHeapCount(kDefaultRecordingHeapCount)
+{
+
+}
+
+StreamingProcessor::~StreamingProcessor() {
+ deletePreviewStream();
+ deleteRecordingStream();
+}
+
+status_t StreamingProcessor::setPreviewWindow(sp<ANativeWindow> window) {
+ ATRACE_CALL();
+ status_t res;
+
+ res = deletePreviewStream();
+ if (res != OK) return res;
+
+ Mutex::Autolock m(mMutex);
+
+ mPreviewWindow = window;
+
+ return OK;
+}
+
+bool StreamingProcessor::haveValidPreviewWindow() const {
+ Mutex::Autolock m(mMutex);
+ return mPreviewWindow != 0;
+}
+
+status_t StreamingProcessor::updatePreviewRequest(const Parameters &params) {
+ ATRACE_CALL();
+ status_t res;
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return INVALID_OPERATION;
+
+ Mutex::Autolock m(mMutex);
+ if (mPreviewRequest.entryCount() == 0) {
+ res = client->getCameraDevice()->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+ &mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create default preview request: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = params.updateRequest(&mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update common entries of preview "
+ "request: %s (%d)", __FUNCTION__, client->getCameraId(),
+ strerror(-res), res);
+ return res;
+ }
+
+ res = mPreviewRequest.update(ANDROID_REQUEST_ID,
+ &Camera2Client::kPreviewRequestId, 1);
+
+ return OK;
+}
+
+status_t StreamingProcessor::updatePreviewStream(const Parameters &params) {
+ ATRACE_CALL();
+ Mutex::Autolock m(mMutex);
+
+ status_t res;
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return INVALID_OPERATION;
+ sp<Camera2Device> device = client->getCameraDevice();
+
+ if (mPreviewStreamId != NO_STREAM) {
+ // Check if stream parameters have to change
+ uint32_t currentWidth, currentHeight;
+ res = device->getStreamInfo(mPreviewStreamId,
+ &currentWidth, &currentHeight, 0);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error querying preview stream info: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+ if (currentWidth != (uint32_t)params.previewWidth ||
+ currentHeight != (uint32_t)params.previewHeight) {
+ ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d",
+ __FUNCTION__, client->getCameraId(), currentWidth, currentHeight,
+ params.previewWidth, params.previewHeight);
+ res = device->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error waiting for preview to drain: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+ res = device->deleteStream(mPreviewStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete old output stream "
+ "for preview: %s (%d)", __FUNCTION__, client->getCameraId(),
+ strerror(-res), res);
+ return res;
+ }
+ mPreviewStreamId = NO_STREAM;
+ }
+ }
+
+ if (mPreviewStreamId == NO_STREAM) {
+ res = device->createStream(mPreviewWindow,
+ params.previewWidth, params.previewHeight,
+ CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0,
+ &mPreviewStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
+ __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = device->setStreamTransform(mPreviewStreamId,
+ params.previewTransform);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set preview stream transform: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t StreamingProcessor::deletePreviewStream() {
+ ATRACE_CALL();
+ status_t res;
+
+ Mutex::Autolock m(mMutex);
+
+ if (mPreviewStreamId != NO_STREAM) {
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return INVALID_OPERATION;
+ sp<Camera2Device> device = client->getCameraDevice();
+
+ res = device->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Error waiting for preview to drain: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ res = device->deleteStream(mPreviewStreamId);
+ if (res != OK) {
+ ALOGE("%s: Unable to delete old preview stream: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ mPreviewStreamId = NO_STREAM;
+ }
+ return OK;
+}
+
+status_t StreamingProcessor::getPreviewStreamId() const {
+ Mutex::Autolock m(mMutex);
+ return mPreviewStreamId;
+}
+
+status_t StreamingProcessor::setRecordingBufferCount(size_t count) {
+ ATRACE_CALL();
+ // 32 is the current upper limit on the video buffer count for BufferQueue
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return INVALID_OPERATION;
+ if (count > 32) {
+ ALOGE("%s: Camera %d: Error setting %d as video buffer count value",
+ __FUNCTION__, client->getCameraId(), count);
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock m(mMutex);
+
+ // Need to reallocate memory for heap
+ if (mRecordingHeapCount != count) {
+ if (mRecordingHeap != 0) {
+ mRecordingHeap.clear();
+ mRecordingHeap = NULL;
+ }
+ mRecordingHeapCount = count;
+ }
+
+ return OK;
+}
+
+status_t StreamingProcessor::updateRecordingRequest(const Parameters &params) {
+ ATRACE_CALL();
+ status_t res;
+ Mutex::Autolock m(mMutex);
+
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return INVALID_OPERATION;
+
+ if (mRecordingRequest.entryCount() == 0) {
+ res = client->getCameraDevice()->createDefaultRequest(CAMERA2_TEMPLATE_VIDEO_RECORD,
+ &mRecordingRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create default recording request:"
+ " %s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = params.updateRequest(&mRecordingRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update common entries of recording "
+ "request: %s (%d)", __FUNCTION__, client->getCameraId(),
+ strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t StreamingProcessor::updateRecordingStream(const Parameters &params) {
+ ATRACE_CALL();
+ status_t res;
+ Mutex::Autolock m(mMutex);
+
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return INVALID_OPERATION;
+ sp<Camera2Device> device = client->getCameraDevice();
+
+ if (mRecordingConsumer == 0) {
+ // Create CPU buffer queue endpoint. We need one more buffer here so that we can
+ // always acquire and free a buffer when the heap is full; otherwise the consumer
+ // will have buffers in flight we'll never clear out.
+ mRecordingConsumer = new BufferItemConsumer(
+ GRALLOC_USAGE_HW_VIDEO_ENCODER,
+ mRecordingHeapCount + 1,
+ true);
+ mRecordingConsumer->setFrameAvailableListener(this);
+ mRecordingConsumer->setName(String8("Camera2-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 = device->getStreamInfo(mRecordingStreamId,
+ &currentWidth, &currentHeight, 0);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error querying recording output stream info: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
+ strerror(-res), res);
+ return res;
+ }
+ if (currentWidth != (uint32_t)params.videoWidth ||
+ currentHeight != (uint32_t)params.videoHeight) {
+ // TODO: Should wait to be sure previous recording has finished
+ res = device->deleteStream(mRecordingStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete old output stream "
+ "for recording: %s (%d)", __FUNCTION__,
+ client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+ mRecordingStreamId = NO_STREAM;
+ }
+ }
+
+ if (mRecordingStreamId == NO_STREAM) {
+ mRecordingFrameCount = 0;
+ res = device->createStream(mRecordingWindow,
+ params.videoWidth, params.videoHeight,
+ CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mRecordingStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't create output stream for recording: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
+ strerror(-res), res);
+ return res;
+ }
+ }
+
+ return OK;
+}
+
+status_t StreamingProcessor::deleteRecordingStream() {
+ ATRACE_CALL();
+ status_t res;
+
+ Mutex::Autolock m(mMutex);
+
+ if (mRecordingStreamId != NO_STREAM) {
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return INVALID_OPERATION;
+ sp<Camera2Device> device = client->getCameraDevice();
+
+ res = device->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Error waiting for HAL to drain: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ res = device->deleteStream(mRecordingStreamId);
+ if (res != OK) {
+ ALOGE("%s: Unable to delete recording stream: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ mRecordingStreamId = NO_STREAM;
+ }
+ return OK;
+}
+
+status_t StreamingProcessor::getRecordingStreamId() const {
+ return mRecordingStreamId;
+}
+
+status_t StreamingProcessor::startStream(StreamType type,
+ const Vector<uint8_t> &outputStreams) {
+ ATRACE_CALL();
+ status_t res;
+
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return INVALID_OPERATION;
+
+ Mutex::Autolock m(mMutex);
+
+ CameraMetadata &request = (type == PREVIEW) ?
+ mPreviewRequest : mRecordingRequest;
+
+ res = request.update(
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ outputStreams);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)",
+ __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+
+ res = request.sort();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error sorting preview request: %s (%d)",
+ __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+
+ res = client->getCameraDevice()->setStreamingRequest(request);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set preview request to start preview: "
+ "%s (%d)",
+ __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t StreamingProcessor::stopStream() {
+ ATRACE_CALL();
+ status_t res;
+
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return INVALID_OPERATION;
+ sp<Camera2Device> device = client->getCameraDevice();
+
+ res = device->clearStreamingRequest();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't clear stream request: %s (%d)",
+ __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+ res = device->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+ __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+ return OK;
+}
+
+void StreamingProcessor::onFrameAvailable() {
+ ATRACE_CALL();
+ status_t res;
+ sp<Camera2Heap> recordingHeap;
+ size_t heapIdx = 0;
+ nsecs_t timestamp;
+
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return;
+
+ {
+ Mutex::Autolock m(mMutex);
+ BufferItemConsumer::BufferItem imgBuffer;
+ res = mRecordingConsumer->acquireBuffer(&imgBuffer);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)",
+ __FUNCTION__, client->getCameraId(), strerror(-res), res);
+ return;
+ }
+ timestamp = imgBuffer.mTimestamp;
+
+ mRecordingFrameCount++;
+ ALOGV("OnRecordingFrame: Frame %d", mRecordingFrameCount);
+
+ {
+ SharedParameters::Lock l(client->getParameters());
+ // TODO: Signal errors here upstream
+ if (l.mParameters.state != Parameters::RECORD &&
+ l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
+ ALOGV("%s: Camera %d: Discarding recording image buffers "
+ "received after recording done", __FUNCTION__,
+ client->getCameraId());
+ mRecordingConsumer->releaseBuffer(imgBuffer);
+ return;
+ }
+ }
+
+ if (mRecordingHeap == 0) {
+ const size_t bufferSize = 4 + sizeof(buffer_handle_t);
+ ALOGV("%s: Camera %d: Creating recording heap with %d buffers of "
+ "size %d bytes", __FUNCTION__, client->getCameraId(),
+ mRecordingHeapCount, bufferSize);
+
+ mRecordingHeap = new Camera2Heap(bufferSize, mRecordingHeapCount,
+ "Camera2Client::RecordingHeap");
+ if (mRecordingHeap->mHeap->getSize() == 0) {
+ ALOGE("%s: Camera %d: Unable to allocate memory for recording",
+ __FUNCTION__, client->getCameraId());
+ mRecordingConsumer->releaseBuffer(imgBuffer);
+ return;
+ }
+ for (size_t i = 0; i < mRecordingBuffers.size(); i++) {
+ if (mRecordingBuffers[i].mBuf !=
+ BufferItemConsumer::INVALID_BUFFER_SLOT) {
+ ALOGE("%s: Camera %d: Non-empty recording buffers list!",
+ __FUNCTION__, client->getCameraId());
+ }
+ }
+ mRecordingBuffers.clear();
+ mRecordingBuffers.setCapacity(mRecordingHeapCount);
+ mRecordingBuffers.insertAt(0, mRecordingHeapCount);
+
+ mRecordingHeapHead = 0;
+ mRecordingHeapFree = mRecordingHeapCount;
+ }
+
+ if ( mRecordingHeapFree == 0) {
+ ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
+ __FUNCTION__, client->getCameraId());
+ mRecordingConsumer->releaseBuffer(imgBuffer);
+ return;
+ }
+
+ heapIdx = mRecordingHeapHead;
+ mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount;
+ mRecordingHeapFree--;
+
+ ALOGV("%s: Camera %d: Timestamp %lld",
+ __FUNCTION__, client->getCameraId(), timestamp);
+
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap =
+ mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset,
+ &size);
+
+ uint8_t *data = (uint8_t*)heap->getBase() + offset;
+ uint32_t type = kMetadataBufferTypeGrallocSource;
+ *((uint32_t*)data) = type;
+ *((buffer_handle_t*)(data + 4)) = imgBuffer.mGraphicBuffer->handle;
+ ALOGV("%s: Camera %d: Sending out buffer_handle_t %p",
+ __FUNCTION__, client->getCameraId(),
+ imgBuffer.mGraphicBuffer->handle);
+ mRecordingBuffers.replaceAt(imgBuffer, heapIdx);
+ recordingHeap = mRecordingHeap;
+ }
+
+ // Call outside locked parameters to allow re-entrancy from notification
+ Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
+ if (l.mCameraClient != 0) {
+ l.mCameraClient->dataCallbackTimestamp(timestamp,
+ CAMERA_MSG_VIDEO_FRAME,
+ recordingHeap->mBuffers[heapIdx]);
+ }
+}
+
+void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) {
+ ATRACE_CALL();
+ status_t res;
+
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return;
+
+ Mutex::Autolock m(mMutex);
+ // 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__, client->getCameraId(),
+ heap->getHeapID(), mRecordingHeap->mHeap->getHeapID());
+ return;
+ }
+ uint8_t *data = (uint8_t*)heap->getBase() + offset;
+ uint32_t type = *(uint32_t*)data;
+ if (type != kMetadataBufferTypeGrallocSource) {
+ ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)",
+ __FUNCTION__, client->getCameraId(), type,
+ kMetadataBufferTypeGrallocSource);
+ return;
+ }
+
+ // Release the buffer back to the recording queue
+
+ buffer_handle_t imgHandle = *(buffer_handle_t*)(data + 4);
+
+ size_t itemIndex;
+ for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
+ const BufferItemConsumer::BufferItem item =
+ mRecordingBuffers[itemIndex];
+ if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT &&
+ item.mGraphicBuffer->handle == imgHandle) {
+ break;
+ }
+ }
+ if (itemIndex == mRecordingBuffers.size()) {
+ ALOGE("%s: Camera %d: Can't find buffer_handle_t %p in list of "
+ "outstanding buffers", __FUNCTION__, client->getCameraId(),
+ imgHandle);
+ return;
+ }
+
+ ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__,
+ client->getCameraId(), imgHandle);
+
+ res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to free recording frame "
+ "(buffer_handle_t: %p): %s (%d)", __FUNCTION__,
+ client->getCameraId(), imgHandle, strerror(-res), res);
+ return;
+ }
+ mRecordingBuffers.replaceAt(itemIndex);
+
+ mRecordingHeapFree++;
+}
+
+
+status_t StreamingProcessor::dump(int fd, const Vector<String16>& args) {
+ String8 result;
+
+ result.append(" Current requests:\n");
+ if (mPreviewRequest.entryCount() != 0) {
+ result.append(" Preview request:\n");
+ write(fd, result.string(), result.size());
+ mPreviewRequest.dump(fd, 2, 6);
+ } else {
+ result.append(" Preview request: undefined\n");
+ write(fd, result.string(), result.size());
+ }
+
+ if (mRecordingRequest.entryCount() != 0) {
+ result = " Recording request:\n";
+ write(fd, result.string(), result.size());
+ mRecordingRequest.dump(fd, 2, 6);
+ } else {
+ result = " Recording request: undefined\n";
+ write(fd, result.string(), result.size());
+ }
+
+ return OK;
+}
+
+}; // namespace camera2
+}; // namespace android
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.h b/services/camera/libcameraservice/camera2/StreamingProcessor.h
new file mode 100644
index 00000000..ac586143
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERA2_STREAMINGPROCESSOR_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2_STREAMINGPROCESSOR_H
+
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+#include <gui/BufferItemConsumer.h>
+
+#include "Parameters.h"
+#include "CameraMetadata.h"
+
+namespace android {
+
+class Camera2Client;
+class IMemory;
+
+namespace camera2 {
+
+class Camera2Heap;
+
+/**
+ * Management and processing for preview and recording streams
+ */
+class StreamingProcessor: public BufferItemConsumer::FrameAvailableListener {
+ public:
+ StreamingProcessor(wp<Camera2Client> client);
+ ~StreamingProcessor();
+
+ status_t setPreviewWindow(sp<ANativeWindow> window);
+
+ bool haveValidPreviewWindow() const;
+
+ status_t updatePreviewRequest(const Parameters &params);
+ status_t updatePreviewStream(const Parameters &params);
+ status_t deletePreviewStream();
+ int getPreviewStreamId() const;
+
+ status_t setRecordingBufferCount(size_t count);
+ status_t updateRecordingRequest(const Parameters &params);
+ status_t updateRecordingStream(const Parameters &params);
+ status_t deleteRecordingStream();
+ int getRecordingStreamId() const;
+
+ enum StreamType {
+ PREVIEW,
+ RECORD
+ };
+ status_t startStream(StreamType type,
+ const Vector<uint8_t> &outputStreams);
+
+ status_t stopStream();
+
+ // Callback for new recording frames from HAL
+ virtual void onFrameAvailable();
+ // Callback from stagefright which returns used recording frames
+ void releaseRecordingFrame(const sp<IMemory>& mem);
+
+ status_t dump(int fd, const Vector<String16>& args);
+
+ private:
+ mutable Mutex mMutex;
+
+ enum {
+ NO_STREAM = -1
+ };
+
+ wp<Camera2Client> mClient;
+
+ // Preview-related members
+ int mPreviewStreamId;
+ CameraMetadata mPreviewRequest;
+ sp<ANativeWindow> mPreviewWindow;
+
+ // Recording-related members
+ int mRecordingStreamId;
+ int mRecordingFrameCount;
+ sp<BufferItemConsumer> mRecordingConsumer;
+ sp<ANativeWindow> mRecordingWindow;
+ CameraMetadata mRecordingRequest;
+ sp<camera2::Camera2Heap> mRecordingHeap;
+
+ static const size_t kDefaultRecordingHeapCount = 8;
+ size_t mRecordingHeapCount;
+ Vector<BufferItemConsumer::BufferItem> mRecordingBuffers;
+ size_t mRecordingHeapHead, mRecordingHeapFree;
+
+};
+
+
+}; // namespace camera2
+}; // namespace android
+
+#endif