diff --git a/FFmpegFa.sln b/FFmpegFa.sln new file mode 100644 index 0000000..69c434c --- /dev/null +++ b/FFmpegFa.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2002 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFmpegFa", "FFmpegFa\FFmpegFa.csproj", "{9F016916-E740-4B9E-9F54-A7AF1C3BB311}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFmpegFaSample", "FFmpegFaSample\FFmpegFaSample.csproj", "{044E2738-F595-4186-AB3A-766DA0F7C0A1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApp1", "WpfApp1\WpfApp1.csproj", "{CC4F40D0-96D3-4F36-97AE-3CE0794173A1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9F016916-E740-4B9E-9F54-A7AF1C3BB311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F016916-E740-4B9E-9F54-A7AF1C3BB311}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F016916-E740-4B9E-9F54-A7AF1C3BB311}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F016916-E740-4B9E-9F54-A7AF1C3BB311}.Release|Any CPU.Build.0 = Release|Any CPU + {044E2738-F595-4186-AB3A-766DA0F7C0A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {044E2738-F595-4186-AB3A-766DA0F7C0A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {044E2738-F595-4186-AB3A-766DA0F7C0A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {044E2738-F595-4186-AB3A-766DA0F7C0A1}.Release|Any CPU.Build.0 = Release|Any CPU + {CC4F40D0-96D3-4F36-97AE-3CE0794173A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CC4F40D0-96D3-4F36-97AE-3CE0794173A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CC4F40D0-96D3-4F36-97AE-3CE0794173A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CC4F40D0-96D3-4F36-97AE-3CE0794173A1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {82BC0D1A-9561-43FB-B93F-E2EE141304A1} + EndGlobalSection +EndGlobal diff --git a/FFmpegFa/Audio.cs b/FFmpegFa/Audio.cs new file mode 100644 index 0000000..b149498 --- /dev/null +++ b/FFmpegFa/Audio.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace FFmpegFa +{ + /// + /// سمپل رِیت صدا + /// + public enum AudioSampleRate + { + /// + /// 8000 + /// + _8000, + /// + /// 16000 + /// + _16000, + /// + /// 22050 + /// + _22050, + /// + /// 32000 + /// + _32000, + /// + /// 44100 + /// + _44100 = 0, + /// + /// 48000 + /// + _48000 = 1, + /// + /// 72000 + /// + _72000, + /// + /// 96000 + /// + _96000 + } + /// + /// بیت رِیت صدا + /// + public enum AudioBitRate + { + /// + /// 32k + /// + _32, + /// + /// 64k + /// + _64, + /// + /// 96k + /// + _96, + /// + /// 112k + /// + _112, + /// + /// 128k + /// + _128, + /// + /// 160k + /// + _160, + /// + /// 192k + /// + _192, + /// + /// 256k + /// + _256, + /// + /// 320k + /// + _320, + /// + /// 448k + /// + _448, + /// + /// 512k + /// + _512, + /// + /// 640k + /// + _640 + } +} diff --git a/FFmpegFa/AudioFileType.cs b/FFmpegFa/AudioFileType.cs new file mode 100644 index 0000000..f2de39f --- /dev/null +++ b/FFmpegFa/AudioFileType.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace FFmpegFa +{ + /// + /// تایپ فایل های خروجی آهنگ ها + /// + public enum AudioFileType + { + Mp3, + Mp2, + Ogg, + Aac, + Ac3, + Wav, + M4a, + Wma + } +} diff --git a/FFmpegFa/ConverterCodecType.cs b/FFmpegFa/ConverterCodecType.cs new file mode 100644 index 0000000..786d005 --- /dev/null +++ b/FFmpegFa/ConverterCodecType.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace FFmpegFa +{ + /// + /// کدک تایپ + /// + public enum ConverterCodecType + { + /// + /// کدک ایکس 264 تقریبا بهترین کدک هست و همه ی فایل های تصویری رو پشتیبانی میکنه + /// + x264, + /// + /// کدک ایکس 265 فقط مخصوص فایل های ام کی وی هست + /// + x265 + } +} diff --git a/FFmpegFa/FFmpeg.cs b/FFmpegFa/FFmpeg.cs new file mode 100644 index 0000000..a5e2424 --- /dev/null +++ b/FFmpegFa/FFmpeg.cs @@ -0,0 +1,1768 @@ +using FFmpegFa.Helpers; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +//ffmpeg +//-i input +//-b 1200k +//-minrate 1200k +//-maxrate 1200k +//-bufsize 1200k +//-ab 64k +//-vcodec libx264 +//-acodec aac -strict -2 +//-ac 2 +//-ar 44100 +//-s 320x240 +//-y output.mp4 +/// +/// FFmpeg namespace +/// +namespace FFmpegFa +{ + /// + /// کلاس نمایش پروسه + /// + public class FFmpegProgress + { + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + /// + /// میزان پروسه طی شده + /// + public int Percent { get; set; } = 0; + /// + /// زمان فیلم اِنکُد شده + /// + public TimeSpan CurrentTime { get; set; } = TimeSpan.FromMilliseconds(0); + /// + /// فریم فعلی + /// + public int CurrentFrame { get; set; } = 0; + /// + /// فریم رِیت فعلی + /// + public double CurrentFrameRate { get; set; } = 0; + /// + /// سایز فعلی فایل نهایی + /// + public string CurrentFileSize { get; set; } = string.Empty; + /// + /// بیت رِیت فعلی + /// + public string CurrentBitRate { get; set; } = string.Empty; + /// + /// سرعت اِنکُدینگ کردن + /// + public string CurrentSpeed { get; set; } = string.Empty; + /// + /// اطلاعات فایل ورودی + /// + public FFmpegInfo InputFileInfo { get; set; } + } + /// + /// دِلیگِت وُید پروسه + /// + /// سِندِر + /// پروسه فایل + public delegate void FFmpegProgressChanged(FFmpeg sender, FFmpegProgress ffmpegProgress); + /// + /// کلاس اصلی، تمامی کارها در این کلاس انجام میشود + /// + public class FFmpeg: Interfaces.IFFmpeg, IDisposable + { + string StartupPath; + const string FFmpegPath = @"\ffmpeg.exe"; + /// + /// رویداد تغییرات + /// + public event FFmpegProgressChanged OnProgressChanged; + + /// + /// نسخه کتابخانه را به شما باز میگرداند + /// + /// نسخه کتابخانه + public string LibraryVersion() { return "1.0.0.0"; } + /// + /// درباره سازنده این کتابخانه + /// + /// اطلاعات سازنده + public string AboutAuthor() + { + return @"Nasrollah Jokar [Ramtin] Ramtinak@live.com [2018 - Shahrivar 1397]"; + } + + /// + /// ساخت کُنستراکتور + /// + public FFmpeg() + { + //StartupPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + StartupPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "ffmpegfa"); + if (!Directory.Exists(StartupPath)) + Directory.CreateDirectory(StartupPath); + ExtractFFmpeg(); + } + + /// + /// دیستِراکتور + /// + ~FFmpeg() + { + Dispose(); + } + + /// + /// اکسترکت کردن اف اف ام پی ای جی + /// + void ExtractFFmpeg() + { + try + { + if (!File.Exists(StartupPath + FFmpegPath)) + { + //new Thread(new ThreadStart(() => + //{ + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + if (!Directory.Exists(StartupPath)) + Directory.CreateDirectory(StartupPath); + var filePath = StartupPath + @"\ffmpeg.zip"; + File.WriteAllBytes(filePath, Properties.Resources.ffmpeg); + //Thread.Sleep(4000); + ArchiveManager.UnArchive(filePath, StartupPath); + //Thread.Sleep(1200); + //File.Delete(tempFilePath); + filePath = null; + stopwatch.Stop(); + Debug.WriteLine(stopwatch.Elapsed.ToString()); + //})).Start(); + + } + } + catch (Exception ex) { Debug.WriteLine("ExtractFFmpeg ex: " + ex.Message); } + } + + /// + /// گرفتن اطلاعات یک فایل ویدیویی + /// + /// مسیر فایل + /// مقدار بازگشتی + public FFmpegInfo GetInformation(string filePath) + { + var name = ""; + if (filePath.Contains("\\")) + name = Path.GetFileName(filePath); + else name = filePath; + + var content = RunCommandAndGetResponse($"-i \"{filePath}\""); + FFmpegInfo fFmpegInfo = new FFmpegInfo(content, name); + //OnInformation?.Invoke(this, fFmpegInfo); + + return fFmpegInfo; + } + + //ffprobe -v quiet -print_format json -show_format -show_streams somefile.asf + /*void RunCommandFFProbe(string command) + { + //var ffmpegPath = Application.StartupPath + @"\ffmpeg.exe"; + //var args = $"-show_streams -i \"{textBox1.Text}\""; + //Show(ffmpegPath); + //Show(args); + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + @"\ffprobe.exe"; + process.StartInfo.Arguments = command; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => { + StreamReader sr = process.StandardError; + GetResult("Start act"); + GetResult("Start Act\r\n" +sr.ReadToEnd() +"\r\nEnd Act"); + //while (!sr.EndOfStream) + //{ + // GetResult(sr.ReadLine()); + //} + })).Start(); + } + void RunCommand(string command) + { + //var ffmpegPath = Application.StartupPath + @"\ffmpeg.exe"; + //var args = $"-show_streams -i \"{textBox1.Text}\""; + //Show(ffmpegPath); + //Show(args); + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = command; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => { + StreamReader sr = process.StandardError; + GetResult("Start act\r\n"+sr.ReadToEnd() + "\r\nEnd Act"); + //while (!sr.EndOfStream) + //{ + // GetResult(sr.ReadLine()); + //} + //GetResult("End act"); + })).Start(); + } + */ + + /// + /// اجرای دستور و باز گردانی + /// + /// دستور برای ارسال + /// بازگردانی اطلاعات + string RunCommandAndGetResponse(string command) + { + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = command; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + StreamReader sr = process.StandardError; + var content = sr.ReadToEnd(); + + return content; + } + + /// + /// مبدل آهنگ(پیشفرض به ام پی تری تبدیل میکند) + /// + /// فایل ورودی(هم میتواند ویدیو باشد هم آهنگ) + /// آدرس و نام فایل خروجی + public void ConvertAudio(string inputFile, string outputFile) + { + ConvertAudio(inputFile, outputFile, AudioFileType.Mp3); + } + + /// + /// مبدل آهنگ + /// + /// فایل ورودی(هم میتواند ویدیو باشد هم آهنگ) + /// آدرس و نام فایل خروجی + /// نوع خروجی آهنگ + public void ConvertAudio(string inputFile, string outputFile,AudioFileType outputAudioType) + { + ConvertAudio(inputFile, outputFile, AudioFileType.Mp3, AudioSampleRate._44100, AudioBitRate._128); + } + + /// + /// مبدل آهنگ و تنظیمات کیفیت + /// + /// فایل ورودی(هم میتواند ویدیو باشد هم آهنگ) + /// آدرس و نام فایل خروجی + /// نوع خروجی آهنگ + /// سمپل رِیت آهنگ + /// بیت رِیت آهنگ + public void ConvertAudio(string inputFile, string outputFile, AudioFileType outputAudioType, + AudioSampleRate outputAudioSampleRate, AudioBitRate outputAudioBitRate) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + ////////////////////////////////////////////////////////////////////////////////////////// + //ffmpeg -i input.wav -vn -ar 44100 -ac 2 -ab 192k -f mp3 output.mp3 + //Explanation of the used arguments in this example: + //-i - input file + //-vn - Disable video, to make sure no video is included if the source would be a video file + //-ar - Set the audio sampling frequency. For output streams it is + //set by default to the frequency of the corresponding input stream. + //For input streams this option only makes sense for audio grabbing devices + //and raw demuxers and is mapped to the corresponding demuxer options. + + //-ac - Set the number of audio channels. For output streams it is set by default to the number + //of input audio channels. For input streams this option only makes sense for audio grabbing + //devices and raw demuxers and is mapped to the corresponding demuxer options. So used here + //to make sure it is stereo (2 channels) + + //-ab - actually seems to be changed, so should be replaced for newer ffmpeg version to -b:a 192k Converts the audio bitrate to be exact 192kbit per second + + //-f - Force input or output file format. The format is normally auto detected for input files and guessed from the file extension for output files, so this option is not needed in most cases + ////////////////////////////////////////////////////////////////////////////////////////// + + + //ffmpeg -i input.mp4 -b:v 1M -b:a 192k output.avi + //audio.ogg -f mp3 newfile.mp3 + + //var cmd = $"-i \"{ inputFile}\" -vn -f {audioFileType.ToString().ToLower()} \"{outputFile}\""; + //ffmpeg -i input.wav -vn -ar 44100 -ac 2 -ab 192k -f mp3 output.mp3 + + var bitRate = "128k"; + try + { + bitRate = outputAudioBitRate.ToString().Replace("_", "") + "k"; + } + catch { } + var sampleRate = "44100"; + try + { + sampleRate = outputAudioSampleRate.ToString().Replace("_", "") ; + } + catch { } + //ffmpeg -i input.mp3 -c:a libfdk_aac -b:a 128k output.m4a + var cmd = string.Empty; + //if (outputAudioType == AudioFileType.M4a) + // //ffmpeg -i input.mp3 -c:a libfdk_aac output.m4a + // //cmd = $"-i \"{inputFile}\" -vn -c:a libfdk_aac -b:a {bitRate} \"{outputFile}\""; + // //cmd = $"-i \"{inputFile}\" -vn -ar {sampleRate} -ac 2 -ab {bitRate} -f aac \"{outputFile}\""; + // //ffmpeg -i input.mp3 -c:a aac -b:a 192k output.m4a + // //-i input.mp3 -c:a aac -b:a 128k output.m4a + // cmd = $"-i \"{inputFile}\" -c:a aac -b:a 128k \"{outputFile}\""; + //else + cmd = $"-i \"{inputFile}\" -vn -ar {sampleRate} -ac 2 -ab {bitRate} -f {outputAudioType.ToString().ToLower()} \"{outputFile}\""; + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + //Thread.Sleep(3000); + //Debug.WriteLine(process.ProcessName); + //return; + + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + //GetResult("Start act\r\n" + sr.ReadToEnd() + "\r\nEnd Act"); + + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + + //Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + + } + + + /// + /// مبدل ویدیو + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + public void ConvertVideo(string inputFile, string outputFile) + { + ConvertVideo(inputFile, outputFile, ConverterCodecType.x264); + } + + /// + /// مبدل ویدیو(پیشفرض: ویدیو بیت 3000 و ایدیو بیت 192) + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + /// کدک برای مبدل(فقط برای فایل های ام کی وی) + public void ConvertVideo(string inputFile, string outputFile,ConverterCodecType outputCodecType) + { + + ConvertVideo(inputFile, outputFile, outputCodecType, VideoBitRate._3000k, AudioBitRate._192); + + } + + /// + /// مبدل ویدیو + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + /// کدک برای مبدل(فقط برای فایل های ام کی وی) + /// بیت رِیت ویدیو خروجی + /// بیت رِیت آهنگ ویدیو خروجی + public void ConvertVideo(string inputFile, string outputFile, ConverterCodecType outputCodecType, VideoBitRate outputVideoBitRate, AudioBitRate outputAudioBitRate) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + var lib = "libx264"; + if (Path.GetExtension(outputFile).ToLower() == ".mkv") + { + switch (outputCodecType) + { + + case ConverterCodecType.x265: + lib = "libx265"; + break; + default: + case ConverterCodecType.x264: + lib = "libx264"; + break; + } + } + var audioBitRate = "192k"; + try + { + audioBitRate = outputAudioBitRate.ToString().Replace("_", "") + "k"; + } + catch { } + var videoBitRate = "3000k"; + try + { + videoBitRate = outputAudioBitRate.ToString().Replace("_", ""); + } + catch { } + //ffmpeg -i input.mp4 -b:v 1M -b:a 192k output.avi + + //var cmd = (string.Format(FFmpegCommands.ConvertUltraFast, inputFile, outputFile, lib + " -b:v 4M -b:a 192k ")); + var cmd = (string.Format(FFmpegCommands.ConvertUltraFast, inputFile, outputFile, lib + $" -b:v {videoBitRate} -b:a {audioBitRate} ")); + + //var cmd = $"-i \"{ inputFile}\" -b:v 4M -b:a 192k \"{outputFile}\""; + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + //Thread.Sleep(3000); + //Debug.WriteLine(process.ProcessName); + //return; + + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + //GetResult("Start act\r\n" + sr.ReadToEnd() + "\r\nEnd Act"); + + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + // //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + + + + } + + /// + /// حذف صدا از ویدیو + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + public void RemoveAudioFromVideo(string inputFile, string outputFile) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + //var bitRate = "128k"; + + //var sampleRate = "44100"; + + var cmd = string.Empty; + // -c:v copy -c:a copy -map 0:v -map 0:a + cmd = $"-i \"{inputFile}\" -an -c:v copy -map 0:v \"{outputFile}\""; + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + //Thread.Sleep(3000); + //Debug.WriteLine(process.ProcessName); + //return; + + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + //GetResult("Start act\r\n" + sr.ReadToEnd() + "\r\nEnd Act"); + + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + Debug.WriteLine(v); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + //Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + + } + + /// + /// استخراج صدا از ویدیو + /// + /// فایل ورودی ویدیو + /// فایل خروجی آهنگ + public void ExtractAudioFromVideo(string inputFile, string outputFile) + { + ExtractAudioFromVideo(inputFile, outputFile, AudioBitRate._256); + } + + /// + /// استخراج صدا از ویدیو به همراه تنظیم بیت رِیت صدا + /// + /// فایل ورودی ویدیو + /// فایل خروجی آهنگ + /// بیت رِیت خروجی صدا + void ExtractAudioFromVideo(string inputFile, string outputFile, AudioBitRate outputAudioBitRate) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + var bitRate = "192"; + try + { + + bitRate = outputAudioBitRate.ToString().Replace("_", ""); + } catch { } + //var sampleRate = "44100"; + + var cmd = string.Empty; + //-i video.mp4 -vn -ab 256 audio.mp3 + cmd = $"-i \"{inputFile}\" -vn -ab {bitRate} \"{outputFile}\""; + cmd = $"-i \"{inputFile}\" -vn -b:a {bitRate} \"{outputFile}\""; + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + //Thread.Sleep(3000); + //Debug.WriteLine(process.ProcessName); + //return; + + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + //GetResult("Start act\r\n" + sr.ReadToEnd() + "\r\nEnd Act"); + + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + //Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + + } + + /// + /// تغییر سایز ویدیو + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + /// سایز جدید + public void ResizeVideo(string inputFile, string outputFile, VideoSize newSize) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + + + var cmd = string.Empty; + //-i input.mp4 -s 480x320 -c:a copy output.mp4 + var wh = string.Format("{0}x{1}", newSize.Width, newSize.Height); + + cmd = $"-i \"{inputFile}\" -s {wh} -c:a copy \"{outputFile}\""; + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + Debug.WriteLine(v); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + //Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + } + + /// + /// تغییر سایز ویدیو به همراه تنظیمات کیفیت + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + /// سایز جدید + /// بیت رِیت خروجی ویدیو + /// بیت رِیت خروجی صدا + public void ResizeVideo(string inputFile, string outputFile, VideoSize newSize, VideoBitRate outputVideoBitRate, AudioBitRate outputAudioBitRate) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + + var audioBitRate = "192k"; + try + { + audioBitRate = outputAudioBitRate.ToString().Replace("_", "") + "k"; + } + catch { } + var videoBitRate = "3000k"; + try + { + videoBitRate = outputAudioBitRate.ToString().Replace("_", ""); + } + catch { } + var cmd = string.Empty; + //-i input.mp4 -s 480x320 -c:a copy output.mp4 + var wh = string.Format("{0}x{1}", newSize.Width, newSize.Height); + + cmd = $"-i \"{inputFile}\" -s {wh} -b:v {videoBitRate} -b:a {audioBitRate} \"{outputFile}\""; + //var cmd = $"-i \"{ inputFile}\" -b:v 4M -b:a 192k \"{outputFile}\""; + ////cmd = $"-i \"{inputFile}\" -s {wh} -c:a copy \"{outputFile}\""; + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + Debug.WriteLine(v); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + //Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + } + + /// + /// اضافه کردن زیر نویس درون فایل ویدیویی + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + /// فایل های زیرنویس + public void MergeSubtitlesToVideo(string inputFile, string outputFile, /*string subtitleFile*/params string[] subtitlesFilePaths) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + + if (Path.GetExtension(outputFile).Replace(".", "").ToLower() != "mkv") + throw new Exception("Output file most be an MKV file."); + + var cmd = string.Empty; + //ffmpeg -newsubtitle subtitles.srv -i video.avi ... + //ffmpeg -i video.avi -vf subtitles=subtitle.srt out.avi + //ffmpeg - i video.avi - vf subtitles = subtitle.srt out.avi + + //ffmpeg -i video.mp4 -i subtitle1.srt -i subtitle2.srt -map 0 -map 1 -map 2 \ + //-c copy -metadata:s:s:0 language=eng -metadata:s:s:1 language=ipk output.mkv + + //ffmpeg -i Clean.mp4 -i spanish.ass -i english.ass -c:s mov_text -c:v copy -c:a copy -map 0:v -map 0:a -map 1 -map 2 -metadata:s:s:0 language=spa -metadata:s:s:1 language=eng With2CC.mp4 + + var subtitle = ""; + var map = ""; + var ix = 1; + var cs = ""; + var meta = ""; + foreach (var item in subtitlesFilePaths) + { + subtitle += $"-i \"{item}\" "; + map += $"-map {ix}:0 "; + //-c:s srt + var extension = Path.GetExtension(item).Replace(".", "").ToLower(); + cs += $"-c:s {extension} "; + //-metadata:s:a:0 language=eng -metadata:s:a:0 title="Title 1" \ + + meta += $"-metadata:s:s:{ix-1} language=unknown -metadata:s:s:{ix - 1} title=\"Subtitle Track #{ix}\" "; + ix++; + } + //ffmpeg -f concat -i files.lst -c copy -scodec copy output.mp4 + //cmd = $"-i \"{inputFile}\" \"{subtitle}\" -c:s mov_text -c:v copy -c:a copy -map 0:v -map 0:a -map 1 -map 2 -metadata:s:s:0 language=spa -metadata:s:s:1 language=eng"; + + //cmd = $"-f concat -i \"{inputFile}\" \"{subtitle}\" -c copy -scodec copy \"{outputFile}\""; + //ffmpeg -i infile.mp4 -i infile.srt -c copy -c:s mov_text outfile.mp4 + //cmd = $"-i \"{inputFile}\" \"{subtitle}\" -c copy -c:s mov_text -c:v copy -c:a copy \"{outputFile}\""; + //ffmpeg -i input.mp4 -f srt -i input.srt -i input2.srt\ -map 0:0 -map 0:1 -map 1:0 -map 2:0 -c:v copy -c:a copy \ -c:s srt -c:s srt output.mkv + cmd = $"-i \"{inputFile}\" -f srt {subtitle.TrimEnd()} -map 0:0 -map 0:1 {map.TrimEnd()} -c:v copy -c:a copy {cs.TrimEnd()} {meta.TrimEnd()} \"{outputFile}\""; + Debug.WriteLine(cmd); + //var lib = "libx264"; + //cmd = (string.Format(FFmpegCommands.ConvertUltraFast, inputFile, outputFile, lib)); + //ffmpeg -i video.avi -vf subtitles=subtitle.srt out.avi + //cmd = $"-i \"{inputFile}\" -vf subtitles=\"{subtitleFile}\" -c copy -c:s mov_text -c:v copy -c:a copy \"{outputFile}\""; + + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + Debug.WriteLine(v); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + //Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + } + + /// + /// نوشتن زیرنویس روی فایل ویدیویی(این زیرنویس ها به عنوان هارد سابتایتل شناخته میشوند) + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + /// فایل زیرنویس + public void BurnSubtitleIntoVideo(string inputFile, string outputFile, string subtitleFile) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + + + //ffmpeg -i video.avi -vf subtitles=subtitle.srt out.avi + var cmd = $"-i \"{inputFile}\" -vf subtitles=\"{subtitleFile}\" \"{outputFile}\""; + + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + //Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + Debug.WriteLine(v); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + //Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + } + + /// + /// بریدن قسمتی از فایل ویدیویی یا فایل موزیک + /// + /// فایل ورودی ویدیو یا آهنگ + /// فایل خروجی ویدیو یا آهنگ + /// زمان شروع + /// مدت زمان + public void CropVideoOrAudio(string inputFile, string outputFile, TimeSpan startTime, TimeSpan duration) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + + + //ffmpeg -i source-file.foo -ss 0 -t 600 first-10-min.m4v + //ffmpeg -i input.mp4 -ss 00:00:50.0 -codec copy -t 20 output.mp4 + + var cmd = $"-i \"{inputFile}\" -ss {startTime.EncodeTime()} -codec copy -t {duration.TotalSeconds} \"{outputFile}\""; + + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + //Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + Debug.WriteLine(v); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + //Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + } + + /// + /// افزودن صدا(ها) به یک فایل ویدیویی + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + /// حذف صدای ویدیوی ورودی + /// فایل های صدا + public void MergeAudioToVideo(string inputFile, string outputFile, bool removeDefaultAudio, params string[] audiosFilesPaths) + { + MergeAudioToVideo(inputFile, outputFile, removeDefaultAudio, AudioBitRate._256, audiosFilesPaths); + } + + /// + /// افزودن صدا(ها) به یک فایل ویدیویی به همراه تنظیم بیت رِیت + /// + /// فایل ورودی ویدیو + /// فایل خروجی ویدیو + /// حذف صدای ویدیوی ورودی + /// بیت رِیت خروجی صدا + /// فایل های صدا + public void MergeAudioToVideo(string inputFile, string outputFile, bool removeDefaultAudio, AudioBitRate outputAudioBitRate, params string[] audiosFilesPaths) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + + + //if (Path.GetExtension(outputFile).Replace(".", "").ToLower() != "mkv") + // throw new Exception("Output file most be an container file like MP4 or MKV."); + + //if (Path.GetExtension(outputFile).Replace(".", "").ToLower() != "mp4") + // throw new Exception("Output file most be an container file like MP4 or MKV."); + + var cmd = string.Empty; + + var audio = ""; + var map = ""; + var ix = 1; + //if (removeDefaultAudio) + // ix = 0; + var meta = ""; + foreach (var item in audiosFilesPaths) + { + audio += $"-i \"{item}\" "; + map += $"-map {ix}:0 "; + //-c:s srt + var extension = Path.GetExtension(item).Replace(".", "").ToLower(); + //-metadata:s:a:0 language=eng -metadata:s:a:0 title="Title 1" \ + + meta += $"-metadata:s:a:{ix} language=unknown -metadata:s:a:{ix} title=\"Audio Track #{ix}\" "; + ix++; + } + + //ffmpeg -i video.mp4 -i audio.mp3 -map 0:0 -map 1:0 -shortest output.mp4 + + var bitRate = "192k"; + try + { + + bitRate = outputAudioBitRate.ToString().Replace("_", "") +"k"; + } + catch { } + + //ffmpeg -i input.mp4 -f srt -i input.srt -i input2.srt\ -map 0:0 -map 0:1 -map 1:0 -map 2:0 -c:v copy -c:a copy \ -c:s srt -c:s srt output.mkv + if (removeDefaultAudio) + cmd = $"-i \"{inputFile}\" {audio.TrimEnd()} -map 0:0 {map.TrimEnd()} -c:v copy -b:a {bitRate} {meta.TrimEnd()} \"{outputFile}\""; + else + cmd = $"-i \"{inputFile}\" {audio.TrimEnd()} -map 0:0 -map 0:1 {map.TrimEnd()} -c:v copy -b:a {bitRate} {meta.TrimEnd()} \"{outputFile}\""; + + + Debug.WriteLine(cmd); + + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + var name = ""; + if (inputFile.Contains("\\")) + name = Path.GetFileName(inputFile); + else name = inputFile; + + + progress = new FFmpegProgress(); + bool d = false; + TimeSpan totalTimeSpan = TimeSpan.FromMilliseconds(0); + Debug.WriteLine("Total:" + totalTimeSpan.TotalMilliseconds); + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + Debug.WriteLine(v); + if (v.ToLower().Contains("duration") && !d) + { + try + { + FFmpegInfo fFmpegInfo = new FFmpegInfo(v, name); + totalTimeSpan = fFmpegInfo.Duration; + progress.InputFileInfo = fFmpegInfo; + + //Debug.WriteLine(fFmpegInfo.Duration.ToString()); + d = true; + } + catch { } + } + if (v.Contains("time=") && totalTimeSpan.TotalMilliseconds != 0) + { + try + { + SendProgress(totalTimeSpan, v); + } + catch { } + } + } + try + { + SendProgress(totalTimeSpan, ".:::END:::."); + // 100% + } + catch { } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + } + + public void ExtractImageFromVideo(string inputFile, string outputFile) + { + if (string.IsNullOrEmpty(inputFile)) + throw new Exception("Inputfile is empty. Choose an input file."); + if (string.IsNullOrEmpty(outputFile)) + throw new Exception("Outputfile is empty. Choose an output file."); + //ffmpeg -i input_file.mp4 -ss 01:23:45 -vframes 1 output.jpg + //-i input file the path to the input file + //-ss 01:23:45 seek the position to the specified timestamp + //-vframes 1 only handle one video frame + //output.jpg output filename, should have a well-known extension + var cmd = $"-i \"{inputFile}\" -ss 00:00:06 -vframes 1 \"{outputFile}\""; + + + Debug.WriteLine(cmd); + + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = StartupPath + FFmpegPath; + process.StartInfo.Arguments = cmd; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => { + + StreamReader sr = process.StandardError; + Debug.WriteLine("Start....."); + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + Debug.WriteLine(v); + } + Debug.WriteLine("End....."); + + //GetResult("End act"); + })).Start(); + } + /// + /// پروسه فایل + /// + FFmpegProgress progress = new FFmpegProgress(); + + /// + /// ارسال پروسه به رویداد + /// + /// زمان کل + /// رشته ورودی + void SendProgress(TimeSpan totalTime, string content) + { + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + string[] split = content.Split(' '); + if (!content.Contains(".:::END:::.")) + { + foreach (var row in split) + { + if (row.Contains("time=") && totalTime.TotalMilliseconds != 0) + { + var time = row.Split('='); + var currentTime = TimeSpan.Parse(time[1]); + + var percent = (int)/*Math.Round*/((currentTime.TotalMilliseconds / totalTime.TotalMilliseconds) * 100); + Debug.WriteLine(percent + "% " + time[1]); + progress.Percent = percent; + progress.CurrentTime = currentTime; + + } + if (row.Contains("speed=") && totalTime.TotalMilliseconds != 0) + { + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + var speed = row.Split('='); + progress.CurrentSpeed = speed[1]; + } + + } + //frame= 18 fps=0.0 q=0.0 size= 7kB time=00:00:00.88 bitrate= 68.8kbits/s speed=1.69x + if (content.Contains("frame=") && content.Contains("fps")) + { + var frame = content.Substring(content.IndexOf("frame=") + "frame=".Length); + frame = frame.Substring(0, frame.IndexOf("fps")); + frame = frame.Trim().TrimEnd().TrimStart(); + progress.CurrentFrame = int.Parse(frame); + } + if (content.Contains("fps=") && content.Contains("q")) + { + var frameRate = content.Substring(content.IndexOf("fps=") + "fps=".Length); + frameRate = frameRate.Substring(0, frameRate.IndexOf("q")); + frameRate = frameRate.Trim().TrimEnd().TrimStart(); + progress.CurrentFrameRate = double.Parse(frameRate); + } + if (content.Contains("size=") && content.Contains("time")) + { + var size = content.Substring(content.IndexOf("size=") + "size=".Length); + size = size.Substring(0, size.IndexOf("time")); + size = size.Trim().TrimEnd().TrimStart(); + progress.CurrentFileSize = size; + } + if (content.Contains("bitrate=") && content.Contains("speed")) + { + var bitrate = content.Substring(content.IndexOf("bitrate=") + "bitrate=".Length); + bitrate = bitrate.Substring(0, bitrate.IndexOf("speed")); + bitrate = bitrate.Trim().TrimEnd().TrimStart(); + progress.CurrentBitRate = bitrate; + } + } + else + { + progress.Percent = 100; + } + + OnProgressChanged?.Invoke(this, progress); + + } + + /// + /// Dispose + /// + public void Dispose() + { + //foreach (var process in ProcessList) + //{ + // process.na + try + { + Process[] workers = Process.GetProcessesByName("ffmpeg"); + foreach (Process worker in workers) + { + try + { + worker.Kill(); + worker.WaitForExit(); + worker.Dispose(); + } + catch { } + } + } + catch { } + //} + Dispose(true); + + // Use SupressFinalize in case a subclass + // of this type implements a finalizer. + GC.SuppressFinalize(this); + } + + /// + /// Dispose + /// + /// IsDisposing + protected virtual void Dispose(bool disposing) + { + //if (!_disposed) + { + if (disposing) + { + // Clear all property values that maybe have been set + // when the class was instantiated + //InputPath = null; + StartupPath = null; + } + + // Indicate that the instance has been disposed. + //_disposed = true; + } + } + } + + /// + /// اطلاعات فایل صوتی یا تصویری + /// + public class FFmpegInfo + { + /// + /// اِنکُدر فایل + /// + public string Encoder { get; set; } + //public string Duration { get; set; } + /// + /// نام فایل + /// + public string Name { get; set; } + /// + /// بیت رِیت فایل + /// + public string BitRate { get; set; } + /// + /// زمان فایل + /// + public TimeSpan Duration/*2*/ { get; set; } + /// + /// استریم های صدا + /// + public List AudioStreams { get; internal set; } = new List(); + /// + /// استریم های ویدیو + /// + public List VideoStreams { get; internal set; } = new List(); + internal FFmpegInfo(string content,string name) + { + if (string.IsNullOrEmpty(content)) + return; + try + { + Name = name; + var list = new List(content.Split(new string[] + { + Environment.NewLine,"\r\n","\n" + }, StringSplitOptions.RemoveEmptyEntries)); + + foreach (var item in list) + { + if (item.Contains("encoder")) + { + try + { + //encoder : Lavf56.1.100 + var encoder = item.Substring(item.IndexOf("encoder")); + encoder = encoder.Substring(encoder.IndexOf(":") + 1); + Encoder = encoder.Trim(); + } + catch { } + } + else if (item.Contains("Duration")) + { + try + { + // Duration: 00:04:01.26, start: 0.000000, bitrate: 3239 kb/s + var split = item.Split(','); + var dur = split[0].Substring(split[0].IndexOf("Duration:") + "Duration:".Length).Trim().TrimStart().TrimEnd(); + + Duration = TimeSpan.Parse(dur); + + + + foreach (var it in split) + if (it.Contains("kb")) + { + BitRate = it.Substring(it.IndexOf("bitrate:") + "bitrate:".Length).Trim(); + break; + } + } + catch { } + + } + } + + var streams = new List(content.Split(new string[] + { + "Stream #" + }, StringSplitOptions.RemoveEmptyEntries)); + if (streams.Count > 0) + streams.RemoveAt(0); + + VideoStreams = new List(); + AudioStreams = new List(); + int ix = 0; + foreach (var item in streams) + { + if(item.Contains("Video")) + { + VideoStreams.Add(new VideoStreamInfo(item, ix)); + } + else if (item.Contains("Audio")) + { + AudioStreams.Add(new AudioStreamInfo(item, ix)); + } + ix++; + } + } + catch { } + } + } + + /// + /// استریم صدا + /// + public class AudioStreamInfo + { + //Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default) + //Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp (default) + /// + /// نام استریم صدا + /// + public string Name { get; private set; } + /// + /// نام کُدِک + /// + public string CodecName { get; private set; } + /// + /// بیت رِیت صدا + /// + public string BitRate { get; private set; } + /// + /// سمپل رِیت صدا + /// + public string SamplingRate { get; private set; } + + internal AudioStreamInfo(string content,int id) + { + if (string.IsNullOrEmpty(content)) + return; + try + { + if (content.ToLower().Contains("audio")) + { + //Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default) + //Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp (default) + content = content.Trim(); + MatchCollection reg = Regex.Matches(content, @"\(([^)]*)\)", RegexOptions.Singleline | RegexOptions.IgnoreCase); + if (reg.Count > 0) + { + foreach (Capture item in reg) + content = content.Replace(item.Value, item.Value.Replace(",", "%$")); + } + var split = content.Split(','); + Name = $"Stream #{id} -Audio"; + CodecName = split[0].Substring(split[0].IndexOf("Audio") + 6).Trim().TrimStart().TrimEnd().Replace("%$", ","); + foreach (var item in split) + { + if (item.Contains("Hz")) + { + SamplingRate = item.Trim(); + SamplingRate = SamplingRate.Substring(0, SamplingRate.IndexOf(" ")); + float i = float.Parse(SamplingRate.Trim()); + i = i / 1000; + SamplingRate = i + " kHz"; + } + else if (item.Contains("kb")) + { + BitRate = item.Substring(0,item.IndexOf("\r\n")).Trim().TrimStart().TrimEnd().Replace("%$", ","); + } + } + } + } + catch { } + } + } + + /// + /// استریم ویدیو + /// + public class VideoStreamInfo + { + //Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 3107 kb/s, 23.98 fps, 23.98 tbr, 90k tbn, 47.95 tbc (default) + //Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 1k tbn, 50 tbc (default) + /// + /// نام استریم ویدیو + /// + public string Name { get; private set; } + /// + /// نام کُدِک + /// + public string CodecName { get; private set; } + /// + /// رنگ فضا + /// + public string ColorSpace { get; private set; } + /// + /// عرض ویدیو بر حسب پیکسل + /// + public int PixelWidth { get; private set; } + /// + /// طول ویدیو بر حسب پیکسل + /// + public int PixelHeight { get; private set; } + /// + /// فریم رِیت ویدیو + /// + public string FrameRate { get; private set; } + /// + /// بیت رِیت ویدیو + /// + public string BitRate { get; private set; } + internal VideoStreamInfo(string content,int id) + { + if (string.IsNullOrEmpty(content)) + return; + try + { + if (content.ToLower().Contains("video")) + { + //Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 3107 kb/s, 23.98 fps, 23.98 tbr, 90k tbn, 47.95 tbc (default) + //Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 1k tbn, 50 tbc (default) + + content = content.Trim(); + MatchCollection reg = Regex.Matches(content, @"\(([^)]*)\)", RegexOptions.Singleline | RegexOptions.IgnoreCase); + if (reg.Count > 0) + { + foreach (Capture item in reg) + content = content.Replace(item.Value, item.Value.Replace(",", "%$")); + } + + //var split = content.Split(','); + var split = content.Split(','); + Name = $"Stream #{id} -Video"; + + CodecName = split[0].Substring(split[0].IndexOf("Video:") + 6).Trim().TrimStart().TrimEnd().Replace("%$", ","); + if (split[1].Contains("(")) + ColorSpace = split[1].Substring(0, split[1].IndexOf("(")).Trim().TrimStart().TrimEnd().Replace("%$", ",").ToUpper(); + else + ColorSpace = split[1].Trim().TrimStart().TrimEnd().Replace("%$", ",").ToUpper(); + var heightWidth = ""; + split[2] = split[2].Trim().TrimStart().TrimEnd(); + if (split[2].Contains(" ")) + heightWidth = split[2].Substring(0, split[2].IndexOf(" ")).Trim().TrimStart().TrimEnd(); + else heightWidth = split[2]; + PixelWidth = int.Parse(heightWidth.Split('x')[0]); + PixelHeight = int.Parse(heightWidth.Split('x')[1]); + + foreach (var item in split) + { + if (item.Contains("fps")) + { + FrameRate = item.Trim().TrimStart().TrimEnd().Replace("%$", ",").ToUpper(); + } + else if (item.Contains("kb")) + { + BitRate = item.Trim().TrimStart().TrimEnd().Replace("%$", ","); + } + } + } + } + catch { } + } + + } +} diff --git a/FFmpegFa/FFmpegCommands.cs b/FFmpegFa/FFmpegCommands.cs new file mode 100644 index 0000000..9192d11 --- /dev/null +++ b/FFmpegFa/FFmpegCommands.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +//-i "INPUTFILE.OGG" -vn -ar 44100 -ac 2 -ab 192k -f mp3 "OUTPUTFILE.mp3" +namespace FFmpegFa +{ + /// + /// https://www.labnol.org/internet/useful-ffmpeg-commands/28490/ + /// + class FFmpegCommands + { + + public const string Information = "-i {0}"; + public const string ExtractSub = "-i {textBox1.Text} -map 0:s:? \"{st}subs.srt\" -map 0:s:1 \"{st}rmt2.srt\""; + //00:00:50.0 + public const string Cut = "-i {0} -ss {2} -codec copy -t 20 {1}"; + /*/// + /// -i video.mp4 -t 00:00:50 -c copy small-1.mp4 -ss 00:00:50 -codec copy small-2.mp4 + /// + //public const string Split = "-i video.mp4 -t 00:00:50 -c copy small-1.mp4 -ss 00:00:50 -codec copy small-2.mp4"; + */ + + + + /// + /// -i youtube.flv -c:v libx264 filename.mp4 + /// + public const string Convert = "-i \"{0}\" -c:v {2} \"{1}\""; + /// + /// -i video.wmv -c:v libx264 -preset ultrafast video.mp4 + /// + public const string ConvertUltraFast = "-i \"{0}\" -c:v {2} -preset ultrafast \"{1}\""; + + /// + /// -f concat -i file-list.txt -c copy output.mp4 + /// + public const string Concat = "-f concat -i file-list.txt -c copy output.mp4"; + + /// + /// Use the -an parameter to disable the audio portion of a video stream. + /// -i video.mp4 -an mute-video.mp4 + /// + public const string MuteAudio = "-i video.mp4 -an mute-video.mp4"; + + /// + /// The -vn switch extracts the audio portion from a video and we are using the -ab switch to save the audio as a 256kbps MP3 audio file. + /// + public const string ExtractAudio = "-i video.mp4 -vn -ab 256 audio.mp3"; + + /// + /// FFmpeg is an excellent tool for converting videos into animated GIFs and the quality isn’t bad either. Use the scale filter to specify the width of the GIF, the -t parameter specific the duration while -r specifies the frame rate (fps). + /// + public const string ConvertToGif = "-i video.mp4 -vf scale=500:-1 -t 10 -r 10 image.gif"; + + + /// + /// This command will extract the video frame at the 15s mark and saves it as a 800px wide JPEG image. You can also use the -s switch (like -s 400×300) to specify the exact dimensions of the image file though it will probably create a stretched image if the image size doesn’t follow the aspect ratio of the original video file. + /// + public const string ExtractFrames = "-ss 00:00:15 -i video.mp4 -vf scale=800:-1 -vframes 1 image.jpg"; + + /// + /// You can use FFmpeg to automatically extract image frames from a video every ‘n’ seconds and the images are saved in a sequence. This command saves image frame after every 4 seconds. + /// + public const string ConvertToImages = "ffmpeg -i movie.mp4 -r 0.25 frames_%04d.png"; + + /// + /// You can also specify the -shortest switch to finish the encoding when the shortest clip ends. + /// + public const string MergingAudio = "-i video.mp4 -i audio.mp3 -c:v copy -c:a aac -strict experimental output.mp4"; + /// + /// You can also specify the -shortest switch to finish the encoding when the shortest clip ends. + /// + public const string MergingAudio2 = "-i video.mp4 -i audio.mp3 -c:v copy -c:a aac -strict experimental -shortest output.mp4"; + + /// + /// Use the size (-s) switch with ffmpeg to resize a video while maintaining the aspect ratio. + /// + public const string Resize = "-i input.mp4 -s 480x320 -c:a copy output.mp4"; + + + /// + /// This command creates a video slideshow using a series of images that are named as img001.png, img002.png, etc. Each image will have a duration of 5 seconds (-r 1/5). + /// + public const string CreateVideoSlideshowFromImages = "-r 1/5 -i img%03d.png -c:v libx264 -r 30 -pix_fmt yuv420p slideshow.mp4"; + + + + /// + /// You can add a cover image to an audio file and the length of the output video will be the same as that of the input audio stream. This may come handy for uploading MP3s to YouTube. + /// + public const string AddAPosterImageToAudio = "-loop 1 -i image.jpg -i audio.mp3 -c:v libx264 -c:a aac -strict experimental -b:a 192k -shortest output.mp4"; + + + + /// + /// Use the -t parameter to specify the duration of the video. + /// + public const string ConvertASingleImageToVideo = "-loop 1 -i image.png -c:v libx264 -t 30 -pix_fmt yuv420p video.mp4"; + + + + /// + /// This will take the subtitles from the .srt file. FFmpeg can decode most common subtitle formats. + /// + public const string AddSubtitleToVideo = "-i movie.mp4 -i subtitles.srt -map 0 -map 1 -c copy -c:v libx264 -crf 23 -preset veryfast output.mkv"; + + /// + /// This will create a 30 second audio file starting at 90 seconds from the original audio file without transcoding. + /// + public const string CropAnAudio = "-ss 00:01:30 -t 30 -acodec copy -i inputfile.mp3 outputfile.mp3"; + + /// + /// You can use the volume filter to alter the volume of a media file using FFmpeg. This command will half the volume of the audio file. + /// + public const string ChangeAudioVolume = "-i input.wav -af 'volume=0.5' output.wav"; + + /// + /// This command will rotate a video clip 90° clockwise. You can set transpose to 2 to rotate the video 90° anti-clockwise. + /// + public const string RotateVideo = "-i input.mp4 -filter:v 'transpose=1' rotated-video.mp4"; + /// + /// This will rotate the video 180° counter-clockwise. + /// + public const string RotateVideo2 = "-i input.mp4 -filter:v 'transpose=2,transpose=2' rotated-video.mp4"; + + /// + /// You can change the speed of your video using the setpts (set presentation time stamp) filter of FFmpeg. This command will make the video 8x (1/8) faster or use setpts=4*PTS to make the video 4x slower. + /// + public const string SpeedUpDownVideo = "-i input.mp4 -filter:v \"setpts=0.125*PTS\" output.mp4"; + /// + /// For changing the speed of audio, use the atempo audio filter. This command will double the speed of audio. You can use any value between 0.5 and 2.0 for audio. + /// + public const string SpeedUpDownAudio = "-i input.mkv -filter:a \"atempo=2.0\" -vn output.mkv"; + } +} diff --git a/FFmpegFa/FFmpegFa.csproj b/FFmpegFa/FFmpegFa.csproj new file mode 100644 index 0000000..7886c25 --- /dev/null +++ b/FFmpegFa/FFmpegFa.csproj @@ -0,0 +1,79 @@ + + + + + Debug + AnyCPU + {9F016916-E740-4B9E-9F54-A7AF1C3BB311} + Library + Properties + FFmpegFa + FFmpegFa + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {50A7E9B0-70EF-11D1-B75A-00A0C90564FE} + 1 + 0 + 0 + tlbimp + False + True + + + + + + + + + + \ No newline at end of file diff --git a/FFmpegFa/FFmpegHelper.cs b/FFmpegFa/FFmpegHelper.cs new file mode 100644 index 0000000..d4d9c3c --- /dev/null +++ b/FFmpegFa/FFmpegHelper.cs @@ -0,0 +1,12 @@ +using System; + +namespace FFmpegFa +{ + static class FFmpegHelper + { + public static string EncodeTime(this TimeSpan time) + { + return $"{time.Hours:00}:{time.Minutes:00}:{time.Seconds:00}.{time.Milliseconds:00}"; + } + } +} diff --git a/FFmpegFa/Helpers/ArchiveManager.cs b/FFmpegFa/Helpers/ArchiveManager.cs new file mode 100644 index 0000000..7384eb8 --- /dev/null +++ b/FFmpegFa/Helpers/ArchiveManager.cs @@ -0,0 +1,211 @@ +using Shell32; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.AccessControl; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace FFmpegFa.Helpers +{ + class ArchiveManager + { + private static string _lastError = ""; + private const int SLEEP_DURATION = 100; + private const int TIMEOUT_VALUE = 5; + + public static bool Archive(string archiveFile, string unArchiveFolder) + { + try + { + _lastError = ""; + if (!VerifyExtension(archiveFile)) + { + return false; + } + byte[] buffer = new byte[] { + 80, 0x4b, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 + }; + FileStream stream = File.Create(Path.GetFullPath(archiveFile)); + stream.Write(buffer, 0, buffer.Length); + stream.Flush(); + stream.Close(); + stream = null; + Shell shell = (Shell)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("13709620-C279-11CE-A49E-444553540000"))); + Folder folderObjDestination = shell.NameSpace(Path.GetFullPath(archiveFile)); + Folder folderObjSource = shell.NameSpace(Path.GetFullPath(unArchiveFolder)); + folderObjDestination.CopyHere(folderObjSource.Items(), 20); + if (!WaitTillItemCountIsEqual(folderObjSource, folderObjDestination)) + { + return false; + } + return true; + } + catch (Exception exception) + { + _lastError = "ERROR: Could not create archive. Exception: " + exception.Message; + return false; + } + } + + private static bool CheckAndGetExtractionPath(ref string fileName, out string extractionPath) + { + _lastError = ""; + try + { + fileName = Path.GetFullPath(fileName); + extractionPath = Path.GetDirectoryName(fileName); + if (!File.Exists(fileName)) + { + _lastError = "ERROR: File " + fileName + " does NOT exist"; + return false; + } + extractionPath = Path.Combine(extractionPath, Path.GetFileNameWithoutExtension(fileName)); + if (!Directory.Exists(extractionPath)) + { + Directory.CreateDirectory(extractionPath); + } + return true; + } + catch (Exception exception) + { + extractionPath = ""; + _lastError = "ERROR: Could not get/create the extraction path. Exception: " + exception.Message; + return false; + } + } + + public static bool CopyPermissions(string sourceFile, string destFile) + { + try + { + _lastError = ""; + FileInfo info = new FileInfo(Path.GetFullPath(sourceFile)); + FileInfo info2 = new FileInfo(Path.GetFullPath(destFile)); + FileSecurity accessControl = info.GetAccessControl(); + accessControl.SetAccessRuleProtection(true, true); + info2.SetAccessControl(accessControl); + return true; + } + catch (Exception exception) + { + _lastError = "ERROR: Could not copy permissions. Exception: " + exception.Message; + return false; + } + } + + public static bool UnArchive(string archiveFile) + { + try + { + _lastError = ""; + string extractionPath = ""; + if (!CheckAndGetExtractionPath(ref archiveFile, out extractionPath)) + { + return false; + } + if (!UnArchive(archiveFile, extractionPath)) + { + return false; + } + return true; + } + catch (Exception exception) + { + _lastError = "ERROR: Could not unarchive. Exception: " + exception.Message; + return false; + } + } + + public static bool UnArchive(string archiveFile, string unArchiveFolder) + { + try + { + _lastError = ""; + if (!VerifyExtension(archiveFile)) + { + return false; + } + Shell shell = (Shell)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("13709620-C279-11CE-A49E-444553540000"))); + Folder folderObjSource = shell.NameSpace(Path.GetFullPath(archiveFile)); + Folder folderObjDestination = shell.NameSpace(Path.GetFullPath(unArchiveFolder)); + foreach (FolderItem item in folderObjSource.Items()) + { + folderObjDestination.CopyHere(item, 20); + } + if (!WaitTillItemCountIsEqual(folderObjSource, folderObjDestination)) + { + return false; + } + return true; + } + catch (Exception exception) + { + _lastError = "ERROR: Could not unarchive. Exception: " + exception.Message; + return false; + } + } + + private static bool VerifyExtension(string fileName) + { + try + { + _lastError = ""; + string str = Path.GetExtension(fileName).ToUpper().Trim(); + if (str != ".ZIP") + { + _lastError = "ERROR: Invalid extension '" + str + "' found in file name"; + return false; + } + return true; + } + catch (Exception exception) + { + _lastError = "ERROR: Could not get/create the extraction path. Exception: " + exception.Message; + return false; + } + } + + private static bool WaitTillItemCountIsEqual(Folder folderObjSource, Folder folderObjDestination) + { + try + { + _lastError = ""; + if ((folderObjSource == null) || (folderObjDestination == null)) + { + _lastError = "ERROR: One or more Folder object(s) is/are null"; + return false; + } + int count = folderObjSource.Items().Count; + int num2 = 50; + int num3 = 0; + while (folderObjDestination.Items().Count < count) + { + if (num2 <= num3++) + { + _lastError = "ERROR: Timeout occurred while processing archive"; + return false; + } + Thread.Sleep(100); + } + return true; + } + catch (Exception exception) + { + _lastError = "ERROR: Could not create archive. Exception: " + exception.Message; + return false; + } + } + + public static string LastError + { + get + { + return _lastError; + } + } + } +} diff --git a/FFmpegFa/Interfaces/IFFmpeg.cs b/FFmpegFa/Interfaces/IFFmpeg.cs new file mode 100644 index 0000000..fbcd351 --- /dev/null +++ b/FFmpegFa/Interfaces/IFFmpeg.cs @@ -0,0 +1,41 @@ +using System; + +namespace FFmpegFa.Interfaces +{ + /// + /// اینترفیس فایل + /// + public interface IFFmpeg + { + string LibraryVersion(); + string AboutAuthor(); + //void OpenFile(string filePath); + FFmpegInfo GetInformation(string filePath); + void ConvertVideo(string inputFile, string outputFile); + void ConvertVideo(string inputFile, string outputFile, ConverterCodecType outputCodecType); + void ConvertVideo(string inputFile, string outputFile, ConverterCodecType outputCodecType, VideoBitRate outputVideoBitRate, AudioBitRate outputAudioBitRate); + + void ConvertAudio(string inputFile, string outputFile); + void ConvertAudio(string inputFile, string outputFile, AudioFileType outputAudioType); + void ConvertAudio(string inputFile, string outputFile, AudioFileType outputAudioType, AudioSampleRate outputAudioSampleRate, AudioBitRate outputAudioBitRate); + + void RemoveAudioFromVideo(string inputFile, string outputFile); + + void ExtractAudioFromVideo(string inputFile, string outputFile); + //void ExtractAudioFromVideo(string inputFile, string outputFile, AudioBitRate outputAudioBitRate); + + void ResizeVideo(string inputFile, string outputFile, VideoSize newSize); + void ResizeVideo(string inputFile, string outputFile, VideoSize newSize, VideoBitRate outputVideoBitRate, AudioBitRate outputAudioBitRate); + + void BurnSubtitleIntoVideo(string inputFile, string outputFile, string subtitleFile); + void MergeSubtitlesToVideo(string inputFile, string outputFile, params string[] subtitlesFilePaths); + + void CropVideoOrAudio(string inputFile, string outputFile, TimeSpan startTime, TimeSpan duration); + + //void ExtractFrameToImage(string inputFile, string outputImageFile, VideoSize size); + + void MergeAudioToVideo(string inputFile, string outputFile, bool removeDefaultAudio, params string[] audiosFilesPaths); + void MergeAudioToVideo(string inputFile, string outputFile, bool removeDefaultAudio, AudioBitRate outputAudioBitRate, params string[] audiosFilesPaths); + void ExtractImageFromVideo(string inputFile, string outputFile); + } +} diff --git a/FFmpegFa/Properties/AssemblyInfo.cs b/FFmpegFa/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3681ef6 --- /dev/null +++ b/FFmpegFa/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("FFmpegFa")] +[assembly: AssemblyDescription("A .NET Library to easy use FFmpeg library in .net apps.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Ramtin Jokar [Ramtinak@live.com]")] +[assembly: AssemblyProduct("FFmpegFa")] +[assembly: AssemblyCopyright("Copyright © 2018 - Esfand 1396")] +[assembly: AssemblyTrademark("Ramtinak@live.com")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9f016916-e740-4b9e-9f54-a7af1c3bb311")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/FFmpegFa/Properties/Resources.Designer.cs b/FFmpegFa/Properties/Resources.Designer.cs new file mode 100644 index 0000000..eda458b --- /dev/null +++ b/FFmpegFa/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace FFmpegFa.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FFmpegFa.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ffmpeg { + get { + object obj = ResourceManager.GetObject("ffmpeg", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/FFmpegFa/Properties/Resources.resx b/FFmpegFa/Properties/Resources.resx new file mode 100644 index 0000000..16f2ec9 --- /dev/null +++ b/FFmpegFa/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\ffmpeg.zip;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/FFmpegFa/Resources/ffmpeg.zip b/FFmpegFa/Resources/ffmpeg.zip new file mode 100644 index 0000000..26c68ad Binary files /dev/null and b/FFmpegFa/Resources/ffmpeg.zip differ diff --git a/FFmpegFa/VideoFileType.cs b/FFmpegFa/VideoFileType.cs new file mode 100644 index 0000000..442af96 --- /dev/null +++ b/FFmpegFa/VideoFileType.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace FFmpegFa +{ + /// + /// سایز ویدیو + /// + public class VideoSize + { + /// + /// عرض ویدیو + /// + public int Width { get; set; } + /// + /// طول ویدیو + /// + public int Height { get; set; } + + public VideoSize() : this(0, 0) { } + /// + /// تعیین عرض و طول ویدیو + /// + /// عرض ویدیو + /// طول ویدیو + public VideoSize(int width, int height) { Width = width; Height = height; } + } + /// + /// بیت ریت ویدیو ها(هرچی بالاتر باشه کیفیت ویدیو بالاتر هست) + /// + public enum VideoBitRate + { + _96k, + _128k, + _160k, + _192k, + _256k, + _300k, + _400k, + _500k, + _600k, + _800k, + _1000k, + _1200k, + _1500k, + _1600k, + _1800k, + _2000k, + _2500k, + _3000k, + _3500k, + _4000k, + _4500k, + _5000k, + _5500k, + _6000k, + _8000k, + _10000k, + _15000k, + _20000k + } + /// + /// تابپ فایل های خروجی ویدیوها + /// + public enum VideoFileType + { + Mkv, + Avi, + Mp4, + Mov, + Mpg, + Mpeg, + Wmv, + Asf, + M4p, + M4v, + Webm, + _3gp, + _3g2, + _3gp2, + _3ga, + Mp4v, + M2ts, + Wm, + Flv, + Vob, + Qt, + M4b, + M4r, + Ts, + F4v, + Hevc, + x265, + Hdmov, + Moov, + Mpe, + Mpg2, + Mpeg1, + Mpeg4, + Divx, + Ogv, + Mxf, + M2p, + Mts, + Rm, + Rmvb + } +} diff --git a/FFmpegFaSample/FFmpegFaSample.csproj b/FFmpegFaSample/FFmpegFaSample.csproj new file mode 100644 index 0000000..1d87229 --- /dev/null +++ b/FFmpegFaSample/FFmpegFaSample.csproj @@ -0,0 +1,83 @@ + + + + + Debug + AnyCPU + {044E2738-F595-4186-AB3A-766DA0F7C0A1} + WinExe + FFmpegFaSample + FFmpegFaSample + v4.0 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {9f016916-e740-4b9e-9f54-a7af1c3bb311} + FFmpegFa + + + + \ No newline at end of file diff --git a/FFmpegFaSample/Form1.Designer.cs b/FFmpegFaSample/Form1.Designer.cs new file mode 100644 index 0000000..d480525 --- /dev/null +++ b/FFmpegFaSample/Form1.Designer.cs @@ -0,0 +1,301 @@ +namespace FFmpegFaSample +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.mypanel = new System.Windows.Forms.Panel(); + this.button9 = new System.Windows.Forms.Button(); + this.button8 = new System.Windows.Forms.Button(); + this.button7 = new System.Windows.Forms.Button(); + this.button6 = new System.Windows.Forms.Button(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.button5 = new System.Windows.Forms.Button(); + this.richTextBox2 = new System.Windows.Forms.RichTextBox(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button3 = new System.Windows.Forms.Button(); + this.button4 = new System.Windows.Forms.Button(); + this.richTextBox1 = new System.Windows.Forms.RichTextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); + this.textBox4 = new System.Windows.Forms.TextBox(); + this.button10 = new System.Windows.Forms.Button(); + this.button11 = new System.Windows.Forms.Button(); + this.button12 = new System.Windows.Forms.Button(); + this.mypanel.SuspendLayout(); + this.SuspendLayout(); + // + // mypanel + // + this.mypanel.Controls.Add(this.button12); + this.mypanel.Controls.Add(this.button11); + this.mypanel.Controls.Add(this.button10); + this.mypanel.Controls.Add(this.textBox4); + this.mypanel.Controls.Add(this.button9); + this.mypanel.Controls.Add(this.button8); + this.mypanel.Controls.Add(this.button7); + this.mypanel.Controls.Add(this.button6); + this.mypanel.Controls.Add(this.textBox3); + this.mypanel.Controls.Add(this.button5); + this.mypanel.Controls.Add(this.richTextBox2); + this.mypanel.Controls.Add(this.progressBar1); + this.mypanel.Controls.Add(this.textBox2); + this.mypanel.Controls.Add(this.textBox1); + this.mypanel.Controls.Add(this.button3); + this.mypanel.Controls.Add(this.button4); + this.mypanel.Controls.Add(this.richTextBox1); + this.mypanel.Controls.Add(this.button1); + this.mypanel.Controls.Add(this.button2); + this.mypanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.mypanel.Location = new System.Drawing.Point(0, 0); + this.mypanel.Name = "mypanel"; + this.mypanel.Size = new System.Drawing.Size(729, 484); + this.mypanel.TabIndex = 3; + // + // button9 + // + this.button9.Location = new System.Drawing.Point(644, 55); + this.button9.Name = "button9"; + this.button9.Size = new System.Drawing.Size(69, 23); + this.button9.TabIndex = 14; + this.button9.Text = "button9"; + this.button9.UseVisualStyleBackColor = true; + this.button9.Click += new System.EventHandler(this.button9_Click); + // + // button8 + // + this.button8.Location = new System.Drawing.Point(573, 55); + this.button8.Name = "button8"; + this.button8.Size = new System.Drawing.Size(69, 23); + this.button8.TabIndex = 13; + this.button8.Text = "button8"; + this.button8.UseVisualStyleBackColor = true; + this.button8.Click += new System.EventHandler(this.button8_Click); + // + // button7 + // + this.button7.Location = new System.Drawing.Point(498, 55); + this.button7.Name = "button7"; + this.button7.Size = new System.Drawing.Size(69, 23); + this.button7.TabIndex = 12; + this.button7.Text = "button7"; + this.button7.UseVisualStyleBackColor = true; + this.button7.Click += new System.EventHandler(this.button7_Click); + // + // button6 + // + this.button6.Location = new System.Drawing.Point(423, 55); + this.button6.Name = "button6"; + this.button6.Size = new System.Drawing.Size(69, 23); + this.button6.TabIndex = 11; + this.button6.Text = "button6"; + this.button6.UseVisualStyleBackColor = true; + this.button6.Click += new System.EventHandler(this.button6_Click); + // + // textBox3 + // + this.textBox3.Location = new System.Drawing.Point(12, 84); + this.textBox3.Name = "textBox3"; + this.textBox3.Size = new System.Drawing.Size(189, 20); + this.textBox3.TabIndex = 10; + this.textBox3.Text = "kf.srt"; + // + // button5 + // + this.button5.Location = new System.Drawing.Point(348, 55); + this.button5.Name = "button5"; + this.button5.Size = new System.Drawing.Size(69, 23); + this.button5.TabIndex = 9; + this.button5.Text = "button5"; + this.button5.UseVisualStyleBackColor = true; + this.button5.Click += new System.EventHandler(this.button5_Click); + // + // richTextBox2 + // + this.richTextBox2.Location = new System.Drawing.Point(361, 142); + this.richTextBox2.Name = "richTextBox2"; + this.richTextBox2.Size = new System.Drawing.Size(352, 291); + this.richTextBox2.TabIndex = 8; + this.richTextBox2.Text = ""; + // + // progressBar1 + // + this.progressBar1.Location = new System.Drawing.Point(3, 113); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(710, 23); + this.progressBar1.TabIndex = 7; + // + // textBox2 + // + this.textBox2.Location = new System.Drawing.Point(3, 29); + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(710, 20); + this.textBox2.TabIndex = 6; + this.textBox2.Text = "k3.mp4"; + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(3, 3); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(710, 20); + this.textBox1.TabIndex = 5; + this.textBox1.Text = "k.mp4"; + // + // button3 + // + this.button3.Location = new System.Drawing.Point(175, 55); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(75, 23); + this.button3.TabIndex = 3; + this.button3.Text = "button3"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // button4 + // + this.button4.Location = new System.Drawing.Point(264, 55); + this.button4.Name = "button4"; + this.button4.Size = new System.Drawing.Size(69, 23); + this.button4.TabIndex = 4; + this.button4.Text = "button4"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // richTextBox1 + // + this.richTextBox1.Location = new System.Drawing.Point(3, 142); + this.richTextBox1.Name = "richTextBox1"; + this.richTextBox1.Size = new System.Drawing.Size(352, 291); + this.richTextBox1.TabIndex = 2; + this.richTextBox1.Text = "h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9]" + + ", 3107 kb/s"; + // + // button1 + // + this.button1.Location = new System.Drawing.Point(3, 55); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 0; + this.button1.Text = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // button2 + // + this.button2.Location = new System.Drawing.Point(84, 55); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.TabIndex = 1; + this.button2.Text = "button2"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // backgroundWorker1 + // + this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork); + // + // textBox4 + // + this.textBox4.Location = new System.Drawing.Point(207, 84); + this.textBox4.Name = "textBox4"; + this.textBox4.Size = new System.Drawing.Size(189, 20); + this.textBox4.TabIndex = 15; + this.textBox4.Text = "ke.srt"; + // + // button10 + // + this.button10.Location = new System.Drawing.Point(402, 82); + this.button10.Name = "button10"; + this.button10.Size = new System.Drawing.Size(69, 23); + this.button10.TabIndex = 16; + this.button10.Text = "button10"; + this.button10.UseVisualStyleBackColor = true; + this.button10.Click += new System.EventHandler(this.button10_Click); + // + // button11 + // + this.button11.Location = new System.Drawing.Point(477, 81); + this.button11.Name = "button11"; + this.button11.Size = new System.Drawing.Size(69, 23); + this.button11.TabIndex = 17; + this.button11.Text = "button11"; + this.button11.UseVisualStyleBackColor = true; + this.button11.Click += new System.EventHandler(this.button11_Click); + // + // button12 + // + this.button12.Location = new System.Drawing.Point(552, 81); + this.button12.Name = "button12"; + this.button12.Size = new System.Drawing.Size(69, 23); + this.button12.TabIndex = 18; + this.button12.Text = "button12"; + this.button12.UseVisualStyleBackColor = true; + this.button12.Click += new System.EventHandler(this.button12_Click); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(729, 484); + this.Controls.Add(this.mypanel); + this.Name = "Form1"; + this.Text = "Form1"; + this.mypanel.ResumeLayout(false); + this.mypanel.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel mypanel; + private System.Windows.Forms.RichTextBox richTextBox2; + private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.RichTextBox richTextBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button5; + private System.ComponentModel.BackgroundWorker backgroundWorker1; + private System.Windows.Forms.Button button6; + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.Button button9; + private System.Windows.Forms.Button button8; + private System.Windows.Forms.Button button7; + private System.Windows.Forms.TextBox textBox4; + private System.Windows.Forms.Button button12; + private System.Windows.Forms.Button button11; + private System.Windows.Forms.Button button10; + } +} + diff --git a/FFmpegFaSample/Form1.cs b/FFmpegFaSample/Form1.cs new file mode 100644 index 0000000..8df3039 --- /dev/null +++ b/FFmpegFaSample/Form1.cs @@ -0,0 +1,304 @@ +using FFmpegFa; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Windows.Forms; + +namespace FFmpegFaSample +{ + public partial class Form1 : Form + { + FFmpeg fFmpeg; + public Form1() + { + InitializeComponent(); + + fFmpeg = new FFmpeg(/*Application.StartupPath*/); + fFmpeg.OnProgressChanged += FFmpeg_OnProgressChanged; + } + + private void button1_Click(object sender, EventArgs e) + { + } + + private void FFmpeg_OnInformation(FFmpeg sender, FFmpegInfo FFmpegInfo) + { + Debug.WriteLine(FFmpegInfo.Name); + } + + private void button2_Click(object sender, EventArgs e) + { + + } + const string FFmpegPath = @"\ffmpeg.exe"; + + private void button3_Click(object sender, EventArgs e) + { + ///-i {textBox1.Text} -map single_highest_quality_video_stream_from_all_inputs -map single_highest_quality_audio_stream_from_all_inputs {textBox2.Text} + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = Application.StartupPath + FFmpegPath; + //--txt_format text -i input_file out.srt + var st = "C:\\Users\\Ramti\\Documents\\Visual Studio 2017\\Projects\\FFmpegFa\\FFmpegFaSample\\bin\\Debug\\New folder\\"; + + //process.StartInfo.Arguments = $"-txt_format text -i {textBox1.Text} out.srt"; + process.StartInfo.Arguments = $"-i {textBox1.Text} -map 0:s:? \"{st}subs.srt\" -map 0:s:1 \"{st}rmt2.srt\""; + // -vn -an -codec:s srt + //process.StartInfo.Arguments = $"-i {textBox1.Text} -c:s copy sub.srt"; + + //process.StartInfo.Arguments = $"-i {textBox1.Text} -an -vcodec copy {textBox2.Text}"; + //process.StartInfo.Arguments = $"-i {textBox1.Text} -map single_highest_quality_video_stream_from_all_inputs -map single_highest_quality_audio_stream_from_all_inputs {textBox2.Text}"; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + + StreamReader sr = process.StandardError; + richTextBox2.Text += sr.ReadToEnd(); + + //fFmpeg.GetInformation3(); + } + + private void button4_Click(object sender, EventArgs e) + { + //h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 3107 kb/s + //h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + var ff = fFmpeg.GetInformation(textBox1.Text); + Debug.WriteLine(ff.Duration); + stopwatch.Stop(); + Debug.WriteLine(stopwatch.Elapsed.ToString()); + + return; + + + var content = "h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps"; + + //var aontent = Regex.Replace(content, @"\(([^)]*)\)",""); + //foreach(var item in content.ToCharArray()) + //richTextBox2.Text = /*ExtractNumber*/(aontent); + + //var match = Regex.Match(content, @"\(([^)]*)\)"); + + + MatchCollection reg = Regex.Matches(content, @"\(([^)]*)\)", RegexOptions.Singleline | RegexOptions.IgnoreCase); + var content2 = ""; + if (reg.Count > 0) + { + foreach(Capture item in reg) + content2 = content.Replace(item.Value, item.Value.Replace(",", "%$")); + } + + var split = content2.Split(','); + stopwatch.Stop(); + Debug.WriteLine(stopwatch.Elapsed.ToString()); + richTextBox2.Text += Environment.NewLine + Environment.NewLine + content2; + } + + private void button5_Click(object sender, EventArgs e) + { + //richTextBox1.Text = System.Reflection.Assembly.GetExecutingAssembly().Location +"\r\n\r\n" + + // System.Reflection.Assembly.GetExecutingAssembly().CodeBase + "\r\n\r\n" + + + //Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + + ////using (ZipArchive archive = ZipFile.Open(zipPath, ZipArchiveMode.Update)) + ////{ + //// archive.CreateEntryFromFile(newFile, "NewEntry.txt"); + //// archive.ExtractToDirectory(extractPath); + ////} + + fFmpeg.ConvertVideo(textBox1.Text, textBox2.Text, ConverterCodecType.x265); + + } + + private void FFmpeg_OnProgressChanged(FFmpeg sender, FFmpegProgress progress) + { + Debug.WriteLine(progress.Percent + "% " + progress.CurrentSpeed + " " + +progress.CurrentFileSize + " " + progress.CurrentBitRate + " "+ + progress.CurrentFrame + " " +progress.CurrentFrameRate + " "+ + progress.CurrentTime+" "); + if (InvokeRequired) + { + BeginInvoke(new Action(() => FFmpeg_OnProgressChanged(sender,progress))); + return; + } + progressBar1.Value = progress.Percent; + } + + private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) + { + + + } + + private void button6_Click(object sender, EventArgs e) + { + fFmpeg.ConvertAudio(textBox1.Text, textBox2.Text, AudioFileType.M4a); + return; + + + + + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.FileName = Application.StartupPath + FFmpegPath; + //--txt_format text -i input_file out.srt + + + //process.StartInfo.Arguments = $"-txt_format text -i {textBox1.Text} out.srt"; + process.StartInfo.Arguments =textBox3.Text; + // -vn -an -codec:s srt + //process.StartInfo.Arguments = $"-i {textBox1.Text} -c:s copy sub.srt"; + + //process.StartInfo.Arguments = $"-i {textBox1.Text} -an -vcodec copy {textBox2.Text}"; + //process.StartInfo.Arguments = $"-i {textBox1.Text} -map single_highest_quality_video_stream_from_all_inputs -map single_highest_quality_audio_stream_from_all_inputs {textBox2.Text}"; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + new Thread(new ThreadStart(() => + { + StreamReader sr = process.StandardError; + while (!sr.EndOfStream) + { + var v = (sr.ReadLine()); + SSS(v); + } + //new Action(() => { richTextBox2.Text += sr.ReadToEnd(); }).Invoke(); + + })).Start(); + } + void SSS(string content) + { + if (InvokeRequired) + { + BeginInvoke(new Action(() => SSS(content))); + return; + } + + richTextBox2.Text += content+"\r\n\r\n"; + } + + private void button7_Click(object sender, EventArgs e) + { + fFmpeg.RemoveAudioFromVideo(textBox1.Text, textBox2.Text); + + } + + private void button8_Click(object sender, EventArgs e) + { + fFmpeg.ExtractAudioFromVideo(textBox1.Text, textBox2.Text); + + } + + private void button9_Click(object sender, EventArgs e) + { + fFmpeg.BurnSubtitleIntoVideo(textBox1.Text, textBox2.Text, textBox3.Text); + + } + + private void button10_Click(object sender, EventArgs e) + { + fFmpeg.CropVideoOrAudio(textBox1.Text, textBox2.Text, TimeSpan.FromSeconds(40),TimeSpan.FromSeconds(20)); + + } + + private void button11_Click(object sender, EventArgs e) + { + fFmpeg.ResizeVideo(textBox1.Text, textBox2.Text, new VideoSize(320,240)); + + } + + private void button12_Click(object sender, EventArgs e) + { + fFmpeg.MergeAudioToVideo(textBox1.Text, textBox2.Text, false,AudioBitRate._192, textBox3.Text, textBox4.Text); + } + } +} + + + +/* + private void button4_Click(object sender, EventArgs e) + { + //h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 3107 kb/s + //h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + var content = "h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps"; + + //var aontent = Regex.Replace(content, @"\(([^)]*)\)",""); + //foreach(var item in content.ToCharArray()) + //richTextBox2.Text = +(aontent); + + //var match = Regex.Match(content, @"\(([^)]*)\)"); + + + MatchCollection reg = Regex.Matches(content, @"\(([^)]*)\)", RegexOptions.Singleline | RegexOptions.IgnoreCase); +var content2 = ""; + if (reg.Count > 0) + { + foreach(Capture item in reg) + content2 = content.Replace(item.Value, item.Value.Replace(",", "%$")); + } + + var split = content2.Split(','); +stopwatch.Stop(); + Debug.WriteLine(stopwatch.Elapsed.ToString()); + richTextBox2.Text += Environment.NewLine + Environment.NewLine + content2; + } + + private void button5_Click(object sender, EventArgs e) +{ + var content = richTextBox1.Text; + + var aontent = Regex.Replace(content, @"\(([^)]*)\)", ""); + //foreach(var item in content.ToCharArray()) + + + //var match = Regex.Match(content, @"\(([^)]*)\)"); + + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + + string str = "h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps"; + var c = str.ToCharArray(); + List result = new List(); + for (int i = 0; i < c.Length; i++) + { + var temp = string.Empty; + if (c[i] == '(') + { + i++; + for (; i < c.Length; i++) + { + if (c[i] != ')') + { + temp += c[i]; + } + else + break; + } + if (temp.Length != 0) + result.Add(temp); + + } + } + richTextBox2.Text = string.Join(",", result); + stopwatch.Stop(); + Debug.WriteLine(stopwatch.Elapsed.ToString()); + +}*/ \ No newline at end of file diff --git a/FFmpegFaSample/Form1.resx b/FFmpegFaSample/Form1.resx new file mode 100644 index 0000000..59099f2 --- /dev/null +++ b/FFmpegFaSample/Form1.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/FFmpegFaSample/Program.cs b/FFmpegFaSample/Program.cs new file mode 100644 index 0000000..b91efa3 --- /dev/null +++ b/FFmpegFaSample/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace FFmpegFaSample +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/FFmpegFaSample/Properties/AssemblyInfo.cs b/FFmpegFaSample/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8c0a704 --- /dev/null +++ b/FFmpegFaSample/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("FFmpegFaSample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FFmpegFaSample")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("044e2738-f595-4186-ab3a-766da0f7c0a1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/FFmpegFaSample/Properties/Resources.Designer.cs b/FFmpegFaSample/Properties/Resources.Designer.cs new file mode 100644 index 0000000..547c690 --- /dev/null +++ b/FFmpegFaSample/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace FFmpegFaSample.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FFmpegFaSample.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/FFmpegFaSample/Properties/Resources.resx b/FFmpegFaSample/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/FFmpegFaSample/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/FFmpegFaSample/Properties/Settings.Designer.cs b/FFmpegFaSample/Properties/Settings.Designer.cs new file mode 100644 index 0000000..7cdbd76 --- /dev/null +++ b/FFmpegFaSample/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace FFmpegFaSample.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/FFmpegFaSample/Properties/Settings.settings b/FFmpegFaSample/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/FFmpegFaSample/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/WpfApp1/App.xaml b/WpfApp1/App.xaml new file mode 100644 index 0000000..2e70522 --- /dev/null +++ b/WpfApp1/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/WpfApp1/App.xaml.cs b/WpfApp1/App.xaml.cs new file mode 100644 index 0000000..c0f8ae6 --- /dev/null +++ b/WpfApp1/App.xaml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace WpfApp1 +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/WpfApp1/MainWindow.xaml b/WpfApp1/MainWindow.xaml new file mode 100644 index 0000000..8b6ea0a --- /dev/null +++ b/WpfApp1/MainWindow.xaml @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +