Beispiel #1
0
        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;
                }
            }
        }
Beispiel #2
0
        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;
                    }
                }
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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)));
                }
            }
        }
Beispiel #6
0
        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);
        }
Beispiel #10
0
        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)));
        }
Beispiel #11
0
        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);
        }
Beispiel #12
0
        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);
        }