DEV Community

Cover image for Tired of complicated compilation?Integrate AeroFFmpeg with one click to make Android audio and video development easier!

Tired of complicated compilation?Integrate AeroFFmpeg with one click to make Android audio and video development easier!

Tired of complicated compilation?Integrate AeroFFmpeg with one click to make Android audio and video development easier!

Preface

As an Android developer, have you ever needed to implement audio and video features in your project, but been put off by FFmpeg's complex compilation process? To use FFmpeg on Android, you need to:

  • Download the FFmpeg source code, possibly including various dependent libraries.
  • Configure a complex cross-compilation environment, such as the NDK and compiler.
  • Write lengthy compilation scripts to handle compatibility issues with different CPU architectures and operating systems.
  • Have to start all over again with every FFmpeg version update.
  • This process can be a nightmare, time-consuming and labor-intensive, and prone to errors if you're not careful!

This article introduces AeroFFmpeg, the open-source FFmpeg Android SDK project. It compiles FFmpeg into a simple, easy-to-use AAR (Android Archive) file, providing an out-of-the-box solution for Android developers. With just a few lines of code, Android developers can integrate powerful FFmpeg features into their Android projects.

Minimalistic AeroFFmpeg Integration

Currently, AeroFFmpeg has a minSdk of 24 and a targetSdk of 34. It is compiled based on FFmpeg 4.2.9 and supports MP3, H.264, and H.265. Currently, AeroFFmpeg only supports the arm64-v8a and x86 architectures and does not yet support 16KB page sizes. Once AeroFFmpeg is integrated into your project, you can immediately use the FFmpeg command line. The following describes how to integrate and use AeroFFmpeg.

Importing the AeroFFmpeg AAR File

Since AeroFFmpeg has not yet been released to the Maven repository, you will need to integrate the AAR file directly by importing it. The AAR file address is as follows:

https://github.com/Ilovecat1949/AeroFFmpeg/releases/tag/v1.0.0

  1. Copy the AAR file to the libs folder under the app module in your Android project. If the libs folder does not exist, create one manually.

Importing the AAR file

  1. Configure the build.gradle file Open the app module's build.gradle file. You need to configure two sections: repositories and dependencies.
repositories {
    flatDir {
        dirs("libs")
    }
}

implementation(files("libs/AeroFFmpeglib-release.aar"))


Enter fullscreen mode Exit fullscreen mode

The declaration repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) in the settings.gradle.kts file will prevent the module from being added locally. If present, replace this declaration with repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS).

Replace Declaration

  1. Sync the Project Click Sync Now. Gradle will automatically download the .aar file and all its dependencies from the specified Maven repository and add it to your project.

With these steps, you've integrated AeroFFmpeg into your project.

AeroFFmpeg Usage and Scenarios

AeroFFmpeg uses a singleton model and supports the FFmpeg command line, which executes asynchronously in a child thread. Note that AeroFFmpeg does not support multi-threaded concurrent execution of the FFmpeg command line; a new command line task cannot be started before the previous one has completed. If you need to support concurrent audio and video tasks, consider using Android multi-process programming to call different AeroFFmpeg instances.

//Start an FFmpeg command line task
//Returns a result: 0 for success, -1 for failure
val result = AeroFFmpeg.start("ffmpeg -i input.mp4 output.mp4")

//Get the current task status: 0: Executing the task or not executing at all; 1: Task completed without error; -1: Task completed with error
AeroFFmpeg.getTaskState()

//Cancel the task
AeroFFmpeg.cancelTask()

//Get the current task progress. Returns a Double value in milliseconds.
AeroFFmpeg.getProgressTime()

//Process log information through the log callback function
AeroFFmpeg.setLogListener (
object: OnLogListener {
override fun onLog(level: Int, message: String) {
Log.d("AeroFFmpeg.setLogListener","$level,$message")

}
}
)
Enter fullscreen mode Exit fullscreen mode

Completing Background Audio and Video Tasks with AeroFFmpeg and WorkManager

Next, we'll develop an application that performs background audio and video tasks based on AeroFFmpeg and WorkManager. WorkManager, as the officially recommended background task API, offers advantages such as high reliability, persistent execution, and high energy efficiency. For detailed usage of WorkManager, please refer to my previous article.
First, define a Worker class that executes the FFmpeg command line.

