/// <inheritdoc />
        public async Task <(MediaAttachment attachment, Stream stream)> GetAttachment(BaseItem item, string mediaSourceId, int attachmentStreamIndex, CancellationToken cancellationToken)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (string.IsNullOrWhiteSpace(mediaSourceId))
            {
                throw new ArgumentNullException(nameof(mediaSourceId));
            }

            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, null, true, false, cancellationToken).ConfigureAwait(false);

            var mediaSource = mediaSources
                              .FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));

            if (mediaSource == null)
            {
                throw new ResourceNotFoundException($"MediaSource {mediaSourceId} not found");
            }

            var mediaAttachment = mediaSource.MediaAttachments
                                  .FirstOrDefault(i => i.Index == attachmentStreamIndex);

            if (mediaAttachment == null)
            {
                throw new ResourceNotFoundException($"MediaSource {mediaSourceId} has no attachment with stream index {attachmentStreamIndex}");
            }

            var attachmentStream = await GetAttachmentStream(mediaSource, mediaAttachment, cancellationToken)
                                   .ConfigureAwait(false);

            return(mediaAttachment, attachmentStream);
        }
Exemple #2
0
        private async Task <Tuple <Stream, string> > GetSubtitleStream(string itemId,
                                                                       string mediaSourceId,
                                                                       int subtitleStreamIndex,
                                                                       CancellationToken cancellationToken)
        {
            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(itemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);

            var mediaSource = mediaSources
                              .First(i => string.Equals(i.Id, mediaSourceId));

            var subtitleStream = mediaSource.MediaStreams
                                 .First(i => i.Type == MediaStreamType.Subtitle && i.Index == subtitleStreamIndex);

            var inputFiles = new[] { mediaSource.Path };

            if (mediaSource.VideoType.HasValue)
            {
                if (mediaSource.VideoType.Value == VideoType.BluRay ||
                    mediaSource.VideoType.Value == VideoType.Dvd)
                {
                    var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSourceId));
                    inputFiles = mediaSourceItem.GetPlayableStreamFiles().ToArray();
                }
            }

            var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false);

            var stream = await GetSubtitleStream(fileInfo.Item1, fileInfo.Item2, fileInfo.Item4, cancellationToken).ConfigureAwait(false);

            return(new Tuple <Stream, string>(stream, fileInfo.Item3));
        }
        private async Task <PlaybackInfoResponse> GetPlaybackInfo(Guid id, Guid userId, string[] supportedLiveMediaTypes, string mediaSourceId = null, string liveStreamId = null)
        {
            var user   = _userManager.GetUserById(userId);
            var item   = _libraryManager.GetItemById(id);
            var result = new PlaybackInfoResponse();

            if (string.IsNullOrWhiteSpace(liveStreamId))
            {
                IEnumerable <MediaSourceInfo> mediaSources;
                try
                {
                    // TODO handle supportedLiveMediaTypes ?
                    mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, user, true, false, CancellationToken.None).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    mediaSources = new List <MediaSourceInfo>();
                    _logger.LogError(ex, "Could not find media sources for item id {id}", id);
                    // TODO PlaybackException ??
                    //result.ErrorCode = ex.ErrorCode;
                }

                result.MediaSources = mediaSources.ToArray();

                if (!string.IsNullOrWhiteSpace(mediaSourceId))
                {
                    result.MediaSources = result.MediaSources
                                          .Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase))
                                          .ToArray();
                }
            }
            else
            {
                var mediaSource = await _mediaSourceManager.GetLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false);

                result.MediaSources = new MediaSourceInfo[] { mediaSource };
            }

            if (result.MediaSources.Length == 0)
            {
                if (!result.ErrorCode.HasValue)
                {
                    result.ErrorCode = PlaybackErrorCode.NoCompatibleStream;
                }
            }
            else
            {
                result.MediaSources = Clone(result.MediaSources);

                result.PlaySessionId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
            }

            return(result);
        }
Exemple #4
0
        private async Task <PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, string[] supportedLiveMediaTypes, string mediaSourceId = null, string liveStreamId = null)
        {
            var result = new PlaybackInfoResponse();

            if (string.IsNullOrWhiteSpace(liveStreamId))
            {
                IEnumerable <MediaSourceInfo> mediaSources;
                try
                {
                    mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, supportedLiveMediaTypes, CancellationToken.None).ConfigureAwait(false);
                }
                catch (PlaybackException ex)
                {
                    mediaSources     = new List <MediaSourceInfo>();
                    result.ErrorCode = ex.ErrorCode;
                }

                result.MediaSources = mediaSources.ToList();

                if (!string.IsNullOrWhiteSpace(mediaSourceId))
                {
                    result.MediaSources = result.MediaSources
                                          .Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase))
                                          .ToList();
                }
            }
            else
            {
                var mediaSource = await _mediaSourceManager.GetLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false);

                result.MediaSources = new List <MediaSourceInfo> {
                    mediaSource
                };
            }

            if (result.MediaSources.Count == 0)
            {
                if (!result.ErrorCode.HasValue)
                {
                    result.ErrorCode = PlaybackErrorCode.NoCompatibleStream;
                }
            }
            else
            {
                result.MediaSources = Clone(result.MediaSources);

                result.PlaySessionId = Guid.NewGuid().ToString("N");
            }

            return(result);
        }
Exemple #5
0
        public async Task <Stream> GetSubtitles(string itemId,
                                                string mediaSourceId,
                                                int subtitleStreamIndex,
                                                string outputFormat,
                                                long startTimeTicks,
                                                long?endTimeTicks,
                                                bool preserveOriginalTimestamps,
                                                CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(itemId))
            {
                throw new ArgumentNullException("itemId");
            }
            if (string.IsNullOrWhiteSpace(mediaSourceId))
            {
                throw new ArgumentNullException("mediaSourceId");
            }

            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(itemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);

            var mediaSource = mediaSources
                              .First(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));

            var subtitleStream = mediaSource.MediaStreams
                                 .First(i => i.Type == MediaStreamType.Subtitle && i.Index == subtitleStreamIndex);

            var subtitle = await GetSubtitleStream(mediaSource, subtitleStream, cancellationToken)
                           .ConfigureAwait(false);

            var inputFormat = subtitle.Item2;
            var writer      = TryGetWriter(outputFormat);

            // Return the original if we don't have any way of converting it
            if (writer == null)
            {
                return(subtitle.Item1);
            }

            // Return the original if the same format is being requested
            // Character encoding was already handled in GetSubtitleStream
            if (string.Equals(inputFormat, outputFormat, StringComparison.OrdinalIgnoreCase))
            {
                return(subtitle.Item1);
            }

            using (var stream = subtitle.Item1)
            {
                return(ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps, cancellationToken));
            }
        }
