437 lines
12 KiB
C++
437 lines
12 KiB
C++
/*
|
|
**
|
|
** Copyright (C) 2013, 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_NDEBUG 0
|
|
#define LOG_TAG "ProCamera"
|
|
#include <utils/Log.h>
|
|
#include <utils/threads.h>
|
|
#include <utils/Mutex.h>
|
|
|
|
#include <binder/IPCThreadState.h>
|
|
#include <binder/IServiceManager.h>
|
|
#include <binder/IMemory.h>
|
|
|
|
#include <camera/ProCamera.h>
|
|
#include <camera/IProCameraUser.h>
|
|
#include <camera/IProCameraCallbacks.h>
|
|
|
|
#include <gui/IGraphicBufferProducer.h>
|
|
|
|
#include <system/camera_metadata.h>
|
|
|
|
namespace android {
|
|
|
|
sp<ProCamera> ProCamera::connect(int cameraId)
|
|
{
|
|
return CameraBaseT::connect(cameraId, String16(),
|
|
ICameraService::USE_CALLING_UID);
|
|
}
|
|
|
|
ProCamera::ProCamera(int cameraId)
|
|
: CameraBase(cameraId)
|
|
{
|
|
}
|
|
|
|
CameraTraits<ProCamera>::TCamConnectService CameraTraits<ProCamera>::fnConnectService =
|
|
&ICameraService::connectPro;
|
|
|
|
ProCamera::~ProCamera()
|
|
{
|
|
|
|
}
|
|
|
|
/* IProCameraUser's implementation */
|
|
|
|
// callback from camera service
|
|
void ProCamera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
|
|
{
|
|
return CameraBaseT::notifyCallback(msgType, ext1, ext2);
|
|
}
|
|
|
|
void ProCamera::onLockStatusChanged(
|
|
IProCameraCallbacks::LockStatus newLockStatus)
|
|
{
|
|
ALOGV("%s: newLockStatus = %d", __FUNCTION__, newLockStatus);
|
|
|
|
sp<ProCameraListener> listener;
|
|
{
|
|
Mutex::Autolock _l(mLock);
|
|
listener = mListener;
|
|
}
|
|
if (listener != NULL) {
|
|
switch (newLockStatus) {
|
|
case IProCameraCallbacks::LOCK_ACQUIRED:
|
|
listener->onLockAcquired();
|
|
break;
|
|
case IProCameraCallbacks::LOCK_RELEASED:
|
|
listener->onLockReleased();
|
|
break;
|
|
case IProCameraCallbacks::LOCK_STOLEN:
|
|
listener->onLockStolen();
|
|
break;
|
|
default:
|
|
ALOGE("%s: Unknown lock status: %d",
|
|
__FUNCTION__, newLockStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProCamera::onResultReceived(int32_t requestId, camera_metadata* result) {
|
|
ALOGV("%s: requestId = %d, result = %p", __FUNCTION__, requestId, result);
|
|
|
|
sp<ProCameraListener> listener;
|
|
{
|
|
Mutex::Autolock _l(mLock);
|
|
listener = mListener;
|
|
}
|
|
|
|
CameraMetadata tmp(result);
|
|
|
|
// Unblock waitForFrame(id) callers
|
|
{
|
|
Mutex::Autolock al(mWaitMutex);
|
|
mMetadataReady = true;
|
|
mLatestMetadata = tmp; // make copy
|
|
mWaitCondition.broadcast();
|
|
}
|
|
|
|
result = tmp.release();
|
|
|
|
if (listener != NULL) {
|
|
listener->onResultReceived(requestId, result);
|
|
} else {
|
|
free_camera_metadata(result);
|
|
}
|
|
|
|
}
|
|
|
|
status_t ProCamera::exclusiveTryLock()
|
|
{
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NO_INIT;
|
|
|
|
return c->exclusiveTryLock();
|
|
}
|
|
status_t ProCamera::exclusiveLock()
|
|
{
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NO_INIT;
|
|
|
|
return c->exclusiveLock();
|
|
}
|
|
status_t ProCamera::exclusiveUnlock()
|
|
{
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NO_INIT;
|
|
|
|
return c->exclusiveUnlock();
|
|
}
|
|
bool ProCamera::hasExclusiveLock()
|
|
{
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NO_INIT;
|
|
|
|
return c->hasExclusiveLock();
|
|
}
|
|
|
|
// Note that the callee gets a copy of the metadata.
|
|
int ProCamera::submitRequest(const struct camera_metadata* metadata,
|
|
bool streaming)
|
|
{
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NO_INIT;
|
|
|
|
return c->submitRequest(const_cast<struct camera_metadata*>(metadata),
|
|
streaming);
|
|
}
|
|
|
|
status_t ProCamera::cancelRequest(int requestId)
|
|
{
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NO_INIT;
|
|
|
|
return c->cancelRequest(requestId);
|
|
}
|
|
|
|
status_t ProCamera::deleteStream(int streamId)
|
|
{
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NO_INIT;
|
|
|
|
status_t s = c->deleteStream(streamId);
|
|
|
|
mStreams.removeItem(streamId);
|
|
|
|
return s;
|
|
}
|
|
|
|
status_t ProCamera::createStream(int width, int height, int format,
|
|
const sp<Surface>& surface,
|
|
/*out*/
|
|
int* streamId)
|
|
{
|
|
*streamId = -1;
|
|
|
|
ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
|
|
format);
|
|
|
|
if (surface == 0) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
return createStream(width, height, format,
|
|
surface->getIGraphicBufferProducer(),
|
|
streamId);
|
|
}
|
|
|
|
status_t ProCamera::createStream(int width, int height, int format,
|
|
const sp<IGraphicBufferProducer>& bufferProducer,
|
|
/*out*/
|
|
int* streamId) {
|
|
*streamId = -1;
|
|
|
|
ALOGV("%s: createStreamT %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
|
|
format);
|
|
|
|
if (bufferProducer == 0) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
sp <IProCameraUser> c = mCamera;
|
|
status_t stat = c->createStream(width, height, format, bufferProducer,
|
|
streamId);
|
|
|
|
if (stat == OK) {
|
|
StreamInfo s(*streamId);
|
|
|
|
mStreams.add(*streamId, s);
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
status_t ProCamera::createStreamCpu(int width, int height, int format,
|
|
int heapCount,
|
|
/*out*/
|
|
sp<CpuConsumer>* cpuConsumer,
|
|
int* streamId) {
|
|
return createStreamCpu(width, height, format, heapCount,
|
|
/*synchronousMode*/true,
|
|
cpuConsumer, streamId);
|
|
}
|
|
|
|
status_t ProCamera::createStreamCpu(int width, int height, int format,
|
|
int heapCount,
|
|
bool synchronousMode,
|
|
/*out*/
|
|
sp<CpuConsumer>* cpuConsumer,
|
|
int* streamId)
|
|
{
|
|
ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
|
|
format);
|
|
|
|
*cpuConsumer = NULL;
|
|
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NO_INIT;
|
|
|
|
sp<IGraphicBufferProducer> producer;
|
|
sp<IGraphicBufferConsumer> consumer;
|
|
BufferQueue::createBufferQueue(&producer, &consumer);
|
|
sp<CpuConsumer> cc = new CpuConsumer(consumer, heapCount
|
|
/*, synchronousMode*/);
|
|
cc->setName(String8("ProCamera::mCpuConsumer"));
|
|
|
|
sp<Surface> stc = new Surface(producer);
|
|
|
|
status_t s = createStream(width, height, format,
|
|
stc->getIGraphicBufferProducer(),
|
|
streamId);
|
|
|
|
if (s != OK) {
|
|
ALOGE("%s: Failure to create stream %dx%d (fmt=0x%x)", __FUNCTION__,
|
|
width, height, format);
|
|
return s;
|
|
}
|
|
|
|
sp<ProFrameListener> frameAvailableListener =
|
|
new ProFrameListener(this, *streamId);
|
|
|
|
getStreamInfo(*streamId).cpuStream = true;
|
|
getStreamInfo(*streamId).cpuConsumer = cc;
|
|
getStreamInfo(*streamId).synchronousMode = synchronousMode;
|
|
getStreamInfo(*streamId).stc = stc;
|
|
// for lifetime management
|
|
getStreamInfo(*streamId).frameAvailableListener = frameAvailableListener;
|
|
|
|
cc->setFrameAvailableListener(frameAvailableListener);
|
|
|
|
*cpuConsumer = cc;
|
|
|
|
return s;
|
|
}
|
|
|
|
camera_metadata* ProCamera::getCameraInfo(int cameraId) {
|
|
ALOGV("%s: cameraId = %d", __FUNCTION__, cameraId);
|
|
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NULL;
|
|
|
|
camera_metadata* ptr = NULL;
|
|
status_t status = c->getCameraInfo(cameraId, &ptr);
|
|
|
|
if (status != OK) {
|
|
ALOGE("%s: Failed to get camera info, error = %d", __FUNCTION__, status);
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
status_t ProCamera::createDefaultRequest(int templateId,
|
|
camera_metadata** request) const {
|
|
ALOGV("%s: templateId = %d", __FUNCTION__, templateId);
|
|
|
|
sp <IProCameraUser> c = mCamera;
|
|
if (c == 0) return NO_INIT;
|
|
|
|
return c->createDefaultRequest(templateId, request);
|
|
}
|
|
|
|
void ProCamera::onFrameAvailable(int streamId) {
|
|
ALOGV("%s: streamId = %d", __FUNCTION__, streamId);
|
|
|
|
sp<ProCameraListener> listener = mListener;
|
|
StreamInfo& stream = getStreamInfo(streamId);
|
|
|
|
if (listener.get() != NULL) {
|
|
listener->onFrameAvailable(streamId, stream.cpuConsumer);
|
|
}
|
|
|
|
// Unblock waitForFrame(id) callers
|
|
{
|
|
Mutex::Autolock al(mWaitMutex);
|
|
getStreamInfo(streamId).frameReady++;
|
|
mWaitCondition.broadcast();
|
|
}
|
|
}
|
|
|
|
int ProCamera::waitForFrameBuffer(int streamId) {
|
|
status_t stat = BAD_VALUE;
|
|
Mutex::Autolock al(mWaitMutex);
|
|
|
|
StreamInfo& si = getStreamInfo(streamId);
|
|
|
|
if (si.frameReady > 0) {
|
|
int numFrames = si.frameReady;
|
|
si.frameReady = 0;
|
|
return numFrames;
|
|
} else {
|
|
while (true) {
|
|
stat = mWaitCondition.waitRelative(mWaitMutex,
|
|
mWaitTimeout);
|
|
if (stat != OK) {
|
|
ALOGE("%s: Error while waiting for frame buffer: %d",
|
|
__FUNCTION__, stat);
|
|
return stat;
|
|
}
|
|
|
|
if (si.frameReady > 0) {
|
|
int numFrames = si.frameReady;
|
|
si.frameReady = 0;
|
|
return numFrames;
|
|
}
|
|
// else it was some other stream that got unblocked
|
|
}
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
int ProCamera::dropFrameBuffer(int streamId, int count) {
|
|
StreamInfo& si = getStreamInfo(streamId);
|
|
|
|
if (!si.cpuStream) {
|
|
return BAD_VALUE;
|
|
} else if (count < 0) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
if (!si.synchronousMode) {
|
|
ALOGW("%s: No need to drop frames on asynchronous streams,"
|
|
" as asynchronous mode only keeps 1 latest frame around.",
|
|
__FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
int numDropped = 0;
|
|
for (int i = 0; i < count; ++i) {
|
|
CpuConsumer::LockedBuffer buffer;
|
|
if (si.cpuConsumer->lockNextBuffer(&buffer) != OK) {
|
|
break;
|
|
}
|
|
|
|
si.cpuConsumer->unlockBuffer(buffer);
|
|
numDropped++;
|
|
}
|
|
|
|
return numDropped;
|
|
}
|
|
|
|
status_t ProCamera::waitForFrameMetadata() {
|
|
status_t stat = BAD_VALUE;
|
|
Mutex::Autolock al(mWaitMutex);
|
|
|
|
if (mMetadataReady) {
|
|
return OK;
|
|
} else {
|
|
while (true) {
|
|
stat = mWaitCondition.waitRelative(mWaitMutex,
|
|
mWaitTimeout);
|
|
|
|
if (stat != OK) {
|
|
ALOGE("%s: Error while waiting for metadata: %d",
|
|
__FUNCTION__, stat);
|
|
return stat;
|
|
}
|
|
|
|
if (mMetadataReady) {
|
|
mMetadataReady = false;
|
|
return OK;
|
|
}
|
|
// else it was some other stream or metadata
|
|
}
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
CameraMetadata ProCamera::consumeFrameMetadata() {
|
|
Mutex::Autolock al(mWaitMutex);
|
|
|
|
// Destructive: Subsequent calls return empty metadatas
|
|
CameraMetadata tmp = mLatestMetadata;
|
|
mLatestMetadata.clear();
|
|
|
|
return tmp;
|
|
}
|
|
|
|
ProCamera::StreamInfo& ProCamera::getStreamInfo(int streamId) {
|
|
return mStreams.editValueFor(streamId);
|
|
}
|
|
|
|
}; // namespace android
|