Change the framework to use the new camera preview path.

This change makes the camera HAL interface take an ANativeWindow interface from
which all the camera preview buffers will be allocated.  The framework code
running in application processes now passes a Surface object rather than an
ISurface to the camera server via Binder when setting the preview surface.  The
camera server then forwards that Surface object (which implements the
ANativeWindow interface) to the camera HAL, which uses it to communicate with
SurfaceFlinger to allocate the camera preview buffers.

Change-Id: Ie438f721559cd7de5e4f848a26d96360dda07b5f
This commit is contained in:
Jamie Gennis
2010-08-10 16:37:53 -07:00
parent 7fdaa2329e
commit 85cfdd0112
20 changed files with 89 additions and 133 deletions

View File

@@ -22,8 +22,6 @@
namespace android {
class ISurface;
/*
* A set of bit masks for specifying how the received preview frames are
* handled before the previewCallback() call.
@@ -152,9 +150,8 @@ public:
status_t getStatus() { return mStatus; }
// pass the buffered ISurface to the camera service
// pass the buffered Surface to the camera service
status_t setPreviewDisplay(const sp<Surface>& surface);
status_t setPreviewDisplay(const sp<ISurface>& surface);
// start preview mode, must call setPreviewDisplay first
status_t startPreview();

View File

@@ -18,6 +18,7 @@
#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
#include <binder/IMemory.h>
#include <ui/egl/android_natives.h>
#include <utils/RefBase.h>
#include <surfaceflinger/ISurface.h>
#include <camera/Camera.h>
@@ -86,8 +87,8 @@ class CameraHardwareInterface : public virtual RefBase {
public:
virtual ~CameraHardwareInterface() { }
/** Return the IMemoryHeap for the preview image heap */
virtual sp<IMemoryHeap> getPreviewHeap() const = 0;
/** Set the ISurface from which the preview buffers should be dequeued */
virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf) = 0;
/** Return the IMemoryHeap for the raw image heap */
virtual sp<IMemoryHeap> getRawHeap() const = 0;

View File

@@ -20,7 +20,7 @@
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/Surface.h>
#include <binder/IMemory.h>
#include <utils/String8.h>
#include <camera/Camera.h>
@@ -45,8 +45,8 @@ public:
// allow other processes to use this ICamera interface
virtual status_t unlock() = 0;
// pass the buffered ISurface to the camera service
virtual status_t setPreviewDisplay(const sp<ISurface>& surface) = 0;
// pass the buffered Surface to the camera service
virtual status_t setPreviewDisplay(const sp<Surface>& surface) = 0;
// set the preview callback flag to affect how the received frames from
// preview are handled.

View File

@@ -22,7 +22,7 @@
namespace android {
class ISurface;
class Surface;
class ICamera;
class IMediaRecorderClient;
@@ -32,7 +32,7 @@ public:
DECLARE_META_INTERFACE(MediaRecorder);
virtual status_t setCamera(const sp<ICamera>& camera) = 0;
virtual status_t setPreviewSurface(const sp<ISurface>& surface) = 0;
virtual status_t setPreviewSurface(const sp<Surface>& surface) = 0;
virtual status_t setVideoSource(int vs) = 0;
virtual status_t setAudioSource(int as) = 0;
virtual status_t setOutputFormat(int of) = 0;
@@ -68,4 +68,3 @@ public:
}; // namespace android
#endif // ANDROID_IMEDIARECORDER_H

View File

