Android MediaRecorder stop()未被调用

时间:2016-08-01 04:40:50

标签: java android mediarecorder android-mediarecorder

我有一个非常奇怪的错误,我的某些代码没有被调用,但看起来没有任何理由不能调用它。

调用

onFinishedRecording并注销标记"Finished recording.",但之后的代码根本不会被调用。调用mMediaRecorder.stop();时,所有代码都会停止调用。它也没有进入catch块。为什么会这样?

我认为它可能与不同的线程有关,但我检查了所有的线程名称,它们都在同一个主线程上运行。

此外,我的相机预览设置可能有问题吗?当我尝试播放视频时,它已损坏且无法播放。

除了上述问题之外,我的后退按钮在应用程序中没有做任何事情。不完全说明为什么或如何与我实施的代码相关。

MyLibrary类(库模块类)

public class MyLibrary implements PreciseCountdownTimer.PreciseCountdownTimerCallback {

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

    private static MyLibrary mInstance;

    private Activity mActivity;
    private CameraInitListener mCallback;

    private int mCameraId = -1;
    private Camera mCamera;
    private SurfaceView mCameraPreview;
    private MediaRecorder mMediaRecorder;
    private PreciseCountdownTimer mTimer;
    private File mTempVideoFile;

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

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

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

        if (ViewUtil.checkValidRootView(mActivity)) {
            PermissionUtil.requestPermissions(mActivity);
            prepareCamera();
            if (mCamera == null) {
                return;
            }
            addCameraPreview();
        }
    }

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

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

    public void stopRecording() {
        onFinishedRecording();
    }

    @Override
    public void onPreciseTimerTick(long remainingTime) {
        Log.d(TAG, "TICK: " + String.valueOf(remainingTime));
    }

    @Override
    public void onPreciseTimerFinished() {
        Log.d(TAG, "Timer Finished.");
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                onFinishedRecording();
            }
        });
    }

    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 {
                Log.d(TAG, "Initializing front camera.");
                mCamera = Camera.open(mCameraId);
            } catch (Exception e) {
                Log.e(TAG, "Error initializing front camera: " + e.getMessage());
                mCamera = null;
            }
        } else {
            mCamera = null;
        }
    }

    private void releaseCamera() {
        if (mCamera != null){
            Log.d(TAG, "Releasing camera.");
            mCamera.release();
            mCamera = null;
        }
    }

    private void addCameraPreview() {
        mCameraPreview = new SurfaceView(mActivity);
        mCameraPreview.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                Log.d(TAG, "Preview surface created.");
                try {
                    Log.d(TAG, "Setting preview display.");
                    mCamera.setPreviewDisplay(holder);
                    mCamera.startPreview();
                    onPreviewDisplaySet();
                } catch (IOException e) {
                    Log.e(TAG, "Error setting camera preview: " + e.getMessage());
                }
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                Log.d(TAG, "Preview surface changed.");
                // 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 (mCameraPreview.getHolder().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(mActivity, mCameraId);
                mCamera.setDisplayOrientation(rotation);

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

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

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                Log.d(TAG, "Preview surface destroyed.");
            }
        });
        mCameraPreview.setLayoutParams(new FrameLayout.LayoutParams(100, 100, Gravity.TOP|Gravity.RIGHT));
        mCameraPreview.setBackgroundColor(ContextCompat.getColor(mActivity, android.R.color.holo_red_dark));

        final WindowManager windowManager =
                (WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE);
        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(1, 1,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, 0, PixelFormat.UNKNOWN);
        windowManager.addView(mCameraPreview, layoutParams);
    }

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

    private void onPreviewDisplaySet() {
        createTempVideoFile();

        prepareMediaRecorder();
        if (mMediaRecorder == null) {
            return;
        }

        prepareTimer();
        mCallback.onCameraInitialized();
    }

    private void createTempVideoFile() {
        mTempVideoFile = FileUtil.getTempVideoFile(mActivity);
    }

    private void prepareMediaRecorder() {
        if (mCamera != null) {
            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));
        mMediaRecorder.setOutputFile(mTempVideoFile.getAbsolutePath());
        mMediaRecorder.setPreviewDisplay(mCameraPreview.getHolder().getSurface());
