How to use FFmpeg in Android

FFmpeg, a powerful multimedia processing library, provides developers with the ability to manipulate audio and video files in Android applications. In this comprehensive guide, we will explore the steps to integrate FFmpeg into an Android project and provide examples of how to use it for basic multimedia processing tasks.

  1. Setting Up the Development Environment:
    Before integrating FFmpeg into your Android project, ensure you have Android Studio installed on your development machine. Android Studio is the official IDE for Android development.
  2. Creating a New Android Project:
    Open Android Studio and create a new Android project. Ensure that you have a minimum SDK version of 16 or higher, as FFmpeg requires a relatively recent Android version.
  3. Adding FFmpeg Dependency:
    To integrate FFmpeg into your Android project, you can use precompiled binaries or compile FFmpeg from source. For simplicity, we will use a precompiled binary.
  • Open your app-level build.gradle file.
  • Add the following dependency:
    gradle implementation 'com.arthenica:mobile-ffmpeg-full:5.0.4'
  1. Syncing Gradle and Updating Project:
    After adding the dependency, sync your Gradle files to ensure that the necessary dependencies are downloaded. Click on “Sync Now” when prompted.
  2. Basic FFmpeg Usage:
    Now that FFmpeg is integrated, you can use it for various multimedia processing tasks. For instance, let’s consider a simple command to convert a video file. In your activity or fragment, use the following code:
   FFmpeg.execute("-i input.mp4 -c:v h264 output.mp4");

This command converts an input video file (input.mp4) to the H.264 video codec and saves the result as output.mp4. You can customize the command to suit your specific requirements.

  1. Handling FFmpeg Execution Output:
    FFmpeg commands may generate output that you might want to analyze. To capture this output, you can use the FFmpeg.executeAsync method with a callback:
   FFmpeg.executeAsync("-i input.mp4 -c:v h264 output.mp4", new ExecuteCallback() {
       @Override
       public void apply(long executionId, int returnCode) {
           Log.i("FFmpeg", "Return code: " + returnCode);
       }
   });

This allows you to examine the execution results and respond accordingly.

  1. Running FFmpeg Commands Asynchronously:
    To prevent freezing the UI, run FFmpeg commands in the background using AsyncTask or other concurrency mechanisms. For example:
   new AsyncTask<Void, Void, Void>() {
       @Override
       protected Void doInBackground(Void... voids) {
           FFmpeg.execute("-i input.mp4 -c:v h264 output.mp4");
           return null;
       }
   }.execute();
  1. Handling Permissions:
    If your FFmpeg commands involve accessing files or resources, ensure that your app has the necessary permissions. Include the required permissions in your AndroidManifest.xml file.
   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Follow these steps to integrate ffmpeg library in Android

Android version requirement

  • For versions 4.4 and 4.4.LTS, add mavenCentral() to your build.gradle and make sure that it is listed before jcenter()
  • For 4.3.2 and older releases, add jcenter()
repositories {
    mavenCentral()
}
  • Add MobileFFmpeg dependency to your build.gradle in mobile-ffmpeg-<package name> pattern
dependencies {
    implementation 'com.arthenica:mobile-ffmpeg-full:4.4'
}

Execute synchronous FFmpeg commands

import com.arthenica.mobileffmpeg.Config;
import com.arthenica.mobileffmpeg.FFmpeg;

int rc = FFmpeg.execute("-i file1.mp4 -c:v mpeg4 file2.mp4");

if (rc == RETURN_CODE_SUCCESS) {
    Log.i(Config.TAG, "Command execution completed successfully.");
} else if (rc == RETURN_CODE_CANCEL) {
    Log.i(Config.TAG, "Command execution cancelled by user.");
} else {
    Log.i(Config.TAG, String.format("Command execution failed with rc=%d and the output below.", rc));
    Config.printLastCommandOutput(Log.INFO);
}

Execute asynchronous FFmpeg commands

import com.arthenica.mobileffmpeg.Config;
import com.arthenica.mobileffmpeg.FFmpeg;

long executionId = FFmpeg.executeAsync("-i file1.mp4 -c:v mpeg4 file2.mp4", new ExecuteCallback() {

    @Override
    public void apply(final long executionId, final int returnCode) {
        if (returnCode == RETURN_CODE_SUCCESS) {
            Log.i(Config.TAG, "Async command execution completed successfully.");
        } else if (returnCode == RETURN_CODE_CANCEL) {
            Log.i(Config.TAG, "Async command execution cancelled by user.");
        } else {
            Log.i(Config.TAG, String.format("Async command execution failed with returnCode=%d.", returnCode));
        }
    }
});

Execute FFprobe commands

import com.arthenica.mobileffmpeg.Config;
import com.arthenica.mobileffmpeg.FFprobe;

int rc = FFprobe.execute("-i file1.mp4");

if (rc == RETURN_CODE_SUCCESS) {
    Log.i(Config.TAG, "Command execution completed successfully.");
} else {
    Log.i(Config.TAG, String.format("Command execution failed with rc=%d and the output below.", rc));
    Config.printLastCommandOutput(Log.INFO);
}

Check execution output later

int rc = Config.getLastReturnCode();

if (rc == RETURN_CODE_SUCCESS) {
    Log.i(Config.TAG, "Command execution completed successfully.");
} else if (rc == RETURN_CODE_CANCEL) {
    Log.i(Config.TAG, "Command execution cancelled by user.");
} else {
    Log.i(Config.TAG, String.format("Command execution failed with rc=%d and the output below.", rc));
    Config.printLastCommandOutput(Log.INFO);
}

Stop ongoing FFmpeg operations

  • Stop all executions
FFmpeg.cancel();
  • Stop a specific execution
FFmpeg.cancel(executionId);

Get media information for a file

MediaInformation info = FFprobe.getMediaInformation("<file path or uri>");

Record video using Android camera

FFmpeg.execute("-f android_camera -i 0:0 -r 30 -pixel_format bgr0 -t 00:00:05 <record file path>");

Enable log callback

Config.enableLogCallback(new LogCallback() {
    public void apply(LogMessage message) {
        Log.d(Config.TAG, message.getText());
    }
});

Enable statistics callback

Config.enableStatisticsCallback(new StatisticsCallback() {
    public void apply(Statistics newStatistics) {
        Log.d(Config.TAG, String.format("frame: %d, time: %d", newStatistics.getVideoFrameNumber(), newStatistics.getTime()));
    }
});

Ignore the handling of a signal

Config.ignoreSignal(Signal.SIGXCPU);

List ongoing executions

final List<FFmpegExecution> ffmpegExecutions = FFmpeg.listExecutions();
for (int i = 0; i < ffmpegExecutions.size(); i++) {
    FFmpegExecution execution = ffmpegExecutions.get(i);
    Log.d(TAG, String.format("Execution %d = id:%d, startTime:%s, command:%s.", i, execution.getExecutionId(), execution.getStartTime(), execution.getCommand()));
}

Set default log level

Config.setLogLevel(Level.AV_LOG_FATAL);

Register custom fonts directory

Config.setFontDirectory(this, "<folder with fonts>", Collections.EMPTY_MAP);

Conclusion: Integrating FFmpeg into your Android project provides powerful multimedia processing capabilities. In this guide, you have learned the steps to add FFmpeg as a dependency, execute basic FFmpeg commands, and handle output asynchronously. For more advanced usage and customization, refer to the FFmpeg documentation and explore additional features that can enhance your multimedia processing capabilities in Android applications.

Leave a Comment