美文网首页工作生活编程开发
java 调用 ffmpeg shell 进行mp3 文件拼接

java 调用 ffmpeg shell 进行mp3 文件拼接

作者: 升职哦 | 来源:发表于2019-06-30 13:50 被阅读72次

一、ffmpeg mp3 多音频拼接 merge(注意是拼接不是融合)

  1. 先上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环境的安装可以参考我的上一篇文章:

ffmpeg pcm 转mp3及linux下的环境搭建

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命令

https://blog.csdn.net/10km/article/details/78913746jianshu

相关文章

网友评论

    本文标题:java 调用 ffmpeg shell 进行mp3 文件拼接

    本文链接:https://www.haomeiwen.com/subject/znqbcctx.html