Merge pull request #2180 from MediaBrowser/dev

update timeshifting
This commit is contained in:
Luke 2016-09-18 16:39:35 -04:00 committed by GitHub
commit 4ea1cd5d12
13 changed files with 88 additions and 48 deletions

View File

@ -15,6 +15,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommonIO; using CommonIO;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api namespace MediaBrowser.Api
{ {
@ -187,7 +188,8 @@ namespace MediaBrowser.Api
CancellationTokenSource = cancellationTokenSource, CancellationTokenSource = cancellationTokenSource,
Id = transcodingJobId, Id = transcodingJobId,
PlaySessionId = playSessionId, PlaySessionId = playSessionId,
LiveStreamId = liveStreamId LiveStreamId = liveStreamId,
MediaSource = state.MediaSource
}; };
_activeTranscodingJobs.Add(job); _activeTranscodingJobs.Add(job);
@ -281,6 +283,14 @@ namespace MediaBrowser.Api
} }
} }
public TranscodingJob GetTranscodingJob(string playSessionId)
{
lock (_activeTranscodingJobs)
{
return _activeTranscodingJobs.FirstOrDefault(j => string.Equals(j.PlaySessionId, playSessionId, StringComparison.OrdinalIgnoreCase));
}
}
/// <summary> /// <summary>
/// Called when [transcode begin request]. /// Called when [transcode begin request].
/// </summary> /// </summary>
@ -656,6 +666,7 @@ namespace MediaBrowser.Api
/// Gets or sets the path. /// Gets or sets the path.
/// </summary> /// </summary>
/// <value>The path.</value> /// <value>The path.</value>
public MediaSourceInfo MediaSource { get; set; }
public string Path { get; set; } public string Path { get; set; }
/// <summary> /// <summary>
/// Gets or sets the type. /// Gets or sets the type.

View File

@ -1847,8 +1847,19 @@ namespace MediaBrowser.Api.Playback
var archivable = item as IArchivable; var archivable = item as IArchivable;
state.IsInputArchive = archivable != null && archivable.IsArchive; state.IsInputArchive = archivable != null && archivable.IsArchive;
MediaSourceInfo mediaSource; MediaSourceInfo mediaSource = null;
if (string.IsNullOrWhiteSpace(request.LiveStreamId)) if (string.IsNullOrWhiteSpace(request.LiveStreamId))
{
//TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ?
// ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId)
// : null;
//if (currentJob != null)
//{
// mediaSource = currentJob.MediaSource;
//}
if (mediaSource == null)
{ {
var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList(); var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList();
@ -1861,6 +1872,7 @@ namespace MediaBrowser.Api.Playback
mediaSource = mediaSources.First(); mediaSource = mediaSources.First();
} }
} }
}
else else
{ {
mediaSource = await MediaSourceManager.GetLiveStream(request.LiveStreamId, cancellationToken).ConfigureAwait(false); mediaSource = await MediaSourceManager.GetLiveStream(request.LiveStreamId, cancellationToken).ConfigureAwait(false);

View File

@ -104,7 +104,7 @@ namespace MediaBrowser.Api.Playback.Hls
throw; throw;
} }
var waitForSegments = state.SegmentLength >= 10 ? 2 : 3; var waitForSegments = state.SegmentLength >= 10 ? 2 : (state.SegmentLength > 3 || !isLive ? 3 : 4);
await WaitForMinimumSegmentCount(playlist, waitForSegments, cancellationTokenSource.Token).ConfigureAwait(false); await WaitForMinimumSegmentCount(playlist, waitForSegments, cancellationTokenSource.Token).ConfigureAwait(false);
} }
} }
@ -128,10 +128,9 @@ namespace MediaBrowser.Api.Playback.Hls
var audioBitrate = state.OutputAudioBitrate ?? 0; var audioBitrate = state.OutputAudioBitrate ?? 0;
var videoBitrate = state.OutputVideoBitrate ?? 0; var videoBitrate = state.OutputVideoBitrate ?? 0;
var appendBaselineStream = false;
var baselineStreamBitrate = 64000; var baselineStreamBitrate = 64000;
var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, appendBaselineStream, baselineStreamBitrate); var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, baselineStreamBitrate);
job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType); job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
@ -161,7 +160,7 @@ namespace MediaBrowser.Api.Playback.Hls
} }
} }
private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, bool includeBaselineStream, int baselineStreamBitrate) private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, int baselineStreamBitrate)
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
@ -175,14 +174,6 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "/stream.m3u8"); var playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "/stream.m3u8");
builder.AppendLine(playlistUrl); builder.AppendLine(playlistUrl);
// Low bitrate stream
if (includeBaselineStream)
{
builder.AppendLine("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + baselineStreamBitrate.ToString(UsCulture));
playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "-low/stream.m3u8");
builder.AppendLine(playlistUrl);
}
return builder.ToString(); return builder.ToString();
} }

