Android's MediaPlayer class correlation function call

Benpian is to analyze the system to play Android device with MediaPlayer class process video during each class or function call each other, only the trunk analysis process, not the minutiae Sike, and dwell on achieving Native layer of C ++, I Xueshiqianbao qualifications, you forgot to criticism , pay more exchanges!

Since the function call when you want to analyze video player, must have a process, you can catch the trunk, the following is a typical sequence of play - a small Java application, we analyze the backbone of this process:

A block code is as follows:

 MediaPlayer mediaPlayer = new MediaPlayer();
 mediaPlayer.setDataSource("/sdcard/The Human.wav");
 mediaPlayer.prepare();
 mediaPlayer.start();
 mediaPlayer.stop();

First, A blocks of the first line of code: MediaPlayer mediaPlayer = new MediaPlayer (); // Create Object MediaPlayer

Native its constructor in the source layer as follows: (expression seems a little awkward, I want to express the application layer of Java programs -> JNI-> Native of C ++)

  MediaPlayer::MediaPlayer()
  {
      ALOGV("constructor");
      mListener = NULL;
      mCookie = NULL;
      mStreamType = AUDIO_STREAM_MUSIC;
      mCurrentPosition = -1;
      mSeekPosition = -1;
      mCurrentState = MEDIA_PLAYER_IDLE;
     mPrepareSync = false;
     mPrepareStatus = NO_ERROR;
     mLoop = false;
     mLeftVolume = mRightVolume = 1.0;
     mVideoWidth = mVideoHeight = 0;
     mLockThreadId = 0;
     mAudioSessionId = AudioSystem::newAudioSessionId();
     AudioSystem::acquireAudioSessionId(mAudioSessionId);
     mSendLevel = 0;
     mRetransmitEndpointValid = false;
 }

Here are just some of the not initialize class variables and process relationships, we continue to analyze the A block down the second line of code:

 mediaPlayer.setDataSource("/sdcard/The Human.wav");       

This function can be said that the most important function manual carefully reading this article, you will find the full analysis of all it! ! ! ! Native code which correspond to the following layers:

B-block code is as follows:

  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;
      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;
 }

Here we focus on the analysis of the fifth row of B block of code, the seventh row, the ninth row, the twelfth row

First a brief analysis of the role of each line under

B.5 (B fifth line of code blocks), const sp <IMediaPlayerService> & service (getMediaPlayerService ()), obtained MediaPlayerService;

B.7, sp <IMediaPlayer> player (service-> create (this, mAudiaSessionId)), the returned MediaPlayerService Client object Player, subsequent use of the Client will MediaPlayer services, so that each corresponds to a Client MediaPlayer

B.9, player-> setDataSource ( "sdcard / The Human.wav"), select the correct player, and the player provided data source

B.12, attachNewPlayer (player); save the latest Client object, the object is disconnected before the Client

The B.5 lines of code getMediaPlayerService () and obtain:

C-block code is as follows:

// establish binder interface to MediaPlayerService
/*static*/const sp<IMediaPlayerService>&
IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        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();
    }
    binder->linkToDeath(sDeathNotifier);
    sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    return sMediaPlayerService;
}

C above block code through a communication Binder, and ultimately achieve the purpose of obtaining MediaPlayerService, not the focus of this analysis, and its value is assigned Service

setDataSource operation to turn through interaction with mediaplayerservice to be completed

The B.7 line service-> create (this, mAudiaSessionId) opens, to obtain:

D-block code is as follows:

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;
}

Client class inheritance relationship is: Client-> BnMediaPlayer-> IMediaPlayer code above analysis, it can be seen create method, a Client object is constructed, and this client object is added to the global list mediapalyerservice class: mClient

Therefore, Server-side, our new target is Client, is MediaPlayerService inner class. The Client performed MediaPlayerService the vast majority of operations. Similarly, we also data transmission over the future are to be processed inside the class Client. Here, the object is created on the Server side, so just say that each of the above MediaPlayer corresponds to a Client

B returns to the previous block code, B.9 line player-> setDataSource ( "sdcard / The Human.wav"), expand:

To give E block code is as follows:

Block Code E

  status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
  {
      ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
      struct stat sb;
      int ret = fstat(fd, &sb);
      if (ret != 0) {
          ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
          return UNKNOWN_ERROR;
      }
 
     ALOGV("st_dev  = %llu", sb.st_dev);
     ALOGV("st_mode = %u", sb.st_mode);
     ALOGV("st_uid  = %lu", sb.st_uid);
     ALOGV("st_gid  = %lu", sb.st_gid);
     ALOGV("st_size = %llu", sb.st_size);
 
     if (offset >= sb.st_size) {
         ALOGE("offset error");
         ::close(fd);
         return UNKNOWN_ERROR;
     }
     if (offset + length > sb.st_size) {
         length = sb.st_size - offset;
         ALOGV("calculated length = %lld", length);
     }
 
     player_type playerType = MediaPlayerFactory::getPlayerType(this,
                                                                fd,
                                                                offset,
                                                                length);
     sp<MediaPlayerBase> p = setDataSource_pre(playerType);
     if (p == NULL) {
         return NO_INIT;
     }
 
     // now set data source
     setDataSource_post(p, p->setDataSource(fd, offset, length));
     return mStatus;
 }

 