Exemple #6
0
        async Task <Stream> ISubtitleEncoder.GetSubtitles(BaseItem item, string mediaSourceId, int subtitleStreamIndex, string outputFormat, long startTimeTicks, long endTimeTicks, bool preserveOriginalTimestamps, CancellationToken cancellationToken)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }
            if (string.IsNullOrWhiteSpace(mediaSourceId))
            {
                throw new ArgumentNullException(nameof(mediaSourceId));
            }

            // TODO network path substition useful ?
            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, null, true, true, cancellationToken).ConfigureAwait(false);

            var mediaSource = mediaSources
                              .First(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));

            var subtitleStream = mediaSource.MediaStreams
                                 .First(i => i.Type == MediaStreamType.Subtitle && i.Index == subtitleStreamIndex);

            var subtitle = await GetSubtitleStream(mediaSource, subtitleStream, cancellationToken)
                           .ConfigureAwait(false);

            var inputFormat = subtitle.format;
            var writer      = TryGetWriter(outputFormat);

            // Return the original if we don't have any way of converting it
            if (writer == null)
            {
                return(subtitle.stream);
            }

            // Return the original if the same format is being requested
            // Character encoding was already handled in GetSubtitleStream
            if (string.Equals(inputFormat, outputFormat, StringComparison.OrdinalIgnoreCase))
            {
                return(subtitle.stream);
            }

            using (var stream = subtitle.stream)
            {
                return(ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps, cancellationToken));
            }
        }
        private async Task <object> GetPlaybackInfo(string id, string userId)
        {
            IEnumerable <MediaSourceInfo> mediaSources;
            var result = new LiveMediaInfoResult();

            try
            {
                mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false);
            }
            catch (PlaybackException ex)
            {
                mediaSources     = new List <MediaSourceInfo>();
                result.ErrorCode = ex.ErrorCode;
            }

            result.MediaSources = mediaSources.ToList();

            return(ToOptimizedResult(result));
        }
Exemple #8
0
        public async Task <EncodingJob> CreateJob(EncodingJobOptions options, bool isVideoRequest, IProgress <double> progress, CancellationToken cancellationToken)
        {
            var request = options;

            if (string.IsNullOrEmpty(request.AudioCodec))
            {
                request.AudioCodec = InferAudioCodec(request.OutputContainer);
            }

            var state = new EncodingJob(_logger, _mediaSourceManager)
            {
                Options        = options,
                IsVideoRequest = isVideoRequest,
                Progress       = progress
            };

            if (!string.IsNullOrWhiteSpace(request.AudioCodec))
            {
                state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
                request.AudioCodec         = state.SupportedAudioCodecs.FirstOrDefault();
            }

            var item = _libraryManager.GetItemById(request.ItemId);

            state.ItemType = item.GetType().Name;

            state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);

            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);

            var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
               ? mediaSources.First()
               : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));

            var videoRequest = state.Options;

            AttachMediaSourceInfo(state, mediaSource, videoRequest);

            //var container = Path.GetExtension(state.RequestedUrl);

            //if (string.IsNullOrEmpty(container))
            //{
            //    container = request.Static ?
            //        state.InputContainer :
            //        (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.');
            //}

            //state.OutputContainer = (container ?? string.Empty).TrimStart('.');

            state.OutputAudioBitrate    = GetAudioBitrateParam(state.Options, state.AudioStream);
            state.OutputAudioSampleRate = request.AudioSampleRate;

            state.OutputAudioCodec = state.Options.AudioCodec;

            state.OutputAudioChannels = GetNumAudioChannelsParam(state.Options, state.AudioStream, state.OutputAudioCodec);

            if (videoRequest != null)
            {
                state.OutputVideoCodec   = state.Options.VideoCodec;
                state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream);

                if (state.OutputVideoBitrate.HasValue)
                {
                    var resolution = ResolutionNormalizer.Normalize(
                        state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
                        state.OutputVideoBitrate.Value,
                        state.VideoStream == null ? null : state.VideoStream.Codec,
                        state.OutputVideoCodec,
                        videoRequest.MaxWidth,
                        videoRequest.MaxHeight);

                    videoRequest.MaxWidth  = resolution.MaxWidth;
                    videoRequest.MaxHeight = resolution.MaxHeight;
                }
            }

            ApplyDeviceProfileSettings(state);

            if (videoRequest != null)
            {
                TryStreamCopy(state, videoRequest);
            }

            //state.OutputFilePath = GetOutputFilePath(state);

            return(state);
        }
Exemple #9
0
        public async Task <EncodingJob> CreateJob(EncodingJobOptions options, EncodingHelper encodingHelper, bool isVideoRequest, IProgress <double> progress, CancellationToken cancellationToken)
        {
            var request = options;

            if (string.IsNullOrEmpty(request.AudioCodec))
            {
                request.AudioCodec = InferAudioCodec(request.Container);
            }

            var state = new EncodingJob(_logger, _mediaSourceManager)
            {
                Options        = options,
                IsVideoRequest = isVideoRequest,
                Progress       = progress
            };

            if (!string.IsNullOrWhiteSpace(request.VideoCodec))
            {
                state.SupportedVideoCodecs = request.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
                request.VideoCodec         = state.SupportedVideoCodecs.FirstOrDefault();
            }

            if (!string.IsNullOrWhiteSpace(request.AudioCodec))
            {
                state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
                request.AudioCodec         = state.SupportedAudioCodecs.FirstOrDefault();
            }

            if (!string.IsNullOrWhiteSpace(request.SubtitleCodec))
            {
                state.SupportedSubtitleCodecs = request.SubtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
                request.SubtitleCodec         = state.SupportedSubtitleCodecs.FirstOrDefault(i => _mediaEncoder.CanEncodeToSubtitleCodec(i))
                                                ?? state.SupportedSubtitleCodecs.FirstOrDefault();
            }

            var item = _libraryManager.GetItemById(request.Id);

            state.ItemType = item.GetType().Name;

            state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);

            // TODO
            // var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ??
            //                    item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null);

            // if (primaryImage != null)
            // {
            //     state.AlbumCoverPath = primaryImage.Path;
            // }

            // TODO network path substition useful ?
            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, null, true, true, cancellationToken).ConfigureAwait(false);

            var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
               ? mediaSources.First()
               : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));

            var videoRequest = state.Options;

            encodingHelper.AttachMediaSourceInfo(state, mediaSource, null);

            //var container = Path.GetExtension(state.RequestedUrl);

            //if (string.IsNullOrEmpty(container))
            //{
            //    container = request.Static ?
            //        state.InputContainer :
            //        (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.');
            //}

            //state.OutputContainer = (container ?? string.Empty).TrimStart('.');

            state.OutputAudioBitrate = encodingHelper.GetAudioBitrateParam(state.Options, state.AudioStream);

            state.OutputAudioCodec = state.Options.AudioCodec;

            state.OutputAudioChannels = encodingHelper.GetNumAudioChannelsParam(state, state.AudioStream, state.OutputAudioCodec);

            if (videoRequest != null)
            {
                state.OutputVideoCodec   = state.Options.VideoCodec;
                state.OutputVideoBitrate = encodingHelper.GetVideoBitrateParamValue(state.Options, state.VideoStream, state.OutputVideoCodec);

                if (state.OutputVideoBitrate.HasValue)
                {
                    var resolution = ResolutionNormalizer.Normalize(
                        state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
                        state.VideoStream == null ? (int?)null : state.VideoStream.Width,
                        state.VideoStream == null ? (int?)null : state.VideoStream.Height,
                        state.OutputVideoBitrate.Value,
                        state.VideoStream == null ? null : state.VideoStream.Codec,
                        state.OutputVideoCodec,
                        videoRequest.MaxWidth,
                        videoRequest.MaxHeight);

                    videoRequest.MaxWidth  = resolution.MaxWidth;
                    videoRequest.MaxHeight = resolution.MaxHeight;
                }
            }

            ApplyDeviceProfileSettings(state);

            if (videoRequest != null)
            {
                encodingHelper.TryStreamCopy(state);
            }

            //state.OutputFilePath = GetOutputFilePath(state);

            return(state);
        }
        public async Task <EncodingJob> CreateJob(EncodingJobOptions options, bool isVideoRequest, IProgress <double> progress, CancellationToken cancellationToken)
        {
            var request = options;

            if (string.IsNullOrEmpty(request.AudioCodec))
            {
                request.AudioCodec = InferAudioCodec(request.OutputContainer);
            }

            var state = new EncodingJob(_logger, _mediaSourceManager)
            {
                Options        = options,
                IsVideoRequest = isVideoRequest,
                Progress       = progress
            };

            if (!string.IsNullOrWhiteSpace(request.AudioCodec))
            {
                state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
                request.AudioCodec         = state.SupportedAudioCodecs.FirstOrDefault();
            }

            var item = _libraryManager.GetItemById(request.ItemId);

            state.ItemType = item.GetType().Name;

            state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);

            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);

            var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
               ? mediaSources.First()
               : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));

            AttachMediaStreamInfo(state, mediaSource, options);

            state.OutputAudioBitrate    = GetAudioBitrateParam(request, state.AudioStream);
            state.OutputAudioSampleRate = request.AudioSampleRate;

            state.OutputAudioCodec = GetAudioCodec(request);

            state.OutputAudioChannels = GetNumAudioChannelsParam(request, state.AudioStream, state.OutputAudioCodec);

            if (isVideoRequest)
            {
                state.OutputVideoCodec   = GetVideoCodec(request);
                state.OutputVideoBitrate = GetVideoBitrateParamValue(request, state.VideoStream);

                if (state.OutputVideoBitrate.HasValue)
                {
                    var resolution = ResolutionNormalizer.Normalize(state.OutputVideoBitrate.Value,
                                                                    state.OutputVideoCodec,
                                                                    request.MaxWidth,
                                                                    request.MaxHeight);

                    request.MaxWidth  = resolution.MaxWidth;
                    request.MaxHeight = resolution.MaxHeight;
                }
            }

            ApplyDeviceProfileSettings(state);

            TryStreamCopy(state, request);

            state.Quality = options.Context == EncodingContext.Static ?
                            EncodingQuality.MaxQuality :
                            GetQualitySetting();

            return(state);
        }
