commit
4ea1cd5d12
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -88,6 +88,10 @@ namespace MediaBrowser.Api.Playback
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!RunTimeTicks.HasValue)
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user