android流媒体开发框架介绍

blackmouse 发布于11月前 阅读12215次
0 条评论

简介

android流媒体往往总被我们忽略,而真正等到问题来的时候,来个“突然袭击”是非常痛苦的,因此有了这篇文章,希望大家可以笼统的了解一下这个框架,等到问题来的时候,至少知道从什么地方开始入手。

我们开始认识一下流媒体的功能:在线播放音视频流,我们支持两种协议,第一种是http,另一种是rtsp(实时数据的传输)。


上层代码结构分析

当我们选择一个视频网址,播放的界面在图库源代码中,packages/apps/Gallery3D/src/com/cooliris/media/MovieView.java

这个是播放器界面主类,也是所有跟用户直接交互的类,在oncreate的时候会调用mUri=getIntent.getData()

得到这个mUri后再传给并初始化给MovieViewControl.java这个类,他实现了

MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener,MediaPlayer.OnSeekCompleteListener接口,再跟videoview类相交互

Framework/base/core/java/android/VideoView类:

Displays a video file. The VideoView class can load images from various sources (such as resources or content providers), takes care of computing its measurement from the video so that it can be used in any layout manager, and provides various display options such as scaling and tinting.

播放一个视频文件。VideoView类可以从多种渠道加载图片(比如从content providers),这里也支持自动计算视频的匹配度以至于可以在任何布局管理器里面使用,也提供各种显示选项比如说缩放和着色。

由此也可以看出,framework中的VideoView类是视频播放的核心类。

下面我们来揭开VideoView神秘面纱吧

VideoView是一个自定义View:

public class VideoView extends SurfaceView implements MediaPlayerControl ,SetCanPause{…}


VideoView几个重要的函数

1.构造函数:

public VideoView(Context context) {
        super(context);
        initVideoView();
};

2.initVideoView()函数:

private void initVideoView() {
                   …
        Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        mWinWidth = display.getWidth();
        mWinHeight = display.getHeight();
}

初始化这个view的高度和宽度,这里是全屏大小


3.setVideoURI()函数:

  public void setVideoURI(Uri uri, Map<String, String> headers) {
        mUri = uri;
        mIsStream=isStream();
        mHeaders = headers;
        mSeekWhenPrepared = 0;
        openVideo();
        requestLayout();
        invalidate();
};

设定video的uri并打开video和对界面进行更新操作


4.openVideo()函数:

private void openVideo() {
        // Tell the music playback service to pause
        // TODO: these constants need to be published somewhere in the framework.
        Intent i = new Intent("com.android.music.musicservicecommand");
        i.putExtra("command", "pause");//pause music
i.putExtra("fm_stop", "stop");//stop fm
        mContext.sendBroadcast(i);
        release(false);
        try {
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
…
            attachMediaController();
        } catch (Exception ex) {…}
}

这里主要是初始化一个MediaPlayer类,设置一些监听器,停止音乐和播放器,设置播放地址


5.MediaPlayer. setDataSource()函数:

public void setDataSource(Context context, Uri uri, Map<String, String> headers) {
        String scheme = uri.getScheme();
        if(scheme == null || scheme.equals("file")) {
            setDataSource(uri.getPath());return;
        }
        AssetFileDescriptor fd = null;
        try {
            ContentResolver resolver = context.getContentResolver();
            fd = resolver.openAssetFileDescriptor(uri, "r");
            if (fd.getDeclaredLength() < 0) {
                setDataSource(fd.getFileDescriptor());
            } else {
     setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
            }return;
        } catch (Exception ex) {
        } finally {…}
        setDataSource(uri.toString(), headers);
return;
    }

分本地和网络两种,本地就直接传路径


数据序列图

播放的界面即为VideoView,获得用户传入的url后进行解析,若为文件则为本地播放,若为http或者rtsp格式的即为网络流媒体视频,通过movieViewController进行播放的控制,比如暂停、停止、快退和快进等,真正与底层交互的是framework/base/core/java/android/widget/VideoView.java类


类关系图

MovieViewControl类实现了MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener,MediaPlayer.OnSeekCompleteListener,而VideoView实现了MediaPlayerControl,MovieViewControl和VideoView是复合的关系。


播放视频代码结构

通过frameworks/base/media/jni/android_media_MediaPlayer.cpp文件实现与底层的交互,在底层是基于OpenCore的库实现的,opencore的代码位于external/opencore底下。

JAVA类的路径:

frameworks/base/media/java/android/media/MediaPlayer.java

JAVA本地调用部分(JNI):frameworks/base/media/jni/android_media_MediaPlayer.cpp

这部分内容编译成为目标是libmedia_jni.so。主要的头文件在以下的目录中:frameworks/base/include/media/

多媒体底层库在以下的目录中:

frameworks/base/media/libmedia/

这部分的内容被编译成库libmedia.so。

多媒体服务部分:

frameworks/base/media/libmediaplayerservice/

文件为mediaplayerservice.h和mediaplayerservice.cpp

这部分内容被编译成库libmediaplayerservice.so。

基于OpenCore的多媒体播放器部分

external/opencore/

这部分内容被编译成库libopencoreplayer.so。

从程序规模上来看,libopencoreplayer.so是主要的实现部分,而其他的库基本上都是在其上建立的封装和为建立进程间通讯的机制。

libmediaplayerservice.so是Media的服务器,它通过继承libmedia.so的类实现服务器的功能,而libmedia.so中的另外一部分内容则通过进程间通讯和libmediaplayerservice.so进行通讯。libmediaplayerservice.so的真正功能通过调用OpenCore Player来完成。


二个重要的头文件头文件mediaplayer.h、IMediaPlayer.h

mediaplayer.h是对外的接口类,它最主要是定义了一个MediaPlayer类:

class MediaPlayer : public BnMediaPlayerClient
{
public:
    MediaPlayer();
    ~MediaPlayer();
    void onFirstRef();
    void disconnect();
    status_t    setDataSource(const char *url);
    status_t    setDataSource(int fd, int64_t offset, int64_t length);
    status_t    setVideoSurface(const sp<Surface>& surface);
    status_t    setListener(const sp<MediaPlayerListener>& listener);
    status_t    prepare();
    status_t    prepareAsync();
    status_t    start();
    status_t    stop();
    status_t    pause();
    bool       isPlaying();
    status_t    getVideoWidth(int *w);
    status_t    getVideoHeight(int *h);
    status_t    seekTo(int msec);
    status_t    getCurrentPosition(int *msec);
    status_t    getDuration(int *msec);
    status_t    reset();
    status_t    setAudioStreamType(int type);
    status_t    setLooping(int loop);
    status_t    setVolume(float leftVolume, float rightVolume);
    void    notify(int msg, int ext1, int ext2);
    static    sp<IMemory>    decode(const char* url, uint32_t *pSampleRate, int* pNumChannels);
    static    sp<IMemory>    decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels);
}

从接口中可以看出MediaPlayer类刚好实现了一个MediaPlayer的基本操作,例如播放(start)、停止(stop)、暂停(pause)等。

 IMediaPlayer.h主要的的内容是一个实现MediaPlayer功能的接口:

class IMediaPlayer: public IInterface
{
public:
    DECLARE_META_INTERFACE(MediaPlayer);
    virtual void    disconnect() = 0;
    virtual status_t    setVideoSurface(const sp<ISurface>& surface) = 0;
    virtual status_t    prepareAsync() = 0;
    virtual status_t    start() = 0;
    virtual status_t    stop() = 0;
    virtual status_t    pause() = 0;
    virtual status_t    isPlaying(bool* state) = 0;
    virtual status_t    getVideoSize(int* w, int* h) = 0;
    virtual status_t    seekTo(int msec) = 0;
    virtual status_t    getCurrentPosition(int* msec) = 0;
    virtual status_t    getDuration(int* msec) = 0;
    virtual status_t    reset() = 0;
    virtual status_t    setAudioStreamType(int type) = 0;
    virtual status_t    setLooping(int loop) = 0;
    virtual status_t    setVolume(float leftVolume, float rightVolume) = 0;
};
class BnMediaPlayer: public BnInterface<IMediaPlayer>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,  
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

在IMediaPlayer类中,主要定义MediaPlayer的功能接口,这个类必须被继承才能够使用。值得注意的是,这些接口和MediaPlayer类的接口有些类似,但是它们并没有直接的关系。事实上,在MediaPlayer类的各种实现中,一般都会通过调用IMediaPlayer类的实现类来完成。

需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。