本文为剑西独家授权发布,剑西也是做Android多媒体开发,算是同道中人,不过他主要集中在视频压缩,利用FFmpeg,能做很多事,但是做到效果好,却不多。今天看下他的分享,剑西的blog是:剑西的博客_CSDN博客-音视频,Android常识,计算机基础领域博主。
1.预热
时光荏苒,光阴如梭,离上一次吹牛逼已经过去了两三个月,身边很多人的女票已经分了又合,合了又分,本屌依旧骄傲单身。上一次啊我们大致说了一些简单的FFmpeg命令以及Java层简单的调用方式,然后有很多朋友在github或者csdn上给我留言,很多时候我都选择避而不答,原因是本库以前用的so包是不开源的,我根本改不了里面东西。但是这一次啊我们玩点大的,我重新编译了 FFmpeg且重写JNI的接口函数,这次将从C到Java全面开源,2.0项目花了本尊两个多月的业余时间,今天终于完工,非常鸡冻,且本博客将抒发出作者的全部心声,有没有很鸡冻,有没有。鸡冻之余,我也想吐槽下其软便的效率,确实不是很高,3.0的时候将会试试硬编码,或则在2.0迭代的时候会采用H265编码,这都是后话了,不过看微信把小视频换成大视频的节奏,应该可以搞。
本文涉及知识点:
Andorid 视频和音频采集
YUV视频处理(手动剪切、旋转、镜像等)PCM音频处理
利用FFmpeg API ,YUV编码为H264、PCM编码为AAC
FFmpeg 编码器的配置
JNI在工程中的实际运用
Android下FFmpeg命令工具的制作与应用
Android Studio插件 cMake 在工程中的应用
充能:
至少需要知道YUV、PCM、MP4是什么(视音频编解码技术零基础学习方法)。
最好能先阅读编译Android下可用的FFmpeg(包含libx264与libfdk-aac)、编译Android下可执行命令的FFmpeg、Android下玩JNI的新老三种姿势,为了不太啰嗦,这些文章中分享过的大多数知识将不再重复。
对C/C++基本语法有基本的了解。
本人环境与工具
系统: macOS-10.12.5
编译器: Android Studio-2.3.2
ndk: r14
FFmpeg: 3.2.5
★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。
见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
2.项目概括:
2.1效果图:
项目地址没变:GitHub - mabeijianxi/small-video-record: 利用FFmpeg视频录制微信小视频与其压缩处理 这里复用了1.0版本的gif图,因为界面一点没变,功能的话暂时没封装那么多,没关系后期会补上。
2.2 整体流程:
2.3 工程目录浏览:
3.新建项目
我们新建一个项目,也许与以往不同,需要勾选上 C++ 支持与 C++ standard选项时选择 C++ 11,如下图:
C++支持是必须的,至于选用C++ 11也是有原因的,后面我们会用的里面的一些API。 然后我们把在编译Android下可用的FFmpeg(包含libx264与libfdk-aac)中编译好的六个动态库、头文件还有 cmdutils.c cmdutils.h cmdutils_common_opts.h config.h ffmpeg.c ffmpeg.h ffmpeg_filter.c ffmpeg_opt.c copy到我们工程的 cpp目录下,完成后你cpp目录应该如下
也许你会比我多一个自动生成的native-lib.cpp,这个文件暂时保留它。
4.编写JNI接口:
我新建了一个接口类FFmpegBridge.java,且根据我的需求暂时定义了如下方法:
package com.mabeijianxi.smallvideorecord2.jniinterface;import java.util.ArrayList;/** * Created by jianxi on 2017/5/12. * https://github.com/mabeijianxi * mabeijianxi@gmail.com */public class FFmpegBridge { private static ArrayList<FFmpegStateListener> listeners=new ArrayList(); static { System.loadLibrary("avutil"); System.loadLibrary("swresample"); System.loadLibrary("avcodec"); System.loadLibrary("avformat"); System.loadLibrary("swscale"); System.loadLibrary("avfilter"); System.loadLibrary("jx_ffmpeg_jni"); } /** * 结束录制并且转码保存完成 */ public static final int ALL_RECORD_END =1; public final static int ROTATE_0_CROP_LF=0; /** * 旋转90度剪裁左上 */ public final static int ROTATE_90_CROP_LT =1; /** * 暂时没处理 */ public final static int ROTATE_180=2; /** * 旋转270(-90)裁剪左上,左右镜像 */ public final static int ROTATE_270_CROP_LT_MIRROR_LR=3; /** * * @return 返回ffmpeg的编译信息 */ public static native String getFFmpegConfig(); /** * 命令形式运行ffmpeg * @param cmd * @return 返回0表示成功 */ private static native int jxCMDRun(String cmd[]); /** * 编码一帧视频,暂时只能编码yv12视频 * @param data * @return */ public static native int