【问题标题】:Detect when video file has been really written?检测视频文件何时真正写入?
【发布时间】:2015-01-15 04:46:35
【问题描述】:

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 是否有办法检测记录的文件并发出信号。

--

我刚刚在 http://developer.android.com/reference/android/media/MediaRecorder.html#setMaxDuration(int)987654321@ 的 Android 文档中跳过了这个

“停止是异步发生的,无法保证在通知侦听器时记录器已经停止。”

这解释了为什么文件有时没有正确关闭,这隐含地意味着使用 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 文档中的规定相反,我必须显式调用 stop。
  2. 即使 configureRecorderOutput 只引发了一次,我的侦听器也被调用了两次。我尝试了相同的外部 cwac 摄像头,那里的听众只被调用一次。

不确定我是否在某处出错或 cwac-camera 出现问题。

有人评论吗?

--

关于 2.,不管是什么,我的日志显示触发事件的媒体记录器是相同的,并且在 what=800 (MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) 之后不久,就会引发未记录的 what=536871912。第二次引发事件时,未记录的 what=268436456。

[来自华硕备忘录 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 事件也被引发了两次,但未记录的 what=?根本没有提出来。供应商具体实施?

[来自三星 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()之后。

我尝试在事件中传递的 MediaRecorder 上直接调用 stop(),它在 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

【问题讨论】:

    标签: android video commonsware-cwac cwac-camera


    【解决方案1】:

    FileObserver 可用于检测文件何时最终被写入。它可以挂接到 CameraHost 中的 getVideoDirectory() 覆盖:

    @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() 不起作用,因为它可能会在文件实际写入磁盘之前报告文件已完成。

    【讨论】:

      猜你喜欢
      • 2013-08-25
      • 1970-01-01
      • 2011-12-04
      • 1970-01-01
      • 1970-01-01
      • 2022-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多