mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-10 08:34:12 +01:00
Merge pull request #170 from test-in-prod/master
Enhance ffprobe duration parsing
This commit is contained in:
commit
814f499f62
5 changed files with 74 additions and 10 deletions
|
@ -239,9 +239,8 @@ public void Builder_BuildString_Loop()
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Builder_BuildString_Seek()
|
public void Builder_BuildString_Seek()
|
||||||
{
|
{
|
||||||
var str = FFMpegArguments.FromFileInput("input.mp4", false, opt => opt.Seek(TimeSpan.FromSeconds(10)))
|
var str = FFMpegArguments.FromFileInput("input.mp4", false, opt => opt.Seek(TimeSpan.FromSeconds(10))).OutputToFile("output.mp4", false, opt => opt.Seek(TimeSpan.FromSeconds(10))).Arguments;
|
||||||
.OutputToFile("output.mp4", false, opt => opt.Seek(TimeSpan.FromSeconds(10))).Arguments;
|
Assert.AreEqual("-ss 00:00:10.000 -i \"input.mp4\" -ss 00:00:10.000 \"output.mp4\"", str);
|
||||||
Assert.AreEqual("-ss 00:00:10 -i \"input.mp4\" -ss 00:00:10 \"output.mp4\"", str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
|
@ -25,6 +25,22 @@ public async Task Audio_FromStream_Duration()
|
||||||
Assert.IsTrue(fileAnalysis.Duration == streamAnalysis.Duration);
|
Assert.IsTrue(fileAnalysis.Duration == streamAnalysis.Duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MediaAnalysis_ParseDuration()
|
||||||
|
{
|
||||||
|
var durationHHMMSS = new FFProbeStream { Duration = "05:12:59.177" };
|
||||||
|
var longDuration = new FFProbeStream { Duration = "149:07:50.911750" };
|
||||||
|
var shortDuration = new FFProbeStream { Duration = "00:00:00.83" };
|
||||||
|
|
||||||
|
var testdurationHHMMSS = MediaAnalysis.ParseDuration(durationHHMMSS);
|
||||||
|
var testlongDuration = MediaAnalysis.ParseDuration(longDuration);
|
||||||
|
var testshortDuration = MediaAnalysis.ParseDuration(shortDuration);
|
||||||
|
|
||||||
|
Assert.IsTrue(testdurationHHMMSS.Days == 0 && testdurationHHMMSS.Hours == 5 && testdurationHHMMSS.Minutes == 12 && testdurationHHMMSS.Seconds == 59 && testdurationHHMMSS.Milliseconds == 177);
|
||||||
|
Assert.IsTrue(testlongDuration.Days == 6 && testlongDuration.Hours == 5 && testlongDuration.Minutes == 7 && testlongDuration.Seconds == 50 && testlongDuration.Milliseconds == 911);
|
||||||
|
Assert.IsTrue(testdurationHHMMSS.Days == 0 && testshortDuration.Hours == 0 && testshortDuration.Minutes == 0 && testshortDuration.Seconds == 0 && testshortDuration.Milliseconds == 830);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public async Task Uri_Duration()
|
public async Task Uri_Duration()
|
||||||
{
|
{
|
||||||
|
|
3
FFMpegCore/Assembly.cs
Normal file
3
FFMpegCore/Assembly.cs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("FFMpegCore.Test")]
|
|
@ -8,11 +8,28 @@ namespace FFMpegCore.Arguments
|
||||||
public class SeekArgument : IArgument
|
public class SeekArgument : IArgument
|
||||||
{
|
{
|
||||||
public readonly TimeSpan? SeekTo;
|
public readonly TimeSpan? SeekTo;
|
||||||
|
|
||||||
public SeekArgument(TimeSpan? seekTo)
|
public SeekArgument(TimeSpan? seekTo)
|
||||||
{
|
{
|
||||||
SeekTo = seekTo;
|
SeekTo = seekTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => !SeekTo.HasValue ? string.Empty : $"-ss {SeekTo.Value}";
|
public string Text {
|
||||||
|
get {
|
||||||
|
if(SeekTo.HasValue)
|
||||||
|
{
|
||||||
|
int hours = SeekTo.Value.Hours;
|
||||||
|
if(SeekTo.Value.Days > 0)
|
||||||
|
{
|
||||||
|
hours += SeekTo.Value.Days * 24;
|
||||||
|
}
|
||||||
|
return $"-ss {hours.ToString("00")}:{SeekTo.Value.Minutes.ToString("00")}:{SeekTo.Value.Seconds.ToString("00")}.{SeekTo.Value.Milliseconds.ToString("000")}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ private MediaFormat ParseFormat(Format analysisFormat)
|
||||||
{
|
{
|
||||||
return new MediaFormat
|
return new MediaFormat
|
||||||
{
|
{
|
||||||
Duration = TimeSpan.Parse(analysisFormat.Duration ?? "0"),
|
Duration = ParseDuration(analysisFormat.Duration),
|
||||||
FormatName = analysisFormat.FormatName,
|
FormatName = analysisFormat.FormatName,
|
||||||
FormatLongName = analysisFormat.FormatLongName,
|
FormatLongName = analysisFormat.FormatLongName,
|
||||||
StreamCount = analysisFormat.NbStreams,
|
StreamCount = analysisFormat.NbStreams,
|
||||||
|
@ -66,7 +66,6 @@ private VideoStream ParseVideoStream(FFProbeStream stream)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private AudioStream ParseAudioStream(FFProbeStream stream)
|
private AudioStream ParseAudioStream(FFProbeStream stream)
|
||||||
{
|
{
|
||||||
return new AudioStream
|
return new AudioStream
|
||||||
|
@ -115,11 +114,41 @@ public static int ParseIntInvariant(string line) =>
|
||||||
int.Parse(line, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
|
int.Parse(line, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
|
||||||
|
public static TimeSpan ParseDuration(string duration)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(duration))
|
||||||
|
{
|
||||||
|
var match = DurationRegex.Match(duration);
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
// ffmpeg may provide < 3-digit number of milliseconds (omitting trailing zeros), which won't simply parse correctly
|
||||||
|
// e.g. 00:12:02.11 -> 12 minutes 2 seconds and 110 milliseconds
|
||||||
|
var millisecondsPart = match.Groups[4].Value;
|
||||||
|
if (millisecondsPart.Length < 3)
|
||||||
|
{
|
||||||
|
millisecondsPart = millisecondsPart.PadRight(3, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
var hours = int.Parse(match.Groups[1].Value);
|
||||||
|
var minutes = int.Parse(match.Groups[2].Value);
|
||||||
|
var seconds = int.Parse(match.Groups[3].Value);
|
||||||
|
var milliseconds = int.Parse(millisecondsPart);
|
||||||
|
return new TimeSpan(0, hours, minutes, seconds, milliseconds);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return TimeSpan.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return TimeSpan.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static TimeSpan ParseDuration(FFProbeStream ffProbeStream)
|
public static TimeSpan ParseDuration(FFProbeStream ffProbeStream)
|
||||||
{
|
{
|
||||||
return !string.IsNullOrEmpty(ffProbeStream.Duration)
|
return ParseDuration(ffProbeStream.Duration);
|
||||||
? TimeSpan.Parse(ffProbeStream.Duration)
|
|
||||||
: TimeSpan.Parse(TrimTimeSpan(ffProbeStream.GetDuration()) ?? "0");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? TrimTimeSpan(string? durationTag)
|
private static string? TrimTimeSpan(string? durationTag)
|
||||||
|
|
Loading…
Reference in a new issue