您的位置:首页 > 移动开发 > Android开发

Android MediaPlayer学习笔记

2013-11-06 10:42 399 查看
Android的MediaPlayer应该算是一个大的子系统,整个流程比较长,不过好的是流程还比较清晰,代码跟起来也不是很难。

MediaPlayer是从MediaPlayer.java开始的,应用如果想播放音乐,先要new 一个MediaPlayer,并设置其相关的参数。

先列出主要的代码文件,他们都在frameworks里面:

Java层代码:

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

Jni层代码:

base/media/jni/android_media_MediaPlayer.cpp

本地代码:

av/media/libmedia/mediaplayer.cpp

./av/media/libmedia/IMediaPlayer.cpp

MediaPlayerService:

av/media/libmediaplayerservice/MediaPlayerService.cpp

这里MediaPlayerService里的内部类Client从BnMediaPlayer继承,从IMediaPlayer的BnMediaPlayer里的调用会到这里;然后又会跳到AudioOutput里,这个类是从MediaPlayerInterface.h里的MediaPlayerBase::AudioSink继承而来。

在新建一个MediaPlayer时会调用setDataSource这个函数,这个函数会调用MediaPlayerFactory::getPlayerType,根据播放文件的类型选择合适的播放器。

av/media/libmedia/AudioTrack.cpp

av/media/libmedia/IAudioTrack.cpp

av/services/audioflinger/AudioFlinger.cpp

1. 新建一个MediaPlayer的实例:

 1)Java中new出一个MediaPlayer实例后,紧接着就会调用setDataSource,调用传到mediaplayer.java中会调用:

status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)

{

    ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);

    status_t err = UNKNOWN_ERROR;

    // 得到MediaPlayerService的BpMediaPlayerService引用

    const sp<IMediaPlayerService>& service(getMediaPlayerService());

    if (service != 0) {

        sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));                  

        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||

            (NO_ERROR != player->setDataSource(fd, offset, length))) {

            player.clear();

        }

        err = attachNewPlayer(player);

    }

    return err;

}

 2) sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId))调用的是BpMediaPlayerService的create,   remote()->transact(CREATE, data, &reply)调用通过Binder传到MediaPlayerService,再调用其的create函数,其返回了一个MediaPlayerService::Client的实例,返回后到interface_cast<IMediaPlayer>(reply.readStrongBinder())这一句,这里有个interface_cast<IMediaPlayer>,这是在干什么呢?

在Java里每次new出一个MediaPlayer,在服务端也会新建一个实例。

    virtual sp<IMediaPlayer> create(

            pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId) {

        Parcel data, reply;

        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());

        data.writeInt32(pid);

        data.writeStrongBinder(client->asBinder());

        data.writeInt32(audioSessionId);

        remote()->transact(CREATE, data, &reply);

        return interface_cast<IMediaPlayer>(reply.readStrongBinder());

    }

sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client,

        int audioSessionId)

{

    int32_t connId = android_atomic_inc(&mNextConnId);

    sp<Client> c = new Client(

            this, pid, connId, client, audioSessionId,

            IPCThreadState::self()->getCallingUid());

    ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,

         IPCThreadState::self()->getCallingUid());

    wp<Client> w = c;

    {

        Mutex::Autolock lock(mLock);

        mClients.add(w);

    }

    return c;

}

 

 3) interface_cast是在IInterface.h里定义的如下:

template<typename INTERFACE>

inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)

{

    return INTERFACE::asInterface(obj);

}

代入IMediaPlayer后如下:

template<typename IMediaPlayer>

inline sp<IMediaPlayer> interface_cast(const sp<IBinder>& obj)

{

    return IMediaPlayer::asInterface(obj);

}

asInterface(obj)的定义也在这个文件中,在其定义中返回了new BpMediaPlayer的实例,所以在1)中的player其实就是BpMediaPlayer的强引用。后面的player->setDataSource(fd, offset, length)调用的就是BpMediaPlayer里的函数,通过Binder,会传到BnMediaPlayer,BnMediaPlayer又是MediaPlayerService::Client的父类,最终其实就是在调用MediaPlayerService::Client的函数。

2. setDataSource函数,这是一个很重要的函数,在MediaPlayerService::Client中的setDataSource,会根据播放文件的类型选择合适的播放器。setDataSource_pre会调用createPlayer(),然后调用MediaPlayerFactory::createPlayer(playerType, this, notify),返回播放器的实例。

    player_type playerType = MediaPlayerFactory::getPlayerType(this,

                                                               fd,

                                                               offset,

                                                               length);

    sp<MediaPlayerBase> p = setDataSource_pre(playerType);

 在setDataSource_pre中接着new AudioOutput,最后一句把mAudioOutput传到MediaPlayerInterface中,又因为播放器都是从类MediaPlayerInterface中继承而来,比如class StagefrightPlayer : public MediaPlayerInterface,所以播放器可以通过这个来操作AudioOutput里的函数。AudioOutput里的函数大都通过AudioTrack的函数来操作,AudioTrack是在status_t
