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。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。