自定义SurfaceView应用程序丢失了曲面和无效的预览曲面

时间:2016-07-18 06:10:54

标签: android camera surfaceview mediarecorder android-mediarecorder

我创建了一个包含自定义SurfaceView的库:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = CameraPreview.class.getSimpleName();

    private final SurfaceHolder mHolder;
    private final Camera mCamera;
    private final int mCameraId;

    public CameraPreview(Context context, Camera camera, int cameraId) {
        super(context);
        mCamera = camera;
        mCameraId = cameraId;
        mHolder = getHolder();
        mHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.e(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
            // ignore: tried to stop a non-existent preview
        }

        // Adjust orientation
        final int rotation = CameraUtil.getAdjustedDisplayOrientation(getContext(), mCameraId);
        mCamera.setDisplayOrientation(rotation);

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // Empty. Take care of releasing the Camera preview in your activity.
    }
}

我创建了另一个库类CameraPreview的实例:

public class LibraryClass implements PreciseCountdownTimer.PreciseCountdownTimerCallback {

    private static final String TAG = LibraryClass.class.getSimpleName();
    private static final long MAX_RECORD_TIME_MILLIS = 3000;
    private static final long INTERVAL_MILLIS = 1000;

    private static LibraryClass mInstance;

    private Activity mActivity;
    private CameraInitListener mCallback;

    private int mCameraId = -1;
    private Camera mCamera;
    private CameraPreview mCameraPreview;
    private MediaRecorder mMediaRecorder;
    private PreciseCountdownTimer mTimer;
    private boolean mIsRecording = false;
    private File mTempVideoFile;

    public static LibraryClass getInstance() {
        if (mInstance == null) {
            mInstance = new LibraryClass();
        }
        return mInstance;
    }

    // Call this in onResume of the activity
    public void initialize(Activity activity) {
        mActivity = activity;

        try {
            mCallback = (CameraInitListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.getClass().getSimpleName()
                    + " must implement CameraInitListener");
        }

        if (ViewUtil.checkValidRootView(activity)) {
            PermissionUtil.requestPermissions(activity);
            prepareCamera();
            addCameraPreview();
            prepareMediaRecorder();
            prepareTimer();
            mCallback.onCameraInitialized();
        }
    }

    // Call this in onPause of the activity
    public void release() {
        releaseMediaRecorder();
        releaseCamera();
        removeCameraPreview();
        releaseTimer();
    }

    public void startRecording() {
        if (checkPermissions()) {
            try {
                mIsRecording = true;
                mMediaRecorder.start();
                mTimer.start();
                Log.d(TAG, "Recording started.");
            } catch (IllegalStateException e) {
                releaseMediaRecorder();
                releaseTimer();
            }
        } else {
            releaseMediaRecorder();
        }
    }

    public void stopRecording() {
        mIsRecording = false;
        mMediaRecorder.stop();
        releaseMediaRecorder();
        releaseTimer();
        getSignedUrl();
    }

    @Override
    public void onPreciseTimerTick(long remainingTime) {

    }

    @Override
    public void onPreciseTimerFinished() {
        mIsRecording = false;
        mMediaRecorder.stop();
        releaseMediaRecorder();
        releaseTimer();
        getSignedUrl();
    }

    private boolean checkPermissions() {
        if (PermissionUtil.checkCameraPermission(mActivity)
                && PermissionUtil.checkRecordAudioPermission(mActivity)
                && PermissionUtil.checkWriteExternalStoragePermission(mActivity)) {
            return true;
        } else {
            return false;
        }
    }

    private void prepareCamera() {
        mCameraId = CameraUtil.getFrontCameraId();
        if (mCameraId != -1) {
            try {
                mCamera = Camera.open(mCameraId);
            } catch (Exception e) {
                Log.e(TAG, "Error initializing front camera.");
                e.printStackTrace();
                mCamera = null;
            }
        }
    }

    private void releaseCamera() {
        if (mCamera != null){
            mCamera.release();
            mCamera = null;
        }
    }

    private void addCameraPreview() {
        if (mCamera == null) {
            return;
        }

        mCameraPreview = new CameraPreview(mActivity, mCamera, mCameraId);
        mCameraPreview.setLayoutParams(new FrameLayout.LayoutParams(100, 100, Gravity.TOP|Gravity.RIGHT));
        mCameraPreview.setBackgroundColor(ContextCompat.getColor(mActivity, android.R.color.holo_red_dark));

        final ViewGroup rootView = ViewUtil.getRootView(mActivity);
        rootView.addView(mCameraPreview);
    }

    private void removeCameraPreview() {
        if (mCameraPreview != null) {
            final ViewGroup rootView = ViewUtil.getRootView(mActivity);
            rootView.removeView(mCameraPreview);
        }
    }

    private void prepareMediaRecorder() {
        if (mCamera == null) {
            return;
        }

        mCamera.unlock();

        mMediaRecorder = new MediaRecorder();
        mMediaRecorder.setCamera(mCamera);
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mMediaRecorder.setProfile(CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_HIGH));

//        mTempVideoFile = FileUtil.getTempVideoFile(getContext());
        mTempVideoFile = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_MOVIES), DateUtil.getCurrentTimeStamp() + ".mp4");
        mMediaRecorder.setOutputFile(mTempVideoFile.getAbsolutePath());

        mMediaRecorder.setPreviewDisplay(mCameraPreview.getHolder().getSurface());
//        mMediaRecorder.setOrientationHint(90);

        try {
            mMediaRecorder.prepare();
        } catch (IllegalStateException|IOException e) {
            Log.e(TAG, "Error preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
        }
    }

    private void releaseMediaRecorder() {
        if (mMediaRecorder != null) {
            mMediaRecorder.reset();
            mMediaRecorder.release();
            mMediaRecorder = null;
        }

        if (mCamera != null) {
            mCamera.lock();
        }
    }

    private void prepareTimer() {
        mTimer = new PreciseCountdownTimer(MAX_RECORD_TIME_MILLIS, INTERVAL_MILLIS, this);
    }

    private void releaseTimer() {
        if (mTimer != null) {
            mTimer.stop();
        }
    }

我设置了一些调试断点,没有调用任何SurfaceView方法:surfaceCreatedsurfaceChangedsurfaceDestroyed

当我致电mMediaRecorder.prepare()时,它会捕获异常并releaseMediaRecorder

为什么我会收到错误?

E/MediaRecorderJNI: Application lost the surface
Error preparing MediaRecorder: invalid preview surface

0 个答案:

没有答案