commit
88150e461c
|
@ -819,10 +819,10 @@ namespace MediaBrowser.Api.Playback
|
|||
{
|
||||
if (state.PlayableStreamFileNames.Count > 0)
|
||||
{
|
||||
return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
|
||||
return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
|
||||
}
|
||||
|
||||
return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol);
|
||||
return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -45,6 +45,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
return false;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _virtual children
|
||||
/// </summary>
|
||||
|
|
|
@ -17,6 +17,9 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// </summary>
|
||||
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
|
||||
{
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
public MusicAlbum()
|
||||
{
|
||||
Artists = new List<string>();
|
||||
|
@ -48,6 +51,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsCumulativeRunTimeTicks
|
||||
{
|
||||
|
@ -83,8 +95,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
get { return false; }
|
||||
}
|
||||
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tracks.
|
||||
/// </summary>
|
||||
|
@ -103,8 +113,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
return Tracks;
|
||||
}
|
||||
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
|
|
@ -48,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
get { return true; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return !IsAccessedByName;
|
||||
|
|
|
@ -129,6 +129,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
get { return false; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool DetectIsInMixedFolder()
|
||||
{
|
||||
if (SupportsIsInMixedFolderDetection)
|
||||
|
|
|
@ -38,6 +38,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -61,6 +61,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
get { return false; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is folder.
|
||||
/// </summary>
|
||||
|
|
|
@ -26,6 +26,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the game system.
|
||||
/// </summary>
|
||||
|
|
|
@ -20,5 +20,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
|
||||
|
||||
bool EnableRememberingTrackSelections { get; }
|
||||
|
||||
bool SupportsPlayedStatus { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,13 +29,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
get
|
||||
{
|
||||
return Album;
|
||||
return AlbumEntity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[IgnoreDataMember]
|
||||
public PhotoAlbum Album
|
||||
public PhotoAlbum AlbumEntity
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -16,6 +16,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
||||
|
|
|
@ -33,6 +33,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearCache()
|
||||
{
|
||||
lock (_childIdsLock)
|
||||
|
|
|
@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
return list;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetChildCount(User user)
|
||||
{
|
||||
return GetChildren(user, true).Count();
|
||||
|
|
|
@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override string CreatePresentationUniqueKey()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
|
||||
|
|
|
@ -54,6 +54,15 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return Status == RecordingStatus.Completed && base.SupportsPlayedStatus;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override LocationType LocationType
|
||||
{
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
/// <param name="inputFiles">The input files.</param>
|
||||
/// <param name="protocol">The protocol.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol);
|
||||
string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the input argument.
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
public IIsoMount MountedIso { get; set; }
|
||||
public VideoType VideoType { get; set; }
|
||||
public List<string> PlayableStreamFileNames { get; set; }
|
||||
public int AnalyzeDurationSections { get; set; }
|
||||
|
||||
public MediaInfoRequest()
|
||||
{
|
||||
|
|
|
@ -31,6 +31,15 @@ namespace MediaBrowser.Controller.Playlists
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsPlayedStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Equals(MediaType, "Video", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool AlwaysScanInternalMetadataPath
|
||||
{
|
||||
|
|
|
@ -431,10 +431,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
{
|
||||
if (state.PlayableStreamFileNames.Count > 0)
|
||||
{
|
||||
return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
|
||||
return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
|
||||
}
|
||||
|
||||
return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol);
|
||||
return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -26,6 +26,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
return string.Format("\"{0}\"", url);
|
||||
}
|
||||
if (protocol == MediaProtocol.Udp)
|
||||
{
|
||||
var url = inputFiles.First();
|
||||
|
||||
return string.Format("\"{0}\"", url);
|
||||
}
|
||||
|
||||
return GetConcatInputArgument(inputFiles);
|
||||
}
|
||||
|
@ -74,9 +80,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
return path.Replace("\"", "\\\"");
|
||||
}
|
||||
|
||||
public static string GetProbeSizeArgument(bool isDvd)
|
||||
public static string GetProbeSizeArgument(int numInputFiles)
|
||||
{
|
||||
return isDvd ? "-probesize 1G -analyzeduration 200M" : "";
|
||||
return numInputFiles > 1 ? "-probesize 1G" : "";
|
||||
}
|
||||
|
||||
public static string GetAnalyzeDurationArgument(int numInputFiles)
|
||||
{
|
||||
return numInputFiles > 1 ? "-analyzeduration 200M" : "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -426,10 +426,24 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
|
||||
|
||||
var probeSizeArgument = GetProbeSizeArgument(inputFiles, request.Protocol);
|
||||
var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length);
|
||||
string analyzeDuration;
|
||||
|
||||
if (request.AnalyzeDurationSections > 0)
|
||||
{
|
||||
analyzeDuration = "-analyzeduration " +
|
||||
(request.AnalyzeDurationSections*1000000).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length);
|
||||
}
|
||||
|
||||
probeSize = probeSize + " " + analyzeDuration;
|
||||
probeSize = probeSize.Trim();
|
||||
|
||||
return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters,
|
||||
probeSizeArgument, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
|
||||
probeSize, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -450,9 +464,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
/// <param name="inputFiles">The input files.</param>
|
||||
/// <param name="protocol">The protocol.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol)
|
||||
public string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol)
|
||||
{
|
||||
return EncodingUtils.GetProbeSizeArgument(inputFiles.Length > 1);
|
||||
var results = new List<string>();
|
||||
|
||||
var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length);
|
||||
var analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(probeSize))
|
||||
{
|
||||
results.Add(probeSize);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(analyzeDuration))
|
||||
{
|
||||
results.Add(analyzeDuration);
|
||||
}
|
||||
return string.Join(" ", results.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -871,7 +899,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) :
|
||||
string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg);
|
||||
|
||||
var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol);
|
||||
var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputPath }, protocol);
|
||||
|
||||
if (!string.IsNullOrEmpty(probeSize))
|
||||
{
|
||||
|
@ -982,7 +1010,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
|
||||
|
||||
var probeSize = GetProbeSizeArgument(new[] { inputArgument }, protocol);
|
||||
var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputArgument }, protocol);
|
||||
|
||||
if (!string.IsNullOrEmpty(probeSize))
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace MediaBrowser.Model.MediaInfo
|
|||
File = 0,
|
||||
Http = 1,
|
||||
Rtmp = 2,
|
||||
Rtsp = 3
|
||||
Rtsp = 3,
|
||||
Udp = 4
|
||||
}
|
||||
}
|
|
@ -598,7 +598,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
dto.Altitude = item.Altitude;
|
||||
dto.IsoSpeedRating = item.IsoSpeedRating;
|
||||
|
||||
var album = item.Album;
|
||||
var album = item.AlbumEntity;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
|
|
|
@ -269,9 +269,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
positionTicks = 0;
|
||||
}
|
||||
|
||||
if (item is Audio)
|
||||
if (!item.SupportsPlayedStatus)
|
||||
{
|
||||
positionTicks = 0;
|
||||
data.Played = false;
|
||||
}
|
||||
|
||||
data.PlaybackPositionTicks = positionTicks;
|
||||
|
|
|
@ -27,6 +27,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using CommonIO;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
@ -59,8 +60,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
public static EmbyTV Current;
|
||||
|
||||
public event EventHandler DataSourceChanged { add { } remove { } }
|
||||
public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged { add { } remove { } }
|
||||
public event EventHandler DataSourceChanged;
|
||||
public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged;
|
||||
|
||||
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
|
||||
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
@ -1009,7 +1010,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
|
||||
public async Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
|
||||
{
|
||||
ActiveRecordingInfo info;
|
||||
|
||||
|
@ -1017,22 +1018,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
if (_activeRecordings.TryGetValue(recordingId, out info))
|
||||
{
|
||||
return Task.FromResult(new List<MediaSourceInfo>
|
||||
var stream = new MediaSourceInfo
|
||||
{
|
||||
new MediaSourceInfo
|
||||
{
|
||||
Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
|
||||
Id = recordingId,
|
||||
SupportsDirectPlay = false,
|
||||
SupportsDirectStream = true,
|
||||
SupportsTranscoding = true,
|
||||
IsInfiniteStream = true,
|
||||
RequiresOpening = false,
|
||||
RequiresClosing = false,
|
||||
Protocol = Model.MediaInfo.MediaProtocol.Http,
|
||||
BufferMs = 0
|
||||
}
|
||||
});
|
||||
Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
|
||||
Id = recordingId,
|
||||
SupportsDirectPlay = false,
|
||||
SupportsDirectStream = true,
|
||||
SupportsTranscoding = true,
|
||||
IsInfiniteStream = true,
|
||||
RequiresOpening = false,
|
||||
RequiresClosing = false,
|
||||
Protocol = Model.MediaInfo.MediaProtocol.Http,
|
||||
BufferMs = 0
|
||||
};
|
||||
|
||||
var isAudio = false;
|
||||
await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return new List<MediaSourceInfo>
|
||||
{
|
||||
stream
|
||||
};
|
||||
}
|
||||
|
||||
throw new FileNotFoundException();
|
||||
|
@ -1258,6 +1264,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
string liveStreamId = null;
|
||||
|
||||
OnRecordingStatusChanged();
|
||||
|
||||
try
|
||||
{
|
||||
var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
|
||||
|
@ -1353,6 +1361,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
|||
{
|
||||
_timerProvider.Delete(timer);
|
||||
}
|
||||
|
||||
OnRecordingStatusChanged();
|
||||
}
|
||||
|
||||
private void OnRecordingStatusChanged()
|
||||
{
|
||||
EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs
|
||||
{
|
||||
|
||||
}, _logger);
|
||||
}
|
||||
|
||||
private async void EnforceKeepUpTo(TimerInfo timer)
|
||||
|
|
110
MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs
Normal file
110
MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs
Normal file
|
@ -0,0 +1,110 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
{
|
||||
public class LiveStreamHelper
|
||||
{
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger)
|
||||
{
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
|
||||
{
|
||||
var originalRuntime = mediaSource.RunTimeTicks;
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
|
||||
{
|
||||
InputPath = mediaSource.Path,
|
||||
Protocol = mediaSource.Protocol,
|
||||
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
|
||||
ExtractChapters = false,
|
||||
AnalyzeDurationSections = 2
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
mediaSource.Bitrate = info.Bitrate;
|
||||
mediaSource.Container = info.Container;
|
||||
mediaSource.Formats = info.Formats;
|
||||
mediaSource.MediaStreams = info.MediaStreams;
|
||||
mediaSource.RunTimeTicks = info.RunTimeTicks;
|
||||
mediaSource.Size = info.Size;
|
||||
mediaSource.Timestamp = info.Timestamp;
|
||||
mediaSource.Video3DFormat = info.Video3DFormat;
|
||||
mediaSource.VideoType = info.VideoType;
|
||||
|
||||
mediaSource.DefaultSubtitleStreamIndex = null;
|
||||
|
||||
// Null this out so that it will be treated like a live stream
|
||||
if (!originalRuntime.HasValue)
|
||||
{
|
||||
mediaSource.RunTimeTicks = null;
|
||||
}
|
||||
|
||||
var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
|
||||
|
||||
if (audioStream == null || audioStream.Index == -1)
|
||||
{
|
||||
mediaSource.DefaultAudioStreamIndex = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
mediaSource.DefaultAudioStreamIndex = audioStream.Index;
|
||||
}
|
||||
|
||||
var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
|
||||
if (videoStream != null)
|
||||
{
|
||||
if (!videoStream.BitRate.HasValue)
|
||||
{
|
||||
var width = videoStream.Width ?? 1920;
|
||||
|
||||
if (width >= 1900)
|
||||
{
|
||||
videoStream.BitRate = 8000000;
|
||||
}
|
||||
|
||||
else if (width >= 1260)
|
||||
{
|
||||
videoStream.BitRate = 3000000;
|
||||
}
|
||||
|
||||
else if (width >= 700)
|
||||
{
|
||||
videoStream.BitRate = 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
// This is coming up false and preventing stream copy
|
||||
videoStream.IsAVC = null;
|
||||
}
|
||||
|
||||
// Try to estimate this
|
||||
if (!mediaSource.Bitrate.HasValue)
|
||||
{
|
||||
var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum();
|
||||
|
||||
if (total > 0)
|
||||
{
|
||||
mediaSource.Bitrate = total;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -121,9 +121,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
foreach (var service in _services)
|
||||
{
|
||||
service.DataSourceChanged += service_DataSourceChanged;
|
||||
service.RecordingStatusChanged += Service_RecordingStatusChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void Service_RecordingStatusChanged(object sender, RecordingStatusChangedEventArgs e)
|
||||
{
|
||||
_lastRecordingRefreshTime = DateTime.MinValue;
|
||||
}
|
||||
|
||||
public List<ITunerHost> TunerHosts
|
||||
{
|
||||
get { return _tunerHosts; }
|
||||
|
@ -2299,6 +2305,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
|
||||
var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
|
||||
|
||||
info.RecordAnyChannel = true;
|
||||
info.RecordAnyTime = true;
|
||||
info.Days = new List<DayOfWeek>
|
||||
{
|
||||
DayOfWeek.Sunday,
|
||||
DayOfWeek.Monday,
|
||||
DayOfWeek.Tuesday,
|
||||
DayOfWeek.Wednesday,
|
||||
DayOfWeek.Thursday,
|
||||
DayOfWeek.Friday,
|
||||
DayOfWeek.Saturday
|
||||
};
|
||||
|
||||
info.Id = null;
|
||||
|
||||
return new Tuple<SeriesTimerInfo, ILiveTvService>(info, service);
|
||||
|
|
|
@ -146,7 +146,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
}
|
||||
else
|
||||
{
|
||||
await AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
|
||||
await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -216,92 +216,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
}
|
||||
}
|
||||
|
||||
private async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
|
||||
{
|
||||
var originalRuntime = mediaSource.RunTimeTicks;
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
|
||||
{
|
||||
InputPath = mediaSource.Path,
|
||||
Protocol = mediaSource.Protocol,
|
||||
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
|
||||
ExtractChapters = false
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
mediaSource.Bitrate = info.Bitrate;
|
||||
mediaSource.Container = info.Container;
|
||||
mediaSource.Formats = info.Formats;
|
||||
mediaSource.MediaStreams = info.MediaStreams;
|
||||
mediaSource.RunTimeTicks = info.RunTimeTicks;
|
||||
mediaSource.Size = info.Size;
|
||||
mediaSource.Timestamp = info.Timestamp;
|
||||
mediaSource.Video3DFormat = info.Video3DFormat;
|
||||
mediaSource.VideoType = info.VideoType;
|
||||
|
||||
mediaSource.DefaultSubtitleStreamIndex = null;
|
||||
|
||||
// Null this out so that it will be treated like a live stream
|
||||
if (!originalRuntime.HasValue)
|
||||
{
|
||||
mediaSource.RunTimeTicks = null;
|
||||
}
|
||||
|
||||
var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
|
||||
|
||||
if (audioStream == null || audioStream.Index == -1)
|
||||
{
|
||||
mediaSource.DefaultAudioStreamIndex = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
mediaSource.DefaultAudioStreamIndex = audioStream.Index;
|
||||
}
|
||||
|
||||
var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
|
||||
if (videoStream != null)
|
||||
{
|
||||
if (!videoStream.BitRate.HasValue)
|
||||
{
|
||||
var width = videoStream.Width ?? 1920;
|
||||
|
||||
if (width >= 1900)
|
||||
{
|
||||
videoStream.BitRate = 8000000;
|
||||
}
|
||||
|
||||
else if (width >= 1260)
|
||||
{
|
||||
videoStream.BitRate = 3000000;
|
||||
}
|
||||
|
||||
else if (width >= 700)
|
||||
{
|
||||
videoStream.BitRate = 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
// This is coming up false and preventing stream copy
|
||||
videoStream.IsAVC = null;
|
||||
}
|
||||
|
||||
// Try to estimate this
|
||||
if (!mediaSource.Bitrate.HasValue)
|
||||
{
|
||||
var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum();
|
||||
|
||||
if (total > 0)
|
||||
{
|
||||
mediaSource.Bitrate = total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Task CloseMediaSource(string liveStreamId)
|
||||
{
|
||||
return _liveTvManager.CloseLiveStream(liveStreamId);
|
||||
|
|
|
@ -234,6 +234,7 @@
|
|||
<Compile Include="LiveTv\EmbyTV\TimerManager.cs" />
|
||||
<Compile Include="LiveTv\Listings\SchedulesDirect.cs" />
|
||||
<Compile Include="LiveTv\Listings\XmlTvListingsProvider.cs" />
|
||||
<Compile Include="LiveTv\LiveStreamHelper.cs" />
|
||||
<Compile Include="LiveTv\LiveTvConfigurationFactory.cs" />
|
||||
<Compile Include="LiveTv\LiveTvDtoService.cs" />
|
||||
<Compile Include="LiveTv\LiveTvManager.cs" />
|
||||
|
|
|
@ -633,10 +633,14 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||
data.PlayCount++;
|
||||
data.LastPlayedDate = DateTime.UtcNow;
|
||||
|
||||
if (!(item is Video))
|
||||
if (!(item is Video) && item.SupportsPlayedStatus)
|
||||
{
|
||||
data.Played = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Played = false;
|
||||
}
|
||||
|
||||
await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
@ -847,11 +851,11 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||
{
|
||||
playedToCompletion = _userDataManager.UpdatePlayState(item, data, positionTicks.Value);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
// If the client isn't able to report this, then we'll just have to make an assumption
|
||||
data.PlayCount++;
|
||||
data.Played = true;
|
||||
data.Played = item.SupportsPlayedStatus;
|
||||
data.PlaybackPositionTicks = 0;
|
||||
playedToCompletion = true;
|
||||
}
|
||||
|
|
|
@ -704,7 +704,7 @@ namespace MediaBrowser.ServerApplication
|
|||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
Verb = "runas",
|
||||
ErrorDialog = false,
|
||||
Arguments = String.Format("/c sc stop {0} & sc start {0}", BackgroundService.GetExistingServiceName())
|
||||
Arguments = String.Format("/c sc stop {0} & sc start {0} & sc start {0}", BackgroundService.GetExistingServiceName())
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Common.Internal</id>
|
||||
<version>3.0.661</version>
|
||||
<version>3.0.662</version>
|
||||
<title>MediaBrowser.Common.Internal</title>
|
||||
<authors>Luke</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
|
||||
<copyright>Copyright © Emby 2013</copyright>
|
||||
<dependencies>
|
||||
<dependency id="MediaBrowser.Common" version="3.0.661" />
|
||||
<dependency id="MediaBrowser.Common" version="3.0.662" />
|
||||
<dependency id="NLog" version="4.3.8" />
|
||||
<dependency id="SimpleInjector" version="3.2.2" />
|
||||
</dependencies>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Common</id>
|
||||
<version>3.0.661</version>
|
||||
<version>3.0.662</version>
|
||||
<title>MediaBrowser.Common</title>
|
||||
<authors>Emby Team</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Server.Core</id>
|
||||
<version>3.0.661</version>
|
||||
<version>3.0.662</version>
|
||||
<title>Media Browser.Server.Core</title>
|
||||
<authors>Emby Team</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<description>Contains core components required to build plugins for Emby Server.</description>
|
||||
<copyright>Copyright © Emby 2013</copyright>
|
||||
<dependencies>
|
||||
<dependency id="MediaBrowser.Common" version="3.0.661" />
|
||||
<dependency id="MediaBrowser.Common" version="3.0.662" />
|
||||
<dependency id="Interfaces.IO" version="1.0.0.5" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
|
Loading…
Reference in New Issue
Block a user