android.hardware.camera2使用指南

API 21中将原来的camera API弃用转而推荐使用新增的camera2 API,这是一个大的动作,因为新API换了架构,让开发者用起来更难了。
先来看看camera2包架构示意图:

这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送Capture请求,而摄像头会返回CameraMetadata。这一切建立在一个叫作CameraCaptureSession的会话中。

下面是camera2包中的主要类:

其中CameraManager是那个站在高处统管所有摄像投设备(CameraDevice)的管理者,而每个CameraDevice自己会负责建立CameraCaptureSession以及建立CaptureRequest。CameraCharacteristics是CameraDevice的属性描述类,非要做个对比的话,那么它与原来的CameraInfo有相似性。
类图中有着三个重要的callback,虽然这增加了阅读代码的难度,但是你必须要习惯,因为这是新包的风格。其中CameraCaptureSession.CaptureCallback将处理预览和拍照图片的工作,需要重点对待。

这些类是如何相互配合的?下面是简单的流程图。

我是用SurfaceView作为显示对象(当然还可以TextureView去显示,详见参考中的项目)
核心代码如下:

<code class="hljs java has-numbering">        mCameraManager = (CameraManager) <span class="hljs-keyword">this</span>.getSystemService(Context.CAMERA_SERVICE);
        mSurfaceView = (SurfaceView)findViewById(R.id.surfaceview);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(<span class="hljs-keyword">new</span> SurfaceHolder.Callback() {
            <span class="hljs-annotation">@Override</span>
            <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">surfaceCreated</span>(SurfaceHolder holder) {
                initCameraAndPreview();
            }
        });</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>
<code class="hljs avrasm has-numbering">    private void initCameraAndPreview() {
        Log<span class="hljs-preprocessor">.d</span>(<span class="hljs-string">"linc"</span>,<span class="hljs-string">"init camera and preview"</span>)<span class="hljs-comment">;</span>
        HandlerThread handlerThread = new HandlerThread(<span class="hljs-string">"Camera2"</span>)<span class="hljs-comment">;</span>
        handlerThread<span class="hljs-preprocessor">.start</span>()<span class="hljs-comment">;</span>
        mHandler = new Handler(handlerThread<span class="hljs-preprocessor">.getLooper</span>())<span class="hljs-comment">;</span>
        try {
            mCameraId = <span class="hljs-string">""</span>+CameraCharacteristics<span class="hljs-preprocessor">.LENS</span>_FACING_FRONT<span class="hljs-comment">;</span>
            mImageReader = ImageReader<span class="hljs-preprocessor">.newInstance</span>(mSurfaceView<span class="hljs-preprocessor">.getWidth</span>(), mSurfaceView<span class="hljs-preprocessor">.getHeight</span>(),
                    ImageFormat<span class="hljs-preprocessor">.JPEG</span>,<span class="hljs-comment">/*maxImages*/</span><span class="hljs-number">7</span>)<span class="hljs-comment">;</span>
            mImageReader<span class="hljs-preprocessor">.setOnImageAvailableListener</span>(mOnImageAvailableListener, mHandler)<span class="hljs-comment">;</span>

            mCameraManager<span class="hljs-preprocessor">.openCamera</span>(mCameraId, DeviceStateCallback, mHandler)<span class="hljs-comment">;</span>
        } catch (CameraAccessException e) {
            Log<span class="hljs-preprocessor">.e</span>(<span class="hljs-string">"linc"</span>, <span class="hljs-string">"open camera failed."</span> + e<span class="hljs-preprocessor">.getMessage</span>())<span class="hljs-comment">;</span>
        }
    }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>