//        mMediaRecorder.setOrientationHint(90);

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

    private void releaseMediaRecorder() {
        if (mMediaRecorder != null) {
            Log.d(TAG, "Releasing media recorder.");
            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) {
            Log.d(TAG, "Stopping timer.");
            mTimer.stop();
        }
    }

    private void onFinishedRecording() {
        Log.d(TAG, "Finished recording.");
        try {
            mMediaRecorder.stop();
            Log.d(TAG, "Media recorder stopped.");
        } catch (Exception e) {
            e.printStackTrace();
        }

        releaseMediaRecorder();
        releaseTimer();
        getSignedUrl();
    }

    private void getSignedUrl() {
        new GcpSigningRequest(new NetworkCallback<String>() {
            @Override
            public void onSuccess(String response) {
                uploadVideo(response);
            }

            @Override
            public void onError() {
                Log.e(TAG, "Error getting signing request.");
            }
        }).addToQueue();
    }

    private void uploadVideo(String signedUrl) {
        new UploadToGoogleRequest(signedUrl, mTempVideoFile.getName(),
                Uri.parse(mTempVideoFile.getAbsolutePath()), new NetworkCallback<Boolean>() {
            @Override
            public void onSuccess(Boolean response) {

            }

            @Override
            public void onError() {

            }
        }).addToQueue();
    }
}

RecordActivity

public class RecordActivity extends AppCompatActivity implements
        CameraInitListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onResume() {
        super.onResume();
        MyLibrary.getInstance().initialize(this);
    }

    @Override
    protected void onPause() {
        MyLibrary.getInstance().release();
        super.onPause();
    }

    @Override
    public void onCameraInitialized() {
        MyLibrary.getInstance().startRecording();
    }
}

所以在调用此方法之前一切正常:

    private void onFinishedRecording() {
        Log.d(TAG, "Finished recording.");
        try {
            mMediaRecorder.stop();
            Log.d(TAG, "Media recorder stopped.");
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }

        releaseMediaRecorder();
        releaseTimer();
        getSignedUrl();
    }

完整手机Stacktrace

