/// <summary> /// Concat a second video at the end of the main video. /// </summary> /// <param name="secondVideo">The second video to add at the end of the main one.</param> public void concatVideos(Video secondVideo) { /* Conversion of both videos */ //this.video.convertVideo(); //secondVideo.convertVideo(); /* Settings needed to concatenate the videos */ String[] inputVideoPaths = new String[2]; String outputVideoPath = this.video.filePath; String outputName = this.video.fileName; String newPath = "C:\\Users\\Théo\\Desktop\\videos\\final.mp4"; String commandConcat = "- i \"concat:" + this.video.filePath + "|" + secondVideo.filePath + "\" - codec copy " + outputVideoPath; long outputSize = video.fileSize + secondVideo.fileSize; inputVideoPaths[0] = video.filePath; inputVideoPaths[1] = secondVideo.filePath; var concatSetting = new NReco.VideoConverter.ConcatSettings(); //concatSetting.ConcatVideoStream = true; //concatSetting.ConcatAudioStream = false; //concatSetting.VideoCodec = "h264"; //concatSetting.VideoFrameRate = 30; //concatSetting.SetVideoFrameSize(1280, 720); processPercentage = "0 %"; ffMpegConverter.ConvertProgress += updateProgress; ffMpegConverter.ConcatMedia(inputVideoPaths, newPath, Format.mp4, concatSetting); video = new Model.Video(newPath, "final", outputSize); }
static void Main(string[] args) { _handler += new EventHandler(Handler); SetConsoleCtrlHandler(_handler, true); try { for (int i = 0; i < args.Length; i++) { if (args[i].Substring(0, 2) != "--") { switch (args[i]) { case "-p": SourcePath = args[++i].TrimEnd('\\'); break; case "-it": InputsType = args[++i].TrimStart('.').ToLower(); break; case "-i": Intervals = int.TryParse(args[++i], out int intervals) ? intervals : 3; break; } } else { string param = args[i].Remove(args[i].IndexOf('=') + 1); string value = args[i].Substring(args[i].IndexOf('=') + 1); switch (param) { case "--path": SourcePath = value.TrimEnd('\\'); break; case "--inputs_type": InputsType = value.TrimStart('.').ToLower(); break; case "--output_type": OutputType = value.TrimStart('.').ToLower(); break; case "--interval": Intervals = int.TryParse(value, out int intervals) ? intervals : 3; break; case "--preset": if (Enum.GetNames(typeof(PresetType)).Any(type => type.ToLower() == args[i + 1].ToLower())) { FFMpegSettings.Preset = (PresetType)Enum.Parse(typeof(PresetType), value, true); } else { PresetRecord = value; } break; case "--crf": if (int.TryParse(value, out int crfScale)) { FFMpegSettings.CRFScale = crfScale; } else { FFMpegSettings.CRFScale = -1; } break; case "--aq": if (decimal.TryParse(args[i + 1], out decimal audioQuality)) { FFMpegSettings.AudioQuality = Math.Round(audioQuality, 1, MidpointRounding.AwayFromZero); } else { FFMpegSettings.AudioQuality = -1; } break; } } } } catch (Exception ex) { Log(contents: "Error input", messageType: MessageType.ERROR); Log(contents: ex.Message, messageType: MessageType.ERROR); Console.WriteLine(); return; } Log(contents: "Start processing"); long beginTick = DateTime.Now.Ticks; if (!Directory.Exists(SourcePath)) { Log(contents: $@"Can NOT match the source folder ""{ SourcePath }""", messageType: MessageType.ERROR); } else if (!typeof(Format).GetFields(BindingFlags.Public | BindingFlags.Static).Any(format => format.Name.ToLower() == InputsType)) { Log(contents: $@"""{ InputsType.ToUpper() }"" is NOT support for input", messageType: MessageType.ERROR); } else if (!typeof(Format).GetFields(BindingFlags.Public | BindingFlags.Static).Any(format => format.Name.ToLower() == OutputType)) { Log(contents: $@"""{ OutputType.ToUpper() }"" is NOT support for output", messageType: MessageType.ERROR); } else if (!string.IsNullOrEmpty(PresetRecord)) { Log(contents: $@"""{ PresetRecord.ToUpper() }"" is NOT support for preset type", messageType: MessageType.ERROR); } else if (51 < FFMpegSettings.CRFScale || FFMpegSettings.CRFScale < 0) { Log(contents: $@"""{ FFMpegSettings.CRFScale }"" is out of CRF scale range (the value should be 0-51)", messageType: MessageType.ERROR); } else if (10m < FFMpegSettings.AudioQuality || FFMpegSettings.AudioQuality < 0.1m) { Log(contents: $@"""{ FFMpegSettings.AudioQuality }"" is out of audio quality range (the value should be 1-10)", messageType: MessageType.ERROR); } else { try { Log(contents: "Parse the folder structure", messageType: MessageType.INFO); Videos = new Dictionary <string, List <Video> >(); PassVideos = new List <string[]>(); foreach (var videoPath in Directory.GetFiles(SourcePath, $"*.{ InputsType }").ToList()) { string videoName = videoPath; videoName = videoName.Remove(0, videoName.LastIndexOf('\\') + 1); videoName = videoName.Remove(videoName.LastIndexOf('.')); if (Videos.Count <= 0) { Videos.Add(videoName, new List <Video>() { new Video() { Name = videoName, Path = videoPath, Type = InputsType } }); } else { int length = DateTime.Now.ToString("yyyyMMdd_HHmmss").Length; if (videoName.Length != length) { PassVideos.Add(new string[] { videoName, $"Error name format (length != { length })" }); } else if (!Regex.IsMatch(videoName, @"^\d+_\d+$")) { PassVideos.Add(new string[] { videoName, $"Error name format (is not all numbers)" }); } else { DateTime lastTime = DateTime.ParseExact(Videos.Last().Value.Last().Name, "yyyyMMdd_HHmmss", CultureInfo.InvariantCulture); DateTime thisTime = DateTime.ParseExact(videoName, "yyyyMMdd_HHmmss", CultureInfo.InvariantCulture); if ((thisTime - lastTime).TotalMinutes <= Intervals) { Videos.Last().Value.Add(new Video() { Name = videoName, Path = videoPath, Type = InputsType }); } else { Videos.Add(videoName, new List <Video>() { new Video() { Name = videoName, Path = videoPath, Type = InputsType } }); } } } } DisplayVideos(); // Init FFMpegConverter FFMpegConverter = new FFMpegConverter(); FFMpegConverter.ConvertProgress += FFMpegConverter_ConvertProgress; var format = typeof(Format) .GetFields(BindingFlags.Public | BindingFlags.Static) .First(f => f.Name.ToLower() == OutputType).Name; // Join videos foreach (var pair in Videos) { try { string folderPath = $@"{ SourcePath }\Joins"; if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } JoinVideoName = pair.Key; Log(contents: $"Preparing to join video in { JoinVideoName }.{ format.ToString() }", messageType: MessageType.INFO); FFMpegConverter.ConcatMedia( inputFiles: pair.Value.Select(video => video.Path).ToArray(), outputFile: $@"{ folderPath }\{ pair.Key }.{ format.ToString() }", outputFormat: Format.mov.ToString(), settings: new ConcatSettings() { CustomOutputArgs = FFMpegSettings.GetArgsLine() }); ClearCurrentConsoleLine(); Log(contents: $"Join video in { JoinVideoName }.{ format.ToString() }", messageType: MessageType.INFO, writeMode: WriteMode.Append); Log(contents: " take", messageType: MessageType.INFO, withTitle: false, writeMode: WriteMode.Append); Log(contents: $" { new TimeSpan(DateTime.Now.Ticks - beginTick).Days.ToString().PadLeft(2, ' ') } d" + $" { new TimeSpan(DateTime.Now.Ticks - beginTick).Hours.ToString().PadLeft(2, ' ') } h" + $" { new TimeSpan(DateTime.Now.Ticks - beginTick).Minutes.ToString().PadLeft(2, ' ') } m" + $" { new TimeSpan(DateTime.Now.Ticks - beginTick).Seconds.ToString().PadLeft(2, ' ') } s", messageType: MessageType.TIME, withTitle: false, onlyTitleColor: false); } catch (Exception ex) { Log(contents: $"Join video in { JoinVideoName }.{ format.ToString() } ({ ex.Message })", messageType: MessageType.ERROR); } } // Summary Log(contents: $"Process exited in", messageType: MessageType.INFO, withTitle: true, writeMode: WriteMode.Append); Log(contents: $" { new TimeSpan(DateTime.Now.Ticks - beginTick).Days.ToString() } d" + $" { new TimeSpan(DateTime.Now.Ticks - beginTick).Hours.ToString() } h" + $" { new TimeSpan(DateTime.Now.Ticks - beginTick).Minutes.ToString() } m" + $" { new TimeSpan(DateTime.Now.Ticks - beginTick).Seconds.ToString() } s", messageType: MessageType.TIME, withTitle: false, onlyTitleColor: false, writeMode: WriteMode.Append); } catch (Exception ex) { Log(contents: ex.Message, messageType: MessageType.ERROR); } } Console.WriteLine(); }
private void aGenerateVideoButton_Click(object sender, EventArgs e) { aErrorText.Text = ""; var videoInput = aVideoURLs.Text.TrimEnd('\r', '\n'); var videoURLs = videoInput.Split('\n'); aProgressBar.Visible = true; aProgressBar.Style = ProgressBarStyle.Marquee; aProgressBar.MarqueeAnimationSpeed = 30; var videoNum = 1; var videosFolderPath = Application.StartupPath + @"\Videos"; if (!Directory.Exists(videosFolderPath)) { Directory.CreateDirectory(videosFolderPath); } Thread thread = new Thread(() => { var videos = new string[videoURLs.Length]; foreach (var video in videoURLs) { using (WebClient client = new WebClient()) { try { client.DownloadFile(new Uri(video), videosFolderPath + @"\video" + videoNum + ".mp4"); } catch { aProgressBar.Visible = false; aErrorText.Text = "Error: Invalid Twitch Clip Links"; return; } videos[videoNum - 1] = videosFolderPath + @"\video" + videoNum + ".mp4"; videoNum++; } } if (aCompileVideos.Checked) { var validFileName = !string.IsNullOrEmpty(aFileName.Text) && aFileName.Text.IndexOfAny(Path.GetInvalidFileNameChars()) < 0; if (!validFileName) { aProgressBar.Visible = false; aErrorText.Text = "Error: Invalid File Name"; return; } var outputLocation = videosFolderPath + @"\" + aFileName.Text + ".mp4"; var ffMpeg = new FFMpegConverter(); var set = new ConcatSettings(); set.ConcatVideoStream = true; set.ConcatAudioStream = true; try { set.SetVideoFrameSize(Convert.ToInt32(aXResolution.Text), Convert.ToInt32(aYResolution.Text)); } catch { aProgressBar.Visible = false; aErrorText.Text = "Error: Invalid Resolution"; return; } var videosDuplicate = videos; if (aAddIntro.Checked) { var temp = new string[videos.Length + 1]; temp[0] = openFileDialog1.FileName; for (int i = 0; i < videos.Length; i++) { temp[i + 1] = videos[i]; } videos = temp; } if (aAddOutro.Checked) { var temp = new string[videos.Length + 1]; temp[videos.Length] = openFileDialog2.FileName; for (int i = 0; i < videos.Length; i++) { temp[i] = videos[i]; } videos = temp; } try { ffMpeg.ConcatMedia(videos, outputLocation, Format.mp4, set); } catch (Exception) { aProgressBar.Visible = false; if (aAddIntro.Checked) { aErrorText.Text = "Error: Invalid Resolution or Invalid Twitch Clip URLs or Invalid Intro/Outro Resolution"; } else { aErrorText.Text = "Error: Invalid Resolution or Invalid Twitch Clip URLs"; } return; } if (aDeleteClipsAfterwards.Visible && aDeleteClipsAfterwards.Checked) { var listToUse = aAddIntro.Checked || aAddOutro.Checked ? videosDuplicate : videos; foreach (var videoPath in listToUse) { if (File.Exists(videoPath)) { File.Delete(videoPath); } } } } aProgressBar.Visible = false; }) { IsBackground = true }; thread.Start(); }
private void MergeFiles() { string empty = string.Empty; int num = 0; if (this.media.Count > 0) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Network.SetAcl(this.VideoPath); using (RPM_VideoTag rPMVideoTag = new RPM_VideoTag()) { foreach (MediaFile medium in this.media) { this.TagList = rPMVideoTag.GetTagList(medium.FileID); foreach (VideoTag tagList in this.TagList) { TimeSpan timeSpan = new TimeSpan(0, 0, Convert.ToInt32(tagList.StartTime)); TimeSpan timeSpan1 = new TimeSpan(0, 0, Convert.ToInt32(tagList.EndTime)); string str = string.Format("{0:00}:{1:00}:{2:D2}", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds); string str1 = string.Format("{0:00}:{1:00}:{2:D2}", timeSpan1.Hours, timeSpan1.Minutes, timeSpan1.Seconds); TimeSpan timeSpan2 = timeSpan1 - timeSpan; string str2 = string.Format("{0:00}:{1:00}:{2:D2}", timeSpan2.Hours, timeSpan2.Minutes, timeSpan2.Seconds); ListItemsCollection items = this.vListBox.Items; object[] shortDesc = new object[] { tagList.ShortDesc, str, str1, str2 }; items.Insert(string.Format("{0} {1}-{2} Len: {3}", shortDesc), 0); string str3 = string.Format("{0}{1}", num, Path.GetExtension(medium.FileName)); try { ProcessStartInfo processStartInfo = new ProcessStartInfo() { UseShellExecute = false, CreateNoWindow = true, FileName = Path.Combine(Directory.GetCurrentDirectory(), "ffmpeg.exe") }; processStartInfo.CreateNoWindow = true; object[] fileName = new object[] { str, medium.FileName, str2, this.VideoPath, str3 }; processStartInfo.Arguments = string.Format("-v 0 -y -ss {0} -i \"{1}\" -t {2} -c:v copy -c:a copy \"{3}\\{4}\"", fileName); Process.Start(processStartInfo).WaitForExit(); } catch (Exception exception1) { Exception exception = exception1; this.vListBox.Items.Insert(exception.Message, 0); MessageBox.Show(exception.Message); } string str4 = Path.Combine(this.VideoPath, str3); if (!File.Exists(str4)) { this.vListBox.Items.Insert(string.Format(LangCtrl.GetString("mv_ErrorCreating", "Error creating: {0}"), str3), 0); } else { this.tFiles.Add(string.Format("{0}", str4)); num++; } } } string[] strArrays = new string[this.tFiles.Count]; int num1 = 0; foreach (string tFile in this.tFiles) { if (!File.Exists(tFile)) { continue; } strArrays[num1] = tFile; num1++; } if ((int)strArrays.Length > 0) { string str5 = "MP4"; if (this.btnAVI.Checked) { str5 = "AVI"; } if (this.btnMOV.Checked) { str5 = "MOV"; } string str6 = string.Format("{0}\\{1}.{2}", this.VideoPath, this.txtName.Text, str5); empty = str6; this.vListBox.Items.Insert(LangCtrl.GetString("mv_Merging", "Merging Video Files...This may take a few minutes..."), 0); Thread.Sleep(3000); if ((int)strArrays.Length != 1) { try { ConcatSettings concatSetting = new ConcatSettings(); FFMpegConverter fFMpegConverter = new FFMpegConverter(); Thread.Sleep(1000); fFMpegConverter.ConcatMedia(strArrays, str6, str5, concatSetting); } catch (Exception exception2) { this.vListBox.Items.Insert(exception2.Message, 0); } } else { File.Move(strArrays[0], str6); } } if (!this.chk_SaveSegments.Checked) { try { foreach (string tFile1 in this.tFiles) { if (!File.Exists(tFile1)) { continue; } File.Delete(tFile1); } } catch (Exception exception3) { this.vListBox.Items.Insert(exception3.Message, 0); } } stopwatch.Stop(); TimeSpan elapsed = stopwatch.Elapsed; string str7 = string.Format("{0:00}:{1:00}:{2:D2}", elapsed.Hours, elapsed.Minutes, elapsed.Seconds); this.vListBox.Items.Insert(string.Format(LangCtrl.GetString("mv_MergeComplete", "{0} - File Merge completed. Elapsed Time {1}"), DateTime.Now, str7), 0); if (File.Exists(empty) && Global.IsRights(Global.RightsProfile, UserRights.REDACT) && Global.IsRedact) { base.BeginInvoke(new MethodInvoker(() => { if (MessageBox.Show(this, LangCtrl.GetString("mv_RedactVideo", "Redact video file?"), "Redact", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { try { Global.Log("REDACT", string.Format("Redact Video Merge: {0}", empty)); Process.Start(new ProcessStartInfo() { FileName = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "Redact/VideoEditor.exe"), Arguments = string.Concat("\"", empty, "\"") }); } catch { } } })); } } base.BeginInvoke(new MethodInvoker(() => { this.btn_Close.Enabled = true; this.pictureBox1.Visible = false; })); } }