aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api/Playback/BaseStreamingService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Api/Playback/BaseStreamingService.cs')
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs124
1 files changed, 88 insertions, 36 deletions
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index a9aaab00c..612f73191 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1,5 +1,4 @@
-using System.Text;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
@@ -22,6 +21,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -937,8 +937,6 @@ namespace MediaBrowser.Api.Playback
ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType);
- state.LogFileStream.Dispose();
-
throw;
}
@@ -1096,23 +1094,12 @@ namespace MediaBrowser.Api.Playback
/// </summary>
/// <param name="process">The process.</param>
/// <param name="state">The state.</param>
- protected async void OnFfMpegProcessExited(Process process, StreamState state)
+ protected void OnFfMpegProcessExited(Process process, StreamState state)
{
- if (state.IsoMount != null)
- {
- state.IsoMount.Dispose();
- state.IsoMount = null;
- }
-
- if (state.StandardInputCancellationTokenSource != null)
- {
- state.StandardInputCancellationTokenSource.Cancel();
- }
+ state.Dispose();
var outputFilePath = GetOutputFilePath(state);
- state.LogFileStream.Dispose();
-
try
{
Logger.Info("FFMpeg exited with code {0} for {1}", process.ExitCode, outputFilePath);
@@ -1121,18 +1108,6 @@ namespace MediaBrowser.Api.Playback
{
Logger.Info("FFMpeg exited with an error for {0}", outputFilePath);
}
-
- if (!string.IsNullOrEmpty(state.LiveTvStreamId))
- {
- try
- {
- await LiveTvManager.CloseLiveStream(state.LiveTvStreamId, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error closing live tv stream", ex);
- }
- }
}
protected double? GetFramerateParam(StreamState state)
@@ -1357,7 +1332,7 @@ namespace MediaBrowser.Api.Playback
request.AudioCodec = InferAudioCodec(url);
}
- var state = new StreamState
+ var state = new StreamState(LiveTvManager, Logger)
{
Request = request,
RequestedUrl = url
@@ -1393,7 +1368,7 @@ namespace MediaBrowser.Api.Playback
mediaUrl = streamInfo.Url;
}
- if (!string.IsNullOrEmpty(path) && File.Exists(path))
+ if (!string.IsNullOrEmpty(path))
{
state.MediaPath = path;
state.IsRemote = false;
@@ -1406,7 +1381,7 @@ namespace MediaBrowser.Api.Playback
state.RunTimeTicks = recording.RunTimeTicks;
- if (recording.RecordingInfo.Status == RecordingStatus.InProgress && !state.IsRemote)
+ if (recording.RecordingInfo.Status == RecordingStatus.InProgress)
{
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
}
@@ -1429,7 +1404,7 @@ namespace MediaBrowser.Api.Playback
state.LiveTvStreamId = streamInfo.Id;
- if (!string.IsNullOrEmpty(streamInfo.Path) && File.Exists(streamInfo.Path))
+ if (!string.IsNullOrEmpty(streamInfo.Path))
{
state.MediaPath = streamInfo.Path;
state.IsRemote = false;
@@ -1515,6 +1490,14 @@ namespace MediaBrowser.Api.Playback
}
}
+ if (state.AudioStream != null)
+ {
+ //if (CanStreamCopyAudio(request, state.AudioStream))
+ //{
+ // request.AudioCodec = "copy";
+ //}
+ }
+
return state;
}
@@ -1538,7 +1521,7 @@ namespace MediaBrowser.Api.Playback
}
// If client is requesting a specific video profile, it must match the source
- if (!string.IsNullOrEmpty(request.Profile) && !string.Equals(request.Profile, videoStream.Profile))
+ if (!string.IsNullOrEmpty(request.Profile) && !string.Equals(request.Profile, videoStream.Profile, StringComparison.OrdinalIgnoreCase))
{
return false;
}
@@ -1599,12 +1582,50 @@ namespace MediaBrowser.Api.Playback
return false;
}
}
- return false;
}
return SupportsAutomaticVideoStreamCopy;
}
+ private bool CanStreamCopyAudio(StreamRequest request, MediaStream audioStream)
+ {
+ // Source and target codecs must match
+ if (string.IsNullOrEmpty(request.AudioCodec) || !string.Equals(request.AudioCodec, audioStream.Codec, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ // Video bitrate must fall within requested value
+ if (request.AudioBitRate.HasValue)
+ {
+ if (!audioStream.BitRate.HasValue || audioStream.BitRate.Value > request.AudioBitRate.Value)
+ {
+ return false;
+ }
+ }
+
+ // Channels must fall within requested value
+ var channels = request.AudioChannels ?? request.MaxAudioChannels;
+ if (channels.HasValue)
+ {
+ if (!audioStream.Channels.HasValue || audioStream.Channels.Value > channels.Value)
+ {
+ return false;
+ }
+ }
+
+ // Sample rate must fall within requested value
+ if (request.AudioSampleRate.HasValue)
+ {
+ if (!audioStream.SampleRate.HasValue || audioStream.SampleRate.Value > request.AudioSampleRate.Value)
+ {
+ return false;
+ }
+ }
+
+ return SupportsAutomaticVideoStreamCopy;
+ }
+
protected virtual bool SupportsAutomaticVideoStreamCopy
{
get
@@ -1722,7 +1743,21 @@ namespace MediaBrowser.Api.Playback
// 0 = native, 1 = transcoded
var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
- const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
+ var flagValue = DlnaFlags.DLNA_ORG_FLAG_STREAMING_TRANSFER_MODE |
+ DlnaFlags.DLNA_ORG_FLAG_BACKGROUND_TRANSFERT_MODE |
+ DlnaFlags.DLNA_ORG_FLAG_DLNA_V15;
+
+ if (isStaticallyStreamed)
+ {
+ //flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_BYTE_BASED_SEEK;
+ }
+ else if (state.RunTimeTicks.HasValue)
+ {
+ //flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_TIME_BASED_SEEK;
+ }
+
+ var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000",
+ Enum.Format(typeof(DlnaFlags), flagValue, "x"));
if (!string.IsNullOrWhiteSpace(state.OrgPn))
{
@@ -1772,6 +1807,23 @@ namespace MediaBrowser.Api.Playback
}
}
+ [Flags]
+ private enum DlnaFlags
+ {
+ DLNA_ORG_FLAG_SENDER_PACED = (1 << 31),
+ DLNA_ORG_FLAG_TIME_BASED_SEEK = (1 << 30),
+ DLNA_ORG_FLAG_BYTE_BASED_SEEK = (1 << 29),
+ DLNA_ORG_FLAG_PLAY_CONTAINER = (1 << 28),
+ DLNA_ORG_FLAG_S0_INCREASE = (1 << 27),
+ DLNA_ORG_FLAG_SN_INCREASE = (1 << 26),
+ DLNA_ORG_FLAG_RTSP_PAUSE = (1 << 25),
+ DLNA_ORG_FLAG_STREAMING_TRANSFER_MODE = (1 << 24),
+ DLNA_ORG_FLAG_INTERACTIVE_TRANSFERT_MODE = (1 << 23),
+ DLNA_ORG_FLAG_BACKGROUND_TRANSFERT_MODE = (1 << 22),
+ DLNA_ORG_FLAG_CONNECTION_STALL = (1 << 21),
+ DLNA_ORG_FLAG_DLNA_V15 = (1 << 20),
+ };
+
private void AddTimeSeekResponseHeaders(StreamState state, IDictionary<string, string> responseHeaders)
{
var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds.ToString(UsCulture);