最近想把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。(當前編譯採用這個版本)
配置NDK環境
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.o
In 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 EncoderEXAMPLES-$(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 checksumEXAMPLES-$(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進行調試。