Chinaunix首页 | 论坛 | 博客
  • 博客访问: 526299
  • 博文数量: 107
  • 博客积分: 927
  • 博客等级: 大尉
  • 技术积分: 865
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-13 17:50
文章分类

全部博文(107)

文章存档

2014年(2)

2013年(13)

2012年(16)

2011年(76)

分类: Java

2011-11-30 12:06:39

框架

Android <wbr>Camera框架

1.1 Camera Framework

Android <wbr>Camera框架

1.2 Camera TakePicture Image Display

Android <wbr>Camera框架

1.3 Camera Preview Display

Android <wbr>Camera框架

2 Camera应用层分析

com.android.camera这个包,几个主要的类文件如下: 

PhotoViewerGalleryPicker.java(所有图片集)--->ImageGallery.java(某个Folder下图片列表)--->ViewImage.java(看某张具体图片) 
VideoPlayer
GalleryPicker.java(所有视频集) --->MovieView.java(看某一个视频) 
Camera
Camera.javaCamera取景及拍照) 
VideoCamera
VideoCamera.javaVideoCamera取景及摄像)

Camera基本操作:

拍照预览:startPreview

停止预览:stopPreview

拍照:takePicture

 

Camera类中connect()是一个静态函数,它用于得到一个Camera的实例

回调函数:setShutterCallbacksetRawCallbacksetJpegCallback等,用于上层使用

android.hardware.Camera.ErrorCallback 摄像头出错时调用

android.hardware.Camera.open打开摄像头设备:

 mCameraDevice=android.hardware.Camera.open();

 

 

2.1一些回调接口控制Camera状态 2.1.1 android.hardware.Camera.ErrorCallback

android.hardware.Camera.ErrorCallback:摄像头出错的时候调用,这个接口具有一个void onError(int error,Camera camera)函数;其中,

前者表示数据类型,取值是Camera类中的常量CAMERA_ERROR_UNKNOWN或者是 CAMERA_ERROR_SERVICE_DIED

前者是不明错误,后者是表示服务已经关闭,

在这种情况下需要释放当前的Camera对象,然后再初 始化一个。

private static final class ErrorCallback implements android.hardware.Camera.ErrorCallback { public void onError(int error, android.hardware.Camera camera) { if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) { mMediaServerDied = true; Log.v(TAG, "media server died"); } } }

2.1.2 android.hardware.camera.PreviewCallback

android.hardware.camera.PreviewCallback:在图像预览时调用,这个接口有一个void onPreviewFrame(byte[] data,Camera camera);参数data为每帧图像的数据流。我们可以根据实际需要来实现这个接口。

2.1.3 android.hardware.Camera.ShutterCallback

android.hardware.Camera.ShutterCallback:在图像预览的时候调用,这个接口具有一个void onShutter();可以在改函数中通知用户快门已经关闭,例如播放一个声音。 private final class ShutterCallback implements android.hardware.Camera.ShutterCallback { public void onShutter() { mShutterCallbackTime = System.currentTimeMillis(); mShutterLag = mShutterCallbackTime - mCaptureStartTime; Log.v(TAG, "mShutterLag = " + mShutterLag + "ms"); clearFocusState(); } }

4.android.hardware.Camera.PictureCallback:当拍摄相片的时候调用,该接口具有一个void onPictureTaken(byte[] data,Camera camera)函数;参数和预览的一样。在android中主要有三个类实现了这个接口,分别是PostViewPictureCallback RawPictureCallbackJepgPictureCallback。我们可以根据需要定义自己需要的类。

2.1.4 android.hardware.Camera.AutoFocusCallback

android.hardware.Camera.AutoFocusCallback:当自动对焦时候调用,该接口具有一个void onAutoFocus(boolean focused,Camera camera)函数;

2.1.5 android.hardware.Camera.OnZoomChangeListener

还提供了放大缩小的监听器android.hardware.Camera.OnZoomChangeListener

3 解析图片

当取得照片的数据流后可以通过BitmapFactorydecodeByteArray()函数来解析图片。

另外还可以通过Camera对象的getParameters()函数来得到一个android.hardware.Camera.Parameters 对象,Parameters提供了一些接口来设置Camera的属性:

1.setPictureFormat(int pixel_format):设置图片的格式,其取值为PixelFormat YCbCr_420_SPPixelFormatRGB_565或者PixelFormatJPEG

