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做的那些事