本文将仿照此前博文Android NDK Camera2小结的方式,来记录Camera1的使用。
Camera1仅为Java实现(不必纠结于此,Native实现...JNI反调...你懂的~且性能差别不大)。
本文的讲解基于UML Component图,描述Camera1核心对象及API的调用生成关系。如缩略图不清晰,可点击放大。
Component图中,模块为函数,节点为对象。横向(左或右)箭头为资源释放操作调用。调用过程与顺序/时机无关。
其中绿色模块为Camera对象成员方法,黄色为Camera类静态方法。
粉色为Camera.Parameters对象成员方法。
红色为自定义方法,需要自行实现。
Component图未包含所有接口,仅为Camera1预览模式的简单实现。
相比于Camera2的复杂架构,Camera1(android.hardware.Camera)十分简单,仅为一个类文件。因此,操作也即为简便。
遵循以下步骤便可完成预览。
使用静态方法Camera.getNumberOfCameras,获取camera数量num。Camera ID范围为【0,num-1】。
int cameraCount = Camera.getNumberOfCameras();
以Camera ID作为传参,调用静态方法Camera.getCameraInfo,获取对应CameraInfo。CameraInfo仅包括三项,Facing(镜头方向,前置/后置),orientation(镜头旋转角度)和canDisableShutterSound(是否支持取消快门声音)。
通常通过CameraInfo,来确定要使用的Camera。
for (int i = 0; i < cameraCount; i++) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(i, cameraInfo);
}
以Camera ID作为传参,调用静态方法Camera.open即可打开设备,该方法将返回一个Camera对象。但打开设备,并不代表能够看到画面。仍需要后续操作,来完成预览。包括设置Camera.Parameters,以及画布(surface View)。若需要使用图片数据,则需要设置Callback接口。
Camera camera = Camera.open(cameraId);
获取Camera对象后,调用成员方法getParameters,可以获取Camera.Parameters。Camera.Parameters中包含的信息,要远多于CameraInfo。在获取Camera.Parameters后,可以调用成员方法getSupportedXXXX来获取相应的数据。例如分辨率,预览格式等。
对于分辨率,可以调用Camera.Parameters成员方法getSupportedPreviewSizes,获取List
Camera.Parameters params = camera.getParameters();
List supportSizes = params.getSupportedPreviewSizes();
...
mParams.setPreviewSize(width, height);
对于预览格式,可以调用Camera.Parameters成员方法getSupportedPreviewFormats,获取List
parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);
当然,还有其它一些参数可以设置,例如曝光补偿(可参照关于Android Camera的曝光补偿),焦距(可参照关于Android Camera变焦)等。
List zoomRatios =parameters.getZoomRatios();
int MAX_ZOOM = mParams.getMaxZoom();
int tMaxExposure=parameters.getMaxExposureCompensation();
int tMinExposure=parameters.getMinExposureCompensation();
...
mParams.setZoom(currentZoom);
parameters.setExposureCompensation(mExposureCompensationRate);
在设置完Camera.Parameters子项后,需要将其回填给Camera,需要调用Camera成员方法setParameters。
mCamera.setParameters(mParams);
surface view为Camera的画布,仅需将其SurfaceHolder作为传参,调用Camera的成员方法setPreviewDisplay即可完成预览界面设置。
SurfaceHolder holder;
...
mCamera.setPreviewDisplay(holder);
通过用Camera的成员方法setDisplayOrientation调设置画面的矫正角度,使得画面以自然0度显示在画布上。通常使用角度为0,90,180,270。关于android设备的角度问题,将另辟博文描述。
mCamera.setDisplayOrientation(90);
如果想获取图像数据,则需要通过调用Camera的成员方法setPreviewCallback添加Callback方法。默认返回为YCbCr_420_SP格式的数据。
PreviewCallback mpreview = new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
}
};
mCamera.setPreviewCallback(mpreview);
public interface PreviewCallback
{
/**
* Called as preview frames are displayed. This callback is invoked
* on the event thread {@link #open(int)} was called from.
*
* If using the {@link android.graphics.ImageFormat#YV12} format,
* refer to the equations in {@link Camera.Parameters#setPreviewFormat}
* for the arrangement of the pixel data in the preview callback
* buffers.
*
* @param data the contents of the preview frame in the format defined
* by {@link android.graphics.ImageFormat}, which can be queried
* with {@link android.hardware.Camera.Parameters#getPreviewFormat()}.
* If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}
* is never called, the default will be the YCbCr_420_SP
* (NV21) format.
* @param camera the Camera service object.
*/
void onPreviewFrame(byte[] data, Camera camera);
};
完成相关设置后,仅需调用Camera成员方法startPreview即可。
mCamera.startPreview();
调用Camera成员方法stopPreview即可。
mCamera.stopPreview()
调用Camera成员方法release即可。
mCamera.release();
Android Camera2 Java实现始于andorid 5.0, Native 实现则开始于android7.0(API level24)。
到目前为止,5.0以上系统市场占有率为85%,7.0以上系统仅为37%,因此,Camera2不足以适配所有Android 设备。
所以,Camera1虽然最终将被替代,但仍有存在价值。Camera1仅为单个类,没有Camera2复杂的结构,并且java实现还是相对简单实用。在不考虑被遗弃的情况,Camera1还是更为通用。