如何在游戏视图中添加相机预览(表面视图)

时间:2017-02-19 16:57:59

标签: android android-camera surfaceview

可以在我的游戏视图中添加相机预览吗? 我试图在游戏视图中添加相机预览,这个错误出现了。

E / SurfaceHolder:异常锁定表面java.lang.IllegalArgumentException

我的游戏循环似乎有问题 但我不知道如何解决它。 有谁知道如何解决这个问题?

我的GameLoop

public class MainThread extends Thread {
public static final int MAX_FPS = 30;
private double averageFPS;
private SurfaceHolder surfaceHolder;
private GamePanel gamePanel;
private boolean running;
public static Canvas canvas;

public void setRunning(boolean running){
    this.running = running;
}

public MainThread(SurfaceHolder surfaceHolder, GamePanel gamePanel){
    super();
    this.surfaceHolder = surfaceHolder;
    this.gamePanel = gamePanel;
}

@Override
public void run() {
    long startTime;
    long timeMillis = 1000/MAX_FPS;
    long waitTime;
    int frameCount = 0;
    long totalTime = 0;
    long targetTime = 1000/MAX_FPS;

    while(running){
        startTime = System.nanoTime();
        canvas = null;

        try{
            canvas = this.surfaceHolder.lockCanvas();
            synchronized (surfaceHolder){
                this.gamePanel.update();
                this.gamePanel.draw(canvas);
            }
        } catch (Exception e) {e.printStackTrace();}
        finally {
            if (canvas != null){
                try{
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }catch (Exception e) {e.printStackTrace();}
            }
        }
        timeMillis = (System.nanoTime() - startTime) / 1000000;
        waitTime = targetTime - timeMillis;
        try{
            if(waitTime > 0 )
                this.sleep(waitTime);
        }catch (Exception e) {e.printStackTrace();}

        totalTime += System.nanoTime() - startTime;
        frameCount++;
        if(frameCount == MAX_FPS){
            averageFPS = 1000/((totalTime/frameCount)/1000000);
            frameCount = 0;
            totalTime = 0;
            System.out.println(averageFPS);
        }
    }
}

}

我的GameView

public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
private MainThread thread;

private ObstacleManager obstacleManager;

private SurfaceHolder mHolder;
private Camera mCamera;

public GamePanel(Context context, Camera camera) {
    super(context);
    mCamera = camera;
    mCamera.setDisplayOrientation(90);
    mHolder = getHolder();
    mHolder.addCallback(this);
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    thread = new MainThread(mHolder, this);

    obstacleManager = new ObstacleManager(100, 100, Color.BLACK);
    setFocusable(true);
}

@Override
public void surfaceCreated(SurfaceHolder holder) {

    try{
        //when the surface is created, we can set the camera to draw images in this surfaceholder
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

    } catch (IOException e) {
        Log.d("ERROR", "Camera error on surfaceCreated " + e.getMessage());
    }
    thread = new MainThread(holder, this);
    thread.setRunning(true);
    thread.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    //before changing the application orientation, you need to stop the preview, rotate and then start it again
    if(mHolder.getSurface() == null)//check if the surface is ready to receive camera data
        return;

    try{
        mCamera.stopPreview();
    } catch (Exception e){
        //this will happen when you are trying the camera if it's not running
    }

    //now, recreate the camera preview
    try{
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();
    } catch (IOException e) {
        Log.d("ERROR", "Camera error on surfaceChanged " + e.getMessage());
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    boolean retry = false;
    while(retry){
        try{
            thread.setRunning(false);
            thread.join();
        }catch (Exception e) {e.printStackTrace(); }
        retry = false;
    }
    mCamera.stopPreview();
    mCamera.release();
}

public void update(){
    obstacleManager.update();
}

@Override
public void draw(Canvas canvas){
    super.draw(canvas);
    //canvas.drawColor(Color.WHITE);
    obstacleManager.draw(canvas);
}

}

我的主要活动

public class Main2Activity extends Activity {

//declaring gameview
private GameView gameView;
private Camera mCamera;
private FrameLayout frameLayout;
private GamePanel gamePanel;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);

    DisplayMetrics dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);
    Constants.SCREEN_WIDTH = dm.widthPixels;
    Constants.SCREEN_HEIGHT = dm.heightPixels;


    try {
        mCamera = Camera.open(0);//you can use open(int) to use different cameras
    } catch (Exception e) {
        Log.d("ERROR", "Failed to get camera: " + e.getMessage());
    }

    if (mCamera != null) {
        frameLayout = (FrameLayout) findViewById(R.id.gameView);
        gamePanel = new GamePanel(this, mCamera);
        frameLayout.addView(gamePanel);
    }

}

}

1 个答案:

答案 0 :(得分:0)

您无法在相机预览和画布绘制中使用相同的曲面。你可以创建两个表面,一个在另一个旁边,但是甚至不试图将一个表面放在另一个表面之上,它们不会可靠地保持z顺序。最好的方法是将相机预览切换为SurfaceTexture,并使用相同的OpenGL上下文绘制游戏和相机预览。