@@ -22,7 +22,7 @@
namespace android {
class ISurface;
class Surface;
struct MediaRecorderBase {
MediaRecorderBase() {}
@@ -37,7 +37,7 @@ struct MediaRecorderBase {
virtual status_t setVideoSize(int width, int height) = 0;
virtual status_t setVideoFrameRate(int frames_per_second) = 0;
virtual status_t setCamera(const sp<ICamera>& camera) = 0;
virtual status_t setPreviewSurface(const sp<ISurface>& surface) = 0;
virtual status_t setPreviewSurface(const sp<Surface>& surface) = 0;
virtual status_t setOutputFile(const char *path) = 0;
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setParameters(const String8& params) = 0;

View File

@@ -23,7 +23,7 @@
namespace android {
class ISurface;
class Surface;
class ICamera;
class AuthorDriverWrapper;
@@ -41,7 +41,7 @@ public:
virtual status_t setVideoSize(int width, int height);
virtual status_t setVideoFrameRate(int frames_per_second);
virtual status_t setCamera(const sp<ICamera>& camera);
virtual status_t setPreviewSurface(const sp<ISurface>& surface);
virtual status_t setPreviewSurface(const sp<Surface>& surface);
virtual status_t setOutputFile(const char *path);
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
virtual status_t setParameters(const String8& params);
@@ -66,4 +66,3 @@ private:
}; // namespace android
#endif // ANDROID_PVMEDIARECORDER_H

View File

@@ -94,7 +94,7 @@ private:
friend class SurfaceComposerClient;
// camera and camcorder need access to the ISurface binder interface for preview
friend class Camera;
friend class CameraService;
friend class MediaRecorder;
// mediaplayer needs access to ISurface for display
friend class MediaPlayer;
@@ -173,7 +173,7 @@ private:
* (eventually this should go away and be replaced by proper APIs)
*/
// camera and camcorder need access to the ISurface binder interface for preview
friend class Camera;
friend class CameraService;
friend class MediaRecorder;
// MediaPlayer needs access to ISurface for display
friend class MediaPlayer;
@@ -310,4 +310,3 @@ private:
}; // namespace android
#endif // ANDROID_SF_SURFACE_H

View File

@@ -167,32 +167,20 @@ status_t Camera::unlock()
return c->unlock();
}
// pass the buffered ISurface to the camera service
// pass the buffered Surface to the camera service
status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
{
LOGV("setPreviewDisplay");
LOGV("setPreviewDisplay(%p)", surface.get());
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
if (surface != 0) {
return c->setPreviewDisplay(surface->getISurface());
return c->setPreviewDisplay(surface);
} else {
LOGD("app passed NULL surface");
return c->setPreviewDisplay(0);
}
}
status_t Camera::setPreviewDisplay(const sp<ISurface>& surface)
{
LOGV("setPreviewDisplay");
if (surface == 0) {
LOGD("app passed NULL surface");
}
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
return c->setPreviewDisplay(surface);
}
// start preview mode
status_t Camera::startPreview()
{
@@ -375,4 +363,3 @@ void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
}
}; // namespace android

View File

@@ -64,13 +64,13 @@ public:
remote()->transact(DISCONNECT, data, &reply);
}
// pass the buffered ISurface to the camera service
status_t setPreviewDisplay(const sp<ISurface>& surface)
// pass the buffered Surface to the camera service
status_t setPreviewDisplay(const sp<Surface>& surface)
{
LOGV("setPreviewDisplay");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
data.writeStrongBinder(surface->asBinder());
Surface::writeToParcel(surface, &data);
remote()->transact(SET_PREVIEW_DISPLAY, data, &reply);
return reply.readInt32();
}
@@ -258,7 +258,7 @@ status_t BnCamera::onTransact(
case SET_PREVIEW_DISPLAY: {
LOGV("SET_PREVIEW_DISPLAY");
CHECK_INTERFACE(ICamera, data, reply);
sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
sp<Surface> surface = Surface::readFromParcel(data);
reply->writeInt32(setPreviewDisplay(surface));
return NO_ERROR;
} break;
@@ -376,4 +376,3 @@ status_t BnCamera::onTransact(
// ----------------------------------------------------------------------------
}; // namespace android

View File

@@ -344,11 +344,6 @@ ssize_t SharedBufferClient::dequeue()
{
SharedBufferStack& stack( *mSharedStack );
if (stack.head == tail && stack.available == mNumBuffers) {
LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
tail, stack.head, stack.available, stack.queued);
}
RWLock::AutoRLock _rd(mLock);
const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);

View File

@@ -363,6 +363,13 @@ status_t Surface::writeToParcel(
height = surface->mHeight;
format = surface->mFormat;
flags = surface->mFlags;
} else if (surface != 0 && surface->mSurface != 0) {
LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
"mSurface = %p, mIdentity = %d, mWidth = %d, mHeight = %d, "
"mFormat = %d, mFlags = 0x%08x, mInitCheck = %d",
surface->mSurface.get(), surface->mIdentity, surface->mWidth,
surface->mHeight, surface->mFormat, surface->mFlags,
surface->mInitCheck);
}
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
parcel->writeInt32(identity);
@@ -434,6 +441,9 @@ void Surface::init()
mSharedBufferClient = new SharedBufferClient(
mClient.getSharedClient(), token, 2, mIdentity);
mInitCheck = mClient.getSharedClient()->validate(token);
} else {
LOGW("Not initializing the shared buffer client because token = %d",
token);
}
}
}

View File

@@ -19,7 +19,7 @@
#define LOG_TAG "IMediaRecorder"
#include <utils/Log.h>
#include <binder/Parcel.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/Surface.h>
#include <camera/ICamera.h>
#include <media/IMediaRecorderClient.h>
#include <media/IMediaRecorder.h>
@@ -69,12 +69,12 @@ public:
return reply.readInt32();
}
status_t setPreviewSurface(const sp<ISurface>& surface)
status_t setPreviewSurface(const sp<Surface>& surface)
{
LOGV("setPreviewSurface(%p)", surface.get());
Parcel data, reply;
data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
data.writeStrongBinder(surface->asBinder());
Surface::writeToParcel(surface, &data);
remote()->transact(SET_PREVIEW_SURFACE, data, &reply);
return reply.readInt32();
}
@@ -409,7 +409,7 @@ status_t BnMediaRecorder::onTransact(
case SET_PREVIEW_SURFACE: {
LOGV("SET_PREVIEW_SURFACE");
CHECK_INTERFACE(IMediaRecorder, data, reply);
sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
sp<Surface> surface = Surface::readFromParcel(data);
reply->writeInt32(setPreviewSurface(surface));
return NO_ERROR;
} break;

View File

@@ -65,7 +65,7 @@ status_t MediaRecorder::setPreviewSurface(const sp<Surface>& surface)
return INVALID_OPERATION;
}
status_t ret = mMediaRecorder->setPreviewSurface(surface->getISurface());
status_t ret = mMediaRecorder->setPreviewSurface(surface);
if (OK != ret) {
LOGV("setPreviewSurface failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
@@ -643,4 +643,3 @@ void MediaRecorder::died()
}
}; // namespace android

View File

@@ -70,7 +70,7 @@ status_t MediaRecorderClient::setCamera(const sp<ICamera>& camera)
return mRecorder->setCamera(camera);
}
status_t MediaRecorderClient::setPreviewSurface(const sp<ISurface>& surface)
status_t MediaRecorderClient::setPreviewSurface(const sp<Surface>& surface)
{
LOGV("setPreviewSurface");
Mutex::Autolock lock(mLock);
@@ -337,4 +337,3 @@ status_t MediaRecorderClient::dump(int fd, const Vector<String16>& args) const {
}
}; // namespace android

View File

@@ -29,7 +29,7 @@ class MediaRecorderClient : public BnMediaRecorder
{
public:
virtual status_t setCamera(const sp<ICamera>& camera);
virtual status_t setPreviewSurface(const sp<ISurface>& surface);
virtual status_t setPreviewSurface(const sp<Surface>& surface);
virtual status_t setVideoSource(int vs);
virtual status_t setAudioSource(int as);
virtual status_t setOutputFormat(int of);
@@ -66,4 +66,3 @@ private:
}; // namespace android
#endif // ANDROID_MEDIARECORDERCLIENT_H

View File

@@ -35,7 +35,7 @@
#include <camera/ICamera.h>
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/Surface.h>
#include <utils/Errors.h>
#include <sys/types.h>
#include <ctype.h>
@@ -201,7 +201,7 @@ status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
return OK;
}
status_t StagefrightRecorder::setPreviewSurface(const sp<ISurface> &surface) {
status_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
LOGV("setPreviewSurface: %p", surface.get());
mPreviewSurface = surface;

View File

@@ -42,7 +42,7 @@ struct StagefrightRecorder : public MediaRecorderBase {
virtual status_t setVideoSize(int width, int height);
virtual status_t setVideoFrameRate(int frames_per_second);
virtual status_t setCamera(const sp<ICamera>& camera);
virtual status_t setPreviewSurface(const sp<ISurface>& surface);
virtual status_t setPreviewSurface(const sp<Surface>& surface);
virtual status_t setOutputFile(const char *path);
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
virtual status_t setParameters(const String8& params);
@@ -63,7 +63,7 @@ private:
};
sp<Camera> mCamera;
sp<ISurface> mPreviewSurface;
sp<Surface> mPreviewSurface;
sp<IMediaRecorderClient> mListener;
sp<MediaWriter> mWriter;
sp<AudioSource> mAudioSourceNode;
@@ -144,4 +144,3 @@ private:
} // namespace android
#endif // STAGEFRIGHT_RECORDER_H_

