基于Android平台的x264的移植与应用(一):移植篇

    http://www.cnblogs.com/tairikun/

写这篇博客的目的是希望可以帮助到那些在将x264移植到Android过程中遭遇坎坷还没有成功的朋友们,同时也算是对我这段时间学习的一个总结。

--------------------------------------------------------------------------------------

首先,先贴上我的编译环境:

操作系统:ubuntu 11.10

jdk:jdk-6u31-linux-i586

eclipse:eclipse-SDK-3.7.2-linux-gtk

ndk:由于ndk版本不断提高,但不同版本ndk的目录结构和使用的gcc又不尽相同,本文将对两个版本的ndk分别进行介绍(android-ndk-r4b-linux-x86 与 android-ndk-r6-linux-x86),你可以根据自己的ndk目录进行配置。

x264源码:last_x264

--------------------------------------------------------------------------------------

记得上课的时候王老师说过一句话:“忘了过去的苦难,就是未来的灾难!”。

为了让我的未来没有灾难,我将记录下在编译过程遭受的苦难 ^_^

(1)最开始的时候我是在windows 7 + cygwin环境下编译的,但是一直没有成功,可能是因为不太相信cygwin这样的模拟环境,我终于决定转战linux,于是在linux的世界里从此就诞生了一名菜鸟,可正是如此,才有了下面的故事……

(2)因为初次接触linux,我就像一个丈二的和尚努力地去摸我的头脑,说实话,摸得可真够累的,真是太习惯了windows傻瓜式的操作方法了!!!然后我就瞎搞胡搞,总算是有些熟悉linux环境了。

(3)刚开始编译x264的时候,很happy的在google百度上找了一些编译的方法,比如这篇《编译x264》,什么都不管就照着上面的做。直接 ./configure 之后就 make, 看到生成了libx264的库,比见到鬼还高兴,可是当用ndk编译调用libx264的jni的时候,就乱七八糟的一大堆错误 = =.|| ,然后还一直找这些莫名其妙错误的解决方案。当然,最后没有好结果 Orz.  

(PS:我这里要批评一下GFW,你妹的我用google刚刚谷了一会儿点击结果弹出的页面显示的都是:无法访问此网页,DNS查找失败……!!!)

(4)在第3步纠结了很久,后来知道用./configure编译使用的是默认的gcc编译器集,而gcc编译出来的文件是在本地执行的,因为产生的是x86的二进制文件。而我们移植的x264并不是在本地使用,因此需要交叉移植,交叉移植?神马? 知道了在linux下交叉编译需要用到arm-linux-gcc,果断找用arm-linux-gcc编译x264的文章《交叉编译x264文件》,原来在make之前得先将config.mak里面的gcc全部改成arm-linux-gcc,还有其他一些也得修改为arm-linux-的编译器集。改了之后,我还是编译不过,因为我机器上没有这个编译器,于是下载arm-linux-gcc编译器,配置后环境后,再make了一次。这下我开心了半死,编译成功,胜利在望了有木有!!! ^_^

(5)将第4步编译好的libx264放到android里面调用,当用ndk编译调用libx264的jni的时候,成功生成了.so文件,这意味着我成功了吗??

(6)当我很开心的拿我的HTC G3安装运行生成的apk的时候,却出现了错误java.lang.unSatifiedLinkerror: libx264 not found。 我晕,我甚至将生成的apk解包,发现里面安安静静地躺着libx264啊,想起了《皇帝的新装》这个故事,皇帝明明没有穿衣服,人们硬要说他穿着漂亮的衣裳,尼玛我的libx264就放在那里,你硬要说它不在!??。这是肿么一回事,又找了许久资料不见解决之道。心都凉了有木有!!!

(7)咳,烦死了去洗了个澡。回来决定再试一次,于是百度到了这篇文章《compile libx264 with android-ndk-r4b》,因为很早就试过这篇文章的配置,发现出错了,于是放弃了。现在已经走投无路了,我就死马当做活马医。用这个配置运行后,出现错误arm-eabi-gcc:没有那个文件或目录。。。可是配置里面明明就有那个gcc啊,由于在用arm-linux-gcc的时候也有出现类似的错误,是因为没有这个库,现在有这个库了还说它不存在,这不是坑爹吗?然后我抱着试一试的态度将arm-eabi-的路径加入到PATH之后,然后再用这个配置文件编译了一次,TT太感动了,成功编译了,然后用编译好的库做测试运行成功了,运行成功了,成功了。。我高兴得晚上都睡不着觉。

(8)原来用arm-linux-gcc是在x86机器上编译可以在arm机器上运行的二进制代码,在android上运行不成功,是因为android不是arm平台吧?不知道我分析的对不对,如果有错,欢迎指正。另:有更多关于gcc, arm-linux-gcc, arm-eabi-gcc的相关知识也希望你能告诉我,给我这个linux菜鸟上个课 ^_^

(9)总结:x264移植到Android下用的不是gcc,不是arm-linux-gcc,而是arm-eabi-gcc。

--------------------------------------------------------------------------------------

唠叨了这么久,终于要进入正题了 Orz

本文介绍的编译方式最后生成的是静态库,如果需要编译成动态库的朋友可以点击这里,不过这篇文章只介绍了编译的思路,并没有提供确切地方法,需要的朋友还得自己去琢磨咯!

 

【一:使用ndk-r4b编译x264】

步骤:

1,将x264压缩包解压,假设解压后的目录为libx264。

2,在libx264目录下新建一个脚本文件myconfig.sh,然后将《compile libx264 with android-ndk-r4b》里面的代码贴到myconfig.sh里面。

3,将第一句配置 export ARM_ROOT=/home/frank/android-ndk-r4b 改成你ndk-r4b的路径。

4,打开终端,并将终端定位到libx264的目录下,输入 sudo sh ./myconfig.sh

5,当提示可以运行make的时候,输入make

6,如果程序可以很正常的编译,那么恭喜你,你已经成功了,你可以不用看下面的内容了;如果输入make之后,看到这些信息:/bin/sh:arm-eabi-gcc:未找到命令,那么你和我一样遇到了这个问题,请继续看第7步。

7,在终端输入: sudo gedit  /etc/profile ,在打开的文本中定位到文件末尾,输入以下脚本

#set arm-eabi-gcc environment
export ARM_EABI_GCC=/opt/java/ndk/android-ndk-r4b/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin
export PATH=$ARM_EABI_GCC:$PATH

注意:ARM_EABI_GCC中的/opt/java/ndk/android-ndk-r4b是我ndk-r4b的路径,你要根据自己ndk路径修改!

保存后关闭文本。这一步的目的是为arm-eabi-gcc添加环境变量。

8,上一步修改的配置需要重启电脑才能生效,为了能够使其立即生效,需要在终端输入:source /etc/profile,接着输入:echo $PATH 查看ARM_EABI_GCC的路径是否有在输出的内容中,如果有,则看第9步,否则认真检查,重新配置一下环境变量。

9,环境变量配置好了之后,输入命令:make,如果不再提示说arm-eabi-gcc未找到命令而且看到程序正在编译,那么恭喜你,你将成功编译libx264.

10,我编译好的 libx264.a 文件的大小为773.8k, 你的呢? ^_^

 

【二:使用ndk-r6编译x264】

ndk-r6用到的不再是arm-embi-gcc,而是arm-linux-androideabi-gcc。具体编译步骤还请查看【一:用ndk-r4b编译】,只不过用的myconfig.sh不同,以及ARM_EABI_GCC不同。

这里我贴上用ndk-r6编译的myconfig.sh脚本:

#------------------------------myconfig.sh------------------------------

export ARM_ROOT=/opt/java/ndk/android-ndk-r6
export ARM_INC=$ARM_ROOT/platforms/android-8/arch-arm/usr/include/
export ARM_LIB=$ARM_ROOT/platforms/android-8/arch-arm/usr/lib/
export ARM_TOOL=$ARM_ROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86
export ARM_LIBO=$ARM_TOOL/lib/gcc/arm-linux-androideabi/4.4.3
export PATH=$ARM_TOOL/bin:$PATH
export ARM_PRE=arm-linux-androideabi

./configure --disable-gpac --extra-cflags=" -I$ARM_INC -fPIC -DANDROID -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__  -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -DANDROID  -Wa,--noexecstack -MMD -MP " --extra-ldflags="-nostdlib -Bdynamic -Wl,--no-undefined -Wl,-z,noexecstack  -Wl,-z,nocopyreloc -Wl,-soname,/system/lib/libz.so -Wl,-rpath-link=$ARM_LIB,-dynamic-linker=/system/bin/linker -L$ARM_LIB -nostdlib $ARM_LIB/crtbegin_dynamic.o $ARM_LIB/crtend_android.o -lc -lm -ldl -lgcc" --cross-prefix=${ARM_PRE}- --disable-asm --host=arm-linux --disable-shared

#------------------------------myconfig.sh-----------------------------

注意:第一句ARM_ROOT还是得根据你ndk-r6的位置进行配置

另外,贴上/etc/profile中需要添加的配置:

#set arm-linux-androideabi-gcc
export ARM_LINUX_ANDROIDEABI_GCC=/opt/java/ndk/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin
export PATH=$ARM_LINUX_ANDROIDEABI_GCC:$PATH

我用ndk-r6编译好的libx264.a大小为778.6k,你可以参考一下你编译好的文件大小。

--------------------------------------------------------------------------------------

本文算是结束了,如果你通过本文成功编译好了libx264,那么:“亲,别忘了给个好评哦!^_^”

posted @ 2013-03-15 13:18 树袋熊TRK 阅读(1) 评论(0)  编辑

 2012年9月26日

Android.mk 编译文件是用来向 Android NDK描述你的 C,C++源代码文件的,   这篇文档描
述了它的语法。在阅读下面的内容之前,假定你已经阅读了 docs/OVERVIEW.TXT 文件,了解
了它们的脚色和用途。
一、概述
  一个 Android.mk file 用来向编译系统描述你的源代码。具体来说:
  (1) 该文件是GNU Makefile的一小部分,会被编译系统解析一次或更多次的build系统。
因此,您应尽量减少您声明的变量,不要认为某些变量在解析过程中不会被定义。
  (2)这个文件的语法允许把你的源代码组织成模块,一个模块属下列类型之一:
  1)静态库 
  2)共享库
  且只有共享库将被安装/复制到您的应用软件包,虽然静态库能被用于生成共享库。
  可以在每一个 Android.mk file 中定义一个或多个模块,你也可以在几个模块中使用同一个
源代码文件。
  编译系统为你处理许多细节问题。例如,你不需要在你的 Android.mk 中列出头文件和依
赖文件。NDK 编译系统将会为你自动处理这些问题。这也意味着,在升级 NDK 后,你应该
得到新的 toolchain/platform支持,而且不需要改变你的 Android.mk 文件。
  注意,这个语法同公开发布的 Android平台的开源代码很接近,然而编译系统实现他们的
方式却是不同的,这是故意这样设计的,可以让程序开发人员重用外部库的源代码更容易。
  在描述语法细节之前,咱们来看一个简单的"hello world"的例子,比如,下面的文件:
 sources/helloworld/helloworld.c
 sources/helloworld/Android.mk
 'helloworld.c'是一个 JNI 共享库,实现返回"hello world"字符串的原生方法。相应的
Android.mk 文件会象下面这样:
LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_MODULE:= helloworld
 
LOCAL_SRC_FILES := helloworld.c
 
include $(BUILD_SHARED_LIBRARY)
 
  解释一下这几行代码:
  LOCAL_PATH := $(call my-dir)
  一个Android.mk file首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。
在这个例子中, 宏函数‘my-dir’,  由编译系统提供,用于返回当前路径(即包含Android.mk file
文件的目录)。
 
  include $(CLEAR_VARS)
  CLEAR_VARS 由编译系统提供(可以在 android 安装目录下的/build/core/config.mk 文件看
到其定义,为 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk),指定让 GNU MAKEFILE
为你清除许多 LOCAL_XXX 变量 ( 例如 LOCAL_MODULE , LOCAL_SRC_FILES , Android.mk 文档规范 2
LOCAL_STATIC_LIBRARIES,等等…),除 LOCAL_PATH。这是必要的,因为所有的编译控
制文件都在同一个 GNU MAKE 执行环境中,所有的变量都是全局的。
 
  LOCAL_MODULE := helloworld
  LOCAL_MODULE 变量必须定义,以标识你在 Android.mk 文件中描述的每个模块。名称
必须是唯一的,而且不包含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话
说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件。注意:如果把库命名为
‘libhelloworld’,编译系统将不会添加任何的 lib 前缀,也会生成 libhelloworld.so,这是
为了支持来源于 Android平台的源代码的 Android.mk 文件。
 
  LOCAL_SRC_FILES := helloworld.c
  LOCAL_SRC_FILES 变量必须包含将要编译打包进模块中的 C 或 C++源代码文件。不用
在这里列出头文件和包含文件,编译系统将会自动找出依赖型的文件。
【注意,默认的 C++源码文件的扩展名是‘.cpp’ 。指定一个不同的扩展名也是可能的,只要定义
LOCAL_DEFAULT_CPP_EXTENSION 变量,不要忘记开始的小圆点(也就是定义为  ‘.cxx’,而不是‘cxx’)】 
 
  include $(BUILD_SHARED_LIBRARY)
  BUILD_SHARED_LIBRARY 是编译系统提供的变量,指向一个 GNU Makefile 脚本(应该
就是在 build/core  目录下的 shared_library.mk) ,负责收集自从上次调用 'include
$(CLEAR_VARS)'以来,定义在 LOCAL_XXX 变量中的所有信息,并且决定编译什么,如何正
确地去做。并根据其规则生成静态库。同理对于静态库。
 
  在 sources/samples目录下有更复杂一点的例子,写有注释的 Android.mk 文件。
二、参考
  这是一份你应该在 Android.mk 中依赖或定义的变量列表,可以定义其他变量为自己使用,
但是 NDK编译系统保留下列变量名:
 -以 LOCAL_开头的名字(例如 LOCAL_MODULE)
 -以 PRIVATE_, NDK_ 或 APP_开头的名字(内部使用)
 -小写名字(内部使用,例如‘my-dir’)
  如果为了方便在 Android.mk 中定义自己的变量,建议使用 MY_前缀,一个小例子:
MY_SOURCES := foo.c
 
ifneq ($(MY_CONFIG_BAR),)
 MY_SOURCES += bar.c
endif
 
LOCAL_SRC_FILES += $(MY_SOURCES)
 
1. GNU Make  变量
  这些 GNU Make  变量在你的 Android.mk 文件解析之前,就由编译系统定义好了。注意在
某些情况下,NDK可能分析 Android.mk 几次,每一次某些变量的定义会有不同。
  (1)CLEAR_VARS:  指向一个编译脚本,几乎所有未定义的 LOCAL_XXX 变量都在
"Module-description"节中列出。必须在开始一个新模块之前包含这个脚本:include
$(CLEAR_VARS)
  (2)BUILD_SHARED_LIBRARY:  指向编译脚本,收集所有的在 LOCAL_XXX 变量中提
供的信息,并且决定如何把列出的源代码文件编译成一个共享库。注意,必须至少在包含这
个文件之前定义 LOCAL_MODULE 和 LOCAL_SRC_FILES。使用例子:  Android.mk 文档规范 3
include $(BUILD_SHARED_LIBRARY) 
#这将生成一个名为 lib$(LOCAL_MODULE).so 的文件
 
(3) BUILD_STATIC_LIBRARY:  一个 BUILD_SHARED_LIBRARY 变量用于编译一个静
态库。静态库不会复制到的 project/packages 中,但是能够用于编译共享库, (看下面描述的
LOCAL_STATIC_LIBRARIES and LOCAL_STATIC_WHOLE_LIBRARIES)。使用例子:
include $(BUILD_STATIC_LIBRARY) 
#注意,这将会生成一个名为 lib$(LOCAL_MODULE).a 的文件
 
  (4)TARGET_ARCH: 目标 CPU平台的名字,  和 android 开放源码中指定的那样。如果是
