2017-01-29 11 views
1

Так что я играл все выходные с помощью камеры2 api. Теперь я нахожусь в точке, где я начинаю понимать, как вещи связаны друг с другом. При тестировании api для реализации приложения для записи видео я ударил стену.Как повторно использовать поверхность MediaRecorder в Camera2 API на Android?

Я начал с изменения Android Camera2Video Sample в соответствии с моими потребностями. Меня беспокоит то, что после каждого процесса записи воссоздается сеанс камеры. Хуже того, когда начинается сеанс записи, происходит то, что сначала будет уничтожен сеанс предварительного просмотра, и будет создан сеанс записи. После завершения сеанса записи он уничтожается и создается новый сеанс предварительного просмотра.

В документации четко сказано:

Создание сессии является дорогостоящей операцией и может занять несколько сотен миллисекунд ... CameraCaptureSession Documentation

Результат выглядит довольно уродливо и экран заикается, когда я ударил запись и остановка. Я хотел улучшить это поведение, поэтому я возился с кодом.

Что я делаю сейчас я создаю мой один и только CameraSession, где я добавить мой просмотр поверхности (TextureView), а также поверхность с уже создана MediaRecorder путем вызова метода getSurface. Это отлично работает для первого видео, но когда я пытаюсь захватить второе видео, я получаю IllegalArgumentException: Bad argument passed to camera service. Я думаю, что это связано с тем, что поверхность MediaRecorder, которую я перехожу на CameraSession на его создание, каким-то образом разрушена или изменена, когда я сброшу MediaRecorder, чтобы подготовить новую запись.

Мой вопрос сейчас в том, есть ли какой-либо путь вокруг этой проблемы? (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. Таким образом, вы можете настроить постоянную поверхность на одну из выходных поверхностей сеанса захвата, и вам не нужно будет воссоздать сеанс захвата, чтобы изменить поверхность MediaRecorder, созданную при новом вызове prepare().

Приложения Google Nexus и Pixel могут запускать и останавливать видеозапись без какого-либо заикания в предварительном просмотре, так что это определенно возможно сделать это как-то.