View File

@ -68,8 +68,6 @@ namespace MediaBrowser.Api.Playback.Hls
[Api(Description = "Gets an Http live streaming segment file. Internal use only.")] [Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
public class GetHlsVideoSegmentLegacy : VideoStreamRequest public class GetHlsVideoSegmentLegacy : VideoStreamRequest
{ {
// TODO: Deprecate with new iOS app
public string PlaylistId { get; set; } public string PlaylistId { get; set; }
/// <summary> /// <summary>
@ -113,7 +111,7 @@ namespace MediaBrowser.Api.Playback.Hls
var file = request.SegmentId + Path.GetExtension(Request.PathInfo); var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, file); file = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, file);
var normalizedPlaylistId = request.PlaylistId.Replace("-low", string.Empty); var normalizedPlaylistId = request.PlaylistId;
var playlistPath = Directory.EnumerateFiles(_config.ApplicationPaths.TranscodingTempPath, "*") var playlistPath = Directory.EnumerateFiles(_config.ApplicationPaths.TranscodingTempPath, "*")
.FirstOrDefault(i => string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1); .FirstOrDefault(i => string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1);

View File

@ -88,6 +88,10 @@ namespace MediaBrowser.Api.Playback
return 10; return 10;
} }
if (!RunTimeTicks.HasValue)
{
return 10;
}
return 6; return 6;
} }

View File

@ -148,7 +148,7 @@ namespace MediaBrowser.Api.Subtitles
{ {
var item = (Video)_libraryManager.GetItemById(new Guid(request.Id)); var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));
var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, false).ConfigureAwait(false); var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, null, false, CancellationToken.None).ConfigureAwait(false);
var builder = new StringBuilder(); var builder = new StringBuilder();

View File

@ -60,11 +60,8 @@ namespace MediaBrowser.Controller.Library
/// <summary> /// <summary>
/// Gets the static media source. /// Gets the static media source.
/// </summary> /// </summary>
/// <param name="item">The item.</param>
/// <param name="mediaSourceId">The media source identifier.</param>
/// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
/// <returns>MediaSourceInfo.</returns> /// <returns>MediaSourceInfo.</returns>
Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution); Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Opens the media source. /// Opens the media source.

View File

@ -827,6 +827,7 @@ namespace MediaBrowser.Dlna.PlayTo
public string DeviceId { get; set; } public string DeviceId { get; set; }
public string MediaSourceId { get; set; } public string MediaSourceId { get; set; }
public string LiveStreamId { get; set; }
public BaseItem Item { get; set; } public BaseItem Item { get; set; }
public MediaSourceInfo MediaSource { get; set; } public MediaSourceInfo MediaSource { get; set; }
@ -910,6 +911,10 @@ namespace MediaBrowser.Dlna.PlayTo
{ {
request.StartPositionTicks = long.Parse(val, CultureInfo.InvariantCulture); request.StartPositionTicks = long.Parse(val, CultureInfo.InvariantCulture);
} }
else if (i == 22)
{
request.LiveStreamId = val;
}
} }
request.Item = string.IsNullOrWhiteSpace(request.ItemId) request.Item = string.IsNullOrWhiteSpace(request.ItemId)
@ -920,7 +925,7 @@ namespace MediaBrowser.Dlna.PlayTo
request.MediaSource = hasMediaSources == null request.MediaSource = hasMediaSources == null
? null ? null
: (await mediaSourceManager.GetMediaSource(hasMediaSources, request.MediaSourceId, false).ConfigureAwait(false)); : (await mediaSourceManager.GetMediaSource(hasMediaSources, request.MediaSourceId, request.LiveStreamId, false, CancellationToken.None).ConfigureAwait(false));
return request; return request;
} }

View File

