【问题标题】:Taking a picture with Android's Camera (API 19): onPictureTaken is not called使用 Android 的相机 (API 19) 拍照:不调用 onPictureTaken
【发布时间】:2015-08-13 18:45:48
【问题描述】:

我对应该非常简单的事情感到沮丧:使用 Android 的相机 API(没有预览)拍照。我一直在关注 stackoverflow 的几个答案,但没有成功。

最初我遵循了这个答案 (@sush):How to take pictures from the camera without preview when my app starts?

但从未调用过 PictureCallback。然后我跟着这个答案(@Alex Cohn):

您正确地发现不应该在 startPreview() 之前或之后立即调用 takePicture()。 (onPictureTaken never called)

这促使我尝试了三种解决方案。

解决方案 1

第一个解决方案在 SurfaceHolder 中放置一个 回调

public class TestActivity extends Activity
{
    private Camera mCamera;                         

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        takeSnapShot();
    }

    @Override
    protected void onPause()
    {
        clearCamera();
        super.onPause();
    }

    private void takeSnapShot()
    {
        if (mCamera == null)
        {
            try { mCamera = Camera.open(); }
            catch (Exception e) { e.printStackTrace(); }

            SurfaceView surface = (SurfaceView) findViewById(R.id.preview);
            surface.getHolder().addCallback(mSurfaceHolderCallback);

            try { mCamera.setPreviewDisplay(surface.getHolder()); }
            catch (IOException e) { e.printStackTrace(); }

            mCamera.startPreview();
        }
    }

    private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback()
    {
        @Override
        public void surfaceCreated(SurfaceHolder holder)
        {
            try
            {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
                mCamera.takePicture(null, null, mPictureCallback);
            }
            catch (IOException e) { e.printStackTrace(); }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {}

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
    };

    private final Camera.PictureCallback mPictureCallback = new Camera.PictureCallback()
    {
        @Override
        public void onPictureTaken(byte[] data, Camera camera)
        {
            FileOutputStream outStream = null;

            try
            {
                File dir_path =
                    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);

                File pictureFile = new File(dir_path, "snapshot-test.jpg");

                outStream = new FileOutputStream(pictureFile);
                outStream.write(data);
                outStream.close();
            }
            catch (FileNotFoundException e) { e.printStackTrace(); }
            catch (IOException e) { e.printStackTrace(); }
            finally { clearCamera(); }
        }
    };

    private void clearCamera()
    {
        if (mCamera != null)
        {
            try
            {
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
            catch (final Exception e) { e.printStackTrace(); }
        }
    }

如果我只调用一次 takeSnapShot,第一个解决方案就可以工作。不幸的是,我无法让 mSurfaceHolderCallback 多次运行 SurfaceCreated

解决方案 2

我的第二个解决方案是使用 PreviewCallback。在这个解决方案中,我重新使用了 onPause

public class TestActivity extends Activity
{
    private Camera mCamera;                         
    private boolean mReadyToTakePicture;             

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        takeSnapShot();
    }

    private void takeSnapShot()
    {
        if (mCamera == null)
        {
            try { mCamera = Camera.open(); }
            catch (Exception e) { e.printStackTrace(); }

            mCamera.setPreviewCallback(mRawPreviewCallback);
            SurfaceView surface = (SurfaceView) findViewById(R.id.preview);

            try { mCamera.setPreviewDisplay(surface.getHolder()); }
            catch (IOException e) { e.printStackTrace(); }

            mCamera.startPreview();
        }
    }

    private final Camera.PreviewCallback mRawPreviewCallback = new Camera.PreviewCallback()
    {
        @Override
        public void onPreviewFrame(byte [] rawData, Camera camera)
        {
            int rawDataLength = 0;

            if (rawData != null) { rawDataLength = rawData.length; }
            if (rawDataLength > 0 && !mReadyToTakePicture)
            {
                mReadyToTakePicture = true;
                mCamera.takePicture(null, null, mPictureCallback);
            }
            else { mReadyToTakePicture = false; }
        }
    };

    private final Camera.PictureCallback mPictureCallback = new Camera.PictureCallback()
    {
        @Override
        public void onPictureTaken(byte[] data, Camera camera)
        {
            FileOutputStream outStream = null;
            mReadyToTakePicture = false;

            try
            {
                File dir_path =
                        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);

                File pictureFile = new File(dir_path, "snapshot-test.jpg");

                outStream = new FileOutputStream(pictureFile);
                outStream.write(data);
                outStream.close();
            }
            catch (FileNotFoundException e) { e.printStackTrace(); }
            catch (IOException e) { e.printStackTrace(); }
            finally { clearCamera(); }
        }
    };

    private void clearCamera()
    {
        if (mCamera != null)
        {
            try
            {
                mReadyToTakePicture = false;
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
            catch (final Exception e) { e.printStackTrace(); }
        }
    }
}

