Запись видео и обратный вызов onPreviewFrame одновременно - PullRequest
0 голосов
/ 13 сентября 2018

Я пытаюсь записать видео с использованием MediaRecorder и получить необработанные кадры (байтовые массивы) из onPreviewFrame метода обратного вызова

Кажется, это не так просто, мб, это даже невозможно, я не знаю ...

Но я нашел несколько ответов (для похожих вопросов), и люди говорят, что вам следует повторно подключить экземпляр камеры (Camera.reconnect()) после вызова MediaRecorder.start() и снова установить обратный вызов для предварительного просмотра

Я пробовал что-то подобное, но это не работает (запись работает, но onPreviewFrame никогда не вызывается)

Я также пытался вызвать методы stopPreview и startPreview камеры после MediaRecorder.start(), но, похоже, не следует делать это иначе, когда я пытаюсь остановить запись (MediaRecorder.stop()) после того, как такие действия приложение перестанет отвечать (оно становится замороженная)

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.sample_main);
    mPreview = findViewById(R.id.surface_view);
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            testVideoRecording();
        }
    }, 1000);
}

@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
    Log.i(TAG, "onPreviewFrame");
}

private void testVideoRecording() {
    mCamera = Camera.open();

    Camera.Parameters parameters = mCamera.getParameters();
    List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
    List<Camera.Size> mSupportedVideoSizes = parameters.getSupportedVideoSizes();
    Camera.Size optimalSize = CameraHelper.getOptimalVideoSize(mSupportedVideoSizes,
            mSupportedPreviewSizes, mPreview.getWidth(), mPreview.getHeight());

    CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
    profile.videoFrameWidth = optimalSize.width;
    profile.videoFrameHeight = optimalSize.height;

    parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
    mCamera.setParameters(parameters);
    try {
        mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
    } catch (IOException e) {
        e.printStackTrace();
    }

    mCamera.setPreviewCallback(this);

    mMediaRecorder = new MediaRecorder();

    // Step 1: Unlock and set camera to MediaRecorder
    mCamera.unlock();
    mMediaRecorder.setCamera(mCamera);

    // Step 2: Set sources
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

    // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    mMediaRecorder.setProfile(profile);

    // Step 4: Set output file
    mOutputFile = new File(Environment.getExternalStorageDirectory()
            + File.separator + "test.mp4");
    if (mOutputFile.exists()) mOutputFile.delete();

    mMediaRecorder.setOutputFile(mOutputFile.getPath());

    // Step 5: Prepare configured MediaRecorder
    try {
        mMediaRecorder.prepare();
    } catch (IOException e) {
        e.printStackTrace();
    }
    mMediaRecorder.start();

    // Step 6: try to set preview frame callback

    //mCamera.stopPreview();

    try {
        mCamera.reconnect();
    } catch (IOException e) {
        e.printStackTrace();
    }

    /*try {
        mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
    } catch (IOException e) {
        e.printStackTrace();
    }*/

    mCamera.setPreviewCallback(this);

    //mCamera.startPreview();
}

Итак, я хочу знать, возможно ли использовать MediaRecorder и предварительный просмотр фрейма одновременно. Если да, то как это сделать правильно?

Ответы [ 2 ]

0 голосов
/ 15 сентября 2018

Прежде всего, я настоятельно рекомендую перейти с устаревшего Camera API (Camera.open(),…) на новый camera2 API , если только вашвсе целевые устройства ниже Android API 21. Новый API гораздо более мощный и гибкий.Например, он изначально поддерживает несколько целей в одной CaptureSession ограничениями в зависимости от CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL ). Здесь является примером использования MediaRecorder и ImageReader в одном сеансе.

Когда camera2 находится на уровне LEGACY на устройстве, все же может быть безопаснее использовать старый API напрямую (это родной язык таких камер).

Если вы застряли со старым API, рассмотрите один из образцов , которые записывают видео с использованием MediaCodec и MediaMuxer.Он более мощный, чем MediaRecorder, но требует больше работы.

Подвох, очевидно, заключается в том, что MediaCodec появляется в API 21, поэтому эти примеры в основном актуальны для устройств LEGACY.

Если вам действительно нужно работать со старыми устройствами, у вас нет выбора, кроме как запустить какой-нибудь альтернативный видеокодер, передаваемый из кадров, которые приходят к вам при onPreviewFrame() обратном вызове.

0 голосов
/ 15 сентября 2018

(отредактировано на основе комментария Алекса ниже)

Да, это возможно в целом. API камеры может быть хитрым, необходимы точность и постоянство.

Сначала начните с примера кода, который, как вы знаете, работает. Например, официальный учебник по захвату видео с оригинальным API: https://developer.android.com/guide/topics/media/camera#capture-video. Отлично, теперь, когда у вас есть пример кода, работающего на вашем устройстве, вы в большинстве своем. Если вы не можете заставить его работать на своем устройстве, попробуйте хотя бы одну другую марку устройства.

Далее, сделайте так, чтобы ваш собственный код приложения совпадал с потоками и вызовами API из примера. Когда вы получаете сообщение об ошибке или зависании, посмотрите журналы, чтобы понять, что произошло. Часто это что-то тривиальное, например, отсутствие разрешений в манифесте.

Наконец, логи, логи, логи. В этом вопросе, если вы опубликовали ошибки из журналов вместе с вашим кодом, возможно, вы обнаружили конкретную проблему с конкретным ответом.

Удачи!

...