FFmpeg 基础知识

第一、FFmpeg 简介和基础知识

1.1 FFmpeg 简介

FFmpeg的名称来自MPEG视频编码标准,前面的“FF”代表“Fast Forward”,FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。可以轻易地实现多种视频格式之间的相互转换。包括如下几个部分:

  • libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能,包含demuxers和muxer库。
  • libavcodec:用于各种类型声音/图像编解码。
  • libavutil:包含一些公共的工具函数。
  • libswscale:用于视频场景比例缩放、色彩映射转换。
  • libpostproc:用于后期效果处理。
  • ffmpeg:是一个命令行工具,用来对视频文件转换格式,也支持对电视卡实时编码。
  • ffsever:是一个HTTP多媒体实时广播流服务器,支持时光平移。
  • ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示。
  • ffprobe:收集多媒体文件或流的信息,并以人和机器可读的方式输出。

1.2 FFmpeg 基础知识

容器(Container):一种文件格式,比如flv,mkv等。
流(Stream):一种视频数据信息的传输方式,5种流:音频,视频,字幕,附件,数据。
帧(Frame):帧代表一幅静止的图像,分为I帧,P帧,B帧。
编解码器(Codec):是对视频进行压缩或者解压缩,CODEC = COde(编码) +DECode(解码)。
复用/解复用(mux/demux):把不同的流按照某种容器的规则放入容器,这种行为叫做复用(mux)。
                       把不同的流从某种容器中解析出来,这种行为叫做解复用(demux)。
帧率:帧率也叫帧频率,帧率是视频文件中每一秒的帧数,肉眼想看到连续移动图像至少需要15帧。
码率:比特率(也叫码率,数据率)是一个确定整体视频/音频质量的参数,秒为单位处理的字节数,码率和视频质量成正比,在视频文件中中比特率用bps来表达。

第二、FFmpeg 命令行工具使用指南

2.1 什么是FFmpeg 

FFmpeg (命令行工具) 是一个快速的音视频转换工具。

2.2 FFmpeg 使用方法

FFmpeg 语法格式: 

ffmpeg {1} {2} -i {3} {4} {5}

上面命令中,五个部分的参数依次如下。

  1. 全局参数
  2. 输入文件参数
  3. 输入文件
  4. 输出文件参数
  5. 输出文件

示例:将 mp4 文件转成 webm 文件,这两个都是容器格式。输入的 mp4 文件的音频编码格式是 aac,视频编码格式是 H.264;输出的 webm 文件的视频编码格式是 VP9,音频格式是 Vorbis

ffmpeg \
-y \ # 全局参数
-c:a libfdk_aac -c:v libx264 \ # 输入文件参数
-i input.mp4 \ # 输入文件
-c:v libvpx-vp9 -c:a libvorbis \ # 输出文件参数
output.webm # 输出文件

2.3 FFmpeg 常用命令行参数

-c:指定编码器
-c copy:直接复制,不经过重新编码(这样比较快)
-c:v:指定视频编码器
-c:a:指定音频编码器
-i:指定输入文件
-an:去除音频流
-vn: 去除视频流
-preset:指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow。
-y:不经过确认,输出时直接覆盖同名文件。

2.4 FFmpeg 常见用法

2.4.1 查看文件信息:

查看视频文件的元信息,比如编码格式和比特率,可以只使用-i参数。

ffmpeg -i input.mp4

上面命令会输出很多冗余信息,加上-hide_banner参数,可以只显示元信息。

ffmpeg -i input.mp4 -hide_banner

2.4.2 转换编码格式

转换编码格式(transcoding)指的是, 将视频文件从一种编码转成另一种编码。比如转成 H.264 编码,一般使用编码器libx264,所以只需指定输出文件的视频编码器即可。

ffmpeg -i [input.file] -c:v libx264 output.mp4

转成 H.265 编码的写法。

ffmpeg -i [input.file] -c:v libx265 output.mp4

2.4.3 转换容器格式

转换容器格式(transmuxing)指的是,将视频文件从一种容器转到另一种容器。下面是 mp4 转 webm 的写法。

ffmpeg -i input.mp4 -c copy output.webm

