private void AddVideoResource(DlnaOptions options, XmlWriter writer, BaseItem video, string deviceId, Filter filter, StreamInfo streamInfo = null) { if (streamInfo == null) { var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user); streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions { ItemId = video.Id, MediaSources = sources.ToArray(), Profile = _profile, DeviceId = deviceId, MaxBitrate = _profile.MaxStreamingBitrate }); } var targetWidth = streamInfo.TargetWidth; var targetHeight = streamInfo.TargetHeight; var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader(streamInfo.Container, streamInfo.TargetVideoCodec.FirstOrDefault(), streamInfo.TargetAudioCodec.FirstOrDefault(), targetWidth, targetHeight, streamInfo.TargetVideoBitDepth, streamInfo.TargetVideoBitrate, streamInfo.TargetTimestamp, streamInfo.IsDirectStream, streamInfo.RunTimeTicks ?? 0, streamInfo.TargetVideoProfile, streamInfo.TargetVideoLevel, streamInfo.TargetFramerate ?? 0, streamInfo.TargetPacketLength, streamInfo.TranscodeSeekInfo, streamInfo.IsTargetAnamorphic, streamInfo.IsTargetInterlaced, streamInfo.TargetRefFrames, streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, streamInfo.TargetVideoCodecTag); foreach (var contentFeature in contentFeatureList) { AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo); } var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken) .Where(subtitle => subtitle.DeliveryMethod == SubtitleDeliveryMethod.External) .ToList(); foreach (var subtitle in subtitleProfiles) { var subtitleAdded = AddSubtitleElement(writer, subtitle); if (subtitleAdded && _profile.EnableSingleSubtitleLimit) { break; } } }
private void AddVideoResource(XmlElement container, IHasMediaSources video, string deviceId, Filter filter, StreamInfo streamInfo = null) { if (streamInfo == null) { var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList(); streamInfo = new StreamBuilder(_logger).BuildVideoItem(new VideoOptions { ItemId = GetClientId(video), MediaSources = sources, Profile = _profile, DeviceId = deviceId, MaxBitrate = _profile.MaxStreamingBitrate }); } var targetWidth = streamInfo.TargetWidth; var targetHeight = streamInfo.TargetHeight; var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader(streamInfo.Container, streamInfo.VideoCodec, streamInfo.AudioCodec, targetWidth, targetHeight, streamInfo.TargetVideoBitDepth, streamInfo.TargetVideoBitrate, streamInfo.TargetTimestamp, streamInfo.IsDirectStream, streamInfo.RunTimeTicks, streamInfo.TargetVideoProfile, streamInfo.TargetVideoLevel, streamInfo.TargetFramerate, streamInfo.TargetPacketLength, streamInfo.TranscodeSeekInfo, streamInfo.IsTargetAnamorphic, streamInfo.IsTargetCabac, streamInfo.TargetRefFrames, streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, streamInfo.TargetVideoCodecTag); foreach (var contentFeature in contentFeatureList) { AddVideoResource(container, video, deviceId, filter, contentFeature, streamInfo); } foreach (var subtitle in streamInfo.GetSubtitleProfiles(false, _serverAddress, _accessToken)) { if (subtitle.DeliveryMethod == SubtitleDeliveryMethod.External) { var subtitleAdded = AddSubtitleElement(container, subtitle); if (subtitleAdded && _profile.EnableSingleSubtitleLimit) { break; } } } }
private async Task <bool> DownloadSubtitles(Video video, SubtitleOptions options, CancellationToken cancellationToken) { if ((options.DownloadEpisodeSubtitles && video is Episode) || (options.DownloadMovieSubtitles && video is Movie)) { var mediaStreams = _mediaSourceManager.GetStaticMediaSources(video, false).First().MediaStreams; var downloadedLanguages = await new SubtitleDownloader(_logger, _subtitleManager) .DownloadSubtitles(video, mediaStreams, options.SkipIfEmbeddedSubtitlesPresent, options.SkipIfAudioTrackMatches, options.RequirePerfectMatch, options.DownloadLanguages, cancellationToken).ConfigureAwait(false); // Rescan if (downloadedLanguages.Count > 0) { await video.RefreshMetadata(cancellationToken).ConfigureAwait(false); return(false); } return(true); } return(false); }
private PlaylistItem CreatePlaylistItem(BaseItem item, User user, long startPostionTicks, string mediaSourceId, int?audioStreamIndex, int?subtitleStreamIndex) { var deviceInfo = _device.Properties; var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()) ?? _dlnaManager.GetDefaultProfile(); var hasMediaSources = item as IHasMediaSources; var mediaSources = hasMediaSources != null ? (_mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList() : new List <MediaSourceInfo>(); var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex); playlistItem.StreamInfo.StartPositionTicks = startPostionTicks; playlistItem.StreamUrl = playlistItem.StreamInfo.ToDlnaUrl(_serverAddress, _accessToken); var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager) .GetItemDidl(item, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo); playlistItem.Didl = itemXml; return(playlistItem); }
public async Task <object> Get(GetSubtitle request) { if (string.Equals(request.Format, "js", StringComparison.OrdinalIgnoreCase)) { request.Format = "json"; } if (string.IsNullOrEmpty(request.Format)) { var item = (Video)_libraryManager.GetItemById(new Guid(request.Id)); var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false, null) .First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id)); var subtitleStream = mediaSource.MediaStreams .First(i => i.Type == MediaStreamType.Subtitle && i.Index == request.Index); return(await ResultFactory.GetStaticFileResult(Request, subtitleStream.Path).ConfigureAwait(false)); } using (var stream = await GetSubtitles(request).ConfigureAwait(false)) { using (var reader = new StreamReader(stream)) { var text = reader.ReadToEnd(); if (string.Equals(request.Format, "vtt", StringComparison.OrdinalIgnoreCase) && request.AddVttTimeMap) { text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000"); } return(ResultFactory.GetResult(text, MimeTypes.GetMimeType("file." + request.Format))); } } }
private async Task <IEnumerable <MediaSourceInfo> > GetMediaSourcesInternal(BaseItem item, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken) { IEnumerable <MediaSourceInfo> sources; var forceRequireOpening = false; try { if (activeRecordingInfo != null) { sources = await EmbyTV.EmbyTV.Current.GetRecordingStreamMediaSources(activeRecordingInfo, cancellationToken) .ConfigureAwait(false); } else { sources = await _liveTvManager.GetChannelMediaSources(item, cancellationToken) .ConfigureAwait(false); } } catch (NotImplementedException) { sources = _mediaSourceManager.GetStaticMediaSources(item, false); forceRequireOpening = true; } var list = sources.ToList(); var serverUrl = await _appHost.GetLocalApiUrl(cancellationToken).ConfigureAwait(false); foreach (var source in list) { source.Type = MediaSourceType.Default; source.BufferMs = source.BufferMs ?? 1500; if (source.RequiresOpening || forceRequireOpening) { source.RequiresOpening = true; } if (source.RequiresOpening) { var openKeys = new List <string>(); openKeys.Add(item.GetType().Name); openKeys.Add(item.Id.ToString("N")); openKeys.Add(source.Id ?? string.Empty); source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray()); } // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) { source.Path = serverUrl; } } _logger.LogDebug("MediaSources: {0}", _jsonSerializer.SerializeToString(list)); return(list); }
public async Task <ActionResult> GetSubtitle( [FromRoute, Required] Guid itemId, [FromRoute, Required] string?mediaSourceId, [FromRoute, Required] int index, [FromRoute, Required] string?format, [FromQuery] long?endPositionTicks, [FromQuery] bool copyTimestamps = false, [FromQuery] bool addVttTimeMap = false, [FromRoute, Required] long startPositionTicks = 0) { if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase)) { format = "json"; } if (string.IsNullOrEmpty(format)) { var item = (Video)_libraryManager.GetItemById(itemId); var idString = itemId.ToString("N", CultureInfo.InvariantCulture); var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false) .First(i => string.Equals(i.Id, mediaSourceId ?? idString, StringComparison.Ordinal)); var subtitleStream = mediaSource.MediaStreams .First(i => i.Type == MediaStreamType.Subtitle && i.Index == index); FileStream stream = new FileStream(subtitleStream.Path, FileMode.Open, FileAccess.Read); return(File(stream, MimeTypes.GetMimeType(subtitleStream.Path))); } if (string.Equals(format, "vtt", StringComparison.OrdinalIgnoreCase) && addVttTimeMap) { await using Stream stream = await EncodeSubtitles(itemId, mediaSourceId, index, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false); using var reader = new StreamReader(stream); var text = await reader.ReadToEndAsync().ConfigureAwait(false); text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000", StringComparison.Ordinal); return(File(Encoding.UTF8.GetBytes(text), MimeTypes.GetMimeType("file." + format))); } return(File( await EncodeSubtitles( itemId, mediaSourceId, index, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false), MimeTypes.GetMimeType("file." + format))); }
private async Task <IEnumerable <MediaSourceInfo> > GetMediaSourcesInternal(ILiveTvItem item, CancellationToken cancellationToken) { IEnumerable <MediaSourceInfo> sources; try { if (item is ILiveTvRecording) { sources = await _liveTvManager.GetRecordingMediaSources(item.Id.ToString("N"), cancellationToken) .ConfigureAwait(false); } else { sources = await _liveTvManager.GetChannelMediaSources(item.Id.ToString("N"), cancellationToken) .ConfigureAwait(false); } } catch (NotImplementedException) { var hasMediaSources = (IHasMediaSources)item; sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false) .ToList(); } var list = sources.ToList(); var serverUrl = _appHost.LocalApiUrl; foreach (var source in list) { source.Type = MediaSourceType.Default; source.RequiresOpening = true; source.BufferMs = source.BufferMs ?? 1500; var openKeys = new List <string>(); openKeys.Add(item.GetType().Name); openKeys.Add(item.Id.ToString("N")); openKeys.Add(source.Id ?? string.Empty); source.OpenToken = string.Join("|", openKeys.ToArray()); // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) { source.Path = serverUrl; } } _logger.Debug("MediaSources: {0}", _jsonSerializer.SerializeToString(list)); return(list); }
private async Task <IEnumerable <MediaSourceInfo> > GetMediaSourcesInternal(ILiveTvItem item, CancellationToken cancellationToken) { IEnumerable <MediaSourceInfo> sources; try { if (item is ILiveTvRecording) { sources = await _liveTvManager.GetRecordingMediaSources(item.Id.ToString("N"), cancellationToken) .ConfigureAwait(false); } else { sources = await _liveTvManager.GetChannelMediaSources(item.Id.ToString("N"), cancellationToken) .ConfigureAwait(false); } } catch (NotImplementedException) { var hasMediaSources = (IHasMediaSources)item; sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false) .ToList(); } var list = sources.ToList(); foreach (var source in list) { source.Type = MediaSourceType.Default; source.RequiresOpening = true; source.BufferMs = source.BufferMs ?? 1500; var openKeys = new List <string>(); openKeys.Add(item.GetType().Name); openKeys.Add(item.Id.ToString("N")); source.OpenToken = string.Join("|", openKeys.ToArray()); } _logger.Debug("MediaSources: {0}", _jsonSerializer.SerializeToString(list)); return(list); }
public object Get(GetSubtitle request) { if (string.Equals(request.Format, "js", StringComparison.OrdinalIgnoreCase)) { request.Format = "json"; } if (string.IsNullOrEmpty(request.Format)) { var item = (Video)_libraryManager.GetItemById(new Guid(request.Id)); var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false, null) .First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id)); var subtitleStream = mediaSource.MediaStreams .First(i => i.Type == MediaStreamType.Subtitle && i.Index == request.Index); return(ToStaticFileResult(subtitleStream.Path)); } var stream = GetSubtitles(request).Result; return(ResultFactory.GetResult(stream, MimeTypes.GetMimeType("file." + request.Format))); }
private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, SyncOptions syncOptions, IProgress <double> progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetVideoOptions(jobItem, job); var conversionOptions = new VideoOptions { Profile = jobOptions.DeviceProfile }; conversionOptions.DeviceId = jobItem.TargetId; conversionOptions.Context = EncodingContext.Static; conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); var streamInfo = new StreamBuilder(_logger).BuildVideoItem(conversionOptions); var mediaSource = streamInfo.MediaSource; // No sense creating external subs if we're already burning one into the video var externalSubs = streamInfo.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode ? new List <SubtitleStreamInfo>() : streamInfo.GetExternalSubtitles(false, true, null, null); // Mark as requiring conversion if transcoding the video, or if any subtitles need to be extracted var requiresVideoTranscoding = streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting; var requiresConversion = requiresVideoTranscoding || externalSubs.Any(i => RequiresExtraction(i, mediaSource)); if (requiresConversion && !enableConversion) { return; } jobItem.MediaSourceId = streamInfo.MediaSourceId; jobItem.TemporaryPath = GetTemporaryPath(jobItem); if (requiresConversion) { jobItem.Status = SyncJobItemStatus.Converting; } if (requiresVideoTranscoding) { // Save the job item now since conversion could take a while await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); try { var lastJobUpdate = DateTime.MinValue; var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(async pct => { progress.Report(pct); if ((DateTime.UtcNow - lastJobUpdate).TotalSeconds >= DatabaseProgressUpdateIntervalSeconds) { jobItem.Progress = pct / 2; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); } }); jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { OutputDirectory = jobItem.TemporaryPath, CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit, ReadInputAtNativeFramerate = !syncOptions.EnableFullSpeedTranscoding }, innerProgress, cancellationToken); } catch (OperationCanceledException) { jobItem.Status = SyncJobItemStatus.Queued; jobItem.Progress = 0; } catch (Exception ex) { jobItem.Status = SyncJobItemStatus.Failed; _logger.ErrorException("Error during sync transcoding", ex); } if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued) { await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); return; } jobItem.MediaSource = await GetEncodedMediaSource(jobItem.OutputPath, user, true).ConfigureAwait(false); } else { if (mediaSource.Protocol == MediaProtocol.File) { jobItem.OutputPath = mediaSource.Path; } else if (mediaSource.Protocol == MediaProtocol.Http) { jobItem.OutputPath = await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false); } else { throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } jobItem.MediaSource = mediaSource; } jobItem.MediaSource.SupportsTranscoding = false; if (externalSubs.Count > 0) { // Save the job item now since conversion could take a while await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await ConvertSubtitles(jobItem, externalSubs, streamInfo, cancellationToken).ConfigureAwait(false); } jobItem.Progress = 50; jobItem.Status = SyncJobItemStatus.ReadyToTransfer; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); }
private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) { var dto = new BaseItemDto { ServerId = _appHost.SystemId }; if (item.SourceType == SourceType.Channel) { dto.SourceType = item.SourceType.ToString(); } if (options.ContainsField(ItemFields.People)) { AttachPeople(dto, item); } if (options.ContainsField(ItemFields.PrimaryImageAspectRatio)) { try { AttachPrimaryImageAspectRatio(dto, item); } catch (Exception ex) { // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions _logger.LogError(ex, "Error generating PrimaryImageAspectRatio for {itemName}", item.Name); } } if (options.ContainsField(ItemFields.DisplayPreferencesId)) { dto.DisplayPreferencesId = item.DisplayPreferencesId.ToString("N", CultureInfo.InvariantCulture); } if (user != null) { AttachUserSpecificInfo(dto, item, user, options); } if (item is IHasMediaSources && options.ContainsField(ItemFields.MediaSources)) { dto.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, true, user).ToArray(); NormalizeMediaSourceContainers(dto); } if (options.ContainsField(ItemFields.Studios)) { AttachStudios(dto, item); } AttachBasicFields(dto, item, owner, options); if (options.ContainsField(ItemFields.CanDelete)) { dto.CanDelete = user == null ? item.CanDelete() : item.CanDelete(user); } if (options.ContainsField(ItemFields.CanDownload)) { dto.CanDownload = user == null ? item.CanDownload() : item.CanDownload(user); } if (options.ContainsField(ItemFields.Etag)) { dto.Etag = item.GetEtag(user); } var liveTvManager = LivetvManager; var activeRecording = liveTvManager.GetActiveRecordingInfo(item.Path); if (activeRecording != null) { dto.Type = "Recording"; dto.CanDownload = false; dto.RunTimeTicks = null; if (!string.IsNullOrEmpty(dto.SeriesName)) { dto.EpisodeTitle = dto.Name; dto.Name = dto.SeriesName; } liveTvManager.AddInfoToRecordingDto(item, dto, activeRecording, user); } return(dto); }