Android多媒体之MediaPlayerService
来源:互联网 发布:拓普网络怎么样 编辑:程序博客网 时间:2024/05/27 08:13
如同其它service一样,MediaPlayerService在Android架构中起着承上启下的作用。向上提供media相关的api,向下调用其它框架(opencore、stegefright)具体实现相关功能。
涉及到代理到MediaPlayerService的IPC在前文已经分析过了,所以这里重点讨 论实现。如apk调用setDataSource,经过Binder IPC会调用到MediaPlayerService::Client::setDataSource。
以一个播放器应用的流程作为分析起点:
1. MediaPlayer mp = new MediaPlayer();
2. mp.setDataSource(”/sdcard/aaa.mp3”);
3. mp.prepare();
4. mp.start();
5. mp.stop();
MediaPlayer为MediaPlayerService的客户端,不做分析。直接看setDataSource:
status_t MediaPlayerService::Client::setDataSource(const sp<IStreamSource> &source)status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)status_t MediaPlayerService::Client::setDataSource(const char *url, const KeyedVector<String8, String8> *headers)
setDataSource根据data源参数不同有三种形式:IStreamSource(rtsp)类型、文件(本地)类型、url(http)类型。
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length) { player_type playerType =MediaPlayerFactory::getPlayerType(this, fd, offset, length); sp<MediaPlayerBase> p = setDataSource_pre(playerType); setDataSource_post(p, p->setDataSource(fd, offset, length));}enum player_type { PV_PLAYER = 1, SONIVOX_PLAYER = 2, STAGEFRIGHT_PLAYER = 3, NU_PLAYER = 4, // argument to the 'test:' url in the setDataSource call. TEST_PLAYER = 5,};
aaa.mp3属性文件源,首先由MediaPlayerFactory产生一个播放器,播放的类型为:STAGEFRIGHT_PLAYER。
所有类型都事先注册到sFactoryMap中,然后再取出来。
StagefrightPlayer::StagefrightPlayer() : mPlayer(new AwesomePlayer) { mPlayer->setListener(this);}
StagefrightPlayer类型实质是AwesomePlayer播放器,AwesomePlayer框架后文再介绍。继续MediaPlayerService中的流程:
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre( player_type playerType){ // create the right type of player sp<MediaPlayerBase> p = createPlayer(playerType); if (!p->hardwareOutput()) { mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid()); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); }}
可以看到playerType(AwesomePlayer)得到之后,就开始创建AwesomePlayer的实例,接着又创建一个音频输出AudioOutput实例,并设置音频接收器setAudioSink。最后设置新的数据源: setDataSource_post(p, p->setDataSource(fd, offset, length));
这样播放器和数据源都设置好了,我们的aaa.mp3文件保存在FileSource类型里: sp<DataSource> dataSource = new FileSource(fd, offset, length);
其中class FileSource : public DataSource
下边进入mp.prepare();
调用status_t MediaPlayerService::Client::prepareAsync()
status_t MediaPlayerService::Client::prepareAsync(){ sp<MediaPlayerBase> p = getPlayer(); status_t ret = p->prepareAsync(); if (ret == NO_ERROR) mAntagonizer->start();}
这里的p为AwesomePlayer,准备工作又涉及到AwesomePlayer的播放框架,简单提一下,AwesomePlayer以事件驱动框架进行运作,所以会准备事件队列。
status_t AwesomePlayer::prepareAsync() { return prepareAsync_l();}status_t AwesomePlayer::prepareAsync_l() { mQueue.start(); modifyFlags(PREPARING, SET); mAsyncPrepareEvent = new AwesomeEvent( this, &AwesomePlayer::onPrepareAsyncEvent); mQueue.postEvent(mAsyncPrepareEvent); return OK;}
队列TimedEventQueue mQueue;
对事件的处理需要协同时间。
void TimedEventQueue::start() { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_create(&mThread, &attr, ThreadWrapper, this); pthread_attr_destroy(&attr);}
start设置线程属性,
PTHREAD_CREATE_JOINABLE这个属性表明新创建的线程必须使用pthread_join()等待线程结束,否则线程所占用的资源不会得到释放,会造成资源泄露。在线程创建并运行以后可以用pthread_detach()来设置。
然后产生一个onPrepareAsyncEvent事件,并post到mQueue中,
TimedEventQueue::event_id TimedEventQueue::postTimedEvent( const sp<Event> &event, int64_t realtime_us) { Mutex::Autolock autoLock(mLock); event->setEventID(mNextEventID++); List<QueueItem>::iterator it = mQueue.begin(); while (it != mQueue.end() && realtime_us >= (*it).realtime_us) { ++it; } QueueItem item; item.event = event; item.realtime_us = realtime_us; item.has_wakelock = false; if (it == mQueue.begin()) { mQueueHeadChangedCondition.signal(); } if (realtime_us > ALooper::GetNowUs() + kWakelockMinDelay) { acquireWakeLock_l(); item.has_wakelock = true; } mQueue.insert(it, item); mQueueNotEmptyCondition.signal(); return event->eventID();
这个带时间的队列控制非常巧妙,while进行空转耗时,实质代码: mQueue.insert(it, item);
mQueueNotEmptyCondition.signal();
加入事件,发送信号。
接下来是mp.start();
status_t MediaPlayerService::Client::start(){ ALOGV("[%d] start", mConnId); sp<MediaPlayerBase> p = getPlayer(); if (p == 0) return UNKNOWN_ERROR; p->setLooping(mLoop); return p->start();}status_t AwesomePlayer::setLooping(bool shouldLoop) { Mutex::Autolock autoLock(mLock); modifyFlags(LOOPING, CLEAR); if (shouldLoop) { modifyFlags(LOOPING, SET); } return OK;}status_t StagefrightPlayer::start() { return mPlayer->play();}
先是修改播放器的标志:
void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) {
然后调用play进行播放。
status_t AwesomePlayer::play() { modifyFlags(CACHE_UNDERRUN, CLEAR); return play_l();}status_t AwesomePlayer::play_l() { mMediaRenderingStartGeneration = ++mStartGeneration; if (mDecryptHandle != NULL) { int64_t position; getPosition(&position); mDrmManagerClient->setPlaybackStatus(mDecryptHandle, Playback::START, position / 1000); } if (mAudioSource != NULL) { if (mAudioPlayer == NULL) { createAudioPlayer_l(); } if (mTimeSource == NULL && mAudioPlayer == NULL) { mTimeSource = &mSystemTimeSource; } if (mVideoSource != NULL) { // Kick off video playback postVideoEvent_l(); if (mAudioSource != NULL && mVideoSource != NULL) { postVideoLagEvent_l(); } } return OK;}
这个play函数比较长,处理各种异常情况,如没有播放前准备、文件解密准备、无视频播放实例、无音频播放实例等等。当这些条件都满足后,就向队列送一个video事件postVideoEvent_l();同时还要对当前电池电量进行监控等。
最后一步mp.stop();最终调用StagefrightPlayer的pause。
status_t StagefrightPlayer::stop() { ALOGV("stop"); return pause(); // what's the difference?}status_t StagefrightPlayer::pause() { ALOGV("pause"); return mPlayer->pause();}status_t AwesomePlayer::pause_l(bool at_eos) { notifyListener_l(MEDIA_PAUSED); cancelPlayerEvents(true /* keepNotifications */); postAudioTearDownEvent(kOffloadPauseMaxUs); modifyFlags(PLAYING, CLEAR);
结束时取消播放事件,然后暂停音频播放,再清除播放标志。
这样一个mp3文件的播放控制流程在就分析完了,主要涉及到MediaPlayerService与stagefright框架、awesomeplayer,越来越接近核心的部分了。
- Android多媒体之MediaPlayerService
- Android之MediaPlayerService服务详解
- Android开发之MediaPlayerService服务详解(一)
- Android开发之MediaPlayerService服务详解(一)
- Android Binder机制浅析之注册MediaPlayerService(1)
- Android Binder机制浅析之注册MediaPlayerService(2)
- 六、Android Binder机制浅析之注册MediaPlayerService(1)
- 六、Android Binder机制浅析之注册MediaPlayerService(2)
- Android MediaPlayerService解析
- MediaPlayerService
- Audio笔记之MediaPlayerService:setDataSource
- Audio笔记之MediaPlayerService启动
- Audio笔记之MediaPlayerService:prepare
- Android MediaPlayer 分析- MediaPlayerService.cpp
- Android下MediaPlayerService构架介绍
- Android JB MediaPlayerService Interface Analysis
- Android多媒体之录制
- Android多媒体之MediaPlayer
- Kruskal最小生成树
- iOS开发UI篇—程序启动原理和UIApplication
- 07.10C
- 英里 英尺 英寸的换算
- cmd命令
- Android多媒体之MediaPlayerService
- 实现一个可以在队列满时,将溢出的部分缓存入文件,待空闲时取出的队列
- 使用HBuilder开发移动APP:开发环境准备 (转)
- 1 1 2 3 5 8 13 21 34
- Node.js Express 框架
- leetcode_c++:哈希:Isomorphic Strings(205)
- 图解Linux命令之--fold命令
- 用DirectX实现魔方(三)视角变换及缩放(附源码)
- Node.js RESTful API