注意:上面例子中,只是转一下容器,内部的编码格式不变,所以使用-c copy指定直接拷贝,不经过转码,这样比较快。

2.4.4 调整码率

调整码率(transrating)指的是,改变编码的比特率,一般用来将视频文件的体积变小。下面的例子指定码率最小为964K,最大为3856K,缓冲区大小为 2000K。

ffmpeg \
-i input.mp4 \
-minrate 964K -maxrate 3856K -bufsize 2000K \
output.mp4

2.4.5 改变分辨率(transsizing)

下面是改变视频分辨率(transsizing)的例子,从 1080p 转为 480p 。

ffmpeg \
-i input.mp4 \
-vf scale=480:-1 \
output.mp4

2.4.6 提取音频

有时,需要从视频里面提取音频(demuxing),可以像下面这样写。

ffmpeg \
-i input.mp4 \
-vn -c:a copy \
output.aac

上面例子中,-vn表示去掉视频,-c:a copy表示不改变音频编码,直接拷贝。

2.4.7 添加音轨

添加音轨(muxing)指的是,将外部音频加入视频,比如添加背景音乐或旁白。

ffmpeg \
-i input.aac -i input.mp4 \
output.mp4

上面例子中,有音频和视频两个输入文件,FFmpeg 会将它们合成为一个文件。

2.4.8 截图

下面的例子是从指定时间开始,连续对1秒钟的视频进行截图。

ffmpeg \
-y \
-i input.mp4 \
-ss 00:01:24 -t 00:00:01 \
output_%3d.jpg

如果只需要截一张图,可以指定只截取一帧。

ffmpeg \
-ss 01:23:45 \
-i input \
-vframes 1 -q:v 2 \
output.jpg

上面例子中,-vframes 1指定只截取一帧,-q:v 2表示输出的图片质量,一般是1到5之间(1 为质量最高)。

2.4.9 裁剪

裁剪(cutting)指的是,截取原始视频里面的一个片段,输出为一个新视频。可以指定开始时间(start)和持续时间(duration),也可以指定结束时间(end)。

$ ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
$ ffmpeg -ss [start] -i [input] -to [end] -c copy [output]

下面是实际的例子。

ffmpeg -ss 00:01:50 -i [input] -t 10.5 -c copy [output]
ffmpeg -ss 2.5 -i [input] -to 10 -c copy [output]

上面例子中,-c copy表示不改变音频和视频的编码格式,直接拷贝,这样会快很多。

2.5.0 为音频添加封面

有些视频网站只允许上传视频文件。如果要上传音频文件,必须为音频添加封面,将其转为视频,然后上传。

下面命令可以将音频文件,转为带封面的视频文件。

ffmpeg \
-loop 1 \
-i cover.jpg -i input.mp3 \
-c:v libx264 -c:a aac -b:a 192k -shortest \
output.mp4

上面命令中,有两个输入文件,一个是封面图片cover.jpg,另一个是音频文件input.mp3-loop 1参数表示图片无限循环,-shortest参数表示音频文件结束,输出视频就结束。

 

第三、FFplay 命令行工具使用指南

3.1 什么是FFplay

FFplay 是一个使用了 ffmpeg 和 sdl 库的简单的可移植的媒体播放器。

3.2 FFplay 使用方法

FFplay 语法格式:

ffplay [选项] ['输入文件']

 FFplay使用示例:

1、播放 test.mkv ,播放完成后自动退出

ffplay -autoexit test.mkv

2、以 320 × 240 的大学播放 test.mkv

ffplay -x 320 -y 240 test.mkv

3.3 FFplay 选项类别

3.3.1 FFplay 通用选项

'-L'    显示 license
'-h, -?, -help, --help [arg]' 打印帮助信息;可以指定一个参数 arg ,如果不指定,只打印基本选项
    可选的 arg 选项:
    'long'    除基本选项外,还将打印高级选项
    'full'    打印一个完整的选项列表,包含 encoders, decoders, demuxers, muxers, filters 等的共享以及私有选项
    'decoder=decoder_name'    打印名称为 "decoder_name" 的解码器的详细信息
    'encoder=encoder_name'    打印名称为 "encoder_name" 的编码器的详细信息
    'demuxer=demuxer_name'    打印名称为 "demuxer_name" 的 demuxer 的详细信息
    'muxer=muxer_name'        打印名称为 "muxer_name" 的 muxer 的详细信息
    'filter=filter_name'      打印名称为 "filter_name" 的过滤器的详细信息
	
