一个小玩具:NDK编译FFmpeg的例子
FFmpeg NDK编译 和最简单的APK
准备
硬件:
一台电脑,实验在Lenovo
T430上
一个Android设备,实验在
三星S3/A7
编译环境:
Ubuntu 14.04
(ant\java等命令必须支持)
工具包:
NDK:
https://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86_64.tar.bz2
SDK:https://dl.google.com/android/adt/adt-bundle-linux-x86_64-20140702.zip
Ffmpeg:
http://ffmpeg.org/releases/ffmpeg-2.7.2.tar.bz2
步骤
1. 配置编译FFmpeg,
生成库文件libxxx.so和include头文件
2.
用eclipse生成一个最简单APK,load静态卡,调用native方法
3.将第1步的libxxx.so文件,由ndk-build工具重新编译
4.
引用第2步的库文件,编写自己的jni
call native函数
1. 配置编译FFmpeg,
生成库文件libxxx.so和include头文件
tar -xvjf
ffmpeg-2.7.2.tar.bz2
cd ffmpeg-2.7.2
gedit my-make.sh
将下面的代码拷贝到my-make.sh中
#!/bin/bash
NDK=/opt/adrd-stuff/android-ndk-r10b
SYSROOT=$NDK/platforms/android-19/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffserver \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
build_one
make -j8
make install
## end of my-make.sh
然后:
chmod +x my-make.sh
mkdir android/arm -p
./my-make.sh
最后就可以在android/arm下面:
~~~~~~~~~~~/android/arm$
ls
bin include lib
share
2.
用eclipse生成一个最简单APK,load静态库,调用native方法
在android
eclipse开发环境中,新建一个最简单的android
application。
此处关节是添加文件FFmpegNative.java
└── src
└── com
└──
az
└──
ffmpegapp
├──
FFmpegNative.java
└──
MainActivity.java
package
com.az.ffmpegapp;
publicclass
FFmpegNative {
static{
System.loadLibrary("avutil-54");
System.loadLibrary("avcodec-56");
System.loadLibrary("swresample-1");
System.loadLibrary("avformat-56");
System.loadLibrary("swscale-3");
System.loadLibrary("avfilter-5");
System.loadLibrary("ffmpeg_codec");
}
publicstaticnativeint
avcodec_find_decoder(int
codecID);
}
确保在bin目录下生成了
bin/classes/com/az/ffmpegapp/FFmpegNative.class
3.将第1步的libxxx.so文件,由ndk-build工具重新编译
(1)
在FFmpegApp下面,新建目录jni
(2)jni下面新建目录ffmpeg,把第1大步生成的文件拷贝到此目录下
ls ffmpeg/
bin include lib
share
(3)编写Android.mk文件
LOCAL_PATH := $(call
my-dir)
include
$(CLEAR_VARS)
LOCAL_MODULE :=
avcodec-56-prebuilt
LOCAL_SRC_FILES :=
ffmpeg/lib/libavcodec-56.so
include
$(PREBUILT_SHARED_LIBRARY)
include
$(CLEAR_VARS)
LOCAL_MODULE
:=avdevice-56-prebuilt
LOCAL_SRC_FILES
:=ffmpeg/lib/libavdevice-56.so
include
$(PREBUILT_SHARED_LIBRARY)
include
$(CLEAR_VARS)
LOCAL_MODULE
:=avfilter-5-prebuilt
LOCAL_SRC_FILES
:=ffmpeg/lib/libavfilter-5.so
include
$(PREBUILT_SHARED_LIBRARY)
include
$(CLEAR_VARS)
LOCAL_MODULE
:=avformat-56-prebuilt
LOCAL_SRC_FILES
:=ffmpeg/lib/libavformat-56.so
include
$(PREBUILT_SHARED_LIBRARY)
include
$(CLEAR_VARS)
LOCAL_MODULE :=
avutil-54-prebuilt
LOCAL_SRC_FILES
:=ffmpeg/lib/libavutil-54.so
include
$(PREBUILT_SHARED_LIBRARY)
include
$(CLEAR_VARS)
LOCAL_MODULE :=
avswresample-1-prebuilt
LOCAL_SRC_FILES
:=ffmpeg/lib/libswresample-1.so
include
$(PREBUILT_SHARED_LIBRARY)
include
$(CLEAR_VARS)
LOCAL_MODULE :=
swscale-3-prebuilt
LOCAL_SRC_FILES
:=ffmpeg/lib/libswscale-3.so
include
$(PREBUILT_SHARED_LIBRARY)
#end of Andoid.mk
(4)运行ndk-build
此时生成了文件在../libs/armeabi下面:
tree ../libs/
../libs/
├──
android-support-v4.jar
├──
android-support-v7-appcompat.jar
└── armeabi
├──
libavcodec-56.so
├──
libavdevice-56.so
├──
libavfilter-5.so
├──
libavformat-56.so
├──
libavutil-54.so
├──
libswresample-1.so
└──
libswscale-3.so
4.
引用第2步的库文件,编写自己的jni
call native函数
(1)注意到第2大步里面生成的bin/classes/com/az/ffmpegapp/FFmpegNative.class
cd
bin
javah
-classpath classes/ com.az.ffmpegapp.FFmpegNative
生成文件:com_az_ffmpegapp_FFmpegNative.h
(2)
拷贝到jni下,实现这个头文件里面的方法,更换一个名字native_avcodec_find_decoder(文字最后附录一个完整c文件FFmpegNative.c)
#include
<libavcodec/avcodec.h>
JNIEXPORT
jint JNICALL native_avcodec_find_decoder(JNIEnv * e, jclass jc, jint
codecID)
{
LOGI("%s
called\n",__func__);
AVCodec
*codec = NULL;
/*register
all formats and codecs */
av_register_all();
codec=
avcodec_find_decoder(codecID);
if(codec
!= NULL) {
return
0;
}
else {
return
-1;
}
}
(3)编辑Android.mk,在前面的基础上,最后面添加:
include $(CLEAR_VARS)
LOCAL_MODULE :=ffmpeg_codec
LOCAL_SRC_FILES :=FFmpegNative.c
LOCAL_LDLIBS := -llog #-ljnigraphics -lz -landroid
LOCAL_C_INCLUDES += $(LOCAL_PATH)/ffmpeg/include
LOCAL_SHARED_LIBRARIES:= \
avcodec-56-prebuilt \
avdevice-56-prebuilt \
avfilter-5-prebuilt \
avformat-56-prebuilt \
avutil-54-prebuilt
include $(BUILD_SHARED_LIBRARY)
(4)ndk-build
tree ../libs/
../libs/
├── android-support-v4.jar
├── android-support-v7-appcompat.jar
└── armeabi
├── libavcodec-56.so
├── libavdevice-56.so
├── libavfilter-5.so
├── libavformat-56.so
├── libavutil-54.so
├── libffmpeg_codec.so
├── libswresample-1.so
└── libswscale-3.so
libffmpeg_codec.so
就是新生成的库。
(5)Eclipse重新编译生成APK
由于在MainActivity.java有下面的打印语句:
protectedvoid
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if
(FFmpegNative.avcodec_find_decoder(28)==0)
Log.d("MainActivity","Find
decoder 28");
else
Log.d("MainActivity","Not
Find");
}
JNI
native里面有调试语句:
JNIEXPORT
jint JNICALL native_avcodec_find_decoder(JNIEnv * e, jclass jc, jint
codecID)
{
#if
LOGI("%s called\n",__func__);
在logcat可以有下面的打印:
D/MainActivity(12786):
Find decoder 28
I/SubCommand(12786):
native_avcodec_find_decoder called
注意:
NDK版本:
32bits小机用:android-ndk32-r10b-linux-x86_64.tar.bz2
64bits小机用:android-ndk64-r10b-linux-x86_64.tar.bz2
64bits编译出来的APK在S3上面运行,会有闪退的现象,
E/dalvikvm(31393):
dlopen("/data/app-lib/com.az.ffmpegapp-1/libavformat-56.so")
failed: dlopen failed: cannot locate symbol "atof"
referenced by "libavformat-56.so"...
W/dalvikvm(31393):
Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing
Lcom/az/ffmpegapp/FFmpegNative;
E/AndroidRuntime(31393):
Process: com.az.ffmpegapp, PID: 31393
E/AndroidRuntime(31393):
at com.az.ffmpegapp.FFmpegNative.<clinit>(FFmpegNative.java:7)
E/AndroidRuntime(31393):
at com.az.ffmpegapp.MainActivity.onCreate(MainActivity.java:15)
W/ActivityManager(
834): Force finishing activity com.az.ffmpegapp/.MainActivity
附录文件:
FFmpegNative.c
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <android/log.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h> /* Header for class com_az_ffmpegapk_FFmpegNative */ #ifndef _Included_com_az_ffmpegapk_FFmpegNative
#define _Included_com_az_ffmpegapk_FFmpegNative
#define LOG_TAG "SubCommand"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOG_DEBUG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_az_ffmpegapk_FFmpegNative
* Method: avcodec_find_decoder
* Signature: (I)I
*/
#include <libavcodec/avcodec.h>
JNIEXPORT jint JNICALL native_avcodec_find_decoder(JNIEnv * e, jclass jc, jint codecID)
{
#if 1
LOGI("%s called\n",__func__);
AVCodec *codec = NULL; /*register all formats and codecs */
av_register_all();
codec= avcodec_find_decoder(codecID); if(codec != NULL) {
return 0;
} else {
return -1;
}
#endif
}
#define JNIREG_CLASS "com/az/ffmpegapp/FFmpegNative" //class name to be registered
/**
* Table of methods associated with a single class.
*/
static JNINativeMethod gMethods[] = {
{ "avcodec_find_decoder", "(I)I", (void*)native_avcodec_find_decoder }
}; /*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = (*env)->FindClass(env, className);
if (clazz == NULL) {
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
} return JNI_TRUE;
} /*
* Register native methods for all classes we know about.
*/
static int registerNatives(JNIEnv* env)
{
if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
sizeof(gMethods) / sizeof(gMethods[0])))
return JNI_FALSE; return JNI_TRUE;
} /*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
LOGI("--------------------------------------------------------------------\n");
LOGI("OnLoad: %s:%s\n", __DATE__, __TIME__);
LOGI("--------------------------------------------------------------------\n"); if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
assert(env != NULL); if (!registerNatives(env)) {
return -1;
}
/* success -- return valid version number */
result = JNI_VERSION_1_6; return result;
}
#ifdef __cplusplus
}
#endif
#endif
jni/Android.mk
jni$ cat Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS)
LOCAL_MODULE := avcodec-56-prebuilt
LOCAL_SRC_FILES := ffmpeg/lib/libavcodec-56.so
include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)
LOCAL_MODULE :=avdevice-56-prebuilt
LOCAL_SRC_FILES :=ffmpeg/lib/libavdevice-56.so
include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)
LOCAL_MODULE :=avfilter-5-prebuilt
LOCAL_SRC_FILES :=ffmpeg/lib/libavfilter-5.so
include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)
LOCAL_MODULE :=avformat-56-prebuilt
LOCAL_SRC_FILES :=ffmpeg/lib/libavformat-56.so
include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)
LOCAL_MODULE := avutil-54-prebuilt
LOCAL_SRC_FILES :=ffmpeg/lib/libavutil-54.so
include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)
LOCAL_MODULE := avswresample-1-prebuilt
LOCAL_SRC_FILES :=ffmpeg/lib/libswresample-1.so
include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)
LOCAL_MODULE := swscale-3-prebuilt
LOCAL_SRC_FILES :=ffmpeg/lib/libswscale-3.so
include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)
LOCAL_MODULE :=ffmpeg_codec
LOCAL_SRC_FILES :=FFmpegNative.c
LOCAL_LDLIBS := -llog #-ljnigraphics -lz -landroid
LOCAL_C_INCLUDES += $(LOCAL_PATH)/ffmpeg/include
LOCAL_SHARED_LIBRARIES:= \
avcodec-56-prebuilt \
avdevice-56-prebuilt \
avfilter-5-prebuilt \
avformat-56-prebuilt \
avutil-54-prebuilt
include $(BUILD_SHARED_LIBRARY)
src/com/az/ffmpegapp/FFmpegNative.java
package com.az.ffmpegapp;
public class FFmpegNative {
static{
System.loadLibrary("avutil-54");
System.loadLibrary("avcodec-56");
System.loadLibrary("swresample-1");
System.loadLibrary("avformat-56");
System.loadLibrary("swscale-3");
System.loadLibrary("avfilter-5");
System.loadLibrary("ffmpeg_codec");
}
public static native int avcodec_find_decoder(int codecID);
}
src/com/az/ffmpegapp/MainActivity.java
package com.az.ffmpegapp; import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem; public class MainActivity extends ActionBarActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (FFmpegNative.avcodec_find_decoder(28)==0)
Log.d("MainActivity","Find decoder 28");
else
Log.d("MainActivity","Not Find");
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
一个小玩具:NDK编译FFmpeg的例子的更多相关文章
- anroid ndk编译ffmpeg 引用librtmp libx264
Ffmpeg 无处不在,自然android系统少不了它,折腾了不少时间完成 ndk编译ffmpeg,生成so库中引用了外部库librtmp,libx264.条条大路通罗马, 也许还有别的更好的方法去完 ...
- 用Android NDK编译FFmpeg
附(2018-01-06): 有一个将x264及lame等库集成进去了且基于android的ffmpeg的编译方法,地址参见: https://github.com/writing ...
- Linux下NDK编译FFMPEG包含neon参数
FFMPEG编译成Android库已经有很多案例了,编译优化neon的也很多,以下是我通过实践成功的案例,这里主要讲编译的配置文件,其他设置可结合Linux下使用NDK编译FFMPEG(libstag ...
- 64位 CentOS NDK 编译 FFMPEG
64位 CentOS NDK 编译 FFMPEG 一. 参考文章: http://www.cnblogs.com/baopu/p/4733029.html http://www.c ...
- 一个小玩具:NDK编译SDL的例子
NDK编译SDL 准备: 硬件 一台电脑,实验在Lenovo T430上 一个Android设备,实验在 三星S3/A7 编译环境: Ubuntu 14.04 (ant\java等命令必须支持) 工具 ...
- Linux下使用NDK编译FFMPEG(libstagefright)
这个月要负责一个项目,使用FFMPEG渲染视频,主要是Android端的,由于性能要求,要使用硬解码,但网上大多数教程都是没有libstagefright的,所以个人觉得,生成的so库文件也是没有开启 ...
- [原]如何用Android NDK编译FFmpeg
我们知道在Ubuntu下直接编译FFmpeg是很简单的,主要是先执行./configure,接着执行make命令来编译,完了紧接着执行make install执行安装.那么如何使用Android的ND ...
- NDK编译FFMpeg[Linux]
最近在研究视频直播相关的技术,了解到了FFmpeg,就在网上查看如何将FFmpeg移植到Android中,查了几天,看的东西不少,就是没有一个可以完全移植成功的,最后通过产看各种资料,结合网上的资料, ...
- FFmpeg编译:Linux下使用NDK编译FFmpeg
环境: Ubuntu 1.下载并解压FFmpeg3.4.zip(略) 2.将编译脚本放入到FFmpeg解压后的目录. 3.执行编译脚本: ./linux_build_android.sh linux_ ...
随机推荐
- 如何使用json在前后台进行数据传输
上一篇博客写到用javascript生成多组文本,可以让数据的输入不受显示,现在我们需要把这些输入写入数据库,这里就用到json传入. 首先,我们来写一下后台如何生成要传输的数据 function g ...
- JavaScript 函数和对象
在javascirpt 世界中,所有的函数都是对象,并且还可以被用来创建对象. function make_person(firstname, lastname, age) { person = {} ...
- JFS 文件系统概述及布局分析
JFS 文件系统概述及布局分析 日志文件系统如何缩短系统重启时间 如果发生系统崩溃,JFS 提供了快速文件系统重启.通过使用数据库日志技术,JFS 能在几秒或几分钟之内把文件系统恢复到一致状态,而非日 ...
- 浅析STL allocator
一般而言,我们习惯的 C++ 内存配置操作和释放操作是这样的: class FOO{}; FOO *pf = new FOO; delete pf; 我们看其中第二行和第三行,虽然都是只有一句,当是都 ...
- Linux企业级开发技术(5)——libevent企业级开发之简介
Libevent是一个用于编写高速可移植非阻塞IO应用的库,它的设计目标是: 可移植性:使用libevent编写的程序应该可以在libevent支持的所有平台上工作.即使没有好的方式进行非阻塞IO,l ...
- 数据结构(主席树):HDU 5654 xiaoxin and his watermelon candy
Problem Description During his six grade summer vacation, xiaoxin got lots of watermelon candies fro ...
- 【模拟】Codeforces 699B One Bomb
题目链接: http://codeforces.com/problemset/problem/699/B 题目大意: N*M的图,*代表墙.代表空地.问能否在任意位置(可以是墙上)放一枚炸弹(能炸所在 ...
- 【动态规划】Vijos P1037 搭建双塔
题目链接: https://vijos.org/p/1037 题目大意: 给n块砖的长度(n<=100),问从中任选m块砖能否建成2个相同高度的塔. 能的话求最高高度,不能输出 Impossib ...
- SQL时间格式化
1 取值后格式化 {:d}小型:如2005 {:D}大型:如2005年5月6日 {:f}完整型 2 当前时间获取 DateTime.Now.ToShortDateString 3 取值中格式化SQL ...
- TabHost结合RadioButton实现主页的导航效果
布局文件的设置,如下 <?xml version="1.0" encoding="utf-8"?> <TabHost xmlns:androi ...