Exemple #11
0
        public async Task <EncodingJob> CreateJob(EncodingJobOptions options, bool isVideoRequest, IProgress <double> progress, CancellationToken cancellationToken)
        {
            var request = options;

            if (string.IsNullOrEmpty(request.AudioCodec))
            {
                request.AudioCodec = InferAudioCodec(request.OutputContainer);
            }

            var state = new EncodingJob(_logger, _liveTvManager)
            {
                Options        = options,
                IsVideoRequest = isVideoRequest,
                Progress       = progress
            };

            if (!string.IsNullOrWhiteSpace(request.AudioCodec))
            {
                state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
                request.AudioCodec         = state.SupportedAudioCodecs.FirstOrDefault();
            }

            var item = _libraryManager.GetItemById(request.ItemId);

            List <MediaStream> mediaStreams = null;

            state.ItemType = item.GetType().Name;

            if (item is ILiveTvRecording)
            {
                var recording = await _liveTvManager.GetInternalRecording(request.ItemId, cancellationToken).ConfigureAwait(false);

                state.VideoType    = VideoType.VideoFile;
                state.IsInputVideo = string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);

                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);

                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 <MediaStream>();

                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);

            state.OutputAudioBitrate    = GetAudioBitrateParam(request, state.AudioStream);
            state.OutputAudioSampleRate = request.AudioSampleRate;

            state.OutputAudioCodec = GetAudioCodec(request);

            state.OutputAudioChannels = GetNumAudioChannelsParam(request, state.AudioStream, state.OutputAudioCodec);

            if (isVideoRequest)
            {
                state.OutputVideoCodec   = GetVideoCodec(request);
                state.OutputVideoBitrate = GetVideoBitrateParamValue(request, state.VideoStream);

                if (state.OutputVideoBitrate.HasValue)
                {
                    var resolution = ResolutionNormalizer.Normalize(state.OutputVideoBitrate.Value,
                                                                    state.OutputVideoCodec,
                                                                    request.MaxWidth,
                                                                    request.MaxHeight);

                    request.MaxWidth  = resolution.MaxWidth;
                    request.MaxHeight = resolution.MaxHeight;
                }
            }

            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";
                }
            }

            return(state);
        }