public static bool IsImageStreamChanged(ImageTranscoding image) { bool notChanged = true; notChanged &= (image.SourceOrientation == 0 || image.TargetAutoRotate == false); notChanged &= (image.SourceHeight == 0 || image.SourceHeight <= image.TargetHeight); notChanged &= (image.SourceWidth == 0 || image.SourceWidth <= image.TargetWidth); notChanged &= (image.TargetPixelFormat == PixelFormat.Unknown || image.SourcePixelFormat == image.TargetPixelFormat); notChanged &= (image.TargetImageCodec == ImageContainer.Unknown || image.SourceImageCodec == image.TargetImageCodec); return(notChanged == false); }
public async Task Initialize(MediaItem item, int?edition = null) { IsLive = false; MediaItemId = item.MediaItemId; if (MediaItemAspect.TryGetAttribute(item.Aspects, MediaAspect.ATTR_TITLE, out string title)) { MediaItemTitle = title; } else { MediaItemTitle = "?"; } var info = await MediaAnalyzer.ParseMediaItemAsync(item, edition); if (info == null) { Logger.Warn("MediaServer: Mediaitem {0} couldn't be analyzed", item.MediaItemId); return; } if (item.Aspects.ContainsKey(AudioAspect.ASPECT_ID)) { IsAudio = true; } else if (item.Aspects.ContainsKey(ImageAspect.ASPECT_ID)) { IsImage = true; } else if (item.Aspects.ContainsKey(VideoAspect.ASPECT_ID)) { IsVideo = true; } else { Logger.Warn("MediaServer: Mediaitem {0} contains no required aspect information", item.MediaItemId); return; } if (item.HasEditions && !edition.HasValue) { //Find edition with best matching audio that doesn't require transcoding int currentPriority = -1; bool currentRequiresTranscoding = false; var preferredAudioLang = Client.PreferredAudioLanguages.ToList(); foreach (var checkEdition in info.Metadata.Keys) { for (int idx = 0; idx < info.Audio[checkEdition].Count; idx++) { VideoTranscoding video = TranscodeProfileManager.GetVideoTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Client.Profile.ID, info, checkEdition, Client.PreferredAudioLanguages, IsLive, ""); bool requiresTranscoding = video != null; for (int priority = 0; priority < preferredAudioLang.Count; priority++) { if (preferredAudioLang[priority].Equals(info.Audio[checkEdition][idx].Language, StringComparison.InvariantCultureIgnoreCase) == true) { if (currentPriority == -1 || priority < currentPriority || (!requiresTranscoding && currentRequiresTranscoding && priority == currentPriority)) { currentPriority = priority; currentRequiresTranscoding = requiresTranscoding; edition = checkEdition; } } } } } } if (!edition.HasValue) { //Assign first edition _edition = info.Metadata.Min(m => m.Key); } else { _edition = edition.Value; } string transcodeId = item.MediaItemId.ToString() + "_" + Client.Profile.ID; if (MediaServerPlugin.Settings.TranscodingAllowed) { if (IsAudio) { AudioTranscoding audio = TranscodeProfileManager.GetAudioTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Client.Profile.ID, info, _edition, IsLive, transcodeId); TranscodingParameter = audio; } else if (IsImage) { ImageTranscoding image = TranscodeProfileManager.GetImageTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Client.Profile.ID, info, _edition, transcodeId); TranscodingParameter = image; } else if (IsVideo) { VideoTranscoding video = TranscodeProfileManager.GetVideoTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Client.Profile.ID, info, _edition, Client.PreferredAudioLanguages, IsLive, transcodeId); if (video != null) { if (video.TargetVideoContainer == VideoContainer.Hls) { IsSegmented = true; } if (MediaServerPlugin.Settings.HardcodedSubtitlesAllowed == false) { video.TargetSubtitleSupport = SubtitleSupport.None; } } TranscodingParameter = video; } } if (TranscodingParameter == null) { if (IsVideo) { VideoTranscoding video = TranscodeProfileManager.GetVideoSubtitleTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Client.Profile.ID, info, _edition, IsLive, transcodeId); if (video != null) { if (video.TargetVideoContainer == VideoContainer.Hls) { IsSegmented = true; } if (MediaServerPlugin.Settings.HardcodedSubtitlesAllowed == false) { video.TargetSubtitleSupport = SubtitleSupport.None; } } SubtitleTranscodingParameter = video; } } //Assign some extra meta data DateTime?aspectDate; if (MediaItemAspect.TryGetAttribute(item.Aspects, ImporterAspect.ATTR_DATEADDED, out aspectDate)) { MediaItemAddedDate = aspectDate; } if (MediaItemAspect.TryGetAttribute(item.Aspects, MediaAspect.ATTR_RECORDINGTIME, out aspectDate)) { MediaItemRecordingDate = aspectDate; } if (IsVideo) { if (MediaItemAspect.TryGetAspects(item.Aspects, VideoStreamAspect.Metadata, out var videoStreamAspects)) { MediaItemWidth = videoStreamAspects.FirstOrDefault()?.GetAttributeValue <int?>(VideoStreamAspect.ATTR_WIDTH); MediaItemHeight = videoStreamAspects.FirstOrDefault()?.GetAttributeValue <int?>(VideoStreamAspect.ATTR_HEIGHT); } } else if (IsImage) { if (MediaItemAspect.TryGetAspect(item.Aspects, ImageAspect.Metadata, out var imageAspect)) { MediaItemImageMake = imageAspect?.GetAttributeValue <string>(ImageAspect.ATTR_MAKE); MediaItemImageMake = imageAspect?.GetAttributeValue <string>(ImageAspect.ATTR_MODEL); MediaItemImageMake = imageAspect?.GetAttributeValue <string>(ImageAspect.ATTR_FNUMBER); MediaItemImageMake = imageAspect?.GetAttributeValue <string>(ImageAspect.ATTR_ISO_SPEED); MediaItemImageMake = imageAspect?.GetAttributeValue <string>(ImageAspect.ATTR_EXPOSURE_TIME); MediaItemImageOrientation = imageAspect?.GetAttributeValue <int?>(ImageAspect.ATTR_ORIENTATION); MediaItemWidth = imageAspect?.GetAttributeValue <int?>(ImageAspect.ATTR_WIDTH); MediaItemHeight = imageAspect?.GetAttributeValue <int?>(ImageAspect.ATTR_HEIGHT); } } AssignDlnaMetadata(info, _edition); }
private void AssignDlnaMetadata(MetadataContainer info, int edition) { if (info == null) { return; } List <string> profileList = new List <string>(); if (TranscodingParameter == null) { Metadata = info.Metadata[edition]; Video = info.Video[edition]; Audio = info.Audio[edition]; Image = info.Image[edition]; Subtitles = info.Subtitles[edition]; } else { if (IsImage) { ImageTranscoding image = (ImageTranscoding)TranscodingParameter; TranscodedImageMetadata metadata = MediaConverter.GetTranscodedImageMetadata(image); Metadata = new MetadataStream { Mime = info.Metadata[edition].Mime, ImageContainerType = metadata.TargetImageCodec, Size = Client.EstimateTransodedSize ? info.Metadata[edition].Size : 0, }; Image = new ImageStream { Height = metadata.TargetMaxHeight, Orientation = metadata.TargetOrientation, PixelFormatType = metadata.TargetPixelFormat, Width = metadata.TargetMaxWidth }; } else if (IsAudio) { AudioTranscoding audio = (AudioTranscoding)TranscodingParameter; TranscodedAudioMetadata metadata = MediaConverter.GetTranscodedAudioMetadata(audio); Metadata = new MetadataStream { Mime = info.Metadata[edition].Mime, AudioContainerType = metadata.TargetAudioContainer, Bitrate = metadata.TargetAudioBitrate > 0 ? metadata.TargetAudioBitrate : null, Duration = info.Metadata[edition].Duration, Size = Client.EstimateTransodedSize ? (metadata.TargetAudioBitrate > 0 ? Convert.ToInt64((metadata.TargetAudioBitrate * 1024 * info.Metadata[edition].Duration) / 8.0) : (long?)null) : null, }; AudioStream audioStream = new AudioStream(); audioStream.Bitrate = metadata.TargetAudioBitrate; audioStream.Channels = metadata.TargetAudioChannels; audioStream.Codec = metadata.TargetAudioCodec; audioStream.Frequency = metadata.TargetAudioFrequency; Audio = new List <AudioStream> { audioStream }; } else if (IsVideo) { VideoTranscoding video = (VideoTranscoding)TranscodingParameter; TranscodedVideoMetadata metadata = MediaConverter.GetTranscodedVideoMetadata(video); Metadata = new MetadataStream { Mime = info.Metadata[edition].Mime, VideoContainerType = metadata.TargetVideoContainer, Bitrate = metadata.TargetAudioBitrate > 0 && metadata.TargetVideoBitrate > 0 ? metadata.TargetAudioBitrate + metadata.TargetVideoBitrate : null, Duration = info.Metadata[edition].Duration, Size = Client.EstimateTransodedSize ? (metadata.TargetAudioBitrate > 0 && info.Metadata[edition].Duration > 0 ? Convert.ToInt64((metadata.TargetAudioBitrate * 1024 * info.Metadata[edition].Duration) / 8.0) : (long?)null) : null, }; Video = new VideoStream { AspectRatio = metadata.TargetVideoAspectRatio, Bitrate = metadata.TargetVideoBitrate, Codec = metadata.TargetVideoCodec, Framerate = metadata.TargetVideoFrameRate, HeaderLevel = metadata.TargetLevel, ProfileType = metadata.TargetProfile, RefLevel = metadata.TargetLevel, Height = metadata.TargetVideoMaxHeight, PixelAspectRatio = metadata.TargetVideoPixelAspectRatio, PixelFormatType = metadata.TargetVideoPixelFormat, TimestampType = metadata.TargetVideoTimestamp, Width = metadata.TargetVideoMaxWidth, }; AudioStream audioStream = new AudioStream(); audioStream.Bitrate = metadata.TargetAudioBitrate; audioStream.Channels = metadata.TargetAudioChannels; audioStream.Codec = metadata.TargetAudioCodec; audioStream.Frequency = metadata.TargetAudioFrequency; Audio = new List <AudioStream> { audioStream }; } } if (IsImage) { profileList = DlnaProfiles.ResolveImageProfile(Metadata.ImageContainerType, Image.Width, Image.Height); } else if (IsAudio) { var audio = Audio.FirstOrDefault(); profileList = DlnaProfiles.ResolveAudioProfile(Metadata.AudioContainerType, audio?.Codec ?? AudioCodec.Unknown, audio?.Bitrate, audio?.Frequency, audio?.Channels); } else if (IsVideo) { var audio = Audio.FirstOrDefault(); profileList = DlnaProfiles.ResolveVideoProfile(Metadata.VideoContainerType, Video.Codec, audio?.Codec ?? AudioCodec.Unknown, Video.ProfileType, Video.HeaderLevel, Video.Framerate, Video.Width, Video.Height, Video.Bitrate, audio?.Bitrate, Video.TimestampType); } string profile = ""; string mime = info.Metadata[edition].Mime; if (DlnaProfiles.TryFindCompatibleProfile(Client, profileList, ref profile, ref mime)) { DlnaMime = mime; DlnaProfile = profile; } }
public async Task Initialize(Guid?userId, MediaItem item, int?edition, int?audioId = null, int?subtitleId = null) { MediaItemId = item.MediaItemId; var info = await MediaAnalyzer.ParseMediaItemAsync(item); if (info == null) { Logger.Warn("MP2Extended: Mediaitem {0} couldn't be analyzed", item.MediaItemId); return; } int? audioStreamId = null; List <string> preferredAudioLang = new List <string>(); List <string> preferredSubtitleLang = new List <string>(); await ResourceAccessUtils.AddPreferredLanguagesAsync(userId, preferredAudioLang, preferredSubtitleLang); if (audioId.HasValue) { if (audioId.Value >= EDITION_OFFSET) { edition = (audioId.Value / EDITION_OFFSET) - 1; audioStreamId = audioId.Value - ((audioId.Value / EDITION_OFFSET) * EDITION_OFFSET); } else { audioStreamId = audioId; } } if (item.HasEditions && !edition.HasValue) { //Find edition with best matching audio that doesn't require transcoding int currentPriority = -1; bool currentRequiresTranscoding = false; foreach (var checkEdition in info.Metadata.Keys) { for (int idx = 0; idx < info.Audio[checkEdition].Count; idx++) { VideoTranscoding video = TranscodeProfileManager.GetVideoTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Profile.ID, info, checkEdition, preferredAudioLang, IsLive, ""); bool requiresTranscoding = video != null; for (int priority = 0; priority < preferredAudioLang.Count; priority++) { if (preferredAudioLang[priority].Equals(info.Audio[checkEdition][idx].Language, StringComparison.InvariantCultureIgnoreCase) == true) { if (currentPriority == -1 || priority < currentPriority || (!requiresTranscoding && currentRequiresTranscoding && priority == currentPriority)) { currentPriority = priority; currentRequiresTranscoding = requiresTranscoding; audioStreamId = info.Audio[checkEdition][idx].StreamIndex; _edition = checkEdition; } } } } } } else { //Assign first edition _edition = info.Metadata.Min(m => m.Key); } if (item.Aspects.ContainsKey(AudioAspect.ASPECT_ID)) { IsAudio = true; } else if (item.Aspects.ContainsKey(ImageAspect.ASPECT_ID)) { IsImage = true; } else if (item.Aspects.ContainsKey(VideoAspect.ASPECT_ID)) { IsVideo = true; } else { Logger.Warn("MP2Extended: Mediaitem {0} contains no required aspect information", item.MediaItemId); return; } string transcodeId = item.MediaItemId.ToString() + "_" + Profile.ID; if (IsLive) { transcodeId = Guid.NewGuid().ToString() + "_" + Profile.ID; } if (MP2Extended.Settings.TranscodingAllowed) { if (IsAudio) { AudioTranscoding audio = TranscodeProfileManager.GetAudioTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Profile.ID, info, _edition, IsLive, transcodeId); TranscodingParameter = audio; } else if (IsImage) { ImageTranscoding image = TranscodeProfileManager.GetImageTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Profile.ID, info, _edition, transcodeId); TranscodingParameter = image; } else if (IsVideo) { VideoTranscoding video; if (audioStreamId.HasValue) { video = TranscodeProfileManager.GetVideoTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Profile.ID, info, _edition, audioStreamId.Value, subtitleId, IsLive, transcodeId); } else { video = TranscodeProfileManager.GetVideoTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Profile.ID, info, _edition, preferredAudioLang, IsLive, transcodeId); } if (video != null) { if (video.TargetVideoContainer == VideoContainer.Hls) { IsSegmented = true; } if (MP2Extended.Settings.HardcodedSubtitlesAllowed == false) { video.TargetSubtitleSupport = SubtitleSupport.None; } } TranscodingParameter = video; } } if (TranscodingParameter == null) { if (IsLive) { if (IsVideo) { if (audioStreamId.HasValue) { TranscodingParameter = TranscodeProfileManager.GetLiveVideoTranscoding(info, audioStreamId.Value, transcodeId); } else { TranscodingParameter = TranscodeProfileManager.GetLiveVideoTranscoding(info, preferredAudioLang, transcodeId); } } else if (IsAudio) { TranscodingParameter = TranscodeProfileManager.GetLiveAudioTranscoding(info, transcodeId); } } else if (IsVideo) { VideoTranscoding video = TranscodeProfileManager.GetVideoSubtitleTranscoding(ProfileManager.TRANSCODE_PROFILE_SECTION, Profile.ID, info, _edition, IsLive, transcodeId); if (video != null) { if (video.TargetVideoContainer == VideoContainer.Hls) { IsSegmented = true; } if (MP2Extended.Settings.HardcodedSubtitlesAllowed == false) { video.TargetSubtitleSupport = SubtitleSupport.None; } } TranscodingParameter = video; } } AssignWebMetadata(info, _edition); }
protected override async Task <TranscodeContext> TranscodeImageAsync(string clientId, ImageTranscoding image, bool waitForBuffer) { FFMpegTranscodeContext context = new FFMpegTranscodeContext(_cacheEnabled, _cachePath); context.Partial = false; string transcodingFile = Path.Combine(_cachePath, GetTranscodingImageFileName(image)); if (File.Exists(transcodingFile) == true) { //Use existing context if possible TranscodeContext existingContext = await GetExistingTranscodeContextAsync(clientId, image.TranscodeId).ConfigureAwait(false); if (existingContext != null) { existingContext.TargetFile = transcodingFile; if (existingContext.Stream == null) { existingContext.AssignStream(await GetFileStreamAsync(transcodingFile).ConfigureAwait(false)); } return(existingContext); } else { //Presume that it is a cached file TouchFile(transcodingFile); context.Partial = false; context.TargetFile = transcodingFile; context.AssignStream(await GetFileStreamAsync(transcodingFile).ConfigureAwait(false)); return(context); } } FFMpegTranscodeData data = new FFMpegTranscodeData(_cachePath) { TranscodeId = image.TranscodeId, ClientId = clientId }; if (string.IsNullOrEmpty(image.TranscoderBinPath) == false) { data.TranscoderBinPath = image.TranscoderBinPath; } if (string.IsNullOrEmpty(image.TranscoderArguments) == false) { data.ConcatedFileInput = image.ConcatSourceMediaPaths; data.TranscoderArguments = image.TranscoderArguments; data.InputMediaFilePaths = image.SourceMediaPaths; } else { _ffMpegCommandline.InitTranscodingParameters(image.ConcatSourceMediaPaths, image.SourceMediaPaths, ref data); _ffMpegCommandline.AddTranscodingThreadsParameters(true, ref data); _ffMpegCommandline.AddImageParameters(image, data); data.InputArguments[data.FirstResourceIndex].Add("-f image2pipe"); //pipe works with network drives data.OutputArguments.Add("-f image2"); } data.OutputFilePath = transcodingFile; context.TargetFile = transcodingFile; _logger.Debug("FFMpegMediaConverter: Invoking transcoder to transcode image file '{0}' for transcode '{1}'", image.SourceMediaPaths, image.TranscodeId); context.Start(); context.AssignStream(await ExecuteTranscodingProcessAsync(data, context, waitForBuffer).ConfigureAwait(false)); return(context); }