Skip to content

Instantly share code, notes, and snippets.

@dinesh1301
Created December 8, 2020 08:35
Show Gist options
  • Save dinesh1301/970848682572882427633d35dc3c188a to your computer and use it in GitHub Desktop.
Save dinesh1301/970848682572882427633d35dc3c188a to your computer and use it in GitHub Desktop.
Using FFMpeg to perform video operations
import android.content.Context
import android.os.Environment
import com.arthenica.mobileffmpeg.Config.RETURN_CODE_SUCCESS
import com.arthenica.mobileffmpeg.FFmpeg
import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.Single
import timber.log.Timber
import java.io.File
class FFMpegVideoTools(val context: Context) {
fun compressVideo(url: String): Observable<String> {
val outputFile = getOutputFilePath("compressed", "mp4")
val command = if (url.getExtension() != "mp4") {
"-i $url -preset ultrafast $outputFile"
} else {
"-i $url -vcodec libx265 -crf 28 -c copy $outputFile"
}
return executeCommand(command).andThen(Observable.just(outputFile))
}
fun concatVideos(first: String, second: String): Single<String> {
val outputFile = getOutputFilePath("merged", "mp4")
val command =
"-i $first -i $second -filter_complex \"[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[outv][outa]\" -map \"[outv]\" -map \"[outa]\" -vsync vfr -y $outputFile"
return executeCommand(command).andThen(Single.just(outputFile))
}
private fun executeCommand(command: String): Completable {
val startTime = System.currentTimeMillis()
Timber.tag("FFmpegDebug").d("Executing command: $command")
return Completable.create { emitter ->
FFmpeg.executeAsync(command) { _, returnCode ->
Timber.tag("FFmpegDebug").d("Time taken: ${System.currentTimeMillis() - startTime}")
if (returnCode == RETURN_CODE_SUCCESS)
emitter.onComplete()
else
emitter.onError(Throwable("Failed with code: $returnCode"))
}
}
}
private fun getOutputFilePath(prefix: String, suffix: String): String {
val dir = File(getDownloadDir(context))
dir.mkdirs()
return "${dir.absolutePath}/$prefix-${System.currentTimeMillis()}.$suffix"
}
fun extractThumbNail(videoFile: String): Single<String> {
val outputFile = getOutputFilePath("thumb", "png")
val command = "-i $videoFile -vframes 1 -y $outputFile "
return executeCommand(command).andThen(Single.just(outputFile))
}
fun cancelAllOperations() {
FFmpeg.cancel()
}
private fun getDownloadDir(context: Context): String {
return context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)!!.absolutePath
}
}
fun String.getExtension(): String {
return this.substring(this.indexOfLast { it == '.' } + 1)
}
@dinesh1301
Copy link
Author

use this in your gradle
implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.4'
If you are using RxJava then this code can be used as it is, otherwise some tweaks may be required.

This will compress the videos in ultrafast mode, which might not reduce the size as much. It can be changed through managing some flags, have a look at this answer. You need to play with different flags to optimise the speed/quality/size
https://stackoverflow.com/questions/39486636/ffmpeg-library-is-too-slow-to-compress-the-video-file-android/39489724

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment