private string GetDlnaHeaders(PlaylistItem item)
        {
            var profile    = item.Profile;
            var streamInfo = item.StreamInfo;

            if (streamInfo.MediaType == DlnaProfileType.Audio)
            {
                return(new ContentFeatureBuilder(profile)
                       .BuildAudioHeader(
                           streamInfo.Container,
                           streamInfo.TargetAudioCodec.FirstOrDefault(),
                           streamInfo.TargetAudioBitrate,
                           streamInfo.TargetAudioSampleRate,
                           streamInfo.TargetAudioChannels,
                           streamInfo.TargetAudioBitDepth,
                           streamInfo.IsDirectStream,
                           streamInfo.RunTimeTicks ?? 0,
                           streamInfo.TranscodeSeekInfo));
            }

            if (streamInfo.MediaType == DlnaProfileType.Video)
            {
                var list = new ContentFeatureBuilder(profile)
                           .BuildVideoHeader(
                    streamInfo.Container,
                    streamInfo.TargetVideoCodec.FirstOrDefault(),
                    streamInfo.TargetAudioCodec.FirstOrDefault(),
                    streamInfo.TargetWidth,
                    streamInfo.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,
                    streamInfo.IsTargetAVC);

                return(list.Count == 0 ? null : list[0]);
            }

            return(null);
        }
Exemple #2
0
        private void AddVideoResource(XmlElement container, IHasMediaSources video, string deviceId, Filter filter, StreamInfo streamInfo = null)
        {
            if (streamInfo == null)
            {
                var sources = _user == null?video.GetMediaSources(true).ToList() : video.GetMediaSources(true, _user).ToList();

                streamInfo = new StreamBuilder().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.TargetAudioChannels,
                                                                                          streamInfo.TargetAudioBitrate,
                                                                                          streamInfo.TargetTimestamp,
                                                                                          streamInfo.IsDirectStream,
                                                                                          streamInfo.RunTimeTicks,
                                                                                          streamInfo.TargetVideoProfile,
                                                                                          streamInfo.TargetVideoLevel,
                                                                                          streamInfo.TargetFramerate,
                                                                                          streamInfo.TargetPacketLength,
                                                                                          streamInfo.TranscodeSeekInfo,
                                                                                          streamInfo.IsTargetAnamorphic,
                                                                                          streamInfo.IsTargetCabac,
                                                                                          streamInfo.TargetRefFrames);

            foreach (var contentFeature in contentFeatureList)
            {
                AddVideoResource(container, video, deviceId, filter, contentFeature, streamInfo);
            }

            foreach (var subtitle in streamInfo.GetExternalSubtitles(_serverAddress, false))
            {
                AddSubtitleElement(container, subtitle);
            }
        }
Exemple #3
0
        private void AddImageResElement(
            BaseItem item,
            XmlWriter writer,
            int maxWidth,
            int maxHeight,
            string format,
            string org_Pn)
        {
            var imageInfo = GetImageInfo(item);

            if (imageInfo == null)
            {
                return;
            }

            var albumartUrlInfo = GetImageUrl(imageInfo, maxWidth, maxHeight, format);

            writer.WriteStartElement(string.Empty, "res", NsDidl);

            // Images must have a reported size or many clients (Bubble upnp), will only use the first thumbnail
            // rather than using a larger one when available
            var width  = albumartUrlInfo.width ?? maxWidth;
            var height = albumartUrlInfo.height ?? maxHeight;

            var contentFeatures = new ContentFeatureBuilder(_profile)
                                  .BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn);

            writer.WriteAttributeString(
                "protocolInfo",
                string.Format(
                    CultureInfo.InvariantCulture,
                    "http-get:*:{0}:{1}",
                    MimeTypes.GetMimeType("file." + format),
                    contentFeatures));

            writer.WriteAttributeString(
                "resolution",
                string.Format(CultureInfo.InvariantCulture, "{0}x{1}", width, height));

            writer.WriteString(albumartUrlInfo.url);

            writer.WriteFullEndElement();
        }
