2017-01-29 62 views
1

所以我在camera2 api上玩了整個週末。現在我已經開始理解事情是如何連接在一起的。 雖然測試api來實現視頻錄製應用程序,但我仍然碰壁了。如何在Android上的camera2 API中重用MediaRecorder的Surface?

我開始將Android Camera2Video Sample更改爲我的需要。搞砸我的是,在每次錄製過程之後,攝像機會話正在重新創建。更糟糕的是,當錄製會話開始發生時,預覽會話將首先被銷燬,並創建錄製會話。錄製會話完成後,會被破壞並創建新的預覽會話。

的文件中明確指出:

創建一個會話是一個昂貴的操作,可能需要幾百毫秒... CameraCaptureSession Documentation

結果看起來很醜,畫面斷斷續續時,我打記錄並停止。我想改善這種行爲,所以我擺弄了代碼。

我現在要做的就是創建我的唯一,我通過調用其getSurface方法添加我的預覽表面(TextureView)以及表面從已創建MediaRecorderCameraSession。這適用於第一個視頻,但是當我嘗試捕獲第二個視頻時,我得到一個IllegalArgumentException: Bad argument passed to camera service。我認爲這是因爲當我重置MediaRecorder來準備新錄音時,我在創建時傳遞給CameraSessionMediaRecorder的表面被破壞或更改。

我現在的問題是,有沒有辦法解決這個問題? (setInputSurface(Surface surface))可能只是api級別太高,所以我沒有測試它。

這裏是在相關代碼段的快速概述:

  1. 設置的MediaRecorder

    private void setUpMediaRecorder() throws IOException { 
        if (mMediaRecorder == null) { 
         mMediaRecorder = new MediaRecorder(); 
        } 
        mMediaRecorder.setVideoEncodingBitRate(5000000); 
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); 
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 
        mMediaRecorder.setVideoFrameRate(24); 
        mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight()); 
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); 
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); 
        mMediaRecorder.setOrientationHint(SENSOR_ORIENTATION_DEFAULT_DEGREES); 
        mNextVideoAbsolutePath = getVideoFilePath(); 
        mMediaRecorder.setOutputFile(mNextVideoAbsolutePath); 
        mMediaRecorder.prepare(); 
    } 
    
  2. 創建的所有強大的錄音會議

    SurfaceTexture texture = mTextureView.getSurfaceTexture(); 
    texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); 
    
    List<Surface> surfaces = new ArrayList<>(); 
    // Set up Surface for the camera preview 
    mPreviewSurface = new Surface(texture); 
    surfaces.add(mPreviewSurface); 
    
    // Set up Surface for the MediaRecorder 
    mRecorderSurface = mMediaRecorder.getSurface(); 
    surfaces.add(mRecorderSurface); 
    
    // create the capture session 
    mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() { 
    
        @Override 
        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { 
         mCameraSession = cameraCaptureSession; 
    
         // now that the session is created, start using it for the preview 
         showPreview(); 
        } 
    
        @Override 
        public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { 
         .... 
          } 
         } 
        }, mBackgroundHandler); 
    } catch (CameraAccessException) { 
        e.printStackTrace(); 
    } 
    
    void showPreview() { 
        mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 
        mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); 
        mPreviewBuilder.addTarget(mPreviewSurface); 
        mCameraSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler); 
    } 
    
  3. 開始錄製視頻

    mVideoBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); 
    mVideoBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO); 
    mVideoBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); 
    mVideoBuilder.addTarget(mPreviewSurface); 
    mVideoBuilder.addTarget(mRecorderSurface); 
    // set the request for the capture 
    mCameraSession.setRepeatingRequest(mVideoBuilder.build(), null, mBackgroundHandler); 
    // Start recording 
    mMediaRecorder.start(); 
    
  4. 停止錄製

    mMediaRecorder.stop(); 
    mMediaRecorder.reset(); 
    showPreview(); 
    setUpMediaRecorder(); // this is key to not get an error from the MediaRecorder 
    

所有這一切都完美的作品和錄像的啓動和停止沒有任何的毛病!這很棒,但當我回到步驟3(4)之後,我會看到前面提到的IllegalArgumentException: Bad argument passed to camera service。我一直把頭撞在牆上,但是我找不到解決這個問題的辦法。

任何幫助,非常感謝!

謝謝!

回答

1

退房MediaRecorder#setInputSurface(android.view.Surface)

配置採用表面視頻源時,使用持久表面記錄。

當試圖找出如何重用MediaRecorder捕捉表面時,我偶然發現了它。通過這種方式,您可以將永久性表面設置爲捕獲會話的輸出表面之一,並且不需要重新創建捕獲會話就可以更改從新的prepare()調用生成的MediaRecorder表面。

Google Nexus和Pixel相機應用程序能夠在預覽中沒有任何口吃的情況下啓動和停止視頻錄製,因此絕對可以以某種方式做到這一點。

相關問題