From ec67975171422bb356becdc1bdf433fcc8728780 Mon Sep 17 00:00:00 2001 From: Dominique Rahm Date: Tue, 23 Aug 2016 15:01:30 +0200 Subject: [PATCH] This should fix the freezing cameraPreview if the app is put to sleep with the power button and is woken up later. The static sSurfaceHolder stores the surfaceHolder and onResume() checks if it is still set. There are two cases: 1. If the app is put into background the surfaceHolder gets destroyed correctly (see surfaceDestroyed()) and the static variable is set to null. 2. If the power button is pressed surfaceDestroyed() callback is never called because the surface is not destroyed. In case number 1 we do not have to do anything because our app just goes trough the inital setup with the help of the Surface Callback In case number 2 we still have the surface but we released() everything else, therefore we have to setup() all the other things after opening the camera (EGL, mCameraTexture, mEncoderSurface, mCircEncoder...) This works for me and I hope it will work for others as well. I could not really test it because I cannot build this directory but I used this exact solution in my own app which is built on grafika/Continuous Capture for your changes. Lines starting --- .../grafika/ContinuousCaptureActivity.java | 78 +++++++++++-------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/src/com/android/grafika/ContinuousCaptureActivity.java b/src/com/android/grafika/ContinuousCaptureActivity.java index c59c89ee..e86f0156 100644 --- a/src/com/android/grafika/ContinuousCaptureActivity.java +++ b/src/com/android/grafika/ContinuousCaptureActivity.java @@ -79,6 +79,8 @@ public class ContinuousCaptureActivity extends Activity implements SurfaceHolder private MainHandler mHandler; private float mSecondsOfVideo; + private static SurfaceHolder sSurfaceHolder; + /** * Custom message handler for main UI thread. *

@@ -181,6 +183,8 @@ protected void onResume() { // Ideally, the frames from the camera are at the same resolution as the input to // the video encoder so we don't have to scale. openCamera(VIDEO_WIDTH, VIDEO_HEIGHT, DESIRED_PREVIEW_FPS); + + if(sSurfaceHolder != null) setUp(); } @Override @@ -348,17 +352,47 @@ private void updateBufferStatus(long durationUsec) { @Override // SurfaceHolder.Callback public void surfaceCreated(SurfaceHolder holder) { - Log.d(TAG, "surfaceCreated holder=" + holder); - - // Set up everything that requires an EGL context. - // - // We had to wait until we had a surface because you can't make an EGL context current - // without one, and creating a temporary 1x1 pbuffer is a waste of time. - // - // The display surface that we use for the SurfaceView, and the encoder surface we - // use for video, use the same EGL context. + Log.d(TAG, "surfaceCreated holder=" + holder + " (static=" + sSurfaceHolder + ")"); + if (sSurfaceHolder != null) { + throw new RuntimeException("sSurfaceHolder is already set"); + } + + sSurfaceHolder = holder; + } + + @Override // SurfaceHolder.Callback + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + Log.d(TAG, "surfaceChanged fmt=" + format + " size=" + width + "x" + height + + " holder=" + holder); + setUp(); + updateControls(); + } + + @Override // SurfaceHolder.Callback + public void surfaceDestroyed(SurfaceHolder holder) { + Log.d(TAG, "surfaceDestroyed holder=" + holder); + sSurfaceHolder = null; + } + + @Override // SurfaceTexture.OnFrameAvailableListener; runs on arbitrary thread + public void onFrameAvailable(SurfaceTexture surfaceTexture) { + //Log.d(TAG, "frame available"); + mHandler.sendEmptyMessage(MainHandler.MSG_FRAME_AVAILABLE); + } + + /** + * Set up everything that requires an EGL context. + * We had to wait until we had a surface because you can't make an EGL context current + * without one, and creating a temporary 1x1 pbuffer is a waste of time. + * + * The display surface that we use for the SurfaceView, and the encoder surface we + * use for video, use the same EGL context. + */ + private void setUp() { + assert sSurfaceHolder != null; + mEglCore = new EglCore(null, EglCore.FLAG_RECORDABLE); - mDisplaySurface = new WindowSurface(mEglCore, holder.getSurface(), false); + mDisplaySurface = new WindowSurface(mEglCore, sSurfaceHolder.getSurface(), false); mDisplaySurface.makeCurrent(); mFullFrameBlit = new FullFrameRect( @@ -374,36 +408,16 @@ public void surfaceCreated(SurfaceHolder holder) { throw new RuntimeException(ioe); } mCamera.startPreview(); - // TODO: adjust bit rate based on frame rate? // TODO: adjust video width/height based on what we're getting from the camera preview? - // (can we guarantee that camera preview size is compatible with AVC video encoder?) + // (can we guarantee that camera preview size is compatible with AVC video encoder?) try { mCircEncoder = new CircularEncoder(VIDEO_WIDTH, VIDEO_HEIGHT, 6000000, - mCameraPreviewThousandFps / 1000, 7, mHandler); +- mCameraPreviewThousandFps / 1000, 7, mHandler); } catch (IOException ioe) { throw new RuntimeException(ioe); } mEncoderSurface = new WindowSurface(mEglCore, mCircEncoder.getInputSurface(), true); - - updateControls(); - } - - @Override // SurfaceHolder.Callback - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.d(TAG, "surfaceChanged fmt=" + format + " size=" + width + "x" + height + - " holder=" + holder); - } - - @Override // SurfaceHolder.Callback - public void surfaceDestroyed(SurfaceHolder holder) { - Log.d(TAG, "surfaceDestroyed holder=" + holder); - } - - @Override // SurfaceTexture.OnFrameAvailableListener; runs on arbitrary thread - public void onFrameAvailable(SurfaceTexture surfaceTexture) { - //Log.d(TAG, "frame available"); - mHandler.sendEmptyMessage(MainHandler.MSG_FRAME_AVAILABLE); } /**