diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index f71180754..3e9a0926b 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -3,15 +3,14 @@ using MediaBrowser.Controller;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Session;
using System;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Session;
namespace MediaBrowser.Api
{
@@ -100,7 +99,7 @@ namespace MediaBrowser.Api
{
var jobCount = _activeTranscodingJobs.Count;
- Parallel.ForEach(_activeTranscodingJobs.ToList(), KillTranscodingJob);
+ Parallel.ForEach(_activeTranscodingJobs.ToList(), j => KillTranscodingJob(j, true));
// Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
if (jobCount > 0)
@@ -291,16 +290,16 @@ namespace MediaBrowser.Api
{
var job = (TranscodingJob)state;
- KillTranscodingJob(job);
+ KillTranscodingJob(job, true);
}
///
/// Kills the single transcoding job.
///
/// The device id.
- /// if set to true [is video].
+ /// if set to true [delete files].
/// sourcePath
- internal void KillTranscodingJobs(string deviceId, bool isVideo)
+ internal void KillTranscodingJobs(string deviceId, bool deleteFiles)
{
if (string.IsNullOrEmpty(deviceId))
{
@@ -318,7 +317,7 @@ namespace MediaBrowser.Api
foreach (var job in jobs)
{
- KillTranscodingJob(job);
+ KillTranscodingJob(job, deleteFiles);
}
}
@@ -326,7 +325,8 @@ namespace MediaBrowser.Api
/// Kills the transcoding job.
///
/// The job.
- private void KillTranscodingJob(TranscodingJob job)
+ /// if set to true [delete files].
+ private void KillTranscodingJob(TranscodingJob job, bool deleteFiles)
{
lock (_activeTranscodingJobs)
{
@@ -344,48 +344,44 @@ namespace MediaBrowser.Api
}
}
- var process = job.Process;
-
- var hasExited = true;
-
- try
+ lock (job.ProcessLock)
{
- hasExited = process.HasExited;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
- }
+ var process = job.Process;
+
+ var hasExited = true;
- if (!hasExited)
- {
try
{
- Logger.Info("Killing ffmpeg process for {0}", job.Path);
+ hasExited = process.HasExited;
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
+ }
- process.Kill();
+ if (!hasExited)
+ {
+ try
+ {
+ Logger.Info("Killing ffmpeg process for {0}", job.Path);
- // Need to wait because killing is asynchronous
- process.WaitForExit(5000);
- }
- catch (Win32Exception ex)
- {
- Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
- }
- catch (InvalidOperationException ex)
- {
- Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
- }
- catch (NotSupportedException ex)
- {
- Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
+ //process.Kill();
+ process.StandardInput.WriteLine("q");
+
+ // Need to wait because killing is asynchronous
+ process.WaitForExit(5000);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
+ }
}
}
- // Dispose the process
- process.Dispose();
-
- DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
+ if (deleteFiles)
+ {
+ DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
+ }
}
private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs)
@@ -494,6 +490,8 @@ namespace MediaBrowser.Api
public string DeviceId { get; set; }
public CancellationTokenSource CancellationTokenSource { get; set; }
+
+ public object ProcessLock = new object();
}
///
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index d2369c410..0ecc5d9d1 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -816,6 +816,7 @@ namespace MediaBrowser.Api.Playback
// Must consume both stdout and stderr or deadlocks may occur
RedirectStandardOutput = true,
RedirectStandardError = true,
+ RedirectStandardInput = true,
FileName = MediaEncoder.EncoderPath,
WorkingDirectory = Path.GetDirectoryName(MediaEncoder.EncoderPath),
@@ -1073,8 +1074,9 @@ namespace MediaBrowser.Api.Playback
///
/// The process.
/// The state.
- protected void OnFfMpegProcessExited(Process process, StreamState state)
+ private void OnFfMpegProcessExited(Process process, StreamState state)
{
+ Logger.Debug("Disposing stream resources");
state.Dispose();
try
@@ -1083,8 +1085,19 @@ namespace MediaBrowser.Api.Playback
}
catch
{
- Logger.Info("FFMpeg exited with an error.");
+ Logger.Error("FFMpeg exited with an error.");
}
+
+ // This causes on exited to be called twice:
+ //try
+ //{
+ // // Dispose the process
+ // process.Dispose();
+ //}
+ //catch (Exception ex)
+ //{
+ // Logger.ErrorException("Error disposing ffmpeg.", ex);
+ //}
}
protected double? GetFramerateParam(StreamState state)
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 5de0709fd..39163a103 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -83,7 +83,7 @@ namespace MediaBrowser.Api.Playback.Hls
{
var cancellationTokenSource = new CancellationTokenSource();
- var state = GetState(request, cancellationTokenSource.Token).Result;
+ var state = await GetState(request, cancellationTokenSource.Token).ConfigureAwait(false);
var playlist = state.OutputFilePath;
@@ -154,7 +154,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// System.Int32.
protected int GetSegmentWait()
{
- var minimumSegmentCount = 3;
+ var minimumSegmentCount = 2;
var quality = GetQualitySetting();
if (quality == EncodingQuality.HighSpeed || quality == EncodingQuality.HighQuality)
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 13e858aa5..bb547bbff 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -1,13 +1,10 @@
using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.IO;
using ServiceStack;
using System;
@@ -17,7 +14,6 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using MimeTypes = ServiceStack.MimeTypes;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -83,29 +79,75 @@ namespace MediaBrowser.Api.Playback.Hls
return GetDynamicSegment(request, true).Result;
}
+ private static readonly SemaphoreSlim FfmpegStartLock = new SemaphoreSlim(1, 1);
private async Task