mirror of
https://github.com/unclshura/splitter.git
synced 2026-09-20 07:13:38 +00:00
Loseless split is back. Very fast now. Using key frames.
This commit is contained in:
parent
77bae6e392
commit
092bc88d58
@ -79,8 +79,8 @@ public class JobProcessor(ILogger logger) : LoggingBase(logger, 0), IJobProcesso
|
||||
}
|
||||
else
|
||||
{
|
||||
//processorFactory = i => new PassthroughSplitter(i, _logger);
|
||||
processorFactory = i => new ReencodeSplitter(i, _logger);
|
||||
processorFactory = i => new PassthroughSplitter(i, _logger);
|
||||
//processorFactory = i => new ReencodeSplitter(i, _logger);
|
||||
}
|
||||
|
||||
var segmentsToUse = predefinedSegments;
|
||||
|
||||
@ -82,8 +82,15 @@ public sealed class PassthroughSplitter : LoggingBase, ISegmentProcessor
|
||||
var start = job.SegmentStart;
|
||||
var length = job.SegmentLength;
|
||||
|
||||
// Probe next keyframe packet within a 5-second window
|
||||
var nextKey = ProbeNextKeyframePacket(inputFile, start);
|
||||
|
||||
// Adjust by subtracting X.XX seconds
|
||||
const double shiftBack = 0.1;
|
||||
var seekPos = nextKey > shiftBack ? nextKey - shiftBack : 0.0;
|
||||
|
||||
var args =
|
||||
$"-ss {start.ToString(CultureInfo.InvariantCulture)} " +
|
||||
$"-ss {seekPos.ToString(CultureInfo.InvariantCulture)} " +
|
||||
$"-i \"{inputFile}\" " +
|
||||
$"-t {length.ToString(CultureInfo.InvariantCulture)} " +
|
||||
$"-c copy {string.Join(" ", job.Job.Passthrough)} " +
|
||||
@ -100,4 +107,60 @@ public sealed class PassthroughSplitter : LoggingBase, ISegmentProcessor
|
||||
|
||||
return Process.Start(psi) ?? throw new Exception("Failed to start ffmpeg passthrough.");
|
||||
}
|
||||
|
||||
public static double ProbeNextKeyframePacket(string inputFile, double segmentStart, double window = 11.0)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = "ffprobe",
|
||||
Arguments =
|
||||
"-select_streams v " +
|
||||
$"-read_intervals \"{(segmentStart-0.1).ToString(CultureInfo.InvariantCulture)}%+{window.ToString(CultureInfo.InvariantCulture)}\" " +
|
||||
"-skip_frame nokey " +
|
||||
"-show_packets " +
|
||||
"-show_entries packet=pts_time,flags " +
|
||||
"-of compact=p=0 " +
|
||||
"-v quiet " +
|
||||
$"\"{inputFile}\"",
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using var p = Process.Start(psi);
|
||||
var output = p!.StandardOutput.ReadToEnd();
|
||||
p.WaitForExit();
|
||||
|
||||
double best = double.MaxValue;
|
||||
|
||||
foreach (var line in output.Split('\n'))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
// Example line:
|
||||
// pts_time=23.520000|flags=K__
|
||||
var parts = line.Split('|');
|
||||
if (parts.Length < 2)
|
||||
continue;
|
||||
|
||||
var ptsPart = parts[0].Trim(); // pts_time=23.520000
|
||||
var flagsPart = parts[1].Trim(); // flags=K__
|
||||
|
||||
if (!flagsPart.Contains("K"))
|
||||
continue;
|
||||
|
||||
var ptsStr = ptsPart.Replace("pts_time=", "");
|
||||
if (!double.TryParse(ptsStr, NumberStyles.Float, CultureInfo.InvariantCulture, out var pts))
|
||||
continue;
|
||||
|
||||
if ( best == double.MaxValue)
|
||||
best = pts;
|
||||
if (pts > segmentStart)
|
||||
break;
|
||||
}
|
||||
|
||||
return best == double.MaxValue ? segmentStart : best;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user