arm,表示要生成 ARM 兼容的指令,与 CPU架构的修订版无关。
 
  (5)TARGET_PLATFORM: Android.mk 解析的时候,目标 Android 平台的名字.详情可参
考/development/ndk/docs/stable- apis.txt.
 android-3 -> Official Android 1.5 system images
 android-4 -> Official Android 1.6 system images
 android-5 -> Official Android 2.0 system images
 
  (6)TARGET_ARCH_ABI:  暂时只支持两个 value,armeabi 和 armeabi-v7a。在
现在的版本中一般把这两个值简单的定义为 arm, 通过 android  平台内部对它重定义来获得更
好的匹配。其他的 ABI 将在以后的 NDK 版本中介绍,它们会有不同的名字。注意所有基于
ARM 的 ABI都会把 'TARGET_ARCH'定义成‘arm’,但是会有不同的‘TARGET_ARCH_ABI’。 
 
( 7 ) TARGET_ABI:  目标平台和 ABI 的组合,它事实上被定义成
$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)  ,在想要在真实的设备中针对一个特别的
目标系统进行测试时,会有用。在默认的情况下,它会是'android-3-arm'。
2.  模块描述变量
  下面的变量用于向编译系统描述你的模块。你应该定义在'include  $(CLEAR_VARS)'
和'include $(BUILD_XXXXX)'之间。正如前面描写的那样,$(CLEAR_VARS)是一个脚
本,清除所有这些变量,除非在描述中显式注明。
  (1) LOCAL_PATH:  这个变量用于给出当前文件的路径。必须在 Android.mk 的开头定
义,可以这样使用:
LOCAL_PATH := $(call my-dir)
 
  这个变量不会被$(CLEAR_VARS)清除,因此每个 Android.mk 只需要定义一次(即使在一
个文件中定义了几个模块的情况下)。
 
  (2)LOCAL_MODULE: 这是模块的名字,它必须是唯一的,而且不能包含空格。必须在
包含任一的$(BUILD_XXXX)脚本之前定义它。模块的名字决定了生成文件的名字。例如,如
果一个一个共享库模块的名字是,那么生成文件的名字就是 lib.so。但是,在的 NDK 生成文
件中(或者 Android.mk 或者 Application.mk),应该只涉及(引用)有正常名字的其他模块。
 
  (3)LOCAL_SRC_FILES:  这是要编译的源代码文件列表。只要列出要传递给编译器的
文件,因为编译系统自动计算依赖。注意源代码文件名称都是相对于 LOCAL_PATH的,你可
以使用路径部分,例如:
LOCAL_SRC_FILES := foo.c
 toto/bar.c
 
  【注意:在生成文件中都要使用UNIX风格的斜杠(/).windows风格的反斜杠不会被正确的处理。】  Android.mk 文档规范 4
 
  (4)   LOCAL_CPP_EXTENSION:  这是一个可选变量,用来指定C++代码文件的扩展名,
默认是'.cpp',但是可以改变它,比如:
LOCAL_CPP_EXTENSION := .cxx
 
  (5) LOCAL_C_INCLUDES:  路径的可选配置,是从根目录开始的所有源文件(C, C++
and Assembly)。比如:
LOCAL_C_INCLUDES := sources/foo
或者:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
 
  需要在任何包含 LOCAL_CFLAGS/LOCAL_CPPFLAGS 标志之前。
 
  (6)LOCAL_CFLAGS:  可选的编译器选项,在编译 C 代码文件的时候使用。这可能是有
用的,指定一个附加的包含路径(相对于 NDK的顶层目录),宏定义,或者编译选项。
  注意:不要在 Android.mk 中改变 optimization/debugging 级别,只要在 Application.mk 中
指定合适的信息,就会自动地为你处理这个问题,在调试期间,会让 NDK自动生成有用的数
据文件。
 
  (7)LOCAL_CXXFLAGS:  与 LOCAL_CFLAGS 相同,针对 C++源文件。
 
  (8)LOCAL_CPPFLAGS:  与 LOCAL_CFLAGS 相同,但是对 C 和 C++ source files都适
用。
 
  (9)LOCAL_STATIC_LIBRARIES:  应该链接到这个模块的静态库列表(使用
BUILD_STATIC_LIBRARY 生成),这仅仅对共享库模块才有意义。
 
  (10)LOCAL_SHARED_LIBRARIES:  这个模块在运行时要依赖的共享库模块列表,在
链接时需要,在生成文件时嵌入的相应的信息。注意:这不会附加列出的模块到编译图,也
就是仍然需要在 Application.mk 中把它们添加到程序要求的模块中。
 
  (11)LOCAL_LDLIBS:  编译模块时要使用的附加的链接器选项。这对于使用‘-l’前缀
传递指定库的名字是有用的。例如,下面将告诉链接器生成的模块要在加载时刻链接到
/system/lib/libz.so
LOCAL_LDLIBS := -lz
 
  可查看 docs/STABLE-APIS.TXT 获取使用 NDK发行版能链接到的开放的系统库列表。
 
  (12) LOCAL_ALLOW_UNDEFINED_SYMBOLS:  默认情况下,在试图编译一个共享库时,
任何未定义的引用将导致一个“未定义的符号”错误。这对于在源代码文件中捕捉错误会有
很大的帮助。然而,如果因为某些原因,需要不启动这项检查,可把这个变量设为‘true’。
注意相应的共享库可能在运行时加载失败。(这个一般尽量不要去设为 true)。
 
  (13) LOCAL_ARM_MODE: 默认情况下, arm目标二进制会以 thumb 的形式生成(16 位),
你可以通过设置这个变量为 arm如果你希望你的 module 是以 32 位指令的形式。
'arm' (32-bit instructions) mode. E.g.:
LOCAL_ARM_MODE := arm
【注意:同样可以在编译的时候告诉系统编译特定的类型】
  Android.mk 文档规范 5
(14)LOCAL_SRC_FILES := foo.c bar.c.arm  这样就告诉系统总是将 bar.c 以
arm的模式编译,下面是 GNU Make‘功能’宏,必须通过使用'$(call  )'来求值,他们返
回文本化的信息。
 
  (15)my-dir:返回当前 Android.mk 所在的目录路径,相对于 NDK 编译系统的顶层。
这是有用的,在 Android.mk 文件的开头如此定义:
LOCAL_PATH := $(call my-dir)
 
(16)all-subdir-makefiles: 返回一个位于当前'my-dir'路径的子目录列表。例
如,看下面的目录层次:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
  如果 sources/foo/Android.mk 包含一行:
