diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
index 7054accfad..52221d349e 100644
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
@@ -82,5 +82,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
return null;
}
+
+ protected override bool IsVideoEncoder
+ {
+ get { return false; }
+ }
}
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index a350d05774..3c30d7cd80 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -142,6 +142,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
throw;
}
+ cancellationToken.Register(() => Cancel(process, encodingJob));
+
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
process.BeginOutputReadLine();
@@ -157,6 +159,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
return encodingJob;
}
+ private void Cancel(Process process, EncodingJob job)
+ {
+ Logger.Info("Killing ffmpeg process for {0}", job.OutputFilePath);
+
+ //process.Kill();
+ process.StandardInput.WriteLine("q");
+
+ job.IsCancelled = true;
+ }
+
///
/// Processes the exited.
///
@@ -169,25 +181,53 @@ namespace MediaBrowser.MediaEncoding.Encoder
Logger.Debug("Disposing stream resources");
job.Dispose();
+ var isSuccesful = false;
+
try
{
- Logger.Info("FFMpeg exited with code {0}", process.ExitCode);
+ var exitCode = process.ExitCode;
+ Logger.Info("FFMpeg exited with code {0}", exitCode);
+
+ isSuccesful = exitCode == 0;
+ }
+ catch
+ {
+ Logger.Error("FFMpeg exited with an error.");
+ }
+ if (isSuccesful && !job.IsCancelled)
+ {
+ job.TaskCompletionSource.TrySetResult(true);
+ }
+ else if (job.IsCancelled)
+ {
try
{
- job.TaskCompletionSource.TrySetResult(true);
+ DeleteFiles(job);
+ }
+ catch
+ {
+ }
+ try
+ {
+ job.TaskCompletionSource.TrySetException(new OperationCanceledException());
}
catch
{
}
}
- catch
+ else
{
- Logger.Error("FFMpeg exited with an error.");
-
try
{
- job.TaskCompletionSource.TrySetException(new ApplicationException());
+ DeleteFiles(job);
+ }
+ catch
+ {
+ }
+ try
+ {
+ job.TaskCompletionSource.TrySetException(new ApplicationException("Encoding failed"));
}
catch
{
@@ -206,6 +246,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
//}
}
+ protected virtual void DeleteFiles(EncodingJob job)
+ {
+ File.Delete(job.OutputFilePath);
+ }
+
private void OnTranscodeBeginning(EncodingJob job)
{
job.ReportTranscodingProgress(null, null, null, null);
@@ -219,10 +264,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- protected virtual bool IsVideoEncoder
- {
- get { return false; }
- }
+ protected abstract bool IsVideoEncoder { get; }
protected virtual string GetWorkingDirectory(EncodingJobOptions options)
{
@@ -263,6 +305,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// System.Int32.
protected int GetNumberOfThreads(EncodingJob job, bool isWebm)
{
+ // Only need one thread for sync
+ if (job.Options.Context == EncodingContext.Static)
+ {
+ return 1;
+ }
+
if (isWebm)
{
// Recommended per docs
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
index 40ca08c405..c8d121eead 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
@@ -18,6 +18,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public class EncodingJob : IDisposable
{
public bool HasExited { get; internal set; }
+ public bool IsCancelled { get; internal set; }
public Stream LogFileStream { get; set; }
public IProgress Progress { get; set; }
@@ -399,6 +400,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
// job.Framerate = framerate;
+ if (!percentComplete.HasValue && ticks.HasValue && RunTimeTicks.HasValue)
+ {
+ var pct = ticks.Value/RunTimeTicks.Value;
+ percentComplete = pct*100;
+ }
+
if (percentComplete.HasValue)
{
Progress.Report(percentComplete.Value);
diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
index 36406e3a3f..941649addc 100644
--- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
@@ -173,5 +173,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
return null;
}
+
+ protected override bool IsVideoEncoder
+ {
+ get { return true; }
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
index 7a363c54a9..b09bfe91fb 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Common.Progress;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
@@ -337,7 +338,9 @@ namespace MediaBrowser.Server.Implementations.Sync
cancellationToken.ThrowIfCancellationRequested();
- await ProcessJobItem(item, cancellationToken).ConfigureAwait(false);
+ var innerProgress = new ActionableProgress();
+
+ await ProcessJobItem(item, innerProgress, cancellationToken).ConfigureAwait(false);
var job = _syncRepo.GetJob(item.JobId);
await UpdateJobStatus(job).ConfigureAwait(false);
@@ -346,7 +349,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
- private async Task ProcessJobItem(SyncJobItem jobItem, CancellationToken cancellationToken)
+ private async Task ProcessJobItem(SyncJobItem jobItem, IProgress progress, CancellationToken cancellationToken)
{
var item = _libraryManager.GetItemById(jobItem.ItemId);
if (item == null)
@@ -372,12 +375,12 @@ namespace MediaBrowser.Server.Implementations.Sync
var video = item as Video;
if (video != null)
{
- await Sync(jobItem, video, deviceProfile, cancellationToken).ConfigureAwait(false);
+ await Sync(jobItem, video, deviceProfile, progress, cancellationToken).ConfigureAwait(false);
}
else if (item is Audio)
{
- await Sync(jobItem, (Audio)item, deviceProfile, cancellationToken).ConfigureAwait(false);
+ await Sync(jobItem, (Audio)item, deviceProfile, progress, cancellationToken).ConfigureAwait(false);
}
else if (item is Photo)
@@ -391,7 +394,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
- private async Task Sync(SyncJobItem jobItem, Video item, DeviceProfile profile, CancellationToken cancellationToken)
+ private async Task Sync(SyncJobItem jobItem, Video item, DeviceProfile profile, IProgress progress, CancellationToken cancellationToken)
{
var options = new VideoOptions
{
@@ -412,7 +415,26 @@ namespace MediaBrowser.Server.Implementations.Sync
jobItem.Status = SyncJobItemStatus.Converting;
await _syncRepo.Update(jobItem).ConfigureAwait(false);
- jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, profile), new Progress(), cancellationToken);
+ try
+ {
+ jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, profile), progress,
+ cancellationToken);
+ }
+ catch (OperationCanceledException)
+ {
+ jobItem.Status = SyncJobItemStatus.Queued;
+ }
+ catch (Exception ex)
+ {
+ jobItem.Status = SyncJobItemStatus.Failed;
+ _logger.ErrorException("Error during sync transcoding", ex);
+ }
+
+ if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued)
+ {
+ await _syncRepo.Update(jobItem).ConfigureAwait(false);
+ return;
+ }
}
else
{
@@ -435,7 +457,7 @@ namespace MediaBrowser.Server.Implementations.Sync
await _syncRepo.Update(jobItem).ConfigureAwait(false);
}
- private async Task Sync(SyncJobItem jobItem, Audio item, DeviceProfile profile, CancellationToken cancellationToken)
+ private async Task Sync(SyncJobItem jobItem, Audio item, DeviceProfile profile, IProgress progress, CancellationToken cancellationToken)
{
var options = new AudioOptions
{
@@ -455,8 +477,26 @@ namespace MediaBrowser.Server.Implementations.Sync
{
jobItem.Status = SyncJobItemStatus.Converting;
await _syncRepo.Update(jobItem).ConfigureAwait(false);
-
- jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, profile), new Progress(), cancellationToken);
+
+ try
+ {
+ jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, profile), progress, cancellationToken);
+ }
+ catch (OperationCanceledException)
+ {
+ jobItem.Status = SyncJobItemStatus.Queued;
+ }
+ catch (Exception ex)
+ {
+ jobItem.Status = SyncJobItemStatus.Failed;
+ _logger.ErrorException("Error during sync transcoding", ex);
+ }
+
+ if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued)
+ {
+ await _syncRepo.Update(jobItem).ConfigureAwait(false);
+ return;
+ }
}
else
{
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs
index c2925551b7..068261ffd3 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs
@@ -67,7 +67,7 @@ namespace MediaBrowser.Server.Implementations.Sync
public bool IsHidden
{
- get { return true; }
+ get { return false; }
}
public bool IsEnabled
diff --git a/SharedVersion.cs b/SharedVersion.cs
index d53462b93c..70c7bbf8c4 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-//[assembly: AssemblyVersion("3.0.*")]
-[assembly: AssemblyVersion("3.0.5482.1")]
+[assembly: AssemblyVersion("3.0.*")]
+//[assembly: AssemblyVersion("3.0.5482.1")]