最近想把VP9移植到Android手机上,折腾了很久,终于搞定,现在把方法和大家共享一下。
1、操作系统Ubuntu 12.04
2、下载 android-ndk32-r10d-linux-x86_64.tar.bz2
3、安装yasm,安装方法可以网上搜索
4、下载源代码,可采用以下3种途径
a 网站:http://www.webmproject.org/
b Linux平台
git clone https://github.com/webmproject/libvpx
c 或者直接网上下载libvpx-1.4.0。(当前编译采用这个版本)
sudo gedit /etc/profile
在profile文件末尾加上如下参数:
export ARM_ROOT=/home/willman/Projects/android_tools/ndk export PATH=$ARM_ROOT:$PATH export ARM_INC=$ARM_ROOT/platforms/android-21/arch-arm/usr/include/ export ARM_LIB=$ARM_ROOT/platforms/android-21/arch-arm/usr/lib/ export ARM_TOOL=$ARM_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 export ARM_LIBO=$ARM_TOOL/lib/gcc/arm-linux-androideabi/4.9 export PATH=$ARM_TOOL/bin:$PATH export ARM_PRE=arm-linux-androideabi
装载环境变量
source /etc/profile
验证是否装载成功
ndk-build -v
进入libvpx-1.4.0文件夹后,cd build/ :
编译为Simple_encoder示例:
../configure --target=armv7-android-gcc--sdk-path=$ARM_ROOT --prefix=/usr/local/android/ --extra-cflags="-mfloat-abi=softfp -mfpu=neon" –disable-runtime-cpu-detect
如果没加 --extra-cflags="-mfloat-abi=softfp -mfpu=neon " ,可能会出现下面错误:
[CC] vp8/common/arm/neon/bilinearpredict_neon.c.oIn file included from ../libvpx/vp8/common/arm/neon/bilinearpredict_neon.c:11:0: e:\source\android\android-ndk-r9\toolchains\arm-linuxandroideabi-4.6\prebuilt\windows\bin../lib/gcc/arm-linux-androideabi/4.6/include/arm_neon.h:32:2: error:#error You must enable NEON instructions (e.g. -mfloat-abi=softfp -mfpu=neon) to use arm_neon.h../libvpx/vp8/common/arm/neon/bilinearpredict_neon.c:13:1: error: unknown type name ‘uint16_t’../libvpx/vp8/common/arm/neon/bilinearpredict_neon.c: In function ‘vp8_bilinear_predict4x4_neon’:
需要注意的是: –enable-runtime-cpu-detect(默认开启)会报错,所以如果不需要用到多线程时,可以禁用–disable-runtime-cpu-detect。此外,如果直接默认–enable-examples会报错(如果采用–disable-examples,则不会编译示例,只编译libvpx.a库文件),所以不能直接用完整示例,所以采用simple_encoder和simple_decoder这两个示例。需要对examples.mk这个文件继续修改,即删除上述两个示例之外的所有工程,修改如下:
# List ofexamples to build. UTILS are tools meant for distribution
# whileEXAMPLES demonstrate specific portions of the API.
UTILS-$(CONFIG_DECODERS) += vpxdec.c
vpxdec.SRCS += md5_utils.c md5_utils.h
vpxdec.SRCS += vpx_ports/mem_ops.h
vpxdec.SRCS += vpx_ports/mem_ops_aligned.h
vpxdec.SRCS += vpx_ports/vpx_timer.h
vpxdec.SRCS += vpx/vpx_integer.h
vpxdec.SRCS += args.c args.h
vpxdec.SRCS += ivfdec.c ivfdec.h
vpxdec.SRCS += tools_common.ctools_common.h
vpxdec.SRCS += y4menc.c y4menc.h
ifeq($(CONFIG_LIBYUV),yes)
vpxdec.SRCS += $(LIBYUV_SRCS)
endif
ifeq($(CONFIG_WEBM_IO),yes)
vpxdec.SRCS += $(LIBWEBM_PARSER_SRCS)
vpxdec.SRCS += webmdec.cc webmdec.h
endif
vpxdec.GUID =BA5FE66F-38DD-E034-F542-B1578C5FB950
vpxdec.DESCRIPTION = Full featured decoder
UTILS-$(CONFIG_ENCODERS) += vpxenc.c
vpxenc.SRCS += args.c args.h y4minput.cy4minput.h vpxenc.h
vpxenc.SRCS += ivfdec.c ivfdec.h
vpxenc.SRCS += ivfenc.c ivfenc.h
vpxenc.SRCS += rate_hist.c rate_hist.h
vpxenc.SRCS += tools_common.ctools_common.h
vpxenc.SRCS += warnings.c warnings.h
vpxenc.SRCS += vpx_ports/mem_ops.h
vpxenc.SRCS += vpx_ports/mem_ops_aligned.h
vpxenc.SRCS += vpx_ports/vpx_timer.h
vpxenc.SRCS += vpxstats.c vpxstats.h
ifeq($(CONFIG_LIBYUV),yes)
vpxenc.SRCS += $(LIBYUV_SRCS)
endif
ifeq($(CONFIG_WEBM_IO),yes)
vpxenc.SRCS += $(LIBWEBM_MUXER_SRCS)
vpxenc.SRCS += webmenc.cc webmenc.h
endif
vpxenc.GUID =548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
vpxenc.DESCRIPTION = Full featured encoder
ifeq($(CONFIG_SPATIAL_SVC),yes)
EXAMPLES-$(CONFIG_VP9_ENCODER) += vp9_spatial_svc_encoder.c
vp9_spatial_svc_encoder.SRCS += args.c args.h
vp9_spatial_svc_encoder.SRCS += ivfenc.c ivfenc.h
vp9_spatial_svc_encoder.SRCS += tools_common.c tools_common.h
vp9_spatial_svc_encoder.SRCS += video_common.h
vp9_spatial_svc_encoder.SRCS += video_writer.h video_writer.c
vp9_spatial_svc_encoder.SRCS += vpxstats.c vpxstats.h
vp9_spatial_svc_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D
vp9_spatial_svc_encoder.DESCRIPTION = VP9Spatial SVC Encoder
endif
ifneq($(CONFIG_SHARED),yes)
EXAMPLES-$(CONFIG_VP9_ENCODER) += resize_util.c
endif
EXAMPLES-$(CONFIG_ENCODERS) += vpx_temporal_svc_encoder.c
vpx_temporal_svc_encoder.SRCS += ivfenc.c ivfenc.h
vpx_temporal_svc_encoder.SRCS += tools_common.c tools_common.h
vpx_temporal_svc_encoder.SRCS += video_common.h
vpx_temporal_svc_encoder.SRCS += video_writer.h video_writer.c
vpx_temporal_svc_encoder.GUID = B18C08F2-A439-4502-A78E-849BE3D60947
vpx_temporal_svc_encoder.DESCRIPTION= Temporal SVC Encoder
EXAMPLES-$(CONFIG_DECODERS) += simple_decoder.c
simple_decoder.GUID =D3BBF1E9-2427-450D-BBFF-B2843C1D44CC
simple_decoder.SRCS += ivfdec.h ivfdec.c
simple_decoder.SRCS += tools_common.htools_common.c
simple_decoder.SRCS += video_common.h
simple_decoder.SRCS += video_reader.hvideo_reader.c
simple_decoder.SRCS += vpx_ports/mem_ops.h
simple_decoder.SRCS += vpx_ports/mem_ops_aligned.h
simple_decoder.DESCRIPTION = Simplified decoder loop
EXAMPLES-$(CONFIG_DECODERS) += postproc.c
postproc.SRCS += ivfdec.h ivfdec.c
postproc.SRCS += tools_common.htools_common.c
postproc.SRCS += video_common.h
postproc.SRCS += video_reader.hvideo_reader.c
postproc.SRCS += vpx_ports/mem_ops.h
postproc.SRCS +=vpx_ports/mem_ops_aligned.h
postproc.GUID =65E33355-F35E-4088-884D-3FD4905881D7
postproc.DESCRIPTION = Decoder postprocessor control
EXAMPLES-$(CONFIG_DECODERS) += decode_to_md5.c
decode_to_md5.SRCS += md5_utils.h md5_utils.c
decode_to_md5.SRCS += ivfdec.h ivfdec.c
decode_to_md5.SRCS += tools_common.h tools_common.c
decode_to_md5.SRCS += video_common.h
decode_to_md5.SRCS += video_reader.hvideo_reader.c
decode_to_md5.SRCS += vpx_ports/mem_ops.h
decode_to_md5.SRCS += vpx_ports/mem_ops_aligned.h
decode_to_md5.GUID =59120B9B-2735-4BFE-B022-146CA340FE42
decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum
EXAMPLES-$(CONFIG_ENCODERS) += simple_encoder.c
simple_encoder.SRCS += ivfenc.h ivfenc.c
simple_encoder.SRCS += tools_common.h tools_common.c
simple_encoder.SRCS += video_common.h
simple_encoder.SRCS += video_writer.h video_writer.c
simple_encoder.GUID =4607D299-8A71-4D2C-9B1D-071899B6FBFD
simple_encoder.DESCRIPTION = Simplified encoder loop
EXAMPLES-$(CONFIG_VP9_ENCODER) += vp9_lossless_encoder.c
vp9_lossless_encoder.SRCS += ivfenc.h ivfenc.c
vp9_lossless_encoder.SRCS += tools_common.h tools_common.c
vp9_lossless_encoder.SRCS += video_common.h
vp9_lossless_encoder.SRCS += video_writer.h video_writer.c
vp9_lossless_encoder.GUID = B63C7C88-5348-46DC-A5A6-CC151EF93366
vp9_lossless_encoder.DESCRIPTION= Simplified lossless VP9 encoder
EXAMPLES-$(CONFIG_ENCODERS) += twopass_encoder.c
twopass_encoder.SRCS += ivfenc.h ivfenc.c
twopass_encoder.SRCS += tools_common.h tools_common.c
twopass_encoder.SRCS += video_common.h
twopass_encoder.SRCS += video_writer.h video_writer.c
twopass_encoder.GUID =73494FA6-4AF9-4763-8FBB-265C92402FD8
twopass_encoder.DESCRIPTION = Two-pass encoder loop
EXAMPLES-$(CONFIG_DECODERS) += decode_with_drops.c
decode_with_drops.SRCS += ivfdec.h ivfdec.c
decode_with_drops.SRCS += tools_common.h tools_common.c
decode_with_drops.SRCS += video_common.h
decode_with_drops.SRCS += video_reader.h video_reader.c
decode_with_drops.SRCS += vpx_ports/mem_ops.h
decode_with_drops.SRCS += vpx_ports/mem_ops_aligned.h
decode_with_drops.GUID =CE5C53C4-8DDA-438A-86ED-0DDD3CDB8D26
decode_with_drops.DESCRIPTION = Drops frames while decoding
EXAMPLES-$(CONFIG_ENCODERS) += set_maps.c
set_maps.SRCS += ivfenc.h ivfenc.c
set_maps.SRCS += tools_common.htools_common.c
set_maps.SRCS += video_common.h
set_maps.SRCS += video_writer.hvideo_writer.c
set_maps.GUID =ECB2D24D-98B8-4015-A465-A4AF3DCC145F
set_maps.DESCRIPTION = Set active and ROI maps
EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c
vp8cx_set_ref.SRCS += ivfenc.h ivfenc.c
vp8cx_set_ref.SRCS += tools_common.h tools_common.c
vp8cx_set_ref.SRCS += video_common.h
vp8cx_set_ref.SRCS += video_writer.hvideo_writer.c
vp8cx_set_ref.GUID =C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A
vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame
ifeq($(CONFIG_MULTI_RES_ENCODING),yes)
ifeq($(CONFIG_LIBYUV),yes)
EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8_multi_resolution_encoder.c
vp8_multi_resolution_encoder.SRCS += ivfenc.h ivfenc.c
vp8_multi_resolution_encoder.SRCS += tools_common.h tools_common.c
vp8_multi_resolution_encoder.SRCS += video_writer.h video_writer.c
vp8_multi_resolution_encoder.SRCS += $(LIBYUV_SRCS)
vp8_multi_resolution_encoder.GUID = 04f8738e-63c8-423b-90fa-7c2703a374de
vp8_multi_resolution_encoder.DESCRIPTION= VP8 Multiple-resolution Encoding
endif
endif
# Handle extra library flags depending on codecconfiguration
configure成功后,然后再make。编译后成功后即可在build文件下出现libvpx.a、simple_encoder、simple_decoder等文件,而simple_encoder、simple_decoder是直接可以在手机上运行的可执行文件,可用adb工具利用shell进行调试,在手机上shell调试方法可以参考http://blog.csdn.net/u014006343/article/details/46619927。
编译为完整examples示例:
../configure --target=armv7-android-gcc --sdk-path=$ARM_ROOT --prefix=/usr/local/android/ --extra-cflags="-mfloat-abi=softfp -mfpu=neon" –-disable-webm-io
在用libvpx库时会出现下面错误:undefined reference to `android_getCpuFeatures’:
这个错误是在加入examples时出现(但在单独编译libvpx时并没有出错),经过搜索,在ndk目录下的source目录下发现cpufeatures,该目录里的cpu-features就有android_getCpuFeatures的声明和定义,并且也说明了如何使用。这里采用比较原始的方式,就是自己编译了cpufeature的静态库,然后在需要的项目中在链接进去。
编译libcpu-features.a 文件的方法可以参考http://blog.csdn.net/kl222/article/details/23101115 ,需要注意的是libcpu-features.a 静态库的链接方式,在此需要对examples.mk进行如下修改:
在 CODEC_EXTRA_LIBS=$(sort $(call enabled,CODEC_EXTRA_LIBS))下面添加如下:
CODEC_EXTRA_LIBS+=/home/willman/third-party/libcpu-feaures.a (libcpu-features.a 静态库所在目录)
configure成功后,然后再make。编译后成功后即可在build文件下出现libvpx.a、simple_encoder、simple_decoder、vpxenc、vpxdec等文件,而simple_encoder、simple_decoder、vpxenc、vpxdec是直接可以在手机上运行的可执行文件,可用adb工具利用shell进行调试。