目前,我正在开发一个可以录制视频文件的应用程序。与视频文件并行记录音频文件。最终,有两个文件:.mp4
和.wav
。
我的目的是合并这两个文件。为此,文件应具有大致相同的持续时间。为了确定视频和音频文件的持续时间是否相等,我进行了一系列实验。我已经录制了视频:5次15分钟,5次30分钟,5次45分钟和5次60分钟。
在实验过程中,我捕获了以下值:
文件创建时间(精确到ms)。
IDateTime videoCreated = _fileWrapper.GetCreationTime(videoPath);
IDateTime audioCreated = _fileWrapper.GetCreationTime(audioPath);
文件的最后修改时间(精确到ms)。
IDateTime videoModified = _fileWrapper.GetLastWriteTime(videoPath);
IDateTime audioModified = _fileWrapper.GetLastWriteTime(audioPath);
我借助ffprobe测量了文件的持续时间。
我还计算了文件的长度,从上次更改的时间中减去了创建文件的时间。我们将此值称为计算的持续时间。
接下来,我将描述获得的结果。
如果考虑到计算的持续时间,则视频和音频文件大致相同。音频文件比视频文件短(平均为0.415 s,无关紧要)。
让我们通过ffprobe来了解持续时间。音频文件比视频文件长得多。以下是按组划分的音频和视频文件之间的平均差异:
15 min -12,426 s;
30 min -16,942 s;
45 min -31,403 s;
60 min -34,702 s.
仅适用于音频文件的结果:
ffprobe的持续时间略小于计算的持续时间。以下是不同组中的平均差异:
15 min - 0,424 s;
30 min - 1,129 s;
45 min - 1,816 s;
60 min - 2,292 s.
仅视频文件的结果:
ffprobe的持续时间明显小于计算的持续时间。组结果:
15 min -13,171 s;
30 min -18,630 s;
45 min -33,666 s;
15 min -37,326 s.
为什么ffprobe的持续时间小于计算的持续时间?如何解释所有这些观察?文件的实际持续时间是多少?
已更新。 格式:视频-.mp4,音频-.wav ffprobe命令示例:ffprove exampleFileName -v info -hide_banner -show_entries stream = duration -of xml
视频录制。使用了Vlc.DotNet.Core库。
public void Execute(object parameter)
{
if (_videoRecorder != null && _videoRecorder.IsPlaying())
{
_videoRecorder.Stop(); //!!!
_videoRecorder = null;
TimeSpan videoRecordingTime = TimeSpan.Zero; OnRecordingStopped?.Invoke(sessionService.CurrentDevice.Device.Id, videoRecordingTime);
return;
}
_videoRecorder = new VlcMediaPlayer(_vlcLibDirectory.DirectoryInfo);
_filenameGenerator.Folder = sessionService.PatientVideoDirectory;
_filenameGenerator.GenerateNextFileName();
string fileName = _filenameGenerator.GetName();
string fileDestination = Path.Combine(_filenameGenerator.FolderPath, fileName);
string[] mediaOptions =
{
":sout=#file{dst='" + fileDestination + "'}",
// ":live-caching=0",// TODO: check what that parameter does!
":sout-keep" /*Keep sout open (default disabled) : use the same sout instance across the various playlist items, if possible.*/
// ":file-logging", ":vvv", ":extraintf=logger", ":logfile=VlcLogs.log"
};
_videoRecorder.SetMedia(sessionService.CurrentDevice.MediaStreamUri, mediaOptions); _videoRecorder.Play();
OnRecordingStarted?.Invoke(fileName);
}
录音。使用了NAudio框架。
private void StartRecording()
{
try
{
string patientFolder = Patient.GetString();
_waveFileDestination = string.Empty;
if (IsForVideo)
{
_waveFileDestination = Path.Combine(_systemSetting.VideoServerPath, patientFolder,
_videoFileNameGenerator.GetCurrentNameWithExtension("wav"));
}
else
{
_audioFileNameGenerator.Folder = Path.Combine(_systemSetting.AudioPath, patientFolder);
_audioFileNameGenerator.GenerateNextFileName();
_waveFileDestination = Path.Combine(_audioFileNameGenerator.FolderPath,
_audioFileNameGenerator.GetName());
}
_waveSource = new WaveInEvent
{
DeviceNumber = CapturingDevice.Number,
WaveFormat = new WaveFormat(44100, 1)
};
_waveSource.DataAvailable += WaveSourceOnDataAvailable;
_waveSource.RecordingStopped += WaveSourceOnRecordingStopped;
_waveFile = new WaveFileWriter(_waveFileDestination, _waveSource.WaveFormat);
_waveSource.StartRecording();
if (!IsForVideo)
{
// Save audio media entity
_recordingMediaId = Media.AddToLocation(Patient.Id,
ExaminationId, _audioFileNameGenerator.GetName(),
MediaType.Audio, 0, _workstation.LocationId, DateTime.Now);
Media newMedia = Media.Get(_recordingMediaId);
MediaItem mediaItem = new MediaItem(newMedia, _systemSetting, _mediaManager)
{
PatientSsn = newMedia.AccessionNumber
};
OnAudioAdded(mediaItem);
}
}
catch (Exception exception)
{
}
finally
{
}
}
private void StopRecording()
{
try
{
_waveSource.StopRecording();
if (!IsForVideo)
{
Media media = Media.Get(_recordingMediaId);
media.Duration = Duration.Seconds;
Media.Update(media);
_recordingMediaId = 0;
}
else
{
IsForVideo = false;
}
}
catch (Exception exception)
{
}
OnStateChanged();
}