1

我可以使用 TextureView 正确显示相机视频的预览:

package com.example.camerasurfacetexture;

import java.io.IOException;

import android.app.Activity;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
import android.widget.FrameLayout;

public class MainActivity extends Activity implements SurfaceTextureListener
{

    private Camera mCamera = null;
    private TextureView mTextureView = null;

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

        mTextureView = new TextureView(this);
        mTextureView.setSurfaceTextureListener(this);

        setContentView(mTextureView);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
            int height)
    {
        Log.i("onSurfaceTextureAvailable", "onSurfaceTextureAvailable");

        mCamera = Camera.open();

        Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
        mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
                previewSize.width, previewSize.height, Gravity.CENTER));

        try
        {
            mCamera.setPreviewTexture(surface);
        }
        catch (IOException t)
        {
        }

        mCamera.startPreview();

    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
            int height)
    {
        // Ignored, the Camera does all the work for us
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface)
    {
        Log.i("onSurfaceTextureDestroyed", "onSurfaceTextureDestroyed");
        mCamera.stopPreview();
        mCamera.release();
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface)
    {
        // Update your view here!
    }
}

并使用 SurfaceView:

package com.example.cameratest;

import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

public class MainActivity extends Activity
{
    private SurfaceView preview = null;
    private SurfaceHolder previewHolder = null;
    private Camera camera = null;
    private boolean inPreview = false;
    private boolean cameraConfigured = false;

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

        setContentView(R.layout.activity_main);

        preview = (SurfaceView) findViewById(R.id.cpPreview);
        previewHolder = preview.getHolder();
        previewHolder.addCallback(surfaceCallback);
        previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void onResume()
    {
        super.onResume();

        camera = Camera.open();
        startPreview();
    }

    @Override
    public void onPause()
    {
        if (inPreview)
        {
            camera.stopPreview();
        }

        camera.release();
        camera = null;
        inPreview = false;

        super.onPause();
    }

    private Camera.Size getBestPreviewSize(int width, int height,
            Camera.Parameters parameters)
    {
        Camera.Size result = null;

        for (Camera.Size size : parameters.getSupportedPreviewSizes())
        {
            if (size.width <= width && size.height <= height)
            {
                if (result == null)
                {
                    result = size;
                }
                else
                {
                    int resultArea = result.width * result.height;
                    int newArea = size.width * size.height;

                    if (newArea > resultArea)
                    {
                        result = size;
                    }
                }
            }
        }

        return (result);
    }

    private void initPreview(int width, int height)
    {
        if (camera != null && previewHolder.getSurface() != null)
        {
            try
            {
                camera.setPreviewDisplay(previewHolder);
            }
            catch (Throwable t)
            {
                Log.e("PreviewDemo-surfaceCallback",
                        "Exception in setPreviewDisplay()", t);
                Toast.makeText(MainActivity.this, t.getMessage(),
                        Toast.LENGTH_LONG).show();
            }

            if (!cameraConfigured)
            {
                Camera.Parameters parameters = camera.getParameters();
                Camera.Size size = getBestPreviewSize(width, height, parameters);

                if (size != null)
                {
                    parameters.setPreviewSize(size.width, size.height);
                    camera.setParameters(parameters);
                    cameraConfigured = true;
                }
            }
        }
    }

    private void startPreview()
    {
        if (cameraConfigured && camera != null)
        {
            camera.startPreview();
            inPreview = true;
        }
    }

    SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback()
    {
        public void surfaceCreated(SurfaceHolder holder)
        {
            // no-op -- wait until surfaceChanged()
        }

        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height)
        {
            initPreview(width, height);
            startPreview();
        }

        public void surfaceDestroyed(SurfaceHolder holder)
        {
            // no-op
        }
    };
}

但如果我尝试同时做这两个:

package com.example.multiplecamerapreviewtest;

import java.io.IOException;

import android.app.Activity;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
import android.widget.FrameLayout;
import android.widget.Toast;

public class MainActivity extends Activity implements SurfaceTextureListener
{
    private SurfaceView svPreview = null;
    private SurfaceHolder previewHolder = null;
    private Camera mCamera = null;
    private boolean inPreview = false;
    private boolean cameraConfigured = false;

    private TextureView tvPreview = null;

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

        setContentView(R.layout.activity_main);