<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> CameraDevice.StateCallback DeviceStateCallback = <span class="hljs-keyword">new</span> CameraDevice.StateCallback() {

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onOpened</span>(CameraDevice camera) {
            Log.d(<span class="hljs-string">"linc"</span>,<span class="hljs-string">"DeviceStateCallback:camera was opend."</span>);
            mCameraOpenCloseLock.release();
            mCameraDevice = camera;
            <span class="hljs-keyword">try</span> {
                createCameraCaptureSession();
            } <span class="hljs-keyword">catch</span> (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    };</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul>
<code class="hljs avrasm has-numbering">    private void createCameraCaptureSession() throws CameraAccessException {
        Log<span class="hljs-preprocessor">.d</span>(<span class="hljs-string">"linc"</span>,<span class="hljs-string">"createCameraCaptureSession"</span>)<span class="hljs-comment">;</span>

        mPreviewBuilder = mCameraDevice<span class="hljs-preprocessor">.createCaptureRequest</span>(CameraDevice<span class="hljs-preprocessor">.TEMPLATE</span>_PREVIEW)<span class="hljs-comment">;</span>
        mPreviewBuilder<span class="hljs-preprocessor">.addTarget</span>(mSurfaceHolder<span class="hljs-preprocessor">.getSurface</span>())<span class="hljs-comment">;</span>
        mState = STATE_PREVIEW<span class="hljs-comment">;</span>
        mCameraDevice<span class="hljs-preprocessor">.createCaptureSession</span>(
                Arrays<span class="hljs-preprocessor">.asList</span>(mSurfaceHolder<span class="hljs-preprocessor">.getSurface</span>(), mImageReader<span class="hljs-preprocessor">.getSurface</span>()),
                mSessionPreviewStateCallback, mHandler)<span class="hljs-comment">;</span>
    }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>
<code class="hljs avrasm has-numbering">private CameraCaptureSession<span class="hljs-preprocessor">.StateCallback</span> mSessionPreviewStateCallback = new
            CameraCaptureSession<span class="hljs-preprocessor">.StateCallback</span>() {

        @Override
        public void onConfigured(CameraCaptureSession session) {
            Log<span class="hljs-preprocessor">.d</span>(<span class="hljs-string">"linc"</span>,<span class="hljs-string">"mSessionPreviewStateCallback onConfigured"</span>)<span class="hljs-comment">;</span>
            mSession = session<span class="hljs-comment">;</span>
            try {
                mPreviewBuilder<span class="hljs-preprocessor">.set</span>(CaptureRequest<span class="hljs-preprocessor">.CONTROL</span>_AF_MODE,
                        CaptureRequest<span class="hljs-preprocessor">.CONTROL</span>_AF_MODE_CONTINUOUS_PICTURE)<span class="hljs-comment">;</span>
                mPreviewBuilder<span class="hljs-preprocessor">.set</span>(CaptureRequest<span class="hljs-preprocessor">.CONTROL</span>_AE_MODE,
                        CaptureRequest<span class="hljs-preprocessor">.CONTROL</span>_AE_MODE_ON_AUTO_FLASH)<span class="hljs-comment">;</span>
                session<span class="hljs-preprocessor">.setRepeatingRequest</span>(mPreviewBuilder<span class="hljs-preprocessor">.build</span>(), mSessionCaptureCallback, mHandler)<span class="hljs-comment">;</span>
            } catch (CameraAccessException e) {
                e<span class="hljs-preprocessor">.printStackTrace</span>()<span class="hljs-comment">;</span>
                Log<span class="hljs-preprocessor">.e</span>(<span class="hljs-string">"linc"</span>,<span class="hljs-string">"set preview builder failed."</span>+e<span class="hljs-preprocessor">.getMessage</span>())<span class="hljs-comment">;</span>
            }
        }
    }<span class="hljs-comment">;</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul>
<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> CameraCaptureSession.CaptureCallback mSessionCaptureCallback =
            <span class="hljs-keyword">new</span> CameraCaptureSession.CaptureCallback() {

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCaptureCompleted</span>(CameraCaptureSession session, CaptureRequest request,
                                       TotalCaptureResult result) {
<span class="hljs-comment">//            Log.d("linc","mSessionCaptureCallback, onCaptureCompleted");</span>
            mSession = session;
            checkState(result);
        }

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCaptureProgressed</span>(CameraCaptureSession session, CaptureRequest request,
                                        CaptureResult partialResult) {
            Log.d(<span class="hljs-string">"linc"</span>,<span class="hljs-string">"mSessionCaptureCallback, onCaptureProgressed"</span>);
            mSession = session;
            checkState(partialResult);
        }

        <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">checkState</span>(CaptureResult result) {
            <span class="hljs-keyword">switch</span> (mState) {
                <span class="hljs-keyword">case</span> STATE_PREVIEW:
                    <span class="hljs-comment">// NOTHING</span>
                    <span class="hljs-keyword">break</span>;
                <span class="hljs-keyword">case</span> STATE_WAITING_CAPTURE:
                    <span class="hljs-keyword">int</span> afState = result.get(CaptureResult.CONTROL_AF_STATE);

                    <span class="hljs-keyword">if</span> (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
                            CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState
                            || CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED == afState
                            || CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED == afState) {
                        <span class="hljs-comment">//do something like save picture</span>
                    }
                    <span class="hljs-keyword">break</span>;
            }
        }

    };</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li></ul>

按下capture按钮:

<code class="hljs cs has-numbering">    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCapture</span>(View view) {
        <span class="hljs-keyword">try</span> {
            Log.i(<span class="hljs-string">"linc"</span>, <span class="hljs-string">"take picture"</span>);
            mState = STATE_WAITING_CAPTURE;
            mSession.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
        } <span class="hljs-keyword">catch</span> (CameraAccessException e) {
            e.printStackTrace();
        }
    }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>

测试用genemotion模拟器,直接调用笔记本的摄像头。
配置图如下:

demo界面如下图:

源码:
请参考github中的两个demo项目:
https://github.com/pinguo-yuyidong/Camera2
https://github.com/googlesamples/android-Camera2Basic

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值