include $(call all-subdir-makefiles)
那么它就会自动包含 sources/foo/lib1/Android.mk 和 sources/foo/lib2/Android.mk。这项功
能用于向编译系统提供深层次嵌套的代码目录层次。注意,在默认情况下,NDK 将会只搜索
在 sources/*/Android.mk 中的文件。
 
(17)this-makefile:  返回当前Makefile 的路径(即这个函数调用的地方)
 
(18)parent-makefile:  返回调用树中父 Makefile 路径。即包含当前 Makefile 的
Makefile 路径。
 
(19)grand-parent-makefile
3. Android.mk 使用模板
  在一个 Android.mk 中可以生成多个可执行程序、动态库和静态库。
(1)编译应用程序的模板:
#Test Exe
 
LOCAL_PATH := $(call my-dir)
 
#include $(CLEAR_VARS)
 
LOCAL_SRC_FILES := main.c
 
LOCAL_MODULE := test_exe
 
#LOCAL_C_INCLUDES :=
 
#LOCAL_STATIC_LIBRARIES :=
 
#LOCAL_SHARED_LIBRARIES :=
 
include $(BUILD_EXECUTABLE)
  【注:‘:=’是赋值的意思,‘$’是引用某变量的值】
LOCAL_SRC_FILES 中加入源文件路径,LOCAL_C_INCLUDES 中加入所需要包含的头
文件路径,LOCAL_STATIC_LIBRARIES 加入所需要链接的静态库(*.a)的名称,
LOCAL_SHARED_LIBRARIES 中加入所需要链接的动态库(*.so)的名称,LOCAL_MODULE Android.mk 文档规范 6
表示模块最终的名称,BUILD_EXECUTABLE 表示以一个可执行程序的方式进行编译。
(2)编译静态库的模板:
#Test Static Lib
LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_SRC_FILES := \
 helloworld.c
 
LOCAL_MODULE:= libtest_static
 
#LOCAL_C_INCLUDES :=
 
#LOCAL_STATIC_LIBRARIES :=
 
#LOCAL_SHARED_LIBRARIES :=
 
include $(BUILD_STATIC_LIBRARY)
 
  和上面相似,BUILD_STATIC_LIBRARY 表示编译一个静态库。
(3)编译动态库的模板:
#Test Shared Lib
 
LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_SRC_FILES := helloworld.c
 
LOCAL_MODULE := libtest_shared
 
TARGET_PRELINK_MODULES := false
 
#LOCAL_C_INCLUDES :=
 
#LOCAL_STATIC_LIBRARIES :=
 
#LOCAL_SHARED_LIBRARIES :=
 
include $(BUILD_SHARED_LIBRARY)
 
  和上面相似,BUILD_SHARED_LIBRARY 表示编译一个共享库。
  以上三者的生成结果分别在如下目录中,generic 依具体 target 会变:
out/target/product/generic/obj/EXECUTABLE
out/target/product/generic/obj/STATIC_LIBRARY
out/target/product/generic/obj/SHARED_LIBRARY
 
  每个模块的目标文件夹分别为:
 1)可执行程序:XXX_intermediates
 2)静态库: XXX_static_intermediates
 3)动态库: XXX_shared_intermediates
 
  另外, 在 Android.mk 文件中, 还可以指定最后的目标安装路径, 用 LOCAL_MODULE_PATH Android.mk 文档规范 7
和 LOCAL_UNSTRIPPED_PATH 来指定。不同的文件系统路径用以下的宏进行选择:
  TARGET_ROOT_OUT:表示根文件系统。
   TARGET_OUT:表示 system文件系统。
   TARGET_OUT_DATA:表示 data文件系统。
用法如:
LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT) 

posted @ 2012-09-26 09:09 树袋熊TRK 阅读(17) 评论(0)  编辑

 2012年9月17日

1、GCC

posted @ 2012-09-17 15:23 树袋熊TRK 阅读(4) 评论(0)  编辑

 2012年9月11日

原文链接:http://www.chinaz.com/server/2009/0807/85792.shtml

Linux环境下的软件安装,并不是一件容易的事情;如果通过源代码编译后在安装,当然事情就更为复杂一些;现在安装各种软件的教程都非常普遍;但万变不离其中,对基础知识的扎实掌握,安装各种软件的问题就迎刃而解了。Configure脚本配置工具就是基础之一,它是autoconf的工具的基本应用。

与一些技巧相比,Configure显得基础一些,当然使用和学习起来就显得枯燥乏味一些,当然要成为高手,对基础的熟悉不能超越哦。

为此我转载了一篇关于Configure选项配置的详细介绍。供大家参考

'configure'脚本有大量的命令行选项.对不同的软件包来说,这些选项可能会有变化,但是许多基本的选项是不会改变的.带上'--help'选项执行'configure'脚本可以看到可用的所有选项.尽管许多选项是很少用到的,但是当你为了特殊的需求而configure一个包时,知道他们的存在是很有益处的.下面对每一个选项进行简略的介绍:

--cache-file=FILE

'configure'会在你的系统上测试存在的特性(或者bug!).为了加速随后进行的配置,测试的结果会存储在一个cache file里.当configure一个每个子树里都有'configure'脚本的复杂的源码树时,一个很好的cache file的存在会有很大帮助.

--help

输出帮助信息.即使是有经验的用户也偶尔需要使用使用'--help'选项,因为一个复杂的项目会包含附加的选项.例如,GCC包里的'configure'脚本就包含了允许你控制是否生成和在GCC中使用GNU汇编器的选项.

--no-create

'configure'中的一个主要函数会制作输出文件.此选项阻止'configure'生成这个文件.你可以认为这是一种演习(dry run),尽管缓存(cache)仍然被改写了.

--quiet

--silent

当'configure'进行他的测试时,会输出简要的信息来告诉用户正在作什么.这样作是因为'configure'可能会比较慢,没有这种输出的话用户将会被扔在一旁疑惑正在发生什么.使用这两个选项中的任何一个都会把你扔到一旁.(译注:这两句话比较有意思,原文是这样的:If there was no such output, the user would be left wondering what is happening. By using this option, you too can be left wondering!)

--version

打印用来产生'configure'脚本的Autoconf的版本号.

--prefix=PEWFIX

'--prefix'是最常用的选项.制作出的'Makefile'会查看随此选项传递的参数,当一个包在安装时可以彻底的重新安置他的结构独立部分. 举一个例子,当安装一个包,例如说Emacs,下面的命令将会使Emacs Lisp file被安装到"/opt/gnu/share":

$ ./configure --prefix=/opt/gnu

--exec-prefix=EPREFIX

与'--prefix'选项类似,但是他是用来设置结构倚赖的文件的安装位置.编译好的'emacs'二进制文件就是这样一个问件.如果没有设置这个选项的话,默认使用的选项值将被设为和'--prefix'选项值一样.

--bindir=DIR

指定二进制文件的安装位置.这里的二进制文件定义为可以被用户直接执行的程序.

--sbindir=DIR

指定超级二进制文件的安装位置.这是一些通常只能由超级用户执行的程序.

--libexecdir=DIR

指定可执行支持文件的安装位置.与二进制文件相反,这些文件从来不直接由用户执行,但是可以被上面提到的二进制文件所执行.

--datadir=DIR

指定通用数据文件的安装位置.

--sysconfdir=DIR

指定在单个机器上使用的只读数据的安装位置.

--sharedstatedir=DIR

指定可以在多个机器上共享的可写数据的安装位置.

--localstatedir=DIR

指定只能单机使用的可写数据的安装位置.

--libdir=DIR

指定库文件的安装位置.

--includedir=DIR

指定C头文件的安装位置.其他语言如C++的头文件也可以使用此选项.

--oldincludedir=DIR

指定为除GCC外编译器安装的C头文件的安装位置.

--infodir=DIR

指定Info格式文档的安装位置.Info是被GNU工程所使用的文档格式.

--mandir=DIR

指定手册页的安装位置.

--srcdir=DIR

这个选项对安装没有作用.他会告诉'configure'源码的位置.一般来说不用指定此选项,因为'configure'脚本一般和源码文件在同一个目录下.

--program-prefix=PREFIX

指定将被加到所安装程序的名字上的前缀.例如,使用'--program-prefix=g'来configure一个名为'tar'的程序将会使安装的程序被命名为'gtar'.当和其他的安装选项一起使用时,这个选项只有当他被`Makefile.in'文件使用时才会工作.

--program-suffix=SUFFIX

指定将被加到所安装程序的名字上的后缀.

--program-transform-name=PROGRAM

这里的PROGRAM是一个sed脚本.当一个程序被安装时,他的名字将经过`sed -e PROGRAM'来产生安装的名字.

--build=BUILD

指定软件包安装的系统平台.如果没有指定,默认值将是'--host'选项的值.

--host=HOST

指定软件运行的系统平台.如果没有指定,将会运行`config.guess'来检测.

--target=GARGET

指定软件面向(target to)的系统平台.这主要在程序语言工具如编译器和汇编器上下文中起作用.如果没有指定,默认将使用'--host'选项的值.

--disable-FEATURE

一些软件包可以选择这个选项来提供为大型选项的编译时配置,例如使用Kerberos认证系统或者一个实验性的编译器最优配置.如果默认是提供这些特性,可以使用'--disable-FEATURE'来禁用它,这里'FEATURE'是特性的名字.例如:

$ ./configure --disable-gui

-enable-FEATURE[=ARG]

相反的,一些软件包可能提供了一些默认被禁止的特性,可以使用'--enable-FEATURE'来起用它.这里'FEATURE'是特性的名字.一个特性可能会接受一个可选的参数.例如:

$ ./configure --enable-buffers=128

`--enable-FEATURE=no'与上面提到的'--disable-FEATURE'是同义的.

--with-PACKAGE[=ARG]

在自由软件社区里,有使用已有软件包和库的优秀传统.当用'configure'来配置一个源码树时,可以提供其他已经安装的软件包的信息.例如,倚赖于Tcl和Tk的BLT器件工具包.要配置BLT,可能需要给'configure'提供一些关于我们把Tcl和Tk装的何处的信息:

$ ./configure --with-tcl=/usr/local --with-tk=/usr/local

'--with-PACKAGE=no'与下面将提到的'--without-PACKAGE'是同义的.

--without-PACKAGE

有时候你可能不想让你的软件包与系统已有的软件包交互.例如,你可能不想让你的新编译器使用GNU ld.通过使用这个选项可以做到这一点:

$ ./configure --without-gnu-ld

--x-includes=DIR

这个选项是'--with-PACKAGE'选项的一个特例.在Autoconf最初被开发出来时,流行使用'configure'来作为Imake的一个变通方法来制作运行于X的软件.'--x-includes'选项提供了向'configure'脚本指明包含X11头文件的目录的方法.

--x-libraries=DIR

类似的,'--x-libraries'选项提供了向'configure'脚本指明包含X11库的目录的方法.

在源码树中运行'configure'是不必要的同时也是不好的.一个由'configure'产生的良好的'Makefile'可以构筑源码属于另一棵树的软件包.在一个独立于源码的树中构筑派生的文件的好处是很明显的:派生的文件,如目标文件,会凌乱的散布于源码树.这也使在另一个不同的系统或用不同的配置选项构筑同样的目标文件非常困难.建议使用三棵树:一棵源码树(source tree),一棵构筑树(build tree),一棵安装树(install tree).这里有一个很接近的例子,是使用这种方法来构筑GNU malloc包:

$ gtar zxf mmalloc-1.0.tar.gz

$ mkdir build && cd build

$ ../mmalloc-1.0/configure

creating cache ./config.cache

checking for gcc... gcc

checking whether the C compiler (gcc ) works... yes

checking whether the C compiler (gcc ) is a cross-compiler... no

checking whether we are using GNU C... yes

checking whether gcc accepts -g... yes

checking for a BSD compatible install... /usr/bin/install -c

checking host system type... i586-pc-linux-gnu

checking build system type... i586-pc-linux-gnu

checking for ar... ar

checking for ranlib... ranlib

checking how to run the C preprocessor... gcc -E

checking for unistd.h... yes

checking for getpagesize... yes

checking for working mmap... yes

checking for limits.h... yes

checking for stddef.h... yes

updating cache ../config.cache

creating ./config.status

这样这棵构筑树就被配置了,下面可以继续构筑和安装这个包到默认的位置'/usr/local':

$ make all && make install

一个软件包通过编译源代码安装后,如何完全的卸载??

如果原先的source还在的话,很多source的Makefile都有写uninstall规则,直接在Souce里make uninstall就可行,不过碰到无良作者没写的,那一句一句看Makefile里install部分他都干了些什么,然后挨个删除。

如果source没了.....那就一边郁闷吧

到目前为止, 我装的都可以make uninstall.......

(因为总是不小心装错地方, 结果就make uninstall&&make clean,然后重新configure......)

linux下软件的基本安装和卸载

Linux软件的安装和卸载一直是困扰许多新用户的难题。在Windows中,我们可以使用软件自带的安装卸载程序或在控制面板中的“添加/删除程序”来实现。与其相类似,在Linux下有一个功能强大的软件安装卸载工具,名为RPM。它可以用来建立、安装、查询、更新、卸载软件。该工具是在命令行下使用的。在Shell的提示符后输入rpm,就可获得该命令的帮助信息。

软件的安装

Linux下软件的安装主要有两种不同的形式。第一种安装文件名为xxx.tar.gz;另一种安装文件名为xxx.i386.rpm。以第一种方式发行的软件多为以源码形式发送的;第二种方式则是直接以二进制形式发送的。

对于第一种,安装方法如下:

1 .首先,将安装文件拷贝至你的目录中。例如,如果你是以root身份登录上的,就将软件拷贝至/root中。

#cp xxx.tar.gz /root

2 .由于该文件是被压缩并打包的,应对其解压缩。命令为:

#tar xvzf filename.tar.gz 如果是filename.tar.bz2格式的,应该是tar jxvf filename.tar.bz2来解压

3. 执行该命令后,安装文件按路径,解压缩在当前目录下。用ls命令可以看到解压缩后的文件。通常在解压缩后产生的文件中,有“Install”的文件。该文件为纯文本文件,详细讲述了该软件包的安装方法。

4.执行解压缩后产生的一个名为configure的可执行脚本程序。它是用于检查系统是否有编译时所需的库,以及库的版本是否满足编译的需要等安装所需要的系统信息。为随后的编译工作做准备。命令为: #./configure

如果您想把软件安装到指定目录,应该用#./configure --prefix=/您自己指定的目录,比如我想把一个mlterm安装到/opt/mlterm目录中,应该如下输入

#./configure --prefix=/opt/mlterm

5.检查通过后,将生成用于编译的MakeFile文件。此时,可以开始进行编译了。编译的过程视软件的规模和计算机性能的不同,所耗费的时间也不同。命令为: #make。

6.成功编译后,键入如下的命令开始安装:

#make install

7.安装完毕,应清除编译过程中产生的临时文件和配置过程中产生的文件。键入如下命令:

#make clean

#make distclean

至此,软件的安装结束。

对于第二种,其安装方法要简单得多。

同第一种方式一样,将安装文件拷贝至你的目录中。然后使用rpm来安装该文件。命令如下:

#rpm -i filename.i386.rpm

rpm将自动将安装文件解包,并将软件安装到缺省的目录下。并将软件的安装信息注册到rpm的数据库中。参数i的作用是使rpm进入安装模式。

软件的卸载

1.软件的卸载主要是使用rpm来进行的。卸载软件首先要知道软件包在系统中注册的名称。键入命令:

#rpm -q -a

即可查询到当前系统中安装的所有的软件包。

2. 确定了要卸载的软件的名称,就可以开始实际卸载该软件了。键入命令:

#rpm -e [package name]

即可卸载软件。参数e的作用是使rpm进入卸载模式。对名为[package name]的软件包进行卸载。由于系统中各个软件包之间相互有依赖关系。如果因存在依赖关系而不能卸载,rpm将给予提示并停止卸载。你可以使用如下的命令来忽略依赖关系,直接开始卸载:

#rpm -e [package name] -nodeps

忽略依赖关系的卸载可能会导致系统中其它的一些软件无法使用

如果想知道rpm包安装到哪里了呢?

应该用 #rpm -ql [package name]

3.如何卸载用源码包安装的软件?

最好是看README和INSTALL ;一般的情况下都有说,但大多软件没有提供源码包的卸载方法;我们可以找到软件的安装点删除。主要看你把它安装在哪了。

比如:

如果安装软件时,指定个目录。这个问题也不会难;

比如用源码包安装gaim 的

#./configure --prefix=/opt/gaim

#make

#make install

如果安装mlterm

#./configure --prefix=/opt/mlterm

#make

#make install

把源码包安装的软件,都指定安装在 /opt目录中,这样不就知道了??

如果删除,就删除相应的软件目录;

有些软件要在解压安装目录中执行 make uninstall ,这样就卸载掉了

posted @ 2012-09-11 12:56 树袋熊TRK 阅读(9) 评论(0)  编辑

1、需要编译的Linux软件源码都有说明,安装方法不尽相同。通常编译方法是: 
    ./configure 
    make 
    make install 
其中:configure脚本配置工具是autoconf工具的基本应用,主要的作用是对即将安装的软件进行配置,检查当前的环境是否满足要安装软件的依赖关系,生成makefile文件;通过【./configure --help】可查看一些帮助。基本上每一个源码包在发布的时候都会带一些文档,如README、INSTALL,一般在里面详细介绍了如何安装,以及注意事项。

2、部分软件有安装脚本,一般输入【sh ***.sh】安装。

3、部分软件是二进制代码形式,如googlearth、realplay for linux等。对于realplay安装方法如下: 
    # su 
    # chmod +x 文件名.bin 
    # ./文件名.bin

4、对于rpm或deb格式,双击即可安装,或在终端输入: 
    rpm -ivh ***.rpm 
    dpkg -i ***.deb

posted @ 2012-09-11 11:32 树袋熊TRK 阅读(5) 评论(0)  编辑
1、安装增强功能包(VBoxGuestAdditions)
  利用虚拟机共享的虚拟光驱加载虚拟机的安装目录下 VBoxGuestAdditions.iso文件。
  运行Ubuntu,在光驱下就会有VBoxGuestAdditions镜像,打开镜像并运行autorun.sh安装,安装完毕后会提示重启Ubuntu。

2、设置共享文件夹
  有两种设置共享文件夹的方法:a) 运行Ubuntu前对其进行设置,打开设置选项-数据空间,加载一个共享文件夹,如D:\games;b) 在Ubuntu已经运行时加载,在Ubuntu界面的右下角有一个文件夹选,右击可以加载。

3、挂载共享文件夹
  重新进入虚拟Ubuntu,在命令行终端下输入:
    sudo mkdir /mnt/share
    sudo mount -t vboxsf games/mnt/shared
  其中:"games"是之前创建的共享文件夹的名字。现在Ubuntu和主机可以互传文件了。假如您不想每一次都手动挂载,可以在/etc/fstab中添加一项
    games /mnt/share vboxsf rw,gid=100,uid=1000,auto 0 0
这样就能够自动挂载了。

4、卸载的话使用下面的命令:
    sudo umount -f /mnt/share
注意:
  共享文件夹的名称千万不要和挂载点的名称相同。比如,上面的挂载点是/mnt/shared,如果共享文件夹的名字也是shared的话,在挂载的时候就会出现如下的错误信息(看 http://www.virtualbox.org/ticket/2265):
    /sbin/mount.vboxsf: mounting failed with the error: Protocol error
posted @ 2012-09-11 10:54 树袋熊TRK 阅读(28) 评论(0)  编辑

 2012年9月10日

原文地址:http://www.cnblogs.com/scottwong/archive/2010/12/17/1909455.html

  最近在做 Android 上的项目,我被恶心的一塌糊涂。本以为 Java 是 Android 上的一等公民,结果深入学习之后才发现,Java 在 Android 上 就是个做 UI 的,除此之外无论想干什都得用 C 语言去实现。Android 一个非常糟糕差劲的操作系统,甚至连 Windows Mobile 都不如。Android 能取得今天的市场占有率只是因为当年微软的 Window Phone 7 还在开发中,而 iOS 又只给 iPhone用,所以手机生产商没得选,只能被迫采用 Android 这个连 Linux 内核开发团队都不承认的 Linux 操作系统。而基于 Linux 内核就是 Android 唯一的优点了,正是因为如此我们才想办法能把那些 Linux 上的伟大开源项目移植到 Android 上以弥补 Android 的不足。

  Android 的多媒体功能是如此之弱,限制是如此之多,逼着我只能想办法去把 FFmpeg 移植到 Android 上。 感谢 havlenapetr 给出的示例代码,感谢 ABitNo 整理的说明文档,没有他们的贡献,我不可能把 FFmpeg 成功移植到 Android 上。下面我将说明将 FFmpeg 移植到 Android 上的详细步骤,希望能对正在进行同样工作的朋友有所帮助。

一、下载必要软件

Oracle VM VirtualBox 3.2.12

Ubuntu Desktop Edition 10.10 32-bit

Android NDK r4b (需要越墙访问)

Android NDK r5 (需要越墙访问)

FFmpeg 0.6.1

二、配置编译环境

  1. 在 VirtualBox 中创建一个 Ubuntu 虚拟机
  2. 在 Ubuntu 虚拟机中使用 sudo passwd root 命令启动 root 账户
  3. 用 root 账户登录进入 Ubuntu
  4. 将 android-ndk-r4b-linux-x86.zip 中的内容解压缩到 /root 目录下
  5. 将 android-sdk_r07-linux_x86.tgz 中的内容解压缩到 /root 目录下
  6. 将 ffmpeg-0.6.1.tar.bz2 中的内容解压缩到 /root/ffmpeg/jni 目录下

三、准备编译 FFmpeg

  1. 编写 mk 文件
    1. 在 /root/ffmpeg/jni 目录中创建一个 Android.mk 文件,内容如下
      include $(all-subdir-makefiles)
    2. 在 /root/ffmpeg/jni/ffmpeg-0.6.1 目录中创建一个 Android.mk 文件,内容如下
      LOCAL_PATH := $(call my-dir)
      include $(CLEAR_VARS)
      LOCAL_WHOLE_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale
      LOCAL_MODULE := ffmpeg
      include $(BUILD_SHARED_LIBRARY)
      include $(call all-makefiles-under,$(LOCAL_PATH))
    3. 在 /root/ffmpeg/jni/ffmpeg-0.6.1 目录中创建一个 av.mk 文件,内容如下

      # LOCAL_PATH is one of libavutil, libavcodec, libavformat, or libswscale

      #include $(LOCAL_PATH)/../config-$(TARGET_ARCH).mak
      include $(LOCAL_PATH)/../config.mak

      OBJS :=
      OBJS-yes :=
      MMX-OBJS-yes :=
      include $(LOCAL_PATH)/Makefile

      # collect objects
      OBJS-$(HAVE_MMX) += $(MMX-OBJS-yes)
      OBJS += $(OBJS-yes)

      FFNAME := lib$(NAME)
      FFLIBS := $(foreach,NAME,$(FFLIBS),lib$(NAME))

      FFCFLAGS  = -DHAVE_AV_CONFIG_H -Wno-sign-compare -Wno-switch -Wno-pointer-sign
      FFCFLAGS += -DTARGET_CONFIG=\"config-$(TARGET_ARCH).h\"

      ALL_S_FILES := $(wildcard $(LOCAL_PATH)/$(TARGET_ARCH)/*.S)
      ALL_S_FILES := $(addprefix $(TARGET_ARCH)/, $(notdir $(ALL_S_FILES)))

      ifneq ($(ALL_S_FILES),)
      ALL_S_OBJS := $(patsubst %.S,%.o,$(ALL_S_FILES))
      C_OBJS := $(filter-out $(ALL_S_OBJS),$(OBJS))
      S_OBJS := $(filter $(ALL_S_OBJS),$(OBJS))
      else
      C_OBJS := $(OBJS)
      S_OBJS :=
      endif

      C_FILES := $(patsubst %.o,%.c,$(C_OBJS))
      S_FILES := $(patsubst %.o,%.S,$(S_OBJS))

      FFFILES := $(sort $(S_FILES)) $(sort $(C_FILES))

    4. 在 /root/ffmpeg/jni/ffmpeg-0.6.1/libavcodec 目录中创建一个 Android.mk 文件,内容如下
      LOCAL_PATH := $(call my-dir)
      include $(CLEAR_VARS)
      include $(LOCAL_PATH)/../av.mk
      LOCAL_SRC_FILES := $(FFFILES)
      LOCAL_C_INCLUDES :=        \
          $(LOCAL_PATH)        \
          $(LOCAL_PATH)/..
      LOCAL_CFLAGS += $(FFCFLAGS)
      LOCAL_LDLIBS := -lz
      LOCAL_STATIC_LIBRARIES := $(FFLIBS)
      LOCAL_MODULE := $(FFNAME)
      include $(BUILD_STATIC_LIBRARY)
    5. 在 /root/ffmpeg/jni/ffmpeg-0.6.1/libavformat 目录中创建一个 Android.mk 文件,内容如下
      LOCAL_PATH := $(call my-dir)
      include $(CLEAR_VARS)
      include $(LOCAL_PATH)/../av.mk
      LOCAL_SRC_FILES := $(FFFILES)
      LOCAL_C_INCLUDES :=        \
          $(LOCAL_PATH)        \
          $(LOCAL_PATH)/..
      LOCAL_CFLAGS += $(FFCFLAGS)
      LOCAL_CFLAGS += -include "string.h"
      
       -Dipv6mr_interface=ipv6mr_ifindex
      LOCAL_LDLIBS := -lz
      LOCAL_STATIC_LIBRARIES := $(FFLIBS)
      LOCAL_MODULE := $(FFNAME)
      include $(BUILD_STATIC_LIBRARY)
    6. 在 libavfilter、libavutil、libpostproc 和 libswscale 目录中各创建一个 Android.mk 文件,内容如下
      LOCAL_PATH := $(call my-dir)
      include $(CLEAR_VARS)
      include $(LOCAL_PATH)/../av.mk
      LOCAL_SRC_FILES := $(FFFILES)
      LOCAL_C_INCLUDES :=        \
          $(LOCAL_PATH)        \
          $(LOCAL_PATH)/..
      LOCAL_CFLAGS += $(FFCFLAGS)
      LOCAL_STATIC_LIBRARIES := $(FFLIBS)
      LOCAL_MODULE := $(FFNAME)
      include $(BUILD_STATIC_LIBRARY)
  2. 修改 libm.h 文件和 Makefile 文件
    1. 编辑 /root/ffmpeg/jni/ffmpeg-0.6.1/libavutil 目录中的 libm.h 文件,删除以下 static 方法
      #if
      
       !HAVE_LRINT
      static
      
       av_always_inline av_const long
      
       int
      
       lrint(double
      
       x)
      {
          return
      
       rint(x);
      }
      #endif
      
       /* HAVE_LRINT */
      
      
      
      #if
      
       !HAVE_LRINTF
      static
      
       av_always_inline av_const long
      
       int
      
       lrintf(float
      
       x)
      {
          return
      
       (int
      
      )(rint(x));
      }
      #endif
      
       /* HAVE_LRINTF */
      
      
      
      #if
      
       !HAVE_ROUND
      static
      
       av_always_inline av_const double
      
       round(double
      
       x)
      {
          return
      
       (x > 0) ? floor(x + 0.5) : ceil(x - 0.5);
      }
      #endif
      
       /* HAVE_ROUND */
      
      
      
      #if
      
       !HAVE_ROUNDF
      static
      
       av_always_inline av_const float
      
       roundf(float
      
       x)
      {
          return
      
       (x > 0) ? floor(x + 0.5) : ceil(x - 0.5);
      }
      #endif
      
       /* HAVE_ROUNDF */
      
      
      
      #if
      
       !HAVE_TRUNCF
      static
      
       av_always_inline av_const float
      
       truncf(float
      
       x)
      {
          return
      
       (x > 0) ? floor(x) : ceil(x);
      }
      #endif
      
       /* HAVE_TRUNCF */
      
      
    2. 编辑 libavcodec、libavfilter、libavformat、libavutil、libpostproc 和 libswscale 目录中的 Makefile 文件,删除
      include $(SUBDIR)../subdir.mak
      include $(SUBDIR)../config.mak
  3. 生成 config.h 文件
    1. 在 /root/ffmpeg/jni/ffmpeg-0.6.1 目录中创建一个 config.sh 文件,使用 Android NDK r4b 编译时内容如下
      PREBUILT=/root/android-ndk-r4b/build/prebuilt/linux-x86/arm-eabi-4.4.0
      PLATFORM=/root/android-ndk-r4b/build/platforms/android-8/arch-arm
      
      ./configure --target-os=linux \
          --arch=arm \
          --enable-version3 \
          --enable-gpl \
          --enable-nonfree \
          --disable-stripping \
          --disable-ffmpeg \
          --disable-ffplay \
          --disable-ffserver \
          --disable-ffprobe \
          --disable-encoders \
          --disable-muxers \
          --disable-devices \
          --disable-protocols \
          --enable-protocol=file \
          --enable-avfilter \
          --disable-network \
          --disable-mpegaudio-hp \
          --disable-avdevice \
          --enable-cross-compile \
          --cc=$PREBUILT/bin/arm-eabi-gcc \
          --cross-prefix=$PREBUILT/bin/arm-eabi- \
          --nm=$PREBUILT/bin/arm-eabi-nm \
          --extra-cflags="-fPIC -DANDROID"
      
       \
          --disable-asm
      
       \
          --enable-neon \
          --enable-armv5te \
          --extra-ldflags="-Wl,-T,$PREBUILT/arm-eabi/lib/ldscripts/armelf.x -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtbegin.o $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtend.o -lc -lm -ldl"
      
      
      使用 Android NDK r5 编译时内容如下
      #!/bin/bash
      
      PREBUILT=/root/android-ndk-r5/toolchains/arm-eabi-4.4.0/prebuilt/linux-x86
      PLATFORM=/root/android-ndk-r5/platforms/android-8/arch-arm
      
      ./configure --target-os=linux \
          --arch=arm \
          --enable-version3 \
          --enable-gpl \
          --enable-nonfree \
          --disable-stripping \
          --disable-ffmpeg \
          --disable-ffplay \
          --disable-ffserver \
          --disable-ffprobe \
          --disable-encoders \
          --disable-muxers \
          --disable-devices \
          --disable-protocols \
          --enable-protocol=file \
          --enable-avfilter \
          --disable-network \
          --disable-mpegaudio-hp \
          --disable-avdevice \
          --enable-cross-compile \
          --cc=$PREBUILT/bin/arm-eabi-gcc \
          --cross-prefix=$PREBUILT/bin/arm-eabi- \
          --nm=$PREBUILT/bin/arm-eabi-nm \
          --extra-cflags="-fPIC -DANDROID"
      
       \
          --disable-asm
      
       \
          --enable-neon \
          --enable-armv5te \
          --extra-ldflags="-Wl,-T,$PREBUILT/arm-eabi/lib/ldscripts/armelf.x -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtbegin.o $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtend.o -lc -lm -ldl"
      
      
    2. 打开终端,进入 /root/ffmpeg/jni/ffmpeg-0.6.1 目录,运行下面的命令
      chmod +x config.sh
      ./config.sh
    3. 编辑 /root/ffmpeg/jni/ffmpeg-0.6.1 目录中的 config.h 文件,因为Android的GCC不支持restrict关键字,故将
      #define
      
       restrict restrict
      修改为
      #define
      
       restrict

