记录需求-在Service中拍照

一、需求背景
有必要讲一下需求的背景,防止被想歪。
背景:在一块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的操作封装到内部。
记录需求-在Service中拍照_第1张图片

2、安利工具:DocFetch-文件内容搜索器
写这篇博客的时候,离当时研究这个需求已经过去了一年多,项目文档已经淹没在大批的项目中找不到了,只能记得文件里面关于createCaptureSession的内容,通过文件搜索无法定位,只能去找查找文件内容的工具,最后找到了DocFetch;
在工程目录建立索引花了10几分钟,之后顺利得找到了需要的工程。
记录需求-在Service中拍照_第2张图片
具体的操作可以看参考链接中的文章。
四、参考链接
HandlerThread解析
Everything+Docfetcher 文档查找两把利器

你可能感兴趣的:(java,android)