MediaPlayerService::AudioOutput::open(...)这个函数里new出来的。

    if (!p->hardwareOutput()) {

        mAudioOutput = new AudioOutput(mAudioSessionId);

        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);

    }

3. 在AudioTrack也是一个通过Binder来通信的家伙,主要来用在MediaPlayerService和AudioFlinger两个进程之间通信,一步一步来:

在AudioTrack的构造函数里会调用mStatus = set(...),set调用createTrack_l,进去后调用sp<IAudioTrack> track = audioFlinger->createTrack(...),audioFlinger是一个服务,所以这里就跳到IAudioFlinger.cpp文件里的类BpAudioFlinger里的createTrack函数,通过Binder,到BnAudioFlinger里面:CREATE_TRACK,sp<IAudioTrack> track
= createTrack(...),这里的createTrack是AudioFlinger.cpp文件里的AudioFlinger::createTrack(...),其返回的就是一个new TrackHandle(track)。TrackHandle从BnAudioTrack里继承而来。我们走了这么远终于看到在MediaPlayerService::AudioOut里的诸如start,stop,pause等调用都会传到这里。而这个的实现就是通过IAudioTrack来通信。当然, TrackHandle也没有做任何的处理,而是全部丢给了AudioFlinger::PlaybackThead::Track的函数。这里才是这个这几个函数的最终归宿。

一路分析而来,突然有一种感受,那就是我们平时听说的MediaPlayerService和AudioFlinger都如同人世间一样,风光的都是这些大哥们,实际是干活的都是它们下面的小弟。大哥们只负责把工作接过来,然后就丢给任劳任怨的小弟们。

4. 我们都知道在音乐或其他声音播放过程中一定会有一个循环,用来向Buffer里面填数据,这样音乐就能一直播放,直到播放完成。那我们的这个循环在哪里实现的呢?

4000
在StagefrightPlayer里的AwesomePlayer里,有个AudioPlayer,这个类下面有个fillBuffer函数,看名字就知道它是用来填Buffer的。只要我们跟踪这个函数的调用源头就一定能找到这个循环。AudioSinkCallback(AudioPlayer) <-- start(AudioPlayer) <-- mAudioSink->open(MediaPlayerService::AudioOutput)  <-- CallbackWrapper (MediaPlayerService::AudioOutput)
<-- new AudioTrack(..., CallbackWrapper,...)(MediaPlayerService::AudioOutput) <-- set (AudioTrack) <-- mCbf = cbf(AudioTrack) <-- processAudioBuffer (AudioTrack), processAudioBuffer这个函数里进行了多次调用mCbf。而processAudioBuffer正是新new出来的一个线程AudioTrackThread里的threadLoop里调用的。所以这个循环我们就找到了。它就是processAudioBuffer这个函数。根据threadLoop的定义,只要其不返回false,就会一直调用threadLoop,循环就跑起来了。

5. 另一个问题:Buffer是怎么分配的?

    status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)

    audio_track_cblk_t* cblk = mCblk;

mCblkMemory是整个内存块,mCblk只是内存块中audio_track_cblk_t的一部分,当然是啊前面的那部分:

    mCblkMemory = cblk;

通过cblk->pointer(),即IMemory里的pointer(),获得申请好的内存块,这块内存中包含了audio_track_cblk_t,这里用static_cast进行指针转换后得到audio_track_cblk_t结构的地址。我的理解是申请的这块内存一开始是空的,对audio_track_cblk_t的修改可以做一些控制,stop()调用其实就是把loopStart,loopEnd,loopCount三个值写为0。

    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());

cblk是从AudioFlinger里分配来的,以下内容来处AudioFlinger.cpp:

    sp<IMemory> cblk = track->getCblk();

    sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),...)

在AudioFlinger里面它也叫做mCblkMemory:

    virtual sp<IMemory> getCblk() const { return mCblkMemory; }

在TrackBase构造函数里做如下调用:

mCblkMemory = client->heap()->allocate(size);

client又是什么呢?

   client = registerPid_l(pid);  client是在这个调用里new出来的。

heap()函数:

sp<MemoryDealer> AudioFlinger::Client::heap() const

{

    return mMemoryDealer;

}

mMemoryDealer是一个MemoryDealer对象,所以allocate在MemoryDealer.cpp里:

sp<IMemory> MemoryDealer::allocate(size_t size)

{

    sp<IMemory> memory;

    const ssize_t offset = allocator()->allocate(size);

    if (offset >= 0) {

        memory = new Allocation(this, heap(), offset, size);

    }

    return memory;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: