一、ffmpeg mp3 多音频拼接 merge(注意是拼接不是融合)
- 先上shell命令
#多音频merge拼接
#拼接后的音频之间会有极短的等待时间。
1) Save a list of the MP3 files to concatenate, e.g.,
$ cat mylist.txt
file '/tmp/01.mp3'
file '/tmp/02.mp3'
file '/tmp/03.mp3'
file '/tmp/04.mp3'
file '/tmp/05.mp3'
file '/tmp/06.mp3'
file '/tmp/07.mp3'
2) Run the following command (-safe 0 is not required if mylist.txt uses relative paths instead):
$ ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp3
2.实际业务脚本
#实现功能:扫描指定的文件路径下所有的.mp3文件,然后根据扫描结果进行MP3融合(在扫描的时候要先确认好文件排序规则)。
#!/bin/bash
train_file=filelist.txt
cur_dir=$(cd `dirname $1`; pwd)
date_name=$(date +%Y%m%d%H%M%S)
out_file="merge_"$date_name".mp3"
#删除
for j in `find $cur_dir -name "merge_*.mp3"`
do
rm -rf $j
done
#filelist.txt 中的数据是这样的:
#file '/test.******.com/cms/live/kWRty0jN1561772072044/10_20190629_100246.mp3'
#file '/test.******.com/cms/live/kWRty0jN1561772072044/11_20190629_100246.mp3'
#file '/test.******.com/cms/live/kWRty0jN1561772072044/12_20190629_100246.mp3'
#file '/test.******.com/cms/live/kWRty0jN1561772072044/1_20190629_100246.mp3'
#file '/test.******.com/cms/live/kWRty0jN1561772072044/2_20190629_100246.mp3'
#file '/test.******.com/cms/live/kWRty0jN1561772072044/3_20190629_100246.mp3'
for i in `find $cur_dir -name "*.mp3" | sort -n -k 6 -t /`
do
echo "file '$i'"
done > $1$train_file
chown groupname:groupname ${1}${train_file}
/usr/local/bin/ffmpeg -f concat -safe 0 -i $1$train_file -c copy ${1}${out_file} > /dev/null 2>&1
ffmpeg_pid=$!
while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1
rm -rf $1$train_file
if [ -f "${1}$out_file" ]; then
chown groupname:groupname ${1}${out_file}
echo ${1#*:}${out_file}
else
echo -e "Fail"&&exit
fi
exit
运行方式如下
sh /home/*****/merge_mp3.sh /test.****.com/cms/live/kWRty0jN1561772072044/
二、java调用merge_mp3.sh脚本
这里没有改动sudo的配置文件将用户的密码取消,因此java执行程序中需指定用户密码。
package com.*****.common.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
/** * linux命令行执行器 * @author guyadong * */
public class CmdExecutorUtil {
private static final Logger logger = Logger.getLogger(CmdExecutorUtil.class.getSimpleName());
private static final String SUDO_CMD = "sudo -S";
private static final String SHELL_NAME = "/bin/bash";
private static final String SHELL_PARAM = "-c";
private static final String REDIRECT = "2>&1";
/** 执行 sudo 的密码 */
private final String sudoPassword;
/** 是否显示命令内容及输出 */
private boolean verbose=true;
/** 是否错误输出重定向 */
private boolean errRedirect = true;
/** 是否同步,主线程是否等待命令执行结束 */
private boolean sync = true;
/** 执行多条命令时的命令分隔符 */
private String cmdSeparator = " && ";
private List<String> cmds = new ArrayList<String>(16);
public static CmdExecutorUtil builder(){
return new CmdExecutorUtil();
}
public static CmdExecutorUtil builder(String sudoPasword){
return new CmdExecutorUtil(sudoPasword);
}
protected CmdExecutorUtil(){
this(null);
}
protected CmdExecutorUtil(String sudoPasword){
this.sudoPassword = sudoPasword;
}
public CmdExecutorUtil verbose(boolean verbose){
this.verbose = verbose;
return this;
}
public CmdExecutorUtil errRedirect(boolean errRedirect){
this.errRedirect = errRedirect;
return this;
}
public CmdExecutorUtil sync(boolean sync){
this.sync = sync;
return this;
}
public CmdExecutorUtil cmdSeparator(String cmdSeparator){
if(null != cmdSeparator && !cmdSeparator.isEmpty()){
this.cmdSeparator = cmdSeparator;
}
return this;
}
private String getRedirect(){
return errRedirect ? REDIRECT : "";
}
/** * 添加一条需要sudo执行的命令 * @param cmd 要执行的命令(字符串中不需要有sudo) * @return */
public CmdExecutorUtil sudoCmd(String cmd){
if(null != cmd && 0 != cmd.length()){
if(null == sudoPassword){
cmds.add(String.format("%s %s %s",SUDO_CMD,cmd,getRedirect()));
}else{
cmds.add(String.format("echo '%s' | %s %s %s",sudoPassword,SUDO_CMD,cmd,getRedirect()));
}
}
return this;
}
/** * 添加一条普通命令 * @param cmd * @return */
public CmdExecutorUtil cmd(String cmd){
if(null != cmd && 0 != cmd.length()){
cmds.add(String.format("%s %s",cmd,getRedirect()));
}
return this;
}
private List<String> build(){
return cmds.isEmpty()
? Collections.<String>emptyList()
: Arrays.asList(SHELL_NAME,SHELL_PARAM,join(cmds,cmdSeparator));
}
private static String join(List<String> strs,String separator) {
StringBuffer buffer = new StringBuffer();
for(int i=0;i<strs.size();++i){
if(i>0){
buffer.append(separator);
}
buffer.append(strs.get(i));
}
return buffer.toString();
}
/** * 将{@link InputStream}中所有内容输出到{@link StringBuffer} * @param in * @return * @throws IOException */
private static void toBuffer(InputStream in,StringBuffer buffer) throws IOException{
if(null == in || null == buffer){
return ;
}
InputStreamReader ir = new InputStreamReader(in);
LineNumberReader input = new LineNumberReader(ir);
try{
String line;
while ((line = input.readLine()) != null) {
buffer.append(line).append("\n");
}
}finally{
input.close();
}
}
/** * 调用{@link Runtime#exec(String[])}执行命令 * @return 返回输出结果 */
public String exec() throws IOException{
StringBuffer outBuffer = new StringBuffer();
exec(outBuffer,null);
return outBuffer.toString();
}
/** * 调用{@link Runtime#exec(String[])}执行命令 * @param outBuffer 标准输出 * @param errBuffer 错误信息输出 * @throws IOException */
public void exec(StringBuffer outBuffer,StringBuffer errBuffer) throws IOException{
List<String> cmdlist = build();
if(!cmdlist.isEmpty()){
if(verbose){
logger.info(join(cmdlist," "));
}
Process process = Runtime.getRuntime().exec(cmdlist.toArray(new String[cmdlist.size()]));
if(sync){
try {
process.waitFor();
} catch (InterruptedException e) {
}
}
toBuffer(process.getInputStream(),outBuffer);
toBuffer(process.getErrorStream(),errBuffer);
}
}
public static void main(String[] args) {
try {
String out = CmdExecutorUtil.builder("password")
.errRedirect(true)
.sudoCmd("sh /home/*****/merge_mp3.sh /test.****.com/cms/live/kWRty0jN1561772072044/")
// .sudoCmd("/usr/local/bin/ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp3")
.exec();
System.out.println(out);
} catch (Exception e) {
e.printStackTrace();
}
}
}
这里有一点需要注意下,启用tomcat 的用户 和 merge_mp3.sh 中
chown usergroup:usergroup $1${out_file}
的usergroup 用户要一致,否则可能出现这种情况:文件在服务端已经成功成功生成,但是进行静态资源访问时(nginx/tomcat)提示资源不存在或访问不到。
ffmpeg环境的安装可以参考我的上一篇文章:
https://www.jianshu.com/p/cc2d95485514
参考资料:
1.How to join/merge many mp3 files
https://superuser.com/questions/314239/how-to-join-merge-many-mp3-files
2.java:执行linux sudo命令
网友评论