FFmpeg是一套具有非常强大功能的多媒体处理工具,它几乎涵盖了目前所有主流的多媒体数据封装格式、多媒体传输协议以及音视频编解码器,并且支持多媒体后处理,视频色彩转换、滤镜和缩放等,也支持众多主流的协议:HTTP、RTP、RTSP、RTMP、HLS、UDP等
FFmpeg它主要含有以下几个核心库:
1、libavcodec-提供了更加全面的编解码实现的合集
2、libavformat-提供了更加全面的音视频容器格式的封装和解析以及所支持的协议
3、libavutil-提供了一些公共函数
4、libavfilter-提供音视频的过滤器,如视频加水印、音频变声等
5、libavdevice-提供支持众多设备数据的输入与输出,如读取摄像头数据、屏幕录制
6、libswresample,libavresample-提供音频的重采样工具
7、libswscale-提供对视频图像进行色彩转换、缩放以及像素格式转换,如图像的YUV转换
8、libpostproc-多媒体后处理器
以及包含以下几个工具:
1、ffmpeg-一个流媒体的编解码、格式转换以及多媒体流的内容处理工具
2、ffplay-一个使用FFmpeg编解码的播放器
3、ffprobe-一个多媒体分析工具4、ffserver-一个流多媒体服务器
下载FFmpeg
解压如下
默认编译出来的文件后缀并不是 *.so,这 Android 是识别不了的,需要对ffmpeg-3.3.2目录下的config文件做修改(大概在3304行):
把
SLIBNAME_WITH_VERSION='$(SLIBNAME).$(LIBVERSION)'
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'
修改为:
SLIBNAME_WITH_VERSION='$(SLIBNAME).$(LIBVERSION)'
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
编写shell文件
在ffmpeg-3.3.2文件夹下创建config.sh,配置一些通用的全局变量,如下:
#ndk 环境
NDK=/Users/maimingliang/Documents/NDK/android-ndk-r12b
SYSROOT=$NDK/platforms/android-21/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
# cpu 架构平台,若要编译 x86 则指定 x86
CPU=armv7-a
然后创建ffmpeg编译脚本build_android.sh。如下:
#!/bin/sh
#引入配置文件
. config.sh
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
function build_android
{
./configure \
#编译输出前缀
--prefix=$PREFIX \
#启动生成动态库
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-doc \
--disable-symver \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
build_android
打开终端把目录切换到ffmpeg-3.3.2下,给 build_android.sh 和 config.sh 赋予可执行权限。(chmod 777 build_android.sh config.sh).
并执行 ./build_android.sh。注意:执行前,要把shell文件的注释去掉
编译过程:
编译后生成的目录结构如下
在Android里使用FFmpeg
创建一个工程FFmpegDemo,
对于 NDK 开发,AndroidStudio 2.2 以后就有较好的支持。
直接修改Cmakelists.txt,build.gradle文件即可。
创建工程时,勾选下面的选项:
把.so文件和include下文件copy到libs下。
配置build.gralde文件
android {
......
defaultConfig {
....
ndk {
abiFilters 'armeabi-v7a'
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
配置Cmakelists.txt
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../libs)
add_library( avutil-55
SHARED
IMPORTED )
set_target_properties( avutil-55
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libavutil-55.so )
add_library( swresample-2
SHARED
IMPORTED )
set_target_properties( swresample-2
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libswresample-2.so )
add_library( avcodec-57
SHARED
IMPORTED )
set_target_properties( avcodec-57
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libavcodec-57.so )
add_library( avfilter-6
SHARED
IMPORTED)
set_target_properties( avfilter-6
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libavfilter-6.so )
add_library( swscale-4
SHARED
IMPORTED)
set_target_properties( swscale-4
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libswscale-4.so )
add_library( avformat-57
SHARED
IMPORTED)
set_target_properties( avformat-57
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libavformat-57.so )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
add_library( native-lib
SHARED
src/main/cpp/native-lib.cpp
)
include_directories(libs/include)
#target_include_directories(native-lib PRIVATE libs/include)
target_link_libraries( native-lib swresample-2 avcodec-57 avfilter-6 swscale-4 avformat-57
${log-lib} )
在android studio 2.2 以后使用cmake
配置完成上面的操作,就成功把ffmpeg引入进来了。
测试引入是否成功?
在Main Activity中编写native方法。如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
final TextView tv = (TextView) findViewById(R.id.sample_text);
// tv.setText(stringFromJNI());
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tv.setText(avcodecinfo());
}
});
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
public native String avcodecinfo();
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
}
在native-lib.cpp编写native方法实现,如下:
#include <jni.h>
#include <string>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
JNIEXPORT jstring JNICALL
Java_com_maiml_ffmpegdemo2_MainActivity_avcodecinfo(JNIEnv *env, jobject instance) {
char info[40000] = {0};
av_register_all();
AVCodec *c_temp = av_codec_next(NULL);
while (c_temp != NULL) {
if (c_temp->decode != NULL) {
sprintf(info, "%sdecode:", info);
} else {
sprintf(info, "%sencode:", info);
}
switch (c_temp->type) {
case AVMEDIA_TYPE_VIDEO:
sprintf(info, "%s(video):", info);
break;
case AVMEDIA_TYPE_AUDIO:
sprintf(info, "%s(audio):", info);
break;
default:
sprintf(info, "%s(other):", info);
break;
}
sprintf(info, "%s[%10s]\n", info, c_temp->name);
c_temp = c_temp->next;
}
return env->NewStringUTF(info);
}
extern "C"
jstring
Java_com_maiml_ffmpegdemo2_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
}
运行结果:
END。