class FFmpegTaskWorker(
    appContext: Context,
    workerParams: WorkerParameters
) : CoroutineWorker(appContext, workerParams) {

    // 重写 getForegroundInfo() 以提供前台服务通知信息
    override suspend fun getForegroundInfo(): ForegroundInfo {
        return ForegroundInfo(
            FFMPEG_CMD_ID,
            notificationBuilder.setContentText("开始执行任务...").build()
        )
    }

    override suspend fun doWork(): Result {
        setForeground(getForegroundInfo())
        val cmd = inputData.getString(FFMPEG_CMD)
        return withContext(Dispatchers.IO) {
            try {
            try {
                if(AeroFFmpeg.start(cmd!!)<0){
                    return@withContext Result.failure()
                }
                AeroFFmpeg.start(cmd)
                while(AeroFFmpeg.getTaskState()==0){
                    notificationBuilder.setContentText("任务进度:${formatTimeFromMillis(AeroFFmpeg.getProgressTime())}")
                    setProgress(AeroFFmpeg.getProgressTime())
                    if (ActivityCompat.checkSelfPermission(
                            applicationContext,
                            Manifest.permission.POST_NOTIFICATIONS
                        ) == PackageManager.PERMISSION_GRANTED
                    ) {
                        notificationManager.notify(FFMPEG_CMD_ID, notificationBuilder.build())
                    }
                    delay(100)
                }
                if(AeroFFmpeg.getTaskState()==1){
                    notificationBuilder.setContentText("执行成功")
                    if (ActivityCompat.checkSelfPermission(
                            applicationContext,
                            Manifest.permission.POST_NOTIFICATIONS
                        ) == PackageManager.PERMISSION_GRANTED
                    ) {
                        notificationManager.notify(FFMPEG_CMD_ID, notificationBuilder.build())
                    }
                    return@withContext Result.success()
                }
                else{
                    notificationBuilder.setContentText("执行失败")
                    if (ActivityCompat.checkSelfPermission(
                            applicationContext,
                            Manifest.permission.POST_NOTIFICATIONS
                        ) == PackageManager.PERMISSION_GRANTED
                    ) {
                        notificationManager.notify(FFMPEG_CMD_ID, notificationBuilder.build())
                    }
                    return@withContext Result.failure()
                }
            } catch (e: Exception) {
                e.printStackTrace()
                // Task failed, update notification
                notificationBuilder.setContentText("执行失败").setProgress(0, 0, false)
                return@withContext Result.failure()
            } finally {
                // Ensure notification is cancelled
                if (ActivityCompat.checkSelfPermission(
                        applicationContext,
                        Manifest.permission.POST_NOTIFICATIONS
                    ) == PackageManager.PERMISSION_GRANTED
                ) {
                    notificationManager.cancel(FFMPEG_CMD_ID)
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Define a method to start the task and encapsulate the process of submitting the task to WorkManager.

fun startFFmpegTask(context: Context, cmd: String) {

    val data = workDataOf(FFMPEG_CMD to cmd)
    // Set constraints to only download when connected to a network
    val constraints = Constraints.Builder()
        //.setRequiredNetworkType(NetworkType.CONNECTED)
        .build()

    // Create a OneTimeWorkRequest for the download
    val ffmpegTaskRequest = OneTimeWorkRequestBuilder<FFmpegTaskWorker>()
        .setConstraints(constraints)
        .setInputData(data)
        .addTag(FFMPEG_TASK_TAG)
        .build()
    // Enqueue the work request
    WorkManager.getInstance(context).enqueue(ffmpegTaskRequest)
}
Enter fullscreen mode Exit fullscreen mode

Through the LiveData class, the status and progress of tasks can be observed and displayed in real time, achieving synchronization between background task information and UI display information.

    val context = LocalContext.current
    val workManager = WorkManager.getInstance(context)
    var cmd by remember { mutableStateOf("") }
    val workInfos: LiveData<List<WorkInfo>> = remember {
        workManager.getWorkInfosByTagLiveData(FFMPEG_TASK_TAG)
    }
    val ffmpegTasks by workInfos.observeAsState(initial = emptyList())
    ...

        LazyColumn(
            modifier = Modifier.fillMaxSize()
        ) {
            items(ffmpegTasks) { workInfo ->
                FFmpegTaskItem(workInfo)
            }
        }    
Enter fullscreen mode Exit fullscreen mode

The resulting application is shown below.

Execute FFmpeg command line task in the background

Thus, using AeroFFmpeg, we can easily implement audio and video features in Android apps.

Summary

FFmpeg is a powerful open-source audio and video processing tool that supports transcoding, editing, recording, streaming, filtering, and more. With AeroFFmpeg, you can bring FFmpeg's audio and video capabilities to your Android app without complex NDK configuration or lengthy compilation scripts. I will continue to update and improve AeroFFmpeg.
The AeroFFmpeg repository is as follows:

https://github.com/Ilovecat1949/AeroFFmpeg

The AeroFFmpeg+WorkManager sample code is in the WorkDownloader project in the following repository:

https://github.com/Ilovecat1949/AndroidApps

References

  1. Google Tutorial on Creating an Android Library
  2. Official Android Background Work Guide
  3. Official ffmpeg Command Line Documentation

Top comments (0)