void ProbeScript() { string avsFileName = null; switch (Program.InputType) { case FileType.Video: // Make our temporary file for the AviSynth script avsFileName = GetTemporaryFile(); WriteAvisynthScript(avsFileName, textBoxIn.Text); break; case FileType.Avisynth: avsFileName = Program.InputFile; break; } // ffprobe it var ffprobe = new FFprobe(avsFileName); avsScriptInfo = ffprobe.Probe(); }
void SetFile(string path) { try { ValidateInputFile(path); } catch (Exception e) { MessageBox.Show(e.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (inputFile != null) inputFile.Close(); UnloadFonts(); textBoxIn.Text = path; string fullPath = Path.GetDirectoryName(path); string name = Path.GetFileNameWithoutExtension(path); string title = name; if (textBoxOut.Text == _autoOutput || textBoxOut.Text == "") textBoxOut.Text = _autoOutput = Path.Combine(string.IsNullOrWhiteSpace(Properties.Settings.Default.RememberedFolderOut) ? fullPath : Properties.Settings.Default.RememberedFolderOut, name + ".webm"); audioDisabled = false; progressBarIndexing.Style = ProgressBarStyle.Marquee; progressBarIndexing.Value = 30; boxIndexingProgress.Text = ""; panelHideTheOptions.BringToFront(); buttonGo.Enabled = false; buttonPreview.Enabled = false; buttonBrowseIn.Enabled = false; textBoxIn.Enabled = false; inputFile = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read); // Reset filters Filters.ResetFilters(); DefaultSettings(); listViewProcessingScript.Clear(); boxAdvancedScripting.Checked = false; // STUB: this part is weak boxAdvancedScripting.Enabled = true; textBoxProcessingScript.Hide(); listViewProcessingScript.Show(); if (Path.GetExtension(path) == ".avs") { Program.InputFile = path; Program.InputType = FileType.Avisynth; BackgroundWorker probebw = new BackgroundWorker(); probebw.DoWork += delegate(object sender, DoWorkEventArgs e) { ProbeScript(); }; probebw.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) { boxAdvancedScripting.Enabled = false; listViewProcessingScript.Enabled = false; showToolTip("You're loading an AviSynth script, so Processing is disabled!", 3000); comboLevels.Enabled = boxDeinterlace.Enabled = boxDenoise.Enabled = false; buttonGo.Enabled = buttonBrowseIn.Enabled = textBoxIn.Enabled = true; toolStripFilterButtonsEnabled(false); panelHideTheOptions.SendToBack(); }; labelIndexingProgress.Text = "Probing script..."; probebw.RunWorkerAsync(); return; } else { Program.InputFile = path; Program.InputType = FileType.Video; Program.FileMd5 = null; listViewProcessingScript.Enabled = true; comboLevels.Enabled = boxDeinterlace.Enabled = boxDenoise.Enabled = true; } GenerateAvisynthScript(); // Hash some of the file to make sure we didn't index it already labelIndexingProgress.Text = "Hashing..."; logIndexingProgress("Hashing..."); using (MD5 md5 = MD5.Create()) using (FileStream stream = File.OpenRead(path)) { var filename = new UTF8Encoding().GetBytes(name); var buffer = new byte[4096]; filename.CopyTo(buffer, 0); stream.Read(buffer, filename.Length, 4096 - filename.Length); Program.FileMd5 = BitConverter.ToString(md5.ComputeHash(buffer)); logIndexingProgress("File hash is " + Program.FileMd5.Replace("-", "")); _indexFile = Path.Combine(Path.GetTempPath(), Program.FileMd5 + ".ffindex"); } FFMSSharp.Index index = null; indexbw = new BackgroundWorker(); BackgroundWorker extractbw = new BackgroundWorker(); indexbw.WorkerSupportsCancellation = true; indexbw.WorkerReportsProgress = true; indexbw.ProgressChanged += new ProgressChangedEventHandler(delegate(object sender, ProgressChangedEventArgs e) { this.progressBarIndexing.Value = e.ProgressPercentage; }); indexbw.DoWork += delegate(object sender, DoWorkEventArgs e) { logIndexingProgress("Indexing starting..."); FFMSSharp.Indexer indexer = new FFMSSharp.Indexer(path, FFMSSharp.Source.Lavf); indexer.UpdateIndexProgress += delegate(object sendertwo, FFMSSharp.IndexingProgressChangeEventArgs etwo) { indexbw.ReportProgress((int)(((double)etwo.Current / (double)etwo.Total) * 100)); indexer.CancelIndexing = indexbw.CancellationPending; }; try { if (audioDisabled) // Indexing failed because of the audio, so the user disabled it. { List<int> indexList = new List<int>(); // An empty list means index no tracks. index = indexer.Index(indexList); } else { index = indexer.Index(); } } catch (OperationCanceledException) { audioDisabled = false; // This enables us to cancel the bw even if audio was disabled by the user. e.Cancel = true; return; } catch (Exception error) { if (error.Message.StartsWith("Audio format change detected")) { const string message = "\nIf you were planning on making a WebM with audio, I'm afraid that's not going to happen.\nWould you like to index the file without audio?"; const string caption = "Error"; DialogResult result = DialogResult.Cancel; this.InvokeIfRequired(() => { result = MessageBox.Show(message, caption, MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); }); audioDisabled = (result == DialogResult.OK); } else { MessageBox.Show(error.Message); } e.Cancel = true; return; } index.WriteIndex(_indexFile); }; extractbw.DoWork += new DoWorkEventHandler(delegate { logIndexingProgress("Extraction starting..."); List<int> videoTracks = new List<int>(), audioTracks = new List<int>(); for (int i = 0; i < index.NumberOfTracks; i++) { switch (index.GetTrack(i).TrackType) { case FFMSSharp.TrackType.Video: videoTracks.Add(i); break; case FFMSSharp.TrackType.Audio: audioTracks.Add(i); break; } } if (videoTracks.Count == 0) throw new Exception("No video tracks found!"); else if (videoTracks.Count == 1) { videotrack = videoTracks[0]; } else { this.InvokeIfRequired(() => { var dialog = new TrackSelectDialog("Video", videoTracks); logIndexingProgress("Waiting for user input..."); dialog.ShowDialog(this); videotrack = dialog.SelectedTrack; }); } if (!audioDisabled) { if (audioTracks.Count == 0) { audioDisabled = true; } else if (audioTracks.Count == 1) { audiotrack = audioTracks[0]; audioDisabled = false; } else { this.InvokeIfRequired(() => { var dialog = new TrackSelectDialog("Audio", audioTracks); logIndexingProgress("Waiting for user input..."); dialog.ShowDialog(this); audiotrack = dialog.SelectedTrack; }); audioDisabled = false; } } Program.AttachmentDirectory = Path.Combine(Path.GetTempPath(), Program.FileMd5 + ".attachments"); Directory.CreateDirectory(Program.AttachmentDirectory); logIndexingProgress("Probing input file..."); using (var prober = new FFprobe(Program.InputFile, format: "", argument: "-show_streams -show_format")) { string streamInfo = prober.Probe(); Program.SubtitleTracks = new Dictionary<int, Tuple<string, SubtitleType, string>>(); Program.AttachmentList = new List<string>(); using (var s = new StringReader(streamInfo)) { var doc = new XPathDocument(s); var attachindex = 0; // mkvextract separates track and attachment indices foreach (XPathNavigator nav in doc.CreateNavigator().Select("//ffprobe/streams/stream")) { int streamindex; string streamtitle; string file; streamindex = int.Parse(nav.GetAttribute("index", "")); switch (nav.GetAttribute("codec_type", "")) { case "video": if (streamindex != videotrack) break; // Check if this is a FRAPS yuvj420p video - if so, we need to do something weird here. if (nav.GetAttribute("codec_name", "") == "fraps" && nav.GetAttribute("pix_fmt", "") == "yuvj420p") { logIndexingProgress("Detected yuvj420p FRAPS video, the Color Level fixing setting has been set for you."); this.InvokeIfRequired(() => { comboLevels.SelectedIndex = 2; // PC -> TV conversion }); // If we don't do this, the contrast gets f****d. // See: https://github.com/nixxquality/WebMConverter/issues/89 } // Probe for sample aspect ratio string[] sar = null, dar = null; sar = nav.GetAttribute("sample_aspect_ratio", "").Split(':'); if ((sar[0] == "1" && sar[1] == "1") || (sar[0] == "0" || sar[1] == "0")) break; dar = nav.GetAttribute("display_aspect_ratio", "").Split(':'); float SarNum, SarDen, DarNum, DarDen; SarNum = float.Parse(sar[0]); SarDen = float.Parse(sar[1]); DarNum = float.Parse(dar[0]); DarDen = float.Parse(dar[1]); SarWidth = int.Parse(nav.GetAttribute("width", "")); SarHeight = int.Parse(nav.GetAttribute("height", "")); if (DarNum < DarDen) { SarHeight = (int)(SarHeight / (SarNum / SarDen)); } else { SarWidth = (int)(SarWidth * (SarNum / SarDen)); } SarCompensate = true; logIndexingProgress("We need to compensate for Sample Aspect Ratio, it seems."); break; case "subtitle": // Extract the subtitle file // Get a title streamtitle = nav.GetAttribute("codec_name", ""); SubtitleType type; string extension; if (streamtitle == "dvdsub") // Hold on a moment, this is a vobsub! { type = SubtitleType.VobSub; extension = ".idx"; } else { type = SubtitleType.TextSub; extension = "." + streamtitle; // YOLO } file = Path.Combine(Program.AttachmentDirectory, string.Format("sub{0}{1}", streamindex, extension)); logIndexingProgress(string.Format("Found subtitle track #{0}", streamindex)); if (!File.Exists(file)) // If we didn't extract it already { logIndexingProgress("Extracting..."); using (var mkvextract = new MkvExtract(string.Format(@"tracks ""{0}"" ""{1}:{2}""", Program.InputFile, streamindex, file))) { mkvextract.Start(); mkvextract.WaitForExit(); } } else { logIndexingProgress("Already extracted! Skipping..."); } if (!File.Exists(file)) // Holy shit, it still doesn't exist? break; // Whatever, skip it. if (!nav.IsEmptyElement) // There might be a tag element { nav.MoveTo(nav.SelectSingleNode(".//tag[@key='title']")); var titleTag = nav.GetAttribute("value", ""); streamtitle = titleTag == "" ? streamtitle : titleTag; } // Save it Program.SubtitleTracks.Add(streamindex, new Tuple<string, SubtitleType, string>(streamtitle, type, extension)); break; case @"attachment": // Extract the attachment using mkvmerge nav.MoveTo(nav.SelectSingleNode(".//tag[@key='filename']")); var filename = nav.GetAttribute("value", ""); nav.MoveToNext(); var mimetype = nav.GetAttribute("value", ""); file = Path.Combine(Program.AttachmentDirectory, filename); logIndexingProgress(string.Format("Found attachment '{0}'", filename)); attachindex += 1; if (!mimetype.Contains(@"font")) { logIndexingProgress("Not a font! Skipping..."); break; } Program.AttachmentList.Add(filename); if (File.Exists(file)) // Did we extract it already? { logIndexingProgress("Already extracted! Skipping..."); break; } logIndexingProgress("Extracting..."); using (var mkvextract = new MkvExtract(string.Format(@"attachments ""{0}"" ""{1}:{2}""", Program.InputFile, attachindex, file))) { mkvextract.Start(); mkvextract.WaitForExit(); } break; } } var selectSingleNode = doc.CreateNavigator().SelectSingleNode("//ffprobe/format/tag[@key='title']"); if (selectSingleNode != null) { title = selectSingleNode.GetAttribute("value", ""); logIndexingProgress("Found title " + title); } } } Program.VideoSource = index.VideoSource(path, videotrack); var frame = Program.VideoSource.GetFrame(0); // We're assuming that the entire video has the same settings here, which should be fine. (These options usually don't vary, I hope.) Program.VideoColorRange = frame.ColorRange; Program.VideoInterlaced = frame.InterlacedFrame; SetSlices(frame.EncodedResolution); LoadFonts(msg => logIndexingProgress((string)msg)); }); indexbw.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) { if (audioDisabled == true && e.Cancelled) { indexbw.RunWorkerAsync(); return; } indexing = false; buttonGo.Enabled = false; buttonGo.Text = "Convert"; if (e.Cancelled) { CancelIndexing(); } else { labelIndexingProgress.Text = "Extracting subtitle tracks and attachments..."; progressBarIndexing.Value = 30; progressBarIndexing.Style = ProgressBarStyle.Marquee; extractbw.RunWorkerAsync(); } }; extractbw.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) { CancelIndexing(); const string text = "We couldn't find any video tracks!\nPlease use another input file."; const string caption = "ERROR"; MessageBox.Show(text, caption, MessageBoxButtons.OK, MessageBoxIcon.Error); } boxAudio.Enabled = Program.InputHasAudio = true; if (audioDisabled) { switch (Path.GetExtension(path).ToLower()) { case ".png": break; case ".gif": break; case ".jpg": break; case ".jpeg": break; case ".bmp": break; default: const string text = "We couldn't find any audio tracks.\nIf you want sound, please use another input file.\nIf you don't want audio in your output webm, there's nothing to worry about."; const string caption = "FYI"; MessageBox.Show(text, caption, MessageBoxButtons.OK, MessageBoxIcon.Information); break; } boxAudio.Checked = boxAudio.Enabled = Program.InputHasAudio = false; } buttonGo.Enabled = true; buttonPreview.Enabled = true; buttonBrowseIn.Enabled = true; textBoxIn.Enabled = true; toolStripFilterButtonsEnabled(true); if (boxTitle.Text == _autoTitle || boxTitle.Text == "") boxTitle.Text = _autoTitle = title; if (Program.VideoColorRange == FFMSSharp.ColorRange.MPEG) //boxLevels.Checked = true; if (Program.VideoInterlaced) boxDeinterlace.Checked = true; panelHideTheOptions.SendToBack(); }; if (File.Exists(_indexFile)) { try { index = new FFMSSharp.Index(_indexFile); if (index.BelongsToFile(path)) { try { index.GetFirstIndexedTrackOfType(FFMSSharp.TrackType.Audio); } catch (KeyNotFoundException) { audioDisabled = true; } labelIndexingProgress.Text = "Extracting subtitle tracks and attachments..."; progressBarIndexing.Value = 30; progressBarIndexing.Style = ProgressBarStyle.Marquee; extractbw.RunWorkerAsync(); return; } } catch { File.Delete(_indexFile); } } indexing = true; buttonGo.Enabled = true; buttonGo.Text = "Cancel"; progressBarIndexing.Value = 0; progressBarIndexing.Style = ProgressBarStyle.Continuous; labelIndexingProgress.Text = "Indexing..."; indexbw.RunWorkerAsync(); }