Android之Camera拍照

原创 2013年12月05日 18:59:12

一、看看调用时序图

1.拍照命令时序图


2.拍照数据回调时序图


二、看看源码分析

hardware/amlogic/camera/CameraHal.cpp

status_t CameraHal::takePicture( ){
  ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE,  (int) &mStartCapture);
}

调用父类方法:

hardware/amlogic/camera/BaseCameraAdapter.cpp

status_t BaseCameraAdapter::sendCommand(CameraCommands operation, int value1, int value2, int value3){
  switch ( operation ) {
    case CameraAdapter::CAMERA_START_IMAGE_CAPTURE:
      ret = takePicture();
  }
}

调用子类方法:

hardware/amlogic/camera/V4LCameraAdapter/V4LCameraAdapter.cpp

status_t V4LCameraAdapter::takePicture(){
  if (createThread(beginPictureThread, this) == false)
    return -1;
}
/*static*/ int V4LCameraAdapter::beginPictureThread(void *cookie){
  V4LCameraAdapter *c = (V4LCameraAdapter *)cookie;
  return c->pictureThread();
}
int V4LCameraAdapter::pictureThread(){
  ret = sendFrameToSubscribers(&frame);
}

调用父类方法:

hardware/amlogic/camera/BaseCameraAdapter.cpp

status_t BaseCameraAdapter::sendFrameToSubscribers(CameraFrame *frame){
  ret = __sendFrameToSubscribers(frame, &mImageSubscribers, CameraFrame::IMAGE_FRAME);
/*
//如上callback的设置
hardware/amlogic/camera/CameraHal.cpp
status_t CameraHal::initialize(CameraProperties::Properties* properties){
  mAppCallbackNotifier->setEventProvider(eventMask, mCameraAdapter);
  mAppCallbackNotifier->setFrameProvider(mCameraAdapter);
}

hardware/amlogic/camera/AppCallbackNotifier.cpp 
void AppCallbackNotifier::setFrameProvider(FrameNotifier *frameNotifier){
  mFrameProvider = new FrameProvider(frameNotifier, this, frameCallbackRelay);
  mFrameProvider->enableFrameNotification(CameraFrame::IMAGE_FRAME);
  mFrameProvider->enableFrameNotification(CameraFrame::RAW_FRAME);
}

hardware/amlogic/camera/inc/CamerHal.h 
class FrameProvider{
  public:
    FrameProvider(FrameNotifier *fn, void* cookie, frame_callback frameCallback)
                  :mFrameNotifier(fn), mCookie(cookie),mFrameCallback(frameCallback) { }
}
hardware/amlogic/camera/CameraHalUtilClasses.cpp
int FrameProvider::enableFrameNotification(int32_t frameTypes){
  mFrameNotifier->enableMsgType(frameTypes<<MessageNotifier::FRAME_BIT_FIELD_POSITION
                                , mFrameCallback
                                , NULL
                                , mCookie);
}
hardware/amlogic/camera/BaseCameraAdapter.cpp
void BaseCameraAdapter::enableMsgType(int32_t msgs, frame_callback callback, event_callback eventCb, void* cookie){
  if ( CameraFrame::PREVIEW_FRAME_SYNC == msgs ){
    mFrameSubscribers.add((int) cookie, callback);
  }
  else if ( CameraFrame::IMAGE_FRAME == msgs){
    mImageSubscribers.add((int) cookie, callback);
  }
  else if ( CameraFrame::RAW_FRAME == msgs){
    mRawSubscribers.add((int) cookie, callback);
  }
}
//以下callback就是frameCallbackRelay
//callbak-》subscribers-》mImageSubscribers-》mImageSubscribers.add((int) cookie, callback)-》mFrameCallback-》frameCallbackRelay
*/
}
status_t BaseCameraAdapter::__sendFrameToSubscribers(CameraFrame* frame,
     KeyedVector<int, frame_callback> *subscribers,
     CameraFrame::FrameType frameType){
  callback = (frame_callback) subscribers->valueAt(k);
  callback(frame);
}

该回调函数即是:

hardware/amlogic/camera/AppCallbackNotifier.cpp

void AppCallbackNotifier::frameCallbackRelay(CameraFrame* caFrame){
  appcbn->frameCallback(caFrame);
}
void AppCallbackNotifier::frameCallback(CameraFrame* caFrame){
  msg.command = AppCallbackNotifier::NOTIFIER_CMD_PROCESS_FRAME;
  msg.arg1 = frame;
  mFrameQ.put(&msg);
}
void AppCallbackNotifier::notifyFrame(){
  mFrameQ.get(&msg);
  sp<Encoder_libjpeg> encoder = new Encoder_libjpeg(main_jpeg, tn_jpeg,
    AppCallbackNotifierEncoderCallback,
    (CameraFrame::FrameType)frame->mFrameType,
    this,raw_picture,exif_data);
}

补充——拍照是声音的回调如下:

frameworks/av/services/camera/libcameraservice/CameraClient.cpp

void CameraClient::handleShutter(void) {
  mCameraService->playSound(CameraService::SOUND_SHUTTER);
}
frameworks/av/services/camera/libcameraservice/CameraService.cpp
//mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
void CameraService::playSound(sound_kind kind) {


}
源码中位置:

frameworks/base/data/sounds/OriginalAudio.mk

$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg

frameworks/base/data/sounds/effects/camera_click.ogg

三、项目问题

拍照后,应用程序不调用startPreview导致预览界面不再刷新:

1.看看预览部分CameraHAL的处理

hardware/amlogic/camera/V4LCameraAdapter/V4LCameraAdapter.cpp

int V4LCameraAdapter::previewThread(){
  frame.mFrameMask |= CameraFrame::PREVIEW_FRAME_SYNC;
  ret = sendFrameToSubscribers(&frame);
}
hardware/amlogic/camera/BaseCameraAdapter.cpp
status_t BaseCameraAdapter::sendFrameToSubscribers(CameraFrame *frame){
  ret = __sendFrameToSubscribers(frame, &mFrameSubscribers, CameraFrame::PREVIEW_FRAME_SYNC);
}
status_t BaseCameraAdapter::__sendFrameToSubscribers(CameraFrame* frame,
                                                      KeyedVector<int, frame_callback> *subscribers,
                                                      CameraFrame::FrameType frameType){
  while(k<subscribers->size()){
    callback = (frame_callback) subscribers->valueAt(k);
    for(uint32_t i = 0; i<subscribers_ref.size();i++){
      if((frame->mCookie == ( void * ) subscribers_ref.keyAt(i))&&(subscribers_ref.valueAt(i) == 0)){
      subscribers_ref.replaceValueFor((uint32_t)frame->mCookie,1);
      //CAMHAL_LOGDB("Frame callbback is available, cookie:0x%x, callback:0x%x",(uint32_t)frame->mCookie,(uint32_t)callback);
      callback(frame);
      k = 0;
      is_find = true;
      break;
    }
  }
}
/*
//如上callback的设置
hardware/amlogic/camera/CameraHal.cpp
//设置APP回调函数
status_t CameraHal::initialize(CameraProperties::Properties* properties){
  mAppCallbackNotifier->setEventProvider(eventMask, mCameraAdapter);
  mAppCallbackNotifier->setFrameProvider(mCameraAdapter);
}
//设置刷屏回调函数
status_t CameraHal::setPreviewWindow(struct preview_stream_ops *window){
  mDisplayAdapter->setFrameProvider(mCameraAdapter);
  mDisplayAdapter->setErrorHandler(mAppCallbackNotifier.get());
  ret  = mDisplayAdapter->setPreviewWindow(window);
}
status_t CameraHal::startPreview(){
  ret = mDisplayAdapter->enableDisplay(width, height, NULL, isS3d ? &s3dParams : NULL);
}

//设置APP回调函数
hardware/amlogic/camera/AppCallbackNotifier.cpp 
void AppCallbackNotifier::setFrameProvider(FrameNotifier *frameNotifier){
  mFrameProvider = new FrameProvider(frameNotifier, this, frameCallbackRelay);
  mFrameProvider->enableFrameNotification(CameraFrame::IMAGE_FRAME);
  mFrameProvider->enableFrameNotification(CameraFrame::RAW_FRAME);
}

//设置刷屏回调函数
hardware/amlogic/camera/ANativeWindowDisplayAdapter.cpp
int ANativeWindowDisplayAdapter::setFrameProvider(FrameNotifier *frameProvider){
  mFrameProvider = new FrameProvider(frameProvider, this, frameCallbackRelay);
}
int ANativeWindowDisplayAdapter::enableDisplay(int width, int height, struct timeval *refTime, S3DParameters *s3dParams){
  mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC);
}

//最终设置地方
hardware/amlogic/camera/inc/CamerHal.h 
class FrameProvider{
  public:
    FrameProvider(FrameNotifier *fn, void* cookie, frame_callback frameCallback)
                  :mFrameNotifier(fn), mCookie(cookie),mFrameCallback(frameCallback) { }
}
hardware/amlogic/camera/CameraHalUtilClasses.cpp
int FrameProvider::enableFrameNotification(int32_t frameTypes){
  mFrameNotifier->enableMsgType(frameTypes<<MessageNotifier::FRAME_BIT_FIELD_POSITION
                                , mFrameCallback
                                , NULL
                                , mCookie);
}
hardware/amlogic/camera/BaseCameraAdapter.cpp
void BaseCameraAdapter::enableMsgType(int32_t msgs, frame_callback callback, event_callback eventCb, void* cookie){
  if ( CameraFrame::PREVIEW_FRAME_SYNC == msgs ){
    mFrameSubscribers.add((int) cookie, callback);
  }
  else if ( CameraFrame::IMAGE_FRAME == msgs){
    mImageSubscribers.add((int) cookie, callback);
  }
  else if ( CameraFrame::RAW_FRAME == msgs){
    mRawSubscribers.add((int) cookie, callback);
}
}
*/

如上callback即是ANativeWindowDisplayAdapter.cpp/AppCallbackNotifier.cpp中的frameCallbackRelay,我们分析预览画面只需要关心ANativeWindowDisplayAdapter.cpp(AppCallbackNotifier.cpp是例如拍照和录像,需要将数据送给APP):

hardware/amlogic/camera/ANativeWindowDisplayAdapter.cpp
void ANativeWindowDisplayAdapter::frameCallbackRelay(CameraFrame* caFrame){
  da->frameCallback(caFrame);
}
void ANativeWindowDisplayAdapter::frameCallback(CameraFrame* caFrame){
  PostFrame(df);
}
status_t ANativeWindowDisplayAdapter::PostFrame(ANativeWindowDisplayAdapter::DisplayFrame &dispFrame){
  LOGD("TK----->>>>mPaused is %d\n",mPaused);//add by tankai
  if ( mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_STARTED &&
                (!mPaused ||  CameraFrame::CameraFrame::SNAPSHOT_FRAME == dispFrame.mType) &&
                !mSuspend){
    ret = mANativeWindow->enqueue_buffer(mANativeWindow, mBufferHandleMap[i]);
    mFramesWithCameraAdapterMap.removeItem((int) dispFrame.mBuffer);
  }
  else{
    ret = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[i]);
    mFramesWithCameraAdapterMap.removeItem((int) dispFrame.mBuffer);
  }
}
2.问题分析

从如上可以看出:mPaused为true表示暂停刷屏,mPaused为false表示开始刷屏;我们的问题就出在这里。

hardware/camera/CameraHal.cpp
status_t CameraHal::startPreview(){
  if( (mDisplayAdapter.get() != NULL) && ( !mPreviewEnabled ) && ( mDisplayPaused ) ){
    CAMHAL_LOGDA("Preview is in paused state");
    mDisplayPaused = false;
    mPreviewEnabled = true;
    if ( NO_ERROR == ret ){
      ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); //重新开始预览
/*
hardware/amlogic/camera/ANativeWindowDisplayAdapter.cpp
status_t ANativeWindowDisplayAdapter::pauseDisplay(bool pause){
  mPaused = pause;
}
*/
      if ( NO_ERROR != ret ){
        CAMHAL_LOGEB("Display adapter resume failed %x", ret);
      }
    }
    //restart preview callbacks
    if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME){
      mAppCallbackNotifier->enableMsgType (CAMERA_MSG_PREVIEW_FRAME);
    }
    return ret;
  }
}
//拍照时将mPaused置为false,暂停刷屏:
status_t CameraHal::takePicture( ){
  if (NO_ERROR == ret &&
    NULL != mDisplayAdapter.get() && burst < 1) {
    if (mCameraAdapter->getState() != CameraAdapter::VIDEO_STATE) {
      mDisplayPaused = true;
      mPreviewEnabled = false;
      ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); //暂停预览
/*
hardware/amlogic/camera/ANativeWindowDisplayAdapter.cpp
status_t ANativeWindowDisplayAdapter::pauseDisplay(bool pause){
  mPaused = pause;
}
*/
      // since preview is paused we should stop sending preview frames too
      if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) {
        mAppCallbackNotifier->disableMsgType (mMsgEnabled & CAMERA_MSG_POSTVIEW_FRAME);
        CAMHAL_LOGDA("disable MSG_PREVIEW_FRAME");
      }
    }

