diff --git a/FFMpeg.Xamarin/FFMpeg.Xamarin.csproj b/FFMpeg.Xamarin/FFMpeg.Xamarin.csproj index 36e2193..02592f4 100644 --- a/FFMpeg.Xamarin/FFMpeg.Xamarin.csproj +++ b/FFMpeg.Xamarin/FFMpeg.Xamarin.csproj @@ -15,7 +15,7 @@ Resources\Resource.Designer.cs Off True - v6.0 + v7.0 true @@ -45,6 +45,7 @@ + diff --git a/FFMpeg.Xamarin/FFMpegLibrary.cs b/FFMpeg.Xamarin/FFMpegLibrary.cs index d001a92..fc2e8fa 100644 --- a/FFMpeg.Xamarin/FFMpegLibrary.cs +++ b/FFMpeg.Xamarin/FFMpegLibrary.cs @@ -15,57 +15,54 @@ namespace FFMpeg.Xamarin { public class FFMpegLibrary { + public static string EndOfFFMPEGLine = "final ratefactor:"; public string CDNHost { get; set; } = "raw.githubusercontent.com"; - - - public static FFMpegLibrary Instance = new FFMpegLibrary(); + + public readonly static FFMpegLibrary Instance = new FFMpegLibrary(); private bool _initialized = false; - private Java.IO.File ffmpegFile; + private Java.IO.File _ffmpegFile; /// /// /// /// /// - public async Task Init( - Context context, - string cdn = null, - string downloadTitle = null, - string downloadMessage = null) + public async Task Init(Context context, string cdn = null, string downloadTitle = null, string downloadMessage = null) { if (_initialized) return; - if (cdn != null) { + if (cdn != null) + { CDNHost = cdn; } // do all initialization... var filesDir = context.FilesDir; - ffmpegFile = new Java.IO.File(filesDir + "/ffmpeg"); + _ffmpegFile = new Java.IO.File(filesDir + "/ffmpeg"); - FFMPEGSource source = FFMPEGSource.Get(); + FFMpegSource source = FFMpegSource.Get(); await Task.Run(() => { - - if (ffmpegFile.Exists()) + if (_ffmpegFile.Exists()) { try { - if (source.IsHashMatch(System.IO.File.ReadAllBytes(ffmpegFile.CanonicalPath))) + if (source.IsHashMatch(System.IO.File.ReadAllBytes(_ffmpegFile.CanonicalPath))) { - if (!ffmpegFile.CanExecute()) - ffmpegFile.SetExecutable(true); + if (!_ffmpegFile.CanExecute()) + _ffmpegFile.SetExecutable(true); _initialized = true; return; } } - catch(Exception ex) { + catch (Exception ex) + { System.Diagnostics.Debug.WriteLine($" Error validating file {ex}"); } @@ -73,10 +70,10 @@ await Task.Run(() => // delete the file... - if (ffmpegFile.CanExecute()) - ffmpegFile.SetExecutable(false); - ffmpegFile.Delete(); - System.Diagnostics.Debug.WriteLine($"ffmpeg file deleted at {ffmpegFile.AbsolutePath}"); + if (_ffmpegFile.CanExecute()) + _ffmpegFile.SetExecutable(false); + _ffmpegFile.Delete(); + System.Diagnostics.Debug.WriteLine($"ffmpeg file deleted at {_ffmpegFile.AbsolutePath}"); } }); @@ -86,87 +83,72 @@ await Task.Run(() => return; } - if (ffmpegFile.Exists()) { - ffmpegFile.Delete(); + if (_ffmpegFile.Exists()) + { + _ffmpegFile.Delete(); } // lets try to download - var dlg = new ProgressDialog(context); - dlg.SetTitle(downloadMessage ?? "Downloading Video Converter"); + var dialog = new ProgressDialog(context); + dialog.SetTitle(downloadMessage ?? "Downloading Video Converter"); //dlg.SetMessage(downloadMessage ?? "Downloading Video Converter"); - dlg.Indeterminate = false; - dlg.SetProgressStyle(ProgressDialogStyle.Horizontal); - dlg.SetCancelable(false); - dlg.CancelEvent += (s, e) => { - - }; - - dlg.SetCanceledOnTouchOutside(false); - dlg.Show(); + dialog.Indeterminate = false; + dialog.SetProgressStyle(ProgressDialogStyle.Horizontal); + dialog.SetCancelable(false); + dialog.CancelEvent += (s, e) => + { + }; + dialog.SetCanceledOnTouchOutside(false); + dialog.Show(); using (var c = new System.Net.Http.HttpClient()) { - using (var fout = System.IO.File.OpenWrite(ffmpegFile.AbsolutePath)) + using (var fout = System.IO.File.OpenWrite(_ffmpegFile.AbsolutePath)) { - string url = source.Url; var g = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url); - - var h = await c.SendAsync(g, System.Net.Http.HttpCompletionOption.ResponseHeadersRead); - - - - - + var h = await c.SendAsync(g, System.Net.Http.HttpCompletionOption.ResponseHeadersRead); var buffer = new byte[51200]; - var s = await h.Content.ReadAsStreamAsync(); long total = h.Content.Headers.ContentLength.GetValueOrDefault(); IEnumerable sl; if (h.Headers.TryGetValues("Content-Length", out sl)) { - if (total == 0 && sl.Any()) { + if (total == 0 && sl.Any()) + { long.TryParse(sl.FirstOrDefault(), out total); } } - int count = 0; - int progress = 0; - dlg.Max = (int)total; - - - while ((count = await s.ReadAsync(buffer, 0, buffer.Length)) > 0) { + dialog.Max = (int)total; + while ((count = await s.ReadAsync(buffer, 0, buffer.Length)) > 0) + { await fout.WriteAsync(buffer, 0, count); progress += count; //System.Diagnostics.Debug.WriteLine($"Downloaded {progress} of {total} from {url}"); - dlg.Progress = progress; + dialog.Progress = progress; } - - dlg.Hide(); - - - - + dialog.Hide(); } } - System.Diagnostics.Debug.WriteLine($"ffmpeg file copied at {ffmpegFile.AbsolutePath}"); + System.Diagnostics.Debug.WriteLine($"ffmpeg file copied at {_ffmpegFile.AbsolutePath}"); - if (!ffmpegFile.CanExecute()) + if (!_ffmpegFile.CanExecute()) { - ffmpegFile.SetExecutable(true); + _ffmpegFile.SetExecutable(true); System.Diagnostics.Debug.WriteLine($"ffmpeg file made executable"); } @@ -180,22 +162,18 @@ await Task.Run(() => /// /// /// - public static async Task Run(Context context, string cmd, Action logger = null) { - + public static async Task Run(Context context, string cmd, Action logger = null) + { try { TaskCompletionSource source = new TaskCompletionSource(); - - await Instance.Init(context); await Task.Run(() => { try { - - int n = _Run(context, cmd, logger); source.SetResult(n); } @@ -208,31 +186,23 @@ await Task.Run(() => return await source.Task; } - catch (Exception ex) { - + catch (Exception ex) + { System.Diagnostics.Debug.WriteLine(ex); throw ex; } } - - public static string EndOfFFMPEGLine = "final ratefactor:"; - - private static int _Run( - Context context, - string cmd, - Action logger = null) + + private static int _Run(Context context, string cmd, Action logger = null) { - TaskCompletionSource task = new TaskCompletionSource(); - - System.Diagnostics.Debug.WriteLine($"ffmpeg initialized"); //var process = Java.Lang.Runtime.GetRuntime().Exec( Instance.ffmpegFile.CanonicalPath + " " + cmd ); - var startInfo = new System.Diagnostics.ProcessStartInfo(Instance.ffmpegFile.CanonicalPath, cmd); + var startInfo = new System.Diagnostics.ProcessStartInfo(Instance._ffmpegFile.CanonicalPath, cmd); startInfo.RedirectStandardError = true; startInfo.RedirectStandardOutput = true; @@ -247,43 +217,36 @@ private static int _Run( string error = null; process.Start(); - - - Task.Run(() => { try { using (var reader = process.StandardError) { - string processOutput = ""; - do + StringBuilder processOutput = new StringBuilder(); + while (!finished) { var line = reader.ReadLine(); if (line == null) break; logger?.Invoke(line); - processOutput += line; - - + processOutput.Append(line); + if (line.StartsWith(EndOfFFMPEGLine)) { - - Task.Run(async () => { + Task.Run(async () => + { await Task.Delay(TimeSpan.FromMinutes(1)); finished = true; }); - } - - } while (!finished); - error = processOutput; - - + } + error = processOutput.ToString(); } } - catch (Exception ex) { + catch (Exception ex) + { System.Diagnostics.Debug.WriteLine(ex); } }); @@ -291,70 +254,13 @@ private static int _Run( while (!finished) { process.WaitForExit(10000); - if (process.HasExited) { + if (process.HasExited) + { break; } } return process.ExitCode; - - } - - - } - - - public class FFMPEGSource { - - - public static FFMPEGSource Get() { - - string osArchitecture = Java.Lang.JavaSystem.GetProperty("os.arch"); - - foreach (var source in Sources) { - if (source.IsArch(osArchitecture)) - return source; - } - - throw new NotImplementedException(); - } - - - - - - - public FFMPEGSource(string arch, Func isArch, string hash) - { - this.Arch = arch; - this.IsArch = isArch; - this.Hash = hash; - } - - public static string FFMPEGVersion { get; } = "3.0.1"; - - public static FFMPEGSource[] Sources = new FFMPEGSource[] { - new FFMPEGSource("arm", x=> !x.EndsWith("86"), "4nzzxDKxIYlvyK8tFH7/iNMHTdU="), - new FFMPEGSource("x86", x=> x.EndsWith("86"), "DdTbrTBf8Zeh6p5hWL0ggdIp5w4=") - }; - - public string Arch { get; } - - public string Hash { get; } - - - //https://cdn.rawgit.com/neurospeech/xamarin-android-ffmpeg/master/binary/3.0.1/arm/ffmpeg - //https://raw.githubusercontent.com/neurospeech/xamarin-android-ffmpeg/master/binary/3.0.1/arm/ffmpeg - public string Url => $"https://{FFMpegLibrary.Instance.CDNHost}/neurospeech/xamarin-android-ffmpeg/v1.0.7/binary/{FFMPEGVersion}/{Arch}/ffmpeg"; - - public Func IsArch { get; } - - public bool IsHashMatch(byte[] data) { - var sha = System.Security.Cryptography.SHA1.Create(); - string h = Convert.ToBase64String(sha.ComputeHash(data)); - return h == Hash; - } - } } \ No newline at end of file diff --git a/FFMpeg.Xamarin/FFMpegSource.cs b/FFMpeg.Xamarin/FFMpegSource.cs new file mode 100644 index 0000000..e9ae1b1 --- /dev/null +++ b/FFMpeg.Xamarin/FFMpegSource.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; + +namespace FFMpeg.Xamarin +{ + public class FFMpegSource + { + public static string FFMPEGVersion { get; } = "3.0.1"; + + public FFMpegSource(string arch, Func isArch, string hash) + { + this.Arch = arch; + this.IsArch = isArch; + this.Hash = hash; + } + + public static FFMpegSource[] Sources = new FFMpegSource[] { + new FFMpegSource("arm", x=> !x.EndsWith("86"), "4nzzxDKxIYlvyK8tFH7/iNMHTdU="), + new FFMpegSource("x86", x=> x.EndsWith("86"), "DdTbrTBf8Zeh6p5hWL0ggdIp5w4=") + }; + + public string Arch { get; } + + public string Hash { get; } + + //https://cdn.rawgit.com/neurospeech/xamarin-android-ffmpeg/master/binary/3.0.1/arm/ffmpeg + //https://raw.githubusercontent.com/neurospeech/xamarin-android-ffmpeg/master/binary/3.0.1/arm/ffmpeg + public string Url => $"https://{FFMpegLibrary.Instance.CDNHost}/neurospeech/xamarin-android-ffmpeg/v1.0.7/binary/{FFMPEGVersion}/{Arch}/ffmpeg"; + + public Func IsArch { get; } + + public static FFMpegSource Get() + { + string osArchitecture = Java.Lang.JavaSystem.GetProperty("os.arch"); + + foreach (var source in Sources) + { + if (source.IsArch(osArchitecture)) + return source; + } + + throw new NotImplementedException(); + } + + public bool IsHashMatch(byte[] data) + { + var sha = System.Security.Cryptography.SHA1.Create(); + string h = Convert.ToBase64String(sha.ComputeHash(data)); + return h == Hash; + } + } +} \ No newline at end of file