解决方案:Android 11环境下视频分割和合并问题
背景信息
在Android 11及更高版本中,系统对于文件操作的安全性要求提高了。特别是对外部存储(如/storage/emulated/0
)进行了更严格的权限控制,普通应用不再被允许直接访问并写入这些位置的文件夹和子目录,除非是在特定的应用私有容器内进行的操作。
问题描述
在使用FFmpeg对视频进行分割时,用户遇到了一个错误提示:“Operation not permitted”。具体情况如下:
segment @ 0xb400007727c28800] Failed to open segment
/storage/emulated/0/Movies/splitVideoFolder/split_video000.mp4
Could not write header for output file #0 (incorrect codec parameters ?): Operation not permitted
问题原因分析
- 文件路径访问限制:由于Android 11的权限升级,普通第三方应用不能自由地操作所有外部存储设备。
/storage/emulated/0/Movies/splitVideoFolder
如果该目录不存在或权限不够(尽管错误信息是“Operation not permitted”),会导致写入操作失败。 - 路径不正确:目标文件夹可能并未被创建,或是应用程序尚未获得足够的权限去读取和写入此特定的外部存储位置。
解决方案
- 检查文件路径:
- 确保用户提供的路径是合法且存在的。建议使用Android文件选择器如
StorageAccessFramework
(推荐API 29)进行文件处理,它可以辅助打开应用私有的files
、cache
或可写入的external
存储位置。
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, REQUEST_CODE_TREE_picker);
- 请求恰当权限:
-
通过
<uses-permissions>
声明必要的文件读写权限。例如,需要申请READ_EXTERNAL_STORAGE
和WRITE_EXTERNAL_STORAGE
权限。 -
使用运行时权限检查:在动态运行时(API水平支持)中获取读写外部存储的权限。
-
创建目录并检查路径正确性:
java
File dir = new File(Environment.getExternalStorageDirectory(), "/Movies/splitVideoFolder");
if (!dir.exists()) {
boolean success = dir.mkdirs();
// If created successfully, then continue operations.
} else {
Log.d("MyApp", "The directory already exists. Proceeding.");
} -
使用ContentProvider或Storage Access Framework(SAF)替代:上述错误提示也可以通过使用ContentProvider或者借助Android系统提供的一系列选择性文件写入方式如
DocumentFile.createDirectory
来避开。
示例代码建议
示例代码展示了如何适配API 29及以上版本的Storage Access Framework来操作外部存储:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, REQUEST_CODE_TREE_PICKER);
// In onActivityResult:
DocumentFile root = DocumentFile.fromTreeUri(this, uri);
if (root != null) {
Log.d("MyApp", "Selected Root Directory: "+ root.getName());
// Now create desired sub-directory within this
DocumentFile directory = root.createDirectory("/Movies/splitVideoFolder");
if (directory != null) {
Log.d("MyApp", "Created folder at path:" + directory.getUri().getPath());
// Proceed video processing here with proper permissions.
} else {
Log.e("MyApp", "Could not create the desired directory for video operations");
}
}
通过上述方法,您可以有效地解决在Android 11及其他版本设备上因操作外部存储路径不正确或权限不足导致的问题。