Created
December 8, 2020 08:35
-
-
Save dinesh1301/970848682572882427633d35dc3c188a to your computer and use it in GitHub Desktop.
Using FFMpeg to perform video operations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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/sizehttps://stackoverflow.com/questions/39486636/ffmpeg-library-is-too-slow-to-compress-the-video-file-android/39489724