在此解决方案中,mRawPreviewCallbackmPictureCallback 都不会被调用。

解决方案 3

我的最后一个示例是使用 AsyncTask,它会在实际拍照之前等待一段时间。希望这将为设置预览提供足够的时间。在这个解决方案中,我重新使用了 onPauseclearCamera

public class TestActivity extends Activity
{
    private Camera mCamera;                         

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        takeSnapShot();
    }

    private void takeSnapShot()
    {
        if (mCamera == null)
        {
            try { mCamera = Camera.open(); }
            catch (Exception e) { e.printStackTrace(); }

            SurfaceView surface = (SurfaceView) findViewById(R.id.preview);

            try { mCamera.setPreviewDisplay(surface.getHolder()); }
            catch (IOException e) { e.printStackTrace(); }

            mCamera.startPreview();

            new CameraTask().execute(mCamera);
        }
    }

    private class CameraTask extends AsyncTask<Camera, Void, Void>
    {
        protected String doInBackground(Camera... cameras)
        {
            try { Thread.sleep(1500); } catch (InterruptedException e)
            { e.printStackTrace(); }

            mCamera = cameras[0];
            mCamera.takePicture(null, null, mPictureCallback);

            return mPicturePath;
        }

        private final Camera.PictureCallback mPictureCallback = new Camera.PictureCallback()
        {
            @Override
            public void onPictureTaken(byte[] data, Camera camera)
            {
                FileOutputStream outStream = null;

                try
                {
                    File dir_path =
                        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);

                    File pictureFile = new File(dir_path, "snapshot-test.jpg");
                    mPicturePath = pictureFile.getAbsolutePath();

                    outStream = new FileOutputStream(pictureFile);
                    outStream.write(data);
                    outStream.close();
                }
                catch (FileNotFoundException e) { e.printStackTrace(); }
                catch (IOException e) { e.printStackTrace(); }
                finally { clearCamera(); }
            }
        };
    }
}

解决方案 2 一样,永远不会调用 onPictureTaken

在所有示例中,我的 SurfaceView 的布局如下(无预览):

<SurfaceView
        android:id="@+id/preview"
        android:layout_width="1dp"
        android:layout_height="1dp"></SurfaceView>

在这一点上,我的想法已经不多了。我的第一个示例成功地拍摄了一张照片,所以如果我至少可以强制应用程序运行 surfaceCreated 多次,它应该可以工作。有什么想法吗?

【问题讨论】:

    标签: android android-camera google-glass gdk


    【解决方案1】:

    好的,我之前在姜饼设备上遇到过这个问题。 执行以下操作:

    mCamera.takePicture(null, null, new Camera.PictureCallback() {
                                    @Override
                                    public void onPictureTaken(final byte[] originalData, Camera camera) {
     // logic here
    

    });

    代替:

     mCamera.takePicture(null, null,myCallback);
    

    private PictureCallback mPicallback = new PictureCallback(){ };

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-09
      • 1970-01-01
      • 1970-01-01
      • 2021-08-09
      相关资源
      最近更新 更多