Refactored remaining time estimate.
This commit is contained in:
parent
0da054ccea
commit
aa3c648c4c
@ -168,72 +168,19 @@ namespace AaxDecrypter
|
||||
return aaxcProcesser.Succeeded;
|
||||
}
|
||||
|
||||
private void AaxcProcesser_ProgressUpdate(object sender, TimeSpan e)
|
||||
private void AaxcProcesser_ProgressUpdate(object sender, AaxcProcessUpdate e)
|
||||
{
|
||||
double averageRate = getAverageProcessRate(e);
|
||||
double remainingSecsToProcess = (aaxcTagLib.Properties.Duration - e).TotalSeconds;
|
||||
double estTimeRemaining = remainingSecsToProcess / averageRate;
|
||||
double remainingSecsToProcess = (aaxcTagLib.Properties.Duration - e.ProcessPosition).TotalSeconds;
|
||||
double estTimeRemaining = remainingSecsToProcess / e.ProcessSpeed;
|
||||
|
||||
if (double.IsNormal(estTimeRemaining))
|
||||
DecryptTimeRemaining?.Invoke(this, TimeSpan.FromSeconds(estTimeRemaining));
|
||||
|
||||
double progressPercent = 100 * e.TotalSeconds / aaxcTagLib.Properties.Duration.TotalSeconds;
|
||||
double progressPercent = 100 * e.ProcessPosition.TotalSeconds / aaxcTagLib.Properties.Duration.TotalSeconds;
|
||||
|
||||
DecryptProgressUpdate?.Invoke(this, (int)progressPercent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the average processing rate based on the last 2 to <see cref="MAX_NUM_AVERAGE"/> samples.
|
||||
/// </summary>
|
||||
/// <param name="lastProcessedPosition">Position in the audio file last processed</param>
|
||||
/// <returns>The average processing rate, in book_duration_seconds / second.</returns>
|
||||
private double getAverageProcessRate(TimeSpan lastProcessedPosition)
|
||||
{
|
||||
streamPositions.Enqueue(new StreamPosition
|
||||
{
|
||||
ProcessPosition = lastProcessedPosition,
|
||||
EventTime = DateTime.Now,
|
||||
});
|
||||
|
||||
if (streamPositions.Count < 2)
|
||||
return double.PositiveInfinity;
|
||||
|
||||
//Calculate the harmonic mean of the last 2 to MAX_NUM_AVERAGE progress updates
|
||||
//Units are Book_Duration_Seconds / second
|
||||
|
||||
var lastPos = streamPositions.Count > MAX_NUM_AVERAGE ? streamPositions.Dequeue() : null;
|
||||
|
||||
double harmonicDenominator = 0;
|
||||
int harmonicNumerator = 0;
|
||||
|
||||
foreach (var pos in streamPositions)
|
||||
{
|
||||
if (lastPos is null)
|
||||
{
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
double dP = (pos.ProcessPosition - lastPos.ProcessPosition).TotalSeconds;
|
||||
double dT = (pos.EventTime - lastPos.EventTime).TotalSeconds;
|
||||
|
||||
harmonicDenominator += dT / dP;
|
||||
harmonicNumerator++;
|
||||
lastPos = pos;
|
||||
}
|
||||
|
||||
double harmonicMean = harmonicNumerator / harmonicDenominator;
|
||||
return harmonicMean;
|
||||
}
|
||||
|
||||
private const int MAX_NUM_AVERAGE = 15;
|
||||
private class StreamPosition
|
||||
{
|
||||
public TimeSpan ProcessPosition { get; set; }
|
||||
public DateTime EventTime { get; set; }
|
||||
}
|
||||
|
||||
private Queue<StreamPosition> streamPositions = new Queue<StreamPosition>();
|
||||
|
||||
/// <summary>
|
||||
/// Copy all aacx metadata to m4b file, including cover art.
|
||||
/// </summary>
|
||||
|
||||
@ -7,13 +7,25 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace AaxDecrypter
|
||||
{
|
||||
class AaxcProcessUpdate
|
||||
{
|
||||
public AaxcProcessUpdate(TimeSpan position, double speed)
|
||||
{
|
||||
ProcessPosition = position;
|
||||
ProcessSpeed = speed;
|
||||
EventTime = DateTime.Now;
|
||||
}
|
||||
public TimeSpan ProcessPosition { get; }
|
||||
public double ProcessSpeed { get; }
|
||||
public DateTime EventTime { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download audible aaxc, decrypt, and remux with chapters.
|
||||
/// </summary>
|
||||
class FFMpegAaxcProcesser
|
||||
{
|
||||
public event EventHandler<TimeSpan> ProgressUpdate;
|
||||
public event EventHandler<AaxcProcessUpdate> ProgressUpdate;
|
||||
public string FFMpegPath { get; }
|
||||
public DownloadLicense DownloadLicense { get; }
|
||||
public bool IsRunning { get; private set; }
|
||||
@ -24,7 +36,7 @@ namespace AaxDecrypter
|
||||
|
||||
private StringBuilder remuxerError = new StringBuilder();
|
||||
private StringBuilder downloaderError = new StringBuilder();
|
||||
private static Regex processedTimeRegex = new Regex("time=(\\d{2}):(\\d{2}):(\\d{2}).\\d{2}", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static Regex processedTimeRegex = new Regex("time=(\\d{2}):(\\d{2}):(\\d{2}).\\d{2}.*speed=\\s{0,1}([0-9]*[.]?[0-9]+)(?:e\\+([0-9]+)){0,1}", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private Process downloader;
|
||||
private Process remuxer;
|
||||
|
||||
@ -115,6 +127,7 @@ namespace AaxDecrypter
|
||||
if (processedTimeRegex.IsMatch(e.Data))
|
||||
{
|
||||
//get timestamp of of last processed audio stream position
|
||||
//and processing speed
|
||||
var match = processedTimeRegex.Match(e.Data);
|
||||
|
||||
int hours = int.Parse(match.Groups[1].Value);
|
||||
@ -123,7 +136,11 @@ namespace AaxDecrypter
|
||||
|
||||
var position = new TimeSpan(hours, minutes, seconds);
|
||||
|
||||
ProgressUpdate?.Invoke(sender, position);
|
||||
double speed = double.Parse(match.Groups[4].Value);
|
||||
int exp = match.Groups[5].Success ? int.Parse(match.Groups[5].Value) : 0;
|
||||
speed *= Math.Pow(10, exp);
|
||||
|
||||
ProgressUpdate?.Invoke(this, new AaxcProcessUpdate(position, speed));
|
||||
}
|
||||
|
||||
if (e.Data.Contains("aac bitstream error"))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user