不管是本地播放多媒体,还是流媒体播放,在上层的实现方法都是一样的,总体来说就下面的这些流程。
MediaPlayer mMediaPlayer = new MediaPlayer( ); //创建mediaplayer
mMediaPlayer.setDataSource(mContext, mUri); // setDataSoutce
mMediaPlayer.setDisplay(mSurfaceHolder); // setDisplay
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.prepareAsync(); // Prepare
mMediaPlayer.start(); // start
... // Pause, stop
接下来会以播放流程的步骤去解析NuPayer实现的细节。其中涉及到具体的请求消息构建和处理请参考:AHandler机制。
(1)
framework/av/media/libmedia/mediaplayer.cpp
status_t MediaPlayer::setDataSource(
const sp<IMediaHTTPService> &httpService,
const char *url, const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
status_t err = BAD_VALUE;
if (url != NULL) {
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(httpService, url, headers))) {
player.clear();
}
err = attachNewPlayer(player);
}
}
return err;
}
这里主要是通过mediaPlayerService获取BnMediaplayer,然后通过Binder通信调用底层的setDataSource。这里涉及到了Binder通信的知识,以后再做研究。
成功完成之后,意味着mediaPlayer进入了MEDIA_PLAYER_INITIALIZED状态。
enum media_player_states {
MEDIA_PLAYER_STATE_ERROR = 0,
MEDIA_PLAYER_IDLE = 1 << 0,
MEDIA_PLAYER_INITIALIZED = 1 << 1,
MEDIA_PLAYER_PREPARING = 1 << 2,
MEDIA_PLAYER_PREPARED = 1 << 3,
MEDIA_PLAYER_STARTED = 1 << 4,
MEDIA_PLAYER_PAUSED = 1 << 5,
MEDIA_PLAYER_STOPPED = 1 << 6,
MEDIA_PLAYER_PLAYBACK_COMPLETE = 1 << 7
};
(2)
MediaPlayerService.cpp中具体BnMediaPlayer的执行;
status_t MediaPlayerService::Client::setDataSource(
const sp<IMediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
...
} else {
player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}
setDataSource_post(p, p->setDataSource(httpService, url, headers));
return mStatus;
}
}
这里依据代码URL得出要创建的player类型,这里是NuPlayerDriver(这是个NuPlayer的封装)。
class NuPlayerFactory : public MediaPlayerFactory::IFactory {
...
virtual sp<MediaPlayerBase> createPlayer() {
ALOGV(" create NuPlayer");
return new NuPlayerDriver;
}
};
NuPlayerDriver::NuPlayerDriver()
: mState(STATE_IDLE),
mIsAsyncPrepare(false),
mAsyncResult(UNKNOWN_ERROR),
mSetSurfaceInProgress(false),
mDurationUs(-1),
mPositionUs(-1),
mSeekInProgress(false),
mLooper(new ALooper),
mPlayerFlags(0),
mAtEOS(false),
mLooping(false),
mAutoLoop(false),
mStartupSeekTimeUs(-1) {
ALOGV("NuPlayerDriver(%p)", this);
mLooper->setName("NuPlayerDriver Looper");
mLooper->start(
false, /* runOnCallingThread */
true, /* canCallJava */
PRIORITY_AUDIO);
mPlayer = new NuPlayer;
mLooper->registerHandler(mPlayer);
mPlayer->setDriver(this);
}
NuPlayer就是一个AHandler,继承自AHandler,构成nuplayer的过程,初始化一些状态,标志位,重要的是起了消息队列、Looper和Handler,也就是AHandler机制。
(3)
这个过程创建了NuPlayer之后,从NuPlayerDriver开始执行底层的setDataSource。
从图上看,setDataSource整个过程,做了三件事情:
1. 创建Message
2. 创建HTTPLiveSource
3. onMessageReceived中处理消息
void NuPlayer::setDataSourceAsync(
const sp<IMediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers) {
sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); // 1 创建消息
size_t len = strlen(url);
sp<AMessage> notify = new AMessage(kWhatSourceNotify, id()); // 创建返回通知消息
sp<Source> source;
if (IsHTTPLiveURL(url)) {
source = new HTTPLiveSource(notify, httpService, url, headers); // 2 对于HLS 创建HTTPLiveSource
} else if (!strncasecmp(url, "rtsp://", 7)) {
source = new RTSPSource(
notify, httpService, url, headers, mUIDValid, mUID); // 对于RTSP 创建RTSPSource
} else if ((!strncasecmp(url, "http://", 7)
|| !strncasecmp(url, "https://", 8))
&& ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
|| strstr(url, ".sdp?"))) {
source = new RTSPSource(
notify, httpService, url, headers, mUIDValid, mUID, true);
} else {
sp<GenericSource> genericSource =
new GenericSource(notify, mUIDValid, mUID);
// Don't set FLAG_SECURE on mSourceFlags here for widevine.
// The correct flags will be updated in Source::kWhatFlagsChanged
// handler when GenericSource is prepared.
status_t err = genericSource->setDataSource(httpService, url, headers);
if (err == OK) {
source = genericSource;
} else {
ALOGE("Failed to set data source!");
}
}
msg->setObject("source", source);
msg->post(); // Post消息队列等待处理
}
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatSetDataSource:
{
ALOGV("kWhatSetDataSource");
CHECK(mSource == NULL);
status_t err = OK;
sp<RefBase> obj;
CHECK(msg->findObject("source", &obj));
if (obj != NULL) {
mSource = static_cast<Source *>(obj.get()); // 这个就是上面创建的HTTPLiveSource
} else {
err = UNKNOWN_ERROR;
}
CHECK(mDriver != NULL);
sp<NuPlayerDriver> driver = mDriver.promote();
if (driver != NULL) {
driver->notifySetDataSourceCompleted(err);
}
break;
}
case kWhatSourceNotify:
{
onSourceNotify(msg);
break;
}
}
}
void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
Mutex::Autolock autoLock(mLock);
CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
mAsyncResult = err;
mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
mCondition.broadcast();
}
// 这个函数如同回调函数一样进入HTTPLiveSource,随时能通知到NuPlayer
void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
int32_t what;
CHECK(msg->findInt32("what", &what));
...
}
HTTPLiveSource初始化,基本上没做什么。
NuPlayer::HTTPLiveSource::HTTPLiveSource(
const sp<AMessage> ¬ify,
const sp<IMediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers)
: Source(notify),
mHTTPService(httpService),
mURL(url),
mFlags(0),
mFinalResult(OK),
mOffset(0),
mFetchSubtitleDataGeneration(0) {
if (headers) {
mExtraHeaders = *headers;
ssize_t index =
mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
if (index >= 0) {
mFlags |= kFlagIncognito;
mExtraHeaders.removeItemsAt(index);
}
}
}
上面的步骤进入STATE_SET_DATASOURCE_PENDING状态,NuPlayerDriver的状态:
enum State {
STATE_IDLE,
STATE_SET_DATASOURCE_PENDING,
STATE_UNPREPARED,
STATE_PREPARING,
STATE_PREPARED,
STATE_RUNNING,
STATE_PAUSED,
STATE_RESET_IN_PROGRESS,
STATE_STOPPED, // equivalent to PAUSED
STATE_STOPPED_AND_PREPARING, // equivalent to PAUSED, but seeking
STATE_STOPPED_AND_PREPARED, // equivalent to PAUSED, but seek complete
};
setDataSource基本上简单地初始化了source就完了。