diff --git a/README.md b/README.md
index ce8bbc0..c69eef6 100644
--- a/README.md
+++ b/README.md
@@ -1,27 +1,28 @@
# XamarinAndroidFFmpeg (Xamarin.FFmpeg)
-FFmpeg library to run ffmeg commands over Xamarin.Android.
+FFmpeg library to run ffmeg commands over Xamarin.Forms
## About
-
-- Created to support a solution that needed ffmpeg to control camera devices.
-
+* Created to support a solution that needed ffmpeg to control camera devices.
+* Edited to allow usage on Xamarin.Forms
## Big thanks
-
-- FFmpeg library adapted from https://github.com/neurospeech/xamarin-android-ffmpeg
-- Original library in java https://github.com/WritingMinds/ffmpeg-android-java
-
+* FFmpeg library adapted from https://github.com/neurospeech/xamarin-android-ffmpeg
+* Original library in java https://github.com/WritingMinds/ffmpeg-android-java
## License
-
- - MIT
- - Besides that, to use this library you must accept the licensing terms mentioned in the source project at https://github.com/WritingMinds/ffmpeg-android-java
-
+* MIT
+* Besides that, to use this library you must accept the licensing terms mentioned in the source project at https://github.com/WritingMinds/ffmpeg-android-java
## Nuget package
You can download Xamarin.FFmpeg package from Nuget Package Manager or run following command in Nuget Package Console.
```
-Install-Package Xamarin.FFmpeg -Version 1.0.4
+Install-Package Xamarin.FFmpeg
```
## Usage
-On the way...
+
+### Android
+
+In MainActivity.cs before ``Forms.Init(this, bundle)``:
+```cs
+Xamarin.FFmpeg.Android.Init.Initialize(this.BaseContext);
+```
diff --git a/Xamarin.FFmpeg.Android/FFMpegSource.cs b/Xamarin.FFmpeg.Android/FFMpegSource.cs
new file mode 100644
index 0000000..d61f6a3
--- /dev/null
+++ b/Xamarin.FFmpeg.Android/FFMpegSource.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Xamarin.FFmpeg.Android
+{
+ public class FFmpegSource : IFFmpegSource
+ {
+ public string FFmpegVersion { get; } = "3.0.1.1";
+ public string Url { get; set; }
+ public string Arch { get; }
+ public string Hash { get; }
+ public Func IsArch { get; }
+
+ public FFmpegSource(string arch, Func isArch, string hash)
+ {
+ Arch = arch;
+ IsArch = isArch;
+ Hash = hash;
+ Url = $"https://raw.githubusercontent.com/gperozzo/XamarinAndroidFFmpeg/master/binary/{FFmpegVersion}/{Arch}/ffmpeg";
+ }
+
+ public static FFmpegSource[] Sources = new FFmpegSource[] {
+ new FFmpegSource("arm", x=> !x.EndsWith("86"), "yRVoeaZATQdZIR/lZxMsIa/io9U="),
+ new FFmpegSource("x86", x=> x.EndsWith("86"), "mU4QKhrLEO0aROb9N7JOCJ/rVTA==")
+ };
+
+ internal static FFmpegSource Get()
+ {
+ string osArchitecture = Java.Lang.JavaSystem.GetProperty("os.arch");
+
+ foreach (var source in Sources)
+ {
+ if (source.IsArch(osArchitecture))
+ return source;
+ }
+
+ return null;
+ }
+
+ public void SetUrl(string url)
+ {
+ Url = url;
+ }
+
+ 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/Xamarin.FFmpeg.Android/FFmpegLibrary.cs b/Xamarin.FFmpeg.Android/FFmpegLibrary.cs
new file mode 100644
index 0000000..67585f3
--- /dev/null
+++ b/Xamarin.FFmpeg.Android/FFmpegLibrary.cs
@@ -0,0 +1,315 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Android.App;
+using Android.Content;
+using System.Threading.Tasks;
+using Xamarin.FFmpeg.Exceptions;
+using Xamarin.FFmpeg;
+using Java.IO;
+
+namespace Xamarin.FFmpeg.Android
+{
+ public class FFmpegLibrary : IFFmpegLibrary
+ {
+ public string EndOfFFMPEGLine { get; } = "final ratefactor:";
+ private string Url;
+ private string SourceFolder;
+ private string DownloadTitle;
+ private bool Initialized = false;
+ private File FFmpegFile;
+ internal Context Context;
+
+ ///
+ /// Initializes the FFmpeg library and download it if necessary
+ ///
+ /// Context
+ ///
+ ///
+ ///
+ public async Task Init()
+ {
+ if (Initialized)
+ {
+ return;
+ }
+ FFmpegFile = new File((SourceFolder ?? Context.FilesDir.AbsolutePath) + "/ffmpeg");
+
+ FFmpegSource source = FFmpegSource.Get();
+
+ if (source == null)
+ {
+ throw new FFmpegNotInitializedException();
+ }
+
+ if (Url != null)
+ {
+ source.SetUrl(Url);
+ }
+
+ await Task.Run(() =>
+ {
+ if (FFmpegFile.Exists())
+ {
+ try
+ {
+ if (source.IsHashMatch(System.IO.File.ReadAllBytes(FFmpegFile.CanonicalPath)))
+ {
+ if (!FFmpegFile.CanExecute())
+ {
+ FFmpegFile.SetExecutable(true);
+ }
+
+ Initialized = true;
+
+ return;
+ }
+ }
+ catch (Exception)
+ {
+ // Não implementado
+ }
+
+ if (FFmpegFile.CanExecute())
+ {
+ FFmpegFile.SetExecutable(false);
+ }
+
+ FFmpegFile.Delete();
+ }
+ });
+
+ if (Initialized)
+ {
+ // Ffmpeg file exists...
+ return;
+ }
+
+ if (FFmpegFile.Exists())
+ {
+ FFmpegFile.Delete();
+ }
+
+ await Download();
+
+ if (!FFmpegFile.CanExecute())
+ {
+ FFmpegFile.SetExecutable(true);
+ }
+
+ Initialized = true;
+ }
+
+ ///
+ /// Run a command in FFmpeg (must be executed in the UI thread)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task Run(string cmd, Action logger = null)
+ {
+ try
+ {
+ TaskCompletionSource source = new TaskCompletionSource();
+
+ await Init();
+
+ await Task.Run(() =>
+ {
+ try
+ {
+ int n = _Run(cmd, logger);
+ source.SetResult(n);
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine(ex);
+ source.SetException(ex);
+ }
+ });
+
+ return await source.Task;
+ }
+ catch (Exception)
+ {
+ throw;
+ }
+ }
+
+ private int _Run(string cmd, Action logger = null)
+ {
+ TaskCompletionSource task = new TaskCompletionSource();
+
+ var startInfo = new System.Diagnostics.ProcessStartInfo(FFmpegFile.CanonicalPath, cmd)
+ {
+ RedirectStandardError = true,
+ RedirectStandardOutput = true,
+ UseShellExecute = false
+ };
+
+ var process = new System.Diagnostics.Process
+ {
+ StartInfo = startInfo
+ };
+
+ bool finished = false;
+
+ string error = null;
+
+ process.Start();
+
+ Task.Run(() =>
+ {
+ try
+ {
+ using (var reader = process.StandardError)
+ {
+ StringBuilder processOutput = new StringBuilder();
+ while (!finished)
+ {
+ var line = reader.ReadLine();
+ if (line == null)
+ break;
+ logger?.Invoke(line);
+ processOutput.Append(line);
+
+ if (line.StartsWith(EndOfFFMPEGLine))
+ {
+ Task.Run(async () =>
+ {
+ await Task.Delay(TimeSpan.FromMinutes(1));
+ finished = true;
+ });
+ }
+ }
+ error = processOutput.ToString();
+ }
+ }
+ catch (Exception)
+ {
+ // Não implementado
+ }
+ });
+
+ while (!finished)
+ {
+ process.WaitForExit(10000);
+ if (process.HasExited)
+ {
+ break;
+ }
+ }
+
+ return process.ExitCode;
+ }
+
+ ///
+ /// Download the FFmpeg library
+ ///
+ ///
+ ///
+ ///
+ public async Task Download()
+ {
+ File ffmpegFile;
+
+ if (SourceFolder != null)
+ {
+ ffmpegFile = new File(SourceFolder + "/ffmpeg");
+ }
+ else
+ {
+ var filesDir = Context.FilesDir;
+
+ ffmpegFile = new File(filesDir + "/ffmpeg");
+ }
+
+ FFmpegSource source = FFmpegSource.Get();
+
+ if (source == null)
+ {
+ throw new FFmpegNotInitializedException();
+ }
+
+ if (Url != null)
+ {
+ source.SetUrl(Url);
+ }
+
+ try
+ {
+ using (var c = new System.Net.Http.HttpClient())
+ {
+ 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 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())
+ {
+ long.TryParse(sl.FirstOrDefault(), out total);
+ }
+ }
+
+ int count = 0;
+ int progress = 0;
+
+ while ((count = await s.ReadAsync(buffer, 0, buffer.Length)) > 0)
+ {
+ await fout.WriteAsync(buffer, 0, count);
+
+ progress += count;
+ }
+ }
+ }
+ }
+ catch (Exception)
+ {
+ throw new FFmpegNotDownloadedException();
+ }
+
+ return true;
+ }
+
+ ///
+ /// Set the download url for ffmpeg library
+ ///
+ ///
+ public void SetDownloadUrl(string url)
+ {
+ Url = url;
+ }
+
+ ///
+ /// Set the source folder containing the ffmpeg library
+ ///
+ ///
+ public void SetSourceFolder(string path)
+ {
+ SourceFolder = path;
+ }
+
+ ///
+ /// Set the source folder containing the ffmpeg library
+ ///
+ ///
+ public void SetDownloadTitle(string title)
+ {
+ DownloadTitle = title;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.FFmpeg.Android/Init.cs b/Xamarin.FFmpeg.Android/Init.cs
new file mode 100644
index 0000000..85bcfad
--- /dev/null
+++ b/Xamarin.FFmpeg.Android/Init.cs
@@ -0,0 +1,15 @@
+using Android.Content;
+
+namespace Xamarin.FFmpeg.Android
+{
+ public class Init
+ {
+ public static void Initialize(Context context)
+ {
+ FFmpeg.Init.Initialize(new FFmpegLibrary
+ {
+ Context = context
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Xamarin.FFmpeg/Properties/AssemblyInfo.cs b/Xamarin.FFmpeg.Android/Properties/AssemblyInfo.cs
similarity index 100%
rename from Xamarin.FFmpeg/Properties/AssemblyInfo.cs
rename to Xamarin.FFmpeg.Android/Properties/AssemblyInfo.cs
diff --git a/Xamarin.FFmpeg/Resources/AboutResources.txt b/Xamarin.FFmpeg.Android/Resources/AboutResources.txt
similarity index 100%
rename from Xamarin.FFmpeg/Resources/AboutResources.txt
rename to Xamarin.FFmpeg.Android/Resources/AboutResources.txt
diff --git a/Xamarin.FFmpeg/Resources/Resource.Designer.cs b/Xamarin.FFmpeg.Android/Resources/Resource.Designer.cs
similarity index 93%
rename from Xamarin.FFmpeg/Resources/Resource.Designer.cs
rename to Xamarin.FFmpeg.Android/Resources/Resource.Designer.cs
index 8758e70..26a73f0 100644
--- a/Xamarin.FFmpeg/Resources/Resource.Designer.cs
+++ b/Xamarin.FFmpeg.Android/Resources/Resource.Designer.cs
@@ -9,9 +9,9 @@
//
//------------------------------------------------------------------------------
-[assembly: global::Android.Runtime.ResourceDesignerAttribute("Xamarin.FFmpeg.Resource", IsApplication=false)]
+[assembly: global::Android.Runtime.ResourceDesignerAttribute("Xamarin.FFmpeg.Android.Resource", IsApplication=false)]
-namespace Xamarin.FFmpeg
+namespace Xamarin.FFmpeg.Android
{
diff --git a/Xamarin.FFmpeg/Resources/Values/Strings.xml b/Xamarin.FFmpeg.Android/Resources/Values/Strings.xml
similarity index 100%
rename from Xamarin.FFmpeg/Resources/Values/Strings.xml
rename to Xamarin.FFmpeg.Android/Resources/Values/Strings.xml
diff --git a/Xamarin.FFmpeg/FFMpeg.Xamarin.csproj.bak b/Xamarin.FFmpeg.Android/Xamarin.FFmpeg.Android.csproj
similarity index 83%
rename from Xamarin.FFmpeg/FFMpeg.Xamarin.csproj.bak
rename to Xamarin.FFmpeg.Android/Xamarin.FFmpeg.Android.csproj
index a9554b0..051e372 100644
--- a/Xamarin.FFmpeg/FFMpeg.Xamarin.csproj.bak
+++ b/Xamarin.FFmpeg.Android/Xamarin.FFmpeg.Android.csproj
@@ -9,13 +9,12 @@
{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
Library
Properties
- FFMpeg.Xamarin
- FFMpeg.Xamarin
+ Xamarin.FFmpeg.Android
+ Xamarin.FFmpeg.Android
512
Resources\Resource.Designer.cs
Off
- True
- v7.1
+ v9.0
true
@@ -44,8 +43,9 @@
-
-
+
+
+
@@ -55,6 +55,12 @@
+
+
+ {807f181e-43aa-4516-a86d-d68bb9ef5e95}
+ Xamarin.FFmpeg
+
+
-
\ No newline at end of file
+
+
diff --git a/XamarinAndroidFFmpeg.sln b/XamarinAndroidFFmpeg.sln
index 1ec037b..94e9ec1 100644
--- a/XamarinAndroidFFmpeg.sln
+++ b/XamarinAndroidFFmpeg.sln
@@ -1,16 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2020
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29201.188
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.FFmpeg.Nuget", "Xamarin.FFmpeg.Nuget\Xamarin.FFmpeg.Nuget.csproj", "{0451BAEF-DF2E-4B98-8644-94EE9415E389}"
ProjectSection(ProjectDependencies) = postProject
{1049745B-3D4C-4DFF-AD8B-DC46F460B5D4} = {1049745B-3D4C-4DFF-AD8B-DC46F460B5D4}
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.FFmpeg", "Xamarin.FFmpeg\Xamarin.FFmpeg.csproj", "{1049745B-3D4C-4DFF-AD8B-DC46F460B5D4}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.FFmpeg.Android", "Xamarin.FFmpeg.Android\Xamarin.FFmpeg.Android.csproj", "{1049745B-3D4C-4DFF-AD8B-DC46F460B5D4}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A2C28ED0-0741-4CDE-B9FA-604C145DE4D9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.FFmpeg", "Xamarin.FFMpeg\Xamarin.FFmpeg.csproj", "{807F181E-43AA-4516-A86D-D68BB9EF5E95}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -26,6 +26,10 @@ Global
{1049745B-3D4C-4DFF-AD8B-DC46F460B5D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1049745B-3D4C-4DFF-AD8B-DC46F460B5D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1049745B-3D4C-4DFF-AD8B-DC46F460B5D4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {807F181E-43AA-4516-A86D-D68BB9EF5E95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {807F181E-43AA-4516-A86D-D68BB9EF5E95}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {807F181E-43AA-4516-A86D-D68BB9EF5E95}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {807F181E-43AA-4516-A86D-D68BB9EF5E95}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Additions/AboutAdditions.txt b/src/Additions/AboutAdditions.txt
deleted file mode 100644
index 08caee3..0000000
--- a/src/Additions/AboutAdditions.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-Additions allow you to add arbitrary C# to the generated classes
-before they are compiled. This can be helpful for providing convenience
-methods or adding pure C# classes.
-
-== Adding Methods to Generated Classes ==
-
-Let's say the library being bound has a Rectangle class with a constructor
-that takes an x and y position, and a width and length size. It will look like
-this:
-
-public partial class Rectangle
-{
- public Rectangle (int x, int y, int width, int height)
- {
- // JNI bindings
- }
-}
-
-Imagine we want to add a constructor to this class that takes a Point and
-Size structure instead of 4 ints. We can add a new file called Rectangle.cs
-with a partial class containing our new method:
-
-public partial class Rectangle
-{
- public Rectangle (Point location, Size size) :
- this (location.X, location.Y, size.Width, size.Height)
- {
- }
-}
-
-At compile time, the additions class will be added to the generated class
-and the final assembly will a Rectangle class with both constructors.
-
-
-== Adding C# Classes ==
-
-Another thing that can be done is adding fully C# managed classes to the
-generated library. In the above example, let's assume that there isn't a
-Point class available in Java or our library. The one we create doesn't need
-to interact with Java, so we'll create it like a normal class in C#.
-
-By adding a Point.cs file with this class, it will end up in the binding library:
-
-public class Point
-{
- public int X { get; set; }
- public int Y { get; set; }
-}
\ No newline at end of file
diff --git a/src/Jars/AboutJars.txt b/src/Jars/AboutJars.txt
deleted file mode 100644
index c359b62..0000000
--- a/src/Jars/AboutJars.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-This directory is for Android .jars.
-
-There are 2 types of jars that are supported:
-
-== Input Jar ==
-
-This is the jar that bindings should be generated for.
-
-For example, if you were binding the Google Maps library, this would
-be Google's "maps.jar".
-
-Set the build action for these jars in the properties page to "InputJar".
-
-
-== Reference Jars ==
-
-These are jars that are referenced by the input jar. C# bindings will
-not be created for these jars. These jars will be used to resolve
-types used by the input jar.
-
-NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
-based on the Target Framework selected.
-
-Set the build action for these jars in the properties page to "ReferenceJar".
\ No newline at end of file
diff --git a/src/Jars/FFmpegAndroid-debug.aar b/src/Jars/FFmpegAndroid-debug.aar
deleted file mode 100644
index c78b1eb..0000000
Binary files a/src/Jars/FFmpegAndroid-debug.aar and /dev/null differ
diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs
deleted file mode 100644
index 6715424..0000000
--- a/src/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using Android.App;
-
-// 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("Audition800.FFmpeg")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Audition800.FFmpeg")]
-[assembly: AssemblyCopyright("Copyright © 2016")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: ComVisible(false)]
-
-// 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/src/Transforms/EnumFields.xml b/src/Transforms/EnumFields.xml
deleted file mode 100644
index 2295995..0000000
--- a/src/Transforms/EnumFields.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/src/Transforms/EnumMethods.xml b/src/Transforms/EnumMethods.xml
deleted file mode 100644
index 49216c6..0000000
--- a/src/Transforms/EnumMethods.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/src/Transforms/Metadata.xml b/src/Transforms/Metadata.xml
deleted file mode 100644
index 75aebe4..0000000
--- a/src/Transforms/Metadata.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- public
- public
-
-
-
diff --git a/src/Xamarin.FFmpeg.csproj b/src/Xamarin.FFmpeg.csproj
deleted file mode 100644
index ea70612..0000000
--- a/src/Xamarin.FFmpeg.csproj
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {430983C2-C8A0-4644-91E0-397CD6E43063}
- {10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Library
- Properties
- Audition800.FFmpeg
- Audition800.FFmpeg
- 512
- True
- v6.0
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file