简体   繁体   中英

FFMPEG Commands is not working on Android 10

I am working on an android app applying video effects like slow and fast motions. My app is working fine below android 10, but not on android 10 and FFMPEG is not showing any error just blank error message on the onFailure callback method.

I did some research and find out that android has introduced scoped permissions and you can temporarily bypass this by adding this line on manifest android:requestLegacyExternalStorage="true" and you get the storage permission. After adding this line rest portation of app is just working fine fetching user videos and etc but FFMPEG is not working.

If anyone has an idea or clue about this issue please help me out.

here is a working version for compatible devices min API 16 onwards. Support android API 29 (Q)

dependencies {
    implementation 'com.arthenica:mobile-ffmpeg-full:4.4.LTS'
}

Long Term Support packages for MobileFFmpeg v4.4

Supports the following device specifications

Android

Android 4.1 (API level 16) or later

x86 and x86-64 architecturesarm-v7a, arm-v7a-neon, arm64-v8a,

You can find more information on the official repo on github

Update: 20 June 2021

Not maintained anymore as explained in What's next for MobileFFmpeg?

Now is Superseded by FFmpegKit

Here you can find FFmpegKit For Android

Features

  • Supports API Level 24+ on Main releases and API Level 16+ on LTS releases
  • Includes arm-v7a, arm-v7a-neon, arm64-v8a, x86 and x86_64 architectures
  • Can handle Storage Access Framework (SAF) Uris
  • Camera access on supported devices
  • Builds shared native libraries (.so)
  • Creates Android archive with .aar extension

Try this

dependencies {

implementation 'com.arthenica:mobile-ffmpeg-full:4.4.LTS'

}

Also see this..ffmpeg-video-editor-android

Use this library which supports targetSdkVersion 29.

implementation 'com.arthenica:mobile-ffmpeg-video:4.4'

Command used for video compression:

val complexCommand = arrayOf( "-y", "-i", inputPath!!, "-s", "640x480", "-r", "25", "-vcodec", "mpeg4", "-b:v", "1000k", "-b:a", "48000", "-ac", "2", "-ar", "22050", outputFilePath )

Compression method:

  private fun execFFmpegBinary(command: Array<String>, inputPath: String?, listener: CompressionListener?, outputFilePath: String) {
    Config.enableLogCallback { message -> Log.e(Config.TAG, message.text) }
    Config.enableStatisticsCallback { newStatistics ->
        Log.e(
            Config.TAG,
            String.format(
                "frame: %d, time: %d",
                newStatistics.videoFrameNumber,
                newStatistics.time
            )
        )
        Log.d(
            TAG,
            "Started command : ffmpeg " + Arrays.toString(command)
        )
        
        val videoLength = inputPath?.let { VideoUtils.getVideoDuration(it) }
        Log.d(TAG, "execFFmpegBinary: Video Length : $videoLength")
        val progress: Float =
            java.lang.String.valueOf(newStatistics.time).toFloat() / videoLength!!
        val progressFinal = progress * 100
        Log.d(TAG, "Video Length: $progressFinal")
        Log.d(
            Config.TAG,
            java.lang.String.format(
                "frame: %d, time: %d",
                newStatistics.videoFrameNumber,
                newStatistics.time
            )
        )
        Log.d(
            Config.TAG,
            java.lang.String.format(
                "Quality: %f, time: %f",
                newStatistics.videoQuality,
                newStatistics.videoFps
            )
        )
        //progressDialog.setProgress(progressFinal.toInt())
        //val adjustProgress = progressFinal/1.5f
        Log.d(TAG, "execFFmpegBinary: Progress: ${progressFinal.toInt()}")
        listener?.onProgress(progressFinal.toInt())
        Log.d(TAG, "progress : $newStatistics")
    }
    Log.d(
        TAG,
        "Started command : ffmpeg " + Arrays.toString(command)
    )
   /* progressDialog.setMessage("Processing...")
    progressDialog.show()*/
    val executionId = com.arthenica.mobileffmpeg.FFmpeg.executeAsync(
        command
    ) { executionId1: Long, returnCode: Int ->
        if (returnCode == RETURN_CODE_SUCCESS) {
            Log.d(
                TAG,
                "Finished command : ffmpeg " + Arrays.toString(command)
            )

            listener?.compressionFinished(SUCCESS, true, fileOutputPath = outputFilePath)
        } else if (returnCode == Config.RETURN_CODE_CANCEL) {
            Log.e(
                TAG,
                "Async command execution cancelled by user."
            )
            listener?.onFailure(String.format(
                "Async command execution cancelled by user."
            ))
            //if (progressDialog != null) progressDialog.dismiss()
        } else {
            Log.e(
                TAG,
                String.format(
                    "Async command execution failed with returnCode=%d.",
                    returnCode
                )
            )
            listener?.onFailure(String.format(
                "Async command execution failed with returnCode=%d.",
                returnCode
            ))
           // if (progressDialog != null) progressDialog.dismiss()
        }
    }
    Log.e(TAG, "execFFmpegMergeVideo executionId-$executionId")
}

Compression Listener:

 interface CompressionListener {
    fun compressionFinished(
        status: Int,
        isVideo: Boolean,
        fileOutputPath: String?
    )

    fun onFailure(message: String?)
    fun onProgress(progress: Int)
}

Call using:

execFFmpegBinary(complexCommand, inputPath, listener, outputFilePath)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM