Refactored remaining time estimate.

This commit is contained in:
Michael Bucari-Tovo 2021-06-30 13:21:39 -06:00
parent 0da054ccea
commit aa3c648c4c
2 changed files with 25 additions and 61 deletions

View File

@ -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>

View File

@ -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"))