如何在 Android 31 中通过 ffmpeg 操作文件:权限被拒绝

How to manipulate files by ffmpeg in Android 31: permission denied

我正在尝试在我的 android 应用程序中使用 FFmpeg。所以我想在继续之前测试它是否有效。我使用外部库:github link
代码如下所示:

package net.omidn.aslanmediaconverter;

import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.arthenica.ffmpegkit.ExecuteCallback;
import com.arthenica.ffmpegkit.FFmpegKit;
import com.arthenica.ffmpegkit.FFmpegSession;
import com.arthenica.ffmpegkit.Session;

import net.bramp.ffmpeg.job.FFmpegJob;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;


public class MainActivity extends AppCompatActivity {
    
    private static final String TAG = "MainActivity";
    FFmpegJob myjob;

    @Override
    protected void onCreate(Bundle savedInstanceState) {


        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView textView = (TextView) findViewById(R.id.text_view);


        FFmpegJob job = null;

        File inFile = new File("/storage/emulated/0/video_2021-05-29_17-50-20.mp4");
        String inputName = Uri.fromFile(inFile).toString();
        Log.d(TAG, inputName);
        Log.d(TAG,"file exists : " + String.valueOf(inFile.exists()));
        Log.d(TAG,"file canRead : " + String.valueOf(inFile.canRead()));

        FFmpegSession fFmpegSession = FFmpegKit.executeAsync("-i file:///storage/emulated/0/video_2021-05-29_17-50-20.mp4 -c:v mpeg4 file:///storage/emulated/0/out.mp4",
                new ExecuteCallback() {
                    @Override
                    public void apply(Session session) {

                    }
                });
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        textView.setText("" + fFmpegSession.getState().name() + "    " + fFmpegSession.getOutput());
    }

}

如您所见,我使用 file:/// 协议提供文件。如果我不使用它,结果是一样的。 Log.d(...) 的三行将打印:

2021-06-03 00:58:08.869 8376-8376/net.omidn.aslanmediaconverter D/MainActivity: file:///storage/emulated/0/video_2021-05-29_17-50-20.mp4
2021-06-03 00:58:08.869 8376-8376/net.omidn.aslanmediaconverter D/MainActivity: file exists : true
2021-06-03 00:58:08.869 8376-8376/net.omidn.aslanmediaconverter D/MainActivity: file canRead : false

视频文件对存储具有读取权限:

我从 the libraries wiki 页面找到了执行此操作的方法。

这里引用一下:

如果要将使用存储访问框架 (SAF) 选择的文件与 FFmpegKit 一起使用,可以使用以下方法将 Uri 转换为使用 [=12] 定义的文件路径=] 的 saf: 协议。该路径可以安全地用作 FFmpegKitFFprobeKit 命令中的输入或输出。

输入

Uri uri = intent.getData();
String inputPath = FFmpegKitConfig.getSafParameterForRead(requireContext(), uri);
FFmpegKit.execute("-i " + inputPath + " ... output.mp4");

输出

Uri uri = intent.getData();
String outputPath = FFmpegKitConfig.getSafParameterForWrite(requireContext(), uri);
FFmpegKit.execute("-i input.mp4 ... " + outputPath);

The wiki page on GitHub