android采用FFmpeg实现音视频合成与分离
作者:徐福记456 时间:2022-03-05 09:18:16
上一篇文章谈到音频剪切、混音、拼接与转码,也详细介绍cMake配置与涉及FFmpeg文件的导入: android端采用FFmpeg进行音频混合与拼接剪切 。现在接着探讨音视频的合成与分离。
1、音频提取
从多媒体文件中提取音频,关键命令为“-acodec copy -vn”,其中“-acodec copy”是采用音频编码器拷贝音频流,“-vn”是去掉video视频流:
/**
* 使用ffmpeg命令行进行抽取音频
* @param srcFile 原文件
* @param targetFile 目标文件
* @return 抽取后的音频文件
*/
public static String[] extractAudio(String srcFile, String targetFile){
//-vn:video not
String mixAudioCmd = "ffmpeg -i %s -acodec copy -vn %s";
mixAudioCmd = String.format(mixAudioCmd, srcFile, targetFile);
return mixAudioCmd.split(" ");//以空格分割为字符串数组
}
2、视频提取
从多媒体文件中提取视频,关键命令为“-vcodec copy -an”,其中“-vcodec copy”是采用视频编码器拷贝视频流,“-an”是去掉audio音频流:
/**
* 使用ffmpeg命令行进行抽取视频
* @param srcFile 原文件
* @param targetFile 目标文件
* @return 抽取后的视频文件
*/
public static String[] extractVideo(String srcFile, String targetFile){
//-an audio not
String mixAudioCmd = "ffmpeg -i %s -vcodec copy -an %s";
mixAudioCmd = String.format(mixAudioCmd, srcFile, targetFile);
return mixAudioCmd.split(" ");//以空格分割为字符串数组
}
3、音视频合成
把音频和视频文件合成多媒体文件,关键命令是“-i %s -i %s -t”,分别代表输入音频、视频和文件时长。需要注意的是,如果原视频文件包含有音频,先把单独视频流抽取出来,然后再使用独立音频和视频进行合成:
/**
* 使用ffmpeg命令行进行音视频合成
* @param videoFile 视频文件
* @param audioFile 音频文件
* @param duration 视频时长
* @param muxFile 目标文件
* @return 合成后的文件
*/
@SuppressLint("DefaultLocale")
public static String[] mediaMux(String videoFile, String audioFile, int duration, String muxFile){
//-t:时长 如果忽略音视频时长,则把"-t %d"去掉
String mixAudioCmd = "ffmpeg -i %s -i %s -t %d %s";
mixAudioCmd = String.format(mixAudioCmd, videoFile, audioFile, duration, muxFile);
return mixAudioCmd.split(" ");//以空格分割为字符串数组
}
单独的视频提取出来后,进行音视频合成:
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 100){
String audioFile = PATH + File.separator + "tiger.mp3";//tiger.mp3
String muxFile = PATH + File.separator + "media-mux.mp4";
try {
//使用MediaPlayer获取视频时长
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(videoFile);
mediaPlayer.prepare();
//单位为ms
int videoDuration = mediaPlayer.getDuration()/1000;
Log.i(TAG, "videoDuration=" + videoDuration);
mediaPlayer.release();
//使用MediaMetadataRetriever获取音频时长
MediaMetadataRetriever mediaRetriever = new MediaMetadataRetriever();
mediaRetriever.setDataSource(audioFile);
//单位为ms
String duration = mediaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
int audioDuration = (int)(Long.parseLong(duration)/1000);
Log.i(TAG, "audioDuration=" + audioDuration);
mediaRetriever.release();
//如果视频时长比音频长,采用音频时长,否则用视频时长
int mDuration = Math.min(audioDuration, videoDuration);
//使用纯视频与音频进行合成
String[] commandLine = FFmpegUtil.mediaMux(temp, audioFile, mDuration, muxFile);
executeFFmpegCmd(commandLine);
isMux = false;
} catch (Exception e) {
e.printStackTrace();
}
}
}
拼接好FFmpeg命令后,调用native方法去执行:
/**
* 调用ffmpeg处理音视频
* @param handleType handleType
*/
private void doHandleMedia(int handleType){
String[] commandLine = null;
switch (handleType){
case 0://音视频合成
try {
//视频文件有音频,先把纯视频文件抽取出来
commandLine = FFmpegUtil.extractVideo(videoFile, temp);
isMux = true;
} catch (Exception e) {
e.printStackTrace();
}
break;
case 1://提取音频
String extractAudio = PATH + File.separator + "extractAudio.aac";
commandLine = FFmpegUtil.extractAudio(srcFile, extractAudio);
break;
case 2://提取视频
String extractVideo = PATH + File.separator + "extractVideo.mp4";
commandLine = FFmpegUtil.extractVideo(srcFile, extractVideo);
break;
default:
break;
}
executeFFmpegCmd(commandLine);
}
FFmpeg执行的回调:
/**
* 执行ffmpeg命令行
* @param commandLine commandLine
*/
private void executeFFmpegCmd(final String[] commandLine){
if(commandLine == null){
return;
}
FFmpegCmd.execute(commandLine, new FFmpegCmd.OnHandleListener() {
@Override
public void onBegin() {
Log.i(TAG, "handle media onBegin...");
}
@Override
public void onEnd(int result) {
Log.i(TAG, "handle media onEnd...");
if(isMux){
mHandler.obtainMessage(100).sendToTarget();
}else {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MediaHandleActivity.this, "handle media finish...", Toast.LENGTH_SHORT).show();
}
});
}
}
});
}
来源:https://blog.csdn.net/u011686167/article/details/79146373
标签:android,FFmpeg,音视频
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
Android Handler,Message,MessageQueue,Loper源码解析详解
2022-04-17 17:34:57
![](https://img.aspxhome.com/file/2023/7/103867_0s.png)
MyBatis数据脱敏的实现方案介绍
2021-10-06 19:22:34
![](https://img.aspxhome.com/file/2023/2/68742_0s.png)
Mybatis 开发注解快速入门
2021-12-01 16:03:36
![](https://img.aspxhome.com/file/2023/8/128838_0s.png)
C#实现图形区域组合操作的方法
2023-05-01 19:08:21
C#编程获取资源文件中图片的方法
2023-05-23 06:13:39
Android Service详解及示例代码
2021-12-24 05:44:17
![](https://img.aspxhome.com/file/2023/7/88667_0s.jpg)
5步学会使用VideoView播放视频
2023-09-12 05:51:07
C#服务端图片打包下载实现代码解析
2023-01-26 07:36:23
Java split函数拆分后变成null问题解决方案
2022-05-24 17:00:36
![](https://img.aspxhome.com/file/2023/6/129166_0s.png)
java实现简单快递系统
2021-11-28 07:01:57
![](https://img.aspxhome.com/file/2023/8/69698_0s.jpg)
详解SpringMVC中的异常处理
2022-10-22 07:05:14
详解备忘录模式及其在Java设计模式编程中的实现
2023-08-24 22:34:02
![](https://img.aspxhome.com/file/2023/6/58436_0s.jpg)
Java实战之实现用户登录
2022-08-03 14:42:55
![](https://img.aspxhome.com/file/2023/0/69110_0s.png)
Android App开发中使用RecyclerView替代ListView的实践
2021-06-14 06:53:36
![](https://img.aspxhome.com/file/2023/2/109222_0s.jpg)
通过C#程序操作Config文件
2023-11-30 14:24:06
Java基础之多线程
2022-11-30 11:01:43
Android 实现定时器的四种方式总结及实现实例
2023-04-20 15:22:04
java面向对象之人机猜拳小游戏
2021-12-20 18:12:34
![](https://img.aspxhome.com/file/2023/9/67189_0s.png)
详解Spring Boot Profiles 配置和使用
2021-10-05 22:54:57
Java CPU性能分析工具代码实例
2023-09-28 04:52:54