四、开始编译 FFmpeg

很多人在用 havlenapetr 的方法编译 FFmpeg 时只得到一个 1599 字节 1.6KB 大小的 libffmpeg.so 文件,无论是用 Android NDK r4b 编译还是用 Android NDK r5 编译结果都是如此,很让人抓狂。我也很郁闷,最后花时间研究了一下 NDK,终于发现了解决方法,而且 Android NDK r4b 和 Android NDK r5  的情况还是完全不同的,请继续往下读。

  1. 使用 Android NDK r4b 编译

    打开 android-ndk-r4b/build/toolchains/arm-eabi-4.4.0 目录中的 setup.mk 文件,你会发现 Google 在里面定义了一个用于编译动态库的 cmd-build-shared-library 函数。在cmd-build-shared-library 函数中 Google 使用了 PRIVATE_WHOLE_STATIC_LIBRARIES 函数。但是你在 android-ndk-r4b/build/core 目录中的 build-binary.mk 文件里却找不到 PRIVATE_WHOLE_STATIC_LIBRARIES 函数…… 外?WHY?终于搞清楚了,原来得不到正确的 libffmpeg.so 文件不是我的错,而是 Android NDK r4b 的 BUG!你妹啊!你大爷啊!坑爹呢这是!发布前不做测试吗!居然漏掉一个函数!!!(我敢说这是个 BUG 是因为 Google 在 Android NDK r5 中修复了这个 BUG)

    木办法,只好手动替 Google 修补这个 BUG。好在修改方法很简单,只需要照 build-binary.mk 文件里的 PRIVATE_STATIC_LIBRARIES 增加一个 PRIVATE_WHOLE_STATIC_LIBRARIES 就行了。具体方法见下图

    修改前的 build-binary.mk 文件 
    image

    修改后的 build-binary.mk 文件 
    image

    保存 build-binary.mk 文件之后,运行下面的命令编译

    /root/android-ndk-r4b/ndk-build NDK_PROJECT_PATH=/root/ffmpeg

    接着你会看到 warning 不停的出现在屏幕上,熬过这段心惊肉跳的时间之后,你会看到 libffmpeg.so 文件已经被编译生成了。


    image

    看看 /root/ffmpeg/obj/local/armeabi 目录中的 libffmpeg.so 文件,文件大小是 12.2MB 

    image

    再看看 /root/ffmpeg/libs/local/armeabi 目录中的 libffmpeg.so 文件,文件大小是 3.2MB

    image
  2. 使用 Android NDK r5 编译

    打开 android-ndk-r5/build/core 目录中的 build-binary.mk 文件,发现 Google 这次没有忘记 PRIVATE_WHOLE_STATIC_LIBRARIES,但还最后编译得到的 libffmpeg.so 文件大小还是不正确。 这次的问题是,android-ndk-r5 默认是使用 arm-linux-androideabi-4.4.3 编译,而不是 arm-eabi-4.4.0。但 android-ndk-r5/toolchains/arm-linux-androideabi-4.4.3 目录中的 setup.mk 文件里定义的  cmd-build-shared-library 函数并没有将静态库文件链接在一起生成动态库文件。所以解决的办法就是在执行 ndk-build 时加上 NDK_TOOLCHAIN 参数,指定使用 arm-eabi-4.4.0 来编译。完整命令如下

    /root/android-ndk-r5/ndk-build NDK_PROJECT_PATH=/root/ffmpeg NDK_TOOLCHAIN=arm-eabi-4.4.0 NDK_PLATFORM=android-8

