2011-12-08 12:06:17 BABY313 阅读数 5532
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26282 人正在学习 去看看 钟文昌

基于移动平台的多媒体框架——移植播放器到Android上


今天很成功地将我们自己开发的基于ffmpeg播放器移植到了Android上,并且在tablet上面测试成功。按照本文提供的思路,可以移植所有基于ffmpeg的播放器到Android上。


准备工作:

需要的两个库,ffmpeg和SDL,其编译方法在前文中都有叙述。

在开发时,需要把这两个编译好的库文件:libffmpeg.so和libSDL.so放入<ndk-path>/platforms/android-8/arch-arm/usr/lib/下面;在调试和运行时,需要用adb push到Android的/system/lib/下面。

(本文所述的项目版本有所出入,并且很长时间没有维护过。再次强烈推荐各位只是当作参考,领略大意。建议用vlc官方的android版本进行尝试,与本文思想相同,却可以省掉很多不必要的麻烦。)

本文示例的播放器下载地址是https://github.com/pkuembedded/TVplayer。这个播放器是我们实验室自己开发的,目前尚不完善在不断更新中,但是基本的播放功能都有了。读者可以根据自己的兴趣按照本文思路移植其他功能强大的开源播放器,包括自己开发的播放器。


第一步:eclipse中新建一个Android工程。

为了与PC Linux版的TVplayer区分,该工程名为TVplayer_Android。包名为com.player,类名为TVplayer。

新建工程时,要选择和编译ffmpeg和SDL一致的Android的版本以及ndk、sdk版本。

第二步:将待移植的播放器导入该工程。

在TVplayer_Android目录下新建jni/src.将TVplayer下的src中所有c文件与h文件复制到TVplayer_Android/jni/src中,以准备用NDK编译。
新建TVplayer_Android/jni/Android.mk。内容为:

LOCAL_PATH := $(call my-dir)/src


include $(CLEAR_VARS)


LOCAL_MODULE    := TVplayer
LOCAL_SRC_FILES := \
audio.c \
display.c \
file.c \
queue.c \
sync.c \
TVplayer.c \
video.c


LOCAL_C_INCLUDES += /home/baby/workspace/SDL-1.3.0-6050/include/
LOCAL_C_INCLUDES += /home/baby/workspace/avs/ffmpeg-0.8.7/


LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -lffmpeg -lSDL -llog


include $(BUILD_SHARED_LIBRARY)
其中:
LOCAL_SRC_FILES开头的一行后面加入需要编译的源文件。
LOCAL_C_INCLUDES开头的两行用来包含c库的头文件,将你的ffmpeg和SDL的头文件目录加在此处。
LOCAL_LDLIBS开头的一行中,加-llog便于调试。

第三步:实现java类。

为了让Android支持SDL,需要SDL源文件中的SDLActivity.java文件。将SDLActivity.java复制到与我们自己的TVplayer.java同级目录。
修改TVplayer.java为:

public class TVplayer extends SDLActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

这里采用的方法是用自己的类继承SDLActivity类,在onCreate方法中调用父类方法。简单起见也可以直接把SDLActivity类改名为TVplayer,为了以后方面添加其他类而不至于太臃肿,没有采用这种方法。SDLActivity.java要稍作修改:将原来的System.loadLibrary函数全部注释,然后在原位置添加一句System.loadLibrary("TVplayer");结果如下:
static {
    //System.loadLibrary("SDL");
    //System.loadLibrary("SDL_image");
    //System.loadLibrary("SDL_mixer");
    //System.loadLibrary("SDL_ttf");
    //System.loadLibrary("main");
    System.loadLibrary("TVplayer");
}

第四步:修改c文件。

