一、准备源码包
在ffmpeg官网下载0.6版本的源码包
wget http://ffmpeg.org/releases/ffmpeg-0.6.tar.bz2
二、NDK目录准备
因为NDK编译时只识别JNI目录下的Android.mk, 所以需要做个链接
tar xjvf ffmpeg-0.6.tar.bz2 ln -s ffmpeg-0.6 jni
cd ffmpeg-0.6
三、ffmpeg配置
这里提供一个配置脚本 config.sh
export NDKRROOT=/backup/software/android/android-ndk-r8b export PREBUILT=$NDKRROOT/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86 export PLATFORM=$NDKRROOT/platforms/android-14/arch-arm export PATH=$PATH:$PREBUILT/bin export TMPDIR=/tmp ./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-linux-androideabi-gcc \ --cross-prefix=$PREBUILT/bin/arm-linux-androideabi- \ --nm=$PREBUILT/bin/arm-linux-androideabi-nm \ --extra-cflags="-fPIC -DANDROID" \ --disable-asm \ --enable-neon \ --enable-armv5te \ --extra-ldflags="-Wl,-T,$PREBUILT/arm-linux-androideabi/lib/ldscripts/armelf_linux_eabi.x -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib $PREBUILT/lib/gcc/arm-linux-androideabi/4.6.x-google/crtbegin.o $PREBUILT/lib/gcc/arm-linux-androideabi/4.6.x-google/crtend.o -lc -lm -ldl"
配置时出错的概率很高,需要注意一下问题:
1、NDKRROOT 需要设定成你自己的NDK所在路径
2、根据NDK版本不同,PREBUILT、PLATFORM路径里面的名字可能不一样,请确认是你正在使用的版本
3、根据NDK版本不同,交叉编译的工具名称可能不同,请确认
--cc=$PREBUILT/bin/arm-linux-androideabi-gcc
--cross-prefix=$PREBUILT/bin/arm-linux-androideabi-
--nm=$PREBUILT/bin/arm-linux-androideabi-nm
是否设置正确
4、根据NDK版本不同,编译是需要的静态链接文件可能不一样,armelf_linux_eabi.x 可能名字不一样,找到ldscripts下对应的.x文件即可,crtbegin.o、crtend.o
可能路径不一样,请确认是正确的
5、出错提示:
a)找不到交叉编译工具
类似Unknown C compiler /toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/ arm-linux-androideabi-gcc,请确认路径设置均正常
b)出现不能创建执行文件
类似 arm-linux-androideabi-gcc is unable to create an executable file,请确认export TMPDIR=/tmp 中设定的路径存在且可以访问
6、自定义配置
如果需要对ffmpeg进行裁剪获取有其他需求,请自行配在config选项
运行config.sh开始configure
chmod +x config.sh ./config.sh
四、Android.mk 准备
1、库文件makefile公用部分, 取名为av.mk,放置在ffmpeg-0.6目录下
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))
2、库文件通用makefile, 取名Android.mk,分别放置在libavcodec、ibavdevice、libavfilter、libavformat、libavutil、libpostproc、libswscale目录下
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)
同时对libavcodec、ibavdevice、libavfilter、libavformat、libavutil、libpostproc、libswscale目录下的Makefile文件,注释掉其中的
include $(SUBDIR)../subdir.mak include $(SUBDIR)../config.mak
这两行不在一起,找找都注释掉
3、应用程序makefile, 取名为Android.mk,放置在ffmpeg-0.6目录下
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale libavfilter libavdevice LOCAL_MODULE := ffmpeg LOCAL_C_INCLUDES := \ $(LOCAL_PATH) \ $(LOCAL_PATH)/libavcodec \ $(LOCAL_PATH)/libavdevice \ $(LOCAL_PATH)/libavfilter \ $(LOCAL_PATH)/libavformat \ $(LOCAL_PATH)/libavutil \ $(LOCAL_PATH)/libpostproc \ $(LOCAL_PATH)/libswscale \ LOCAL_SRC_FILES := \ ffmpeg.c\ cmdutils.c include $(BUILD_EXECUTABLE) include $(call all-makefiles-under,$(LOCAL_PATH))如果只要做库文件的,参考文档1里面有介绍
五、编译及相关问题解决
1、 运行NDK开始编译,命令如:
/backup/software/android/android-ndk-r8b/ndk-build
2、错误解决
a)
/works/workspace/android-console/jni/libavutil/libm.h:62:43: error: static declaration of 'lrint' follows non-static declaration /works/workspace/android-console/jni/libavutil/libm.h:69:43: error: static declaration of 'lrintf' follows non-static declaration /works/workspace/android-console/jni/libavutil/libm.h:76:41: error: static declaration of 'round' follows non-static declaration /works/workspace/android-console/jni/libavutil/libm.h:83:40: error: static declaration of 'roundf' follows non-static declaration /works/workspace/android-console/jni/libavutil/libm.h:90:40: error: static declaration of 'truncf' follows non-static declaration
删除libavutil/libm.h相关的static函数定义
b)
/works/workspace/android-console/jni/ffmpeg.c:3636:19: error: storage size of 'rusage' isn't known /works/workspace/android-console/jni/ffmpeg.c:3638:15: error: 'RUSAGE_SELF' undeclared (first use in this function)
将config.h 中
#define HAVE_GETRUSAGE 1
修改为
#define HAVE_GETRUSAGE 0
c)
/works/workspace/android-console/jni/cmdutils.c:41:21: fatal error: version.h: No such file or directory
在ffmpeg-0.6目录下运行
./version.sh . version.h
d)
/works/workspace/android-console/jni/cmdutils.c:270:19: error: storage size of 'rl' isn't known /works/workspace/android-console/jni/cmdutils.c:271:19: error: 'RLIMIT_CPU' undeclared (first use in this function)将config.h 中
#define HAVE_SETRLIMIT 1修改为
#define HAVE_SETRLIMIT 0
e)
In file included from /works/workspace/android-console/jni/libavformat/../libavcodec/mpegaudio.h:31:0, from /works/workspace/android-console/jni/libavformat/asfdec.c:26: /works/workspace/android-console/jni/libavformat/../libavcodec/dsputil.h:448:47: error: expected ';', ',' or ')' before 'v1' /works/workspace/android-console/jni/libavformat/asfdec.c: In function 'asf_read_header': /works/workspace/android-console/jni/libavformat/asfdec.c:380:21: warning: 'AVPaletteControl' is deprecated (declared at /works/workspace/android-console/jni/libavformat/../libavcodec/avcodec.h:2808) [-Wdeprecated-declarations] make: *** [/works/workspace/android-console/obj/local/armeabi/objs/avformat/asfdec.o] Error 1
原始数据:转置后数据:
-- populate some test data if object_id('tempdb..#tmp') is not null drop table #tmp create table #tmp ( ID int identity(1,1) not null, MainField varchar(100), ThatField int, ThatOtherField datetime ) insert into #tmp (MainField, ThatField, ThatOtherField) select 'A', 10, '1/1/2000' union all select 'A', 20, '2/1/2000' union all select 'A', 30, '3/1/2000' union all select 'B', 10, '1/1/2001' union all select 'B', 20, '2/1/2001' union all select 'B', 30, '3/1/2001' union all select 'B', 40, '4/1/2001' union all select 'C', 10, '1/1/2002' union all select 'D', 10, '1/1/2000' union all select 'D', 20, '2/1/2000' --union all -- pivot over multiple columns using the 1.1, 1.2, 2.1, 2.2 sequence trick select MainField, max([1.1]) as ThatField1, max([1.2]) as ThatOtherField1, max([2.1]) as ThatField2, max([2.2]) as ThatOtherField2, max([3.1]) as ThatField3, max([3.2]) as ThatOtherField3, max([4.1]) as ThatField4, max([4.2]) as ThatOtherField4 from
( ( select x.*, cast(row_number() over (partition by MainField order by ThatField) as varchar(2)) + '.1' as ThatFieldSequence, cast(row_number() over (partition by MainField order by ThatField) as varchar(
1. 31 days of Windows 8#12 Background Task: http://www.jeffblankenburg.com/2012/11/12/31-days-of-windows-8-day-12-background-tasks/
2. 31 days of Windows 8 #11 Lock Screen : http://www.jeffblankenburg.com/2012/11/11/31-days-of-windows-8-day-11-lock-screen-apps/
3. Background Task 白皮书: http://www.microsoft.com/en-us/download/details.aspx?id=27411
在使用锁屏应用的时候,你要保证你明白自己要做些什么准备:
1. 使用Wide Logo,即你要提供wide logo 310*150
2. 使用Badge, 即你要提供badge logo 24*24
3. 使用Background Task, 而且background task 支持的事件是Control channel, timer, push notification类型。
4. 设置你的Background Task的EntryPoint
5. 你需要在Manifest里面声明你使用LockScreen。
具体的操作步骤大家可以参考文献2。
锁屏应用比较简单,重要的一点是,如果你在程序中询问了用户是否允许使用锁屏应用,你将只有这一次修改的机会,不然你就只能通过PC Control进行设置了。但是如果你的Windows 8 没有激活的话,你只能卸载应用程序,重新安装一遍了。
代码如下:
2 create_task(BackgroundExecutionManager::RequestAccessAsync()).then([this](BackgroundAccessStatus status)
3 {
4 //这一步可以不要
5 //BackgroundAccessStatus status1 = BackgroundExecutionManager::GetAccessStatus();
6 if((status == BackgroundAccessStatus::AllowedWithAlwaysOnRealTimeConnectivity)||
7 (status == BackgroundAccessStatus::AllowedMayUseActiveRealTimeConnectivity))
8 {
9 XmlDocument^ badgeData = BadgeUpdateManager::GetTemplateContent(BadgeTemplateType::BadgeNumber);
10 XmlNodeList^ badgeXML = badgeData->GetElementsByTagName("badge");
11 ((XmlElement^)badgeXML->Item(0))->SetAttribute("value","Playing");
12
13 BadgeNotification^ badge = ref new BadgeNotification(badgeData);
14 BadgeUpdateManager::CreateBadgeUpdaterForApplication()->Update(badge);
15 }
16 });
运行,然后会弹出一个对话框,像这样
点击Allow之后,按下WIN+L你就可以看到锁屏上面出现的Badge图片和你的number了。
一般情况下,我们会使用后台任务(Background Task)来更新Lock Screen App的数据。
后台任务
1. 什么是后台任务?
后台任务是:即使程序已经被挂起或者不在运行了,还在默默地执行的任务。
2. 后台任务与前台任务的区别?
首先,前台任务占据了整个屏幕,用户直接与其进行交互。后台任务不能与用户交互,除了(Tile, Toast, 和Lock Screen)
其次,因为前台要与用户交互,它使用所有可用的系统资源,包括CPU time 和Network资源,并且不受限。后台任务使用系统资源的时候是受限制的。
再次,前台任务处理主要事务,后台任务处理短时间、轻量级的事务。
最后,后台任务不论前台任务是否处于Running状态,它都会运行。
3. 后台任务的目的?
大家都知道,Windows 8 应用程序的生命周期分为Running,Suspended,Terminated三种状态。App处于前台时,为Running状态,处于后台时,为Suspended状态,用户关闭App时或者在Suspended状态太久,系统自动关闭App时,为Terminated状态。
我们可以从Suspended状态将App变为Running状态,我们不能在后台运行太复杂,太耗时耗资源的程序,因为如果你这么做了,你将会非常耗费电量,并且,用户切换回前台时,会感觉到非常卡,有延迟。
因为上述的目的:延长电池用量,保证用户流畅的体验,我们需要限制后台任务对资源的使用,而且我们的后台任务要尽量精简。
4. 后台任务的执行环境?
一般情况下,我们都要把我们的后台任务作为一个Runtime Component,引用到主工程中去。这样,一个后台任务就是一个class library,一个in-proc server DLL。这个library可以在我们的App中运行,也可以在系统提供的主机环境中运行(BackgroundTaskHost.exe)。这个exe是在App相同的容器内运行,当它不需要的时候,会自动退出。
5. 后台任务的适合场景?
播放音乐,上传下载文件,刷新瓷贴、通知、LockScreen,应用程序间共享合约。下载Mail,VOIP、IM信息,用户改变系统设置
6. 后台任务基本概念?