diff options
7 files changed, 794 insertions, 533 deletions
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index c7927fe..eff47c8 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 d315abb..33e0b56 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms) { 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 ¶ms) { } } 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 ¶ms) { return res; } -status_t Camera2Client::updatePreviewStream(const Parameters ¶ms) { - ATRACE_CALL(); - status_t res; - - if (mPreviewStreamId != NO_STREAM) { - // Check if stream parameters have to change - uint32_t currentWidth, currentHeight; - res = mDevice->getStreamInfo(mPreviewStreamId, - ¤tWidth, ¤tHeight, 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 ¶ms) { - 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 ¶ms) { - 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 ¶ms) { - 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, - ¤tWidth, ¤tHeight, 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 1eb024a..3a9d307 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 ¶ms); - status_t updatePreviewStream(const Parameters ¶ms); + 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 ¶ms); - status_t updateRecordingStream(const Parameters ¶ms); - /** Notification-related members */ bool mAfInMotion; diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.cpp b/services/camera/libcameraservice/camera2/JpegProcessor.cpp index a40ddcc..7b368fa 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 5464519..836bd02 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 0000000..140138d --- /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 ¶ms) { + 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 ¶ms) { + 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, + ¤tWidth, ¤tHeight, 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 ¶ms) { + 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 ¶ms) { + 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, + ¤tWidth, ¤tHeight, 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 0000000..ac58614 --- /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 ¶ms); + status_t updatePreviewStream(const Parameters ¶ms); + status_t deletePreviewStream(); + int getPreviewStreamId() const; + + status_t setRecordingBufferCount(size_t count); + status_t updateRecordingRequest(const Parameters ¶ms); + status_t updateRecordingStream(const Parameters ¶ms); + 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 |