五、结语

  关于如何编写在 Android 上运行的 FFmpeg 播放器,请看 havlenapetr/FFMpeg 、tewilove/faplayer 、NicoRo 和 android / ffmpeg dynamic module, JNI simple wrapper (需要越墙访问)

  希望我的这篇随笔能对读到这里你有帮助。

posted @ 2012-09-10 17:37 树袋熊TRK 阅读(69) 评论(0)  编辑

移植ffmpeg到windows,主要修改的是ffmpeg中VC6不支持的C99语法,简单移植步骤如下:

1、首先装好Linux、VMware和SDL,配置好smb,在Linux下编译通过,验证能正确的运行。

2、将Linux下相应目录的所有文件通过smb拖到Windows,以后的修改移植都在Windows下进行。

3、对照所有同名的.c文件和.o文件,如果有.c文件没有对应的同名.o文件,说明此.c文件没有编译,可直接删除(不过我的习惯是在此文件后加.old后缀来标示,这类文件有几十个)。注意:有几个.c文件是被include在其他.c文件中,因此没有.o文件,不可删除(我的习惯是把这类文件加.inc后缀,并且修改相应include的文件名)。这类文件共计有 jpeg_ls.c.inc、mdec.c.inc、motion_est_template.c.inc、svq3.c.inc和wmv2.c.inc。

4、修改config.h文件,关闭掉MMX/SSE2等汇编加速开关。定义CONFIG_WIN32标示目标系统为WIN32。

5、删掉目录下所有Linux编译生成的中间文件,包括.o文件、.d文件,还有Linux下的可执行文件。删前做好备份。

6、用VC6建一个工程文件,把所有.c和.h文件加入到工程中,不包括ffmpeg.c/ffserver.c文件,不包括改了后缀名的.old文件和.inc文件。

    注意:在libavcodec和libavformat目录下有些同名的.c文件,为区别同名.c文件,我的习惯是libavcodec目录下的文件名加_codec,libavformat目录下的文件名加_format。

7、首先搜查所有的AVCodec,对照.h文件中的定义改C99语法,通常是填一些NULL或0之类的值,接着搜查并处理所有的AVInputFormat,最后搜查并处理所有的AVOutputFormat。

8、搜查并处理所有AVRational语法。

9、至此主要的修改已经完成,剩下的工作主要是动态数组和一些数组初始化,函数实参初始化等。一维的动态数组比较好改,多维的动态数组比较困难,但是多维的动态数组多半用于编码,如果只要解码可以简单的注释掉;数组初始化和函数实参初始化只需要多加一个临时变量,很简单的修改。

10:有些.h文件在VC6中找不到,可以从Linux中拷贝,也可以自己简单定义。最后编译修改.c文件的时候,一个一个的编译,一个一个的修改,没必要全部编译。

