Refactored remaining time estimate.
This commit is contained in:
parent
0da054ccea
commit
aa3c648c4c
@ -168,72 +168,19 @@ namespace AaxDecrypter
|
|||||||
return aaxcProcesser.Succeeded;
|
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.ProcessPosition).TotalSeconds;
|
||||||
double remainingSecsToProcess = (aaxcTagLib.Properties.Duration - e).TotalSeconds;
|
double estTimeRemaining = remainingSecsToProcess / e.ProcessSpeed;
|
||||||
double estTimeRemaining = remainingSecsToProcess / averageRate;
|
|
||||||
|
|
||||||
if (double.IsNormal(estTimeRemaining))
|
if (double.IsNormal(estTimeRemaining))
|
||||||
DecryptTimeRemaining?.Invoke(this, TimeSpan.FromSeconds(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);
|
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>
|
/// <summary>
|
||||||
/// Copy all aacx metadata to m4b file, including cover art.
|
/// Copy all aacx metadata to m4b file, including cover art.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -7,13 +7,25 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AaxDecrypter
|
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>
|
/// <summary>
|
||||||
/// Download audible aaxc, decrypt, and remux with chapters.
|
/// Download audible aaxc, decrypt, and remux with chapters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class FFMpegAaxcProcesser
|
class FFMpegAaxcProcesser
|
||||||
{
|
{
|
||||||
public event EventHandler<TimeSpan> ProgressUpdate;
|
public event EventHandler<AaxcProcessUpdate> ProgressUpdate;
|
||||||
public string FFMpegPath { get; }
|
public string FFMpegPath { get; }
|
||||||
public DownloadLicense DownloadLicense { get; }
|
public DownloadLicense DownloadLicense { get; }
|
||||||
public bool IsRunning { get; private set; }
|
public bool IsRunning { get; private set; }
|
||||||
@ -24,7 +36,7 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
private StringBuilder remuxerError = new StringBuilder();
|
private StringBuilder remuxerError = new StringBuilder();
|
||||||
private StringBuilder downloaderError = 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 downloader;
|
||||||
private Process remuxer;
|
private Process remuxer;
|
||||||
|
|
||||||
@ -115,6 +127,7 @@ namespace AaxDecrypter
|
|||||||
if (processedTimeRegex.IsMatch(e.Data))
|
if (processedTimeRegex.IsMatch(e.Data))
|
||||||
{
|
{
|
||||||
//get timestamp of of last processed audio stream position
|
//get timestamp of of last processed audio stream position
|
||||||
|
//and processing speed
|
||||||
var match = processedTimeRegex.Match(e.Data);
|
var match = processedTimeRegex.Match(e.Data);
|
||||||
|
|
||||||
int hours = int.Parse(match.Groups[1].Value);
|
int hours = int.Parse(match.Groups[1].Value);
|
||||||
@ -123,7 +136,11 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
var position = new TimeSpan(hours, minutes, seconds);
|
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"))
|
if (e.Data.Contains("aac bitstream error"))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user