2.setPreviewFormat(int pixel_format):设置图片的预览格式,取值如上。

3.setPictureSize(int width,int height):设置图片的高度和宽度,单位为像素。

4.setPreviewSize(int width,int height):设置预览的高度和宽度,取值如上。

5.setPreviewFrameRate(int fps):设置图片预览的帧速。

在设置好Camera的参数后,可以通过函数void startPreview()开始预览图像、void stopPreview()结束预览,通过autoFocus(AutoFocusCallback cb)来自动对焦,最后可以通过takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)函数来拍照。

该函数有三个参数,分别为快门回调接口、原生图像数据接口和压缩格式图片数据接口。

如果数据格式不存在的话数据流为空,如果不需要 实现这些接口则这些参数取值可以为null

4 拍照流程

Android Camera程序开发过程中,要用到Exif相关的知识,如果处理不当,会导致拍摄的JPEG图片无法正常浏览。在Froyo(Android 2.2)源码中的Camera应用是不对Exif信息进行写操作,而只是读操作,对于Exif的写操作是交给Camera硬件抽象层去完成,这是google的设计逻辑。但是不同的Android平台及其相关子平台,再加上不同的Camera应用,相互交替,排列组合,或许会出现这样一种情况:底层没有去写Exif,而上层应用也没有写Exif信息,那么图片的显示信息将会丢失。其中影响最为严重的是Orientation这个参数。

Froyo camera的逻辑是这样的:
Camera这个Activity中,有一个内部类ImageCapture,其中包含一个重要的方法:
private void capture() {
// Set rotation.
mParameters.setRotation(mLastOrientation);
....................
 mCameraDevice.setParameters(mParameters);

mCameraDevice.takePicture(mShutterCallback,mRawPictureCallback, mPostViewPictureCallback, new JpegPictureCallback(loc));
}

大致流程是这样的:

1)       获取设备 android.hardware.Camera.open(int)

2)       获取现有设置参数 getParameters()

3)       设置参数SetParameters(Camera.Parameters)

4)       设置预览预览顺时针角度 Camera.setDisplayOrientation(int degrees)

5)       setPreviewDisplay(surfaceHolder) 设置这个才能预览,预览才能拍摄

6)       调用startPreview 执行预览

7)      拍照 takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback),并回到4个中的回调函数callback

8)       拍摄一张相片后,停止预览,如果想继续拍照,再次调用startPreview()

9)       调用stopPreview()停止预览

10)    调用release()释放设备

快速切换摄像模式:

1)       获取并初始化设备并且开始预览

2)       调用unlock()允许media进程访问Camera

3)       通过setCamera(Camera)切换模式,可以在MediaRecorder中看到拍摄视频设置

4)       当拍摄结束,调用reconnect重新后去并锁住Camera

5)       如果继续拍摄,可以重新调用startPreview()

6)       调用stopPreview()release() 退出Camera


 

1.将拍照时相机的方向添加进Camera.Parameters的实例中;
2.
将全部相机拍照参数传给android.hardware.Camera的对象;
3.
调用方法takePicture,并设置好非常重要的4callback;
4.
生成Exif数据的事情就由HAL来完成;
5.
4callback返回数据(这个callback是最重要的,而且是不可缺省的,也就是说前3callback设置成Null也不会影响拍照功能),见如下代码:
private final class JpegPictureCallback implements PictureCallback {
public void onPictureTaken(final byte[] jpegData, final android.hardware.Camera camera) {
//jpegData
JPEG数据,是由HAL层根据应用传输的各种参数(Camera.Parameters的实例)以及JPEG压缩算法生成的。
mImageCapture.storeImage(jpegData, camera, mLocation);
}
}


 

Preview模式下,通过ClickShutterButtonCameraPreviw模式进入TakePicture模式。在进入TakePicture模式之前,需要关闭Camera的预览功能,即停止Camera Preview Display。在TakePicture模式下,AP层首先会发送一个Focus请求,Focus请求会直接到达CameraHardware层,CameraHardware调用底层硬件提供的接口完成Focus功能。并通过回调函数notify,发送CAMERA_MSG_FOCUS消息,完成Focus,在完成Focus之前,系统并不会停止Preview Display,只有上层接到底层返回的FOCUS成功消息之后,才真正的进入TakePicture模式。在进入TakePicture之后,Camera主要完成三个功能。

阅读(4264) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~