08-15 21:17:46.735 24660-24660/com.walintukai.heatmapdemo I/dalvikvm: Could not find method android.content.res.Resources.getDrawable, referenced from method android.support.v7.widget.ResourcesWrapper.getDrawable
08-15 21:17:46.735 24660-24660/com.walintukai.heatmapdemo W/dalvikvm: VFY: unable to resolve virtual method 690: Landroid/content/res/Resources;.getDrawable (ILandroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
08-15 21:17:46.735 24660-24660/com.walintukai.heatmapdemo D/dalvikvm: VFY: replacing opcode 0x6e at 0x0002
08-15 21:17:46.735 24660-24660/com.walintukai.heatmapdemo I/dalvikvm: Could not find method android.content.res.Resources.getDrawableForDensity, referenced from method android.support.v7.widget.ResourcesWrapper.getDrawableForDensity
08-15 21:17:46.735 24660-24660/com.walintukai.heatmapdemo W/dalvikvm: VFY: unable to resolve virtual method 692: Landroid/content/res/Resources;.getDrawableForDensity (IILandroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
08-15 21:17:46.735 24660-24660/com.walintukai.heatmapdemo D/dalvikvm: VFY: replacing opcode 0x6e at 0x0002
08-15 21:17:46.785 933-11266/? D/KeyguardUpdateMonitor: sendKeyguardVisibilityChanged(true)
08-15 21:17:46.785 933-933/? D/KeyguardUpdateMonitor: handleKeyguardVisibilityChanged(1)
08-15 21:17:46.785 731-2931/? E/EnterpriseContainerManager: ContainerPolicy Service is not yet ready!!!
08-15 21:17:46.785 731-2931/? D/EnterpriseDeviceManager: ContainerId: 0
08-15 21:17:46.785 731-2931/? W/LicenseLogService: log() failed
08-15 21:17:46.805 170-170/? E/SMD: DCD ON
08-15 21:17:46.865 933-11213/? D/KeyguardUpdateMonitor: sendKeyguardVisibilityChanged(true)
08-15 21:17:46.865 933-933/? D/KeyguardUpdateMonitor: handleKeyguardVisibilityChanged(1)
08-15 21:17:46.935 380-24718/? E/mm-camera: color_correct_apply_gain: cc_gain_adj 1.000, digital_gain_brightness 1.000 dig_gain = 1.000
08-15 21:17:47.055 731-24783/? W/ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast:1509 com.android.server.InputMethodManagerService$4.run:2683 java.lang.Thread.run:841 <bottom of call stack> <bottom of call stack> 
08-15 21:17:47.145 174-234/? E/qdmemalloc: heap_msk=3000000 flags=1

08-15 21:17:47.165 174-234/? E/qdmemalloc: heap_msk=40000000 flags=1

08-15 21:17:47.185 933-10839/? D/KeyguardUpdateMonitor: sendKeyguardVisibilityChanged(true)
08-15 21:17:47.185 933-933/? D/KeyguardUpdateMonitor: handleKeyguardVisibilityChanged(1)
08-15 21:17:47.225 933-947/? D/KeyguardUpdateMonitor: sendKeyguardVisibilityChanged(true)
08-15 21:17:47.245 933-933/? D/KeyguardUpdateMonitor: handleKeyguardVisibilityChanged(1)
08-15 21:17:47.265 933-10842/? D/KeyguardUpdateMonitor: sendKeyguardVisibilityChanged(true)
08-15 21:17:47.275 174-940/? E/qdmemalloc: heap_msk=3000000 flags=1

08-15 21:17:47.275 174-940/? E/qdmemalloc: heap_msk=40000000 flags=1

08-15 21:17:47.285 24660-24660/com.walintukai.heatmapdemo D/RecordingService: Tick: 2000
08-15 21:17:47.295 933-933/? D/KeyguardUpdateMonitor: handleKeyguardVisibilityChanged(1)
08-15 21:17:47.305 179-24742/? W/CameraSource: Timed out waiting for incoming camera video frames: 0 us
08-15 21:17:47.375 933-11213/? D/KeyguardUpdateMonitor: sendKeyguardVisibilityChanged(true)
08-15 21:17:47.375 933-933/? D/KeyguardUpdateMonitor: handleKeyguardVisibilityChanged(1)
08-15 21:17:47.506 933-953/? D/KeyguardUpdateMonitor: sendKeyguardVisibilityChanged(true)
08-15 21:17:47.506 933-933/? D/KeyguardUpdateMonitor: handleKeyguardVisibilityChanged(1)
08-15 21:17:47.666 731-838/? D/PackageManager: [MSG] CHECK_PENDING_VERIFICATION
08-15 21:17:47.766 179-460/? D/AudioStreamOutALSA: standby
08-15 21:17:47.766 179-460/? D/ALSAModule: s_standby: handle 0xb7c24650 h 0x0
08-15 21:17:47.766 179-460/? E/ALSAModule: s_standby handle h 0xb7ceb678
08-15 21:17:47.836 933-6432/? D/KeyguardUpdateMonitor: sendKeyguardVisibilityChanged(true)
08-15 21:17:47.846 933-933/? D/KeyguardUpdateMonitor: handleKeyguardVisibilityChanged(1)
08-15 21:17:47.846 174-234/? I/SurfaceFlinger: id=833 Removed ieatmapdemo (12/17)
08-15 21:17:47.846 174-940/? I/SurfaceFlinger: id=833 Removed ieatmapdemo (-2/17)
08-15 21:17:47.896 933-11464/? D/KeyguardUpdateMonitor: sendKeyguardVisibilityChanged(true)
08-15 21:17:47.906 933-933/? D/KeyguardUpdateMonitor: handleKeyguardVisibilityChanged(1)
08-15 21:17:47.956 179-460/? D/ALSAModule: checkRunningHandle return false
08-15 21:17:47.956 179-460/? D/alsa_ucm: snd_use_case_set(): uc_mgr 0xb7bf62a0 identifier _verb value Inactive
08-15 21:17:47.956 179-460/? D/alsa_ucm: Set mixer controls for HiFi enable 0
08-15 21:17:47.956 179-460/? D/alsa_ucm: Setting mixer control: PRI_RX Audio Mixer MultiMedia1, value: 0
08-15 21:17:47.956 179-460/? E/ALSAModule: Number of modifiers 1
08-15 21:17:47.956 179-460/? E/ALSAModule: index 0 modifier Capture Music
08-15 21:17:47.956 179-460/? E/ALSAModule: use case is Capture Music
08-15 21:17:47.956 179-460/? E/ALSAModule: usecase_type is 2
08-15 21:17:47.956 179-460/? D/alsa_ucm: snd_use_case_set(): uc_mgr 0xb7bf62a0 identifier _disdev value Speaker
08-15 21:17:47.956 179-460/? D/alsa_ucm: Set mixer controls for Speaker enable 0
08-15 21:17:47.956 179-460/? D/alsa_ucm: Setting mixer control: RX5 MIX1 INP1, value: ZERO
08-15 21:17:47.966 179-460/? D/alsa_ucm: Setting mixer control: RX5 MIX1 INP2, value: ZERO
08-15 21:17:47.966 179-460/? D/alsa_ucm: Setting mixer control: LINEOUT2 Volume, value: 0
08-15 21:17:47.966 179-460/? D/alsa_ucm: Setting mixer control: LINEOUT4 Volume, value: 0
08-15 21:17:47.966 179-460/? D/alsa_ucm: Setting mixer control: RX5 Digital Volume, value: 0
08-15 21:17:48.286 24660-24660/com.walintukai.heatmapdemo D/RecordingService: Tick: 1000
08-15 21:17:48.296 731-824/? D/SensorService:   0.2 -0.0 11.0
08-15 21:17:48.647 731-824/? E/Sensors: accelHandler 0.162861 -0.044308 11.044633
08-15 21:17:48.727 179-24722/? E/mm-camera: poll type 1 returns 0
08-15 21:17:48.727 179-24723/? E/mm-camera: poll type 1 returns 0
08-15 21:17:48.727 179-24721/? E/mm-camera: poll type 1 returns 0
08-15 21:17:49.297 24660-24660/com.walintukai.heatmapdemo D/RecordingService: Tick: 0
08-15 21:17:49.297 24660-24660/com.walintukai.heatmapdemo D/RecordingService: Timer Finished
08-15 21:17:49.297 24660-24660/com.walintukai.heatmapdemo D/RecordingService: Finished recording
08-15 21:17:49.297 179-20689/? D/MPEG4Writer: Stopping Video track
08-15 21:17:49.808 170-170/? E/SMD: DCD ON
08-15 21:17:50.309 179-24742/? W/CameraSource: Timed out waiting for incoming camera video frames: 0 us
08-15 21:17:51.440 179-24720/? E/mm-camera: poll type 1 returns 0
08-15 21:17:51.570 179-24724/? E/mm-camera: poll type 0 returns 0
08-15 21:17:51.800 731-824/? D/SensorService:   0.2 -0.0 11.1
08-15 21:17:52.111 731-856/? V/AlarmManager: waitForAlarm result :4
08-15 21:17:52.121 731-856/? V/AlarmManager: trigger ELAPSED_REALTIME_WAKEUP or RTC_WAKEUP
08-15 21:17:52.151 731-824/? E/Sensors: accelHandler 0.129331 -0.021555 11.078163
08-15 21:17:52.151 19505-24874/? I/Finsky: [3562] com.google.android.finsky.receivers.FlushLogsReceiver$FlushLogsService.onHandleIntent(163): Flushing event logs for [wwRg65ZPhINg_7-olzSHzcWExtM]
08-15 21:17:52.161 19505-19520/? I/PlayCommon: [3510] com.google.android.play.a.al.e(730): Preparing logs for uploading
08-15 21:17:52.161 19505-20595/? I/PlayCommon: [3552] com.google.android.play.a.w.a(27553): Starting to flush logs
08-15 21:17:52.161 19505-20595/? I/PlayCommon: [3552] com.google.android.play.a.w.a(27564): Log flushed by 0 successful uploads
08-15 21:17:52.201 1184-1184/? I/Auth: [AuthDelegateWrapper] Service intent: Intent { cmp=com.google.android.gms/.auth.account.authenticator.DefaultAuthDelegateService }.
08-15 21:17:52.201 1184-1184/? I/Auth: [AuthDelegateWrapper] Service intent: Intent { cmp=com.google.android.gms/.auth.account.authenticator.DefaultAuthDelegateService }.
08-15 21:17:52.261 19505-19520/? I/PlayCommon: [3510] com.google.android.play.a.al.a(870): Connecting to server: https://play.googleapis.com/play/log?format=raw&proto_v2=true
08-15 21:17:52.441 731-826/? W/ProcessCpuTracker: Skipping unknown process pid 24877
08-15 21:17:52.451 731-826/? W/ProcessCpuTracker: Skipping unknown process pid 24879
08-15 21:17:52.451 731-826/? W/ProcessCpuTracker: Skipping unknown process pid 24880

2 个答案:

答案 0 :(得分:2)

好吧,我已经遇到了类似的情况,其中一些本机代码会崩溃并且破坏当前的线程,而不会说任何东西都没有返回到Java代码。

但是因为它不是主线程,所以应用程序的其余部分似乎都很好。

也许android设备监视器会向你展示一些关于运行线程的事情。

希望这很有用。

答案 1 :(得分:1)

我认为您应该在此之前检查mediaRecorder不是null,然后再致电stop()