Android Camera TakePicture過程分析
Android Camera TakePicture過程分析
接著上一篇文章,繼續講解camera拍照等具體功能實行流程
Camera子系统采用C/S架构,客户端和服务端在两个不同的进程当中,它们使用android中的binder机制进行通信,
本系列文章将从Android Camera应用程序到硬件抽象的实现一步一步对照相机系统进行分析,首先从CameraService初始化过程着手,然后从上层APP打开照相机->进行preview->拍照以及聚焦等功能的实现全面的学习照相机子系统
1、CameraService初始化过程
frameworks\base\media\mediaserver\Main_MediaServer.cpp
CameraService在MediaServer中初始化,代码是MediaServer的main函数,在该函数中初始化照相机服务,已在上一篇文章中講述
CameraService中的instantiate方法用来创建CameraService实例,并进行相应的初始化,这个函数定义在它的父类BinderService中:frameworks/base/include/binder/BinderService.h
相机服务的初始化过程首先是创建CameraService实例,然后将其注册到ServiceManager中,关于它的启动是发生在init.rc中,通过media_server来启动CameraService,具体代码如下:
system/core/rootdir/init.rc
service servicemanager /system/bin/servicemanager
class core
user system
group system
critical
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
service media /system/bin/mediaserver
class main
user media
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc
ioprio rt 4
在cameraService注册以及启动过程中cameraService自身会执行一些初始化的工作,主要涉及到如下工作
frameworks/base/services/camera/libcameraservice/CameraService.cpp
- CameraService::CameraService()
-
:mSoundRef(0),mModule(0)
-
{
- LOGI("CameraService started (pid=%d)",getpid());
- gCameraService=this;
-
}
- void CameraService::onFirstRef()
-
{
- BnCameraService::onFirstRef();
-
if(hw_get_module(CAMERA_HARDWARE_MODULE_ID,
-
(consthw_module_t**)&mModule)<0){
- LOGE("Could not load camera HAL module");
- mNumberOfCameras=0;
-
}
-
else{
-
mNumberOfCameras=mModule->get_number_of_cameras();
-
if(mNumberOfCameras>MAX_CAMERAS){
- LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
- mNumberOfCameras,MAX_CAMERAS);
- mNumberOfCameras=MAX_CAMERAS;
-
}
-
for(inti=0;i<mNumberOfCameras;i++){
- setCameraFree(i);
-
}
-
}
- }
2、应用程序链接相机服务过程
在camera应用程序启动的时候首先会和CameraService建立连接,camera应用程序代码就不分析了,上一篇文章已經說過,下面这副图是一个简单的流程图
从上面的流程图我们可以看出在请求服务的过程中多出用到了应用框架层的camera类,该类定义在 frameworks/base/core/java/android/hardware/Camera.java文件当中,这一个类正是Camera子系统中APP层和JNI层交换的接口,它对上为应用程序提供了各种操作Camera的方法,向下访问JNI实现它自身的接口Camera类定义如下:
- publicclassCamera{
-
publicstatic Camera open(intcameraId){
- return new Camera(cameraId);
-
}
-
.................
- Camera(intcameraId){
- Looper looper;
-
if((looper=Looper.myLooper())!=null){
- mEventHandler=new EventHandler(this,looper);
-
}elseif((looper=Looper.getMainLooper())!=null){
- mEventHandler=new EventHandler(this,looper);
-
}else{
- mEventHandler=null;
-
}
- native_setup(new WeakReference<Camera>(this),cameraId);
-
}
- }
在app中,takepicture是在capture方法中被调用的:packages/apps/OMAPCamera/src/com/ti/omap4/android/camera/Camera.java(apk)
- @Override
-
publicboolean capture(){
- synchronized(mCameraStateLock){
-
//Ifwe are alreadyinthe
middle of taking a snapshotthenignore.
-
if(mCameraState==SNAPSHOT_IN_PROGRESS||mCameraDevice==null){
- returnfalse;
-
}
- mCaptureStartTime=System.currentTimeMillis();
- mPostViewPictureCallbackTime=0;
- mJpegImageData=null;
-
//Setrotationandgps
data.
- Util.setRotationParameter(mParameters,mCameraId,mOrientation);
-
Locationloc=mLocationManager.getCurrentLocation();
- Util.setGpsParameters(mParameters,loc);
-
if(canSetParameters()){
- mCameraDevice.setParameters(mParameters);
-
}
- try{
-
mCameraDevice.takePicture(mShutterCallback,mRawPictureCallback,
-
mPostViewPictureCallback,new
JpegPictureCallback(loc));
-
}catch(RuntimeException e){
- e.printStackTrace();
- returnfalse;
-
}
- mFaceDetectionStarted=false;
- setCameraState(SNAPSHOT_IN_PROGRESS);
- returntrue;
-
}
- }
- publicfinal void takePicture(ShutterCallback
shutter,PictureCallback raw,
- PictureCallback postview,PictureCallback jpeg){
- mShutterCallback=shutter;
- mRawImageCallback=raw;
- mPostviewCallback=postview;
- mJpegCallback=jpeg;
-
//Ifcallbackisnotset,donotsend
me callbacks.
-
intmsgType=0;
-
if(mShutterCallback!=null){
- msgType|=CAMERA_MSG_SHUTTER;
-
}
-
if(mRawImageCallback!=null){
- msgType|=CAMERA_MSG_RAW_IMAGE;
-
}
-
if(mPostviewCallback!=null){
- msgType|=CAMERA_MSG_POSTVIEW_FRAME;
-
}
-
if(mJpegCallback!=null){
- msgType|=CAMERA_MSG_COMPRESSED_IMAGE;
-
}
- native_takePicture(msgType);
- }
- static void android_hardware_Camera_takePicture(JNIEnv*env,jobject
thiz,intmsgType)
-
{
- LOGV("takePicture");
- JNICameraContext*context;
- sp<Camera>camera=get_native_camera(env,thiz,&context);
-
if(camera==0)return;
-
/*
-
*When CAMERA_MSG_RAW_IMAGEisrequested,ifthe
raw image callback
-
*bufferisavailable,CAMERA_MSG_RAW_IMAGEisenabledtogetthe
-
*notification _and_ the data;otherwise,CAMERA_MSG_RAW_IMAGE_NOTIFY
-
*isenabledtoreceive the callback
notification but no data.
-
*
-
*Note that CAMERA_MSG_RAW_IMAGE_NOTIFYisnotexposedtothe
-
*Java application.
-
*/
-
if(msgType&CAMERA_MSG_RAW_IMAGE){
- LOGV("Enable raw image callback buffer");
-
if(!context->isRawImageCallbackBufferAvailable()){
- LOGV("Enable raw image notification, since no callback buffer exists");
- msgType&=~CAMERA_MSG_RAW_IMAGE;
- msgType|=CAMERA_MSG_RAW_IMAGE_NOTIFY;
-
}
-
}
-
if(camera->takePicture(msgType)!=NO_ERROR){
- jniThrowRuntimeException(env,"takePicture
failed");
- return;
-
}
- }
- status_t Camera::takePicture(intmsgType,constString8¶ms)
-
{
- LOGV("takePicture: 0x%x",msgType);
- sp<ICamera>c=mCamera;
-
if(c==0)return
NO_INIT;
-
return c->takePicture(msgType,params);
- }
- //take a picture-imageisreturnedincallback
- #ifdef OMAP_ENHANCEMENT_CPCAM
- status_t CameraService::Client::takePicture(intmsgType,constString8¶ms){
- #else
- status_t CameraService::Client::takePicture(intmsgType){
- #endif
- LOG1("takePicture (pid %d): 0x%x",getCallingPid(),msgType);
- Mutex::Autolock lock(mLock);
- status_t result=checkPidAndHardware();
-
if(result!=NO_ERROR)return
result;
-
if((msgType&CAMERA_MSG_RAW_IMAGE)&&
-
(msgType&CAMERA_MSG_RAW_IMAGE_NOTIFY)){
- LOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
-
" cannot be both enabled");
- return BAD_VALUE;
-
}
-
//We only accept picture related message types
-
//andignore other types of messagesfortakePicture().
-
intpicMsgType=msgType
-
&(CAMERA_MSG_SHUTTER|
- CAMERA_MSG_POSTVIEW_FRAME|
- CAMERA_MSG_RAW_IMAGE|
- #ifdef OMAP_ENHANCEMENT
- CAMERA_MSG_RAW_BURST|
- #endif
- CAMERA_MSG_RAW_IMAGE_NOTIFY|
- CAMERA_MSG_COMPRESSED_IMAGE);
- #ifdef OMAP_ENHANCEMENT
- picMsgType|=CAMERA_MSG_COMPRESSED_BURST_IMAGE;
- #endif
- enableMsgType(picMsgType);
- #ifdef OMAP_ENHANCEMENT
-
//make sure the other capture messages are disabled
- picMsgType=~picMsgType&
-
(CAMERA_MSG_SHUTTER|
- CAMERA_MSG_POSTVIEW_FRAME|
- CAMERA_MSG_RAW_IMAGE|
- CAMERA_MSG_RAW_BURST|
- CAMERA_MSG_RAW_IMAGE_NOTIFY|
- CAMERA_MSG_COMPRESSED_IMAGE|
- CAMERA_MSG_COMPRESSED_BURST_IMAGE);
- disableMsgType(picMsgType);
- #endif
- #ifdef OMAP_ENHANCEMENT_CPCAM
-
return mHardware->takePicture(params);
- #else
- return mHardware->takePicture();
- #endif
- }
- /**
-
*Take a picture.
-
*/
- #ifdef OMAP_ENHANCEMENT_CPCAM
- status_t takePicture(constShotParameters¶ms)
-
{
- LOGV("%s(%s)",__FUNCTION__,mName.string());
-
if(mDevice->ops->take_picture)
- return mDevice->ops->take_picture(mDevice,
- params.flatten().string());
- return INVALID_OPERATION;
-
}
- #else
- status_t takePicture()
-
{
- LOGV("%s(%s)",__FUNCTION__,mName.string());
-
if(mDevice->ops->take_picture)
-
return mDevice->ops->take_picture(mDevice);//从这里开始通过V4L2子系统调用到kerner
driver的设备,以后针对这个部分做详细学习
- return INVALID_OPERATION;
-
}
- #endif
首先还是必须先追溯到Camera客户端与服务端连接的时候,由我的上一遍初始化的文章知道,Camera客户端与服务端连接的时候,首先调用的是client端的connect方法,
client的connect方法首先getservice,然后调用server端的connect方法,为了方便理解我再次把这部分代码贴出:
server的connect()函数定义在以下路径:frameworks/base/services/camera/libcameraservice/CameraService.cpp
- sp<ICamera>CameraService::connect(
-
constsp<ICameraClient>&cameraClient,intcameraId){
-
intcallingPid=getCallingPid();
- sp<CameraHardwareInterface>hardware=NULL;
- LOG1("CameraService::connect E (pid %d, id %d)",callingPid,cameraId);
-
if(!mModule){
- LOGE("Camera HAL module not loaded");
- returnNULL;
-
}
- sp<Client>client;
-
if(cameraId<0||cameraId>=mNumberOfCameras){
- LOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
- callingPid,cameraId);
- returnNULL;
-
}
- char value[PROPERTY_VALUE_MAX];
- property_get("sys.secpolicy.camera.disabled",value,"0");
-
if(strcmp(value,"1")==0){
-
//Cameraisdisabled by DevicePolicyManager.
- LOGI("Camera is disabled. connect X (pid %d) rejected",callingPid);
- returnNULL;
-
}
- Mutex::Autolock lock(mServiceLock);
-
if(mClient[cameraId]!=0){
- client=mClient[cameraId].promote();
-
if(client!=0){
-
if(cameraClient->asBinder()==client->getCameraClient()->asBinder()){
- LOG1("CameraService::connect X (pid %d) (the same client)",
- callingPid);
- return client;
-
}else{
- LOGW("CameraService::connect X (pid %d) rejected (existing client).",
- callingPid);
- returnNULL;
-
}
-
}
- mClient[cameraId].clear();
-
}
-
if(mBusy[cameraId]){
- LOGW("CameraService::connect X (pid %d) rejected"
-
" (camera %d is still busy).",callingPid,cameraId);
- returnNULL;
-
}
- struct camera_info info;
-
if(mModule->get_camera_info(cameraId,&info)!=OK){
- LOGE("Invalid camera id %d",cameraId);
- returnNULL;
-
}
- char camera_device_name[10];
- snprintf(camera_device_name,sizeof(camera_device_name),"%d",cameraId);
- hardware=new CameraHardwareInterface(camera_device_name);
-
if(hardware->initialize(&mModule->common)!=OK){
- hardware.clear();
- returnNULL;
-
}
-
client=new
Client(this,cameraClient,hardware,cameraId,info.facing,callingPid);
- mClient[cameraId]=client;
- LOG1("CameraService::connect X");
- return client;
- }
这个时候便会调用client这个内部类的client构造函数,而我们的回调函数也正是在这个时候被设置,看看代码:
- CameraService::Client::Client(constsp<CameraService>&cameraService,
-
constsp<ICameraClient>&cameraClient,
-
constsp<CameraHardwareInterface>&hardware,
-
intcameraId,intcameraFacing,intclientPid){
-
intcallingPid=getCallingPid();
- LOG1("Client::Client E (pid %d)",callingPid);
- mCameraService=cameraService;
- mCameraClient=cameraClient;
- mHardware=hardware;
- mCameraId=cameraId;
- mCameraFacing=cameraFacing;
- mClientPid=clientPid;
- mMsgEnabled=0;
- mSurface=0;
- mPreviewWindow=0;
- #ifdef OMAP_ENHANCEMENT_CPCAM
- mTapin=0;
- mTapinClient=0;
- mTapout=0;
- mTapoutClient=0;
- #endif
-
mHardware->setCallbacks(notifyCallback,
-
dataCallback,
-
dataCallbackTimestamp,
-
(void*)cameraId);
-
//Enable zoom,error,focus,andmetadata
messages by default
- enableMsgType(CAMERA_MSG_ERROR|CAMERA_MSG_ZOOM|CAMERA_MSG_FOCUS|
- CAMERA_MSG_PREVIEW_METADATA);
-
//Callbackisdisabled by default
- mPreviewCallbackFlag=CAMERA_FRAME_CALLBACK_FLAG_NOOP;
- mOrientation=getOrientation(0,mCameraFacing==CAMERA_FACING_FRONT);
- mPlayShutterSound=true;
- cameraService->setCameraBusy(cameraId);
- cameraService->loadSound();
- LOG1("Client::Client X (pid %d)",callingPid);
- }
这里先针对其中的dataCallback回调方法做介绍,其他的回调方法以此类推,所以我们就先看一下dataCallback方法中都做了些什么事情:
这里的回调函数是camera server层的回调函数:frameworks/base/services/camera/libcameraservice/CameraService.cpp
- void CameraService::Client::dataCallback(int32_t
msgType,
-
constsp<IMemory>&dataPtr,camera_frame_metadata_t*metadata,void*user){
- LOG2("dataCallback(%d)",msgType);
- sp<Client>client=getClientFromCookie(user);
-
if(client==0)return;
-
if(!client->lockIfMessageWanted(msgType))return;
-
if(dataPtr==0&&metadata==NULL){
- LOGE("Null data returned in data callback");
- client->handleGenericNotify(CAMERA_MSG_ERROR,UNKNOWN_ERROR,0);
- return;
-
}
- switch(msgType&~CAMERA_MSG_PREVIEW_METADATA){
-
caseCAMERA_MSG_PREVIEW_FRAME:
-
client->handlePreviewData(msgType,dataPtr,metadata);
- break;
-
caseCAMERA_MSG_POSTVIEW_FRAME:
- client->handlePostview(dataPtr);
- break;
-
caseCAMERA_MSG_RAW_IMAGE:
- client->handleRawPicture(dataPtr);
- break;
-
caseCAMERA_MSG_COMPRESSED_IMAGE:
- client->handleCompressedPicture(dataPtr);
- break;
- #ifdef OMAP_ENHANCEMENT
-
caseCAMERA_MSG_COMPRESSED_BURST_IMAGE:
- client->handleCompressedBurstPicture(dataPtr);
- break;
- #endif
- default:
- client->handleGenericData(msgType,dataPtr,metadata);
- break;
-
}
- }
- //preview callback-frame
buffer update
- void CameraService::Client::handlePreviewData(int32_t
msgType,
-
constsp<IMemory>&mem,
- camera_frame_metadata_t*metadata){
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap>heap=mem->getMemory(&offset,&size);
-
//local copy of the callback flags
-
intflags=mPreviewCallbackFlag;
-
//iscallback enabled?
-
if(!(flags&CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)){
-
//Ifthe enable bitisoff,the
copy-outandone-shot bits are ignored
- LOG2("frame callback is disabled");
- mLock.unlock();
- return;
-
}
-
//hold a strong pointertothe client
- sp<ICameraClient>c=mCameraClient;
-
//clear callback flagsifno clientorone-shot
mode
-
if(c==0||(mPreviewCallbackFlag&CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)){
- LOG2("Disable preview callback");
- mPreviewCallbackFlag&=~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK|
- CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK|
- CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
- disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-
}
-
if(c!=0){
-
//Isthe received frame copied
outornot?
-
if(flags&CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK){
- LOG2("frame is copied");
-
copyFrameAndPostCopiedFrame(msgType,c,heap,offset,size,metadata);
-
}else{
- LOG2("frame is forwarded");
- mLock.unlock();
-
c->dataCallback(msgType,mem,metadata);
-
}
-
}else{
- mLock.unlock();
-
}
- }
copyFrameAndPostCopiedFrame这个函数执行两个buff区preview数据的投递,通过它的具体实现过程,可以知道最终他也要调用dataCallback方法继续调用客户端client的回调函数
所以这里直接分析copyFrameAndPostCopiedFrame:
- void CameraService::Client::copyFrameAndPostCopiedFrame(
- int32_t msgType,constsp<ICameraClient>&client,
-
constsp<IMemoryHeap>&heap,size_t
offset,size_t size,
- camera_frame_metadata_t*metadata){
- LOG2("copyFrameAndPostCopiedFrame");
-
//Itisnecessarytocopy
out of pmem before sending thisto
-
//the callback.Forefficiency,reuse
the same MemoryHeapBase
-
//provided it's big enough.Don't
allocate the memoryor
-
//perform the copyifthere's
no callback.
-
//hold the preview lockwhilewe grab
a referencetothe preview buffer
- sp<MemoryHeapBase>previewBuffer;
-
if(mPreviewBuffer==0){
- mPreviewBuffer=new MemoryHeapBase(size,0,NULL);
-
}elseif(size>mPreviewBuffer->virtualSize()){
- mPreviewBuffer.clear();
- mPreviewBuffer=new MemoryHeapBase(size,0,NULL);
-
}
-
if(mPreviewBuffer==0){
- LOGE("failed to allocate space for preview buffer");
- mLock.unlock();
- return;
-
}
- previewBuffer=mPreviewBuffer;
- memcpy(previewBuffer->base(),(uint8_t*)heap->base()+offset,size);
- sp<MemoryBase>frame=new MemoryBase(previewBuffer,0,size);
-
if(frame==0){
- LOGE("failed to allocate space for frame callback");
- mLock.unlock();
- return;
-
}
- mLock.unlock();
-
client->dataCallback(msgType,frame,metadata);
- }
- //callback from camera service when frameorimageisready
- void Camera::dataCallback(int32_t msgType,constsp<IMemory>&dataPtr,
- camera_frame_metadata_t*metadata)
-
{
- sp<CameraListener>listener;
-
{
- Mutex::Autolock _l(mLock);
- listener=mListener;
-
}
-
if(listener!=NULL){
-
listener->postData(msgType,dataPtr,metadata);
-
}
- }
- //connecttocamera
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){
- jniThrowRuntimeException(env,"Fail to
connect to camera service");
- return;
-
}
-
//make sure camera hardwareisalive
-
if(camera->getStatus()!=NO_ERROR){
- jniThrowRuntimeException(env,"Camera
initialization failed");
- return;
-
}
- jclass clazz=env->GetObjectClass(thiz);
-
if(clazz==NULL){
- jniThrowRuntimeException(env,"Can't find
android/hardware/Camera");
- return;
-
}
-
//We use a weak reference so the Camera object can be garbage collected.
-
//The referenceisonly used as a proxyforcallbacks.
-
sp<JNICameraContext>context=new
JNICameraContext(env,weak_this,clazz,camera);
-
context->incStrong(thiz);
-
camera->setListener(context);
-
//save contextinopaque field
- env->SetIntField(thiz,fields.context,(int)context.get());
- }
- //provides persistent contextforcalls
from native codetoJava
-
classJNICameraContext:publicCameraListener
-
{
-
public:
- JNICameraContext(JNIEnv*env,jobject
weak_this,jclass clazz,constsp<Camera>&camera);
-
~JNICameraContext(){release();}
- virtual void notify(int32_t msgType,int32_t ext1,int32_t
ext2);
-
virtual void postData(int32_t
msgType,constsp<IMemory>&dataPtr,
-
camera_frame_metadata_t*metadata);
- virtual void postDataTimestamp(nsecs_t timestamp,int32_t msgType,constsp<IMemory>&dataPtr);
- void postMetadata(JNIEnv*env,int32_t
msgType,camera_frame_metadata_t*metadata);
- void addCallbackBuffer(JNIEnv*env,jbyteArray
cbb,intmsgType);
- void setCallbackMode(JNIEnv*env,bool
installed,bool manualMode);
- sp<Camera>getCamera(){Mutex::Autolock
_l(mLock);return mCamera;}
- bool isRawImageCallbackBufferAvailable()const;
- void release();
-
private:
- void copyAndPost(JNIEnv*env,constsp<IMemory>&dataPtr,intmsgType);
- void clearCallbackBuffers_l(JNIEnv*env,Vector<jbyteArray>*buffers);
- void clearCallbackBuffers_l(JNIEnv*env);
- jbyteArray getCallbackBuffer(JNIEnv*env,Vector<jbyteArray>*buffers,size_t
bufferSize);
- jobject mCameraJObjectWeak;//weak
referencetojava object
- jclass mCameraJClass;//strong referencetojavaclass
- sp<Camera>mCamera;//strong
referencetonative object
- jclass mFaceClass;//strong referencetoFaceclass
- jclass mRectClass;//strong referencetoRectclass
- Mutex mLock;
-
/*
-
*Global reference application-managed raw image buffer queue.
-
*
-
*Manual-only modeissupportedforraw
image callbacks,whichis
-
*setwhenever method addCallbackBuffer()with
msgType=
-
*CAMERA_MSG_RAW_IMAGEiscalled;otherwise,nullisreturned
-
*with raw image callbacks.
-
*/
- Vector<jbyteArray>mRawImageCallbackBuffers;
-
/*
-
*Application-managed preview buffer queueandthe
flags
-
*associated with the usage of the preview buffer callback.
-
*/
- Vector<jbyteArray>mCallbackBuffers;//Global
reference application managed byte[]
- bool mManualBufferMode;//Whethertouse
application managed buffers.
- bool mManualCameraCallbackSet;//Whether
the callback has beenset,usedto
-
//reduce unnecessary callstosetthe
callback.
- };
- void JNICameraContext::postData(int32_t
msgType,constsp<IMemory>&dataPtr,
- camera_frame_metadata_t*metadata)
-
{
-
//VM pointer will beNULLifobjectisreleased
- Mutex::Autolock _l(mLock);
- JNIEnv*env=AndroidRuntime::getJNIEnv();
-
if(mCameraJObjectWeak==NULL){
- LOGW("callback on dead camera object");
- return;
-
}
- int32_t dataMsgType=msgType&~CAMERA_MSG_PREVIEW_METADATA;
-
//return data basedoncallback type
- switch(dataMsgType){
-
caseCAMERA_MSG_VIDEO_FRAME:
-
//should never happen
- break;
-
//Forbackward-compatibility
purpose,ifthereisno callback
-
//bufferforraw image,the
callback returnsnull.
-
caseCAMERA_MSG_RAW_IMAGE:
- LOGV("rawCallback");
-
if(mRawImageCallbackBuffers.isEmpty()){
- env->CallStaticVoidMethod(mCameraJClass,fields.post_event,
- mCameraJObjectWeak,dataMsgType,0,0,NULL);
-
}else{
-
copyAndPost(env,dataPtr,dataMsgType);
-
}
- break;
-
//Thereisno data.
-
case0:
- break;
- default:
- LOGV("dataCallback(%d, %p)",dataMsgType,dataPtr.get());
- copyAndPost(env,dataPtr,dataMsgType);
- break;
-
}
-
//post frame metadatatoJava
-
if(metadata&&(msgType&CAMERA_MSG_PREVIEW_METADATA)){
- postMetadata(env,CAMERA_MSG_PREVIEW_METADATA,metadata);
-
}
- }
- void JNICameraContext::copyAndPost(JNIEnv*env,constsp<IMemory>&dataPtr,intmsgType)
-
{
- jbyteArray obj=NULL;
-
//allocate Java bytearrayandcopy
data
-
if(dataPtr!=NULL){
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap>heap=dataPtr->getMemory(&offset,&size);
- LOGV("copyAndPost: off=%ld, size=%d",offset,size);
- uint8_t*heapBase=(uint8_t*)heap->base();
-
if(heapBase!=NULL){
-
constjbyte*data=reinterpret_cast<constjbyte*>(heapBase+offset);
-
if(msgType==CAMERA_MSG_RAW_IMAGE){
- obj=getCallbackBuffer(env,&mRawImageCallbackBuffers,size);
-
}elseif(msgType==CAMERA_MSG_PREVIEW_FRAME&&mManualBufferMode){
- obj=getCallbackBuffer(env,&mCallbackBuffers,size);
-
if(mCallbackBuffers.isEmpty()){
- LOGV("Out of buffers, clearing callback!");
- mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
- mManualCameraCallbackSet=false;
-
if(obj==NULL){
- return;
-
}
-
}
-
}else{
- LOGV("Allocating callback buffer");
-
obj=env->NewByteArray(size);
-
}
-
if(obj==NULL){
- LOGE("Couldn't allocate byte array for JPEG data");
- env->ExceptionClear();
-
}else{
-
env->SetByteArrayRegion(obj,0,size,data);
-
}
-
}else{
- LOGE("image heap is NULL");
-
}
-
}
-
//post image datatoJava
-
env->CallStaticVoidMethod(mCameraJClass,fields.post_event,
-
mCameraJObjectWeak,msgType,0,0,obj);
-
if(obj){
- env->DeleteLocalRef(obj);
-
}
- }
从这里开始,回调函数进入到camera framework层
frameworks/base/core/java/android/hardware/Camera.java
- privatestatic void postEventFromNative(Object
camera_ref,
-
intwhat,intarg1,intarg2,Object
obj)
-
{
- Camera c=(Camera)((WeakReference)camera_ref).get();
-
if(c==null)
- return;
-
if(c.mEventHandler!=null){
-
Message m=c.mEventHandler.obtainMessage(what,arg1,arg2,obj);
-
c.mEventHandler.sendMessage(m);
-
}
- }
- privateclassEventHandler extends Handler
-
{
-
privateCamera mCamera;
-
publicEventHandler(Camera c,Looper
looper){
- super(looper);
- mCamera=c;
-
}
- @Override
-
publicvoid handleMessage(Message msg){
- switch(msg.what){
-
caseCAMERA_MSG_SHUTTER:
-
if(mShutterCallback!=null){
-
mShutterCallback.onShutter();
-
}
- return;
-
caseCAMERA_MSG_RAW_IMAGE:
-
if(mRawImageCallback!=null){
-
mRawImageCallback.onPictureTaken((byte[])msg.obj,mCamera);
-
}
- return;
-
caseCAMERA_MSG_COMPRESSED_IMAGE:
-
if(mJpegCallback!=null){
-
mJpegCallback.onPictureTaken((byte[])msg.obj,mCamera);
-
}
- return;
-
caseCAMERA_MSG_PREVIEW_FRAME:
-
if(mPreviewCallback!=null){
-
PreviewCallback cb=mPreviewCallback;
-
if(mOneShot){
-
//Clear
the callback variable before the callback
-
//incasethe
app calls setPreviewCallback from
-
//the
callbackfunction
-
mPreviewCallback=null;
-
}elseif(!mWithBuffer){
-
//We're
faking the camera preview modetoprevent
-
//the
app from being flooded with preview frames.
-
//Settooneshot
mode again.
-
setHasPreviewCallback(true,false);
-
}
-
cb.onPreviewFrame((byte[])msg.obj,mCamera);
-
}
- return;
-
caseCAMERA_MSG_POSTVIEW_FRAME:
-
if(mPostviewCallback!=null){
-
mPostviewCallback.onPictureTaken((byte[])msg.obj,mCamera);
-
}
- return;
-
caseCAMERA_MSG_FOCUS:
-
if(mAutoFocusCallback!=null){
-
mAutoFocusCallback.onAutoFocus(msg.arg1==0?false:true,mCamera);
-
}
- return;
-
caseCAMERA_MSG_ZOOM:
-
if(mZoomListener!=null){
- mZoomListener.onZoomChange(msg.arg1,msg.arg2!=0,mCamera);
-
}
- return;
-
caseCAMERA_MSG_PREVIEW_METADATA:
-
if(mFaceListener!=null){
-
mFaceListener.onFaceDetection((Face[])msg.obj,mCamera);
-
}
- return;
-
caseCAMERA_MSG_ERROR:
-
Log.e(TAG,"Error
"+msg.arg1);
-
if(mErrorCallback!=null){
-
mErrorCallback.onError(msg.arg1,mCamera);
-
}
- return;
- default:
-
Log.e(TAG,"Unknown
message type "+msg.what);
- return;
-
}
-
}
- }
默认是没有previewcallback这个回调的,除非你的app设置了setPreviewCallback,可以看出preview的数据还是可以向上层回调,只是系统默认不回调,这里再说深一些:
由上面绿色标注的地方可以看出,我们需要做以下事情,检查PreviewCallback这个在framework中定义的接口有没有设置了setPreviewCallback,设置则调用,这里接口中
的onPreviewFrame方法需要开发者自己实现,这里默认是没有实现的,需要特殊使用的要自己添加,这里是自己的理解,看一下PreviewCallback接口的定义:frameworks/base/core/java/android/hardware/Camera.java
- /**
-
*Callback interface usedtodeliver copies of preview frames as
-
*they are displayed.
-
*
-
*@see #setPreviewCallback(Camera.PreviewCallback)
-
*@see #setOneShotPreviewCallback(Camera.PreviewCallback)
-
*@see #setPreviewCallbackWithBuffer(Camera.PreviewCallback)
-
*@see #startPreview()
-
*/
-
publicinterface PreviewCallback
-
{
-
/**
-
*Called as preview frames are displayed.This callbackisinvoked
-
*onthe event thread{@link#open(int)}was
called from.
-
*
-
*@param data the contents of the preview frameinthe format defined
-
*by{@linkandroid.graphics.ImageFormat},which
can be queried
-
*with{@linkandroid.hardware.Camera.Parameters#getPreviewFormat()}.
-
*If{@linkandroid.hardware.Camera.Parameters#setPreviewFormat(int)}
-
*isnever called,the default
will be the YCbCr_420_SP
-
*(NV21)format.
-
*@param camera the Camera service object.
-
*/
- void onPreviewFrame(byte[]data,Camera
camera);
- };
takePicture()处理过程跟preview差不多,只是增加了回调函数返回时候存储图像的动作,这里分析一下takepicture的处理过程:
- caseCAMERA_MSG_COMPRESSED_IMAGE:
-
if(mJpegCallback!=null){
- mJpegCallback.onPictureTaken((byte[])msg.obj,mCamera);
-
}
- return;
private PictureCallback mJpegCallback;
走到这里我们又不得不回头看看最起初在调用takepicture的时候是怎么调用的
- try{
- mCameraDevice.takePicture(mShutterCallback,mRawPictureCallback,
- mPostViewPictureCallback,new JpegPictureCallback(loc));
-
}catch(RuntimeException e){
- e.printStackTrace();
- returnfalse;
- }
所以这个还是必须得说清楚一点,看看JpegPictureCallback类的定义吧
- privatefinalclassJpegPictureCallback
implements PictureCallback{
-
LocationmLocation;
-
publicJpegPictureCallback(Locationloc){
- mLocation=loc;
-
}
-
publicvoid onPictureTaken(
- final byte[]jpegData,final
android.hardware.Camera camera){
-
if(mPausing){
-
if(mBurstImages>0){
- resetBurst();
- mBurstImages=0;
- mHandler.sendEmptyMessageDelayed(RELEASE_CAMERA,
- CAMERA_RELEASE_DELAY);
-
}
- return;
-
}
- FocusManager.TempBracketingStates tempState=mFocusManager.getTempBracketingState();
- mJpegPictureCallbackTime=System.currentTimeMillis();
-
//Ifpostview callback has
arrived,the captured imageisdisplayed
-
//inpostview callback.Ifnot,the
captured imageisdisplayedin
-
//raw picture callback.
-
if(mPostViewPictureCallbackTime!=0){
- mShutterToPictureDisplayedTime=
- mPostViewPictureCallbackTime-mShutterCallbackTime;
- mPictureDisplayedToJpegCallbackTime=
- mJpegPictureCallbackTime-mPostViewPictureCallbackTime;
-
}else{
- mShutterToPictureDisplayedTime=
- mRawPictureCallbackTime-mShutterCallbackTime;
- mPictureDisplayedToJpegCallbackTime=
- mJpegPictureCallbackTime-mRawPictureCallbackTime;
-
}
-
Log.v(TAG,"mPictureDisplayedToJpegCallbackTime
= "
-
+mPictureDisplayedToJpegCallbackTime+"ms");
-
if(!mIsImageCaptureIntent){
- enableCameraControls(true);
-
if((tempState!=FocusManager.TempBracketingStates.RUNNING)&&
-
!mCaptureMode.equals(mExposureBracketing)&&
-
!mCaptureMode.equals(mZoomBracketing)&&
-
!mBurstRunning==true){
-
//We wanttoshow the taken
pictureforawhile,so we wait
-
//forat least 0.5secondbefore
restarting the preview.
- long delay=500-mPictureDisplayedToJpegCallbackTime;
-
if(delay<0){
- startPreview(true);
- startFaceDetection();
-
}else{
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW,delay);
-
}
-
}
-
}
-
if(!mIsImageCaptureIntent){
- Size s=mParameters.getPictureSize();
-
mImageSaver.addImage(jpegData,mLocation,s.width,s.height);
-
}else{
- mJpegImageData=jpegData;
-
if(!mQuickCapture){
- showPostCaptureAlert();
-
}else{
- doAttach();
-
}
-
}
-
//Check thisinadvance ofeachshot
so we don't addtoshutter
-
//latency.It'struethat
someoneelsecould writetothe SD cardin
-
//the meantimeandfill
it,but that could have happened between the
-
//shutter pressandsaving
the JPEG too.
- checkStorage();
-
if(!mHandler.hasMessages(RESTART_PREVIEW)){
- longnow=System.currentTimeMillis();
- mJpegCallbackFinishTime=now-mJpegPictureCallbackTime;
-
Log.v(TAG,"mJpegCallbackFinishTime
= "
-
+mJpegCallbackFinishTime+"ms");
- mJpegPictureCallbackTime=0;
-
}
-
if(mCaptureMode.equals(mExposureBracketing)){
- mBurstImages--;
-
if(mBurstImages==0){
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW,0);
-
}
-
}
-
//reset burstincaseof
exposure bracketing
-
if(mCaptureMode.equals(mExposureBracketing)&&mBurstImages==0){
- mBurstImages=EXPOSURE_BRACKETING_COUNT;
- mParameters.set(PARM_BURST,mBurstImages);
- mCameraDevice.setParameters(mParameters);
-
}
-
if(mCaptureMode.equals(mZoomBracketing)){
- mBurstImages--;
-
if(mBurstImages==0){
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW,0);
-
}
-
}
-
//reset burstincaseof
zoom bracketing
-
if(mCaptureMode.equals(mZoomBracketing)&&mBurstImages==0){
- mBurstImages=ZOOM_BRACKETING_COUNT;
- mParameters.set(PARM_BURST,mBurstImages);
- mCameraDevice.setParameters(mParameters);
-
}
-
if(tempState==FocusManager.TempBracketingStates.RUNNING){
- mBurstImages--;
-
if(mBurstImages==0){
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW,0);
- mTempBracketingEnabled=true;
- stopTemporalBracketing();
-
}
-
}
-
if(mBurstRunning){
- mBurstImages--;
-
if(mBurstImages==0){
- resetBurst();
- mBurstRunning=false;
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW,0);
-
}
-
}
-
}
- }
而且这里子类重新实现了父类的方法onPictureTaken
这里这个函数不就是handle里面调用的函数了嘛,可以看到上面onPictureTaken的实现过程,其实与preview最大的不同就是我上面标注的部分,
takepicture最终将图片保存下来了
好了,takepicture的过程就说到这里了,下一步要进底层了,HAL和driver之间的那些事,driver做的那些事