J.Chou

说说Android的视频裁剪(三)

17 April 2017

有一段时间没有更新博客了。 最近有人在我的博客中跟我说mp4Parse不能裁剪mov视频,问我有没有其他的解决方案,所以这次我更新了一下自己的项目:Android-Video-Trimmer,使用ffmpeg来实现视频的裁剪。

FFmpeg是为大家所熟悉的处理视频的一个跨平台的开源库,支持android、ios。我们可以自己手动编译不同平台的lib库,从何集成到我们的项目中去。但是FFmpeg是一个C/C++的库,对于熟悉Java开发的Android同学来说,更希望是Java层面的调用。

在我的项目中,集成了一个FFmpegAndroid开发库,这个库优点是我们可以直接用Java的API来执行ffmpge的命令,缺点是该库比较大(大概19M),没办法对库做瘦身缩减工作。下面是我集成这个库的几个步骤。

1. 引入库的方式有两种:aar或者源码依赖

aar依赖:

dependencies {
    compile 'com.writingminds:FFmpegAndroid:0.3.2'
}

源码依赖: 用git将ffmpeg-android-java clone到本地,然后把项目中FFmpegAndroid库的源码加入到自己的项目中。 videoTrim

2.库的初始化

public class ZApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        initFFmpegBinary(this);
    }

    private void initFFmpegBinary(Context context) {

        try {
            FFmpeg.getInstance(context).loadBinary(new LoadBinaryResponseHandler() {
                @Override
                public void onFailure() {
                }
            });

        } catch (FFmpegNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

初始化的目的是根据Android手机的cpu架构,load对应架构的ffmpeg库。

3.执行ffmpeg的commend命令

上面的准备工作做完之后,剩下就是我们关心的问题了,如何执行ffmpeg命令行呢?在前面我已经说了,这个库是对ffmpeg的在Linux系统中命令行的一个封装,所以我们需要在该库中找到一个这样的API。 那我在FFmpegInterface.java类中找到了如下的PAI:

 /**
     * Executes a command
     * @param environvenmentVars Environment variables
     * @param cmd command to execute
     * @param ffmpegExecuteResponseHandler {@link FFmpegExecuteResponseHandler}
     * @throws FFmpegCommandAlreadyRunningException
     */
    public void execute(Map<String, String> environvenmentVars, String[] cmd, FFmpegExecuteResponseHandler ffmpegExecuteResponseHandler) throws FFmpegCommandAlreadyRunningException;
 /**
     * Executes a command
     * @param cmd command to execute
     * @param ffmpegExecuteResponseHandler {@link FFmpegExecuteResponseHandler}
     * @throws FFmpegCommandAlreadyRunningException
     */
    public void execute(String[] cmd, FFmpegExecuteResponseHandler ffmpegExecuteResponseHandler) throws FFmpegCommandAlreadyRunningException;

小伙伴们可以看到参数String[] cmd,就是我所说的控制台的命令行参数,只要将我们的命令行传入,设置好回调,剩下的事情就是静静等着ffmpeg触发我们的回调了,是不是感觉很爽! 下面是我的调用实现:

public static void trimVideo(Context context, String inputFile, String outputFile, long startMs, long endMs, final OnTrimVideoListener callback) {
       final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
       final String outputName = "trimmedVideo_" + timeStamp + ".mp4";

       String start = convertSecondsToTime(startMs/1000);
       String duration = convertSecondsToTime((endMs - startMs)/1000);

       /**ffmpeg -ss START -t DURATION -i INPUT -vcodec copy -acodec copy OUTPUT
        -ss 开始时间,如: 00:00:20,表示从20秒开始;
        -t 时长,如: 00:00:10,表示截取10秒长的视频;
        -i 输入,后面是空格,紧跟着就是输入视频文件;
        -vcodec copy 和 -acodec copy 表示所要使用的视频和音频的编码格式,这里指定为copy表示原样拷贝;
        INPUT,输入视频文件;
        OUTPUT,输出视频文件*/
       String cmd = "-ss " + start + " -t " + duration + " -i " + inputFile + " -vcodec copy -acodec copy " + outputFile + "/" + outputName;
       String[] command = cmd.split(" ");
       try {
           FFmpeg.getInstance(context).execute(command, new ExecuteBinaryResponseHandler() {
               @Override
               public void onFailure(String s) {
               }

               @Override
               public void onSuccess(String s) {
                   callback.onFinishTrim(null);
               }

               @Override
               public void onStart() {
                   callback.onStartTrim();
               }

               @Override
               public void onFinish() {
               }
           });
       } catch (FFmpegCommandAlreadyRunningException e) {
           // do nothing for now
       }
   }

上面主要是拼出ffmpeg视频裁剪的命令行参数。

FFmpeg命令大全

视频裁剪的命令如下: ffmpeg -ss START -t DURATION -i INPUT -vcodec copy -acodec copy OUTPUT 需要主意的是: DURATION 是表示视频的持续时间而不是结束时间 INPUT 表示输入的包含文件名的文件路径 e.g: sdcard/xxx/xx/input.mp4 OUTPUT 表示输出的包含文件名的文件路径 e.g: sdcard/xxx/xx/output.mov

其他命令也基本也差不多,需要实现什么功能之后可以去查询具体的命令行,对着实现就行。

Thanks for reading. To help others please click ❤ to recommend this article if you found it helpful.

You can also follow me at GitHub

— J.Chou