#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
     mDisplayAdapter->setSnapshotTimeRef(&mStartCapture);
#endif
  }

}
3.问题解决

应用层在take_picture之后主动调用startpreview将mPaused改为false;

如果不需要应用主动调用,则需要在HAL将startpreview设为false。

4.如何在应用层取消掉拍照的回调

camera.takePicture(shutterCallback, rawCallback, jpegCallback);
改为
camera.takePicture(null, null, jpegCallback);

原理如下:

frameworks/base/core/java/android/hardware/Camera.java

public final void takePicture(ShutterCallback shutter, PictureCallback raw,
            PictureCallback postview, PictureCallback jpeg) {
        mShutterCallback = shutter;
        mRawImageCallback = raw;
        mPostviewCallback = postview;
        mJpegCallback = jpeg;

        // If callback is not set, do not send me callbacks.
        int msgType = 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);
        mFaceDetectionRunning = false;
    }


版权声明:本文为博主原创文章,未经博主允许不得转载。

Android 学习之Camera拍照流程

最近在看Android 4.2.2上的Camera的源码,仔细看了下拍照的流程,从点击拍照按钮到成像保存为图片,整个流程分析如下: 1、  点击拍照按钮图标会执行ShutterButton类中的d...
  • chenshun310
  • chenshun310
  • 2014年01月20日 09:31
  • 2423

Android Camera开发之基础知识篇

概述Android框架支持设备的相机拍照和录像功能,你的应用可以直接调用系统的Camera应用来拍照或者录像(比如微信拍照),当然也可以利用Android系统提供的API开发一个Camera应用来实现...
  • feidu804677682
  • feidu804677682
  • 2016年08月19日 17:22
  • 14420

玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo

杂家前文是在2012年的除夕之夜仓促完成,后来很多人指出了一些问题,琐事缠身一直没有进行升级。后来随着我自己的使用,越来越发现不出个升级版的demo是不行了。有时候就连我自己用这个demo测一些性能、...
  • yanzi1225627
  • yanzi1225627
  • 2014年06月22日 00:34
  • 127555

Android Camera的使用 (三)

一、创建一个Camear App二、创建拍照功能 创建一拍照我们分以下几步: 1、检测和访问相机—–检测相机是否存在 2、创建一个用来预览的对象——创建一个 类继承自SurfaceView 并实...
  • a992036795
  • a992036795
  • 2016年08月10日 15:50
  • 2827

android Camera

  • 2009年03月18日 22:24
  • 700KB
  • 下载

Android多媒体学习三:实现自己的Camera

Android自带的Camera应用虽然可以满足大多数情景,但是其灵活性上还有不足。但是Android允许我们定制自己的Camera。在Android的hardware包中有一个Camera类。这个类...
  • chenjie19891104
  • chenjie19891104
  • 2011年04月13日 17:17
  • 13898

android camera

  • 2012年12月12日 23:47
  • 700KB
  • 下载

Android相机Camera基础

一、概述 本章节主要讲述的Android相机Camera的相关知识点,主要包含三个方面,Android启动系统相机生成缩略图、Android启动系统相机生成原图以及Android自定义相机等。二、A...
  • chenzheng8975
  • chenzheng8975
  • 2016年12月30日 15:35
  • 617

Android Camera的使用

CameraAndroid Camera 允许你能抓取一张图片或者视频,所有一般使用Camera 类去获取视频源。...
  • zhi184816
  • zhi184816
  • 2016年09月02日 16:53
  • 1073

Android Camera 相机开发详解

在Android 5.0(SDK 21)中,Google使用Camera2替代了Camera接口。Camera2在接口和架构上做了巨大的变动, 但是基于众所周知的原因,我们还必须基于 Android...
  • yoojia
  • yoojia
  • 2016年07月25日 16:38
  • 6200
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android之Camera拍照
举报原因:
原因补充:

(最多只允许输入30个字)