最后祝大家好运,移植顺利。开源ffmpeg是51.8.0的版本,大约修改了5天左右。

http://files.cnblogs.com/mcodec/ffmpeg.51.8_vc6.rar

posted @ 2012-09-10 10:51 树袋熊TRK 阅读(20) 评论(0)  编辑

1、首先安装cygwin。

2、下载ffmpeg源码包:
http://ffmpeg.org/download.html


3、下载ffmpeg源码后,解压到相应目录;打开cygwin,进入ffmpeg相应目录。

4、开始编译,运行以下命令:
    ./configure --enable-memalign-hack --enable-ffserver --enable-network --enable-protocols --enable-muxers
    make
    make install


说明:

1)这次安装只是测试整个安装过程,所以配置的参数只选了最基本的;

2)在执行./configure过程中,曾经出现以下报错:
    ./configure
    ./configure: line 9: $'/r': command not found
    ./configure: line 12: $'/r': command not found
    ...
  这是因为使用SVN下载ffmpeg源码,./configure文件中的换行是'/r/n',cygwin无法识别导致的。
解决办法有几种:a)在linux下或cygwin下用svn去获取ffmpeg代码;b)使用工具替换'/r/n' -> '/n',用UltraEdit即可;c)通过google搜索以下关键词“ffmpeg configure unexpected token”。

3)在执行make命令过程中,又出现以下错误:
    line 53: syntax error near unexpected token `fi'
    line 53: `fi"

解决方法:使用 dos2unix filename
    dos2unix configure
 

4)ffmpeg yasm not found, use --disable-yasm for a crippled build 
  yasm是汇编编译器,因为ffmpeg中为了提高效率用到了汇编指令,比如MMX和SSE。解决这个问题方面有两个:a) 在网上下载一个yasm.exe并安装在mingw/bin下面,编译代码时会发现asm后缀的文件用的编译器是yasm,c文件用的是gcc;b) 不使用汇编指令,即./configure  --disable-yasm。
  yasm下载地址:http://yasm.tortall.net/Download.html
下载yasm-1.2.0-cygwin.exe,改名后放到cygwin/bin下。

 

5、编译完成

  回到Windows目录下,看到已经生成ffmpeg.exe/ffserver.exe。但是这个时候运行会报错,因为刚才我们是用动态方式编译的,所以生成的动态的dll(cygavcodec-51.dll/cygavformat-51.dll/cygavutil-49.dll)是放在类似libavcodec的目录下,所以要么加入到系统环境目录中,要么与ffmpeg.exe放在同一目录下。
  最后,也必须对cygwin的一系列dll加载到Windows的环境目录中。现在即可运行生成的ffmpeg与ffserver!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值