I'm trying to convert series of images into video. For that I'm adding FFmpeg into my Android project. However it is not adding properly, so I can't import class FFmpeg into the code. in the statement "int rc = FFmpeg.execute(command);" FFmpeg is highlighted in red.
I think something wrong with libraries. Could you please give suggestion how import libraries correctly?
My Manifest file below
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.TimelapseLite"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
My settings.gradle file
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
} rootProject.name = "TimelapseLite" include ':app'
My build.gradle file
plugins {
id 'com.android.application'
}
android {
namespace 'ae.vpdev.timelapselite'
compileSdk 33
defaultConfig {
applicationId "ae.vpdev.timelapselite"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.arthenica:mobile-ffmpeg-full:4.5.LTS'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
My code in MainActivity
private void convertImagesToVideo() {
StringBuilder imageListFileContent = new StringBuilder();
for (Uri imageUri : selectedImages) {
imageListFileContent.append("file '").append(imageUri.getPath()).append("'\n");
}
try {
File imageListFile = new File(getCacheDir(), "image_list.txt");
FileWriter writer = new FileWriter(imageListFile);
writer.append(imageListFileContent.toString());
writer.flush();
writer.close();
File outputFile = new File(getExternalFilesDir(null), "output_video.mp4");
String outputFilePath = outputFile.getAbsolutePath();
String command = "-f concat -safe 0 -i " + imageListFile.getAbsolutePath() +
" -vf \"scale=-2:720\" -r 30 -c:v libx264 -pix_fmt yuv420p " + outputFilePath;
int rc = FFmpeg.execute(command);
if (rc == RETURN_CODE_SUCCESS) {
Log.d("FFmpeg", "Video conversion completed successfully");
// Now you can use the outputFilePath to play or share the video
} else {
Log.d("FFmpeg", "Video conversion failed");
}
} catch (IOException e) {
e.printStackTrace();
}
}
I personally would not prefer to add the full FFMPEG SDK, as it increases the app size exponentially, however using Arthenica's FFMPEG-KIT seems the easiest way to get FFMPEG into a project
implementation "com.arthenica:ffmpeg-kit-min-gpl:5.1.LTS"
This new FFMPEG-KIT not only has a reduction in size, but the commands also execute quicker and have better async support and much easier implementation.
To use you just have to import
import com.arthenica.ffmpegkit.FFmpegKit
import com.arthenica.ffmpegkit.ReturnCode
and then :
FFmpegKit.executeAsync(cmdString , {
when {
ReturnCode.isSuccess(it.returnCode) -> {
println("FFMPEG SUCCESS :${it.state.name}")
}
ReturnCode.isCancel(it.returnCode) -> {
println("FFMPEG CANCELLED :${it.returnCode}")
}
it.returnCode.isValueError -> {
println("FFMPEG ERROR :${it.logs.last()}")
}
}
} , {
println("FFMEPG LOG :${it.message}")
} , {
println("FFMEPG STATS :${it.speed}")
})
here cmdString
, is a string of commands, your commands should work but the only issue I ran into was that I had to use -y -i
instead of -f
which seemed to run the commands.