TVplayer_Android/jni/src/TVplayer.c文件也要修改:
实现java中的native函数,如下:
void Java_com_player_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj){
    /* This interface could expand with ABI negotiation, calbacks, etc. */
    SDL_Android_Init(env, cls);

    /* Run the application code! */
    int status;
    char *argv[2];
    argv[0] = strdup("SDL_app");
    argv[1] = NULL;
    //status = main(1, argv);
    status = main(2, argv);
    /* We exit here for consistency with other platforms. */
    exit(status);

//  Java_org_libsdl_app_SDLActivity_nativeInit(env, cls, obj);
}

void Java_com_player_SDLActivity_nativeQuit(JNIEnv* env, jclass cls, jobject obj){
    Java_org_libsdl_app_SDLActivity_nativeQuit(env, cls, obj);
}

void Java_com_player_SDLActivity_onNativeResize(JNIEnv* env, jclass cls, jobject obj, int x, int y, int format){
    Java_org_libsdl_app_SDLActivity_onNativeResize(env, cls, obj, x, y, format);
}
void Java_com_player_SDLActivity_onNativeAccel(JNIEnv* env, jclass cls, jobject obj, float x, float y, float z){
    Java_org_libsdl_app_SDLActivity_onNativeAccel(env, cls, obj, x, y, z);
}

实现方法其实就是调用SDL原来的实现方法。如果你运行过上一篇的移植SDL的例子,了解整个流程,就可以在SDL中找到这些相应的函数。

添加完这些函数之后,java就会调用SDL为Android设计的初始化方法,就可以把原来main函数中调用的SDL_Init函数删去了。

第五步:编译运行:

首先在工程目录下ndk-build,生成libTVplayer.so。
然后在eclipse中编译运行。















2011-11-22 21:12:36 BABY313 阅读数 5380
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26282 人正在学习 去看看 钟文昌

如何把ffmpeg移植到Android上?

今天用NDK-BUILD成功编译了ffmpeg,为我们小组下一步开发Android上的播放器以及播放框架的工作打好了基础。

编译的方法参考的这个博客:

http://abitno.me/compile-ffmpeg-android-ndk

读了博客中的几篇文章,感觉很佩服。写的东西都很不错,水平高而又通俗易懂。

我用的ffmpeg最新的0.8.6版本替换了原文中的0.6版,基本原封不动就可成功。只是在编译的过程中会报几条c语言规范相关的错误,简单的改动一下就可以了。

编译成功,颇为欣喜,简记短述,聊以自慰。微笑


编译脚本:

为了使大家方便更加方便地编译出Android上的ffmpeg,我写了一个简单的shell脚本。经测试在Ubuntu11.10上用android-ndk-r6b编译ffmpeg0.8.x成功。

脚本地址:https://github.com/baby313/gen_Android_ffmpeg/blob/master/gen_player.sh

只需执行一个命令,就可有得到Android上的ffmpeg啦!

2013-08-01 17:14:00 azhou8202 阅读数 458
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26282 人正在学习 去看看 钟文昌
先测试占座
2011-12-08 10:22:44 BABY313 阅读数 7534
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26282 人正在学习 去看看 钟文昌


基于移动平台的多媒体框架——移植SDL到Android



SDL-1.3版开始官方支持Android。本文记录了移植1.3以上的版本的简单过程。
要做一个完整的播放器,只有ffmpeg解码还不够,还需要一个显示视频播放音频的库,SDL是它的完美搭档。如何结合ffmpeg和SDL写一个播放器,可以参考经典教程(http://dranger.com/ffmpeg/)。我这里介绍如何把SDL移植到Android上。


第一步:下载SDL最新版(>=1.3),解压。

$ tar xf <YOUR-SDL-PAHT>/SDL-1.3.tar.gz

第二步:找到android-project目录。这个目录相当于一个Android工程的模板,把这个目录复制到你要要建立工程的地方。

$ mv <YOUR-SDL-PAHT>/SDL-1.3.0-6050/android-project <YOUR-PROJECT-PATH>/

第三步:把第一步解压后的SDL移到android-project下面的jni目录下,并改名为SDL。

如果不改名,文件名会有"SDL-版本号",编译会出错。

android-project$ mv <YOUR-SDL-PAHT>/SDL-1.3.0-6050/ jni/SDL

第四步:将你写好的C代码放到jni/src目录下。

这里我们举例,就把SDL里面的test/testgles.c复制过去。

android-project$ cp jni/SDL/test/testgles.c jni/src/

第五步:编辑jni/src/Android.mk里面LOCAL_SRC_FILES一项,按照注释把相应的文件名改为第四步你自己写的文件名。

这里我们看到有一行是SDL_PATH := ../SDL,这就是SDL所在的路径,如果你第三步没有改SDL的文件名,也可以改这里,总之把它们统一起来就可以了。

android-project$ vi jni/src/Android.mk

第六步:ndk-build。

android-project$ ndk-build

这一步如果编译通过,就算是移植成功了。如果你熟悉jni编程,后面的过程就很简单了。

第七步: 把android-project导入到eclipse中,直接运行就可以了。

如果直接用命令行编译java也可以,eclipse更加方便一些。java部分调用c的代码就在android-project的src目录下面,是SDL官方提供的,最好不要改动。

2012-02-24 09:44:20 BABY313 阅读数 16330
  • Android移植基础

    Android视频课程,该课程可以让学员了解Android系统架构、学习如何下载Android源码、编译及开发Android、学习如何追踪Android源码、了解Linux内核启动流程、了解Android启动流程、学习如何移植外部函式库至Android源码中。

    26282 人正在学习 去看看 钟文昌

基于移动平台的多媒体框架——移植Live555到Android上



live555是一个处理流媒体传输对c++库,再Mplayer与vlc中都有用到。我们计划将其加入到自己编写对Android上的播放器中作为流媒体模块,首先就需要将这个库移植到Android上。

1. 首先在官网下载live555对源码并解压。
2. 新建一个Android工程,将源码文件放到一个该工程的jni目录下,如:jni/live。
3. 新建jni/Android.mk文件作为Makefile。将需要编译对源文件加入到LOCAL_SRC_FILES变量,将需要引用对头文件加入到LOCAL_C_INCLUDES,编译过程中会提示需要参数:-fexceptions,于是加入参数LOCAL_CPPFLAGS += -fexceptions。

内容如下:

4. 新建jni/Application.mk文件。由于live555需要引用stl,所以加入:
APP_STL := gnustl_shared

5. 运行ndk-build就可以得到live555.so文件啦。


后记:

至今为止,我们已经向Android上移植了三个c/c++的库了(ffmpeg、sdl、live555)。如果有按着步骤一步步的做过,相信大家已经很熟悉如何向Android上移植一个c/c++库里。举一反三,融会贯通,相信以后遇到一个新的c/c++工程,你也会觉得轻而易举手到擒来啦!


补充:

本来打算把自己移植好的src发给在回复中留言的几位朋友的,但查了一下发现硬盘坑爹地被我格过几次,东西早就没有了。鉴于这个工作不那么复杂,我索性再做一遍,顺便把移植的过程写的详细点,便于他人参考。

1. 下载了最新的live555源码,日期是12/04/04,用的ndk版本是r7b。

2.预备工作,先用标准的方法make一下,确定你的源码是可以编译过的。

./genMakefiles linux
make
马上就看到成功的结果了,这时不要急得移植。移植是交叉编译了,咱们先不用交叉编译,用gcc编译看看会不会。

了解live555的基本结构之后就可以执行:

g++ BasicUsageEnvironment/*.cpp liveMedia/*.cpp mediaServer/*.cpp UsageEnvironment/*.cpp ./groupsock/*cpp -IBasicUsageEnvironment/include -IliveMedia/include -IBasicUsageEnvironment/include -Igroupsock/include/ -IUsageEnvironment/include -DSOCKLEN_T=socklen_t -shared -o live555.so
这样在本地就生成一个so了。

3. 跟本地一样,如果你了解了ndk的用法,写个简单的mk文件就可以移植了。建工程什么的在上面说了,我就把mk文件贴出来给大家参考一下好了。为了省事,我就建了一个Android.mk文件。写的过程就是碰到什么问题,就改改加加什么参数。(这次连Application.mk都没有加就过了。。。)

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := live555

LOCAL_SRC_FILES :=\
./live/groupsock/GroupEId.cpp \
./live/groupsock/IOHandlers.cpp \
./live/groupsock/NetInterface.cpp \
./live/groupsock/NetAddress.cpp \
./live/groupsock/GroupsockHelper.cpp \
./live/groupsock/Groupsock.cpp \
./live/groupsock/inet.c \
./live/BasicUsageEnvironment/DelayQueue.cpp \
./live/BasicUsageEnvironment/BasicHashTable.cpp \
./live/BasicUsageEnvironment/BasicUsageEnvironment.cpp \
./live/BasicUsageEnvironment/BasicUsageEnvironment0.cpp \
./live/BasicUsageEnvironment/BasicTaskScheduler.cpp \
./live/BasicUsageEnvironment/BasicTaskScheduler0.cpp \
./live/UsageEnvironment/HashTable.cpp \
./live/UsageEnvironment/strDup.cpp \
./live/UsageEnvironment/UsageEnvironment.cpp \
./live/liveMedia/MP3Internals.cpp \
./live/liveMedia/StreamReplicator.cpp \
./live/liveMedia/MPEG4GenericRTPSource.cpp \
./live/liveMedia/BitVector.cpp \
./live/liveMedia/MatroskaFileParser.cpp \
./live/liveMedia/ADTSAudioFileServerMediaSubsession.cpp \
./live/liveMedia/H264VideoRTPSink.cpp \
./live/liveMedia/MP3StreamState.cpp \
./live/liveMedia/RTSPServerSupportingHTTPStreaming.cpp \
./live/liveMedia/MP3AudioMatroskaFileServerMediaSubsession.cpp \
./live/liveMedia/InputFile.cpp \
./live/liveMedia/MPEGVideoStreamParser.cpp \
./live/liveMedia/AMRAudioFileSource.cpp \
./live/liveMedia/Locale.cpp \
./live/liveMedia/T140TextRTPSink.cpp \
./live/liveMedia/MediaSink.cpp \
./live/liveMedia/QuickTimeFileSink.cpp \
./live/liveMedia/RTPSink.cpp \
./live/liveMedia/VorbisAudioRTPSink.cpp \
./live/liveMedia/AMRAudioFileSink.cpp \
./live/liveMedia/MP3ADUTranscoder.cpp \
./live/liveMedia/VorbisAudioMatroskaFileServerMediaSubsession.cpp \
./live/liveMedia/H264VideoFileServerMediaSubsession.cpp \
./live/liveMedia/H263plusVideoRTPSource.cpp \
./live/liveMedia/RTSPClient.cpp \
./live/liveMedia/DVVideoRTPSource.cpp \
./live/liveMedia/H264VideoStreamFramer.cpp \
./live/liveMedia/DVVideoStreamFramer.cpp \
./live/liveMedia/MultiFramedRTPSink.cpp \
./live/liveMedia/BasicUDPSink.cpp \
./live/liveMedia/Base64.cpp \
./live/liveMedia/H261VideoRTPSource.cpp \
./live/liveMedia/MP3InternalsHuffman.cpp \
./live/liveMedia/MPEG2TransportStreamMultiplexor.cpp \
./live/liveMedia/MP3AudioFileServerMediaSubsession.cpp \
./live/liveMedia/MPEG1or2AudioRTPSource.cpp \
./live/liveMedia/H263plusVideoFileServerMediaSubsession.cpp \
./live/liveMedia/MP3Transcoder.cpp \
./live/liveMedia/H263plusVideoStreamParser.cpp \
./live/liveMedia/AudioInputDevice.cpp \
./live/liveMedia/MP3FileSource.cpp \
./live/liveMedia/MPEG4LATMAudioRTPSource.cpp \
./live/liveMedia/MPEG2TransportStreamFromPESSource.cpp \
./live/liveMedia/AACAudioMatroskaFileServerMediaSubsession.cpp \
./live/liveMedia/WAVAudioFileServerMediaSubsession.cpp \
./live/liveMedia/MP3ADURTPSource.cpp \
./live/liveMedia/FileSink.cpp \
./live/liveMedia/MPEG1or2DemuxedServerMediaSubsession.cpp \
./live/liveMedia/MP3InternalsHuffmanTable.cpp \
./live/liveMedia/TCPStreamSink.cpp \
./live/liveMedia/MediaSource.cpp \
./live/liveMedia/MPEG2TransportStreamFramer.cpp \
./live/liveMedia/JPEGVideoRTPSink.cpp \
./live/liveMedia/JPEGVideoSource.cpp \
./live/liveMedia/AC3AudioFileServerMediaSubsession.cpp \
./live/liveMedia/AMRAudioRTPSink.cpp \
./live/liveMedia/MPEG4VideoFileServerMediaSubsession.cpp \
./live/liveMedia/AMRAudioFileServerMediaSubsession.cpp \
./live/liveMedia/H264VideoMatroskaFileServerMediaSubsession.cpp \
./live/liveMedia/MPEG2IndexFromTransportStream.cpp \
./live/liveMedia/MPEG1or2FileServerDemux.cpp \
./live/liveMedia/GSMAudioRTPSink.cpp \
./live/liveMedia/MPEG1or2VideoStreamFramer.cpp \
./live/liveMedia/AMRAudioRTPSource.cpp \
./live/liveMedia/EBMLNumber.cpp \
./live/liveMedia/MP3ADUinterleaving.cpp \
./live/liveMedia/SimpleRTPSink.cpp \
./live/liveMedia/MPEG1or2VideoRTPSink.cpp \
./live/liveMedia/MPEG2TransportStreamTrickModeFilter.cpp \
./live/liveMedia/AC3AudioRTPSource.cpp \
./live/liveMedia/MultiFramedRTPSource.cpp \
./live/liveMedia/ServerMediaSession.cpp \
./live/liveMedia/JPEGVideoRTPSource.cpp \
./live/liveMedia/MP3ADU.cpp \
./live/liveMedia/FileServerMediaSubsession.cpp \
./live/liveMedia/DVVideoFileServerMediaSubsession.cpp \
./live/liveMedia/DarwinInjector.cpp \
./live/liveMedia/OnDemandServerMediaSubsession.cpp \
./live/liveMedia/H263plusVideoRTPSink.cpp \
./live/liveMedia/TextRTPSink.cpp \
./live/liveMedia/MPEG1or2VideoStreamDiscreteFramer.cpp \
./live/liveMedia/MediaSession.cpp \
./live/liveMedia/AC3AudioStreamFramer.cpp \
./live/liveMedia/QuickTimeGenericRTPSource.cpp \
./live/liveMedia/SimpleRTPSource.cpp \
./live/liveMedia/FramedFileSource.cpp \
./live/liveMedia/T140TextMatroskaFileServerMediaSubsession.cpp \
./live/liveMedia/PassiveServerMediaSubsession.cpp \
./live/liveMedia/ByteStreamMemoryBufferSource.cpp \
./live/liveMedia/RTCP.cpp \
./live/liveMedia/MP3ADURTPSink.cpp \
./live/liveMedia/ADTSAudioFileSource.cpp \
./live/liveMedia/MPEG1or2VideoRTPSource.cpp \
./live/liveMedia/MPEG1or2VideoFileServerMediaSubsession.cpp \
./live/liveMedia/MPEG4ESVideoRTPSink.cpp \
./live/liveMedia/RTPSource.cpp \
./live/liveMedia/H264VideoStreamDiscreteFramer.cpp \
./live/liveMedia/AVIFileSink.cpp \
./live/liveMedia/StreamParser.cpp \
./live/liveMedia/MPEG2TransportStreamFromESSource.cpp \
./live/liveMedia/VP8VideoRTPSink.cpp \
./live/liveMedia/FramedFilter.cpp \
./live/liveMedia/VideoRTPSink.cpp \
./live/liveMedia/MPEG4VideoStreamDiscreteFramer.cpp \
./live/liveMedia/QCELPAudioRTPSource.cpp \
./live/liveMedia/MPEG4VideoStreamFramer.cpp \
./live/liveMedia/Media.cpp \
./live/liveMedia/ByteStreamMultiFileSource.cpp \
./live/liveMedia/MPEG2TransportUDPServerMediaSubsession.cpp \
./live/liveMedia/H263plusVideoStreamFramer.cpp \
./live/liveMedia/VorbisAudioRTPSource.cpp \
./live/liveMedia/RTSPCommon.cpp \
./live/liveMedia/FramedSource.cpp \
./live/liveMedia/MatroskaDemuxedTrack.cpp \
./live/liveMedia/MPEG1or2AudioStreamFramer.cpp \
./live/liveMedia/VP8VideoMatroskaFileServerMediaSubsession.cpp \
./live/liveMedia/MPEG1or2Demux.cpp \
./live/liveMedia/AudioRTPSink.cpp \
./live/liveMedia/DeviceSource.cpp \
./live/liveMedia/MPEG1or2AudioRTPSink.cpp \
./live/liveMedia/ByteStreamFileSource.cpp \
./live/liveMedia/WAVAudioFileSource.cpp \
./live/liveMedia/uLawAudioFilter.cpp \
./live/liveMedia/RTSPServer.cpp \
./live/liveMedia/VP8VideoRTPSource.cpp \
./live/liveMedia/H264VideoRTPSource.cpp \
./live/liveMedia/MatroskaFileServerDemux.cpp \
./live/liveMedia/MPEG4LATMAudioRTPSink.cpp \
./live/liveMedia/MPEG2TransportStreamIndexFile.cpp \
./live/liveMedia/SIPClient.cpp \
./live/liveMedia/MP3HTTPSource.cpp \
./live/liveMedia/BasicUDPSource.cpp \
./live/liveMedia/AC3AudioMatroskaFileServerMediaSubsession.cpp \
./live/liveMedia/H264VideoFileSink.cpp \
./live/liveMedia/MPEG2TransportFileServerMediaSubsession.cpp \
./live/liveMedia/DigestAuthentication.cpp \
./live/liveMedia/MPEG4ESVideoRTPSource.cpp \
./live/liveMedia/MatroskaFile.cpp \
./live/liveMedia/MP3ADUdescriptor.cpp \
./live/liveMedia/AMRAudioSource.cpp \
./live/liveMedia/MPEG4GenericRTPSink.cpp \
./live/liveMedia/MPEGVideoStreamFramer.cpp \
./live/liveMedia/AC3AudioRTPSink.cpp \
./live/liveMedia/DVVideoRTPSink.cpp \
./live/liveMedia/OutputFile.cpp \
./live/liveMedia/MPEG1or2DemuxedElementaryStream.cpp \
./live/liveMedia/RTPInterface.cpp \
./live/liveMedia/our_md5hl.c \
./live/liveMedia/our_md5.c \
./live/liveMedia/rtcp_from_spec.c 


LOCAL_C_INCLUDES := \
./live/BasicUsageEnvironment/include \
./live/liveMedia/include \
./live/BasicUsageEnvironment/include \
./live/groupsock/include \
./live/UsageEnvironment/include

LOCAL_CPPFLAGS += -fexceptions -DXLOCALE_NOT_USED=1 -DNULL=0 -DNO_SSTREAM=1 -UIP_ADD_SOURCE_MEMBERSHIP

include $(BUILD_SHARED_LIBRARY)


(有关in_addr的地方编译不过的,稍微修改下源码,去掉s_addr即可。

没有更多推荐了,返回首页