Определить, когда видео файл был действительно написан?

В библиотеке cwac-camera есть обработчики событий, которые вызываются до сохранения фотографии:

@Override public void saveImage(PictureTransaction xact, byte[] image) {}

Я только что пропустил это или нет раковины, которая говорит мне, когда видео файл был сохранен?

Еще немного справочной информации: есть два способа закончить видео. Один по телефону

.stopRecording();

другой - путем настройки рекордера на максимальную длительность / максимальный размер файла (в этом случае запись останавливается без явного вызова stopRecording():

recorder.setMaxDuration()

В обоих случаях, как мне кажется, Android требуется около 100-200 мсек для завершения файла. Поскольку видео файл часто поврежден, когда я просто использую

mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
        @Override public void onInfo(MediaRecorder mr, int what, int extra) {}
}

чтобы определить, когда он закончен, или попробуйте прочитать его сразу после вызова stopRecording(). Я попытался с помощью FileObserver определить, когда медиа-рекордер действительно закрывает файл, что хорошо работает.

Я хотел бы обсудить эту проблему, если у кого-то был такой же опыт, и если есть способ, как cwac-camera обнаруживает и сигнализирует записанный файл.

-

Я просто перешагнул через это в документации по Android здесь http://developer.android.com/reference/android/media/MediaRecorder.html

"Остановка происходит асинхронно, нет гарантии, что рекордер остановится к тому времени, когда слушатель получит уведомление".

Это объясняет, почему файл иногда не закрывается должным образом, и это неявно означает, что использование FileObserver, вероятно, является единственным безопасным и рабочим способом доступа к файлу после его записи.

Таким образом, нам нужно что-то подобное, чтобы обнаружить событие.

@Override protected File getVideoPath() {
    File file = super.getVideoPath(); // assemble the video path
    fileObserverPath = file.getAbsolutePath();

    fileObserver = new FileObserver(fileObserverPath, FileObserver.CLOSE_WRITE) {
        @Override public void onEvent(int event, String videoPath) {

            System.out.println("**** CameraHost: write closed");

            if (fileObserver != null) { // defensive
                fileObserver.stopWatching();
                fileObserver = null;
            }

            // process the file here
        }
    };
    fileObserver.startWatching();

    return file;
}

-

Я пошел дальше и добавил следующий код в CameraHost, чтобы получить время:

@Override public void configureRecorderOutput(int cameraId, MediaRecorder recorder) {

    System.out.println("**** CameraHost: configureRecorderOutput");

    recorder.setMaxDuration(Constants.FRAMEPLAYER_MAX_RECORDING_LENGTH_PER_FRAME_MSEC);
    recorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
        @Override public void onInfo(MediaRecorder mr, int what, int extra) {
            switch (what) {
                case MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED: {

                    System.out.println("**** CameraHost: MEDIA_RECORDER_INFO_MAX_DURATION_REACHED");

                    break;
                }
            }
        }
    });

    super.configureRecorderOutput(cameraId, recorder);
}

Тайминги:

11-20 07:33:28.974  32602-32602/cc.closeup.android I/System.out﹕ **** CameraHost: configureRecorderOutput
11-20 07:33:31.064  32602-32602/cc.closeup.android I/System.out﹕ **** CameraHost: MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
11-20 07:33:31.084  32602-32602/cc.closeup.android I/System.out﹕ **** CameraHost: MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
11-20 07:33:36.914  32602-32655/cc.closeup.android I/System.out﹕ **** CameraHost: write closed
11-20 07:33:36.914  32602-32655/cc.closeup.android I/System.out﹕ **** CameraHost: write closed

Две странные вещи:

  1. MEDIA_RECORDER_INFO_MAX_DURATION_REACHED повышается, но запись не останавливается. Вопреки тому, что указано в документации Android, я должен явно вызвать стоп.
  2. Даже если configureRecorderOutput вызывается только один раз, мои слушатели вызываются дважды. Я попробовал ту же самую внешнюю камеру cwac, и там слушателей вызывают только один раз.

Не уверен, что я где-то допустил ошибку или что-то пошло не так в cwac-камере.

Кто-нибудь там комментировать?

-

Что касается 2., что бы это ни было, мой журнал показывает, что медиа-рекордер, который запускает событие, является тем же самым, и вскоре после того, что =800 (MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) недокументированное, что =536871912 повышается. Во второй раз событие поднято без документов what = 268436456.

[из Asus Memo Pad 7:]

11-20 09:41:25.748    3398-3398/cc.closeup.android I/System.out﹕ **** CameraHost: onInfo: mr = android.media.MediaRecorder@41c9da88, what = 800, extra 0
11-20 09:41:25.748    3398-3398/cc.closeup.android I/System.out﹕ **** CameraHost: MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
11-20 09:41:25.748    3398-3398/cc.closeup.android I/System.out﹕ **** CameraHost: onInfo: mr = android.media.MediaRecorder@41c9da88, what = 536871912, extra 0

11-20 09:41:25.778    3398-3398/cc.closeup.android I/System.out﹕ **** CameraHost: onInfo: mr = android.media.MediaRecorder@41c9da88, what = 800, extra 0
11-20 09:41:25.778    3398-3398/cc.closeup.android I/System.out﹕ **** CameraHost: MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
11-20 09:41:25.778    3398-3398/cc.closeup.android I/System.out﹕ **** CameraHost: onInfo: mr = android.media.MediaRecorder@41c9da88, what = 268436456, extra 0

Я запустил это на другом устройстве, где событие MEDIA_RECORDER_INFO_MAX_DURATION_REACHED также вызывается дважды, но недокументированное что =? не поднимается вообще. Реализация конкретного поставщика?

[от Samsung Galaxy Note 2:]

11-20 09:46:42.711  25699-25699/cc.closeup.android I/System.out﹕ **** CameraHost: onInfo: mr = android.media.MediaRecorder@42831c30, what = 800, extra 0
11-20 09:46:42.711  25699-25699/cc.closeup.android I/System.out﹕ **** CameraHost: MEDIA_RECORDER_INFO_MAX_DURATION_REACHED

11-20 09:46:42.776  25699-25699/cc.closeup.android I/System.out﹕ **** CameraHost: onInfo: mr = android.media.MediaRecorder@42831c30, what = 800, extra 0
11-20 09:46:42.776  25699-25699/cc.closeup.android I/System.out﹕ **** CameraHost: MEDIA_RECORDER_INFO_MAX_DURATION_REACHED

Я продолжаю отправлять...

-

Что касается 1., запись фактически остановлена ​​(длина записанного файла составляет одну секунду), но FileObserver(), очевидно, вызывается только намного позже, а именно после того, как я явно вызвал cameraView.stop().

Я попытался вызвать stop () непосредственно в MediaRecorder, переданном в событии, которое работает в Android, но не в cwac.

-

Что касается 1., я углубился в это дальше, и похоже, что видеофайл сохраняется записанным, пока я не вызову cameraView.stop () явно - только тогда он усекается до одной секунды и закрывается.

// startRecording() called here

11-20 11:29:49.072    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:49.072    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 32, videoPath = media0.mp4
11-20 11:29:49.082    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:49.082    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:49.082    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:49.082    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:49.082    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:49.082    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.132    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.132    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.132    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.132    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4

11-20 11:29:51.132    4987-4987/cc.closeup.android I/System.out﹕ **** CameraHost: MEDIA_RECORDER_INFO_MAX_DURATION_REACHED

11-20 11:29:51.142    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.142    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.142    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.142    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.142    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
(...)
11-20 11:29:51.182    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.182    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.182    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4

11-20 11:29:51.192    4987-4987/cc.closeup.android I/System.out﹕ **** CameraHost: MEDIA_RECORDER_INFO_MAX_DURATION_REACHED

11-20 11:29:51.192    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.192    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.192    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.192    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.192    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
(...)
11-20 11:29:51.252    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.262    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.262    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.262    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.262    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:51.262    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4

// stopRecording() called here

11-20 11:29:52.492    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.492    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.492    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.492    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.572    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.572    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.572    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.572    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.572    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.572    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.572    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
(...)
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 2, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: FileObserver: onEvent: event = 8, videoPath = media0.mp4
11-20 11:29:52.582    4987-5167/cc.closeup.android I/System.out﹕ **** CameraHost: write closed: videoPath = media0.mp4

1 ответ

Решение

FileObserver может использоваться, чтобы определить, когда файл был наконец записан. Его можно подключить к переопределению getVideoDirectory() в CameraHost:

@Override protected File getVideoDirectory() {
    fileObserver = new FileObserver(videoDirectory.getAbsolutePath(), FileObserver.CLOSE_WRITE) {
        @Override public void onEvent(int event, String videoPath) {
            System.out.println("**** CameraHost: FileObserver: onEvent: event = " + event + ", videoPath = " + videoPath);

            if (fileObserver != null && videoPath != null && event == FileObserver.CLOSE_WRITE) { // do not process directory
                System.out.println("**** CameraHost: write closed: videoPath = " + videoPath);

                // fileObserver.stopWatching(); // TODO this needs to be closed somewhere
                // fileObserver = null;

                raiseVideo(videoPath);
            }
        }
    };
    fileObserver.startWatching();

    return videoDirectory;
}

FileObserver имеет ограничение, что он работает точно только тогда, когда явно вызывается stopRecording(). Он поднимается слишком поздно, если запись прекращается из-за достижения заданного размера или продолжительности файлов (см. Также https://github.com/commonsguy/cwac-camera/issues/242).

Использование Recorder.setOnInfoListener() не работает, потому что он может сообщить о завершении файла, прежде чем он был фактически записан на диск.

Другие вопросы по тегам