diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index c4cdfc9edd..8c4bcf0a31 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1080,7 +1080,7 @@ namespace MediaBrowser.Api.Playback
{
if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo)
{
- transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger);
+ transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager);
state.TranscodingThrottler.Start();
}
}
@@ -2012,7 +2012,6 @@ namespace MediaBrowser.Api.Playback
}
var audioCodec = state.ActualOutputAudioCodec;
-
var videoCodec = state.ActualOutputVideoCodec;
var mediaProfile = state.VideoRequest == null ?
@@ -2033,7 +2032,9 @@ namespace MediaBrowser.Api.Playback
state.TargetTimestamp,
state.IsTargetAnamorphic,
state.IsTargetCabac,
- state.TargetRefFrames);
+ state.TargetRefFrames,
+ state.TargetVideoStreamCount,
+ state.TargetAudioStreamCount);
if (mediaProfile != null)
{
@@ -2118,7 +2119,9 @@ namespace MediaBrowser.Api.Playback
state.TranscodeSeekInfo,
state.IsTargetAnamorphic,
state.IsTargetCabac,
- state.TargetRefFrames
+ state.TargetRefFrames,
+ state.TargetVideoStreamCount,
+ state.TargetAudioStreamCount
).FirstOrDefault() ?? string.Empty;
}
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index b097f3b6af..2d1e896db0 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -346,6 +346,42 @@ namespace MediaBrowser.Api.Playback
}
}
+ public int? TargetVideoStreamCount
+ {
+ get
+ {
+ if (Request.Static)
+ {
+ return GetMediaStreamCount(MediaStreamType.Video, int.MaxValue);
+ }
+ return GetMediaStreamCount(MediaStreamType.Video, 1);
+ }
+ }
+
+ public int? TargetAudioStreamCount
+ {
+ get
+ {
+ if (Request.Static)
+ {
+ return GetMediaStreamCount(MediaStreamType.Audio, int.MaxValue);
+ }
+ return GetMediaStreamCount(MediaStreamType.Audio, 1);
+ }
+ }
+
+ private int? GetMediaStreamCount(MediaStreamType type, int limit)
+ {
+ var count = MediaSource.GetStreamCount(type);
+
+ if (count.HasValue)
+ {
+ count = Math.Min(count.Value, limit);
+ }
+
+ return count;
+ }
+
///
/// Predicts the audio sample rate that will be in the output stream
///
diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs
index 19a9fe9343..58cfa086e3 100644
--- a/MediaBrowser.Api/Playback/TranscodingThrottler.cs
+++ b/MediaBrowser.Api/Playback/TranscodingThrottler.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Model.Logging;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Logging;
using System;
using System.IO;
using System.Threading;
@@ -11,13 +13,18 @@ namespace MediaBrowser.Api.Playback
private readonly ILogger _logger;
private Timer _timer;
private bool _isPaused;
+ private readonly IConfigurationManager _config;
- private readonly long _gapLengthInTicks = TimeSpan.FromMinutes(2).Ticks;
-
- public TranscodingThrottler(TranscodingJob job, ILogger logger)
+ public TranscodingThrottler(TranscodingJob job, ILogger logger, IConfigurationManager config)
{
_job = job;
_logger = logger;
+ _config = config;
+ }
+
+ private EncodingOptions GetOptions()
+ {
+ return _config.GetConfiguration("encoding");
}
public void Start()
@@ -33,7 +40,9 @@ namespace MediaBrowser.Api.Playback
return;
}
- if (IsThrottleAllowed(_job))
+ var options = GetOptions();
+
+ if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdSeconds))
{
PauseTranscoding();
}
@@ -79,19 +88,20 @@ namespace MediaBrowser.Api.Playback
}
}
- private bool IsThrottleAllowed(TranscodingJob job)
+ private bool IsThrottleAllowed(TranscodingJob job, int thresholdSeconds)
{
var bytesDownloaded = job.BytesDownloaded ?? 0;
var transcodingPositionTicks = job.TranscodingPositionTicks ?? 0;
var downloadPositionTicks = job.DownloadPositionTicks ?? 0;
var path = job.Path;
+ var gapLengthInTicks = TimeSpan.FromSeconds(thresholdSeconds).Ticks;
if (downloadPositionTicks > 0 && transcodingPositionTicks > 0)
{
// HLS - time-based consideration
- var targetGap = _gapLengthInTicks;
+ var targetGap = gapLengthInTicks;
var gap = transcodingPositionTicks - downloadPositionTicks;
if (gap < targetGap)
@@ -113,7 +123,7 @@ namespace MediaBrowser.Api.Playback
var bytesTranscoded = job.BytesTranscoded ?? new FileInfo(path).Length;
// Estimate the bytes the transcoder should be ahead
- double gapFactor = _gapLengthInTicks;
+ double gapFactor = gapLengthInTicks;
gapFactor /= transcodingPositionTicks;
var targetGap = bytesTranscoded * gapFactor;
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index 469b60a9c2..7f696f300b 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -158,7 +158,9 @@ namespace MediaBrowser.Dlna.Didl
streamInfo.TranscodeSeekInfo,
streamInfo.IsTargetAnamorphic,
streamInfo.IsTargetCabac,
- streamInfo.TargetRefFrames);
+ streamInfo.TargetRefFrames,
+ streamInfo.TargetVideoStreamCount,
+ streamInfo.TargetAudioStreamCount);
foreach (var contentFeature in contentFeatureList)
{
@@ -280,7 +282,9 @@ namespace MediaBrowser.Dlna.Didl
streamInfo.TargetTimestamp,
streamInfo.IsTargetAnamorphic,
streamInfo.IsTargetCabac,
- streamInfo.TargetRefFrames);
+ streamInfo.TargetRefFrames,
+ streamInfo.TargetVideoStreamCount,
+ streamInfo.TargetAudioStreamCount);
var filename = url.Substring(0, url.IndexOf('?'));
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
index 17385bda62..3eb091a194 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
@@ -526,7 +526,9 @@ namespace MediaBrowser.Dlna.PlayTo
streamInfo.TranscodeSeekInfo,
streamInfo.IsTargetAnamorphic,
streamInfo.IsTargetCabac,
- streamInfo.TargetRefFrames);
+ streamInfo.TargetRefFrames,
+ streamInfo.TargetVideoStreamCount,
+ streamInfo.TargetAudioStreamCount);
return list.FirstOrDefault();
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
index a6a87a3fcb..e9204ef5b0 100644
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
public class AudioEncoder : BaseEncoder
{
- public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, liveTvManager, isoManager, libraryManager, channelManager, sessionManager, subtitleEncoder, mediaSourceManager)
+ public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager)
{
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index 44e0d15173..8266f4d3ad 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -1,6 +1,5 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
@@ -14,6 +13,7 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.MediaInfo;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -31,10 +31,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
protected readonly ILogger Logger;
protected readonly IServerConfigurationManager ConfigurationManager;
protected readonly IFileSystem FileSystem;
- protected readonly ILiveTvManager LiveTvManager;
protected readonly IIsoManager IsoManager;
protected readonly ILibraryManager LibraryManager;
- protected readonly IChannelManager ChannelManager;
protected readonly ISessionManager SessionManager;
protected readonly ISubtitleEncoder SubtitleEncoder;
protected readonly IMediaSourceManager MediaSourceManager;
@@ -45,20 +43,18 @@ namespace MediaBrowser.MediaEncoding.Encoder
ILogger logger,
IServerConfigurationManager configurationManager,
IFileSystem fileSystem,
- ILiveTvManager liveTvManager,
IIsoManager isoManager,
ILibraryManager libraryManager,
- IChannelManager channelManager,
- ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager)
+ ISessionManager sessionManager,
+ ISubtitleEncoder subtitleEncoder,
+ IMediaSourceManager mediaSourceManager)
{
MediaEncoder = mediaEncoder;
Logger = logger;
ConfigurationManager = configurationManager;
FileSystem = fileSystem;
- LiveTvManager = liveTvManager;
IsoManager = isoManager;
LibraryManager = libraryManager;
- ChannelManager = channelManager;
SessionManager = sessionManager;
SubtitleEncoder = subtitleEncoder;
MediaSourceManager = mediaSourceManager;
@@ -68,7 +64,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
IProgress progress,
CancellationToken cancellationToken)
{
- var encodingJob = await new EncodingJobFactory(Logger, LiveTvManager, LibraryManager, ChannelManager, MediaSourceManager)
+ var encodingJob = await new EncodingJobFactory(Logger, LibraryManager, MediaSourceManager)
.CreateJob(options, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false);
encodingJob.OutputFilePath = GetOutputFilePath(encodingJob);
@@ -477,53 +473,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false);
}
- if (string.IsNullOrEmpty(state.MediaPath))
+ if (state.MediaSource.RequiresOpening)
{
- var checkCodecs = false;
-
- if (string.Equals(state.ItemType, typeof(LiveTvChannel).Name))
+ var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
{
- var streamInfo = await LiveTvManager.GetChannelStream(state.Options.ItemId, cancellationToken).ConfigureAwait(false);
+ OpenToken = state.MediaSource.OpenToken
- state.LiveTvStreamId = streamInfo.Id;
+ }, false, cancellationToken).ConfigureAwait(false);
- state.MediaPath = streamInfo.Path;
- state.InputProtocol = streamInfo.Protocol;
+ AttachMediaStreamInfo(state, liveStreamResponse.MediaSource, state.Options);
- await Task.Delay(1500, cancellationToken).ConfigureAwait(false);
-
- AttachMediaStreamInfo(state, streamInfo, state.Options);
- checkCodecs = true;
- }
-
- else if (string.Equals(state.ItemType, typeof(LiveTvVideoRecording).Name) ||
- string.Equals(state.ItemType, typeof(LiveTvAudioRecording).Name))
+ if (state.IsVideoRequest)
{
- var streamInfo = await LiveTvManager.GetRecordingStream(state.Options.ItemId, cancellationToken).ConfigureAwait(false);
-
- state.LiveTvStreamId = streamInfo.Id;
-
- state.MediaPath = streamInfo.Path;
- state.InputProtocol = streamInfo.Protocol;
-
- await Task.Delay(1500, cancellationToken).ConfigureAwait(false);
-
- AttachMediaStreamInfo(state, streamInfo, state.Options);
- checkCodecs = true;
+ EncodingJobFactory.TryStreamCopy(state, state.Options);
}
+ }
- if (state.IsVideoRequest && checkCodecs)
- {
- if (state.VideoStream != null && EncodingJobFactory.CanStreamCopyVideo(state.Options, state.VideoStream))
- {
- state.OutputVideoCodec = "copy";
- }
-
- if (state.AudioStream != null && EncodingJobFactory.CanStreamCopyAudio(state.Options, state.AudioStream, state.SupportedAudioCodecs))
- {
- state.OutputAudioCodec = "copy";
- }
- }
+ if (state.MediaSource.BufferMs.HasValue)
+ {
+ await Task.Delay(state.MediaSource.BufferMs.Value, cancellationToken).ConfigureAwait(false);
}
}
@@ -531,22 +499,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
MediaSourceInfo mediaSource,
EncodingJobOptions videoRequest)
{
- state.InputProtocol = mediaSource.Protocol;
- state.MediaPath = mediaSource.Path;
- state.RunTimeTicks = mediaSource.RunTimeTicks;
- state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
- state.InputBitrate = mediaSource.Bitrate;
- state.InputFileSize = mediaSource.Size;
- state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
-
- if (state.ReadInputAtNativeFramerate)
- {
- state.OutputAudioSync = "1000";
- state.InputVideoSync = "-1";
- state.InputAudioSync = "1";
- }
-
- EncodingJobFactory.AttachMediaStreamInfo(state, mediaSource.MediaStreams, videoRequest);
+ EncodingJobFactory.AttachMediaStreamInfo(state, mediaSource, videoRequest);
}
///
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
index c8d121eead..767f3f829b 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
@@ -1,7 +1,8 @@
-using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
@@ -26,7 +27,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public EncodingJobOptions Options { get; set; }
public string InputContainer { get; set; }
- public List AllMediaStreams { get; set; }
+ public MediaSourceInfo MediaSource { get; set; }
public MediaStream AudioStream { get; set; }
public MediaStream VideoStream { get; set; }
public MediaStream SubtitleStream { get; set; }
@@ -76,12 +77,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
private readonly ILogger _logger;
- private readonly ILiveTvManager _liveTvManager;
+ private readonly IMediaSourceManager _mediaSourceManager;
- public EncodingJob(ILogger logger, ILiveTvManager liveTvManager)
+ public EncodingJob(ILogger logger, IMediaSourceManager mediaSourceManager)
{
_logger = logger;
- _liveTvManager = liveTvManager;
+ _mediaSourceManager = mediaSourceManager;
Id = Guid.NewGuid().ToString("N");
RemoteHttpHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase);
@@ -89,7 +90,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
SupportedAudioCodecs = new List();
PlayableStreamFileNames = new List();
RemoteHttpHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase);
- AllMediaStreams = new List();
TaskCompletionSource = new TaskCompletionSource();
}
@@ -136,15 +136,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
private async void DisposeLiveStream()
{
- if (!string.IsNullOrEmpty(LiveTvStreamId))
+ if (MediaSource.RequiresClosing)
{
try
{
- await _liveTvManager.CloseLiveStream(LiveTvStreamId, CancellationToken.None).ConfigureAwait(false);
+ await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
- _logger.ErrorException("Error closing live tv stream", ex);
+ _logger.ErrorException("Error closing media source", ex);
}
}
}
@@ -394,6 +394,42 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
+ public int? TargetVideoStreamCount
+ {
+ get
+ {
+ if (Options.Static)
+ {
+ return GetMediaStreamCount(MediaStreamType.Video, int.MaxValue);
+ }
+ return GetMediaStreamCount(MediaStreamType.Video, 1);
+ }
+ }
+
+ public int? TargetAudioStreamCount
+ {
+ get
+ {
+ if (Options.Static)
+ {
+ return GetMediaStreamCount(MediaStreamType.Audio, int.MaxValue);
+ }
+ return GetMediaStreamCount(MediaStreamType.Audio, 1);
+ }
+ }
+
+ private int? GetMediaStreamCount(MediaStreamType type, int limit)
+ {
+ var count = MediaSource.GetStreamCount(type);
+
+ if (count.HasValue)
+ {
+ count = Math.Min(count.Value, limit);
+ }
+
+ return count;
+ }
+
public void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded)
{
var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index c5783e1882..8d82010749 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -1,9 +1,10 @@
-using MediaBrowser.Controller.Channels;
+using System.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
@@ -19,19 +20,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
public class EncodingJobFactory
{
private readonly ILogger _logger;
- private readonly ILiveTvManager _liveTvManager;
private readonly ILibraryManager _libraryManager;
- private readonly IChannelManager _channelManager;
private readonly IMediaSourceManager _mediaSourceManager;
protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- public EncodingJobFactory(ILogger logger, ILiveTvManager liveTvManager, ILibraryManager libraryManager, IChannelManager channelManager, IMediaSourceManager mediaSourceManager)
+ public EncodingJobFactory(ILogger logger, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager)
{
_logger = logger;
- _liveTvManager = liveTvManager;
_libraryManager = libraryManager;
- _channelManager = channelManager;
_mediaSourceManager = mediaSourceManager;
}
@@ -42,9 +39,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (string.IsNullOrEmpty(request.AudioCodec))
{
request.AudioCodec = InferAudioCodec(request.OutputContainer);
- }
-
- var state = new EncodingJob(_logger, _liveTvManager)
+ }
+
+ var state = new EncodingJob(_logger, _mediaSourceManager)
{
Options = options,
IsVideoRequest = isVideoRequest,
@@ -58,106 +55,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
var item = _libraryManager.GetItemById(request.ItemId);
-
- List mediaStreams = null;
-
state.ItemType = item.GetType().Name;
- if (item is ILiveTvRecording)
- {
- var recording = await _liveTvManager.GetInternalRecording(request.ItemId, cancellationToken).ConfigureAwait(false);
+ state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
- state.VideoType = VideoType.VideoFile;
- state.IsInputVideo = string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
+ var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, false, cancellationToken).ConfigureAwait(false);
- var path = recording.RecordingInfo.Path;
- var mediaUrl = recording.RecordingInfo.Url;
-
- var source = string.IsNullOrEmpty(request.MediaSourceId)
- ? recording.GetMediaSources(false).First()
- : _mediaSourceManager.GetStaticMediaSource(recording, request.MediaSourceId, false);
+ var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
+ ? mediaSources.First()
+ : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
- mediaStreams = source.MediaStreams;
-
- // Just to prevent this from being null and causing other methods to fail
- state.MediaPath = string.Empty;
-
- if (!string.IsNullOrEmpty(path))
- {
- state.MediaPath = path;
- state.InputProtocol = MediaProtocol.File;
- }
- else if (!string.IsNullOrEmpty(mediaUrl))
- {
- state.MediaPath = mediaUrl;
- state.InputProtocol = MediaProtocol.Http;
- }
-
- state.RunTimeTicks = recording.RunTimeTicks;
- state.DeInterlace = true;
- state.OutputAudioSync = "1000";
- state.InputVideoSync = "-1";
- state.InputAudioSync = "1";
- state.InputContainer = recording.Container;
- state.ReadInputAtNativeFramerate = source.ReadAtNativeFramerate;
- }
- else if (item is LiveTvChannel)
- {
- var channel = _liveTvManager.GetInternalChannel(request.ItemId);
-
- state.VideoType = VideoType.VideoFile;
- state.IsInputVideo = string.Equals(channel.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
- mediaStreams = new List();
-
- state.DeInterlace = true;
-
- // Just to prevent this from being null and causing other methods to fail
- state.MediaPath = string.Empty;
- }
- else
- {
- var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, false, cancellationToken).ConfigureAwait(false);
-
- var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
- ? mediaSources.First()
- : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
-
- mediaStreams = mediaSource.MediaStreams;
-
- state.MediaPath = mediaSource.Path;
- state.InputProtocol = mediaSource.Protocol;
- state.InputContainer = mediaSource.Container;
- state.InputFileSize = mediaSource.Size;
- state.InputBitrate = mediaSource.Bitrate;
- state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
- state.RunTimeTicks = mediaSource.RunTimeTicks;
- state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
-
- var video = item as Video;
-
- if (video != null)
- {
- state.IsInputVideo = true;
-
- if (mediaSource.VideoType.HasValue)
- {
- state.VideoType = mediaSource.VideoType.Value;
- }
-
- state.IsoType = mediaSource.IsoType;
-
- state.PlayableStreamFileNames = mediaSource.PlayableStreamFileNames.ToList();
-
- if (mediaSource.Timestamp.HasValue)
- {
- state.InputTimestamp = mediaSource.Timestamp.Value;
- }
- }
-
- state.RunTimeTicks = mediaSource.RunTimeTicks;
- }
-
- AttachMediaStreamInfo(state, mediaStreams, request);
+ AttachMediaStreamInfo(state, mediaSource, options);
state.OutputAudioBitrate = GetAudioBitrateParam(request, state.AudioStream);
state.OutputAudioSampleRate = request.AudioSampleRate;
@@ -185,26 +93,73 @@ namespace MediaBrowser.MediaEncoding.Encoder
ApplyDeviceProfileSettings(state);
- if (isVideoRequest)
- {
- if (state.VideoStream != null && CanStreamCopyVideo(request, state.VideoStream))
- {
- state.OutputVideoCodec = "copy";
- }
-
- if (state.AudioStream != null && CanStreamCopyAudio(request, state.AudioStream, state.SupportedAudioCodecs))
- {
- state.OutputAudioCodec = "copy";
- }
- }
+ TryStreamCopy(state, request);
return state;
}
- internal static void AttachMediaStreamInfo(EncodingJob state,
- List mediaStreams,
+ internal static void TryStreamCopy(EncodingJob state,
EncodingJobOptions videoRequest)
{
+ if (state.IsVideoRequest)
+ {
+ if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream))
+ {
+ state.OutputVideoCodec = "copy";
+ }
+
+ if (state.AudioStream != null && CanStreamCopyAudio(videoRequest, state.AudioStream, state.SupportedAudioCodecs))
+ {
+ state.OutputAudioCodec = "copy";
+ }
+ }
+ }
+
+ internal static void AttachMediaStreamInfo(EncodingJob state,
+ MediaSourceInfo mediaSource,
+ EncodingJobOptions videoRequest)
+ {
+ state.MediaPath = mediaSource.Path;
+ state.InputProtocol = mediaSource.Protocol;
+ state.InputContainer = mediaSource.Container;
+ state.InputFileSize = mediaSource.Size;
+ state.InputBitrate = mediaSource.Bitrate;
+ state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
+ state.RunTimeTicks = mediaSource.RunTimeTicks;
+ state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
+
+ if (mediaSource.VideoType.HasValue)
+ {
+ state.VideoType = mediaSource.VideoType.Value;
+ }
+
+ state.IsoType = mediaSource.IsoType;
+
+ state.PlayableStreamFileNames = mediaSource.PlayableStreamFileNames.ToList();
+
+ if (mediaSource.Timestamp.HasValue)
+ {
+ state.InputTimestamp = mediaSource.Timestamp.Value;
+ }
+
+ state.InputProtocol = mediaSource.Protocol;
+ state.MediaPath = mediaSource.Path;
+ state.RunTimeTicks = mediaSource.RunTimeTicks;
+ state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
+ state.InputBitrate = mediaSource.Bitrate;
+ state.InputFileSize = mediaSource.Size;
+ state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
+
+ if (state.ReadInputAtNativeFramerate ||
+ mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))
+ {
+ state.OutputAudioSync = "1000";
+ state.InputVideoSync = "-1";
+ state.InputAudioSync = "1";
+ }
+
+ var mediaStreams = mediaSource.MediaStreams;
+
if (videoRequest != null)
{
if (string.IsNullOrEmpty(videoRequest.VideoCodec))
@@ -233,7 +188,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
}
- state.AllMediaStreams = mediaStreams;
+ state.MediaSource = mediaSource;
}
///
@@ -771,7 +726,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.TargetTimestamp,
state.IsTargetAnamorphic,
state.IsTargetCabac,
- state.TargetRefFrames);
+ state.TargetRefFrames,
+ state.TargetVideoStreamCount,
+ state.TargetAudioStreamCount);
if (mediaProfile != null)
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 7fd91bf6f8..4258898073 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -577,10 +577,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger,
ConfigurationManager,
FileSystem,
- LiveTvManager,
IsoManager,
LibraryManager,
- ChannelManager,
SessionManager,
SubtitleEncoder(),
MediaSourceManager())
@@ -599,10 +597,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger,
ConfigurationManager,
FileSystem,
- LiveTvManager,
IsoManager,
LibraryManager,
- ChannelManager,
SessionManager,
SubtitleEncoder(),
MediaSourceManager())
diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
index b8ed97b1fc..26d4a76509 100644
--- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
public class VideoEncoder : BaseEncoder
{
- public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, liveTvManager, isoManager, libraryManager, channelManager, sessionManager, subtitleEncoder, mediaSourceManager)
+ public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager)
{
}
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index f24367298e..afd67eb153 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -8,12 +8,16 @@ namespace MediaBrowser.Model.Configuration
public double DownMixAudioBoost { get; set; }
public string H264Encoder { get; set; }
public bool EnableDebugLogging { get; set; }
+ public bool EnableThrottling { get; set; }
+ public int ThrottleThresholdSeconds { get; set; }
public EncodingOptions()
{
H264Encoder = "libx264";
DownMixAudioBoost = 2;
EncodingQuality = EncodingQuality.Auto;
+ EnableThrottling = true;
+ ThrottleThresholdSeconds = 120;
}
}
}
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
index e0a8e239e1..3769634440 100644
--- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs
+++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
@@ -20,7 +20,9 @@ namespace MediaBrowser.Model.Dlna
TransportStreamTimestamp? timestamp,
bool? isAnamorphic,
bool? isCabac,
- int? refFrames)
+ int? refFrames,
+ int? numVideoStreams,
+ int? numAudioStreams)
{
switch (condition.Property)
{
@@ -56,6 +58,10 @@ namespace MediaBrowser.Model.Dlna
return IsConditionSatisfied(condition, width);
case ProfileConditionValue.RefFrames:
return IsConditionSatisfied(condition, refFrames);
+ case ProfileConditionValue.NumAudioStreams:
+ return IsConditionSatisfied(condition, numAudioStreams);
+ case ProfileConditionValue.NumVideoStreams:
+ return IsConditionSatisfied(condition, numVideoStreams);
case ProfileConditionValue.VideoTimestamp:
return IsConditionSatisfied(condition, timestamp);
default:
@@ -92,7 +98,8 @@ namespace MediaBrowser.Model.Dlna
public bool IsVideoAudioConditionSatisfied(ProfileCondition condition,
int? audioChannels,
int? audioBitrate,
- string audioProfile)
+ string audioProfile,
+ bool? isSecondaryTrack)
{
switch (condition.Property)
{
@@ -102,6 +109,8 @@ namespace MediaBrowser.Model.Dlna
return IsConditionSatisfied(condition, audioBitrate);
case ProfileConditionValue.AudioChannels:
return IsConditionSatisfied(condition, audioChannels);
+ case ProfileConditionValue.IsSecondaryAudio:
+ return IsConditionSatisfied(condition, isSecondaryTrack);
default:
throw new ArgumentException("Unexpected condition on audio file: " + condition.Property);
}
diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
index a3eeecff2f..8161f1c268 100644
--- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
+++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
@@ -117,7 +117,9 @@ namespace MediaBrowser.Model.Dlna
TranscodeSeekInfo transcodeSeekInfo,
bool? isAnamorphic,
bool? isCabac,
- int? refFrames)
+ int? refFrames,
+ int? numVideoStreams,
+ int? numAudioStreams)
{
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo);
@@ -158,7 +160,9 @@ namespace MediaBrowser.Model.Dlna
timestamp,
isAnamorphic,
isCabac,
- refFrames);
+ refFrames,
+ numVideoStreams,
+ numAudioStreams);
List orgPnValues = new List();
diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs
index 4b137a268c..8b9b2edf36 100644
--- a/MediaBrowser.Model/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs
@@ -281,7 +281,9 @@ namespace MediaBrowser.Model.Dlna
TransportStreamTimestamp timestamp,
bool? isAnamorphic,
bool? isCabac,
- int? refFrames)
+ int? refFrames,
+ int? numVideoStreams,
+ int? numAudioStreams)
{
container = StringHelper.TrimStart((container ?? string.Empty), '.');
@@ -315,7 +317,7 @@ namespace MediaBrowser.Model.Dlna
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(c, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames))
+ if (!conditionProcessor.IsVideoConditionSatisfied(c, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
{
anyOff = true;
break;
diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
index ae6dc74c8c..7563ffb5af 100644
--- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
+++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
@@ -17,6 +17,9 @@
VideoTimestamp = 12,
IsAnamorphic = 13,
RefFrames = 14,
- IsCabac = 15
+ IsCabac = 15,
+ NumAudioStreams = 16,
+ NumVideoStreams = 17,
+ IsSecondaryAudio
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 6534eda10c..1cc37de57c 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -495,10 +495,13 @@ namespace MediaBrowser.Model.Dlna
int? packetLength = videoStream == null ? null : videoStream.PacketLength;
int? refFrames = videoStream == null ? null : videoStream.RefFrames;
+ int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
+ int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
+
// Check container conditions
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames))
+ if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
{
return null;
}
@@ -525,7 +528,7 @@ namespace MediaBrowser.Model.Dlna
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames))
+ if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
{
return null;
}
@@ -554,7 +557,8 @@ namespace MediaBrowser.Model.Dlna
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioProfile))
+ bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream);
+ if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioProfile, isSecondaryAudio))
{
return null;
}
@@ -752,6 +756,9 @@ namespace MediaBrowser.Model.Dlna
case ProfileConditionValue.AudioProfile:
case ProfileConditionValue.Has64BitOffsets:
case ProfileConditionValue.PacketLength:
+ case ProfileConditionValue.NumAudioStreams:
+ case ProfileConditionValue.NumVideoStreams:
+ case ProfileConditionValue.IsSecondaryAudio:
case ProfileConditionValue.VideoTimestamp:
{
// Not supported yet
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 12319a1227..feee2d765c 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -672,6 +672,42 @@ namespace MediaBrowser.Model.Dlna
}
}
+ public int? TargetVideoStreamCount
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return GetMediaStreamCount(MediaStreamType.Video, int.MaxValue);
+ }
+ return GetMediaStreamCount(MediaStreamType.Video, 1);
+ }
+ }
+
+ public int? TargetAudioStreamCount
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return GetMediaStreamCount(MediaStreamType.Audio, int.MaxValue);
+ }
+ return GetMediaStreamCount(MediaStreamType.Audio, 1);
+ }
+ }
+
+ private int? GetMediaStreamCount(MediaStreamType type, int limit)
+ {
+ var count = MediaSource.GetStreamCount(type);
+
+ if (count.HasValue)
+ {
+ count = Math.Min(count.Value, limit);
+ }
+
+ return count;
+ }
+
public List GetSelectableAudioStreams()
{
return GetSelectableStreams(MediaStreamType.Audio);
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index 3b45137241..302d18bc0f 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -46,8 +46,8 @@ namespace MediaBrowser.Model.Dto
public int? Bitrate { get; set; }
public TransportStreamTimestamp? Timestamp { get; set; }
- public Dictionary RequiredHttpHeaders { get; set; }
-
+ public Dictionary RequiredHttpHeaders { get; set; }
+
public string TranscodingUrl { get; set; }
public string TranscodingSubProtocol { get; set; }
public string TranscodingContainer { get; set; }
@@ -135,5 +135,35 @@ namespace MediaBrowser.Model.Dto
return null;
}
+
+ public int? GetStreamCount(MediaStreamType type)
+ {
+ int numMatches = 0;
+ int numStreams = 0;
+
+ foreach (MediaStream i in MediaStreams)
+ {
+ numStreams++;
+ if (i.Type == type)
+ {
+ numMatches++;
+ }
+ }
+
+ return numStreams == 0 ? (int?)null : numMatches;
+ }
+
+ public bool? IsSecondaryAudio(MediaStream stream)
+ {
+ foreach (MediaStream currentStream in MediaStreams)
+ {
+ if (currentStream.Type == MediaStreamType.Audio)
+ {
+ return currentStream.Index != stream.Index;
+ }
+ }
+
+ return null;
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
index fdcc4ceb66..ae20fafbab 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
@@ -35,6 +35,8 @@
"HeaderConfirmation": "Confirmation",
"MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
"MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+ "TitleLiveTV": "Live TV",
+ "TitleSync": "Sync",
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
"MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
"MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:",
@@ -93,7 +95,6 @@
"HeaderWelcomeToProjectWebClient": "Welcome to the Emby Web Client",
"ButtonTakeTheTour": "Take the tour",
"HeaderWelcomeBack": "Welcome back!",
- "TitleSync": "Sync",
"TitlePlugins": "Plugins",
"ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
"MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index 0fc603a083..f52d8a9fe3 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -1400,5 +1400,7 @@
"HeaderUpcomingPrograms": "Upcoming Programs",
"ButtonMoreItems": "More...",
"LabelShowLibraryTileNames": "Show library tile names",
- "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
+ "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page",
+ "OptionEnableTranscodingThrottle": "Enable throttling",
+ "OptionEnableTranscodingThrottleHelp": "Throttling will automatically adjust transcoding speed in order to minimize server cpu utilization during playback."
}
diff --git a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs
index 8d4c40fdc5..c3e8cf9444 100644
--- a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs
+++ b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Dlna;
+using System.Collections.Generic;
+using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Server.Implementations.Sync
{
@@ -25,6 +26,9 @@ namespace MediaBrowser.Server.Implementations.Sync
mkvAudio += ",dca";
}
+ var videoProfile = "high|main|baseline|constrained baseline";
+ var videoLevel = "41";
+
DirectPlayProfiles = new[]
{
new DirectPlayProfile
@@ -48,13 +52,37 @@ namespace MediaBrowser.Server.Implementations.Sync
}
};
- ContainerProfiles = new ContainerProfile[] { };
+ ContainerProfiles = new[]
+ {
+ new ContainerProfile
+ {
+ Type = DlnaProfileType.Video,
+ Conditions = new []
+ {
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.NotEquals,
+ Property = ProfileConditionValue.NumAudioStreams,
+ Value = "0",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.EqualsAny,
+ Property = ProfileConditionValue.NumVideoStreams,
+ Value = "1",
+ IsRequired = false
+ }
+ }
+ }
+ };
- CodecProfiles = new[]
+ var codecProfiles = new List
{
new CodecProfile
{
Type = CodecType.Video,
+ Codec = "h264",
Conditions = new []
{
new ProfileCondition
@@ -65,11 +93,18 @@ namespace MediaBrowser.Server.Implementations.Sync
IsRequired = false
},
new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Width,
+ Value = "1920",
+ IsRequired = true
+ },
+ new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080",
- IsRequired = false
+ IsRequired = true
},
new ProfileCondition
{
@@ -77,11 +112,115 @@ namespace MediaBrowser.Server.Implementations.Sync
Property = ProfileConditionValue.RefFrames,
Value = "4",
IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.VideoFramerate,
+ Value = "30",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.Equals,
+ Property = ProfileConditionValue.IsAnamorphic,
+ Value = "false",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.VideoLevel,
+ Value = videoLevel,
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.EqualsAny,
+ Property = ProfileConditionValue.VideoProfile,
+ Value = videoProfile,
+ IsRequired = false
+ }
+ }
+ },
+ new CodecProfile
+ {
+ Type = CodecType.Video,
+ Codec = "mpeg4",
+ Conditions = new []
+ {
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.VideoBitDepth,
+ Value = "8",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Width,
+ Value = "1920",
+ IsRequired = true
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Height,
+ Value = "1080",
+ IsRequired = true
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.RefFrames,
+ Value = "4",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.VideoFramerate,
+ Value = "30",
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.Equals,
+ Property = ProfileConditionValue.IsAnamorphic,
+ Value = "false",
+ IsRequired = false
}
}
}
};
+ var maxAudioChannels = supportsAc3 || supportsDca ? "5" : "2";
+ codecProfiles.Add(new CodecProfile
+ {
+ Type = CodecType.Audio,
+ Codec = "mpeg4",
+ Conditions = new[]
+ {
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.AudioChannels,
+ Value = maxAudioChannels,
+ IsRequired = false
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.Equals,
+ Property = ProfileConditionValue.IsSecondaryAudio,
+ Value = "false",
+ IsRequired = false
+ }
+ }
+ });
+
+ CodecProfiles = codecProfiles.ToArray();
+
SubtitleProfiles = new[]
{
new SubtitleProfile
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index 0a995a8455..8982b5739c 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -364,7 +364,7 @@ namespace MediaBrowser.WebDashboard.Api
"backdrops.js",
"sync.js",
"syncjob.js",
- "syncservices.js",
+ "appservices.js",
"playlistmanager.js",
"mediaplayer.js",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 03a704a46b..2725d63ad8 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -151,7 +151,7 @@
PreserveNewest
-
+
PreserveNewest
@@ -175,7 +175,7 @@
PreserveNewest
-
+
PreserveNewest
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index dd28aae3ac..40da3899c5 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Common.Internal
- 3.0.608
+ 3.0.609
MediaBrowser.Common.Internal
Luke
ebr,Luke,scottisafool
@@ -12,7 +12,7 @@
Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.
Copyright © Emby 2013
-
+
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 0124a609de..7aa9d30551 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Common
- 3.0.608
+ 3.0.609
MediaBrowser.Common
Emby Team
ebr,Luke,scottisafool
diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec
index 3297b66066..8d65ec4315 100644
--- a/Nuget/MediaBrowser.Model.Signed.nuspec
+++ b/Nuget/MediaBrowser.Model.Signed.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Model.Signed
- 3.0.608
+ 3.0.609
MediaBrowser.Model - Signed Edition
Emby Team
ebr,Luke,scottisafool
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index 0a749c98b6..9a5264da95 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Server.Core
- 3.0.608
+ 3.0.609
Media Browser.Server.Core
Emby Team
ebr,Luke,scottisafool
@@ -12,7 +12,7 @@
Contains core components required to build plugins for Emby Server.
Copyright © Emby 2013
-
+