mirror of https://github.com/jellyfin/jellyfin.git
fixes #838 - Support rtmp protocol with channels
This commit is contained in:
parent
f91889e3c4
commit
21fd761b05
|
@ -1,16 +1,12 @@
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Dto;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Persistence;
|
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
|
@ -19,6 +15,7 @@ using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Library;
|
using MediaBrowser.Model.Library;
|
||||||
using MediaBrowser.Model.LiveTv;
|
using MediaBrowser.Model.LiveTv;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -639,16 +636,16 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the probe size argument.
|
/// Gets the probe size argument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="isVideo">if set to <c>true</c> [is video].</param>
|
/// <param name="state">The state.</param>
|
||||||
/// <param name="videoType">Type of the video.</param>
|
|
||||||
/// <param name="isoType">Type of the iso.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private string GetProbeSizeArgument(bool isVideo, VideoType? videoType, IsoType? isoType)
|
private string GetProbeSizeArgument(StreamState state)
|
||||||
{
|
{
|
||||||
var type = !isVideo ? MediaEncoderHelpers.GetInputType(null, null) :
|
if (state.PlayableStreamFileNames.Count > 0)
|
||||||
MediaEncoderHelpers.GetInputType(videoType, isoType);
|
{
|
||||||
|
return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
|
||||||
|
}
|
||||||
|
|
||||||
return MediaEncoder.GetProbeSizeArgument(type);
|
return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -765,7 +762,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected string GetInputArgument(StreamState state)
|
protected string GetInputArgument(StreamState state)
|
||||||
{
|
{
|
||||||
var type = state.IsRemote ? InputType.Url : InputType.File;
|
var protocol = state.InputProtocol;
|
||||||
|
|
||||||
var inputPath = new[] { state.MediaPath };
|
var inputPath = new[] { state.MediaPath };
|
||||||
|
|
||||||
|
@ -773,11 +770,11 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
if (!(state.VideoType == VideoType.Iso && state.IsoMount == null))
|
if (!(state.VideoType == VideoType.Iso && state.IsoMount == null))
|
||||||
{
|
{
|
||||||
inputPath = MediaEncoderHelpers.GetInputArgument(state.MediaPath, state.IsRemote, state.VideoType, state.IsoType, state.IsoMount, state.PlayableStreamFileNames, out type);
|
inputPath = MediaEncoderHelpers.GetInputArgument(state.MediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MediaEncoder.GetInputArgument(inputPath, type);
|
return MediaEncoder.GetInputArgument(inputPath, protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -885,7 +882,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is arbitrary, but add a little buffer time when internet streaming
|
// This is arbitrary, but add a little buffer time when internet streaming
|
||||||
if (state.IsRemote)
|
if (state.InputProtocol != MediaProtocol.File)
|
||||||
{
|
{
|
||||||
await Task.Delay(3000, cancellationTokenSource.Token).ConfigureAwait(false);
|
await Task.Delay(3000, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -1063,11 +1060,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
|
state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(useragent))
|
|
||||||
{
|
|
||||||
useragent = GetUserAgent(state.MediaPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(useragent))
|
if (!string.IsNullOrWhiteSpace(useragent))
|
||||||
{
|
{
|
||||||
return "-user-agent \"" + useragent + "\"";
|
return "-user-agent \"" + useragent + "\"";
|
||||||
|
@ -1076,26 +1068,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the user agent.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
protected string GetUserAgent(string path)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("path");
|
|
||||||
|
|
||||||
}
|
|
||||||
if (path.IndexOf("apple.com", StringComparison.OrdinalIgnoreCase) != -1)
|
|
||||||
{
|
|
||||||
return "QuickTime/7.7.4";
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes the exited.
|
/// Processes the exited.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1388,12 +1360,12 @@ namespace MediaBrowser.Api.Playback
|
||||||
if (!string.IsNullOrEmpty(path))
|
if (!string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
state.MediaPath = path;
|
state.MediaPath = path;
|
||||||
state.IsRemote = false;
|
state.InputProtocol = MediaProtocol.File;
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(mediaUrl))
|
else if (!string.IsNullOrEmpty(mediaUrl))
|
||||||
{
|
{
|
||||||
state.MediaPath = mediaUrl;
|
state.MediaPath = mediaUrl;
|
||||||
state.IsRemote = true;
|
state.InputProtocol = MediaProtocol.Http;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.RunTimeTicks = recording.RunTimeTicks;
|
state.RunTimeTicks = recording.RunTimeTicks;
|
||||||
|
@ -1425,14 +1397,14 @@ namespace MediaBrowser.Api.Playback
|
||||||
if (!string.IsNullOrEmpty(streamInfo.Path))
|
if (!string.IsNullOrEmpty(streamInfo.Path))
|
||||||
{
|
{
|
||||||
state.MediaPath = streamInfo.Path;
|
state.MediaPath = streamInfo.Path;
|
||||||
state.IsRemote = false;
|
state.InputProtocol = MediaProtocol.File;
|
||||||
|
|
||||||
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
|
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(streamInfo.Url))
|
else if (!string.IsNullOrEmpty(streamInfo.Url))
|
||||||
{
|
{
|
||||||
state.MediaPath = streamInfo.Url;
|
state.MediaPath = streamInfo.Url;
|
||||||
state.IsRemote = true;
|
state.InputProtocol = MediaProtocol.Http;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.ReadInputAtNativeFramerate = true;
|
state.ReadInputAtNativeFramerate = true;
|
||||||
|
@ -1445,7 +1417,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
var source = await GetChannelMediaInfo(request.Id, request.MediaSourceId, cancellationToken).ConfigureAwait(false);
|
var source = await GetChannelMediaInfo(request.Id, request.MediaSourceId, cancellationToken).ConfigureAwait(false);
|
||||||
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
||||||
state.IsRemote = source.LocationType == LocationType.Remote;
|
state.InputProtocol = source.Protocol;
|
||||||
state.MediaPath = source.Path;
|
state.MediaPath = source.Path;
|
||||||
state.RunTimeTicks = item.RunTimeTicks;
|
state.RunTimeTicks = item.RunTimeTicks;
|
||||||
state.RemoteHttpHeaders = source.RequiredHttpHeaders;
|
state.RemoteHttpHeaders = source.RequiredHttpHeaders;
|
||||||
|
@ -1461,7 +1433,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
mediaStreams = mediaSource.MediaStreams;
|
mediaStreams = mediaSource.MediaStreams;
|
||||||
|
|
||||||
state.MediaPath = mediaSource.Path;
|
state.MediaPath = mediaSource.Path;
|
||||||
state.IsRemote = mediaSource.LocationType == LocationType.Remote;
|
state.InputProtocol = mediaSource.Protocol;
|
||||||
state.InputContainer = mediaSource.Container;
|
state.InputContainer = mediaSource.Container;
|
||||||
|
|
||||||
if (item is Video)
|
if (item is Video)
|
||||||
|
@ -1921,18 +1893,15 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
var inputModifier = string.Empty;
|
var inputModifier = string.Empty;
|
||||||
|
|
||||||
var probeSize = GetProbeSizeArgument(state.IsInputVideo, state.VideoType, state.IsoType);
|
var probeSize = GetProbeSizeArgument(state);
|
||||||
inputModifier += " " + probeSize;
|
inputModifier += " " + probeSize;
|
||||||
inputModifier = inputModifier.Trim();
|
inputModifier = inputModifier.Trim();
|
||||||
|
|
||||||
if (state.IsRemote)
|
var userAgentParam = GetUserAgentParam(state);
|
||||||
{
|
|
||||||
var userAgentParam = GetUserAgentParam(state);
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(userAgentParam))
|
if (!string.IsNullOrWhiteSpace(userAgentParam))
|
||||||
{
|
{
|
||||||
inputModifier += " " + userAgentParam;
|
inputModifier += " " + userAgentParam;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inputModifier = inputModifier.Trim();
|
inputModifier = inputModifier.Trim();
|
||||||
|
|
|
@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using ServiceStack.Web;
|
using ServiceStack.Web;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -118,13 +119,13 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
var responseHeaders = new Dictionary<string, string>();
|
var responseHeaders = new Dictionary<string, string>();
|
||||||
|
|
||||||
// Static remote stream
|
// Static remote stream
|
||||||
if (request.Static && state.IsRemote)
|
if (request.Static && state.InputProtocol == MediaProtocol.Http)
|
||||||
{
|
{
|
||||||
AddDlnaHeaders(state, responseHeaders, true);
|
AddDlnaHeaders(state, responseHeaders, true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return GetStaticRemoteStreamResult(state.MediaPath, responseHeaders, isHeadRequest).Result;
|
return GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest).Result;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -132,6 +133,11 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.Static && state.InputProtocol != MediaProtocol.File)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format("Input protocol {0} cannot be streamed statically.", state.InputProtocol));
|
||||||
|
}
|
||||||
|
|
||||||
var outputPath = state.OutputFilePath;
|
var outputPath = state.OutputFilePath;
|
||||||
var outputPathExists = File.Exists(outputPath);
|
var outputPathExists = File.Exists(outputPath);
|
||||||
|
|
||||||
|
@ -186,16 +192,19 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the static remote stream result.
|
/// Gets the static remote stream result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mediaPath">The media path.</param>
|
/// <param name="state">The state.</param>
|
||||||
/// <param name="responseHeaders">The response headers.</param>
|
/// <param name="responseHeaders">The response headers.</param>
|
||||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||||
/// <returns>Task{System.Object}.</returns>
|
/// <returns>Task{System.Object}.</returns>
|
||||||
private async Task<object> GetStaticRemoteStreamResult(string mediaPath, Dictionary<string, string> responseHeaders, bool isHeadRequest)
|
private async Task<object> GetStaticRemoteStreamResult(StreamState state, Dictionary<string, string> responseHeaders, bool isHeadRequest)
|
||||||
{
|
{
|
||||||
|
string useragent = null;
|
||||||
|
state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
|
||||||
|
|
||||||
var options = new HttpRequestOptions
|
var options = new HttpRequestOptions
|
||||||
{
|
{
|
||||||
Url = mediaPath,
|
Url = state.MediaPath,
|
||||||
UserAgent = GetUserAgent(mediaPath),
|
UserAgent = useragent,
|
||||||
BufferContent = false
|
BufferContent = false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
@ -50,7 +51,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
public string MediaPath { get; set; }
|
public string MediaPath { get; set; }
|
||||||
|
|
||||||
public bool IsRemote { get; set; }
|
public MediaProtocol InputProtocol { get; set; }
|
||||||
|
|
||||||
public bool IsInputVideo { get; set; }
|
public bool IsInputVideo { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
|
@ -20,16 +21,18 @@ namespace MediaBrowser.Controller.Channels
|
||||||
public int? AudioChannels { get; set; }
|
public int? AudioChannels { get; set; }
|
||||||
public int? AudioSampleRate { get; set; }
|
public int? AudioSampleRate { get; set; }
|
||||||
|
|
||||||
public bool IsRemote { get; set; }
|
|
||||||
|
|
||||||
public string VideoProfile { get; set; }
|
public string VideoProfile { get; set; }
|
||||||
public float? VideoLevel { get; set; }
|
public float? VideoLevel { get; set; }
|
||||||
public float? Framerate { get; set; }
|
public float? Framerate { get; set; }
|
||||||
|
|
||||||
|
public MediaProtocol Protocol { get; set; }
|
||||||
|
|
||||||
public ChannelMediaInfo()
|
public ChannelMediaInfo()
|
||||||
{
|
{
|
||||||
RequiredHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
RequiredHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
IsRemote = true;
|
|
||||||
|
// This is most common
|
||||||
|
Protocol = MediaProtocol.Http;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -67,13 +67,6 @@ namespace MediaBrowser.Controller.Dto
|
||||||
/// <returns>ChapterInfoDto.</returns>
|
/// <returns>ChapterInfoDto.</returns>
|
||||||
ChapterInfoDto GetChapterInfoDto(ChapterInfo chapterInfo, BaseItem item);
|
ChapterInfoDto GetChapterInfoDto(ChapterInfo chapterInfo, BaseItem item);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the media sources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <returns>List{MediaSourceInfo}.</returns>
|
|
||||||
List<MediaSourceInfo> GetMediaSources(BaseItem item);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the item by name dto.
|
/// Gets the item by name dto.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -3,6 +3,7 @@ using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -191,7 +192,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
var info = new MediaSourceInfo
|
var info = new MediaSourceInfo
|
||||||
{
|
{
|
||||||
Id = i.Id.ToString("N"),
|
Id = i.Id.ToString("N"),
|
||||||
LocationType = locationType,
|
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
|
||||||
MediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(),
|
MediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(),
|
||||||
Name = i.Name,
|
Name = i.Name,
|
||||||
Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path,
|
Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path,
|
||||||
|
|
|
@ -549,7 +549,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
Id = i.Id.ToString("N"),
|
Id = i.Id.ToString("N"),
|
||||||
IsoType = i.IsoType,
|
IsoType = i.IsoType,
|
||||||
LocationType = locationType,
|
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
|
||||||
MediaStreams = mediaStreams,
|
MediaStreams = mediaStreams,
|
||||||
Name = GetMediaSourceName(i, mediaStreams),
|
Name = GetMediaSourceName(i, mediaStreams),
|
||||||
Path = enablePathSubstitution ? GetMappedPath(i.Path, locationType) : i.Path,
|
Path = enablePathSubstitution ? GetMappedPath(i.Path, locationType) : i.Path,
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Linq;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.LiveTv
|
namespace MediaBrowser.Controller.LiveTv
|
||||||
{
|
{
|
||||||
public class LiveTvChannel : BaseItem, IItemByName
|
public class LiveTvChannel : BaseItem, IItemByName, IHasMediaSources
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
|
@ -114,5 +114,10 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
{
|
{
|
||||||
return new List<BaseItem>();
|
return new List<BaseItem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Model.Dto.MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -35,59 +36,37 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// Extracts the video image.
|
/// Extracts the video image.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">The input files.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <param name="threedFormat">The threed format.</param>
|
/// <param name="threedFormat">The threed format.</param>
|
||||||
/// <param name="offset">The offset.</param>
|
/// <param name="offset">The offset.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task{Stream}.</returns>
|
/// <returns>Task{Stream}.</returns>
|
||||||
Task<Stream> ExtractVideoImage(string[] inputFiles, InputType type, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
|
Task<Stream> ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the media info.
|
/// Gets the media info.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">The input files.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <param name="isAudio">if set to <c>true</c> [is audio].</param>
|
/// <param name="isAudio">if set to <c>true</c> [is audio].</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, InputType type, bool isAudio, CancellationToken cancellationToken);
|
Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, MediaProtocol protocol, bool isAudio, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the probe size argument.
|
/// Gets the probe size argument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
string GetProbeSizeArgument(InputType type);
|
string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the input argument.
|
/// Gets the input argument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">The input files.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
string GetInputArgument(string[] inputFiles, InputType type);
|
string GetInputArgument(string[] inputFiles, MediaProtocol protocol);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enum InputType
|
|
||||||
/// </summary>
|
|
||||||
public enum InputType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The file
|
|
||||||
/// </summary>
|
|
||||||
File,
|
|
||||||
/// <summary>
|
|
||||||
/// The bluray
|
|
||||||
/// </summary>
|
|
||||||
Bluray,
|
|
||||||
/// <summary>
|
|
||||||
/// The DVD
|
|
||||||
/// </summary>
|
|
||||||
Dvd,
|
|
||||||
/// <summary>
|
|
||||||
/// The URL
|
|
||||||
/// </summary>
|
|
||||||
Url
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
@ -17,56 +18,22 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// Gets the input argument.
|
/// Gets the input argument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="videoPath">The video path.</param>
|
/// <param name="videoPath">The video path.</param>
|
||||||
/// <param name="isRemote">if set to <c>true</c> [is remote].</param>
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <param name="videoType">Type of the video.</param>
|
|
||||||
/// <param name="isoType">Type of the iso.</param>
|
|
||||||
/// <param name="isoMount">The iso mount.</param>
|
/// <param name="isoMount">The iso mount.</param>
|
||||||
/// <param name="playableStreamFileNames">The playable stream file names.</param>
|
/// <param name="playableStreamFileNames">The playable stream file names.</param>
|
||||||
/// <param name="type">The type.</param>
|
|
||||||
/// <returns>System.String[][].</returns>
|
/// <returns>System.String[][].</returns>
|
||||||
public static string[] GetInputArgument(string videoPath, bool isRemote, VideoType videoType, IsoType? isoType, IIsoMount isoMount, IEnumerable<string> playableStreamFileNames, out InputType type)
|
public static string[] GetInputArgument(string videoPath, MediaProtocol protocol, IIsoMount isoMount, List<string> playableStreamFileNames)
|
||||||
{
|
{
|
||||||
var inputPath = isoMount == null ? new[] { videoPath } : new[] { isoMount.MountedPath };
|
if (playableStreamFileNames.Count > 0)
|
||||||
|
|
||||||
type = InputType.File;
|
|
||||||
|
|
||||||
switch (videoType)
|
|
||||||
{
|
{
|
||||||
case VideoType.BluRay:
|
if (isoMount == null)
|
||||||
type = InputType.Bluray;
|
{
|
||||||
inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
|
return GetPlayableStreamFiles(videoPath, playableStreamFileNames).ToArray();
|
||||||
break;
|
}
|
||||||
case VideoType.Dvd:
|
return GetPlayableStreamFiles(isoMount.MountedPath, playableStreamFileNames).ToArray();
|
||||||
type = InputType.Dvd;
|
|
||||||
inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
|
|
||||||
break;
|
|
||||||
case VideoType.Iso:
|
|
||||||
if (isoType.HasValue)
|
|
||||||
{
|
|
||||||
switch (isoType.Value)
|
|
||||||
{
|
|
||||||
case IsoType.BluRay:
|
|
||||||
type = InputType.Bluray;
|
|
||||||
inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
|
|
||||||
break;
|
|
||||||
case IsoType.Dvd:
|
|
||||||
type = InputType.Dvd;
|
|
||||||
inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VideoType.VideoFile:
|
|
||||||
{
|
|
||||||
if (isRemote)
|
|
||||||
{
|
|
||||||
type = InputType.Url;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return inputPath;
|
return new[] {videoPath};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<string> GetPlayableStreamFiles(string rootPath, IEnumerable<string> filenames)
|
public static List<string> GetPlayableStreamFiles(string rootPath, IEnumerable<string> filenames)
|
||||||
|
@ -80,46 +47,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of the input.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="videoType">Type of the video.</param>
|
|
||||||
/// <param name="isoType">Type of the iso.</param>
|
|
||||||
/// <returns>InputType.</returns>
|
|
||||||
public static InputType GetInputType(VideoType? videoType, IsoType? isoType)
|
|
||||||
{
|
|
||||||
var type = InputType.File;
|
|
||||||
|
|
||||||
if (videoType.HasValue)
|
|
||||||
{
|
|
||||||
switch (videoType.Value)
|
|
||||||
{
|
|
||||||
case VideoType.BluRay:
|
|
||||||
type = InputType.Bluray;
|
|
||||||
break;
|
|
||||||
case VideoType.Dvd:
|
|
||||||
type = InputType.Dvd;
|
|
||||||
break;
|
|
||||||
case VideoType.Iso:
|
|
||||||
if (isoType.HasValue)
|
|
||||||
{
|
|
||||||
switch (isoType.Value)
|
|
||||||
{
|
|
||||||
case IsoType.BluRay:
|
|
||||||
type = InputType.Bluray;
|
|
||||||
break;
|
|
||||||
case IsoType.Dvd:
|
|
||||||
type = InputType.Dvd;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MediaInfo GetMediaInfo(InternalMediaInfoResult data)
|
public static MediaInfo GetMediaInfo(InternalMediaInfoResult data)
|
||||||
{
|
{
|
||||||
var internalStreams = data.streams ?? new MediaStreamInfo[] { };
|
var internalStreams = data.streams ?? new MediaStreamInfo[] { };
|
||||||
|
|
|
@ -1,22 +1,27 @@
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.Configuration;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace MediaBrowser.MediaEncoding.Encoder
|
namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
public static class EncodingUtils
|
public static class EncodingUtils
|
||||||
{
|
{
|
||||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
public static string GetInputArgument(List<string> inputFiles, MediaProtocol protocol)
|
||||||
|
|
||||||
public static string GetInputArgument(List<string> inputFiles, bool isRemote)
|
|
||||||
{
|
{
|
||||||
if (isRemote)
|
if (protocol == MediaProtocol.Http)
|
||||||
{
|
{
|
||||||
return GetHttpInputArgument(inputFiles);
|
var url = inputFiles.First();
|
||||||
|
|
||||||
|
return string.Format("\"{0}\"", url);
|
||||||
|
}
|
||||||
|
if (protocol == MediaProtocol.Rtmp)
|
||||||
|
{
|
||||||
|
var url = inputFiles.First();
|
||||||
|
|
||||||
|
return string.Format("\"{0}\"", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetConcatInputArgument(inputFiles);
|
return GetConcatInputArgument(inputFiles);
|
||||||
|
@ -52,35 +57,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return string.Format("file:\"{0}\"", path);
|
return string.Format("file:\"{0}\"", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the HTTP input argument.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inputFiles">The input files.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
private static string GetHttpInputArgument(IEnumerable<string> inputFiles)
|
|
||||||
{
|
|
||||||
var url = inputFiles.First();
|
|
||||||
|
|
||||||
return string.Format("\"{0}\"", url);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetFastSeekValue(EncodingOptions options)
|
|
||||||
{
|
|
||||||
var time = options.StartTimeTicks;
|
|
||||||
|
|
||||||
if (time.HasValue)
|
|
||||||
{
|
|
||||||
var seconds = TimeSpan.FromTicks(time.Value).TotalSeconds;
|
|
||||||
|
|
||||||
if (seconds > 0)
|
|
||||||
{
|
|
||||||
return string.Format("-ss {0}", seconds.ToString(UsCulture));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetProbeSizeArgument(bool isDvd)
|
public static string GetProbeSizeArgument(bool isDvd)
|
||||||
{
|
{
|
||||||
return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty;
|
return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty;
|
||||||
|
|
|
@ -3,6 +3,7 @@ using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
@ -102,37 +103,38 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
/// Gets the media info.
|
/// Gets the media info.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">The input files.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <param name="isAudio">if set to <c>true</c> [is audio].</param>
|
/// <param name="isAudio">if set to <c>true</c> [is audio].</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, InputType type, bool isAudio,
|
public Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, MediaProtocol protocol, bool isAudio,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return GetMediaInfoInternal(GetInputArgument(inputFiles, type), !isAudio,
|
return GetMediaInfoInternal(GetInputArgument(inputFiles, protocol), !isAudio,
|
||||||
GetProbeSizeArgument(type), cancellationToken);
|
GetProbeSizeArgument(inputFiles, protocol), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the input argument.
|
/// Gets the input argument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">The input files.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
/// <exception cref="System.ArgumentException">Unrecognized InputType</exception>
|
/// <exception cref="System.ArgumentException">Unrecognized InputType</exception>
|
||||||
public string GetInputArgument(string[] inputFiles, InputType type)
|
public string GetInputArgument(string[] inputFiles, MediaProtocol protocol)
|
||||||
{
|
{
|
||||||
return EncodingUtils.GetInputArgument(inputFiles.ToList(), type == InputType.Url);
|
return EncodingUtils.GetInputArgument(inputFiles.ToList(), protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the probe size argument.
|
/// Gets the probe size argument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public string GetProbeSizeArgument(InputType type)
|
public string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol)
|
||||||
{
|
{
|
||||||
return EncodingUtils.GetProbeSizeArgument(type == InputType.Dvd);
|
return EncodingUtils.GetProbeSizeArgument(inputFiles.Length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -287,27 +289,27 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
public Task<Stream> ExtractAudioImage(string path, CancellationToken cancellationToken)
|
public Task<Stream> ExtractAudioImage(string path, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return ExtractImage(new[] { path }, InputType.File, true, null, null, cancellationToken);
|
return ExtractImage(new[] { path }, MediaProtocol.File, true, null, null, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Stream> ExtractVideoImage(string[] inputFiles, InputType type, Video3DFormat? threedFormat,
|
public Task<Stream> ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat,
|
||||||
TimeSpan? offset, CancellationToken cancellationToken)
|
TimeSpan? offset, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return ExtractImage(inputFiles, type, false, threedFormat, offset, cancellationToken);
|
return ExtractImage(inputFiles, protocol, false, threedFormat, offset, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Stream> ExtractImage(string[] inputFiles, InputType type, bool isAudio,
|
private async Task<Stream> ExtractImage(string[] inputFiles, MediaProtocol protocol, bool isAudio,
|
||||||
Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
|
Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var resourcePool = isAudio ? _audioImageResourcePool : _videoImageResourcePool;
|
var resourcePool = isAudio ? _audioImageResourcePool : _videoImageResourcePool;
|
||||||
|
|
||||||
var inputArgument = GetInputArgument(inputFiles, type);
|
var inputArgument = GetInputArgument(inputFiles, protocol);
|
||||||
|
|
||||||
if (!isAudio)
|
if (!isAudio)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await ExtractImageInternal(inputArgument, type, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false);
|
return await ExtractImageInternal(inputArgument, protocol, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -315,10 +317,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await ExtractImageInternal(inputArgument, type, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false);
|
return await ExtractImageInternal(inputArgument, protocol, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Stream> ExtractImageInternal(string inputPath, InputType type, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
|
private async Task<Stream> ExtractImageInternal(string inputPath, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(inputPath))
|
if (string.IsNullOrEmpty(inputPath))
|
||||||
{
|
{
|
||||||
|
@ -357,7 +359,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf) :
|
var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf) :
|
||||||
string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf);
|
string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf);
|
||||||
|
|
||||||
var probeSize = GetProbeSizeArgument(type);
|
var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(probeSize))
|
if (!string.IsNullOrEmpty(probeSize))
|
||||||
{
|
{
|
||||||
|
|
|
@ -127,26 +127,19 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
var subtitleStream = mediaSource.MediaStreams
|
var subtitleStream = mediaSource.MediaStreams
|
||||||
.First(i => i.Type == MediaStreamType.Subtitle && i.Index == subtitleStreamIndex);
|
.First(i => i.Type == MediaStreamType.Subtitle && i.Index == subtitleStreamIndex);
|
||||||
|
|
||||||
var inputType = mediaSource.LocationType == LocationType.Remote ? InputType.Url : InputType.File;
|
|
||||||
var inputFiles = new[] { mediaSource.Path };
|
var inputFiles = new[] { mediaSource.Path };
|
||||||
|
|
||||||
if (mediaSource.VideoType.HasValue)
|
if (mediaSource.VideoType.HasValue)
|
||||||
{
|
{
|
||||||
if (mediaSource.VideoType.Value == VideoType.BluRay)
|
if (mediaSource.VideoType.Value == VideoType.BluRay ||
|
||||||
|
mediaSource.VideoType.Value == VideoType.Dvd)
|
||||||
{
|
{
|
||||||
inputType = InputType.Bluray;
|
|
||||||
var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSourceId));
|
|
||||||
inputFiles = mediaSourceItem.GetPlayableStreamFiles().ToArray();
|
|
||||||
}
|
|
||||||
else if (mediaSource.VideoType.Value == VideoType.Dvd)
|
|
||||||
{
|
|
||||||
inputType = InputType.Dvd;
|
|
||||||
var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSourceId));
|
var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSourceId));
|
||||||
inputFiles = mediaSourceItem.GetPlayableStreamFiles().ToArray();
|
inputFiles = mediaSourceItem.GetPlayableStreamFiles().ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, inputType, subtitleStream, cancellationToken).ConfigureAwait(false);
|
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var stream = await GetSubtitleStream(fileInfo.Item1, subtitleStream.Language).ConfigureAwait(false);
|
var stream = await GetSubtitleStream(fileInfo.Item1, subtitleStream.Language).ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -180,7 +173,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
|
|
||||||
private async Task<Tuple<string, string>> GetReadableFile(string mediaPath,
|
private async Task<Tuple<string, string>> GetReadableFile(string mediaPath,
|
||||||
string[] inputFiles,
|
string[] inputFiles,
|
||||||
InputType type,
|
MediaProtocol protocol,
|
||||||
MediaStream subtitleStream,
|
MediaStream subtitleStream,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
@ -189,7 +182,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
// Extract
|
// Extract
|
||||||
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".ass");
|
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".ass");
|
||||||
|
|
||||||
await ExtractTextSubtitle(inputFiles, type, subtitleStream.Index, false, outputPath, cancellationToken)
|
await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, false, outputPath, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return new Tuple<string, string>(outputPath, "ass");
|
return new Tuple<string, string>(outputPath, "ass");
|
||||||
|
@ -451,14 +444,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
/// Extracts the text subtitle.
|
/// Extracts the text subtitle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputFiles">The input files.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
|
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
|
||||||
/// <param name="copySubtitleStream">if set to true, copy stream instead of converting.</param>
|
/// <param name="copySubtitleStream">if set to true, copy stream instead of converting.</param>
|
||||||
/// <param name="outputPath">The output path.</param>
|
/// <param name="outputPath">The output path.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
/// <exception cref="System.ArgumentException">Must use inputPath list overload</exception>
|
/// <exception cref="System.ArgumentException">Must use inputPath list overload</exception>
|
||||||
private async Task ExtractTextSubtitle(string[] inputFiles, InputType type, int subtitleStreamIndex,
|
private async Task ExtractTextSubtitle(string[] inputFiles, MediaProtocol protocol, int subtitleStreamIndex,
|
||||||
bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
|
bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var semaphore = GetLock(outputPath);
|
var semaphore = GetLock(outputPath);
|
||||||
|
@ -469,7 +462,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
{
|
{
|
||||||
if (!File.Exists(outputPath))
|
if (!File.Exists(outputPath))
|
||||||
{
|
{
|
||||||
await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, type), subtitleStreamIndex,
|
await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex,
|
||||||
copySubtitleStream, outputPath, cancellationToken).ConfigureAwait(false);
|
copySubtitleStream, outputPath, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace MediaBrowser.Model.Dto
|
||||||
{
|
{
|
||||||
public class MediaSourceInfo
|
public class MediaSourceInfo
|
||||||
{
|
{
|
||||||
|
public MediaProtocol Protocol { get; set; }
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
@ -17,8 +18,6 @@ namespace MediaBrowser.Model.Dto
|
||||||
public string Container { get; set; }
|
public string Container { get; set; }
|
||||||
public long? Size { get; set; }
|
public long? Size { get; set; }
|
||||||
|
|
||||||
public LocationType LocationType { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public long? RunTimeTicks { get; set; }
|
public long? RunTimeTicks { get; set; }
|
||||||
|
|
|
@ -6,4 +6,11 @@ namespace MediaBrowser.Model.MediaInfo
|
||||||
public const string MP4 = "mp4";
|
public const string MP4 = "mp4";
|
||||||
public const string MKV = "mkv";
|
public const string MKV = "mkv";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum MediaProtocol
|
||||||
|
{
|
||||||
|
File = 0,
|
||||||
|
Http = 1,
|
||||||
|
Rtmp = 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -73,10 +74,9 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputType type = InputType.File;
|
|
||||||
var inputPath = new[] { item.Path };
|
var inputPath = new[] { item.Path };
|
||||||
|
|
||||||
var result = await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
|
var result = await _mediaEncoder.GetMediaInfo(inputPath, MediaProtocol.File, false, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
|
||||||
_json.SerializeToFile(result, cachePath);
|
_json.SerializeToFile(result, cachePath);
|
||||||
|
|
|
@ -126,7 +126,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
|
|
||||||
private const string SchemaVersion = "1";
|
private const string SchemaVersion = "1";
|
||||||
|
|
||||||
private async Task<InternalMediaInfoResult> GetMediaInfo(BaseItem item,
|
private async Task<InternalMediaInfoResult> GetMediaInfo(Video item,
|
||||||
IIsoMount isoMount,
|
IIsoMount isoMount,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
@ -149,17 +149,13 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
var type = InputType.File;
|
var protocol = item.LocationType == LocationType.Remote
|
||||||
var inputPath = isoMount == null ? new[] { item.Path } : new[] { isoMount.MountedPath };
|
? MediaProtocol.Http
|
||||||
|
: MediaProtocol.File;
|
||||||
|
|
||||||
var video = item as Video;
|
var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, protocol, isoMount, item.PlayableStreamFileNames);
|
||||||
|
|
||||||
if (video != null)
|
var result = await _mediaEncoder.GetMediaInfo(inputPath, protocol, false, cancellationToken).ConfigureAwait(false);
|
||||||
{
|
|
||||||
inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, video.LocationType == LocationType.Remote, video.VideoType, video.IsoType, isoMount, video.PlayableStreamFileNames, out type);
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
|
||||||
_json.SerializeToFile(result, cachePath);
|
_json.SerializeToFile(result, cachePath);
|
||||||
|
|
|
@ -9,6 +9,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.MediaInfo
|
namespace MediaBrowser.Providers.MediaInfo
|
||||||
{
|
{
|
||||||
|
@ -89,11 +90,13 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
? TimeSpan.FromTicks(Convert.ToInt64(item.RunTimeTicks.Value * .1))
|
? TimeSpan.FromTicks(Convert.ToInt64(item.RunTimeTicks.Value * .1))
|
||||||
: TimeSpan.FromSeconds(10);
|
: TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
InputType type;
|
var protocol = item.LocationType == LocationType.Remote
|
||||||
|
? MediaProtocol.Http
|
||||||
|
: MediaProtocol.File;
|
||||||
|
|
||||||
var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, item.LocationType == LocationType.Remote, item.VideoType, item.IsoType, isoMount, item.PlayableStreamFileNames, out type);
|
var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, protocol, isoMount, item.PlayableStreamFileNames);
|
||||||
|
|
||||||
var stream = await _mediaEncoder.ExtractVideoImage(inputPath, type, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
|
var stream = await _mediaEncoder.ExtractVideoImage(inputPath, protocol, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
return new DynamicImageResponse
|
return new DynamicImageResponse
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,8 +8,8 @@ using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Channels;
|
using MediaBrowser.Model.Channels;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -182,7 +182,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
|
|
||||||
var list = sources.ToList();
|
var list = sources.ToList();
|
||||||
|
|
||||||
var cachedVersions = list.Where(i => i.LocationType == LocationType.FileSystem).ToList();
|
var cachedVersions = list.Where(i => i.Protocol == MediaProtocol.File).ToList();
|
||||||
|
|
||||||
if (cachedVersions.Count > 0)
|
if (cachedVersions.Count > 0)
|
||||||
{
|
{
|
||||||
|
@ -190,7 +190,12 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var source = list.First();
|
var source = list.FirstOrDefault(i => i.Protocol == MediaProtocol.Http);
|
||||||
|
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var options = new HttpRequestOptions
|
var options = new HttpRequestOptions
|
||||||
{
|
{
|
||||||
|
|
|
@ -280,7 +280,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
MediaStreams = GetMediaStreams(info).ToList(),
|
MediaStreams = GetMediaStreams(info).ToList(),
|
||||||
|
|
||||||
Container = info.Container,
|
Container = info.Container,
|
||||||
LocationType = info.IsRemote ? LocationType.Remote : LocationType.FileSystem,
|
Protocol = info.Protocol,
|
||||||
Path = info.Path,
|
Path = info.Path,
|
||||||
RequiredHttpHeaders = info.RequiredHttpHeaders,
|
RequiredHttpHeaders = info.RequiredHttpHeaders,
|
||||||
RunTimeTicks = item.RunTimeTicks,
|
RunTimeTicks = item.RunTimeTicks,
|
||||||
|
@ -555,17 +555,18 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
return GetChannelItemEntity(i.Item2, channelProvider, channel, token);
|
return GetChannelItemEntity(i.Item2, channelProvider, channel, token);
|
||||||
});
|
});
|
||||||
|
|
||||||
IEnumerable<BaseItem> internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
|
var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
|
||||||
|
|
||||||
internalItems = ApplyFilters(internalItems, query.Filters, user);
|
internalItems = ApplyFilters(internalItems, query.Filters, user).ToArray();
|
||||||
|
await RefreshIfNeeded(internalItems, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (query.StartIndex.HasValue)
|
if (query.StartIndex.HasValue)
|
||||||
{
|
{
|
||||||
internalItems = internalItems.Skip(query.StartIndex.Value);
|
internalItems = internalItems.Skip(query.StartIndex.Value).ToArray();
|
||||||
}
|
}
|
||||||
if (query.Limit.HasValue)
|
if (query.Limit.HasValue)
|
||||||
{
|
{
|
||||||
internalItems = internalItems.Take(query.Limit.Value);
|
internalItems = internalItems.Take(query.Limit.Value).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnItemArray = internalItems.Select(i => _dtoService.GetBaseItemDto(i, query.Fields, user))
|
var returnItemArray = internalItems.Select(i => _dtoService.GetBaseItemDto(i, query.Fields, user))
|
||||||
|
@ -658,6 +659,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
});
|
});
|
||||||
|
|
||||||
var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
|
var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
|
||||||
|
await RefreshIfNeeded(internalItems, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var returnItemArray = internalItems.Select(i => _dtoService.GetBaseItemDto(i, query.Fields, user))
|
var returnItemArray = internalItems.Select(i => _dtoService.GetBaseItemDto(i, query.Fields, user))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
|
@ -1111,7 +1111,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
|
|
||||||
if (tvChannel != null)
|
if (tvChannel != null)
|
||||||
{
|
{
|
||||||
dto.MediaSources = GetMediaSources(tvChannel);
|
dto.MediaSources = tvChannel.GetMediaSources(true).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
var channelItem = item as IChannelItem;
|
var channelItem = item as IChannelItem;
|
||||||
|
@ -1123,43 +1123,6 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MediaSourceInfo> GetMediaSources(BaseItem item)
|
|
||||||
{
|
|
||||||
var video = item as Video;
|
|
||||||
|
|
||||||
if (video != null)
|
|
||||||
{
|
|
||||||
return video.GetMediaSources(true).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
var audio = item as Audio;
|
|
||||||
|
|
||||||
if (audio != null)
|
|
||||||
{
|
|
||||||
return audio.GetMediaSources(true).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = new List<MediaSourceInfo>
|
|
||||||
{
|
|
||||||
new MediaSourceInfo
|
|
||||||
{
|
|
||||||
Id = item.Id.ToString("N"),
|
|
||||||
LocationType = item.LocationType,
|
|
||||||
Name = item.Name,
|
|
||||||
Path = GetMappedPath(item),
|
|
||||||
MediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
|
|
||||||
{
|
|
||||||
ItemId = item.Id
|
|
||||||
|
|
||||||
}).ToList(),
|
|
||||||
|
|
||||||
RunTimeTicks = item.RunTimeTicks
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetMappedPath(IHasMetadata item)
|
private string GetMappedPath(IHasMetadata item)
|
||||||
{
|
{
|
||||||
var path = item.Path;
|
var path = item.Path;
|
||||||
|
|
|
@ -222,7 +222,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
RunTimeTicks = (info.EndDate - info.StartDate).Ticks,
|
RunTimeTicks = (info.EndDate - info.StartDate).Ticks,
|
||||||
OriginalAirDate = info.OriginalAirDate,
|
OriginalAirDate = info.OriginalAirDate,
|
||||||
|
|
||||||
MediaSources = _dtoService.GetMediaSources((BaseItem)recording)
|
MediaSources = recording.GetMediaSources(true).ToList()
|
||||||
};
|
};
|
||||||
|
|
||||||
dto.MediaStreams = dto.MediaSources.SelectMany(i => i.MediaStreams).ToList();
|
dto.MediaStreams = dto.MediaSources.SelectMany(i => i.MediaStreams).ToList();
|
||||||
|
@ -317,7 +317,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
Id = info.Id.ToString("N"),
|
Id = info.Id.ToString("N"),
|
||||||
MediaType = info.MediaType,
|
MediaType = info.MediaType,
|
||||||
ExternalId = info.ExternalId,
|
ExternalId = info.ExternalId,
|
||||||
MediaSources = _dtoService.GetMediaSources(info)
|
MediaSources = info.GetMediaSources(true).ToList()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
|
|
|
@ -148,5 +148,27 @@
|
||||||
"LabelChapterDownloaders": "Chapter downloaders:",
|
"LabelChapterDownloaders": "Chapter downloaders:",
|
||||||
"LabelChapterDownloadersHelp": "Enable and rank your preferred chapter downloaders in order of priority. Lower priority downloaders will only be used to fill in missing information.",
|
"LabelChapterDownloadersHelp": "Enable and rank your preferred chapter downloaders in order of priority. Lower priority downloaders will only be used to fill in missing information.",
|
||||||
"HeaderFavoriteAlbums": "Favorite Albums",
|
"HeaderFavoriteAlbums": "Favorite Albums",
|
||||||
"HeaderLatestChannelMedia": "Latest Channel Items"
|
"HeaderLatestChannelMedia": "Latest Channel Items",
|
||||||
|
"ButtonOrganizeFile": "Organize File",
|
||||||
|
"ButtonDeleteFile": "Delete File",
|
||||||
|
"HeaderOrganizeFile": "Organize File",
|
||||||
|
"HeaderDeleteFile": "Delete File",
|
||||||
|
"StatusSkipped": "Skipped",
|
||||||
|
"StatusFailed": "Failed",
|
||||||
|
"StatusSuccess": "Success",
|
||||||
|
"MessageFileWillBeDeleted": "The following file will be deleted:",
|
||||||
|
"MessageSureYouWishToProceed": "Are you sure you wish to proceed?",
|
||||||
|
"MessageDuplicatesWillBeDeleted": "In addition the following dupliates will be deleted:",
|
||||||
|
"MessageFollowingFileWillBeMovedFrom": "The following file will be moved from:",
|
||||||
|
"MessageDestinationTo": "to:",
|
||||||
|
"HeaderSelectWatchFolder": "Select Watch Folder",
|
||||||
|
"HeaderSelectWatchFolderHelp": "Browse or enter the path to your watch folder. The folder must be writeable.",
|
||||||
|
"OrganizePatternResult": "Result: {0}",
|
||||||
|
"HeaderRestart": "Restart",
|
||||||
|
"HeaderShutdown": "Shutdown",
|
||||||
|
"MessageConfirmRestart": "Are you sure you wish to restart Media Browser Server?",
|
||||||
|
"MessageConfirmShutdown": "Are you sure you wish to shutdown Media Browser Server?",
|
||||||
|
"ButtonUpdateNow": "Update Now",
|
||||||
|
"NewVersionOfSomethingAvailable": "A new version of {0} is available!",
|
||||||
|
"VersionXIsAvailableForDownload": "Version {0} is now available for download."
|
||||||
}
|
}
|
|
@ -14,6 +14,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.MediaEncoder
|
namespace MediaBrowser.Server.Implementations.MediaEncoder
|
||||||
{
|
{
|
||||||
|
@ -133,15 +134,15 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
|
||||||
// Add some time for the first chapter to make sure we don't end up with a black image
|
// Add some time for the first chapter to make sure we don't end up with a black image
|
||||||
var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(FirstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks);
|
var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(FirstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks);
|
||||||
|
|
||||||
InputType type;
|
var protocol = MediaProtocol.File;
|
||||||
|
|
||||||
var inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, false, video.VideoType, video.IsoType, null, video.PlayableStreamFileNames, out type);
|
var inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, protocol, null, video.PlayableStreamFileNames);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
|
|
||||||
using (var stream = await _encoder.ExtractVideoImage(inputPath, type, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false))
|
using (var stream = await _encoder.ExtractVideoImage(inputPath, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
|
using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common.Internal</id>
|
<id>MediaBrowser.Common.Internal</id>
|
||||||
<version>3.0.405</version>
|
<version>3.0.406</version>
|
||||||
<title>MediaBrowser.Common.Internal</title>
|
<title>MediaBrowser.Common.Internal</title>
|
||||||
<authors>Luke</authors>
|
<authors>Luke</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
|
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.405" />
|
<dependency id="MediaBrowser.Common" version="3.0.406" />
|
||||||
<dependency id="NLog" version="2.1.0" />
|
<dependency id="NLog" version="2.1.0" />
|
||||||
<dependency id="SimpleInjector" version="2.5.0" />
|
<dependency id="SimpleInjector" version="2.5.0" />
|
||||||
<dependency id="sharpcompress" version="0.10.2" />
|
<dependency id="sharpcompress" version="0.10.2" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common</id>
|
<id>MediaBrowser.Common</id>
|
||||||
<version>3.0.405</version>
|
<version>3.0.406</version>
|
||||||
<title>MediaBrowser.Common</title>
|
<title>MediaBrowser.Common</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Server.Core</id>
|
<id>MediaBrowser.Server.Core</id>
|
||||||
<version>3.0.405</version>
|
<version>3.0.406</version>
|
||||||
<title>Media Browser.Server.Core</title>
|
<title>Media Browser.Server.Core</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.405" />
|
<dependency id="MediaBrowser.Common" version="3.0.406" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
|
Loading…
Reference in New Issue