E block of code focuses on E.27, E.31, E.37, (note though that side are setDataSource compared to its function, however, a start is a function of MediaPlayer, has now become a MediaPlayerService function, indicating that ultimately it MediaPlayerService in),

The E.27 Code getPlayerType (.......) Expand get:

Code: setDataSource_post (p, p-> setDataSource (fd, offset, length)); we focus setDataSource look at the second argument of this function (fd, offset, length), deployed as follows:

 

player_type MediaPlayerFactory::getPlayerType(constsp<IMediaPlayer>& client,
intfd,
int64_t offset,
int64_t length) {
GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
}

= Continued macro GET_PLAYER_TYPE_IMPL (client, fd, offset, length); expanded to give:

Code Block F

#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) { \
bestScore = getDefaultPlayerType(); \
} \
\
returnret;

We look v-> scoreFactory (a, bestScore); this code, which use the factory pattern and scoring mechanism Andrew system, this is currently only understand a little bit, here is the choice in the registration of several players the highest scoring player to perform the next process, if all the players are not appropriate, it will select the default player to operate,

The next line of code to continue E.31 setDataSource_pre (playerType), get:

G Block Code

  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;
     }
 
     if (!p->hardwareOutput()) {
         mAudioOutput = new AudioOutput(mAudioSessionId);
         static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
     }
 
     return p;
 }

Continue the above seventh row createPlayer (playerType) to give the following code:

  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;
 }

Line 10 to continue the above, here the Factory design pattern, in which the source /frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp, expand MediaPlayerFactory :: createPlayer (playerType, this, notify) ;, as follows:

 sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
          player_type playerType,
          void* cookie,
          notify_callback_f notifyFunc) {
      sp<MediaPlayerBase> p;
      IFactory* factory;
      status_t init_result;
      Mutex::Autolock lock_(&sLock);
  
     if (sFactoryMap.indexOfKey(playerType) < 0) {
         ALOGE("Failed to create player object of type %d, no registered"
               " factory", playerType);
         return p;
     }
 
     factory = sFactoryMap.valueFor(playerType);
     CHECK(NULL != factory);
     p = factory->createPlayer();
 
    if (p == NULL) {
         ALOGE("Failed to create player object of type %d, create failed",
                playerType);
         return p;
     }
 
     init_result = p->initCheck();
     if (init_result == NO_ERROR) {
         p->setNotifyCallback(cookie, notifyFunc);
     } else {
         ALOGE("Failed to create player object of type %d, initCheck failed"
               " (res = %d)", playerType, init_result);
         p.clear();
     }
 
     return p;
 }

 

Analysis of the above code, line 18, which is representative of the foregoing Factory Rate mode that acquires the highest score of the class factory player, such as

class OMXPlayerFactory : public MediaPlayerFactory::IFactory
class StagefrightPlayerFactory : public MediaPlayerFactory::IFactory 
class NuPlayerFactory : public MediaPlayerFactory::IFactory

Factory class prototype is as follows:

class IFactory {
   public:
     virtual ~IFactory() { }
     virtual float scoreFactory(const sp<IMediaPlayer>& client,
                                const char* url,
                                float curScore,
                                const KeyedVector<String8, String8> *headers = NULL) { return 0.0; }
     virtual float scoreFactory(const sp<IMediaPlayer>& client,
                                int fd,
                                int64_t offset,
                                int64_t length,
                                float curScore) { return 0.0; }
     virtual float scoreFactory(const sp<IMediaPlayer>& client,
                                const sp<IStreamSource> &source,
                                float curScore) { return 0.0; }
     virtual sp<MediaPlayerBase> createPlayer() = 0;
 };

How can assume their diligence scoring mechanism is selected StagefrightPlayerFactory, to continue the code on line 18 factory-> createPlayer (), and obtained the following code:

     virtual sp<MediaPlayerBase> createPlayer() {
         ALOGV(" create StagefrightPlayer");
         return new StagefrightPlayer();
     }

View StagefrightPlayer class constructor

 StagefrightPlayer::StagefrightPlayer()
     : mPlayer(new AwesomePlayer) {
     ALOGV("StagefrightPlayer");
 
     mPlayer->setListener(this);
 }

It now appears that the real work of the people there are AwesomePlayer, to work the players have finally created the

This is the code we analyzed sp E.31 of <MediaPlayerBase> p = setDataSource_pre (playerType) ;, how kind is not to go too far forgot a fork in the time to come, let us continue to analyze E.37 line bar code; setDataSource_post (p, p-> setDataSource (fd, offset, length)); which is to analyze the second parameter p-> setDataSource (fd, offset, length), but the use here of the player to work set some properties, call time, the actual implementation of the method setDataSource player, but actual setDataSource_post just the player stored in the local member mPlayer, the code is as follows:

void MediaPlayerService::Client::setDataSource_post(
constsp<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;
}
}

Here we analyze the calling process came to an end also continue to analyze down is StagefrightPlaye concrete realization, and so over a period of time to figure out the detailed implementation Bowen released again on stagefrightPlayer achieved!

Comments welcome, welcome to exchange, I will respond promptly, progress with each other .......

Guess you like

Origin blog.csdn.net/shanshenyuyou/article/details/90779870