/// <summary> /// Loops through the Media table to set the FileName, Length, Width and Height fields. /// </summary> /// <param name="progress">Reports the progress of the operation. First report is the amount of files to process, then subsequent reports represent the quantity done.</param> /// <returns>Whether some data was modified.</returns> public async Task<bool> LoadMediaInfoAsync(IProgress<int> progress) { // Calling this method when it is already running allows listening to the progress. if (progress != null) { loadingMediaInfoProgress = progress; // First progress report is total count. if (isLoadingMediaInfo) loadingMediaInfoProgress.Report(loadingMediaInfoCount); } if (isLoadingMediaInfo) return false; isLoadingMediaInfo = true; bool HasChanges = false; using (Entities context = new Entities()) { // Loop through all media items with missing Length, Width or Height. var Query = (from v in context.Media where v.FileName == null || v.Length == null || ((v.MediaTypeId == (int)MediaType.Video || v.MediaTypeId == (int)MediaType.Image) && v.Height == null) select v); // First progress report contains the total count. Subsequent reports contain the quantity completed. loadingMediaInfoCount = Query.Count(); if (loadingMediaInfoProgress != null) loadingMediaInfoProgress.Report(loadingMediaInfoCount); int ItemsCompleted = 0; string DefaultFileName; string FilePath; DefaultMediaPath PathCalc = new DefaultMediaPath(); PathCalc.LoadData(); MediaInfoReader MediaInfo = new MediaInfoReader(); foreach (Media item in Query) { // Try to auto-attach file if default file name exists. if (item.FileName == null) { DefaultFileName = PathCalc.GetDefaultFileName(item.Artist, item.Title, item.MediaCategoryId, item.MediaType); foreach (string ext in Settings.GetMediaTypeExtensions(item.MediaType)) { FilePath = Settings.NaturalGroundingFolder + DefaultFileName + ext; if (File.Exists(FilePath)) { item.FileName = DefaultFileName + ext; HasChanges = true; await Task.Delay(1); break; } } } // Load media file to set Length, Width and Height. if (item.FileName != null && await MediaInfo.LoadInfoAsync(item)) HasChanges = true; // Send update with the quantity of files completed. if (loadingMediaInfoProgress != null) loadingMediaInfoProgress.Report(++ItemsCompleted); } MediaInfo.Dispose(); if (HasChanges) context.SaveChanges(); } isLoadingMediaInfo = false; loadingMediaInfoCount = 0; loadingMediaInfoProgress = null; return HasChanges; }
/// <summary> /// Returns whether the local file should be replaced by the YouTube version. /// </summary> /// <param name="localFile">A path to the local file.</param> /// <param name="serverFile">The information of the available server file.</param> /// <returns>True if the local file should be replaced.</returns> public async Task<VideoListItemStatusEnum> IsHigherQualityAvailable(string localFile, BestFormatInfo serverFile) { // If there is no local file, it should be downloaded. if (!File.Exists(localFile)) return VideoListItemStatusEnum.HigherQualityAvailable; // If local file is FLV and there's another format available, it should be downloaded. string LocalFileExt = Path.GetExtension(localFile).ToLower(); if (LocalFileExt == ".flv" && serverFile.BestVideo.VideoType != VideoType.Flash) return VideoListItemStatusEnum.HigherQualityAvailable; // Original VCD files and files of unrecognized extensions should not be replaced. MediaInfoReader InfoReader = new MediaInfoReader(); await InfoReader.LoadInfoAsync(localFile); if (!DownloadBusiness.DownloadedExtensions.Contains(LocalFileExt) || InfoReader.VideoFormat == "MPEG Video") { serverFile.StatusText = "Not from YouTube"; return VideoListItemStatusEnum.OK; } // For server file size, estimate 10% extra for audio. Estimate 35% advantage for VP9 format. non-DASH WebM is VP8 and doesn't have that bonus. long ServerFileSize = (long)(serverFile.BestVideo.FileSize * 1.1); if (serverFile.BestVideo.VideoType == VideoType.WebM && serverFile.BestVideo.AdaptiveType == AdaptiveType.Video) ServerFileSize = (long)(ServerFileSize * 1.35); long LocalFileSize = new FileInfo(localFile).Length; if (InfoReader.VideoFormat == "VP9") LocalFileSize = (long)(LocalFileSize * 1.35); // If server resolution is better, download unless local file is bigger. int LocalFileHeight = InfoReader.Height ?? 0; if (serverFile.BestVideo.Resolution > LocalFileHeight) { if (ServerFileSize > LocalFileSize) return VideoListItemStatusEnum.HigherQualityAvailable; else if (ServerFileSize != 0) { // non-DASH videos have no file size specified, and we won't replace local video with non-DASH video. serverFile.StatusText = "Local file larger"; return VideoListItemStatusEnum.OK; } } // Is estimated server file size is at least 15% larger than local file (for same resolution), download. if (ServerFileSize > LocalFileSize * 1.15) return VideoListItemStatusEnum.HigherQualityAvailable; // download audio and merge with local video. (that didn't work, ffmpeg failed to merge back) int? LocalAudioBitRate = InfoReader.AudioBitRate; int ServerAudioBitRate = serverFile.BestAudio != null ? serverFile.BestAudio.AudioBitrate : serverFile.BestVideo.AudioBitrate; // Fix a bug where MediaInfo returns no bitrate for MKV containers with AAC audio. if (LocalAudioBitRate != null || LocalFileExt != ".mkv") { if ((LocalAudioBitRate == null || LocalAudioBitRate < ServerAudioBitRate * .8) && serverFile.BestVideo.Resolution == LocalFileHeight) { // Only redownload for audio if video file size is similar. Videos with AdaptiveType=None don't have file size. if (ServerFileSize > LocalFileSize * .9 && serverFile.BestVideo.AdaptiveType == AdaptiveType.Video) { serverFile.StatusText = "Audio"; return VideoListItemStatusEnum.HigherQualityAvailable; } else { serverFile.StatusText = ""; return VideoListItemStatusEnum.BetterAudioAvailable; } } } return VideoListItemStatusEnum.OK; }
private async void menuExtractAudio_Click(object sender, RoutedEventArgs e) { if (video.FileName != null && File.Exists(Settings.NaturalGroundingFolder + video.FileName)) { MediaInfoReader MInfo = new MediaInfoReader(); await MInfo.LoadInfoAsync(Settings.NaturalGroundingFolder + video.FileName); string Ext = null; if (MInfo.AudioFormat == "MPEG Audio") Ext = ".mp2"; else if (MInfo.AudioFormat == "PCM") Ext = ".wav"; else if (MInfo.AudioFormat == "Vorbis") Ext = ".ogg"; else if (MInfo.AudioFormat == "Opus") Ext = ".opus"; else Ext = ".aac"; SaveFileDialog SaveDlg = new SaveFileDialog(); SaveDlg.InitialDirectory = Settings.NaturalGroundingFolder + "Audios"; SaveDlg.OverwritePrompt = true; SaveDlg.DefaultExt = ".mp3"; SaveDlg.Filter = string.Format("Audio Files|*{0})", Ext); ; SaveDlg.FileName = Path.GetFileNameWithoutExtension(video.FileName) + Ext; if (SaveDlg.ShowDialog() == true) { FfmpegBusiness.ExtractAudio(Settings.NaturalGroundingFolder + video.FileName, SaveDlg.FileName); } } }
private async Task LoadMediaInfoAsync() { MediaInfoReader MediaInfo = new MediaInfoReader(); await MediaInfo.LoadInfoAsync(video); MediaInfo.Dispose(); DimensionText.GetBindingExpression(TextBox.TextProperty).UpdateTarget(); }
private async Task LoadMediaInfoAsync() { using (MediaInfoReader MediaInfo = new MediaInfoReader()) { await MediaInfo.LoadInfoAsync(video); DimensionText.GetBindingExpression(TextBox.TextProperty).UpdateTarget(); DisablePitchCheckBox.IsEnabled = MediaInfo.PixelAspectRatio == 1; if (!DisablePitchCheckBox.IsEnabled) video.DisablePitch = false; } }
private async Task GetMediaInfo(string previewFile, MediaEncoderSettings settings) { MediaInfoReader InfoReader = new MediaInfoReader(); await InfoReader.LoadInfoAsync(previewFile); settings.SourceWidth = InfoReader.Width; settings.SourceHeight = InfoReader.Height; settings.SourceAspectRatio = InfoReader.PixelAspectRatio ?? 1; // Fix last track of VCDs that is widescreen. if (settings.SourceHeight == 288 && settings.SourceWidth == 352 && settings.SourceAspectRatio == 1.485f) settings.SourceAspectRatio = 1.092f; settings.SourceFrameRate = InfoReader.FrameRate; if (settings.ConvertToAvi) await InfoReader.LoadInfoAsync(Settings.NaturalGroundingFolder + settings.FileName); settings.AudioRequiresMkv = (InfoReader.AudioFormat != "AAC"); settings.Position = (InfoReader.Length ?? 0) / 2; }
private async Task GetMediaInfo(string previewFile, MediaEncoderSettings settings) { using (MediaInfoReader InfoReader = new MediaInfoReader()) { await InfoReader.LoadInfoAsync(previewFile); settings.SourceWidth = InfoReader.Width; settings.SourceHeight = InfoReader.Height; settings.SourceAspectRatio = InfoReader.PixelAspectRatio ?? 1; if (settings.SourceAspectRatio != 1) { // Get aspect ratio from FFMPEG which is more accurate. float? SAR = FfmpegBusiness.GetPixelAspectRatio(settings); if (SAR.HasValue) settings.SourceAspectRatio = SAR.Value; } // Fix last track of VCDs that is widescreen. if (settings.SourceHeight == 288 && settings.SourceWidth == 352 && settings.SourceAspectRatio == 1.485f) settings.SourceAspectRatio = 1.092f; settings.SourceFrameRate = InfoReader.FrameRate; if (settings.ConvertToAvi) await InfoReader.LoadInfoAsync(Settings.NaturalGroundingFolder + settings.FileName); settings.SourceAudioFormat = InfoReader.AudioFormat; settings.SourceVideoFormat = InfoReader.VideoFormat; settings.SourceColorMatrix = InfoReader.Height < 720 ? ColorMatrix.Rec601 : ColorMatrix.Rec709; if (!settings.CanCopyAudio) settings.EncodeFormat = VideoFormats.Mkv; settings.SourceAudioBitrate = InfoReader.AudioBitRate; settings.SourceBitDepth = InfoReader.BitDepth; settings.Position = (InfoReader.Length ?? 0) / 2; settings.CalculateSize(); } }