FFMPEG 命令不适用于 Android 10

Posted

技术标签:

【中文标题】FFMPEG 命令不适用于 Android 10【英文标题】:FFMPEG Commands is not working on Android 10 【发布时间】:2020-04-30 03:04:15 【问题描述】:

我正在开发一款应用视频效果(如慢动作和快动作)的 android 应用。我的应用在 android 10 下运行良好,但在 android 10 上运行良好,FFMPEG 没有显示任何错误,只是在 onFailure 回调方法上显示空白错误消息。

我做了一些研究,发现 android 引入了范围权限,您可以通过在清单 android:requestLegacyExternalStorage="true" 上添加此行来暂时绕过它,您将获得存储权限。 添加此行后,应用程序的其余端口可以正常获取用户视频等,但 FFMPEG 无法正常工作。

如果有人对此问题有任何想法或线索,请帮助我。

【问题讨论】:

也许FFmpeg doesn't work on android 10, goes strait to onFailure(String message) with empty message 会有所帮助。 实际上是说FFmpeg正在主目录上执行,android 10删除了应用主目录的执行权限。到目前为止,它看起来像一个死胡同。 ***.com/a/59686838/8416317 感谢您的链接,这些库回调以不同的方式工作,但我会尝试一下 我也有同样的问题。 【参考方案1】:

这是适用于 API 16 及以上兼容设备的工作版本。支持android API 29(Q)

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

MobileFFmpeg v4.4 的长期支持包

支持以下设备规格

安卓

Android 4.1(API 级别 16)或更高版本

x86 和 x86-64 架构sarm-v7a、arm-v7a-neon、arm64-v8a、

您可以在official repo on github找到更多信息

更新:2021 年 6 月 20 日

不再维护,如What’s next for MobileFFmpeg?中所述

现在被FFmpegKit取代

在这里你可以找到FFmpegKit For Android

特点

在主要版本上支持 API 级别 24+,在 LTS 上支持 API 级别 16+ 发布 包括 arm-v7a、arm-v7a-neon、arm64-v8a、x86 和 x86_64 架构 可以处理存储访问框架 (SAF) Uris 支持设备上的相机访问权限 构建共享本机库 (.so) 创建带有 .aar 扩展名的 Android 存档

【讨论】:

在 Manifest 中为 min API 24 编写的库 @MortezaKhodaie 请查看文档了解 LTS 版本 LTS Releases【参考方案2】:

试试这个

依赖

实施 'com.arthenica:mobile-ffmpeg-full:4.4.LTS'

也看到这个.. ffmpeg-video-editor-android

【讨论】:

在 Manifest 中为 min API 24 编写的库 此库将 apk 大小增加到 64 MB 以上。【参考方案3】:

使用这个支持 targetSdkVersion 29 的库。

实现'com.arthenica:mobile-ffmpeg-video:4.4'

用于视频压缩的命令:

val complexCommand = arrayOf( “-y”, “-一世”, 输入路径!!, “-s”, "640x480", "-r", "25", “-vcodec”, "mpeg4", "-b:v", "1000k", "-b:a", "48000", “-ac”, "2", “-ar”, "22050", 输出文件路径 )

压缩方式:

  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")

压缩监听器:

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

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

调用方式:

execFFmpegBinary(complexCommand, inputPath, listener, outputFilePath)

【讨论】:

此库将 apk 大小增加到 64 MB 以上。 您可以在 build.gradle 中使用这样的拆分 apk 来减小大小。检查这个:developer.android.com/studio/build/configure-apk-splits.html 它会降低视频质量。你检查了吗? 你可以使用我开发的这个库。为了保持视频质量,我们需要根据视频分辨率计算 crf。查看回购。 github.com/cvivek07/FFmpegVideoCompressor

以上是关于FFMPEG 命令不适用于 Android 10的主要内容,如果未能解决你的问题,请参考以下文章

视频压缩不适用于 ffmpeg4android_lib 库

ffmpeg 不适用于包含空格的文件名

ffmpeg hls_time选项不适用于h264_nvenc

buildozer 构建 apk 但不适用于 android

Cordova 插件 Geolocation 不适用于 Android 版本 Kitkat

语音识别不适用于 Android 5.1.1 Xamarin