View File

@@ -336,16 +336,9 @@ CameraService::Client::~Client() {
int callingPid = getCallingPid();
LOG1("Client::~Client E (pid %d, this %p)", callingPid, this);
if (mSurface != 0 && !mUseOverlay) {
pthread_t thr;
// We unregister the buffers in a different thread because binder does
// not let us make sychronous transactions in a binder destructor (that
// is, upon our reaching a refcount of zero.)
pthread_create(&thr,
NULL, // attr
unregister_surface,
mSurface.get());
pthread_join(thr, NULL);
// Clean up the ANativeWindow
if (mSurface != 0) {
setPreviewDisplay(0);
}
// set mClientPid to let disconnet() tear down the hardware
@@ -465,6 +458,11 @@ void CameraService::Client::disconnect() {
if (mUseOverlay) {
mOverlayRef = 0;
}
// Release the held ANativeWindow resources.
if (mPreviewWindow != 0) {
mPreviewWindow = 0;
mHardware->setPreviewWindow(mPreviewWindow);
}
mHardware.clear();
mCameraService->removeClient(mCameraClient);
@@ -475,8 +473,8 @@ void CameraService::Client::disconnect() {
// ----------------------------------------------------------------------------
// set the ISurface that the preview will use
status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) {
// set the Surface that the preview will use
status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) {
LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
@@ -486,7 +484,7 @@ status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) {
// return if no change in surface.
// asBinder() is safe on NULL (returns NULL)
if (surface->asBinder() == mSurface->asBinder()) {
if (getISurface(surface)->asBinder() == mSurface->asBinder()) {
return result;
}
@@ -496,44 +494,28 @@ status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) {
// Force the destruction of any previous overlay
sp<Overlay> dummy;
mHardware->setOverlay(dummy);
} else {
mSurface->unregisterBuffers();
}
}
mSurface = surface;
if (surface != 0) {
mSurface = getISurface(surface);
} else {
mSurface = 0;
}
mPreviewWindow = surface;
mOverlayRef = 0;
// If preview has been already started, set overlay or register preview
// buffers now.
if (mHardware->previewEnabled()) {
if (mUseOverlay) {
result = setOverlay();
} else if (mSurface != 0) {
result = registerPreviewBuffers();
} else if (mPreviewWindow != 0) {
result = mHardware->setPreviewWindow(mPreviewWindow);
}
}
return result;
}
status_t CameraService::Client::registerPreviewBuffers() {
int w, h;
CameraParameters params(mHardware->getParameters());
params.getPreviewSize(&w, &h);
// FIXME: don't use a hardcoded format here.
ISurface::BufferHeap buffers(w, h, w, h,
HAL_PIXEL_FORMAT_YCrCb_420_SP,
mOrientation,
0,
mHardware->getPreviewHeap());
status_t result = mSurface->registerBuffers(buffers);
if (result != NO_ERROR) {
LOGE("registerBuffers failed with status %d", result);
}
return result;
}
status_t CameraService::Client::setOverlay() {
int w, h;
CameraParameters params(mHardware->getParameters());
@@ -624,14 +606,14 @@ status_t CameraService::Client::startCameraMode(camera_mode mode) {
switch(mode) {
case CAMERA_PREVIEW_MODE:
if (mSurface == 0) {
if (mSurface == 0 && mPreviewWindow == 0) {
LOG1("mSurface is not set yet.");
// still able to start preview in this case.
}
return startPreviewMode();
case CAMERA_RECORDING_MODE:
if (mSurface == 0) {
LOGE("mSurface must be set before startRecordingMode.");
if (mSurface == 0 && mPreviewWindow == 0) {
LOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");
return INVALID_OPERATION;
}
return startRecordingMode();
@@ -657,16 +639,10 @@ status_t CameraService::Client::startPreviewMode() {
if (result != NO_ERROR) return result;
result = mHardware->startPreview();
} else {
// XXX: Set the orientation of the ANativeWindow.
mHardware->setPreviewWindow(mPreviewWindow);
enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
result = mHardware->startPreview();
if (result != NO_ERROR) return result;
// If preview display has been set, register preview buffers now.
if (mSurface != 0) {
// Unregister here because the surface may be previously registered
// with the raw (snapshot) heap.
mSurface->unregisterBuffers();
result = registerPreviewBuffers();
}
}
return result;
}
@@ -704,13 +680,10 @@ void CameraService::Client::stopPreview() {
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return;
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
mHardware->stopPreview();
if (mSurface != 0 && !mUseOverlay) {
mSurface->unregisterBuffers();
}
mPreviewBuffer.clear();
}
@@ -998,11 +971,6 @@ void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp,
void CameraService::Client::handleShutter(image_rect_type *size) {
mCameraService->playSound(SOUND_SHUTTER);
// Screen goes black after the buffer is unregistered.
if (mSurface != 0 && !mUseOverlay) {
mSurface->unregisterBuffers();
}
sp<ICameraClient> c = mCameraClient;
if (c != 0) {
mLock.unlock();
@@ -1030,7 +998,6 @@ void CameraService::Client::handleShutter(image_rect_type *size) {
HAL_PIXEL_FORMAT_YCrCb_420_SP, mOrientation, 0,
mHardware->getRawHeap());
mSurface->registerBuffers(buffers);
IPCThreadState::self()->flushCommands();
}
@@ -1043,12 +1010,6 @@ void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
if (!mUseOverlay) {
if (mSurface != 0) {
mSurface->postBuffer(offset);
}
}
// local copy of the callback flags
int flags = mPreviewCallbackFlag;
@@ -1108,11 +1069,6 @@ void CameraService::Client::handleRawPicture(const sp<IMemory>& mem) {
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
// Put the YUV version of the snapshot in the preview display.
if (mSurface != 0 && !mUseOverlay) {
mSurface->postBuffer(offset);
}
sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != 0) {
@@ -1270,4 +1226,12 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
return NO_ERROR;
}
sp<ISurface> CameraService::getISurface(const sp<Surface>& surface) {
if (surface != 0) {
return surface->getISurface();
} else {
return sp<ISurface>(0);
}
}
}; // namespace android

View File

@@ -79,6 +79,12 @@ private:
sp<MediaPlayer> mSoundPlayer[NUM_SOUNDS];
int mSoundRef; // reference count (release all MediaPlayer when 0)
// Used by Client objects to extract the ISurface from a Surface object.
// This is used because making Client a friend class of Surface would
// require including this header in Surface.h since Client is a nested
// class.
static sp<ISurface> getISurface(const sp<Surface>& surface);
class Client : public BnCamera
{
public:
@@ -87,7 +93,7 @@ private:
virtual status_t connect(const sp<ICameraClient>& client);
virtual status_t lock();
virtual status_t unlock();
virtual status_t setPreviewDisplay(const sp<ISurface>& surface);
virtual status_t setPreviewDisplay(const sp<Surface>& surface);
virtual void setPreviewCallbackFlag(int flag);
virtual status_t startPreview();
virtual void stopPreview();
@@ -169,6 +175,7 @@ private:
// Ensures atomicity among the public methods
mutable Mutex mLock;
sp<ISurface> mSurface;
sp<ANativeWindow> mPreviewWindow;
// If the user want us to return a copy of the preview frame (instead
// of the original one), we allocate mPreviewBuffer and reuse it if possible.

View File

@@ -1745,12 +1745,15 @@ ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
{
int32_t name = NAME_NOT_FOUND;
sp<Layer> layer(mFlinger->getLayer(sur));
if (layer == 0) return name;
if (layer == 0) {
return name;
}
// if this layer already has a token, just return it
name = layer->getToken();
if ((name >= 0) && (layer->getClient() == this))
if ((name >= 0) && (layer->getClient() == this)) {
return name;
}
name = 0;
do {