RxFFmpeg

ios 剪辑框架 剪辑视频框架_ide

简介: 🔥RxFFmpeg 是基于 ( FFmpeg 4.0 + X264 + mp3lame + fdk-aac ) 编译的适用于 Android 平台的音视频编辑、视频剪辑的快速处理框架,包含以下功能(视频拼接,转码,压缩,裁剪,片头片尾,分离音视频,变速,添加静态贴纸和 gif 动态贴纸,添加字幕,添加滤镜,添加背景音乐,加速减速视频,倒放音视频,音频裁剪,变声,混音,图片合成视频,视频解码图片等主流特色功能

编译环节

编译环境

  • win10 + ubuntu 16.04 + gcc + make

主要依赖以下库进行编译

库名

版本

下载地址

FFmpeg

4.0

http://ffmpeg.org/releases/ffmpeg-4.0.tar.bz2

X264

x264-snapshot-20180212-2245-stable

http://download.videolan.org/x264/snapshots/x264-snapshot-20180212-2245-stable.tar.bz2

mp3lame

3.100

https://jaist.dl.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz

fdk-aac

0.1.6

https://jaist.dl.sourceforge.net/project/opencore-amr/fdk-aac/fdk-aac-0.1.6.tar.gz

ndk

android-ndk-r14b-linux-x86_64

https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip

编译脚本

  • 编译脚本

特色功能

  • 支持任何 FFmpeg 命令执行
  • 支持 FFmpeg 命令执行进度回调
  • 支持中断 FFmpeg 命令
  • 支持同步/异步执行
  • 支持开启/关闭 debug 模式
  • 支持硬件加速,使编解码处理更快(已开启 MediaCodec)
  • 代码封装成 SDK 的方式,方便依赖使用
  • 支持把 FFmpeg 的各子模块 libavutil libavcodec libavformat libavdevice libavfilter libswscale libswresample libpostproc 最终打包成一个 librxffmpeg-core.so 核心库方便依赖使用,无需导入七八个 so 库
  • 支持 libx264 编码库,可以使压缩后的视频体积变的极小,清晰度还保持着很高清,简单的压缩命令: ffmpeg -y -i /storage/emulated/0/1/input.mp4 -b 2097k -r 30 -vcodec libx264 -preset superfast /storage/emulated/0/1/result.mp4
  • 支持添加 mp3、aac、wav 等主流格式的背景音乐
  • 支持主流视频格式转换,如: avi > mp4 > avi
  • 每隔一秒截取一张图 ffmpeg -y -i /storage/emulated/0/1/input.mp4 -f image2 -r 1 -q:v 10 -preset superfast /storage/emulated/0/1/%3d.jpg

使用方式

Gradle

在根目录下的 build.gradle 里添加 maven 仓库

allprojects {
        repositories {
            ...
            maven { url 'https://www.jitpack.io' }
        }
    }

添加依赖,最新版本

dependencies {
    implementation 'com.github.microshow:RxFFmpeg:2.4.0'
}

如果你的 App 只要 v7a 平台,可以只保留 armeabi-v7a,不过推荐加上 arm64-v8a 架构,这样性能会大大提升

 

defaultConfig {
    .
    .
    .
    ndk {
        abiFilters "armeabi-v7a","arm64-v8a"
    }
}

开始

  • 开启/关闭 debug 模式,建议在 Application 初始化调用
RxFFmpegInvoke.getInstance().setDebug(true);
  • FFmpeg 命令执行 (RxJava2 优雅的调用)
private void runFFmpegRxJava() {

        String text = "ffmpeg -y -i /storage/emulated/0/1/input.mp4 -vf boxblur=25:5 -preset superfast /storage/emulated/0/1/result.mp4";

        String[] commands = text.split(" ");

        myRxFFmpegSubscriber = new MyRxFFmpegSubscriber(this);

        //开始执行 FFmpeg 命令
        RxFFmpegInvoke.getInstance()
                .runCommandRxJava(commands)
                .subscribe(myRxFFmpegSubscriber);

    }

    public static class MyRxFFmpegSubscriber extends RxFFmpegSubscriber {

        private WeakReference<HomeFragment> mWeakReference;

        public MyRxFFmpegSubscriber(HomeFragment homeFragment) {
            mWeakReference = new WeakReference<>(homeFragment);
        }

        @Override
        public void onFinish() {
            final HomeFragment mHomeFragment = mWeakReference.get();
            if (mHomeFragment != null) {
                mHomeFragment.cancelProgressDialog("处理成功");
            }
        }

        @Override
        public void onProgress(int progress, long progressTime) {
            final HomeFragment mHomeFragment = mWeakReference.get();
            if (mHomeFragment != null) {
                //progressTime 可以在结合视频总时长去计算合适的进度值
                mHomeFragment.setProgressDialog(progress, progressTime);
            }
        }

        @Override
        public void onCancel() {
            final HomeFragment mHomeFragment = mWeakReference.get();
            if (mHomeFragment != null) {
                mHomeFragment.cancelProgressDialog("已取消");
            }
        }

        @Override
        public void onError(String message) {
            final HomeFragment mHomeFragment = mWeakReference.get();
            if (mHomeFragment != null) {
                mHomeFragment.cancelProgressDialog("出错了 onError:" + message);
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (myRxFFmpegSubscriber != null) {
            myRxFFmpegSubscriber.dispose();
        }
    }
  • FFmpeg 命令执行 (同步方式)
RxFFmpegInvoke.getInstance().runCommand(command, null);
  • 中断 FFmpeg 命令
RxFFmpegInvoke.getInstance().exit();
  • 构建命令,使用 RxFFmpegCommandList 构建,可以有效避免路径带有空格等问题
public static String[] getBoxblur() {
        RxFFmpegCommandList cmdlist = new RxFFmpegCommandList();
        cmdlist.append("-i");
        cmdlist.append("/storage/emulated/0/1/input.mp4");
        cmdlist.append("-vf");
        cmdlist.append("boxblur=5:1");
        cmdlist.append("-preset");
        cmdlist.append("superfast");
        cmdlist.append("/storage/emulated/0/1/result.mp4");
        return cmdlist.build();
    }
  • 获取媒体文件信息
RxFFmpegInvoke.getInstance().getMediaInfo(String filePath);

代码混淆

-dontwarn io.microshow.rxffmpeg.**
-keep class io.microshow.rxffmpeg.**{*;}

ScreenShot

ios 剪辑框架 剪辑视频框架_ide_02

性能比对:arm64-v8a VS armeabi-v7a

ios 剪辑框架 剪辑视频框架_ide_03

 

ios 剪辑框架 剪辑视频框架_ide_04

总结:可以看出 arm64-v8a 架构的运行效率远大于 armeabi-v7a,强烈建议在你的 App 添加 arm64-v8a 架构的 so,同时也是响应 Google 的号召。

实验室

抖音首页视频翻页

  • 视频适配方案
  • 竖屏视频:高宽比例 >= 16/9,则全屏铺满,反之采取第二方案
  • 横屏及其他比例视频:宽度铺满,高度自适应,背景虚化效果
  • 视频播放器基于 ExoPlayer(轻量级播放器)
  • 支持直播视频
  • 支持视频预缓存

ios 剪辑框架 剪辑视频框架_v8_05