Android编程实现外置存储音频裁剪及FFmpeg执行失败问题求解
Android端音频裁剪实现分步指南
现有代码错误排查
你当前执行失败的核心原因如下:
- FFmpeg命令参数冗余错误:你裁剪的是纯音频文件,不需要指定
-vcodec mpeg4视频编码参数,添加后会导致FFmpeg识别不到视频流直接返回错误 - 音频参数配置错误:你填写的
-b:a 48000比特率数值不符合常规MP3编码标准,且和后续-ar 22050采样率参数逻辑冲突 - 存储权限适配问题:Android 10及以上版本
Environment.getExternalStorageDirectory()已被官方废弃,直接读写该路径会被系统权限拦截 - 入参未校验:你代码中
original_path = path的path变量没有做空值、文件存在性校验,路径无效时必然执行失败
完整实现步骤
1. 前置配置
- 首先在模块级
build.gradle引入FFmpeg依赖:
dependencies { implementation 'com.arthenica:mobile-ffmpeg-full:4.4.LTS' }
- 在
AndroidManifest.xml配置权限,适配不同系统版本:
<!-- Android 12及以下存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13及以上音频读取权限 --> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <application ... android:requestLegacyExternalStorage="true"> </application>
注意:所有危险权限需要在代码中动态申请,仅静态声明无效
2. 修正后的业务代码
private void trimMusic(long startMs, long endMs, String fileName) { // 使用应用专属音乐目录,无需额外存储权限即可读写 File folder = new File(requireContext().getExternalFilesDir(Environment.DIRECTORY_MUSIC), "MusicEditor"); if (!folder.exists()) { folder.mkdirs(); } String fileExt = ".mp3"; File destFile = new File(folder, fileName + fileExt); // 注意此处提前校验原始音频路径是否有效、文件是否存在 String originalPath = path; if (TextUtils.isEmpty(originalPath) || !new File(originalPath).exists()) { Toast.makeText(getActivity(), "原始音频文件不存在", Toast.LENGTH_SHORT).show(); return; } // 修正后的纯音频裁剪FFmpeg命令 String[] command = new String[]{ "-ss", String.valueOf(startMs / 1000), "-y", "-i", originalPath, "-t", String.valueOf((endMs - startMs) / 1000), "-acodec", "libmp3lame", "-b:a", "128k", "-ac", "2", "-ar", "44100", destFile.getAbsolutePath() }; execffmpegBinary(command); } private void execffmpegBinary(final String[] command) { // 注册日志回调,失败时可直接查看Logcat定位错误原因 Config.enableLogCallback(message -> Log.e("FFmpeg_LOG", message.getText())); Log.d("FFmpeg_CMD", "执行命令:ffmpeg " + Arrays.toString(command)); FFmpeg.executeAsync(command, (executionId, returnCode) -> { if (returnCode == RETURN_CODE_SUCCESS) { dialog.dismiss(); Toast.makeText(getActivity(), "音频裁剪成功", Toast.LENGTH_LONG).show(); } else if (returnCode == RETURN_CODE_CANCEL) { Log.d("FFmpeg_STATUS", "裁剪任务已取消"); } else { Toast.makeText(getActivity(), "音频裁剪失败,请查看日志排查原因", Toast.LENGTH_LONG).show(); } }); }
3. 调用方式
裁剪歌曲第2分钟到第3分钟的片段,直接调用即可:
// 时间单位为毫秒,2分钟对应120000ms,3分钟对应180000ms trimMusic(120000, 180000, "裁剪后的歌曲名称");
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