Exemple #4
0
        private void AddImageResElement(BaseItem item,
                                        XmlElement element,
                                        int maxWidth,
                                        int maxHeight,
                                        int playbackPercentage,
                                        int unplayedCount,
                                        string format,
                                        string org_Pn)
        {
            var imageInfo = GetImageInfo(item);

            if (imageInfo == null)
            {
                return;
            }

            var result = element.OwnerDocument;

            var albumartUrlInfo = GetImageUrl(imageInfo, maxWidth, maxHeight, playbackPercentage, unplayedCount, format);

            var res = result.CreateElement(string.Empty, "res", NS_DIDL);

            res.InnerText = albumartUrlInfo.Url;

            var width  = albumartUrlInfo.Width;
            var height = albumartUrlInfo.Height;

            var contentFeatures = new ContentFeatureBuilder(_profile)
                                  .BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn);

            res.SetAttribute("protocolInfo", String.Format(
                                 "http-get:*:{0}:{1}",
                                 MimeTypes.GetMimeType("file." + format),
                                 contentFeatures
                                 ));

            if (width.HasValue && height.HasValue)
            {
                res.SetAttribute("resolution", string.Format("{0}x{1}", width.Value, height.Value));
            }

            element.AppendChild(res);
        }
Exemple #5
0
        private void AddImageResElement(BaseItem item,
                                        XmlWriter writer,
                                        int maxWidth,
                                        int maxHeight,
                                        int playbackPercentage,
                                        int unplayedCount,
                                        string format,
                                        string org_Pn)
        {
            var imageInfo = GetImageInfo(item);

            if (imageInfo == null)
            {
                return;
            }

            var albumartUrlInfo = GetImageUrl(imageInfo, maxWidth, maxHeight, playbackPercentage, unplayedCount, format);

            writer.WriteStartElement(string.Empty, "res", NS_DIDL);

            var width  = albumartUrlInfo.Width;
            var height = albumartUrlInfo.Height;

            var contentFeatures = new ContentFeatureBuilder(_profile)
                                  .BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn);

            writer.WriteAttributeString("protocolInfo", String.Format(
                                            "http-get:*:{0}:{1}",
                                            GetMimeType("file." + format),
                                            contentFeatures
                                            ));

            if (width.HasValue && height.HasValue)
            {
                writer.WriteAttributeString("resolution", string.Format("{0}x{1}", width.Value, height.Value));
            }

            writer.WriteString(albumartUrlInfo.Url);

            writer.WriteFullEndElement();
        }
Exemple #6
0
        private void AddAudioResource(DlnaOptions options, XmlWriter writer, IHasMediaSources audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
        {
            writer.WriteStartElement(string.Empty, "res", NS_DIDL);

            if (streamInfo == null)
            {
                var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user);

                streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
                {
                    ItemId       = GetClientId(audio),
                    MediaSources = sources.ToArray(sources.Count),
                    Profile      = _profile,
                    DeviceId     = deviceId
                });
            }

            var url = streamInfo.ToDlnaUrl(_serverAddress, _accessToken);

            var mediaSource = streamInfo.MediaSource;

            if (mediaSource.RunTimeTicks.HasValue)
            {
                writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
            }

            if (filter.Contains("res@size"))
            {
                if (streamInfo.IsDirectStream || streamInfo.EstimateContentLength)
                {
                    var size = streamInfo.TargetSize;

                    if (size.HasValue)
                    {
                        writer.WriteAttributeString("size", size.Value.ToString(_usCulture));
                    }
                }
            }

            var targetAudioBitrate  = streamInfo.TargetAudioBitrate;
            var targetSampleRate    = streamInfo.TargetAudioSampleRate;
            var targetChannels      = streamInfo.TargetAudioChannels;
            var targetAudioBitDepth = streamInfo.TargetAudioBitDepth;

            if (targetChannels.HasValue)
            {
                writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
            }

            if (targetSampleRate.HasValue)
            {
                writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
            }

            if (targetAudioBitrate.HasValue)
            {
                writer.WriteAttributeString("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
            }

            var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
                                                             streamInfo.TargetAudioCodec,
                                                             targetChannels,
                                                             targetAudioBitrate,
                                                             targetSampleRate,
                                                             targetAudioBitDepth);

            var filename = url.Substring(0, url.IndexOf('?'));

            var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
                ? GetMimeType(filename)
                : mediaProfile.MimeType;

            var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader(streamInfo.Container,
                                                                                       streamInfo.TargetAudioCodec,
                                                                                       targetAudioBitrate,
                                                                                       targetSampleRate,
                                                                                       targetChannels,
                                                                                       targetAudioBitDepth,
                                                                                       streamInfo.IsDirectStream,
                                                                                       streamInfo.RunTimeTicks,
                                                                                       streamInfo.TranscodeSeekInfo);

            writer.WriteAttributeString("protocolInfo", String.Format(
                                            "http-get:*:{0}:{1}",
                                            mimeType,
                                            contentFeatures
                                            ));

            writer.WriteString(url);

            writer.WriteFullEndElement();
        }
