一、需求背景
有必要讲一下需求的背景,防止被想歪。
背景:在一块Android的开发板上,有HDMI的输入接口,驱动层已经做了封装,将HDMI输入的视频源转成CameraApi提供给应用层调用;也就是说在Android应用中,只需调用摄像头,就可以获取视频源;
需求:要求在不展示界面的情况下(Service中),对视频源进行截屏,也就是拍照。
二、探索过程
板子上Android的版本是6.0;摄像头的Api是Camera2.0。
通过谷歌官方的例子,可以看到一个正常拍照的流程如下
openCamera(开启设备,启动HandleThread)->
createCameraPreviewSession(创建预览会话)->
setRepeatingRequest(开始预览)->
capatrue(拍照请求)
考虑需求,着重看了createCameraPreviewSession这一步,其中部分代码如下:
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder
= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE\_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback()
可以看到,createCaptureSession方法中第一个参数为surface列表,代码中列表中为,预览界面及拍照存储的Surface;
为在Service中拍照,自然没有预览的界面,所以把列表中的第一个用于预览的surface删除,保留用于保存文件的surface:
camera.createCaptureSession(Arrays.asList(imageReaderSurface), new
CameraCaptureSession.StateCallback()
第二点在于改按钮触发为直接拍照,原有代码中,是先进行预览的请求TEMPLATE_PREVIEW,而后按钮触发再发出TEMPLATE_STILL_CAPTURE获取静态画面,我们改成在创建会话的回调中,一旦状态就绪,就发出保存图片的请求:
//获取ImageReader的Surface
Surface imageReaderSurface = mImageReader.getSurface();
mCaptureRequestBuilder = camera.createCaptureRequest(CameraDevice
.TEMPLATE_STILL_CAPTURE);
//CaptureRequest添加imageReaderSurface,
// 不加的话就会导致ImageReader的onImageAvailable
// ()方法不会回调
mCaptureRequestBuilder.addTarget(imageReaderSurface);
camera.createCaptureSession(Arrays.asList(imageReaderSurface), new
CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
try {
session.capture(mCaptureRequestBuilder.build(),
null,
null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession
session) {
}
}, null);// 关闭相机时别忘了关闭ImageReader
} catch (CameraAccessException e) {
e.printStackTrace();
}
代码中的mCaptureRequestBuilder设置为TEMPLATE_STILL_CAPTURE捕获静态画面捕捉。
全过程为在Service中create中打开摄像头,摄像头开启完毕后,建立捕获对话,完成后发送请求保存文件,
至此需求就完成了。
三、延申
1、涉及如下的知识点
a:SurfaceView、TextureView、View的区别
官方的代码中,使用了TextureView来进行预览
b:HandlerThread
HandlerThread为绑定了Handler的线程,本拍照程序中,应用在后台启动HandlerThread,主线程中在完成了相应的准备后,通过thread绑定的handler向其发送消息。
HandlerThread和Thread的不同在于内部有Looper和Handler,可以接收消息。相当于把绑定handler和thread的操作封装到内部。
2、安利工具:DocFetch-文件内容搜索器
写这篇博客的时候,离当时研究这个需求已经过去了一年多,项目文档已经淹没在大批的项目中找不到了,只能记得文件里面关于createCaptureSession的内容,通过文件搜索无法定位,只能去找查找文件内容的工具,最后找到了DocFetch;
在工程目录建立索引花了10几分钟,之后顺利得找到了需要的工程。
具体的操作可以看参考链接中的文章。
四、参考链接
HandlerThread解析
Everything+Docfetcher 文档查找两把利器
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。