private bool InternalTextStreamSupportsExternalStream(MediaStream stream) { // These usually have styles and fonts that won't convert to text very well if (string.Equals(stream.Codec, "ass", StringComparison.OrdinalIgnoreCase)) { return false; } return true; }
private bool StreamSupportsExternalStream(MediaStream stream) { if (stream.IsExternal) { return true; } if (stream.IsTextSubtitleStream) { return true; } return false; }
private bool StreamSupportsExternalStream(MediaStream stream) { if (stream.IsExternal) { return true; } if (stream.IsTextSubtitleStream) { if (string.Equals(stream.Codec, "ass", StringComparison.OrdinalIgnoreCase)) { return false; } return true; } return false; }
/// <summary> /// Determines whether the specified stream is H264. /// </summary> /// <param name="stream">The stream.</param> /// <returns><c>true</c> if the specified stream is H264; otherwise, <c>false</c>.</returns> protected bool IsH264(MediaStream stream) { return stream.Codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 || stream.Codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1; }
private bool CanStreamCopyAudio(StreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs) { // Source and target codecs must match if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase)) { return false; } // Video bitrate must fall within requested value if (request.AudioBitRate.HasValue) { if (!audioStream.BitRate.HasValue || audioStream.BitRate.Value <= 0) { return false; } if (audioStream.BitRate.Value > request.AudioBitRate.Value) { return false; } } // Channels must fall within requested value var channels = request.AudioChannels ?? request.MaxAudioChannels; if (channels.HasValue) { if (!audioStream.Channels.HasValue || audioStream.Channels.Value <= 0) { return false; } if (audioStream.Channels.Value > channels.Value) { return false; } } // Sample rate must fall within requested value if (request.AudioSampleRate.HasValue) { if (!audioStream.SampleRate.HasValue || audioStream.SampleRate.Value <= 0) { return false; } if (audioStream.SampleRate.Value > request.AudioSampleRate.Value) { return false; } } return true; }
private int? GetAudioBitrateParam(StreamRequest request, MediaStream audioStream) { if (request.AudioBitRate.HasValue) { // Make sure we don't request a bitrate higher than the source var currentBitrate = audioStream == null ? request.AudioBitRate.Value : audioStream.BitRate ?? request.AudioBitRate.Value; return request.AudioBitRate.Value; //return Math.Min(currentBitrate, request.AudioBitRate.Value); } return null; }
/// <summary> /// Converts ffprobe stream info to our MediaStream class /// </summary> /// <param name="isAudio">if set to <c>true</c> [is audio].</param> /// <param name="streamInfo">The stream info.</param> /// <param name="formatInfo">The format info.</param> /// <returns>MediaStream.</returns> private MediaStream GetMediaStream(bool isAudio, MediaStreamInfo streamInfo, MediaFormatInfo formatInfo) { // These are mp4 chapters if (string.Equals(streamInfo.codec_name, "mov_text", StringComparison.OrdinalIgnoreCase)) { return null; } var stream = new MediaStream { Codec = streamInfo.codec_name, Profile = streamInfo.profile, Level = streamInfo.level, Index = streamInfo.index, PixelFormat = streamInfo.pix_fmt }; // Filter out junk if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1) { stream.CodecTag = streamInfo.codec_tag_string; } if (streamInfo.tags != null) { stream.Language = GetDictionaryValue(streamInfo.tags, "language"); } if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Audio; stream.Channels = streamInfo.channels; if (!string.IsNullOrEmpty(streamInfo.sample_rate)) { int value; if (int.TryParse(streamInfo.sample_rate, NumberStyles.Any, _usCulture, out value)) { stream.SampleRate = value; } } stream.ChannelLayout = ParseChannelLayout(streamInfo.channel_layout); if (streamInfo.bits_per_sample > 0) { stream.BitDepth = streamInfo.bits_per_sample; } else if (streamInfo.bits_per_raw_sample > 0) { stream.BitDepth = streamInfo.bits_per_raw_sample; } } else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Subtitle; } else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase)) { stream.Type = isAudio || string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase) ? MediaStreamType.EmbeddedImage : MediaStreamType.Video; stream.Width = streamInfo.width; stream.Height = streamInfo.height; stream.AspectRatio = GetAspectRatio(streamInfo); stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate); stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate); if (streamInfo.bits_per_sample > 0) { stream.BitDepth = streamInfo.bits_per_sample; } else if (streamInfo.bits_per_raw_sample > 0) { stream.BitDepth = streamInfo.bits_per_raw_sample; } //stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase) || // string.Equals(stream.AspectRatio, "2.35:1", StringComparison.OrdinalIgnoreCase) || // string.Equals(stream.AspectRatio, "2.40:1", StringComparison.OrdinalIgnoreCase); // http://stackoverflow.com/questions/17353387/how-to-detect-anamorphic-video-with-ffprobe stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase); if (streamInfo.refs > 0) { stream.RefFrames = streamInfo.refs; } } else { return null; } // Get stream bitrate var bitrate = 0; if (!string.IsNullOrEmpty(streamInfo.bit_rate)) { int value; if (int.TryParse(streamInfo.bit_rate, NumberStyles.Any, _usCulture, out value)) { bitrate = value; } } if (bitrate == 0 && formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video) { // If the stream info doesn't have a bitrate get the value from the media format info int value; if (int.TryParse(formatInfo.bit_rate, NumberStyles.Any, _usCulture, out value)) { bitrate = value; } } if (bitrate > 0) { stream.BitRate = bitrate; } if (streamInfo.disposition != null) { var isDefault = GetDictionaryValue(streamInfo.disposition, "default"); var isForced = GetDictionaryValue(streamInfo.disposition, "forced"); stream.IsDefault = string.Equals(isDefault, "1", StringComparison.OrdinalIgnoreCase); stream.IsForced = string.Equals(isForced, "1", StringComparison.OrdinalIgnoreCase); } return stream; }
/// <summary> /// Determines whether the specified stream is H264. /// </summary> /// <param name="stream">The stream.</param> /// <returns><c>true</c> if the specified stream is H264; otherwise, <c>false</c>.</returns> protected bool IsH264(MediaStream stream) { var codec = stream.Codec ?? string.Empty; return codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 || codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1; }
public bool? IsSecondaryAudio(MediaStream stream) { // Look for the first audio track marked as default foreach (MediaStream currentStream in MediaStreams) { if (currentStream.Type == MediaStreamType.Audio && currentStream.IsDefault) { return currentStream.Index != stream.Index; } } // Look for the first audio track foreach (MediaStream currentStream in MediaStreams) { if (currentStream.Type == MediaStreamType.Audio) { return currentStream.Index != stream.Index; } } return null; }
private bool IsAudioDirectPlaySupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream audioStream) { if (profile.Container.Length > 0) { // Check container type string mediaContainer = item.Container ?? string.Empty; bool any = false; foreach (string i in profile.GetContainers()) { if (StringHelper.EqualsIgnoreCase(i, mediaContainer)) { any = true; break; } } if (!any) { return false; } } return true; }
public static SubtitleProfile GetSubtitleProfile(MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, EncodingContext context) { // Look for an external profile that matches the stream type (text/graphical) foreach (SubtitleProfile profile in subtitleProfiles) { bool requiresConversion = !StringHelper.EqualsIgnoreCase(subtitleStream.Codec, profile.Format); if (!profile.SupportsLanguage(subtitleStream.Language)) { continue; } if (profile.Method == SubtitleDeliveryMethod.External && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format)) { if (!requiresConversion) { return profile; } if (subtitleStream.SupportsExternalStream) { return profile; } // For sync we can handle the longer extraction times if (context == EncodingContext.Static && subtitleStream.IsTextSubtitleStream) { return profile; } } } foreach (SubtitleProfile profile in subtitleProfiles) { bool requiresConversion = !StringHelper.EqualsIgnoreCase(subtitleStream.Codec, profile.Format); if (!profile.SupportsLanguage(subtitleStream.Language)) { continue; } if (profile.Method == SubtitleDeliveryMethod.Embed && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format)) { if (!requiresConversion) { return profile; } return profile; } } return new SubtitleProfile { Method = SubtitleDeliveryMethod.Encode, Format = subtitleStream.Codec }; }
private bool IsEligibleForDirectPlay(MediaSourceInfo item, int? maxBitrate, MediaStream subtitleStream, VideoOptions options) { if (subtitleStream != null) { SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile.SubtitleProfiles, options.Context); if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed) { return false; } } return IsAudioEligibleForDirectPlay(item, maxBitrate); }
private PlayMethod? GetVideoDirectPlayProfile(DeviceProfile profile, MediaSourceInfo mediaSource, MediaStream videoStream, MediaStream audioStream, bool isEligibleForDirectPlay, bool isEligibleForDirectStream) { // See if it can be direct played DirectPlayProfile directPlay = null; foreach (DirectPlayProfile i in profile.DirectPlayProfiles) { if (i.Type == DlnaProfileType.Video && IsVideoDirectPlaySupported(i, mediaSource, videoStream, audioStream)) { directPlay = i; break; } } if (directPlay == null) { _logger.Debug("Profile: {0}, No direct play profiles found for Path: {1}", profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); return null; } string container = mediaSource.Container; List<ProfileCondition> conditions = new List<ProfileCondition>(); foreach (ContainerProfile i in profile.ContainerProfiles) { if (i.Type == DlnaProfileType.Video && ListHelper.ContainsIgnoreCase(i.GetContainers(), container)) { foreach (ProfileCondition c in i.Conditions) { conditions.Add(c); } } } ConditionProcessor conditionProcessor = new ConditionProcessor(); int? width = videoStream == null ? null : videoStream.Width; int? height = videoStream == null ? null : videoStream.Height; int? bitDepth = videoStream == null ? null : videoStream.BitDepth; int? videoBitrate = videoStream == null ? null : videoStream.BitRate; double? videoLevel = videoStream == null ? null : videoStream.Level; string videoProfile = videoStream == null ? null : videoStream.Profile; float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate; bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic; bool? isCabac = videoStream == null ? null : videoStream.IsCabac; int? audioBitrate = audioStream == null ? null : audioStream.BitRate; int? audioChannels = audioStream == null ? null : audioStream.Channels; string audioProfile = audioStream == null ? null : audioStream.Profile; TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : mediaSource.Timestamp; int? packetLength = videoStream == null ? null : videoStream.PacketLength; int? refFrames = videoStream == null ? null : videoStream.RefFrames; int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio); int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video); // Check container conditions foreach (ProfileCondition i in conditions) { if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams)) { LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource); return null; } } string videoCodec = videoStream == null ? null : videoStream.Codec; if (string.IsNullOrEmpty(videoCodec)) { _logger.Debug("Profile: {0}, DirectPlay=false. Reason=Unknown video codec. Path: {1}", profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); return null; } conditions = new List<ProfileCondition>(); foreach (CodecProfile i in profile.CodecProfiles) { if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec, container)) { foreach (ProfileCondition c in i.Conditions) { conditions.Add(c); } } } foreach (ProfileCondition i in conditions) { if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams)) { LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource); return null; } } if (audioStream != null) { string audioCodec = audioStream.Codec; if (string.IsNullOrEmpty(audioCodec)) { _logger.Debug("Profile: {0}, DirectPlay=false. Reason=Unknown audio codec. Path: {1}", profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); return null; } conditions = new List<ProfileCondition>(); foreach (CodecProfile i in profile.CodecProfiles) { if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec, container)) { foreach (ProfileCondition c in i.Conditions) { conditions.Add(c); } } } foreach (ProfileCondition i in conditions) { bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream); if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioProfile, isSecondaryAudio)) { LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource); return null; } } } if (isEligibleForDirectPlay && mediaSource.SupportsDirectPlay) { if (mediaSource.Protocol == MediaProtocol.Http) { if (_localPlayer.CanAccessUrl(mediaSource.Path, mediaSource.RequiredHttpHeaders.Count > 0)) { return PlayMethod.DirectPlay; } } else if (mediaSource.Protocol == MediaProtocol.File) { if (_localPlayer.CanAccessFile(mediaSource.Path)) { return PlayMethod.DirectPlay; } } } if (isEligibleForDirectStream && mediaSource.SupportsDirectStream) { return PlayMethod.DirectStream; } return null; }
private int GetAudioBitrate(int? maxTotalBitrate, int? targetAudioChannels, string targetAudioCodec, MediaStream audioStream) { var defaultBitrate = 128000; if (targetAudioChannels.HasValue) { if (targetAudioChannels.Value >= 5 && (maxTotalBitrate ?? 0) >= 2000000) { defaultBitrate = 320000; } } int encoderAudioBitrateLimit = int.MaxValue; if (audioStream != null) { // Seeing webm encoding failures when source has 1 audio channel and 22k bitrate. // Any attempts to transcode over 64k will fail if (audioStream.Channels.HasValue && audioStream.Channels.Value == 1) { if ((audioStream.BitRate ?? 0) < 64000) { encoderAudioBitrateLimit = 64000; } } } return Math.Min(defaultBitrate, encoderAudioBitrateLimit); }
private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options) { DirectPlayProfile directPlayProfile = null; foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles) { if (i.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(i, item, audioStream)) { directPlayProfile = i; break; } } List<PlayMethod> playMethods = new List<PlayMethod>(); if (directPlayProfile != null) { // While options takes the network and other factors into account. Only applies to direct stream if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate())) { playMethods.Add(PlayMethod.DirectStream); } // The profile describes what the device supports // If device requirements are satisfied then allow both direct stream and direct play if (item.SupportsDirectPlay && IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options))) { playMethods.Add(PlayMethod.DirectPlay); } } return playMethods; }
/// <summary> /// Adds the video stream. /// </summary> /// <param name="streams">The streams.</param> /// <param name="videoStream">The video stream.</param> private void AddVideoStream(List<MediaStream> streams, TSVideoStream videoStream) { var mediaStream = new MediaStream { BitRate = Convert.ToInt32(videoStream.BitRate), Width = videoStream.Width, Height = videoStream.Height, Codec = videoStream.CodecShortName, ScanType = videoStream.IsInterlaced ? "interlaced" : "progressive", Type = MediaStreamType.Video, Index = streams.Count }; if (videoStream.FrameRateDenominator > 0) { float frameRateEnumerator = videoStream.FrameRateEnumerator; float frameRateDenominator = videoStream.FrameRateDenominator; mediaStream.AverageFrameRate = mediaStream.RealFrameRate = frameRateEnumerator / frameRateDenominator; } streams.Add(mediaStream); }
private void UpdateFromMediaInfo(MediaSourceInfo video, MediaStream videoStream) { if (video.Protocol == MediaProtocol.File) { if (videoStream != null) { try { _logger.Debug("Running MediaInfo against {0}", video.Path); var result = new MediaInfoLib().GetVideoInfo(video.Path); videoStream.IsCabac = result.IsCabac ?? videoStream.IsCabac; videoStream.IsInterlaced = result.IsInterlaced ?? videoStream.IsInterlaced; videoStream.BitDepth = result.BitDepth ?? videoStream.BitDepth; videoStream.RefFrames = result.RefFrames; } catch (Exception ex) { _logger.ErrorException("Error running MediaInfo on {0}", ex, video.Path); } } } }
private bool IsVideoDirectPlaySupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream) { if (profile.Container.Length > 0) { // Check container type string mediaContainer = item.Container ?? string.Empty; bool any = false; foreach (string i in profile.GetContainers()) { if (StringHelper.EqualsIgnoreCase(i, mediaContainer)) { any = true; break; } } if (!any) { return false; } } // Check video codec List<string> videoCodecs = profile.GetVideoCodecs(); if (videoCodecs.Count > 0) { string videoCodec = videoStream == null ? null : videoStream.Codec; if (string.IsNullOrEmpty(videoCodec) || !ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec)) { return false; } } List<string> audioCodecs = profile.GetAudioCodecs(); if (audioCodecs.Count > 0) { // Check audio codecs string audioCodec = audioStream == null ? null : audioStream.Codec; if (string.IsNullOrEmpty(audioCodec) || !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec)) { return false; } } return true; }
/// <summary> /// Gets the number of audio channels to specify on the command line /// </summary> /// <param name="request">The request.</param> /// <param name="audioStream">The audio stream.</param> /// <param name="outputAudioCodec">The output audio codec.</param> /// <returns>System.Nullable{System.Int32}.</returns> private int? GetNumAudioChannelsParam(EncodingJobOptions request, MediaStream audioStream, string outputAudioCodec) { var inputChannels = audioStream == null ? null : audioStream.Channels; if (inputChannels <= 0) { inputChannels = null; } var codec = outputAudioCodec ?? string.Empty; if (codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1) { // wmav2 currently only supports two channel output return Math.Min(2, inputChannels ?? 2); } if (request.MaxAudioChannels.HasValue) { if (inputChannels.HasValue) { return Math.Min(request.MaxAudioChannels.Value, inputChannels.Value); } var channelLimit = codec.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) != -1 ? 2 : 6; // If we don't have any media info then limit it to 5 to prevent encoding errors due to asking for too many channels return Math.Min(request.MaxAudioChannels.Value, channelLimit); } return request.AudioChannels; }
/// <summary> /// Converts ffprobe stream info to our MediaStream class /// </summary> /// <param name="streamInfo">The stream info.</param> /// <param name="formatInfo">The format info.</param> /// <returns>MediaStream.</returns> private static MediaStream GetMediaStream(MediaStreamInfo streamInfo, MediaFormatInfo formatInfo) { var stream = new MediaStream { Codec = streamInfo.codec_name, Profile = streamInfo.profile, Level = streamInfo.level, Index = streamInfo.index }; if (streamInfo.tags != null) { stream.Language = GetDictionaryValue(streamInfo.tags, "language"); } if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Audio; stream.Channels = streamInfo.channels; if (!string.IsNullOrEmpty(streamInfo.sample_rate)) { stream.SampleRate = int.Parse(streamInfo.sample_rate, UsCulture); } stream.ChannelLayout = ParseChannelLayout(streamInfo.channel_layout); } else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Subtitle; } else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Video; stream.Width = streamInfo.width; stream.Height = streamInfo.height; stream.AspectRatio = GetAspectRatio(streamInfo); stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate); stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate); } else { return null; } // Get stream bitrate if (stream.Type != MediaStreamType.Subtitle) { var bitrate = 0; if (!string.IsNullOrEmpty(streamInfo.bit_rate)) { bitrate = int.Parse(streamInfo.bit_rate, UsCulture); } else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate)) { // If the stream info doesn't have a bitrate get the value from the media format info bitrate = int.Parse(formatInfo.bit_rate, UsCulture); } if (bitrate > 0) { stream.BitRate = bitrate; } } if (streamInfo.disposition != null) { var isDefault = GetDictionaryValue(streamInfo.disposition, "default"); var isForced = GetDictionaryValue(streamInfo.disposition, "forced"); stream.IsDefault = string.Equals(isDefault, "1", StringComparison.OrdinalIgnoreCase); stream.IsForced = string.Equals(isForced, "1", StringComparison.OrdinalIgnoreCase); } return stream; }
internal static bool CanStreamCopyVideo(EncodingJobOptions request, MediaStream videoStream) { if (videoStream.IsInterlaced) { return false; } if (videoStream.IsAnamorphic ?? false) { return false; } // Can't stream copy if we're burning in subtitles if (request.SubtitleStreamIndex.HasValue) { if (request.SubtitleMethod == SubtitleDeliveryMethod.Encode) { return false; } } // Source and target codecs must match if (!string.Equals(request.VideoCodec, videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { return false; } // If client is requesting a specific video profile, it must match the source if (!string.IsNullOrEmpty(request.Profile)) { if (string.IsNullOrEmpty(videoStream.Profile)) { return false; } if (!string.Equals(request.Profile, videoStream.Profile, StringComparison.OrdinalIgnoreCase)) { var currentScore = GetVideoProfileScore(videoStream.Profile); var requestedScore = GetVideoProfileScore(request.Profile); if (currentScore == -1 || currentScore > requestedScore) { return false; } } } // Video width must fall within requested value if (request.MaxWidth.HasValue) { if (!videoStream.Width.HasValue || videoStream.Width.Value > request.MaxWidth.Value) { return false; } } // Video height must fall within requested value if (request.MaxHeight.HasValue) { if (!videoStream.Height.HasValue || videoStream.Height.Value > request.MaxHeight.Value) { return false; } } // Video framerate must fall within requested value var requestedFramerate = request.MaxFramerate ?? request.Framerate; if (requestedFramerate.HasValue) { var videoFrameRate = videoStream.AverageFrameRate ?? videoStream.RealFrameRate; if (!videoFrameRate.HasValue || videoFrameRate.Value > requestedFramerate.Value) { return false; } } // Video bitrate must fall within requested value if (request.VideoBitRate.HasValue) { if (!videoStream.BitRate.HasValue || videoStream.BitRate.Value > request.VideoBitRate.Value) { return false; } } if (request.MaxVideoBitDepth.HasValue) { if (videoStream.BitDepth.HasValue && videoStream.BitDepth.Value > request.MaxVideoBitDepth.Value) { return false; } } if (request.MaxRefFrames.HasValue) { if (videoStream.RefFrames.HasValue && videoStream.RefFrames.Value > request.MaxRefFrames.Value) { return false; } } // If a specific level was requested, the source must match or be less than if (request.Level.HasValue) { if (!videoStream.Level.HasValue) { return false; } if (videoStream.Level.Value > request.Level.Value) { return false; } } if (request.Cabac.HasValue && request.Cabac.Value) { if (videoStream.IsCabac.HasValue && !videoStream.IsCabac.Value) { return false; } } return request.EnableAutoStreamCopy; }
public ResponseProfile GetVideoMediaProfile(string container, string audioCodec, string videoCodec, MediaStream audioStream, MediaStream videoStream) { container = (container ?? string.Empty).TrimStart('.'); return ResponseProfiles.FirstOrDefault(i => { if (i.Type != DlnaProfileType.Video) { return false; } var containers = i.GetContainers().ToList(); if (containers.Count > 0 && !containers.Contains(container)) { return false; } var audioCodecs = i.GetAudioCodecs().ToList(); if (audioCodecs.Count > 0 && !audioCodecs.Contains(audioCodec ?? string.Empty)) { return false; } var videoCodecs = i.GetVideoCodecs().ToList(); if (videoCodecs.Count > 0 && !videoCodecs.Contains(videoCodec ?? string.Empty)) { return false; } return true; }); }
private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream) { var bitrate = request.VideoBitRate; if (videoStream != null) { var isUpscaling = request.Height.HasValue && videoStream.Height.HasValue && request.Height.Value > videoStream.Height.Value; if (request.Width.HasValue && videoStream.Width.HasValue && request.Width.Value > videoStream.Width.Value) { isUpscaling = true; } // Don't allow bitrate increases unless upscaling if (!isUpscaling) { if (bitrate.HasValue && videoStream.BitRate.HasValue) { bitrate = Math.Min(bitrate.Value, videoStream.BitRate.Value); } } } return bitrate; }
/// <summary> /// Gets the chapter. /// </summary> /// <param name="reader">The reader.</param> /// <returns>ChapterInfo.</returns> private MediaStream GetMediaStream(IDataReader reader) { var item = new MediaStream { Index = reader.GetInt32(1) }; item.Type = (MediaStreamType)Enum.Parse(typeof(MediaStreamType), reader.GetString(2), true); if (!reader.IsDBNull(3)) { item.Codec = reader.GetString(3); } if (!reader.IsDBNull(4)) { item.Language = reader.GetString(4); } if (!reader.IsDBNull(5)) { item.ChannelLayout = reader.GetString(5); } if (!reader.IsDBNull(6)) { item.Profile = reader.GetString(6); } if (!reader.IsDBNull(7)) { item.AspectRatio = reader.GetString(7); } if (!reader.IsDBNull(8)) { item.Path = reader.GetString(8); } item.IsInterlaced = reader.GetBoolean(9); if (!reader.IsDBNull(10)) { item.BitRate = reader.GetInt32(10); } if (!reader.IsDBNull(11)) { item.Channels = reader.GetInt32(11); } if (!reader.IsDBNull(12)) { item.SampleRate = reader.GetInt32(12); } item.IsDefault = reader.GetBoolean(13); item.IsForced = reader.GetBoolean(14); item.IsExternal = reader.GetBoolean(15); if (!reader.IsDBNull(16)) { item.Width = reader.GetInt32(16); } if (!reader.IsDBNull(17)) { item.Height = reader.GetInt32(17); } if (!reader.IsDBNull(18)) { item.AverageFrameRate = reader.GetFloat(18); } if (!reader.IsDBNull(19)) { item.RealFrameRate = reader.GetFloat(19); } if (!reader.IsDBNull(20)) { item.Level = reader.GetFloat(20); } if (!reader.IsDBNull(21)) { item.PixelFormat = reader.GetString(21); } if (!reader.IsDBNull(22)) { item.BitDepth = reader.GetInt32(22); } if (!reader.IsDBNull(23)) { item.IsAnamorphic = reader.GetBoolean(23); } if (!reader.IsDBNull(24)) { item.RefFrames = reader.GetInt32(24); } if (!reader.IsDBNull(25)) { item.IsCabac = reader.GetBoolean(25); } if (!reader.IsDBNull(26)) { var frames = reader.GetString(26); if (!string.IsNullOrWhiteSpace(frames)) { item.KeyFrames = frames.Split(',').Select(i => int.Parse(i, CultureInfo.InvariantCulture)).ToList(); } } return item; }
private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream) { if (videoStream.IsInterlaced) { return false; } // Can't stream copy if we're burning in subtitles if (request.SubtitleStreamIndex.HasValue) { if (request.SubtitleMethod == SubtitleDeliveryMethod.Encode) { return false; } } // Source and target codecs must match if (!string.Equals(request.VideoCodec, videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { return false; } // If client is requesting a specific video profile, it must match the source if (!string.IsNullOrEmpty(request.Profile) && !string.Equals(request.Profile, videoStream.Profile, StringComparison.OrdinalIgnoreCase)) { return false; } // Video width must fall within requested value if (request.MaxWidth.HasValue) { if (!videoStream.Width.HasValue || videoStream.Width.Value > request.MaxWidth.Value) { return false; } } // Video height must fall within requested value if (request.MaxHeight.HasValue) { if (!videoStream.Height.HasValue || videoStream.Height.Value > request.MaxHeight.Value) { return false; } } // Video framerate must fall within requested value var requestedFramerate = request.MaxFramerate ?? request.Framerate; if (requestedFramerate.HasValue) { var videoFrameRate = videoStream.AverageFrameRate ?? videoStream.RealFrameRate; if (!videoFrameRate.HasValue || videoFrameRate.Value > requestedFramerate.Value) { return false; } } // Video bitrate must fall within requested value if (request.VideoBitRate.HasValue) { if (!videoStream.BitRate.HasValue || videoStream.BitRate.Value > request.VideoBitRate.Value) { return false; } } // If a specific level was requested, the source must match or be less than if (!string.IsNullOrEmpty(request.Level)) { double requestLevel; if (double.TryParse(request.Level, NumberStyles.Any, UsCulture, out requestLevel)) { if (!videoStream.Level.HasValue) { return false; } if (videoStream.Level.Value > requestLevel) { return false; } } } return request.EnableAutoStreamCopy; }
/// <summary> /// Gets the chapter. /// </summary> /// <param name="reader">The reader.</param> /// <returns>ChapterInfo.</returns> private MediaStream GetMediaStream(IDataReader reader) { var item = new MediaStream { Index = reader.GetInt32(1) }; item.Type = (MediaStreamType)Enum.Parse(typeof(MediaStreamType), reader.GetString(2), true); if (!reader.IsDBNull(3)) { item.Codec = reader.GetString(3); } if (!reader.IsDBNull(4)) { item.Language = reader.GetString(4); } if (!reader.IsDBNull(5)) { item.ChannelLayout = reader.GetString(5); } if (!reader.IsDBNull(6)) { item.Profile = reader.GetString(6); } if (!reader.IsDBNull(7)) { item.AspectRatio = reader.GetString(7); } if (!reader.IsDBNull(8)) { item.Path = reader.GetString(8); } item.IsInterlaced = reader.GetBoolean(9); if (!reader.IsDBNull(10)) { item.BitRate = reader.GetInt32(10); } if (!reader.IsDBNull(11)) { item.Channels = reader.GetInt32(11); } if (!reader.IsDBNull(12)) { item.SampleRate = reader.GetInt32(12); } item.IsDefault = reader.GetBoolean(13); item.IsForced = reader.GetBoolean(14); item.IsExternal = reader.GetBoolean(15); if (!reader.IsDBNull(16)) { item.Width = reader.GetInt32(16); } if (!reader.IsDBNull(17)) { item.Height = reader.GetInt32(17); } if (!reader.IsDBNull(18)) { item.AverageFrameRate = reader.GetFloat(18); } if (!reader.IsDBNull(19)) { item.RealFrameRate = reader.GetFloat(19); } if (!reader.IsDBNull(20)) { item.Level = reader.GetFloat(20); } if (!reader.IsDBNull(21)) { item.PixelFormat = reader.GetString(21); } if (!reader.IsDBNull(22)) { item.BitDepth = reader.GetInt32(22); } if (!reader.IsDBNull(23)) { item.IsAnamorphic = reader.GetBoolean(23); } return item; }
/// <summary> /// Gets the number of audio channels to specify on the command line /// </summary> /// <param name="request">The request.</param> /// <param name="audioStream">The audio stream.</param> /// <param name="outputAudioCodec">The output audio codec.</param> /// <returns>System.Nullable{System.Int32}.</returns> private int? GetNumAudioChannelsParam(StreamRequest request, MediaStream audioStream, string outputAudioCodec) { if (audioStream != null) { var codec = outputAudioCodec ?? string.Empty; if (audioStream.Channels > 2 && codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1) { // wmav2 currently only supports two channel output return 2; } } if (request.MaxAudioChannels.HasValue) { if (audioStream != null && audioStream.Channels.HasValue) { return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value); } return request.MaxAudioChannels.Value; } return request.AudioChannels; }
protected override bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs) { return false; }
protected override bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream) { if (videoStream.KeyFrames == null || videoStream.KeyFrames.Count == 0) { Logger.Debug("Cannot stream copy video due to missing keyframe info"); return false; } var previousSegment = 0; foreach (var frame in videoStream.KeyFrames) { var length = frame - previousSegment; // Don't allow really long segments because this could result in long download times if (length > 10000) { Logger.Debug("Cannot stream copy video due to long segment length of {0}ms", length); return false; } previousSegment = frame; } return base.CanStreamCopyVideo(request, videoStream); }
/// <summary> /// Adds the audio stream. /// </summary> /// <param name="streams">The streams.</param> /// <param name="audioStream">The audio stream.</param> private void AddAudioStream(List<MediaStream> streams, TSAudioStream audioStream) { var stream = new MediaStream { Codec = audioStream.CodecShortName, Language = audioStream.LanguageCode, Channels = audioStream.ChannelCount, SampleRate = audioStream.SampleRate, Type = MediaStreamType.Audio, Index = streams.Count }; var bitrate = Convert.ToInt32(audioStream.BitRate); if (bitrate > 0) { stream.BitRate = bitrate; } if (audioStream.LFE > 0) { stream.Channels = audioStream.ChannelCount + 1; } streams.Add(stream); }