FFMPEG Avalonia #19058
-
Hello, I am trying to use ffmpeg for avalonia android. But I face with issues running the executable of ffmpeg. I am exporting the ffmpeg executables (for android) to apk and use code to extract needed ffmpeg and remove others. But issue is, when I try to use that ffmpeg executable, it always says that permission is denied and I cannot use it. I tried to chmod the file not helping. Though If I use the Termux on android and go to path of extracted ffmpeg and chmod from termux it helps, and I can use the executable. Any idea on how to properly extract the executable of ffmpeg and run it? using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Android.App;
namespace YoutubeDownloader.Android;
public static class AndroidFFmpegInitializer
{
private static readonly string[] AllArchitectures = ["arm", "arm64-v8a", "i686", "x86_64"]; // "armv7-a", "arm-v7n", add if needed.
public static async Task InitializeAsync()
{
var extractedPath = await ExtractFFmpegFromAssetsAsync();
if (!string.IsNullOrEmpty(extractedPath))
{
// Core.Downloading.FFmpeg.SetCustomPath(extractedPath);
TryToUseFFMPEG(extractedPath);
CleanupUnusedArchitecturesAsync();
}
}
private static void TryToUseFFMPEG(string extractedPath)
{
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = extractedPath,
Arguments = "-h",
RedirectStandardOutput = true,
WorkingDirectory = Path.GetDirectoryName(extractedPath) ?? string.Empty,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError.ReadToEnd();
process.WaitForExit();
Debug.WriteLine($"FFmpeg Output: {output}");
if (!string.IsNullOrEmpty(error))
Debug.WriteLine($"FFmpeg Error: {error}");
}
catch (Exception ex)
{
// returns always [0:] FFmpeg execution failed: An error occurred trying to start process '/data/user/0/com.tyrrrz.youtubedownloader/files/ffmpeg' with working directory '/data/user/0/com.tyrrrz.youtubedownloader/files'. Permission denied
Debug.WriteLine($"FFmpeg execution failed: {ex.Message}");
}
}
private static async Task<string?> ExtractFFmpegFromAssetsAsync()
{
try
{
var context = Application.Context;
if (context == null) return null;
var architecture = GetAndroidArchitecture();
var assetPath = $"{architecture}/ffmpeg";
var internalDir = context.FilesDir?.AbsolutePath;
if (string.IsNullOrEmpty(internalDir)) return null;
var extractedPath = Path.Combine(internalDir, "ffmpeg");
if (File.Exists(extractedPath) && new FileInfo(extractedPath).Length > 0)
return extractedPath;
// Extract from assets
using var assetStream = context.Assets?.Open(assetPath);
if (assetStream == null) return null;
using var fileStream = File.Create(extractedPath);
await assetStream.CopyToAsync(fileStream);
// Set execute permissions
try
{
var process = Process.Start(new ProcessStartInfo
{
FileName = "chmod",
Arguments = $"+x \"{extractedPath}\"",
UseShellExecute = false,
CreateNoWindow = true
});
process?.WaitForExit();
}
catch { }
return extractedPath;
}
catch (Exception ex)
{
Debug.WriteLine($"FFmpeg extraction failed: {ex.Message}");
return null;
}
}
private static void CleanupUnusedArchitecturesAsync()
{
try
{
var context = Application.Context;
if (context == null) return;
var internalDir = context.FilesDir?.AbsolutePath;
if (string.IsNullOrEmpty(internalDir)) return;
var currentArch = GetAndroidArchitecture();
// Remove any previously extracted FFmpeg binaries from other architectures
foreach (var arch in AllArchitectures)
{
if (arch == currentArch) continue;
try
{
var oldBinaryPath = Path.Combine(internalDir, $"ffmpeg_{arch}");
if (File.Exists(oldBinaryPath))
{
File.Delete(oldBinaryPath);
Debug.WriteLine($"Cleaned up unused FFmpeg binary: {arch}");
}
}
catch (Exception ex)
{
Debug.WriteLine($"Failed to cleanup {arch}: {ex.Message}");
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Cleanup failed: {ex.Message}");
}
}
private static string GetAndroidArchitecture()
{
return RuntimeInformation.ProcessArchitecture switch
{
Architecture.Arm => "arm",
Architecture.Arm64 => "arm64-v8a",
Architecture.X86 => "i686",
Architecture.X64 => "x86_64",
_ => "arm64-v8a"
};
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Resolved by creating in Android Project Should look something like this: |
Beta Was this translation helpful? Give feedback.
Resolved by creating in Android Project
libs
folder, and making files inside as AndroidNativeLibrary.Should look something like this: