//下面是一個典型的播放序列:
MediaPlayer player=new MediaPlayer()
player->setDataSource(url,header);
player->prepare();
player->start();
...
//使用MediaPlayerServcie的Client對象設置數據源
status_t MediaPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
status_t err = BAD_VALUE;
if (url != NULL) {
//1、獲得MediaPlayerService
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
//2、返回MediaPlayerService的Client對象player,並保存在Service的數組對象中,
//后續使用該Client將向MediaPlayer提供服務,因此每個MediaPlayer都對應一個Client
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
//3、選擇正確的播放器,並設置播放器的數據源
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(url, headers))) {
player.clear();
}
//4、保存最新的Client對象,斷開之前Client對象
err = attachNewPlayer(player);
}
}
return err;
}
1、獲取MeidaPlayerSercie
/*static*/const sp<IMediaPlayerService>&
IMediaDeathNotifier::getMediaPlayerService()
{
ALOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
//獲得BpServiceManager對象
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
ALOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
//通過Bind獲取BpMediaPlayerService對象
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
}
2、構造MediaPlayerService的Client對象
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
int audioSessionId)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
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;
}
//保存Client端的AudioSessionId等信息
MediaPlayerService::Client::Client(
const sp<MediaPlayerService>& service, pid_t pid,
int32_t connId, const sp<IMediaPlayerClient>& client,
int audioSessionId, uid_t uid)
{
ALOGV("Client(%d) constructor", connId);
mPid = pid;
mConnId = connId;
mService = service;
mClient = client;
mLoop = false;
mStatus = NO_INIT;
mAudioSessionId = audioSessionId;
mUID = uid;
mRetransmitEndpointValid = false;
#if CALLBACK_ANTAGONIZER
ALOGD("create Antagonizer");
mAntagonizer = new Antagonizer(notify, this);
#endif
}
//通過url獲取對應的播放器,然后保存該播放器,並設置播放器的數據源
status_t MediaPlayerService::Client::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
if (url == NULL)
return UNKNOWN_ERROR;
if ((strncmp(url, "http://", 7) == 0) ||
(strncmp(url, "https://", 8) == 0) ||
(strncmp(url, "rtsp://", 7) == 0)) {
if (!checkPermission("android.permission.INTERNET")) {
return PERMISSION_DENIED;
}
}
if (strncmp(url, "content://", 10) == 0) {
// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method
String16 url16(url);
int fd = android::openContentProviderFile(url16);
if (fd < 0)
{
ALOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
return mStatus;
} else {
//通過url獲取對應的播放器
player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}
setDataSource_post(p, p->setDataSource(url, headers));
return mStatus;
}
}
//通過播放器工廠的scoreFactory函數判斷該播放器是否合適,選擇播放器類型
#define GET_PLAYER_TYPE_IMPL(a...) \
Mutex::Autolock lock_(&sLock); \
\
player_type ret = STAGEFRIGHT_PLAYER; \
float bestScore = 0.0; \
\
for (size_t i = 0; i < sFactoryMap.size(); ++i) { \
\
IFactory* v = sFactoryMap.valueAt(i); \
float thisScore; \
CHECK(v != NULL); \
thisScore = v->scoreFactory(a, bestScore); \
if (thisScore > bestScore) { \
ret = sFactoryMap.keyAt(i); \
bestScore = thisScore; \
} \
} \
\
if (0.0 == bestScore) { \
ret = getDefaultPlayerType(); \
} \
\
return ret;
player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
const char* url) {
GET_PLAYER_TYPE_IMPL(client, url);
}
//這里如果所有播放器都不合適,則選擇默認播放器這里流程是,
//從播放器倉庫中選取最佳播放器,通過scoreFactory來確定
player_type MediaPlayerFactory::getDefaultPlayerType() {
char value[PROPERTY_VALUE_MAX];
if (property_get("media.stagefright.use-nuplayer", value, NULL)
&& (!strcmp("1", value) || !strcasecmp("true", value))) {
return NU_PLAYER;
}
return STAGEFRIGHT_PLAYER;
}
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
player_type playerType)
{
ALOGV("player type = %d", playerType);
// create the right type of player
sp<MediaPlayerBase> p = createPlayer(playerType);
if (p == NULL) {
return p;
}
//根據AudioSessionId設置播放器的輸出端
if (!p->hardwareOutput()) {
mAudioOutput = new AudioOutput(mAudioSessionId);
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}
return p;
}
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
// determine if we have the right player type
sp<MediaPlayerBase> p = mPlayer;
if ((p != NULL) && (p->playerType() != playerType)) {
ALOGV("delete player");
p.clear();
}
if (p == NULL) {
p = MediaPlayerFactory::createPlayer(playerType, this, notify);
}
if (p != NULL) {
p->setUID(mUID);
}
return p;
}
//主要是創建播放器
//上面看具體StagefrightPlayerFactory 實現的時候,代碼中實現了createPlayer,此處就是調用的此方法
//因此等價於return (new StagefrightPlayer()) ;
void MediaPlayerService::Client::setDataSource_post(
const sp<MediaPlayerBase>& p,
status_t status)
{
ALOGV(" setDataSource");
mStatus = status;
if (mStatus != OK) {
ALOGE(" error: %d", mStatus);
return;
}
// Set the re-transmission endpoint if one was chosen.
if (mRetransmitEndpointValid) {
mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
if (mStatus != NO_ERROR) {
ALOGE("setRetransmitEndpoint error: %d", mStatus);
}
}
if (mStatus == OK) {
mPlayer = p;
}
}
//setDataSource_post(p, p->setDataSource(source))
//設置播放器的數據源,因為實際的視屏播放是由該播放器完成
status_t StagefrightPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers) {
return mPlayer->setDataSource(url, headers);
}
status_t AwesomePlayer::setDataSource(
const char *uri, const KeyedVector<String8, String8> *headers) {
Mutex::Autolock autoLock(mLock);
return setDataSource_l(uri, headers);
}
status_t AwesomePlayer::setDataSource_l(
const char *uri, const KeyedVector<String8, String8> *headers) {
reset_l();
mUri = uri;
if (headers) {
mUriHeaders = *headers;
ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
if (index >= 0) {
// Browser is in "incognito" mode, suppress logging URLs.
// This isn't something that should be passed to the server.
mUriHeaders.removeItemsAt(index);
modifyFlags(INCOGNITO, SET);
}
}
ALOGI("setDataSource_l(URL suppressed)");
// The actual work will be done during preparation in the call to
// ::finishSetDataSource_l to avoid blocking the calling thread in
// setDataSource for any significant time.
{
Mutex::Autolock autoLock(mStatsLock);
mStats.mFd = -1;
mStats.mURI = mUri;
}
return OK;
}
//4、保存新的MediaPlayerService的Client對象,並斷開之前的Client和Service
status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
{
status_t err = UNKNOWN_ERROR;
sp<IMediaPlayer> p;
{ // scope for the lock
Mutex::Autolock _l(mLock);
if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
(mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
ALOGE("attachNewPlayer called in state %d", mCurrentState);
return INVALID_OPERATION;
}
//重置相關參數
clear_l();
p = mPlayer;
mPlayer = player;//更新Client屬性
if (player != 0) {
mCurrentState = MEDIA_PLAYER_INITIALIZED;
err = NO_ERROR;
} else {
ALOGE("Unable to create media player");
}
}
//斷開之前的Client
if (p != 0) {
p->disconnect();
}
return err;
}
// always call with lock held
void MediaPlayer::clear_l()
{
mCurrentPosition = -1;
mSeekPosition = -1;
mVideoWidth = mVideoHeight = 0;
mRetransmitEndpointValid = false;
}
void MediaPlayerService::Client::disconnect()
{
ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
// grab local reference and clear main reference to prevent future
// access to object
sp<MediaPlayerBase> p;
{
Mutex::Autolock l(mLock);
p = mPlayer;//播放器對象,如StagefrightPlayer
mClient.clear();//MdediaPlayer對象
}
mPlayer.clear();
// clear the notification to prevent callbacks to dead client
// and reset the player. We assume the player will serialize
// access to itself if necessary.
if (p != 0) {
p->setNotifyCallback(0, 0);
#if CALLBACK_ANTAGONIZER
ALOGD("kill Antagonizer");
mAntagonizer->kill();
#endif
p->reset();//調用具體播放器的reset函數,如
}
disconnectNativeWindow();
IPCThreadState::self()->flushCommands();
}
void MediaPlayerService::Client::disconnectNativeWindow() {
if (mConnectedWindow != NULL) {
status_t err = native_window_api_disconnect(mConnectedWindow.get(),
NATIVE_WINDOW_API_MEDIA);
if (err != OK) {
ALOGW("native_window_api_disconnect returned an error: %s (%d)",
strerror(-err), err);
}
}
mConnectedWindow.clear();
}
status_t StagefrightPlayer::reset() {
ALOGV("reset");
mPlayer->reset();
return OK;
}
//具體的reset操作,不同的播放器有不同的實現
void AwesomePlayer::reset_l() {
mVideoRenderingStarted = false;
mActiveAudioTrackIndex = -1;
mDisplayWidth = 0;
mDisplayHeight = 0;
if (mDecryptHandle != NULL) {
mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
Playback::STOP, 0);
mDecryptHandle = NULL;
mDrmManagerClient = NULL;
}
if (mFlags & PLAYING) {
uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
params |= IMediaPlayerService::kBatteryDataTrackAudio;
}
if (mVideoSource != NULL) {
params |= IMediaPlayerService::kBatteryDataTrackVideo;
}
addBatteryData(params);
}
if (mFlags & PREPARING) {
modifyFlags(PREPARE_CANCELLED, SET);
if (mConnectingDataSource != NULL) {
ALOGI("interrupting the connection process");
mConnectingDataSource->disconnect();
}
if (mFlags & PREPARING_CONNECTED) {
// We are basically done preparing, we're just buffering
// enough data to start playback, we can safely interrupt that.
finishAsyncPrepare_l();
}
}
while (mFlags & PREPARING) {
mPreparedCondition.wait(mLock);
}
cancelPlayerEvents();
mWVMExtractor.clear();
mCachedSource.clear();
mAudioTrack.clear();
mVideoTrack.clear();
mExtractor.clear();
// Shutdown audio first, so that the respone to the reset request
// appears to happen instantaneously as far as the user is concerned
// If we did this later, audio would continue playing while we
// shutdown the video-related resources and the player appear to
// not be as responsive to a reset request.
if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
&& mAudioSource != NULL) {
// If we had an audio player, it would have effectively
// taken possession of the audio source and stopped it when
// _it_ is stopped. Otherwise this is still our responsibility.
mAudioSource->stop();
}
mAudioSource.clear();
mTimeSource = NULL;
delete mAudioPlayer;
mAudioPlayer = NULL;
if (mTextDriver != NULL) {
delete mTextDriver;
mTextDriver = NULL;
}
mVideoRenderer.clear();
if (mVideoSource != NULL) {
shutdownVideoDecoder_l();
}
mDurationUs = -1;
modifyFlags(0, ASSIGN);
mExtractorFlags = 0;
mTimeSourceDeltaUs = 0;
mVideoTimeUs = 0;
mSeeking = NO_SEEK;
mSeekNotificationSent = true;
mSeekTimeUs = 0;
mUri.setTo("");
mUriHeaders.clear();
mFileSource.clear();
mBitrate = -1;
mLastVideoTimeUs = -1;
{
Mutex::Autolock autoLock(mStatsLock);
mStats.mFd = -1;
mStats.mURI = String8();
mStats.mBitrate = -1;
mStats.mAudioTrackIndex = -1;
mStats.mVideoTrackIndex = -1;
mStats.mNumVideoFramesDecoded = 0;
mStats.mNumVideoFramesDropped = 0;
mStats.mVideoWidth = -1;
mStats.mVideoHeight = -1;
mStats.mFlags = 0;
mStats.mTracks.clear();
}
mWatchForAudioSeekComplete = false;
mWatchForAudioEOS = false;
}
以上調用流程:
MediaPlayer(JAVA層)->MediaPlayer(C層)->Client->MediaPlayService->StagefrightPlayer->AwesomePlayer
最終所有對應具體文件的操作都需要AwesomePlayer落實,如:
prepare
play
pause
總結下幾種播放器的區別
StagefrightPlayer: 默認播放器,本地文件基本都使用其播放
NuPlayerDriver:主要用於播放網絡視頻,http https rtsp等
SonivoxPlayer:用於播放midi等類型的音樂
