Support multiple cameras in framework.
Change-Id: I081f0fbdca4b633715ea7c3b3d42f8662d27598a
This commit is contained in:
@@ -1,15 +1,24 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
#
|
||||
# Set USE_CAMERA_STUB for non-emulator and non-simulator builds, if you want
|
||||
# the camera service to use the fake camera. For emulator or simulator builds,
|
||||
# we always use the fake camera.
|
||||
# Set USE_CAMERA_STUB if you want to use the fake camera.
|
||||
# Set USE_CAMERA_HARDWARE if you want to use the hardware camera.
|
||||
# For emulator or simulator builds, we use the fake camera only by default.
|
||||
|
||||
ifeq ($(USE_CAMERA_STUB),)
|
||||
USE_CAMERA_STUB:=false
|
||||
ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),)
|
||||
USE_CAMERA_STUB:=true
|
||||
endif #libcamerastub
|
||||
ifeq ($(USE_CAMERA_STUB),)
|
||||
USE_CAMERA_STUB:=true
|
||||
endif
|
||||
ifeq ($(USE_CAMERA_HARDWARE),)
|
||||
USE_CAMERA_HARDWARE:=false
|
||||
endif
|
||||
else
|
||||
# force USE_CAMERA_STUB for testing temporarily
|
||||
# ifeq ($(USE_CAMERA_STUB),)
|
||||
USE_CAMERA_STUB:=true
|
||||
# endif
|
||||
ifeq ($(USE_CAMERA_HARDWARE),)
|
||||
USE_CAMERA_HARDWARE:=true
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(USE_CAMERA_STUB),true)
|
||||
@@ -54,18 +63,18 @@ LOCAL_SHARED_LIBRARIES:= \
|
||||
|
||||
LOCAL_MODULE:= libcameraservice
|
||||
|
||||
LOCAL_CFLAGS += -DLOG_TAG=\"CameraService\"
|
||||
|
||||
ifeq ($(TARGET_SIMULATOR),true)
|
||||
LOCAL_CFLAGS += -DSINGLE_PROCESS
|
||||
endif
|
||||
|
||||
ifeq ($(USE_CAMERA_STUB), true)
|
||||
LOCAL_STATIC_LIBRARIES += libcamerastub
|
||||
LOCAL_CFLAGS += -include CameraHardwareStub.h
|
||||
else
|
||||
LOCAL_CFLAGS += -DUSE_CAMERA_STUB
|
||||
endif
|
||||
|
||||
ifeq ($(USE_CAMERA_HARDWARE),true)
|
||||
LOCAL_CFLAGS += -DUSE_CAMERA_HARDWARE
|
||||
LOCAL_SHARED_LIBRARIES += libcamera
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
||||
@@ -47,14 +47,14 @@ void CameraHardwareStub::initDefaultParameters()
|
||||
{
|
||||
CameraParameters p;
|
||||
|
||||
p.set("preview-size-values","320x240");
|
||||
p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "320x240");
|
||||
p.setPreviewSize(320, 240);
|
||||
p.setPreviewFrameRate(15);
|
||||
p.setPreviewFormat("yuv422sp");
|
||||
p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
|
||||
|
||||
p.set("picture-size-values", "320x240");
|
||||
p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "320x240");
|
||||
p.setPictureSize(320, 240);
|
||||
p.setPictureFormat("jpeg");
|
||||
p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
|
||||
|
||||
if (setParameters(p) != NO_ERROR) {
|
||||
LOGE("Failed to set default parameters?!");
|
||||
@@ -66,14 +66,14 @@ void CameraHardwareStub::initHeapLocked()
|
||||
// Create raw heap.
|
||||
int picture_width, picture_height;
|
||||
mParameters.getPictureSize(&picture_width, &picture_height);
|
||||
mRawHeap = new MemoryHeapBase(picture_width * 2 * picture_height);
|
||||
mRawHeap = new MemoryHeapBase(picture_width * picture_height * 3 / 2);
|
||||
|
||||
int preview_width, preview_height;
|
||||
mParameters.getPreviewSize(&preview_width, &preview_height);
|
||||
LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
|
||||
|
||||
// Note that we enforce yuv422 in setParameters().
|
||||
int how_big = preview_width * preview_height * 2;
|
||||
// Note that we enforce yuv420sp in setParameters().
|
||||
int how_big = preview_width * preview_height * 3 / 2;
|
||||
|
||||
// If we are being reinitialized to the same size as before, no
|
||||
// work needs to be done.
|
||||
@@ -99,7 +99,6 @@ CameraHardwareStub::~CameraHardwareStub()
|
||||
{
|
||||
delete mFakeCamera;
|
||||
mFakeCamera = 0; // paranoia
|
||||
singleton.clear();
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> CameraHardwareStub::getPreviewHeap() const
|
||||
@@ -175,7 +174,7 @@ int CameraHardwareStub::previewThread()
|
||||
|
||||
// Fill the current frame with the fake camera.
|
||||
uint8_t *frame = ((uint8_t *)base) + offset;
|
||||
fakeCamera->getNextFrameAsYuv422(frame);
|
||||
fakeCamera->getNextFrameAsYuv420(frame);
|
||||
|
||||
//LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
|
||||
|
||||
@@ -288,9 +287,9 @@ int CameraHardwareStub::pictureThread()
|
||||
// In the meantime just make another fake camera picture.
|
||||
int w, h;
|
||||
mParameters.getPictureSize(&w, &h);
|
||||
sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
|
||||
sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * h * 3 / 2);
|
||||
FakeCamera cam(w, h);
|
||||
cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());
|
||||
cam.getNextFrameAsYuv420((uint8_t *)mRawHeap->base());
|
||||
mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
|
||||
}
|
||||
|
||||
@@ -307,7 +306,7 @@ status_t CameraHardwareStub::takePicture()
|
||||
{
|
||||
stopPreview();
|
||||
if (createThread(beginPictureThread, this) == false)
|
||||
return -1;
|
||||
return UNKNOWN_ERROR;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -339,12 +338,14 @@ status_t CameraHardwareStub::setParameters(const CameraParameters& params)
|
||||
Mutex::Autolock lock(mLock);
|
||||
// XXX verify params
|
||||
|
||||
if (strcmp(params.getPreviewFormat(), "yuv422sp") != 0) {
|
||||
LOGE("Only yuv422sp preview is supported");
|
||||
if (strcmp(params.getPreviewFormat(),
|
||||
CameraParameters::PIXEL_FORMAT_YUV420SP) != 0) {
|
||||
LOGE("Only yuv420sp preview is supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(params.getPictureFormat(), "jpeg") != 0) {
|
||||
if (strcmp(params.getPictureFormat(),
|
||||
CameraParameters::PIXEL_FORMAT_JPEG) != 0) {
|
||||
LOGE("Only jpeg still pictures are supported");
|
||||
return -1;
|
||||
}
|
||||
@@ -379,22 +380,12 @@ void CameraHardwareStub::release()
|
||||
{
|
||||
}
|
||||
|
||||
wp<CameraHardwareInterface> CameraHardwareStub::singleton;
|
||||
|
||||
sp<CameraHardwareInterface> CameraHardwareStub::createInstance()
|
||||
{
|
||||
if (singleton != 0) {
|
||||
sp<CameraHardwareInterface> hardware = singleton.promote();
|
||||
if (hardware != 0) {
|
||||
return hardware;
|
||||
}
|
||||
}
|
||||
sp<CameraHardwareInterface> hardware(new CameraHardwareStub());
|
||||
singleton = hardware;
|
||||
return hardware;
|
||||
return new CameraHardwareStub();
|
||||
}
|
||||
|
||||
extern "C" sp<CameraHardwareInterface> openCameraHardware()
|
||||
extern "C" sp<CameraHardwareInterface> openCameraHardwareStub()
|
||||
{
|
||||
return CameraHardwareStub::createInstance();
|
||||
}
|
||||
|
||||
@@ -67,8 +67,6 @@ private:
|
||||
CameraHardwareStub();
|
||||
virtual ~CameraHardwareStub();
|
||||
|
||||
static wp<CameraHardwareInterface> singleton;
|
||||
|
||||
static const int kBufferCount = 4;
|
||||
|
||||
class PreviewThread : public Thread {
|
||||
@@ -130,6 +128,8 @@ private:
|
||||
int mCurrentPreviewFrame;
|
||||
};
|
||||
|
||||
extern "C" sp<CameraHardwareInterface> openCameraHardwareStub();
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,207 +21,171 @@
|
||||
|
||||
#include <camera/ICameraService.h>
|
||||
#include <camera/CameraHardwareInterface.h>
|
||||
#include <camera/Camera.h>
|
||||
|
||||
/* This needs to be increased if we can have more cameras */
|
||||
#define MAX_CAMERAS 2
|
||||
|
||||
namespace android {
|
||||
|
||||
class MemoryHeapBase;
|
||||
class MediaPlayer;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
|
||||
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
|
||||
|
||||
// When enabled, this feature allows you to send an event to the CameraService
|
||||
// so that you can cause all references to the heap object gWeakHeap, defined
|
||||
// below, to be printed. You will also need to set DEBUG_REFS=1 and
|
||||
// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp. You just have to
|
||||
// set gWeakHeap to the appropriate heap you want to track.
|
||||
|
||||
#define DEBUG_HEAP_LEAKS 0
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class CameraService : public BnCameraService
|
||||
class CameraService: public BnCameraService
|
||||
{
|
||||
class Client;
|
||||
|
||||
public:
|
||||
static void instantiate();
|
||||
static void instantiate();
|
||||
|
||||
// ICameraService interface
|
||||
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient);
|
||||
CameraService();
|
||||
virtual ~CameraService();
|
||||
|
||||
virtual status_t dump(int fd, const Vector<String16>& args);
|
||||
virtual int32_t getNumberOfCameras();
|
||||
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId);
|
||||
virtual void removeClient(const sp<ICameraClient>& cameraClient);
|
||||
virtual sp<Client> getClientById(int cameraId);
|
||||
|
||||
void removeClient(const sp<ICameraClient>& cameraClient);
|
||||
virtual status_t dump(int fd, const Vector<String16>& args);
|
||||
virtual status_t onTransact(uint32_t code, const Parcel& data,
|
||||
Parcel* reply, uint32_t flags);
|
||||
|
||||
virtual status_t onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
|
||||
enum sound_kind {
|
||||
SOUND_SHUTTER = 0,
|
||||
SOUND_RECORDING = 1,
|
||||
NUM_SOUNDS
|
||||
};
|
||||
|
||||
void loadSound();
|
||||
void playSound(sound_kind kind);
|
||||
void releaseSound();
|
||||
|
||||
private:
|
||||
Mutex mServiceLock;
|
||||
wp<Client> mClient[MAX_CAMERAS]; // protected by mServiceLock
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// atomics to record whether the hardware is allocated to some client.
|
||||
volatile int32_t mBusy[MAX_CAMERAS];
|
||||
void setCameraBusy(int cameraId);
|
||||
void setCameraFree(int cameraId);
|
||||
|
||||
class Client : public BnCamera {
|
||||
// sounds
|
||||
Mutex mSoundLock;
|
||||
sp<MediaPlayer> mSoundPlayer[NUM_SOUNDS];
|
||||
int mSoundRef; // reference count (release all MediaPlayer when 0)
|
||||
|
||||
class Client : public BnCamera
|
||||
{
|
||||
public:
|
||||
// ICamera interface (see ICamera for details)
|
||||
virtual void disconnect();
|
||||
|
||||
// connect new client with existing camera remote
|
||||
virtual status_t connect(const sp<ICameraClient>& client);
|
||||
|
||||
// prevent other processes from using this ICamera interface
|
||||
virtual status_t lock();
|
||||
|
||||
// allow other processes to use this ICamera interface
|
||||
virtual status_t unlock();
|
||||
|
||||
// pass the buffered ISurface to the camera service
|
||||
virtual status_t setPreviewDisplay(const sp<ISurface>& surface);
|
||||
|
||||
// set the preview callback flag to affect how the received frames from
|
||||
// preview are handled.
|
||||
virtual void setPreviewCallbackFlag(int callback_flag);
|
||||
|
||||
// start preview mode, must call setPreviewDisplay first
|
||||
virtual void setPreviewCallbackFlag(int flag);
|
||||
virtual status_t startPreview();
|
||||
|
||||
// stop preview mode
|
||||
virtual void stopPreview();
|
||||
|
||||
// get preview state
|
||||
virtual bool previewEnabled();
|
||||
|
||||
// start recording mode
|
||||
virtual status_t startRecording();
|
||||
|
||||
// stop recording mode
|
||||
virtual void stopRecording();
|
||||
|
||||
// get recording state
|
||||
virtual bool recordingEnabled();
|
||||
|
||||
// release a recording frame
|
||||
virtual void releaseRecordingFrame(const sp<IMemory>& mem);
|
||||
|
||||
// auto focus
|
||||
virtual status_t autoFocus();
|
||||
|
||||
// cancel auto focus
|
||||
virtual status_t cancelAutoFocus();
|
||||
|
||||
// take a picture - returns an IMemory (ref-counted mmap)
|
||||
virtual status_t takePicture();
|
||||
|
||||
// set preview/capture parameters - key/value pairs
|
||||
virtual status_t setParameters(const String8& params);
|
||||
|
||||
// get preview/capture parameters - key/value pairs
|
||||
virtual String8 getParameters() const;
|
||||
|
||||
// send command to camera driver
|
||||
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
|
||||
|
||||
// our client...
|
||||
const sp<ICameraClient>& getCameraClient() const { return mCameraClient; }
|
||||
|
||||
private:
|
||||
friend class CameraService;
|
||||
Client(const sp<CameraService>& cameraService,
|
||||
const sp<ICameraClient>& cameraClient,
|
||||
pid_t clientPid);
|
||||
Client();
|
||||
virtual ~Client();
|
||||
const sp<ICameraClient>& cameraClient,
|
||||
int cameraId,
|
||||
int clientPid);
|
||||
~Client();
|
||||
|
||||
status_t checkPid();
|
||||
// return our camera client
|
||||
const sp<ICameraClient>& getCameraClient() { return mCameraClient; }
|
||||
|
||||
static void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
|
||||
static void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user);
|
||||
static void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
|
||||
const sp<IMemory>& dataPtr, void* user);
|
||||
// check whether the calling process matches mClientPid.
|
||||
status_t checkPid() const;
|
||||
status_t checkPidAndHardware() const; // also check mHardware != 0
|
||||
|
||||
static sp<Client> getClientFromCookie(void* user);
|
||||
|
||||
void handlePreviewData(const sp<IMemory>&);
|
||||
void handleShutter(image_rect_type *image);
|
||||
void handlePostview(const sp<IMemory>&);
|
||||
void handleRawPicture(const sp<IMemory>&);
|
||||
void handleCompressedPicture(const sp<IMemory>&);
|
||||
|
||||
void copyFrameAndPostCopiedFrame(const sp<ICameraClient>& client,
|
||||
const sp<IMemoryHeap>& heap, size_t offset, size_t size);
|
||||
// these are internal functions used to set up preview buffers
|
||||
status_t registerPreviewBuffers();
|
||||
status_t setOverlay();
|
||||
|
||||
// camera operation mode
|
||||
enum camera_mode {
|
||||
CAMERA_PREVIEW_MODE = 0, // frame automatically released
|
||||
CAMERA_RECORDING_MODE = 1, // frame has to be explicitly released by releaseRecordingFrame()
|
||||
};
|
||||
// these are internal functions used for preview/recording
|
||||
status_t startCameraMode(camera_mode mode);
|
||||
status_t startPreviewMode();
|
||||
status_t startRecordingMode();
|
||||
status_t setOverlay();
|
||||
status_t registerPreviewBuffers();
|
||||
|
||||
// these are static callback functions
|
||||
static void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
|
||||
static void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user);
|
||||
static void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user);
|
||||
// convert client from cookie
|
||||
static sp<Client> getClientFromCookie(void* user);
|
||||
// handlers for messages
|
||||
void handleShutter(image_rect_type *size);
|
||||
void handlePreviewData(const sp<IMemory>& mem);
|
||||
void handlePostview(const sp<IMemory>& mem);
|
||||
void handleRawPicture(const sp<IMemory>& mem);
|
||||
void handleCompressedPicture(const sp<IMemory>& mem);
|
||||
void handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2);
|
||||
void handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr);
|
||||
void handleGenericDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
|
||||
|
||||
void copyFrameAndPostCopiedFrame(
|
||||
const sp<ICameraClient>& client,
|
||||
const sp<IMemoryHeap>& heap,
|
||||
size_t offset, size_t size);
|
||||
|
||||
// these are initialized in the constructor.
|
||||
sp<CameraService> mCameraService; // immutable after constructor
|
||||
sp<ICameraClient> mCameraClient;
|
||||
int mCameraId; // immutable after constructor
|
||||
pid_t mClientPid;
|
||||
sp<CameraHardwareInterface> mHardware; // cleared after disconnect()
|
||||
bool mUseOverlay; // immutable after constructor
|
||||
sp<OverlayRef> mOverlayRef;
|
||||
int mOverlayW;
|
||||
int mOverlayH;
|
||||
int mPreviewCallbackFlag;
|
||||
int mOrientation;
|
||||
|
||||
// Ensures atomicity among the public methods
|
||||
mutable Mutex mLock;
|
||||
mutable Mutex mLock;
|
||||
sp<ISurface> mSurface;
|
||||
|
||||
// mSurfaceLock synchronizes access to mSurface between
|
||||
// setPreviewSurface() and postPreviewFrame(). Note that among
|
||||
// the public methods, all accesses to mSurface are
|
||||
// syncrhonized by mLock. However, postPreviewFrame() is called
|
||||
// by the CameraHardwareInterface callback, and needs to
|
||||
// access mSurface. It cannot hold mLock, however, because
|
||||
// stopPreview() may be holding that lock while attempting
|
||||
// to stop preview, and stopPreview itself will block waiting
|
||||
// for a callback from CameraHardwareInterface. If this
|
||||
// happens, it will cause a deadlock.
|
||||
mutable Mutex mSurfaceLock;
|
||||
mutable Condition mReady;
|
||||
sp<CameraService> mCameraService;
|
||||
sp<ISurface> mSurface;
|
||||
int mPreviewCallbackFlag;
|
||||
int mOrientation;
|
||||
// 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.
|
||||
sp<MemoryHeapBase> mPreviewBuffer;
|
||||
|
||||
sp<MediaPlayer> mMediaPlayerClick;
|
||||
sp<MediaPlayer> mMediaPlayerBeep;
|
||||
// We need to avoid the deadlock when the incoming command thread and
|
||||
// the CameraHardwareInterface callback thread both want to grab mLock.
|
||||
// An extra flag is used to tell the callback thread that it should stop
|
||||
// trying to deliver the callback messages if the client is not
|
||||
// interested in it anymore. For example, if the client is calling
|
||||
// stopPreview(), the preview frame messages do not need to be delivered
|
||||
// anymore.
|
||||
|
||||
// these are immutable once the object is created,
|
||||
// they don't need to be protected by a lock
|
||||
sp<ICameraClient> mCameraClient;
|
||||
sp<CameraHardwareInterface> mHardware;
|
||||
pid_t mClientPid;
|
||||
bool mUseOverlay;
|
||||
// This function takes the same parameter as the enableMsgType() and
|
||||
// disableMsgType() functions in CameraHardwareInterface.
|
||||
void enableMsgType(int32_t msgType);
|
||||
void disableMsgType(int32_t msgType);
|
||||
volatile int32_t mMsgEnabled;
|
||||
|
||||
sp<OverlayRef> mOverlayRef;
|
||||
int mOverlayW;
|
||||
int mOverlayH;
|
||||
|
||||
mutable Mutex mPreviewLock;
|
||||
sp<MemoryHeapBase> mPreviewBuffer;
|
||||
// This function keeps trying to grab mLock, or give up if the message
|
||||
// is found to be disabled. It returns true if mLock is grabbed.
|
||||
bool lockIfMessageWanted(int32_t msgType);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
CameraService();
|
||||
virtual ~CameraService();
|
||||
|
||||
// We use a count for number of clients (shoule only be 0 or 1).
|
||||
volatile int32_t mUsers;
|
||||
virtual void incUsers();
|
||||
virtual void decUsers();
|
||||
|
||||
mutable Mutex mServiceLock;
|
||||
wp<Client> mClient;
|
||||
|
||||
#if DEBUG_HEAP_LEAKS
|
||||
wp<IMemoryHeap> gWeakHeap;
|
||||
#endif
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
} // namespace android
|
||||
|
||||
#endif
|
||||
|
||||
@@ -198,10 +198,11 @@ static const int SHIFT2 = 16;
|
||||
static const int DELTA = kYb*(1 << SHIFT2);
|
||||
static const int GAMMA = kYr*(1 << SHIFT2);
|
||||
|
||||
int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16,uint8_t *yuv422,uint32_t *param,uint8_t *table[])
|
||||
int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16, uint8_t *yuv420,
|
||||
uint32_t *param, uint8_t *table[])
|
||||
{
|
||||
uint16_t *inputRGB = (uint16_t*)rgb16;
|
||||
uint8_t *outYUV = yuv422;
|
||||
uint8_t *outYUV = yuv420;
|
||||
int32_t width_dst = param[0];
|
||||
int32_t height_dst = param[1];
|
||||
int32_t pitch_dst = param[2];
|
||||
@@ -260,12 +261,14 @@ uint32_t temp;
|
||||
|
||||
tempY[0] = y0;
|
||||
tempY[1] = y1;
|
||||
tempU[0] = u;
|
||||
tempV[0] = v;
|
||||
|
||||
tempY += 2;
|
||||
tempU += 2;
|
||||
tempV += 2;
|
||||
|
||||
if ((j&1) == 0) {
|
||||
tempU[0] = u;
|
||||
tempV[0] = v;
|
||||
tempU += 2;
|
||||
tempV += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inputRGB += pitch_src;
|
||||
@@ -277,7 +280,7 @@ uint32_t temp;
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
|
||||
static void convert_rgb16_to_yuv422(uint8_t *rgb, uint8_t *yuv, int width, int height)
|
||||
static void convert_rgb16_to_yuv420(uint8_t *rgb, uint8_t *yuv, int width, int height)
|
||||
{
|
||||
if (!tables_initialized) {
|
||||
initYtab();
|
||||
@@ -326,7 +329,7 @@ void FakeCamera::setSize(int width, int height)
|
||||
mCheckY = 0;
|
||||
|
||||
// This will cause it to be reallocated on the next call
|
||||
// to getNextFrameAsYuv422().
|
||||
// to getNextFrameAsYuv420().
|
||||
delete[] mTmpRgb16Buffer;
|
||||
mTmpRgb16Buffer = 0;
|
||||
}
|
||||
@@ -347,13 +350,13 @@ void FakeCamera::getNextFrameAsRgb565(uint16_t *buffer)
|
||||
mCounter++;
|
||||
}
|
||||
|
||||
void FakeCamera::getNextFrameAsYuv422(uint8_t *buffer)
|
||||
void FakeCamera::getNextFrameAsYuv420(uint8_t *buffer)
|
||||
{
|
||||
if (mTmpRgb16Buffer == 0)
|
||||
mTmpRgb16Buffer = new uint16_t[mWidth * mHeight];
|
||||
|
||||
getNextFrameAsRgb565(mTmpRgb16Buffer);
|
||||
convert_rgb16_to_yuv422((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight);
|
||||
convert_rgb16_to_yuv420((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight);
|
||||
}
|
||||
|
||||
void FakeCamera::drawSquare(uint16_t *dst, int x, int y, int size, int color, int shadow)
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
~FakeCamera();
|
||||
|
||||
void setSize(int width, int height);
|
||||
void getNextFrameAsYuv422(uint8_t *buffer);
|
||||
void getNextFrameAsYuv420(uint8_t *buffer);
|
||||
// Write to the fd a string representing the current state.
|
||||
void dump(int fd) const;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ void assert_fail(const char *file, int line, const char *func, const char *expr)
|
||||
INFO("assertion failed at file %s, line %d, function %s:",
|
||||
file, line, func);
|
||||
INFO("%s", expr);
|
||||
exit(1);
|
||||
abort();
|
||||
}
|
||||
|
||||
void assert_eq_fail(const char *file, int line, const char *func,
|
||||
@@ -46,7 +46,7 @@ void assert_eq_fail(const char *file, int line, const char *func,
|
||||
INFO("assertion failed at file %s, line %d, function %s:",
|
||||
file, line, func);
|
||||
INFO("(expected) %s != (actual) %d", expr, actual);
|
||||
exit(1);
|
||||
abort();
|
||||
}
|
||||
|
||||
#define ASSERT(e) \
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
|
||||
virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
|
||||
virtual void dataCallbackTimestamp(nsecs_t timestamp,
|
||||
int32_t msgType, const sp<IMemory>& data) {}
|
||||
int32_t msgType, const sp<IMemory>& data);
|
||||
|
||||
// new functions
|
||||
void clearStat();
|
||||
@@ -176,6 +176,7 @@ private:
|
||||
DefaultKeyedVector<int32_t, int> mDataCount;
|
||||
DefaultKeyedVector<int32_t, int> mDataSize;
|
||||
bool test(OP op, int v1, int v2);
|
||||
void assertTest(OP op, int v1, int v2);
|
||||
|
||||
ICamera *mReleaser;
|
||||
};
|
||||
@@ -199,22 +200,29 @@ bool MCameraClient::test(OP op, int v1, int v2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void MCameraClient::assertTest(OP op, int v1, int v2) {
|
||||
if (!test(op, v1, v2)) {
|
||||
LOGE("assertTest failed: op=%d, v1=%d, v2=%d", op, v1, v2);
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void MCameraClient::assertNotify(int32_t msgType, OP op, int count) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
int v = mNotifyCount.valueFor(msgType);
|
||||
ASSERT(test(op, v, count));
|
||||
assertTest(op, v, count);
|
||||
}
|
||||
|
||||
void MCameraClient::assertData(int32_t msgType, OP op, int count) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
int v = mDataCount.valueFor(msgType);
|
||||
ASSERT(test(op, v, count));
|
||||
assertTest(op, v, count);
|
||||
}
|
||||
|
||||
void MCameraClient::assertDataSize(int32_t msgType, OP op, int dataSize) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
int v = mDataSize.valueFor(msgType);
|
||||
ASSERT(test(op, v, dataSize));
|
||||
assertTest(op, v, dataSize);
|
||||
}
|
||||
|
||||
void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
|
||||
@@ -250,6 +258,11 @@ void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {
|
||||
}
|
||||
}
|
||||
|
||||
void MCameraClient::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
|
||||
const sp<IMemory>& data) {
|
||||
dataCallback(msgType, data);
|
||||
}
|
||||
|
||||
void MCameraClient::waitNotify(int32_t msgType, OP op, int count) {
|
||||
INFO("waitNotify: %d, %d, %d", msgType, op, count);
|
||||
Mutex::Autolock _l(mLock);
|
||||
@@ -348,10 +361,9 @@ void MSurface::waitUntil(int c0, int c1, int c2) {
|
||||
|
||||
sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,
|
||||
int32_t orientation) {
|
||||
// We don't expect this to be called in current hardware.
|
||||
// Not implemented.
|
||||
ASSERT(0);
|
||||
sp<OverlayRef> dummy;
|
||||
return dummy;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -395,38 +407,43 @@ sp<ICameraService> getCameraService() {
|
||||
return cs;
|
||||
}
|
||||
|
||||
int getNumberOfCameras() {
|
||||
sp<ICameraService> cs = getCameraService();
|
||||
return cs->getNumberOfCameras();
|
||||
}
|
||||
|
||||
//
|
||||
// Various Connect Tests
|
||||
//
|
||||
void testConnect() {
|
||||
void testConnect(int cameraId) {
|
||||
INFO(__func__);
|
||||
sp<ICameraService> cs = getCameraService();
|
||||
sp<MCameraClient> cc = new MCameraClient();
|
||||
sp<ICamera> c = cs->connect(cc);
|
||||
sp<ICamera> c = cs->connect(cc, cameraId);
|
||||
ASSERT(c != 0);
|
||||
c->disconnect();
|
||||
}
|
||||
|
||||
void testAllowConnectOnceOnly() {
|
||||
void testAllowConnectOnceOnly(int cameraId) {
|
||||
INFO(__func__);
|
||||
sp<ICameraService> cs = getCameraService();
|
||||
// Connect the first client.
|
||||
sp<MCameraClient> cc = new MCameraClient();
|
||||
sp<ICamera> c = cs->connect(cc);
|
||||
sp<ICamera> c = cs->connect(cc, cameraId);
|
||||
ASSERT(c != 0);
|
||||
// Same client -- ok.
|
||||
ASSERT(cs->connect(cc) != 0);
|
||||
ASSERT(cs->connect(cc, cameraId) != 0);
|
||||
// Different client -- not ok.
|
||||
sp<MCameraClient> cc2 = new MCameraClient();
|
||||
ASSERT(cs->connect(cc2) == 0);
|
||||
ASSERT(cs->connect(cc2, cameraId) == 0);
|
||||
c->disconnect();
|
||||
}
|
||||
|
||||
void testReconnectFailed() {
|
||||
INFO(__func__);
|
||||
sp<ICamera> c = interface_cast<ICamera>(getTempObject());
|
||||
sp<MCameraClient> cc2 = new MCameraClient();
|
||||
ASSERT(c->connect(cc2) != NO_ERROR);
|
||||
sp<MCameraClient> cc = new MCameraClient();
|
||||
ASSERT(c->connect(cc) != NO_ERROR);
|
||||
}
|
||||
|
||||
void testReconnectSuccess() {
|
||||
@@ -434,6 +451,7 @@ void testReconnectSuccess() {
|
||||
sp<ICamera> c = interface_cast<ICamera>(getTempObject());
|
||||
sp<MCameraClient> cc = new MCameraClient();
|
||||
ASSERT(c->connect(cc) == NO_ERROR);
|
||||
c->disconnect();
|
||||
}
|
||||
|
||||
void testLockFailed() {
|
||||
@@ -453,6 +471,7 @@ void testLockSuccess() {
|
||||
INFO(__func__);
|
||||
sp<ICamera> c = interface_cast<ICamera>(getTempObject());
|
||||
ASSERT(c->lock() == NO_ERROR);
|
||||
c->disconnect();
|
||||
}
|
||||
|
||||
//
|
||||
@@ -499,11 +518,11 @@ void runInAnotherProcess(const char *tag) {
|
||||
}
|
||||
}
|
||||
|
||||
void testReconnect() {
|
||||
void testReconnect(int cameraId) {
|
||||
INFO(__func__);
|
||||
sp<ICameraService> cs = getCameraService();
|
||||
sp<MCameraClient> cc = new MCameraClient();
|
||||
sp<ICamera> c = cs->connect(cc);
|
||||
sp<ICamera> c = cs->connect(cc, cameraId);
|
||||
ASSERT(c != 0);
|
||||
// Reconnect to the same client -- ok.
|
||||
ASSERT(c->connect(cc) == NO_ERROR);
|
||||
@@ -514,10 +533,10 @@ void testReconnect() {
|
||||
cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
|
||||
}
|
||||
|
||||
void testLockUnlock() {
|
||||
void testLockUnlock(int cameraId) {
|
||||
sp<ICameraService> cs = getCameraService();
|
||||
sp<MCameraClient> cc = new MCameraClient();
|
||||
sp<ICamera> c = cs->connect(cc);
|
||||
sp<ICamera> c = cs->connect(cc, cameraId);
|
||||
ASSERT(c != 0);
|
||||
// We can lock as many times as we want.
|
||||
ASSERT(c->lock() == NO_ERROR);
|
||||
@@ -530,16 +549,15 @@ void testLockUnlock() {
|
||||
runInAnotherProcess("testLockUnlockSuccess");
|
||||
// Unlock then lock from a different process -- ok.
|
||||
runInAnotherProcess("testLockSuccess");
|
||||
c->disconnect();
|
||||
clearTempObject();
|
||||
}
|
||||
|
||||
void testReconnectFromAnotherProcess() {
|
||||
void testReconnectFromAnotherProcess(int cameraId) {
|
||||
INFO(__func__);
|
||||
|
||||
sp<ICameraService> cs = getCameraService();
|
||||
sp<MCameraClient> cc = new MCameraClient();
|
||||
sp<ICamera> c = cs->connect(cc);
|
||||
sp<ICamera> c = cs->connect(cc, cameraId);
|
||||
ASSERT(c != 0);
|
||||
// Reconnect from a different process -- not ok.
|
||||
putTempObject(c->asBinder());
|
||||
@@ -547,7 +565,6 @@ void testReconnectFromAnotherProcess() {
|
||||
// Unlock then reconnect from a different process -- ok.
|
||||
ASSERT(c->unlock() == NO_ERROR);
|
||||
runInAnotherProcess("testReconnectSuccess");
|
||||
c->disconnect();
|
||||
clearTempObject();
|
||||
}
|
||||
|
||||
@@ -560,10 +577,11 @@ static void flushCommands() {
|
||||
}
|
||||
|
||||
// Run a test case
|
||||
#define RUN(class_name) do { \
|
||||
#define RUN(class_name, cameraId) do { \
|
||||
{ \
|
||||
INFO(#class_name); \
|
||||
class_name instance; \
|
||||
instance.init(cameraId); \
|
||||
instance.run(); \
|
||||
} \
|
||||
flushCommands(); \
|
||||
@@ -571,19 +589,21 @@ static void flushCommands() {
|
||||
|
||||
// Base test case after the the camera is connected.
|
||||
class AfterConnect {
|
||||
public:
|
||||
void init(int cameraId) {
|
||||
cs = getCameraService();
|
||||
cc = new MCameraClient();
|
||||
c = cs->connect(cc, cameraId);
|
||||
ASSERT(c != 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
sp<ICameraService> cs;
|
||||
sp<MCameraClient> cc;
|
||||
sp<ICamera> c;
|
||||
|
||||
AfterConnect() {
|
||||
cs = getCameraService();
|
||||
cc = new MCameraClient();
|
||||
c = cs->connect(cc);
|
||||
ASSERT(c != 0);
|
||||
}
|
||||
|
||||
~AfterConnect() {
|
||||
c->disconnect();
|
||||
c.clear();
|
||||
cc.clear();
|
||||
cs.clear();
|
||||
@@ -612,19 +632,16 @@ public:
|
||||
surface->waitUntil(1, 10, 0); // needs 1 registerBuffers and 10 postBuffer
|
||||
surface->clearStat();
|
||||
|
||||
c->disconnect();
|
||||
// TODO: CameraService crashes for this. Fix it.
|
||||
#if 0
|
||||
sp<MSurface> another_surface = new MSurface();
|
||||
c->setPreviewDisplay(another_surface); // just to make sure unregisterBuffers
|
||||
// is called.
|
||||
surface->waitUntil(0, 0, 1); // needs unregisterBuffers
|
||||
#endif
|
||||
|
||||
cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
|
||||
}
|
||||
};
|
||||
|
||||
class TestStartPreviewWithoutDisplay : AfterConnect {
|
||||
class TestStartPreviewWithoutDisplay : public AfterConnect {
|
||||
public:
|
||||
void run() {
|
||||
ASSERT(c->startPreview() == NO_ERROR);
|
||||
@@ -636,15 +653,17 @@ public:
|
||||
|
||||
// Base test case after the the camera is connected and the preview is started.
|
||||
class AfterStartPreview : public AfterConnect {
|
||||
protected:
|
||||
sp<MSurface> surface;
|
||||
|
||||
AfterStartPreview() {
|
||||
public:
|
||||
void init(int cameraId) {
|
||||
AfterConnect::init(cameraId);
|
||||
surface = new MSurface();
|
||||
ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
|
||||
ASSERT(c->startPreview() == NO_ERROR);
|
||||
}
|
||||
|
||||
protected:
|
||||
sp<MSurface> surface;
|
||||
|
||||
~AfterStartPreview() {
|
||||
surface.clear();
|
||||
}
|
||||
@@ -680,9 +699,6 @@ public:
|
||||
cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
|
||||
cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
|
||||
c->stopPreview();
|
||||
#if 1 // TODO: It crashes if we don't have this. Fix it.
|
||||
usleep(100000);
|
||||
#endif
|
||||
c->disconnect();
|
||||
cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
|
||||
}
|
||||
@@ -697,7 +713,6 @@ public:
|
||||
cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
|
||||
cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
|
||||
cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
|
||||
usleep(100000); // 100ms
|
||||
}
|
||||
c->disconnect();
|
||||
cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
|
||||
@@ -712,32 +727,67 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static bool getNextSize(const char **ptrS, int *w, int *h) {
|
||||
const char *s = *ptrS;
|
||||
|
||||
// skip over ','
|
||||
if (*s == ',') s++;
|
||||
|
||||
// remember start position in p
|
||||
const char *p = s;
|
||||
while (*s != '\0' && *s != 'x') {
|
||||
s++;
|
||||
}
|
||||
if (*s == '\0') return false;
|
||||
|
||||
// get the width
|
||||
*w = atoi(p);
|
||||
|
||||
// skip over 'x'
|
||||
ASSERT(*s == 'x');
|
||||
p = s + 1;
|
||||
while (*s != '\0' && *s != ',') {
|
||||
s++;
|
||||
}
|
||||
|
||||
// get the height
|
||||
*h = atoi(p);
|
||||
*ptrS = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
class TestPictureSize : public AfterStartPreview {
|
||||
public:
|
||||
void checkOnePicture(int w, int h) {
|
||||
const float rate = 0.5; // byte per pixel limit
|
||||
const float rate = 0.9; // byte per pixel limit
|
||||
int pixels = w * h;
|
||||
|
||||
CameraParameters param(c->getParameters());
|
||||
param.setPictureSize(w, h);
|
||||
// disable thumbnail to get more accurate size.
|
||||
param.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, 0);
|
||||
param.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, 0);
|
||||
c->setParameters(param.flatten());
|
||||
|
||||
cc->clearStat();
|
||||
ASSERT(c->takePicture() == NO_ERROR);
|
||||
cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
|
||||
cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
|
||||
//cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
|
||||
cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
|
||||
cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::LT,
|
||||
int(pixels * rate));
|
||||
cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::GT, 0);
|
||||
cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
|
||||
usleep(100000); // 100ms
|
||||
}
|
||||
|
||||
void run() {
|
||||
checkOnePicture(2048, 1536);
|
||||
checkOnePicture(1600, 1200);
|
||||
checkOnePicture(1024, 768);
|
||||
CameraParameters param(c->getParameters());
|
||||
int w, h;
|
||||
const char *s = param.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
|
||||
while (getNextSize(&s, &w, &h)) {
|
||||
LOGD("checking picture size %dx%d", w, h);
|
||||
checkOnePicture(w, h);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -749,6 +799,8 @@ public:
|
||||
|
||||
// Try all flag combinations.
|
||||
for (int v = 0; v < 8; v++) {
|
||||
LOGD("TestPreviewCallbackFlag: flag=%d", v);
|
||||
usleep(100000); // sleep a while to clear the in-flight callbacks.
|
||||
cc->clearStat();
|
||||
c->setPreviewCallbackFlag(v);
|
||||
ASSERT(c->previewEnabled() == false);
|
||||
@@ -781,6 +833,7 @@ public:
|
||||
ASSERT(c->recordingEnabled() == true);
|
||||
sleep(2);
|
||||
c->stopRecording();
|
||||
usleep(100000); // sleep a while to clear the in-flight callbacks.
|
||||
cc->setReleaser(NULL);
|
||||
cc->assertData(CAMERA_MSG_VIDEO_FRAME, MCameraClient::GE, 10);
|
||||
}
|
||||
@@ -806,9 +859,13 @@ public:
|
||||
}
|
||||
|
||||
void run() {
|
||||
checkOnePicture(480, 320);
|
||||
checkOnePicture(352, 288);
|
||||
checkOnePicture(176, 144);
|
||||
CameraParameters param(c->getParameters());
|
||||
int w, h;
|
||||
const char *s = param.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
|
||||
while (getNextSize(&s, &w, &h)) {
|
||||
LOGD("checking preview size %dx%d", w, h);
|
||||
checkOnePicture(w, h);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -827,23 +884,30 @@ int main(int argc, char **argv)
|
||||
INFO("CameraServiceTest start");
|
||||
gExecutable = argv[0];
|
||||
runHolderService();
|
||||
int n = getNumberOfCameras();
|
||||
INFO("%d Cameras available", n);
|
||||
|
||||
testConnect(); flushCommands();
|
||||
testAllowConnectOnceOnly(); flushCommands();
|
||||
testReconnect(); flushCommands();
|
||||
testLockUnlock(); flushCommands();
|
||||
testReconnectFromAnotherProcess(); flushCommands();
|
||||
for (int id = 0; id < n; id++) {
|
||||
INFO("Testing camera %d", id);
|
||||
testConnect(id); flushCommands();
|
||||
testAllowConnectOnceOnly(id); flushCommands();
|
||||
testReconnect(id); flushCommands();
|
||||
testLockUnlock(id); flushCommands();
|
||||
testReconnectFromAnotherProcess(id); flushCommands();
|
||||
|
||||
RUN(TestSetPreviewDisplay);
|
||||
RUN(TestStartPreview);
|
||||
RUN(TestStartPreviewWithoutDisplay);
|
||||
RUN(TestAutoFocus);
|
||||
RUN(TestStopPreview);
|
||||
RUN(TestTakePicture);
|
||||
RUN(TestTakeMultiplePictures);
|
||||
RUN(TestGetParameters);
|
||||
RUN(TestPictureSize);
|
||||
RUN(TestPreviewCallbackFlag);
|
||||
RUN(TestRecording);
|
||||
RUN(TestPreviewSize);
|
||||
RUN(TestSetPreviewDisplay, id);
|
||||
RUN(TestStartPreview, id);
|
||||
RUN(TestStartPreviewWithoutDisplay, id);
|
||||
RUN(TestAutoFocus, id);
|
||||
RUN(TestStopPreview, id);
|
||||
RUN(TestTakePicture, id);
|
||||
RUN(TestTakeMultiplePictures, id);
|
||||
RUN(TestGetParameters, id);
|
||||
RUN(TestPictureSize, id);
|
||||
RUN(TestPreviewCallbackFlag, id);
|
||||
RUN(TestRecording, id);
|
||||
RUN(TestPreviewSize, id);
|
||||
}
|
||||
|
||||
INFO("CameraServiceTest finished");
|
||||
}
|
||||
|
||||
@@ -84,13 +84,29 @@ public class Camera {
|
||||
private boolean mWithBuffer;
|
||||
|
||||
/**
|
||||
* Returns a new Camera object.
|
||||
* Returns the number of Cameras available.
|
||||
* @hide
|
||||
*/
|
||||
public static Camera open() {
|
||||
return new Camera();
|
||||
public native static int getNumberOfCameras();
|
||||
|
||||
/**
|
||||
* Returns a new Camera object.
|
||||
* If {@link #getNumberOfCameras()} returns N, the valid is is 0 to N-1.
|
||||
* The id 0 is the default camera.
|
||||
* @hide
|
||||
*/
|
||||
public static Camera open(int cameraId) {
|
||||
return new Camera(cameraId);
|
||||
}
|
||||
|
||||
Camera() {
|
||||
/**
|
||||
* Returns a new Camera object. This returns the default camera.
|
||||
*/
|
||||
public static Camera open() {
|
||||
return new Camera(0);
|
||||
}
|
||||
|
||||
Camera(int cameraId) {
|
||||
mShutterCallback = null;
|
||||
mRawImageCallback = null;
|
||||
mJpegCallback = null;
|
||||
@@ -107,14 +123,14 @@ public class Camera {
|
||||
mEventHandler = null;
|
||||
}
|
||||
|
||||
native_setup(new WeakReference<Camera>(this));
|
||||
native_setup(new WeakReference<Camera>(this), cameraId);
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
native_release();
|
||||
}
|
||||
|
||||
private native final void native_setup(Object camera_this);
|
||||
private native final void native_setup(Object camera_this, int cameraId);
|
||||
private native final void native_release();
|
||||
|
||||
|
||||
|
||||
@@ -288,10 +288,16 @@ void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env)
|
||||
}
|
||||
}
|
||||
|
||||
// connect to camera service
|
||||
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
|
||||
static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz)
|
||||
{
|
||||
sp<Camera> camera = Camera::connect();
|
||||
return Camera::getNumberOfCameras();
|
||||
}
|
||||
|
||||
// connect to camera service
|
||||
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
|
||||
jobject weak_this, jint cameraId)
|
||||
{
|
||||
sp<Camera> camera = Camera::connect(cameraId);
|
||||
|
||||
if (camera == NULL) {
|
||||
jniThrowException(env, "java/lang/RuntimeException",
|
||||
@@ -566,8 +572,11 @@ static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject t
|
||||
//-------------------------------------------------
|
||||
|
||||
static JNINativeMethod camMethods[] = {
|
||||
{ "getNumberOfCameras",
|
||||
"()I",
|
||||
(void *)android_hardware_Camera_getNumberOfCameras },
|
||||
{ "native_setup",
|
||||
"(Ljava/lang/Object;)V",
|
||||
"(Ljava/lang/Object;I)V",
|
||||
(void*)android_hardware_Camera_native_setup },
|
||||
{ "native_release",
|
||||
"()V",
|
||||
|
||||
@@ -113,7 +113,8 @@ class Camera : public BnCameraClient, public IBinder::DeathRecipient
|
||||
public:
|
||||
// construct a camera client from an existing remote
|
||||
static sp<Camera> create(const sp<ICamera>& camera);
|
||||
static sp<Camera> connect();
|
||||
static int32_t getNumberOfCameras();
|
||||
static sp<Camera> connect(int cameraId);
|
||||
~Camera();
|
||||
void init();
|
||||
|
||||
|
||||
@@ -30,13 +30,16 @@ class ICameraService : public IInterface
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
CONNECT = IBinder::FIRST_CALL_TRANSACTION,
|
||||
GET_NUMBER_OF_CAMERAS = IBinder::FIRST_CALL_TRANSACTION,
|
||||
CONNECT
|
||||
};
|
||||
|
||||
public:
|
||||
DECLARE_META_INTERFACE(CameraService);
|
||||
|
||||
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient) = 0;
|
||||
virtual int32_t getNumberOfCameras() = 0;
|
||||
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient,
|
||||
int cameraId) = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -95,13 +95,20 @@ Camera::~Camera()
|
||||
disconnect();
|
||||
}
|
||||
|
||||
sp<Camera> Camera::connect()
|
||||
int32_t Camera::getNumberOfCameras()
|
||||
{
|
||||
const sp<ICameraService>& cs = getCameraService();
|
||||
if (cs == 0) return 0;
|
||||
return cs->getNumberOfCameras();
|
||||
}
|
||||
|
||||
sp<Camera> Camera::connect(int cameraId)
|
||||
{
|
||||
LOGV("connect");
|
||||
sp<Camera> c = new Camera();
|
||||
const sp<ICameraService>& cs = getCameraService();
|
||||
if (cs != 0) {
|
||||
c->mCamera = cs->connect(c);
|
||||
c->mCamera = cs->connect(c, cameraId);
|
||||
}
|
||||
if (c->mCamera != 0) {
|
||||
c->mCamera->asBinder()->linkToDeath(c);
|
||||
|
||||
@@ -34,12 +34,22 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// get number of cameras available
|
||||
virtual int32_t getNumberOfCameras()
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
|
||||
remote()->transact(BnCameraService::GET_NUMBER_OF_CAMERAS, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
// connect to camera service
|
||||
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient)
|
||||
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(cameraClient->asBinder());
|
||||
data.writeInt32(cameraId);
|
||||
remote()->transact(BnCameraService::CONNECT, data, &reply);
|
||||
return interface_cast<ICamera>(reply.readStrongBinder());
|
||||
}
|
||||
@@ -53,10 +63,15 @@ status_t BnCameraService::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch(code) {
|
||||
case GET_NUMBER_OF_CAMERAS: {
|
||||
CHECK_INTERFACE(ICameraService, data, reply);
|
||||
reply->writeInt32(getNumberOfCameras());
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case CONNECT: {
|
||||
CHECK_INTERFACE(ICameraService, data, reply);
|
||||
sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
|
||||
sp<ICamera> camera = connect(cameraClient);
|
||||
sp<ICamera> camera = connect(cameraClient, data.readInt32());
|
||||
reply->writeStrongBinder(camera->asBinder());
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
@@ -106,7 +106,7 @@ void CameraSourceListener::postDataTimestamp(
|
||||
|
||||
// static
|
||||
CameraSource *CameraSource::Create() {
|
||||
sp<Camera> camera = Camera::connect();
|
||||
sp<Camera> camera = Camera::connect(0);
|
||||
|
||||
if (camera.get() == NULL) {
|
||||
return NULL;
|
||||
|
||||
Reference in New Issue
Block a user