aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs')
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs73
1 files changed, 64 insertions, 9 deletions
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 10543351b9..53cc41501e 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -5,6 +5,8 @@ using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using ServiceStack;
using System;
@@ -18,20 +20,20 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api.Playback.Hls
{
- [Route("/Videos/{Id}/master.m3u8", "GET")]
- [Api(Description = "Gets a video stream using HTTP live streaming.")]
+ [Route("/Videos/{Id}/master.m3u8", "GET", Summary = "Gets a video stream using HTTP live streaming.")]
public class GetMasterHlsVideoStream : VideoStreamRequest
{
public bool EnableAdaptiveBitrateStreaming { get; set; }
+ public SubtitleDeliveryMethod SubtitleMethod { get; set; }
+
public GetMasterHlsVideoStream()
{
EnableAdaptiveBitrateStreaming = true;
}
}
- [Route("/Videos/{Id}/main.m3u8", "GET")]
- [Api(Description = "Gets a video stream using HTTP live streaming.")]
+ [Route("/Videos/{Id}/main.m3u8", "GET", Summary = "Gets a video stream using HTTP live streaming.")]
public class GetMainHlsVideoStream : VideoStreamRequest
{
}
@@ -359,7 +361,17 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistUrl = (state.RunTimeTicks ?? 0) > 0 ? "main.m3u8" : "live.m3u8";
playlistUrl += queryString;
- AppendPlaylist(builder, playlistUrl, totalBitrate);
+ var request = (GetMasterHlsVideoStream) state.Request;
+
+ var subtitleStreams = state.AllMediaStreams
+ .Where(i => i.IsTextSubtitleStream)
+ .ToList();
+
+ var subtitleGroup = subtitleStreams.Count > 0 && request.SubtitleMethod == SubtitleDeliveryMethod.Hls ?
+ "subs" :
+ null;
+
+ AppendPlaylist(builder, playlistUrl, totalBitrate, subtitleGroup);
if (EnableAdaptiveBitrateStreaming(state))
{
@@ -369,16 +381,52 @@ namespace MediaBrowser.Api.Playback.Hls
var variation = GetBitrateVariation(totalBitrate);
var newBitrate = totalBitrate - variation;
- AppendPlaylist(builder, playlistUrl.Replace(requestedVideoBitrate.ToString(UsCulture), (requestedVideoBitrate - variation).ToString(UsCulture)), newBitrate);
+ AppendPlaylist(builder, playlistUrl.Replace(requestedVideoBitrate.ToString(UsCulture), (requestedVideoBitrate - variation).ToString(UsCulture)), newBitrate, subtitleGroup);
variation *= 2;
newBitrate = totalBitrate - variation;
- AppendPlaylist(builder, playlistUrl.Replace(requestedVideoBitrate.ToString(UsCulture), (requestedVideoBitrate - variation).ToString(UsCulture)), newBitrate);
+ AppendPlaylist(builder, playlistUrl.Replace(requestedVideoBitrate.ToString(UsCulture), (requestedVideoBitrate - variation).ToString(UsCulture)), newBitrate, subtitleGroup);
+ }
+
+ if (!string.IsNullOrWhiteSpace(subtitleGroup))
+ {
+ AddSubtitles(state, subtitleStreams, builder);
}
return builder.ToString();
}
+ private void AddSubtitles(StreamState state, IEnumerable<MediaStream> subtitles, StringBuilder builder)
+ {
+ var selectedIndex = state.SubtitleStream == null ? (int?)null : state.SubtitleStream.Index;
+
+ foreach (var stream in subtitles)
+ {
+ const string format = "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"{0}\",DEFAULT={1},FORCED={2},URI=\"{3}\",LANGUAGE=\"{4}\"";
+
+ var name = stream.Language;
+
+ var isDefault = selectedIndex.HasValue && selectedIndex.Value == stream.Index;
+ var isForced = stream.IsForced;
+
+ if (string.IsNullOrWhiteSpace(name)) name = stream.Codec ?? "Unknown";
+
+ var url = string.Format("{0}/Subtitles/{1}/subtitles.m3u8?SegmentLength={2}",
+ state.Request.MediaSourceId,
+ stream.Index.ToString(UsCulture),
+ 30.ToString(UsCulture));
+
+ var line = string.Format(format,
+ name,
+ isDefault ? "YES" : "NO",
+ isForced ? "YES" : "NO",
+ url,
+ stream.Language ?? "Unknown");
+
+ builder.AppendLine(line);
+ }
+ }
+
private bool EnableAdaptiveBitrateStreaming(StreamState state)
{
var request = state.Request as GetMasterHlsVideoStream;
@@ -397,9 +445,16 @@ namespace MediaBrowser.Api.Playback.Hls
return state.VideoRequest.VideoBitRate.HasValue;
}
- private void AppendPlaylist(StringBuilder builder, string url, int bitrate)
+ private void AppendPlaylist(StringBuilder builder, string url, int bitrate, string subtitleGroup)
{
- builder.AppendLine("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + bitrate.ToString(UsCulture));
+ var header = "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + bitrate.ToString(UsCulture);
+
+ if (!string.IsNullOrWhiteSpace(subtitleGroup))
+ {
+ header += string.Format(",SUBTITLES=\"{0}\"", subtitleGroup);
+ }
+
+ builder.AppendLine(header);
builder.AppendLine(url);
}