aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api/Playback
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Api/Playback')
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs63
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs42
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs13
3 files changed, 64 insertions, 54 deletions
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 57c2244c7a..fa78fa0205 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -59,10 +59,11 @@ namespace MediaBrowser.Api.Playback.Hls
/// Processes the request.
/// </summary>
/// <param name="request">The request.</param>
+ /// <param name="isLive">if set to <c>true</c> [is live].</param>
/// <returns>System.Object.</returns>
- protected object ProcessRequest(StreamRequest request)
+ protected object ProcessRequest(StreamRequest request, bool isLive)
{
- return ProcessRequestAsync(request).Result;
+ return ProcessRequestAsync(request, isLive).Result;
}
private static readonly SemaphoreSlim FfmpegStartLock = new SemaphoreSlim(1, 1);
@@ -70,13 +71,12 @@ namespace MediaBrowser.Api.Playback.Hls
/// Processes the request async.
/// </summary>
/// <param name="request">The request.</param>
+ /// <param name="isLive">if set to <c>true</c> [is live].</param>
/// <returns>Task{System.Object}.</returns>
- /// <exception cref="ArgumentException">
- /// A video bitrate is required
+ /// <exception cref="ArgumentException">A video bitrate is required
/// or
- /// An audio bitrate is required
- /// </exception>
- private async Task<object> ProcessRequestAsync(StreamRequest request)
+ /// An audio bitrate is required</exception>
+ private async Task<object> ProcessRequestAsync(StreamRequest request, bool isLive)
{
var cancellationTokenSource = new CancellationTokenSource();
@@ -110,7 +110,8 @@ namespace MediaBrowser.Api.Playback.Hls
throw;
}
- await WaitForMinimumSegmentCount(playlist, GetSegmentWait(), cancellationTokenSource.Token).ConfigureAwait(false);
+ var waitCount = isLive ? 1 : GetSegmentWait();
+ await WaitForMinimumSegmentCount(playlist, waitCount, cancellationTokenSource.Token).ConfigureAwait(false);
}
}
finally
@@ -119,6 +120,22 @@ namespace MediaBrowser.Api.Playback.Hls
}
}
+ if (isLive)
+ {
+ //var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
+
+ //file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, file);
+
+ try
+ {
+ return ResultFactory.GetStaticFileResult(Request, playlist, FileShare.ReadWrite);
+ }
+ finally
+ {
+ ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
+ }
+ }
+
var audioBitrate = state.OutputAudioBitrate ?? 0;
var videoBitrate = state.OutputVideoBitrate ?? 0;
@@ -188,16 +205,18 @@ namespace MediaBrowser.Api.Playback.Hls
protected async Task WaitForMinimumSegmentCount(string playlist, int segmentCount, CancellationToken cancellationToken)
{
- var count = 0;
+ Logger.Debug("Waiting for {0} segments in {1}", segmentCount, playlist);
- // Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written
- using (var fileStream = FileSystem.GetFileStream(playlist, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
+ while (true)
{
- using (var reader = new StreamReader(fileStream))
+ // Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written
+ using (var fileStream = FileSystem.GetFileStream(playlist, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
{
- while (true)
+ using (var reader = new StreamReader(fileStream))
{
- if (!reader.EndOfStream)
+ var count = 0;
+
+ while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync().ConfigureAwait(false);
@@ -206,11 +225,12 @@ namespace MediaBrowser.Api.Playback.Hls
count++;
if (count >= segmentCount)
{
+ Logger.Debug("Finished waiting for {0} segments in {1}", segmentCount, playlist);
return;
}
}
}
- await Task.Delay(25, cancellationToken).ConfigureAwait(false);
+ await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
}
}
@@ -229,7 +249,7 @@ namespace MediaBrowser.Api.Playback.Hls
var itsOffsetMs = hlsVideoRequest == null
? 0
- : ((GetHlsVideoStream)state.VideoRequest).TimeStampOffsetMs;
+ : hlsVideoRequest.TimeStampOffsetMs;
var itsOffset = itsOffsetMs == 0 ? string.Empty : string.Format("-itsoffset {0} ", TimeSpan.FromMilliseconds(itsOffsetMs).TotalSeconds.ToString(UsCulture));
@@ -240,7 +260,15 @@ namespace MediaBrowser.Api.Playback.Hls
// If isEncoding is true we're actually starting ffmpeg
var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0";
- var args = string.Format("{0} {1} -i {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9} -y \"{10}\"",
+ var baseUrlParam = string.Empty;
+
+ if (state.Request is GetLiveHlsStream)
+ {
+ baseUrlParam = string.Format(" -hls_base_url \"{0}/\"",
+ "hls/" + Path.GetFileNameWithoutExtension(outputPath));
+ }
+
+ var args = string.Format("{0} {1} -i {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
itsOffset,
inputModifier,
GetInputArgument(state),
@@ -251,6 +279,7 @@ namespace MediaBrowser.Api.Playback.Hls
state.SegmentLength.ToString(UsCulture),
startNumberParam,
state.HlsListSize.ToString(UsCulture),
+ baseUrlParam,
outputPath
).Trim();
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index bde2c56943..5bb6106860 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -22,11 +22,6 @@ namespace MediaBrowser.Api.Playback.Hls
[Api(Description = "Gets a video stream using HTTP live streaming.")]
public class GetMasterHlsVideoStream : VideoStreamRequest
{
- [ApiMember(Name = "BaselineStreamAudioBitRate", Description = "Optional. Specify the audio bitrate for the baseline stream.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int? BaselineStreamAudioBitRate { get; set; }
-
- [ApiMember(Name = "AppendBaselineStream", Description = "Optional. Whether or not to include a baseline audio-only stream in the master playlist.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool AppendBaselineStream { get; set; }
}
[Route("/Videos/{Id}/main.m3u8", "GET")]
@@ -35,12 +30,6 @@ namespace MediaBrowser.Api.Playback.Hls
{
}
- [Route("/Videos/{Id}/baseline.m3u8", "GET")]
- [Api(Description = "Gets a video stream using HTTP live streaming.")]
- public class GetBaselineHlsVideoStream : VideoStreamRequest
- {
- }
-
/// <summary>
/// Class GetHlsVideoSegment
/// </summary>
@@ -73,16 +62,11 @@ namespace MediaBrowser.Api.Playback.Hls
public object Get(GetDynamicHlsVideoSegment request)
{
- if (string.Equals("baseline", request.PlaylistId, StringComparison.OrdinalIgnoreCase))
- {
- return GetDynamicSegment(request, false).Result;
- }
-
- return GetDynamicSegment(request, true).Result;
+ return GetDynamicSegment(request).Result;
}
private static readonly SemaphoreSlim FfmpegStartLock = new SemaphoreSlim(1, 1);
- private async Task<object> GetDynamicSegment(GetDynamicHlsVideoSegment request, bool isMain)
+ private async Task<object> GetDynamicSegment(GetDynamicHlsVideoSegment request)
{
if ((request.StartTimeTicks ?? 0) > 0)
{
@@ -322,7 +306,9 @@ namespace MediaBrowser.Api.Playback.Hls
var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);
// Main stream
- var playlistUrl = "main.m3u8" + queryString;
+ var playlistUrl = (state.RunTimeTicks ?? 0) > 0 ? "main.m3u8" : "live.m3u8";
+ playlistUrl += queryString;
+
AppendPlaylist(builder, playlistUrl, totalBitrate);
if (state.VideoRequest.VideoBitRate.HasValue)
@@ -385,13 +371,6 @@ namespace MediaBrowser.Api.Playback.Hls
return result;
}
- public object Get(GetBaselineHlsVideoStream request)
- {
- var result = GetPlaylistAsync(request, "baseline").Result;
-
- return result;
- }
-
private async Task<object> GetPlaylistAsync(VideoStreamRequest request, string name)
{
var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
@@ -506,14 +485,6 @@ namespace MediaBrowser.Api.Playback.Hls
/// <returns>System.String.</returns>
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
{
- var hlsVideoRequest = state.VideoRequest as GetHlsVideoStream;
-
- var itsOffsetMs = hlsVideoRequest == null
- ? 0
- : ((GetHlsVideoStream)state.VideoRequest).TimeStampOffsetMs;
-
- var itsOffset = itsOffsetMs == 0 ? string.Empty : string.Format("-itsoffset {0} ", TimeSpan.FromMilliseconds(itsOffsetMs).TotalSeconds.ToString(UsCulture));
-
var threads = GetNumberOfThreads(state, false);
var inputModifier = GetInputModifier(state);
@@ -521,8 +492,7 @@ namespace MediaBrowser.Api.Playback.Hls
// If isEncoding is true we're actually starting ffmpeg
var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0";
- var args = string.Format("{0} {1} -i {2} -map_metadata -1 -threads {3} {4} {5} -flags -global_header {6} -hls_time {7} -start_number {8} -hls_list_size {9} -y \"{10}\"",
- itsOffset,
+ var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
inputModifier,
GetInputArgument(state),
threads,
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index 1a925378bb..28c0219fce 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -32,6 +32,12 @@ namespace MediaBrowser.Api.Playback.Hls
public int TimeStampOffsetMs { get; set; }
}
+ [Route("/Videos/{Id}/live.m3u8", "GET")]
+ [Api(Description = "Gets a video stream using HTTP live streaming.")]
+ public class GetLiveHlsStream : VideoStreamRequest
+ {
+ }
+
/// <summary>
/// Class GetHlsVideoSegment
/// </summary>
@@ -105,7 +111,12 @@ namespace MediaBrowser.Api.Playback.Hls
/// <returns>System.Object.</returns>
public object Get(GetHlsVideoStream request)
{
- return ProcessRequest(request);
+ return ProcessRequest(request, false);
+ }
+
+ public object Get(GetLiveHlsStream request)
+ {
+ return ProcessRequest(request, true);
}
/// <summary>