Exemple #7
0
        private void AddVideoResource(DlnaOptions options, XmlWriter writer, IHasMediaSources 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       = GetClientId(video),
                    MediaSources = sources.ToArray(sources.Count),
                    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,
                                                                                          streamInfo.TargetAudioCodec,
                                                                                          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.IsTargetInterlaced,
                                                                                          streamInfo.TargetRefFrames,
                                                                                          streamInfo.TargetVideoStreamCount,
                                                                                          streamInfo.TargetAudioStreamCount,
                                                                                          streamInfo.TargetVideoCodecTag,
                                                                                          streamInfo.IsTargetAVC);

            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;
                }
            }
        }
Exemple #8
0
        /// <summary>
        /// Adds the dlna headers.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="responseHeaders">The response headers.</param>
        /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
        /// <param name="startTimeTicks">The start time in ticks.</param>
        /// <param name="request">The <see cref="HttpRequest"/>.</param>
        /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
        public static void AddDlnaHeaders(
            StreamState state,
            IHeaderDictionary responseHeaders,
            bool isStaticallyStreamed,
            long?startTimeTicks,
            HttpRequest request,
            IDlnaManager dlnaManager)
        {
            if (!state.EnableDlnaHeaders)
            {
                return;
            }

            var profile = state.DeviceProfile;

            StringValues transferMode = request.Headers["transferMode.dlna.org"];

            responseHeaders.Add("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode.ToString());
            responseHeaders.Add("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*");

            if (state.RunTimeTicks.HasValue)
            {
                if (string.Equals(request.Headers["getMediaInfo.sec"], "1", StringComparison.OrdinalIgnoreCase))
                {
                    var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds;
                    responseHeaders.Add("MediaInfo.sec", string.Format(
                                            CultureInfo.InvariantCulture,
                                            "SEC_Duration={0};",
                                            Convert.ToInt32(ms)));
                }

                if (!isStaticallyStreamed && profile != null)
                {
                    AddTimeSeekResponseHeaders(state, responseHeaders, startTimeTicks);
                }
            }

            profile ??= dlnaManager.GetDefaultProfile();

            var audioCodec = state.ActualOutputAudioCodec;

            if (!state.IsVideoRequest)
            {
                responseHeaders.Add("contentFeatures.dlna.org", ContentFeatureBuilder.BuildAudioHeader(
                                        profile,
                                        state.OutputContainer,
                                        audioCodec,
                                        state.OutputAudioBitrate,
                                        state.OutputAudioSampleRate,
                                        state.OutputAudioChannels,
                                        state.OutputAudioBitDepth,
                                        isStaticallyStreamed,
                                        state.RunTimeTicks,
                                        state.TranscodeSeekInfo));
            }
            else
            {
                var videoCodec = state.ActualOutputVideoCodec;

                responseHeaders.Add(
                    "contentFeatures.dlna.org",
                    ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty);
            }
        }
Exemple #9
0
        private void AddAudioResource(XmlElement container, Audio audio, string deviceId, Filter filter)
        {
            var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL);

            var sources = _dtoService.GetMediaSources(audio);

            var streamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions
            {
                ItemId       = audio.Id.ToString("N"),
                MediaSources = sources,
                Profile      = _profile,
                DeviceId     = deviceId
            });

            var url = streamInfo.ToDlnaUrl(_serverAddress);

            //res.AppendChild(container.OwnerDocument.CreateCDataSection(url));
            res.InnerText = url;

            var mediaSource = sources.First(i => string.Equals(i.Id, streamInfo.MediaSourceId));

            if (mediaSource.RunTimeTicks.HasValue)
            {
                res.SetAttribute("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
            }

            if (filter.Contains("res@size"))
            {
                if (streamInfo.IsDirectStream || streamInfo.EstimateContentLength)
                {
                    var size = streamInfo.TargetSize;

                    if (size.HasValue)
                    {
                        res.SetAttribute("size", size.Value.ToString(_usCulture));
                    }
                }
            }

            var targetAudioBitrate = streamInfo.TargetAudioBitrate;
            var targetSampleRate   = streamInfo.TargetAudioSampleRate;
            var targetChannels     = streamInfo.TargetAudioChannels;

            if (targetChannels.HasValue)
            {
                res.SetAttribute("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
            }

            if (targetSampleRate.HasValue)
            {
                res.SetAttribute("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
            }

            if (targetAudioBitrate.HasValue)
            {
                res.SetAttribute("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
            }

            var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
                                                             streamInfo.AudioCodec,
                                                             targetChannels,
                                                             targetAudioBitrate);

            var filename = url.Substring(0, url.IndexOf('?'));

            var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
                ? MimeTypes.GetMimeType(filename)
                : mediaProfile.MimeType;

            var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader(streamInfo.Container,
                                                                                       streamInfo.TargetAudioCodec,
                                                                                       targetAudioBitrate,
                                                                                       targetSampleRate,
                                                                                       targetChannels,
                                                                                       streamInfo.IsDirectStream,
                                                                                       streamInfo.RunTimeTicks,
                                                                                       streamInfo.TranscodeSeekInfo);

            res.SetAttribute("protocolInfo", String.Format(
                                 "http-get:*:{0}:{1}",
                                 mimeType,
                                 contentFeatures
                                 ));

            container.AppendChild(res);
        }
Exemple #10
0
        private void AddAudioResource(XmlWriter writer, BaseItem audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
        {
            writer.WriteStartElement(string.Empty, "res", NsDidl);

            if (streamInfo == null)
            {
                var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user);

                streamInfo = new StreamBuilder(_mediaEncoder, _logger).BuildAudioItem(new AudioOptions
                {
                    ItemId       = audio.Id,
                    MediaSources = sources.ToArray(),
                    Profile      = _profile,
                    DeviceId     = deviceId
                });
            }

            var url = NormalizeDlnaMediaUrl(streamInfo.ToUrl(_serverAddress, _accessToken));

            var mediaSource = streamInfo.MediaSource;

            if (mediaSource.RunTimeTicks.HasValue)
            {
                writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
            }

            if (filter.Contains("res@size"))
            {
                if (streamInfo.IsDirectStream || streamInfo.EstimateContentLength)
                {
                    var size = streamInfo.TargetSize;

                    if (size.HasValue)
                    {
                        writer.WriteAttributeString("size", size.Value.ToString(_usCulture));
                    }
                }
            }

            var targetAudioBitrate  = streamInfo.TargetAudioBitrate;
            var targetSampleRate    = streamInfo.TargetAudioSampleRate;
            var targetChannels      = streamInfo.TargetAudioChannels;
            var targetAudioBitDepth = streamInfo.TargetAudioBitDepth;

            if (targetChannels.HasValue)
            {
                writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
            }

            if (targetSampleRate.HasValue)
            {
                writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
            }

            if (targetAudioBitrate.HasValue)
            {
                writer.WriteAttributeString("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
            }

            var mediaProfile = _profile.GetAudioMediaProfile(
                streamInfo.Container,
                streamInfo.TargetAudioCodec.FirstOrDefault(),
                targetChannels,
                targetAudioBitrate,
                targetSampleRate,
                targetAudioBitDepth);

            var filename = url.Substring(0, url.IndexOf('?', StringComparison.Ordinal));

            var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
                ? MimeTypes.GetMimeType(filename)
                : mediaProfile.MimeType;

            var contentFeatures = ContentFeatureBuilder.BuildAudioHeader(
                _profile,
                streamInfo.Container,
                streamInfo.TargetAudioCodec.FirstOrDefault(),
                targetAudioBitrate,
                targetSampleRate,
                targetChannels,
                targetAudioBitDepth,
                streamInfo.IsDirectStream,
                streamInfo.RunTimeTicks ?? 0,
                streamInfo.TranscodeSeekInfo);

            writer.WriteAttributeString(
                "protocolInfo",
                string.Format(
                    CultureInfo.InvariantCulture,
                    "http-get:*:{0}:{1}",
                    mimeType,
                    contentFeatures));

            writer.WriteString(url);

            writer.WriteFullEndElement();
        }
Exemple #11
0
        /// <summary>
        /// Adds the dlna headers.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="responseHeaders">The response headers.</param>
        /// <param name="profileManager">The <see cref="IDeviceProfileManager"/> instance.</param>
        /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
        /// <param name="startTimeTicks">The start time in ticks.</param>
        /// <param name="request">The <see cref="HttpRequest"/>.</param>
        private static void AddDlnaHeaders(
            StreamState state,
            IHeaderDictionary responseHeaders,
            IDeviceProfileManager profileManager,
            bool isStaticallyStreamed,
            long?startTimeTicks,
            HttpRequest request)
        {
            if (state == null)
            {
                throw new ArgumentNullException(nameof(state));
            }

            if (responseHeaders == null)
            {
                throw new ArgumentNullException(nameof(responseHeaders));
            }

            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var enableDlnaHeaders = request.Query.TryGetValue("dlna", out _) ||
                                    !string.Equals(request.Headers["GetContentFeatures.DLNA.ORG"], "1", StringComparison.Ordinal);

            if (!enableDlnaHeaders)
            {
                return;
            }

            var profile = state.DeviceProfile;

            StringValues transferMode = request.Headers["transferMode.dlna.org"];

            responseHeaders.Add("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode.ToString());
            responseHeaders.Add("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*");

            if (state.RunTimeTicks.HasValue)
            {
                if (string.Equals(request.Headers["getMediaInfo.sec"], "1", StringComparison.OrdinalIgnoreCase))
                {
                    var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds;
                    responseHeaders.Add("MediaInfo.sec", string.Format(
                                            CultureInfo.InvariantCulture,
                                            "SEC_Duration={0};",
                                            Convert.ToInt32(ms)));
                }

                if (!isStaticallyStreamed && profile != null)
                {
                    AddTimeSeekResponseHeaders(state, responseHeaders, startTimeTicks);
                }
            }

            // if the profile hasn't been assigned see if there is one that matches.
            profile ??= profileManager.GetProfile(
                request.Headers,
                request.HttpContext.Connection.RemoteIpAddress ?? IPAddress.Loopback,
                null);

            var audioCodec = state.ActualOutputAudioCodec;

            if (!state.IsVideoRequest)
            {
                responseHeaders.Add("contentFeatures.dlna.org", ContentFeatureBuilder.BuildAudioHeader(
                                        profile,
                                        state.OutputContainer,
                                        audioCodec,
                                        state.OutputAudioBitrate,
                                        state.OutputAudioSampleRate,
                                        state.OutputAudioChannels,
                                        state.OutputAudioBitDepth,
                                        isStaticallyStreamed,
                                        state.RunTimeTicks,
                                        state.TranscodeSeekInfo));
            }
            else
            {
                var videoCodec = state.ActualOutputVideoCodec;

                responseHeaders.Add(
                    "contentFeatures.dlna.org",
                    ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty);
            }
        }