|
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Configuration;
|
|
using MediaBrowser.Controller.Dto;
|
|
using MediaBrowser.Controller.Dto;
|
|
using MediaBrowser.Controller.Entities;
|
|
using MediaBrowser.Controller.Entities;
|
|
using MediaBrowser.Controller.Library;
|
|
using MediaBrowser.Controller.Library;
|
|
|
|
+using MediaBrowser.Controller.LiveTv;
|
|
using MediaBrowser.Controller.MediaInfo;
|
|
using MediaBrowser.Controller.MediaInfo;
|
|
using MediaBrowser.Controller.Persistence;
|
|
using MediaBrowser.Controller.Persistence;
|
|
using MediaBrowser.Model.Configuration;
|
|
using MediaBrowser.Model.Configuration;
|
|
@@ -62,6 +63,7 @@ namespace MediaBrowser.Api.Playback
|
|
protected IFileSystem FileSystem { get; private set; }
|
|
protected IFileSystem FileSystem { get; private set; }
|
|
|
|
|
|
protected IItemRepository ItemRepository { get; private set; }
|
|
protected IItemRepository ItemRepository { get; private set; }
|
|
|
|
+ protected ILiveTvManager LiveTvManager { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
|
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
|
@@ -74,8 +76,9 @@ namespace MediaBrowser.Api.Playback
|
|
/// <param name="dtoService">The dto service.</param>
|
|
/// <param name="dtoService">The dto service.</param>
|
|
/// <param name="fileSystem">The file system.</param>
|
|
/// <param name="fileSystem">The file system.</param>
|
|
/// <param name="itemRepository">The item repository.</param>
|
|
/// <param name="itemRepository">The item repository.</param>
|
|
- protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository)
|
|
|
|
|
|
+ protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager)
|
|
{
|
|
{
|
|
|
|
+ LiveTvManager = liveTvManager;
|
|
ItemRepository = itemRepository;
|
|
ItemRepository = itemRepository;
|
|
FileSystem = fileSystem;
|
|
FileSystem = fileSystem;
|
|
DtoService = dtoService;
|
|
DtoService = dtoService;
|
|
@@ -194,6 +197,10 @@ namespace MediaBrowser.Api.Playback
|
|
{
|
|
{
|
|
args += string.Format("-map 0:{0}", state.VideoStream.Index);
|
|
args += string.Format("-map 0:{0}", state.VideoStream.Index);
|
|
}
|
|
}
|
|
|
|
+ else if (!state.HasMediaStreams)
|
|
|
|
+ {
|
|
|
|
+ args += string.Format("-map 0:{0}", 0);
|
|
|
|
+ }
|
|
else
|
|
else
|
|
{
|
|
{
|
|
args += "-map -0:v";
|
|
args += "-map -0:v";
|
|
@@ -203,6 +210,10 @@ namespace MediaBrowser.Api.Playback
|
|
{
|
|
{
|
|
args += string.Format(" -map 0:{0}", state.AudioStream.Index);
|
|
args += string.Format(" -map 0:{0}", state.AudioStream.Index);
|
|
}
|
|
}
|
|
|
|
+ else if (!state.HasMediaStreams)
|
|
|
|
+ {
|
|
|
|
+ args += string.Format(" -map 0:{0}", 1);
|
|
|
|
+ }
|
|
|
|
|
|
else
|
|
else
|
|
{
|
|
{
|
|
@@ -336,7 +347,10 @@ namespace MediaBrowser.Api.Playback
|
|
// If fixed dimensions were supplied
|
|
// If fixed dimensions were supplied
|
|
if (request.Width.HasValue && request.Height.HasValue)
|
|
if (request.Width.HasValue && request.Height.HasValue)
|
|
{
|
|
{
|
|
- return string.Format(" -vf \"scale=trunc({0}/2)*2:trunc({1}/2)*2{2}\"", request.Width.Value, request.Height.Value, assSubtitleParam);
|
|
|
|
|
|
+ var widthParam = request.Width.Value.ToString(UsCulture);
|
|
|
|
+ var heightParam = request.Height.Value.ToString(UsCulture);
|
|
|
|
+
|
|
|
|
+ return string.Format(" -vf \"scale=trunc({0}/2)*2:trunc({1}/2)*2{2}\"", widthParam, heightParam, assSubtitleParam);
|
|
}
|
|
}
|
|
|
|
|
|
var isH264Output = outputVideoCodec.Equals("libx264", StringComparison.OrdinalIgnoreCase);
|
|
var isH264Output = outputVideoCodec.Equals("libx264", StringComparison.OrdinalIgnoreCase);
|
|
@@ -344,33 +358,41 @@ namespace MediaBrowser.Api.Playback
|
|
// If a fixed width was requested
|
|
// If a fixed width was requested
|
|
if (request.Width.HasValue)
|
|
if (request.Width.HasValue)
|
|
{
|
|
{
|
|
|
|
+ var widthParam = request.Width.Value.ToString(UsCulture);
|
|
|
|
+
|
|
return isH264Output ?
|
|
return isH264Output ?
|
|
- string.Format(" -vf \"scale={0}:trunc(ow/a/2)*2{1}\"", request.Width.Value, assSubtitleParam) :
|
|
|
|
- string.Format(" -vf \"scale={0}:-1{1}\"", request.Width.Value, assSubtitleParam);
|
|
|
|
|
|
+ string.Format(" -vf \"scale={0}:trunc(ow/a/2)*2{1}\"", widthParam, assSubtitleParam) :
|
|
|
|
+ string.Format(" -vf \"scale={0}:-1{1}\"", widthParam, assSubtitleParam);
|
|
}
|
|
}
|
|
|
|
|
|
// If a fixed height was requested
|
|
// If a fixed height was requested
|
|
if (request.Height.HasValue)
|
|
if (request.Height.HasValue)
|
|
{
|
|
{
|
|
|
|
+ var heightParam = request.Height.Value.ToString(UsCulture);
|
|
|
|
+
|
|
return isH264Output ?
|
|
return isH264Output ?
|
|
- string.Format(" -vf \"scale=trunc(oh*a*2)/2:{0}{1}\"", request.Height.Value, assSubtitleParam) :
|
|
|
|
- string.Format(" -vf \"scale=-1:{0}{1}\"", request.Height.Value, assSubtitleParam);
|
|
|
|
|
|
+ string.Format(" -vf \"scale=trunc(oh*a*2)/2:{0}{1}\"", heightParam, assSubtitleParam) :
|
|
|
|
+ string.Format(" -vf \"scale=-1:{0}{1}\"", heightParam, assSubtitleParam);
|
|
}
|
|
}
|
|
|
|
|
|
// If a max width was requested
|
|
// If a max width was requested
|
|
if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
|
|
if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
|
|
{
|
|
{
|
|
|
|
+ var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
|
|
|
+
|
|
return isH264Output ?
|
|
return isH264Output ?
|
|
- string.Format(" -vf \"scale=min(iw\\,{0}):trunc(ow/a/2)*2{1}\"", request.MaxWidth.Value, assSubtitleParam) :
|
|
|
|
- string.Format(" -vf \"scale=min(iw\\,{0}):-1{1}\"", request.MaxWidth.Value, assSubtitleParam);
|
|
|
|
|
|
+ string.Format(" -vf \"scale=min(iw\\,{0}):trunc(ow/a/2)*2{1}\"", maxWidthParam, assSubtitleParam) :
|
|
|
|
+ string.Format(" -vf \"scale=min(iw\\,{0}):-1{1}\"", maxWidthParam, assSubtitleParam);
|
|
}
|
|
}
|
|
|
|
|
|
// If a max height was requested
|
|
// If a max height was requested
|
|
if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
|
|
if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
|
|
{
|
|
{
|
|
|
|
+ var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
|
|
|
+
|
|
return isH264Output ?
|
|
return isH264Output ?
|
|
- string.Format(" -vf \"scale=trunc(oh*a*2)/2:min(ih\\,{0}){1}\"", request.MaxHeight.Value, assSubtitleParam) :
|
|
|
|
- string.Format(" -vf \"scale=-1:min(ih\\,{0}){1}\"", request.MaxHeight.Value, assSubtitleParam);
|
|
|
|
|
|
+ string.Format(" -vf \"scale=trunc(oh*a*2)/2:min(ih\\,{0}){1}\"", maxHeightParam, assSubtitleParam) :
|
|
|
|
+ string.Format(" -vf \"scale=-1:min(ih\\,{0}){1}\"", maxHeightParam, assSubtitleParam);
|
|
}
|
|
}
|
|
|
|
|
|
if (state.VideoStream == null)
|
|
if (state.VideoStream == null)
|
|
@@ -390,7 +412,10 @@ namespace MediaBrowser.Api.Playback
|
|
// If we're encoding with libx264, it can't handle odd numbered widths or heights, so we'll have to fix that
|
|
// If we're encoding with libx264, it can't handle odd numbered widths or heights, so we'll have to fix that
|
|
if (isH264Output)
|
|
if (isH264Output)
|
|
{
|
|
{
|
|
- return string.Format(" -vf \"scale=trunc({0}/2)*2:trunc({1}/2)*2{2}\"", outputSize.Width, outputSize.Height, assSubtitleParam);
|
|
|
|
|
|
+ var widthParam = outputSize.Width.ToString(UsCulture);
|
|
|
|
+ var heightParam = outputSize.Height.ToString(UsCulture);
|
|
|
|
+
|
|
|
|
+ return string.Format(" -vf \"scale=trunc({0}/2)*2:trunc({1}/2)*2{2}\"", widthParam, heightParam, assSubtitleParam);
|
|
}
|
|
}
|
|
|
|
|
|
// Otherwise use -vf scale since ffmpeg will ensure internally that the aspect ratio is preserved
|
|
// Otherwise use -vf scale since ffmpeg will ensure internally that the aspect ratio is preserved
|
|
@@ -823,11 +848,10 @@ namespace MediaBrowser.Api.Playback
|
|
/// Gets the state.
|
|
/// Gets the state.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="request">The request.</param>
|
|
/// <param name="request">The request.</param>
|
|
|
|
+ /// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <returns>StreamState.</returns>
|
|
/// <returns>StreamState.</returns>
|
|
- protected StreamState GetState(StreamRequest request)
|
|
|
|
|
|
+ protected async Task<StreamState> GetState(StreamRequest request, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
- var item = DtoService.GetItemByDtoId(request.Id);
|
|
|
|
-
|
|
|
|
var url = Request.PathInfo;
|
|
var url = Request.PathInfo;
|
|
|
|
|
|
if (!request.AudioCodec.HasValue)
|
|
if (!request.AudioCodec.HasValue)
|
|
@@ -838,22 +862,48 @@ namespace MediaBrowser.Api.Playback
|
|
var state = new StreamState
|
|
var state = new StreamState
|
|
{
|
|
{
|
|
Request = request,
|
|
Request = request,
|
|
- RequestedUrl = url,
|
|
|
|
- MediaPath = item.Path,
|
|
|
|
- IsRemote = item.LocationType == LocationType.Remote
|
|
|
|
|
|
+ RequestedUrl = url
|
|
};
|
|
};
|
|
|
|
|
|
- var video = item as Video;
|
|
|
|
|
|
+ BaseItem item;
|
|
|
|
+
|
|
|
|
+ if (string.Equals(request.Type, "Recording", StringComparison.OrdinalIgnoreCase))
|
|
|
|
+ {
|
|
|
|
+ var recording = await LiveTvManager.GetInternalRecording(request.Id, cancellationToken).ConfigureAwait(false);
|
|
|
|
+
|
|
|
|
+ state.VideoType = VideoType.VideoFile;
|
|
|
|
+ state.IsInputVideo = string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
|
|
|
+ state.PlayableStreamFileNames = new List<string>();
|
|
|
|
+
|
|
|
|
+ if (!string.IsNullOrEmpty(recording.RecordingInfo.Path) && File.Exists(recording.RecordingInfo.Path))
|
|
|
|
+ {
|
|
|
|
+ state.MediaPath = recording.RecordingInfo.Path;
|
|
|
|
+ state.IsRemote = false;
|
|
|
|
+ }
|
|
|
|
+ else if (!string.IsNullOrEmpty(recording.RecordingInfo.Url))
|
|
|
|
+ {
|
|
|
|
+ state.MediaPath = recording.RecordingInfo.Url;
|
|
|
|
+ state.IsRemote = true;
|
|
|
|
+ }
|
|
|
|
|
|
- if (video != null)
|
|
|
|
|
|
+ item = recording;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
{
|
|
{
|
|
- state.IsInputVideo = true;
|
|
|
|
- state.VideoType = video.VideoType;
|
|
|
|
- state.IsoType = video.IsoType;
|
|
|
|
|
|
+ item = DtoService.GetItemByDtoId(request.Id);
|
|
|
|
|
|
- state.PlayableStreamFileNames = video.PlayableStreamFileNames == null
|
|
|
|
- ? new List<string>()
|
|
|
|
- : video.PlayableStreamFileNames.ToList();
|
|
|
|
|
|
+ var video = item as Video;
|
|
|
|
+
|
|
|
|
+ if (video != null)
|
|
|
|
+ {
|
|
|
|
+ state.IsInputVideo = true;
|
|
|
|
+ state.VideoType = video.VideoType;
|
|
|
|
+ state.IsoType = video.IsoType;
|
|
|
|
+
|
|
|
|
+ state.PlayableStreamFileNames = video.PlayableStreamFileNames == null
|
|
|
|
+ ? new List<string>()
|
|
|
|
+ : video.PlayableStreamFileNames.ToList();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
var videoRequest = request as VideoStreamRequest;
|
|
var videoRequest = request as VideoStreamRequest;
|
|
@@ -880,6 +930,8 @@ namespace MediaBrowser.Api.Playback
|
|
state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
|
|
state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ state.HasMediaStreams = mediaStreams.Count > 0;
|
|
|
|
+
|
|
return state;
|
|
return state;
|
|
}
|
|
}
|
|
|
|
|