'-version'     显示版本信息
'-formats'     显示有效的格式
'-codecs'      显示 libavcodec 已知的所有编解码器
'-decoders'    显示有效的解码器
'-encoders'    显示有效的编码器
'-bsfs'        显示有效的比特流过滤器
'-protocols'   显示有效的协议
'-filters'     显示 libavfilter 有效的过滤器
'-pix_fmts'    显示有效的像素格式 
'-sample_fmts' 显示有效的采样格式
'-layouts'     显示通道名称以及标准通道布局
'-colors'      显示认可的颜色名称
'-hide_banner' 禁止打印欢迎语;也就是禁止默认会显示的版权信息、编译选项以及库版本信息等

3.3.2 FFplay 主要选项

'-x width'        强制以 "width" 宽度显示
'-y height'       强制以 "height" 高度显示
'-an'	          禁止音频
'-vn'             禁止视频
'-ss pos'         跳转到指定的位置(秒)
'-t duration'     播放 "duration" 秒音/视频
'-bytes'          按字节跳转
'-nodisp'         禁止图像显示(只输出音频)
'-f fmt'          强制使用 "fmt" 格式
'-window_title title'  设置窗口标题(默认为输入文件名)
'-loop number'    循环播放 "number" 次(0将一直循环)
'-showmode mode'  设置显示模式
    可选的 mode :
    '0, video'    显示视频
    '1, waves'    显示音频波形
    '2, rdft'     显示音频频带
    默认值为 'video',你可以在播放进行时,按 "w" 键在这几种模式间切换

'-i input_file'   指定输入文件

3.3.3 FFplay 高级选项

'-sync type'          设置主时钟为音频、视频、或者外部。默认为音频。主时钟用来进行音视频同步
'-threads count'      设置线程个数
'-autoexit'           播放完成后自动退出
'-exitonkeydown'      任意键按下时退出
'-exitonmousedown'    任意鼠标按键按下时退出
'-acodec codec_name'  强制指定音频解码器为 "codec_name"
'-vcodec codec_name'  强制指定视频解码器为 "codec_name"
'-scodec codec_name'  强制指定字幕解码器为 "codec_name"

3.3.4 FFplay 快捷键

'q, ESC'            退出
'f'                 全屏
'p, SPC'            暂停
'w'                 切换显示模式(视频/音频波形/音频频带)
's'                 步进到下一帧
'left/right'        快退/快进 10 秒
'down/up'           快退/快进 1 分钟
'page down/page up' 跳转到前一章/下一章(如果没有章节,快退/快进 10 分钟)
'mouse click'       跳转到鼠标点击的位置(根据鼠标在显示窗口点击的位置计算百分比)
参考资料

第四、FFprobe 命令行工具使用指南

4.1 什么是FFprobe

​ffprobe 是一个多媒体流分析工具。它从多媒体流中收集信息,并且以人类和机器可读的形式打印出来。它可以用来检测多媒体流的容器类型,以及每一个多媒体流的格式和类型。它可以作为一个独立的应用来使用,也可以结合文本过滤器执行更复杂的处理。

4.2 FFprobe 使用方法

FFprobe 语法格式:

ffprobe [选项] ['输入文件']

 FFprobe 使用示例:

  • 最简单的使用方式

    ffprobe test.mp4  
  • 不显示欢迎信息

    ffprobe -hide_banner test.mp4  
  • 以 JSON 格式显示每个流的信息

    ffprobe -hide_banner -print_format json -show_streams test.mp4  
  • 显示容器格式相关信息

    ffprobe -hide_banner -show_format test.mp4

4.3 FFprobe选项

‘-f format’    强制使用的格式  
‘-unit’        显示值的单位  
‘-prefix’      显示的值使用标准国际单位制词头  
‘-byte_binary_prefix’ 对字节值强制使用二进制前缀  
‘-sexagesimal’ 时间值使用六十进位的格式 HH:MM:SS.MICROSECONDS  
‘-pretty’      美化显示值的格式。它相当于 "-unit -prefix -byte_binary_prefix -sexagesimal"  
‘-of, -print_format writer_name[=writer_options]’   
              设置输出打印格式。writer_name 指定打印程序 (writer) 的名称,writer_options   
              指定传递给 writer 的选项。例如:将输出打印为 JSON 格式:-print_format json   
‘-select_streams stream_specifier’   
              只选择 stream_specifier 指定的流。该选项只影响那些与流相关的选项  
              (例如:show_streams, show_packets, 等)。  
              举例:只显示音频流,使用命令:  
                ffprobe -show_streams -select_streams a INPUT  
‘-show_data’ 显示有效载荷数据,以十六进制和ASCII转储。与 ‘-show_packets’ 结合使用,它将   
              dump 包数据;与 ‘-show_streams’ 结合使用,它将 dump codec 附加数据。  
‘-show_error’    显示探测输入文件时的错误信息  
‘-show_format’   显示输入多媒体流的容器格式信息  
‘-show_packets’  显示输入多媒体流中每一个包的信息  
‘-show_frames’   显示输入多媒体流中的每一帧以及字幕的信息  
‘-show_streams’  显示输入多媒体流中每一个流的信息  
‘-show_programs’ 显示输入多媒体流中程序以及它们的流的信息  
‘-show_chapters’ 显示格式中存储的章节信息  
‘-count_frames’  计算每一个流中的帧数,在相应的段中进行显示  
‘-count_packets’ 计算每一个流中的包数,在相应的段中进行显示  
‘-show_program_version’   显示程序版本及配置相关信息  
‘-show_library_versions’  显示库版本相关信息  
‘-show_versions’          显示程序和库版本相关信息。相当于同时设置‘-show_program_version’ 和   
                          ‘-show_library_versions’  
‘-i input_file’           指定输入文件  

第五、FFmpeg 之Java功能代码封装

package com.zzg.ffmpeg;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import com.zzg.ffmpeg.config.FfmpegConfig;
import com.zzg.ffmpeg.config.params.FfmpegParam;
import com.zzg.ffmpeg.config.params.FfmpegParams;
import com.zzg.ffmpeg.exception.FfmpegTransformException;
import com.zzg.ffmpeg.media.Media;
import com.zzg.ffmpeg.media.MediaType;


/**
 * ffmpeg 核心功能代码
 * 
 * @author zzg
 *
 */
public class Ffmpeg {

    private final FfmpegConfig ffmpegConfig;

    private final List medias;

    private final FfmpegParams params;

    private List successValues = new ArrayList(Arrays.asList(0));
    
    /**
     * Timeout to wait while generating a PDF, in seconds
     */
    private int timeout = 10;
    
    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public Ffmpeg() {
        this(new FfmpegConfig());
    }

    public Ffmpeg(FfmpegConfig ffmpegConfig) {
        super();
        this.ffmpegConfig = ffmpegConfig;
        this.medias = new ArrayList();
        this.params = new FfmpegParams();
    }

    /**
     * 输入文件
     * 
     * @param source
     */
    public void addMediaInput(String source) {
        this.medias.add(new Media(source, MediaType.input));
    }

    /**
     * 输出文件
     * 
     * @param source
     */
    public void addMediaOutput(String source) {
        this.medias.add(new Media(source, MediaType.output));
    }

    /**
     * ffmpeg 请求参数
     * 
     * @param param
     * @param params
     */
    public void addParam(FfmpegParam param, FfmpegParam... params) {
        this.params.add(param, params);
    }