        svPreview = (SurfaceView) findViewById(R.id.svPreview);
        previewHolder = svPreview.getHolder();
        previewHolder.addCallback(surfaceCallback);
        previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

//        mTextureView = new TextureView(this);
        tvPreview = (TextureView) findViewById(R.id.tvPreview);
        tvPreview.setSurfaceTextureListener(this);

//        setContentView(mTextureView);
    }

    @Override
    public void onResume()
    {
        super.onResume();

        mCamera = Camera.open();
        startPreview();
    }

    @Override
    public void onPause()
    {
        if (inPreview)
        {
            mCamera.stopPreview();
        }

        mCamera.release();
        mCamera = null;
        inPreview = false;

        super.onPause();
    }

    private Camera.Size getBestPreviewSize(int width, int height,
            Camera.Parameters parameters)
    {
        Camera.Size result = null;

        for (Camera.Size size : parameters.getSupportedPreviewSizes())
        {
            if (size.width <= width && size.height <= height)
            {
                if (result == null)
                {
                    result = size;
                }
                else
                {
                    int resultArea = result.width * result.height;
                    int newArea = size.width * size.height;

                    if (newArea > resultArea)
                    {
                        result = size;
                    }
                }
            }
        }

        return (result);
    }

    private void initPreview(int width, int height)
    {
        if (mCamera != null && previewHolder.getSurface() != null)
        {
            try
            {
                mCamera.setPreviewDisplay(previewHolder);
            }
            catch (Throwable t)
            {
                Log.e("PreviewDemo-surfaceCallback",
                        "Exception in setPreviewDisplay()", t);
                Toast.makeText(MainActivity.this, t.getMessage(),
                        Toast.LENGTH_LONG).show();
            }

            if (!cameraConfigured)
            {
                Camera.Parameters parameters = mCamera.getParameters();
                Camera.Size size = getBestPreviewSize(width, height, parameters);

                if (size != null)
                {
                    parameters.setPreviewSize(size.width, size.height);
                    mCamera.setParameters(parameters);
                    cameraConfigured = true;
                }
            }
        }
    }

    private void startPreview()
    {
        if (cameraConfigured && mCamera != null)
        {
            mCamera.startPreview();
            inPreview = true;
        }
    }

    SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback()
    {
        public void surfaceCreated(SurfaceHolder holder)
        {
            // no-op -- wait until surfaceChanged()
        }

        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height)
        {
            initPreview(width, height);
            startPreview();
        }

        public void surfaceDestroyed(SurfaceHolder holder)
        {
            // no-op
        }
    };


    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
            int height)
    {
        Log.i("onSurfaceTextureAvailable", "onSurfaceTextureAvailable");

        mCamera = Camera.open();

        Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
        tvPreview.setLayoutParams(new FrameLayout.LayoutParams(
                previewSize.width, previewSize.height, Gravity.CENTER));

        try
        {
            mCamera.setPreviewTexture(surface);
        }
        catch (IOException t)
        {
        }

        mCamera.startPreview();

    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
            int height)
    {
        // Ignored, the Camera does all the work for us
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface)
    {
        Log.i("onSurfaceTextureDestroyed", "onSurfaceTextureDestroyed");
        mCamera.stopPreview();
        mCamera.release();
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface)
    {
        // Update your view here!
    }
}

调用 mCamera.setPreviewTexture() 时出现“无法连接到相机服务”异常。

根据文档(http://developer.android.com/reference/android/hardware/Camera.html#setPreviewDisplay%28android.view.SurfaceHolder%29),这是预期的行为:

setPreviewDisplay()
 Setting a preview surface will un-set any preview surface texture that was set via setPreviewTexture(SurfaceTexture). 

(反之亦然)。我能做些什么来让这两者同时显示吗?

4

2 回答 2

2

将 Camera 输出发送到SurfaceTexture,然后使用 GLES 在任何您喜欢的地方渲染纹理。

参见Grafika中的“来自相机的纹理”活动。

这需要一些 EGL 管理和对 GLES 的基本熟悉,尽管您只需使用 Grafika 中的代码就可以达到相当远的水平。与使用 NDK 处理像素相比,这种方法可以获得更好的性能,因为 GPU 可以完成所有工作。

于 2014-12-11T16:51:08.943 回答
0

相机是共享的硬件资源。我认为Camera.open()即使在同一个应用程序中,即使在具有相同用户 ID 的同一进程中,您也不能多次访问它 ( )。如何在本地访问用于相机预览的缓冲区,然后从这些缓冲区中读取字节以在任意数量TextureView的 s 或SurfaceViews 或VideoViews 上呈现它们?

编辑:

NDK 资源: 如何使用 JNI 在 C 中获取原始 Android 相机缓冲区?

于 2014-02-06T16:27:16.960 回答