android MediaPlayer播放音视频流程

本文详细分析了Android中使用MediaPlayer播放音视频的流程,从创建MediaPlayer对象到设置数据源,再到native层的处理。重点讲解了setDataSource方法的内部实现,包括权限检查、文件类型判断以及创建不同类型的播放器。最后,文章揭示了MediaPlayer如何通过工厂模式创建CedarPlayer,并介绍了CedarPlayer与CedarXPlayer的关系。
摘要由CSDN通过智能技术生成

在播放一个本地音视频文件或网络传输的音视频流时,apk中一般会调用类似如下代码(本文以播放一个网络视频流为例进行分析):

MediaPlayer mp = new MediaPlayer();(1)   //创建一个播放器

mp.setDataSource("rtsp://10.0.149.217:554/stream1"); (2)//参数指定路径或url   

mp.prepare();  (3) 

mp.start(); (4)

上面的代码中总共有4条语句,本文重点分析(1)和(2),它涉及到播放器是如何一层层调用到多媒体框架中去.

我们先看(1)的调用流程:

public MediaPlayer() {
        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper); //EventHandler用于接收native层发送过来的消息
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }


        mTimeProvider = new TimeProvider(this);
        mOutOfBandSubtitleTracks = new Vector<SubtitleTrack>();
        mOpenSubtitleSources = new Vector<InputStream>();
        mInbandSubtitleTracks = new SubtitleTrack[0];


        /* Native setup requires a weak reference to our object.
         * It's easier to create it here than in C++.
         */
        native_setup(new WeakReference<MediaPlayer>(this));
    }


native_setup()的jni层实现函数为android_media_MediaPlayer_native_setup().定义在android_media_MediaPlayer.cpp中.

static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    ALOGV("native_setup");
    sp<MediaPlayer> mp = new MediaPlayer(); //此处创建了一个native层的MediaPlayer对象
    if (mp == NULL) {
        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
        return;
    }


    // create new listener and give it to MediaPlayer
    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener);


    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
    setMediaPlayer(env, thiz, mp);
}


static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{
    Mutex::Autolock l(sLock);
    sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
    if (player.get()) {
        player->incStrong((void*)setMediaPlayer);
    }
    if (old != 0) {
        old->decStrong((void*)setMediaPlayer);
    }


    env->SetIntField(thiz, fields.context, (int)player.get()); //此处将创建的native层的MediaPlayer对象保存到fields对象的context成员中.
    return old;
}


我们再看(2)的流程:

java层MediaPlayer的setDataSource方法被重载了多次,主要是设置播放音视频的路径不同,但最终都调用到native方法_setDataSource(),它对应的jni实现为

static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 
    if (mp == NULL ) {
        jniThrowException(env, "java

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值