@ -221,8 +221,28 @@ namespace MediaBrowser.Server.Implementations.Library
} }
} }
public async Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution) public async Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken)
{ {
if (!string.IsNullOrWhiteSpace(liveStreamId))
{
return await GetLiveStream(liveStreamId, cancellationToken).ConfigureAwait(false);
}
//await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
//try
//{
// var stream = _openStreams.Values.FirstOrDefault(i => string.Equals(i.MediaSource.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
// if (stream != null)
// {
// return stream.MediaSource;
// }
//}
//finally
//{
// _liveStreamSemaphore.Release();
//}
var sources = await GetPlayackMediaSources(item.Id.ToString("N"), null, enablePathSubstitution, new[] { MediaType.Audio, MediaType.Video }, var sources = await GetPlayackMediaSources(item.Id.ToString("N"), null, enablePathSubstitution, new[] { MediaType.Audio, MediaType.Video },
CancellationToken.None).ConfigureAwait(false); CancellationToken.None).ConfigureAwait(false);

View File

@ -763,7 +763,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
throw new ApplicationException("Tuner not found."); throw new ApplicationException("Tuner not found.");
} }
private async Task<Tuple<MediaSourceInfo, ITunerHost, SemaphoreSlim>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) private async Task<Tuple<MediaSourceInfo, ITunerHost, SemaphoreSlim>> GetChannelStreamInternal(string channelId, CancellationToken cancellationToken)
{ {
_logger.Info("Streaming Channel " + channelId); _logger.Info("Streaming Channel " + channelId);
@ -771,7 +771,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{ {
try try
{ {
var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false); var result = await hostInstance.GetChannelStream(channelId, null, cancellationToken).ConfigureAwait(false);
return new Tuple<MediaSourceInfo, ITunerHost, SemaphoreSlim>(result.Item1, hostInstance, result.Item2); return new Tuple<MediaSourceInfo, ITunerHost, SemaphoreSlim>(result.Item1, hostInstance, result.Item2);
} }
@ -994,7 +994,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try try
{ {
var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None).ConfigureAwait(false); var result = await GetChannelStreamInternal(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
isResourceOpen = true; isResourceOpen = true;
semaphore = result.Item3; semaphore = result.Item3;
var mediaStreamInfo = result.Item1; var mediaStreamInfo = result.Item1;

View File

@ -223,8 +223,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
} }
} }
var stream = var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
if (EnableMediaProbing) if (EnableMediaProbing)
{ {

View File

@ -319,18 +319,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
videoBitrate = 1000000; videoBitrate = 1000000;
} }
if (string.IsNullOrWhiteSpace(videoCodec))
{
var channels = await GetChannels(info, true, CancellationToken.None).ConfigureAwait(false); var channels = await GetChannels(info, true, CancellationToken.None).ConfigureAwait(false);
var channel = channels.FirstOrDefault(i => string.Equals(i.Number, channelId, StringComparison.OrdinalIgnoreCase)); var channel = channels.FirstOrDefault(i => string.Equals(i.Number, channelId, StringComparison.OrdinalIgnoreCase));
if (channel != null) if (channel != null)
{
if (string.IsNullOrWhiteSpace(videoCodec))
{ {
videoCodec = channel.VideoCodec; videoCodec = channel.VideoCodec;
}
audioCodec = channel.AudioCodec; audioCodec = channel.AudioCodec;
if (!videoBitrate.HasValue)
{
videoBitrate = (channel.IsHD ?? true) ? 15000000 : 2000000; videoBitrate = (channel.IsHD ?? true) ? 15000000 : 2000000;
audioBitrate = (channel.IsHD ?? true) ? 448000 : 192000;
} }
audioBitrate = (channel.IsHD ?? true) ? 448000 : 192000;
} }
// normalize // normalize
@ -380,7 +383,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
BitRate = audioBitrate BitRate = audioBitrate
} }
}, },
RequiresOpening = false, RequiresOpening = true,
RequiresClosing = false, RequiresClosing = false,
BufferMs = 0, BufferMs = 0,
Container = "ts", Container = "ts",

View File

@ -307,9 +307,9 @@ namespace MediaBrowser.Server.Implementations.Session
} }
} }
private Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId) private Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId)
{ {
return _mediaSourceManager.GetMediaSource(item, mediaSourceId, false); return _mediaSourceManager.GetMediaSource(item, mediaSourceId, liveStreamId, false, CancellationToken.None);
} }
/// <summary> /// <summary>
@ -337,7 +337,7 @@ namespace MediaBrowser.Server.Implementations.Session
var hasMediaSources = libraryItem as IHasMediaSources; var hasMediaSources = libraryItem as IHasMediaSources;
if (hasMediaSources != null) if (hasMediaSources != null)
{ {
mediaSource = await GetMediaSource(hasMediaSources, info.MediaSourceId).ConfigureAwait(false); mediaSource = await GetMediaSource(hasMediaSources, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false);
if (mediaSource != null) if (mediaSource != null)
{ {
@ -792,7 +792,7 @@ namespace MediaBrowser.Server.Implementations.Session
var hasMediaSources = libraryItem as IHasMediaSources; var hasMediaSources = libraryItem as IHasMediaSources;
if (hasMediaSources != null) if (hasMediaSources != null)
{ {
mediaSource = await GetMediaSource(hasMediaSources, info.MediaSourceId).ConfigureAwait(false); mediaSource = await GetMediaSource(hasMediaSources, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false);
} }
info.Item = GetItemInfo(libraryItem, libraryItem, mediaSource); info.Item = GetItemInfo(libraryItem, libraryItem, mediaSource);