最近在玩ndk(ubuntu), 拿havenaptr ffmpeg 项目简单移植了一下,所谓简单移植就是只是让havenaptr ffmpeg在2.3和4.0上简单跑起来,视频声音没有同步,也没有修改进度条的bug。在实践过程中看了很多高手的blog列举一下。
http://blog.csdn.net/scut1135/article/details/6536157 作者版权意识很强,就是这篇文章排版有点。。。
http://blog.csdn.net/moruite/article/details/6305944 最经典的文章,不多说了
http://blog.csdn.net/piaozhiye/article/details/6363512 很详细,但是基于2.1,2.3/4.0的工作有的地方不同
项目地址是:http://github.com/havlenapetr/FFMpeg
建议大家多看看网站内issues和源代码。
还需要下载aosp(android源码): source.android.com
和havlenapetr修改过的frameworks/base/native/ :https://github.com/havlenapetr/android_frameworks_base
下面我就简单把遇到的问题和解决方案说下,欢迎没有搞定的朋友给我留言,最好把编译环境和出错信息都贴上,我会在半年内坚持回帖,
1. 2.2的native/没有了?
答:我是git下的源码,所以使用git命令就可以切换。
git checkout froyo
这样就有了
git checkout ics
这样就回4.0了
2. 需不需要android的源码?
答:肯定需要,你可以看下jni/prebuild/ (ffmpeg项目)有两个已经编好的so文件,他们是需要在源码下编译生成的然后覆盖。
ps:可能用虚拟机编译不很给力,我现在是使用用widowloader装的32位ubuntu,虽然装的时候可用硬盘比较小,但是cpu和内存给力多了,如果只是处理上面几个项目的话空间还是没问题的啦。
3. 2.3/4.0的移植步骤:
1> cp -r android_frameworks_base/native/video/ aosp/frameworks/base/native/
2> cp -r android_frameworks_base/native/audio/ aosp/frameworks/base/native/
3> cp android_frameworks_base/native/include/android/surface.h aosp/frameworks/base/native/include/android/
4> cp android_frameworks_base/native/include/android/audiotrack.h aosp/frameworks/base/native/include/android/
5> vi aosp/frameworks/base/native/video/jni/Android.mk(我会把我的修改好的Android.mk贴在后面,2.3不需要修改)
可以按照android_frameworks_base(ics)的native/ndk-glue/Android.mk来改下,
去掉camere模块,LOCAL_MODULE:= libndk-glue ---> LOCAL_MODULE:= libjnivideo
6> source build/envsetup.sh
7>lunch 1
8>make
9>这样就能在 out/target/product/generic/obj/lib/中找到libjniaudio.so libjnivideo.so,用他们替换掉jni/prebuild/的同名so文件。
10> 在项目根下执行ndk-build (需要使用ndk-build所在目录或export ndk-build所在目录)。
4. Android.mk (前面数字是行号,不是文件内容,注意)
1 LOCAL_PATH:= $(call my-dir)
2 include $(CLEAR_VARS)
3
4 USE_SURFACE_WRAPPER := true
5
6 # our source files
7 #
8 LOCAL_SRC_FILES:=
9
10 LOCAL_C_INCLUDES += \
11 $(JNI_H_INCLUDE) \
12 frameworks/base/include
13
14 LOCAL_SHARED_LIBRARIES := \
15 libutils
16
17 # for surface API
18 ifeq ($(USE_SURFACE_WRAPPER),true)
19 LOCAL_SRC_FILES += surface.cpp
20
21 LOCAL_C_INCLUDES += \
22 external/skia/include/core
23
24 LOCAL_SHARED_LIBRARIES += \
25 libskia \
26 libgui \
27 libsurfaceflinger_client
28 endif
29
30 # Optional tag would mean it doesn't get installed by default
31 LOCAL_MODULE_TAGS := optional
32
33 LOCAL_PRELINK_MODULE := false
34
35 LOCAL_MODULE:= libjnivideo
36
37 include $(BUILD_SHARED_LIBRARY)
5. 在使用项目中可能出现的小问题
1> FFMpegMovieViewAndroid.java (108) 需要重写所有方法(添加空实现就行)
2> maybe need Project --> clean to clean project
3> 我在使用中产生如下log:
03-27 11:16:06.920: W/dalvikvm(549): JNI WARNING: JNI method called with exception pending
2 03-27 11:16:06.920: W/dalvikvm(549): in Lcom/media/ffmpeg/FFMpegPlayer;._setVideoSurface:(Landroid/view/Surface;)V (FindClass)
3 03-27 11:16:06.920: W/dalvikvm(549): Pending exception is:
4 03-27 11:16:06.920: I/dalvikvm(549): java.lang.NoSuchFieldError: no field with name='mSurface' signature='I' in class Landroid/view/Surface;
5 03-27 11:16:06.920: I/dalvikvm(549): at com.media.ffmpeg.FFMpegPlayer._setVideoSurface(Native Method)
6 03-27 11:16:06.920: I/dalvikvm(549): at com.media.ffmpeg.FFMpegPlayer.setDisplay(FFMpegPlayer.java:129)
7 03-27 11:16:06.920: I/dalvikvm(549): at com.media.ffmpeg.android.FFMpegMovieViewAndroid.openVideo(FFMpegMovieViewAndroid.java:62)
8 03-27 11:16:06.920: I/dalvikvm(549): at com.media.ffmpeg.android.FFMpegMovieViewAndroid.access$1(FFMpegMovieViewAndroid.java:60)
9 03-27 11:16:06.920: I/dalvikvm(549): at com.media.ffmpeg.android.FFMpegMovieViewAndroid$1.surfaceCreated(FFMpegMovieViewAndroid.java:97)
10 03-27 11:16:06.920: I/dalvikvm(549): at android.view.SurfaceView.updateWindow(SurfaceView.java:533)
11 03-27 11:16:06.920: I/dalvikvm(549): at android.view.SurfaceView.access$000(SurfaceView.java:81)
12 03-27 11:16:06.920: I/dalvikvm(549): at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:169)
13 03-27 11:16:06.930: I/dalvikvm(549): at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:590)
14 03-27 11:16:06.930: I/dalvikvm(549): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1617)
15 03-27 11:16:06.930: I/dalvikvm(549): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
16 03-27 11:16:06.930: I/dalvikvm(549): at android.os.Handler.dispatchMessage(Handler.java:99)
17 03-27 11:16:06.930: I/dalvikvm(549): at android.os.Looper.loop(Looper.java:137)
18 03-27 11:16:06.930: I/dalvikvm(549): at android.app.ActivityThread.main(ActivityThread.java:4424)
19 03-27 11:16:06.930: I/dalvikvm(549): at java.lang.reflect.Method.invokeNative(Native Method)
20 03-27 11:16:06.930: I/dalvikvm(549): at java.lang.reflect.Method.invoke(Method.java:511)
21 03-27 11:16:06.930: I/dalvikvm(549): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
22 03-27 11:16:06.930: I/dalvikvm(549): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
23 03-27 11:16:06.930: I/dalvikvm(549): at dalvik.system.NativeStart.main(Native Method)
24 03-27 11:16:06.940: I/dalvikvm(549): "main" prio=5 tid=1 NATIVE
25 03-27 11:16:06.940: I/dalvikvm(549): | group="main" sCount=0 dsCount=0 obj=0x409c1460 self=0x12810
26 03-27 11:16:06.940: I/dalvikvm(549): | sysTid=549 nice=0 sched=0/0 cgrp=default handle=1074082952
27 03-27 11:16:06.940: I/dalvikvm(549): | schedstat=( 1100304534 1384400601 857 ) utm=87 stm=23 core=0
28 03-27 11:16:06.940: I/dalvikvm(549): at com.media.ffmpeg.FFMpegPlayer._setVideoSurface(Native Method)
29 03-27 11:16:06.940: I/dalvikvm(549): at com.media.ffmpeg.FFMpegPlayer.setDisplay(FFMpegPlayer.java:129)
30 03-27 11:16:06.940: I/dalvikvm(549): at com.media.ffmpeg.android.FFMpegMovieViewAndroid.openVideo(FFMpegMovieViewAndroid.java:62)
31 03-27 11:16:06.940: I/dalvikvm(549): at com.media.ffmpeg.android.FFMpegMovieViewAndroid.access$1(FFMpegMovieViewAndroid.java:60)
32 03-27 11:16:06.940: I/dalvikvm(549): at com.media.ffmpeg.android.FFMpegMovieViewAndroid$1.surfaceCreated(FFMpegMovieViewAndroid.java:97)
33 03-27 11:16:06.940: I/dalvikvm(549): at android.view.SurfaceView.updateWindow(SurfaceView.java:533)
34 03-27 11:16:06.940: I/dalvikvm(549): at android.view.SurfaceView.access$000(SurfaceView.java:81)
35 03-27 11:16:06.940: I/dalvikvm(549): at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:169)
36 03-27 11:16:06.940: I/dalvikvm(549): at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:590)
37 03-27 11:16:06.940: I/dalvikvm(549): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1617)
38 03-27 11:16:06.940: I/dalvikvm(549): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
39 03-27 11:16:06.940: I/dalvikvm(549): at android.os.Handler.dispatchMessage(Handler.java:99)
40 03-27 11:16:06.940: I/dalvikvm(549): at android.os.Looper.loop(Looper.java:137)
41 03-27 11:16:06.940: I/dalvikvm(549): at android.app.ActivityThread.main(ActivityThread.java:4424)
42 03-27 11:16:06.940: I/dalvikvm(549): at java.lang.reflect.Method.invokeNative(Native Method)
43 03-27 11:16:06.940: I/dalvikvm(549): at java.lang.reflect.Method.invoke(Method.java:511)
44 03-27 11:16:06.960: I/dalvikvm(549): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
45 03-27 11:16:06.960: I/dalvikvm(549): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
46 03-27 11:16:06.960: I/dalvikvm(549): at dalvik.system.NativeStart.main(Native Method)
47 03-27 11:16:06.960: E/dalvikvm(549): VM aborting
修改方法是:将surface.cpp中mSurface —> mNativeSurface ,然后重新编译(移植过程中(6)(7)(8))就可以了。
4> 我是在android2.3/4.0 的模拟器上测试的,可以工作。
最后,祝大家成功,有问题多看错误信息和源码, 欢迎跟贴提问!