В данный момент я работаю над приложением, которое позволяет записывать видеофайлы.Параллельно с видеофайлом записывается аудиофайл.В конце концов, есть два файла: .mp4
и .wav
.
Моя цель - объединить эти два файла.Для этого файлы должны быть примерно одинаковой продолжительности.Чтобы определить, имеют ли видео и аудио файлы одинаковую продолжительность, я провел серию экспериментов.Я записал видео: 5 раз за 15 минут, 5 раз за 30 минут, 5 раз за 45 минут и 5 раз за 60 минут.
Во время экспериментов я зафиксировал следующие значения:
Время создания файла (с точностью до мс).
IDateTime videoCreated = _fileWrapper.GetCreationTime(videoPath);
IDateTime audioCreated = _fileWrapper.GetCreationTime(audioPath);
Время последнего изменения файла (с точностью до мс).
IDateTime videoModified = _fileWrapper.GetLastWriteTime(videoPath);
IDateTime audioModified = _fileWrapper.GetLastWriteTime(audioPath);
Я измерил продолжительность файлов с помощью ffprobe.
Я также рассчитал длину файлов, вычитая время создания файла из временипоследние изменения.Давайте назовем это значение расчетной продолжительностью.
Далее я опишу полученные результаты.
Если мы примем во внимание рассчитанную продолжительность, видео и аудиофайлы примерно одинаковые.Аудиофайлы немного короче, чем видеофайлы (в среднем 0,415 с, что незначительно).
Давайте перейдем к длительности с помощью 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 framework.
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();
}