android采用FFmpeg实现音视频合成与分离
上一篇文章谈到音频剪切、混音、拼接与转码,也详细介绍cMake配置与涉及FFmpeg文件的导入:android端采用FFmpeg进行音频混合与拼接剪切 。现在接着探讨音视频的合成与分离。
1、音频提取
从多媒体文件中提取音频,关键命令为“-acodeccopy-vn”,其中“-acodeccopy”是采用音频编码器拷贝音频流,“-vn”是去掉video视频流:
/**
*使用ffmpeg命令行进行抽取音频
*@paramsrcFile原文件
*@paramtargetFile目标文件
*@return抽取后的音频文件
*/
publicstaticString[]extractAudio(StringsrcFile,StringtargetFile){
//-vn:videonot
StringmixAudioCmd="ffmpeg-i%s-acodeccopy-vn%s";
mixAudioCmd=String.format(mixAudioCmd,srcFile,targetFile);
returnmixAudioCmd.split("");//以空格分割为字符串数组
}
2、视频提取
从多媒体文件中提取视频,关键命令为“-vcodeccopy-an”,其中“-vcodeccopy”是采用视频编码器拷贝视频流,“-an”是去掉audio音频流:
/**
*使用ffmpeg命令行进行抽取视频
*@paramsrcFile原文件
*@paramtargetFile目标文件
*@return抽取后的视频文件
*/
publicstaticString[]extractVideo(StringsrcFile,StringtargetFile){
//-anaudionot
StringmixAudioCmd="ffmpeg-i%s-vcodeccopy-an%s";
mixAudioCmd=String.format(mixAudioCmd,srcFile,targetFile);
returnmixAudioCmd.split("");//以空格分割为字符串数组
}
3、音视频合成
把音频和视频文件合成多媒体文件,关键命令是“-i%s-i%s-t”,分别代表输入音频、视频和文件时长。需要注意的是,如果原视频文件包含有音频,先把单独视频流抽取出来,然后再使用独立音频和视频进行合成:
/**
*使用ffmpeg命令行进行音视频合成
*@paramvideoFile视频文件
*@paramaudioFile音频文件
*@paramduration视频时长
*@parammuxFile目标文件
*@return合成后的文件
*/
@SuppressLint("DefaultLocale")
publicstaticString[]mediaMux(StringvideoFile,StringaudioFile,intduration,StringmuxFile){
//-t:时长如果忽略音视频时长,则把"-t%d"去掉
StringmixAudioCmd="ffmpeg-i%s-i%s-t%d%s";
mixAudioCmd=String.format(mixAudioCmd,videoFile,audioFile,duration,muxFile);
returnmixAudioCmd.split("");//以空格分割为字符串数组
}
单独的视频提取出来后,进行音视频合成:
publicvoidhandleMessage(Messagemsg){
super.handleMessage(msg);
if(msg.what==100){
StringaudioFile=PATH+File.separator+"tiger.mp3";//tiger.mp3
StringmuxFile=PATH+File.separator+"media-mux.mp4";
try{
//使用MediaPlayer获取视频时长
MediaPlayermediaPlayer=newMediaPlayer();
mediaPlayer.setDataSource(videoFile);
mediaPlayer.prepare();
//单位为ms
intvideoDuration=mediaPlayer.getDuration()/1000;
Log.i(TAG,"videoDuration="+videoDuration);
mediaPlayer.release();
//使用MediaMetadataRetriever获取音频时长
MediaMetadataRetrievermediaRetriever=newMediaMetadataRetriever();
mediaRetriever.setDataSource(audioFile);
//单位为ms
Stringduration=mediaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
intaudioDuration=(int)(Long.parseLong(duration)/1000);
Log.i(TAG,"audioDuration="+audioDuration);
mediaRetriever.release();
//如果视频时长比音频长,采用音频时长,否则用视频时长
intmDuration=Math.min(audioDuration,videoDuration);
//使用纯视频与音频进行合成
String[]commandLine=FFmpegUtil.mediaMux(temp,audioFile,mDuration,muxFile);
executeFFmpegCmd(commandLine);
isMux=false;
}catch(Exceptione){
e.printStackTrace();
}
}
}
拼接好FFmpeg命令后,调用native方法去执行:
/**
*调用ffmpeg处理音视频
*@paramhandleTypehandleType
*/
privatevoiddoHandleMedia(inthandleType){
String[]commandLine=null;
switch(handleType){
case0://音视频合成
try{
//视频文件有音频,先把纯视频文件抽取出来
commandLine=FFmpegUtil.extractVideo(videoFile,temp);
isMux=true;
}catch(Exceptione){
e.printStackTrace();
}
break;
case1://提取音频
StringextractAudio=PATH+File.separator+"extractAudio.aac";
commandLine=FFmpegUtil.extractAudio(srcFile,extractAudio);
break;
case2://提取视频
StringextractVideo=PATH+File.separator+"extractVideo.mp4";
commandLine=FFmpegUtil.extractVideo(srcFile,extractVideo);
break;
default:
break;
}
executeFFmpegCmd(commandLine);
}
FFmpeg执行的回调:
/**
*执行ffmpeg命令行
*@paramcommandLinecommandLine
*/
privatevoidexecuteFFmpegCmd(finalString[]commandLine){
if(commandLine==null){
return;
}
FFmpegCmd.execute(commandLine,newFFmpegCmd.OnHandleListener(){
@Override
publicvoidonBegin(){
Log.i(TAG,"handlemediaonBegin...");
}
@Override
publicvoidonEnd(intresult){
Log.i(TAG,"handlemediaonEnd...");
if(isMux){
mHandler.obtainMessage(100).sendToTarget();
}else{
runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
Toast.makeText(MediaHandleActivity.this,"handlemediafinish...",Toast.LENGTH_SHORT).show();
}
});
}
}
});
}
好了,使用FFmpeg进行音视频合成与分离介绍完毕。如果各位有什么问题或者建议,欢迎交流。
源码:链接地址。如果对您有帮助,麻烦fork和star。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。