    public byte[] getFFMPEG() throws IOException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        try {
            // cmd 执行命令
            String command = getCommand();
            System.out.println("输出指令:" + command);
            Process process = Runtime.getRuntime().exec(getCommandAsArray());

            Future inputStreamToByteArray = executor.submit(streamToByteArrayTask(process.getInputStream()));
            Future outputStreamToByteArray = executor.submit(streamToByteArrayTask(process.getErrorStream()));

            process.waitFor();

            if (!successValues.contains(process.exitValue())) {
                byte[] errorStream = getFuture(outputStreamToByteArray);

                throw new FfmpegTransformException(command, process.exitValue(), errorStream,
                        getFuture(inputStreamToByteArray));
            }
            return getFuture(inputStreamToByteArray);
        } finally {
            executor.shutdownNow();
        }

    }

    private Callable streamToByteArrayTask(final InputStream input) {
        return new Callable() {
            public byte[] call() throws Exception {
                return IOUtils.toByteArray(input);
            }
        };
    }

    private byte[] getFuture(Future future) {
        try {
            return future.get(this.timeout, TimeUnit.SECONDS);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Gets the final ffmpeg command as string
     * 
     * @return the generated command from params
     * @throws IOException
     */
    public String getCommand() throws IOException {
        return StringUtils.join(getCommandAsArray(), " ");
    }

    protected String[] getCommandAsArray() throws IOException {
        List commandLine = new ArrayList();
        // 指令部分ffmpeg
        commandLine.add(ffmpegConfig.getFfmpegCommand());

        commandLine.add("-i");

        // 输入文件
        for (Media media : medias) {
            if (media.getType().equals(MediaType.input)) {
                commandLine.add(media.getSource());
            }
        }

        // 参数部分
        commandLine.addAll(params.getParamsAsStringList());

        // 输出文件
        for (Media media : medias) {
            if (media.getType().equals(MediaType.output)) {
                commandLine.add(media.getSource());
            }
        }
        return commandLine.toArray(new String[commandLine.size()]);
    }

}


package com.zzg.ffmpeg.config;

import java.io.IOException;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
import com.zzg.ffmpeg.exception.FfmpegConfigurationException;

/**
 * ffmpeg 配置对象
 * 
 * @author zzg
 *
 */
public class FfmpegConfig {
    private String ffmpegCommand = "ffmpeg";

    public String getFfmpegCommand() {
        return ffmpegCommand;
    }

    public void setFfmpegCommand(String ffmpegCommand) {
        this.ffmpegCommand = ffmpegCommand;
    }

    public FfmpegConfig() {
        setFfmpegCommand(findExecutable());
    }

    public FfmpegConfig(String ffmpegCommand) {
        super();
        this.ffmpegCommand = ffmpegCommand;
    }

    public String findExecutable() {
        try {
            String osname = System.getProperty("os.name").toLowerCase();
            String cmd = osname.contains("windows") ? "where.exe ffmpeg" : "which ffmpeg";

            Process p = Runtime.getRuntime().exec(cmd);

            p.waitFor();

            String text = IOUtils.toString(p.getInputStream(), Charset.defaultCharset()).trim();
            
            if (text.isEmpty()){
                throw new FfmpegConfigurationException("ffmpeg command was not found in your classpath. " +
                        "Verify its installation or initialize wrapper configurations with correct path/to/ffmpeg");
            }
            setFfmpegCommand(text);
                
        } catch (IOException e) {
            // log日志记录错误信息, 暂时打印堆栈信息
            e.printStackTrace();
        } catch (InterruptedException e) {
            // log日志记录错误信息, 暂时打印堆栈信息
            e.printStackTrace();
        }
        return getFfmpegCommand();
    }

}
package com.zzg.ffmpeg.config.params;

import java.util.ArrayList;
import java.util.List;

/**
 * ffmpeg 请求参数实体对象封住
 * 
 * @author zzg
 *
 */
public class FfmpegParam {

    private String key;

    // 某些指令接受多个参数值
    private List values = new ArrayList();

    public FfmpegParam(String key, String... valueArray) {
        this.key = key;
        for (String value : valueArray) {
            values.add(value);
        }
    }

    // 某些指令无参数值
    public FfmpegParam(String key) {
        this(key, new String[0]);
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public List getValues() {
        return values;
    }

    public void setValues(List values) {
        this.values = values;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder().append(FfmpegSymbol.separator).append(FfmpegSymbol.param).append(key);
        for (String value : values) {
            sb.append(FfmpegSymbol.separator).append(value);
        }
        return sb.toString();
    }

}
package com.zzg.ffmpeg.config.params;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * 批量处理FfmpegParam 请求参数对象
 * @author zzg
 *
 */
public class FfmpegParams {
    private Collection params;

    public FfmpegParams() {
        this.params = new ArrayList();
    }

    public void add(FfmpegParam param, FfmpegParam... params) {
        this.params.add(param);
        this.params.addAll( Arrays.asList( params ) );
    }
    
    public List getParamsAsStringList() {
        List commandLine = new ArrayList();

        for (FfmpegParam p : params) {
            commandLine.add(p.getKey());

            for (String value : p.getValues()) {
                if (value != null) {
                    commandLine.add(value);
                }
            }
        }

        return commandLine;
    }
}
package com.zzg.ffmpeg.config.params;
/**
 * ffmpeg 符号
 * @author zzg
 *
 */
public enum FfmpegSymbol {
    separator(" "), param("");
    
    private final String symbol;

    FfmpegSymbol(String symbol) {
        this.symbol = symbol;
    }

    @Override
    public String toString() {
        return symbol;
    }

}


package com.zzg.ffmpeg.exception;

@SuppressWarnings("serial")
public class FfmpegConfigurationException extends RuntimeException {

    public FfmpegConfigurationException(String message) {
        super(message);
        // TODO Auto-generated constructor stub
    }
    
}
package com.zzg.ffmpeg.exception;

/**
 * ffmpeg 转换异常
 * 
 * @author zzg
 *
 */
@SuppressWarnings("serial")
public class FfmpegTransformException extends RuntimeException {
    private String command;

    private int exitStatus;

    private byte[] out;

    private byte[] err;

    public FfmpegTransformException(String command, int exitStatus, byte[] err, byte[] out) {
        this.command = command;
        this.exitStatus = exitStatus;
        this.err = err;
        this.out = out;
    }

    public String getCommand() {
        return command;
    }

    public int getExitStatus() {
        return exitStatus;
    }

    public byte[] getOut() {
        return out;
    }

    public byte[] getErr() {
        return err;
    }

    @Override
    public String getMessage() {
        return "Process (" + this.command + ") exited with status code " + this.exitStatus + ":\n" + new String(err);
    }
}
package com.zzg.ffmpeg.exception;

/**
 * ffmpeg 转换异常
 * 
 * @author zzg
 *
 */
@SuppressWarnings("serial")
public class FfmpegTransformException extends RuntimeException {
    private String command;

    private int exitStatus;

    private byte[] out;

    private byte[] err;

    public FfmpegTransformException(String command, int exitStatus, byte[] err, byte[] out) {
        this.command = command;
        this.exitStatus = exitStatus;
        this.err = err;
        this.out = out;
    }

    public String getCommand() {
        return command;
    }

    public int getExitStatus() {
        return exitStatus;
    }

    public byte[] getOut() {
        return out;
    }

    public byte[] getErr() {
        return err;
    }

    @Override
    public String getMessage() {
        return "Process (" + this.command + ") exited with status code " + this.exitStatus + ":\n" + new String(err);
    }
}
package com.zzg.ffmpeg.media;
/**
 * 媒体文件:输入输出类型
 * @author zzg
 *
 */
public enum MediaType {
    input,
    output
}
package com.zzg.test;

import java.io.IOException;

import com.zzg.ffmpeg.Ffmpeg;
import com.zzg.ffmpeg.config.params.FfmpegParam;

public class FfmpegTest {

    public static void main(String[] args) throws IOException, InterruptedException {
        // TODO Auto-generated method stub
        Ffmpeg ffmpeg = new Ffmpeg();
        ffmpeg.addMediaInput("C:\\ffmpg\\ffmpeg\\bin\\output.mp4");
        ffmpeg.addMediaOutput("C:\\ffmpg\\ffmpeg\\bin\\test.mp4");
        ffmpeg.addParam(new FfmpegParam("-vcodec", new String[]{"copy"}), new FfmpegParam[]{new FfmpegParam("-an", new String[]{})});
        byte[] bytes = ffmpeg.getFFMPEG();
        System.out.println(new String(bytes));
        
    }

}


pom.xml 文件相关依赖:

 
      2.6
      3.9
  
  
      
          
        
            commons-io
            commons-io
            ${commons-io.version}
        
        
            org.apache.commons
            commons-lang3
            ${commons-lang3.version}
        
      

 

你可能感兴趣的:(Java架构专栏)