MediaPlayer 播放器全面剖析(一)

一、MediaPlayer状态

Android官网上赫然挂着这张MediaPlayer状态图,熟悉这张图,对了解MediaPlayer的工作原理有很大的帮助;
下图中,单箭头表示同步调用,双箭头表示异步调用;


MediaPlayer 播放器全面剖析(一)_第1张图片
mediaplayer_state_diagram.gif
  • MediaPlayer 创建实例或者在调用reset方法之后,播放器处于Idle状态;
  • MediaPlayer 有prepare 和 prepareAysnc两种方法,prepare 针对本地音视频,是同步的;prepareAsync针对网络音视频,异步的;
  • MediaPlayer在播放中调用pause函数,Started ---> Paused 状态切换是瞬间的;但是再次调用 MediaPlayer.start函数,Paused ---> Started 状态切换需要一些耗时;即时是本地音视频,也是需要一些耗时的;
  • MediaPlayer 进入onPrepared状态,才可以设置一些属性,例如 音量、 screenOnWhilePlaying looping;第一次调start函数有效,后续调用无效;
  • MediaPlayer.stop ---> 播放器进入Stopped状态,这事想要重新激活,可以重新调用prepare / prepareAsync 函数

二、MediaPlayer 调用流程剖析

MediaPlayer 从启动,初始化,setDataSource,到 setSurface 步骤的操作过程;


MediaPlayer 播放器全面剖析(一)_第2张图片
MediaPlayer.png
MediaPlayer 播放器全面剖析(一)_第3张图片
MediaPlayer 类关系


本章讲解涉及到的源码路径:
/frameworks/base/media/java/android/media/MediaPlayer.java

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

/frameworks/av/media/libmedia/mediaplayer.cpp

/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp

/frameworks/av/include/media/MediaPlayerInterface.h

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp

/frameworks/av/media/libmedia/mediaplayer.cpp




下面从源码的角度分析一下重要的执行流程:
/frameworks/av/media/libmedia/mediaplayer.cpp

175status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
176{
177    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
178    status_t err = UNKNOWN_ERROR;
179    const sp service(getMediaPlayerService());
180    if (service != 0) {
181        sp player(service->create(this, mAudioSessionId));
182        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
183            (NO_ERROR != player->setDataSource(fd, offset, length))) {
184            player.clear();
185        }
186        err = attachNewPlayer(player);
187    }
188    return err;
189}

执行了:
sp player(service->create(this, mAudioSessionId));

313sp MediaPlayerService::create(const sp& client,
314        audio_session_t audioSessionId)
315{
316    pid_t pid = IPCThreadState::self()->getCallingPid();
317    int32_t connId = android_atomic_inc(&mNextConnId);
318
319    sp c = new Client(
320            this, pid, connId, client, audioSessionId,
321            IPCThreadState::self()->getCallingUid());
322
323    ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
324         IPCThreadState::self()->getCallingUid());
325
326    wp w = c;
327    {
328        Mutex::Autolock lock(mLock);
329        mClients.add(w);
330    }
331    return c;
332}

调用到MediaPlayerService::Client 类中:

795status_t MediaPlayerService::Client::setDataSource(
796        const sp &httpService,
797        const char *url,
798        const KeyedVector *headers)
799{
800    ALOGV("setDataSource(%s)", url);
801    if (url == NULL)
802        return UNKNOWN_ERROR;
803
804    if ((strncmp(url, "http://", 7) == 0) ||
805        (strncmp(url, "https://", 8) == 0) ||
806        (strncmp(url, "rtsp://", 7) == 0)) {
807        if (!checkPermission("android.permission.INTERNET")) {
808            return PERMISSION_DENIED;
809        }
810    }
811
812    if (strncmp(url, "content://", 10) == 0) {
813        // get a filedescriptor for the content Uri and
814        // pass it to the setDataSource(fd) method
815
816        String16 url16(url);
817        int fd = android::openContentProviderFile(url16);
818        if (fd < 0)
819        {
820            ALOGE("Couldn't open fd for %s", url);
821            return UNKNOWN_ERROR;
822        }
823        status_t status = setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
824        close(fd);
825        return mStatus = status;
826    } else {
827        player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
828        sp p = setDataSource_pre(playerType);
829        if (p == NULL) {
830            return NO_INIT;
831        }
832
833        return mStatus =
834                setDataSource_post(
835                p, p->setDataSource(httpService, url, headers));
836    }
837}

重点关注这个代码片段的执行流程:

827        player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
828        sp p = setDataSource_pre(playerType);
829        if (p == NULL) {
830            return NO_INIT;
831        }
832
833        return mStatus =
834                setDataSource_post(
835                p, p->setDataSource(httpService, url, headers));

这儿会执行两个函数:
setDataSource_pre
setDataSource_post

从字面上可以理解,一个是setDataSource 执行前,一个是setDataSource执行后;

724sp MediaPlayerService::Client::setDataSource_pre(
725        player_type playerType)
726{
727    ALOGV("player type = %d", playerType);
728
729    // create the right type of player
730    sp p = createPlayer(playerType);
731    if (p == NULL) {
732        return p;
733    }
734
735    sp sm = defaultServiceManager();
736    sp binder = sm->getService(String16("media.extractor"));
737    if (binder == NULL) {
738        ALOGE("extractor service not available");
739        return NULL;
740    }
741    sp extractorDeathListener =
742            new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
743    binder->linkToDeath(extractorDeathListener);
744
745    sp omx = IOmx::getService();
746    if (omx == nullptr) {
747        ALOGE("IOmx service is not available");
748        return NULL;
749    }
750    sp codecDeathListener =
751            new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
752    omx->linkToDeath(codecDeathListener, 0);
753
754    Mutex::Autolock lock(mLock);
755
756    clearDeathNotifiers_l();
757    mExtractorDeathListener = extractorDeathListener;
758    mCodecDeathListener = codecDeathListener;
759    mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
760
761    if (!p->hardwareOutput()) {
762        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
763                mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
764        static_cast(p.get())->setAudioSink(mAudioOutput);
765    }
766
767    return p;
768}
  • 获取 media.extractor 服务;
  • 获取omx服务;

这两个服务在视频解析和解码的流程中非常重要;

其中在mediaplayer.cpp 中有调用 getMediaPlayerService()函数,具体是在
/frameworks/av/media/libmedia/IMediaDeathNotifier.cpp

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

调用的是初始化定义的media.player服务,就实现从Client到Server端之间的调用;

/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp

241void MediaPlayerFactory::registerBuiltinFactories() {
242    Mutex::Autolock lock_(&sLock);
243
244    if (sInitComplete)
245        return;
246
247    IFactory* factory = new NuPlayerFactory();
248    if (registerFactory_l(factory, NU_PLAYER) != OK)
249        delete factory;
250    factory = new TestPlayerFactory();
251    if (registerFactory_l(factory, TEST_PLAYER) != OK)
252        delete factory;
253
254    sInitComplete = true;
255}

MediaPlayerFactory.cpp是管理播放器的一个工厂类,从源码中可以看出来,目前只有一个NuPlayerFactory 管理类了,TestPlayerFactory 是测试使用的,可以忽略;
NuPlayerFactory工厂类源码如下:

164/*****************************************************************************
165 *                                                                           *
166 *                     Built-In Factory Implementations                      *
167 *                                                                           *
168 *****************************************************************************/
169
170class NuPlayerFactory : public MediaPlayerFactory::IFactory {
171  public:
172    virtual float scoreFactory(const sp& /*client*/,
173                               const char* url,
174                               float curScore) {
175        static const float kOurScore = 0.8;
176
177        if (kOurScore <= curScore)
178            return 0.0;
179
180        if (!strncasecmp("http://", url, 7)
181                || !strncasecmp("https://", url, 8)
182                || !strncasecmp("file://", url, 7)) {
183            size_t len = strlen(url);
184            if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
185                return kOurScore;
186            }
187
188            if (strstr(url,"m3u8")) {
189                return kOurScore;
190            }
191
192            if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) {
193                return kOurScore;
194            }
195        }
196
197        if (!strncasecmp("rtsp://", url, 7)) {
198            return kOurScore;
199        }
200
201        return 0.0;
202    }
203
204    virtual float scoreFactory(const sp& /*client*/,
205                               const sp& /*source*/,
206                               float /*curScore*/) {
207        return 1.0;
208    }
209
210    virtual float scoreFactory(const sp& /*client*/,
211                               const sp& /*source*/,
212                               float /*curScore*/) {
213        // Only NuPlayer supports setting a DataSource source directly.
214        return 1.0;
215    }
216
217    virtual sp createPlayer(pid_t pid) {
218        ALOGV(" create NuPlayer");
219        return new NuPlayerDriver(pid);
220    }
221};

最终createPlayer中是实例化一个NuPlayerDriver对象;
这儿判断是否是m3u8视频类型简直是简单粗暴啊;

  • url的后缀名是不是.m3u8;
  • url中是否包含 m3u8 字符串;
184            if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
185                return kOurScore;
186            }
187
188            if (strstr(url,"m3u8")) {
189                return kOurScore;
190            }

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp

71NuPlayerDriver::NuPlayerDriver(pid_t pid)
72    : mState(STATE_IDLE),
73      mIsAsyncPrepare(false),
74      mAsyncResult(UNKNOWN_ERROR),
75      mSetSurfaceInProgress(false),
76      mDurationUs(-1),
77      mPositionUs(-1),
78      mSeekInProgress(false),
79      mPlayingTimeUs(0),
80      mRebufferingTimeUs(0),
81      mRebufferingEvents(0),
82      mRebufferingAtExit(false),
83      mLooper(new ALooper),
84      mMediaClock(new MediaClock),
85      mPlayer(new NuPlayer(pid, mMediaClock)),
86      mPlayerFlags(0),
87      mAnalyticsItem(NULL),
88      mClientUid(-1),
89      mAtEOS(false),
90      mLooping(false),
91      mAutoLoop(false) {
92    ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
93    mLooper->setName("NuPlayerDriver Looper");
94
95    mMediaClock->init();
96
97    // set up an analytics record
98    mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
99
100    mLooper->start(
101            false, /* runOnCallingThread */
102            true,  /* canCallJava */
103            PRIORITY_AUDIO);
104
105    mLooper->registerHandler(mPlayer);
106
107    mPlayer->init(this);
108}
mPlayer(new NuPlayer(pid, mMediaClock)),

setDataSource 会执行到NuPlayer.cpp 中:

257void NuPlayer::setDataSourceAsync(
258        const sp &httpService,
259        const char *url,
260        const KeyedVector *headers) {
261
262    sp msg = new AMessage(kWhatSetDataSource, this);
263    size_t len = strlen(url);
264
265    sp notify = new AMessage(kWhatSourceNotify, this);
266
267    sp source;
268    if (IsHTTPLiveURL(url)) {
269        source = new HTTPLiveSource(notify, httpService, url, headers);
270        ALOGV("setDataSourceAsync HTTPLiveSource %s", url);
271        mDataSourceType = DATA_SOURCE_TYPE_HTTP_LIVE;
272    } else if (!strncasecmp(url, "rtsp://", 7)) {
273        source = new RTSPSource(
274                notify, httpService, url, headers, mUIDValid, mUID);
275        ALOGV("setDataSourceAsync RTSPSource %s", url);
276        mDataSourceType = DATA_SOURCE_TYPE_RTSP;
277    } else if ((!strncasecmp(url, "http://", 7)
278                || !strncasecmp(url, "https://", 8))
279                    && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
280                    || strstr(url, ".sdp?"))) {
281        source = new RTSPSource(
282                notify, httpService, url, headers, mUIDValid, mUID, true);
283        ALOGV("setDataSourceAsync RTSPSource http/https/.sdp %s", url);
284        mDataSourceType = DATA_SOURCE_TYPE_RTSP;
285    } else {
286        ALOGV("setDataSourceAsync GenericSource %s", url);
287
288        sp genericSource =
289                new GenericSource(notify, mUIDValid, mUID, mMediaClock);
290
291        status_t err = genericSource->setDataSource(httpService, url, headers);
292
293        if (err == OK) {
294            source = genericSource;
295        } else {
296            ALOGE("Failed to set data source!");
297        }
298
299        // regardless of success/failure
300        mDataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
301    }
302    msg->setObject("source", source);
303    msg->post();
304}

通过NuPlayer.cpp 内部定义的AMessage 消息来控制:

548void NuPlayer::onMessageReceived(const sp &msg) {
549    switch (msg->what()) {
550        case kWhatSetDataSource:
551        {
552            ALOGV("kWhatSetDataSource");
553
554            CHECK(mSource == NULL);
555
556            status_t err = OK;
557            sp obj;
558            CHECK(msg->findObject("source", &obj));
559            if (obj != NULL) {
560                Mutex::Autolock autoLock(mSourceLock);
561                mSource = static_cast(obj.get());
562            } else {
563                err = UNKNOWN_ERROR;
564            }
565
566            CHECK(mDriver != NULL);
567            sp driver = mDriver.promote();
568            if (driver != NULL) {
569                driver->notifySetDataSourceCompleted(err);
570            }
571            break;
572        }

接收到消息,将传入的source赋给mSource对象;
根据url来封装source:

267    sp source;
268    if (IsHTTPLiveURL(url)) {
269        source = new HTTPLiveSource(notify, httpService, url, headers);
270        ALOGV("setDataSourceAsync HTTPLiveSource %s", url);
271        mDataSourceType = DATA_SOURCE_TYPE_HTTP_LIVE;
272    } else if (!strncasecmp(url, "rtsp://", 7)) {
273        source = new RTSPSource(
274                notify, httpService, url, headers, mUIDValid, mUID);
275        ALOGV("setDataSourceAsync RTSPSource %s", url);
276        mDataSourceType = DATA_SOURCE_TYPE_RTSP;
277    } else if ((!strncasecmp(url, "http://", 7)
278                || !strncasecmp(url, "https://", 8))
279                    && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
280                    || strstr(url, ".sdp?"))) {
281        source = new RTSPSource(
282                notify, httpService, url, headers, mUIDValid, mUID, true);
283        ALOGV("setDataSourceAsync RTSPSource http/https/.sdp %s", url);
284        mDataSourceType = DATA_SOURCE_TYPE_RTSP;
285    } else {
286        ALOGV("setDataSourceAsync GenericSource %s", url);
287
288        sp genericSource =
289                new GenericSource(notify, mUIDValid, mUID, mMediaClock);
290
291        status_t err = genericSource->setDataSource(httpService, url, headers);
292
293        if (err == OK) {
294            source = genericSource;
295        } else {
296            ALOGE("Failed to set data source!");
297        }
298
299        // regardless of success/failure
300        mDataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
301    }

/frameworks/av/include/media/stagefright/foundation/AHandler.h

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerSource.h

/frameworks/av/media/libmediaplayerservice/nuplayer/StreamingSource.h

/frameworks/av/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h

/frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.h

/frameworks/av/media/libmediaplayerservice/nuplayer/RTSPSource.h

MediaPlayer 播放器全面剖析(一)_第4张图片
MediaPlayer Source 类关系

HTTPLiveSource:针对m3u8 视频,实际上直播不止m3u8一种类型,MediaPlayer 支持有限;
RTSPSource:这是针对RTSP的流,MediaPlayer专门针对RTSP的流做了优化;
GenericSource:通用的source,一些http https file:///协议的url都是走这儿的;

240static bool IsHTTPLiveURL(const char *url) {
241    if (!strncasecmp("http://", url, 7)
242            || !strncasecmp("https://", url, 8)
243            || !strncasecmp("file://", url, 7)) {
244        size_t len = strlen(url);
245        if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
246            return true;
247        }
248
249        if (strstr(url,"m3u8")) {
250            return true;
251        }
252    }
253
254    return false;
255}

setVideoSurfaceTexture 执行到 MediaPlayerService.cpp:

916status_t MediaPlayerService::Client::setVideoSurfaceTexture(
917        const sp& bufferProducer)
918{
919    ALOGV("[%d] setVideoSurfaceTexture(%p)", mConnId, bufferProducer.get());
920    sp p = getPlayer();
921    if (p == 0) return UNKNOWN_ERROR;
922
923    sp binder(IInterface::asBinder(bufferProducer));
924    if (mConnectedWindowBinder == binder) {
925        return OK;
926    }
927
928    sp anw;
929    if (bufferProducer != NULL) {
930        anw = new Surface(bufferProducer, true /* controlledByApp */);
931        status_t err = nativeWindowConnect(anw.get(), "setVideoSurfaceTexture");
932
933        if (err != OK) {
934            ALOGE("setVideoSurfaceTexture failed: %d", err);
935            // Note that we must do the reset before disconnecting from the ANW.
936            // Otherwise queue/dequeue calls could be made on the disconnected
937            // ANW, which may result in errors.
938            reset();
939
940            Mutex::Autolock lock(mLock);
941            disconnectNativeWindow_l();
942
943            return err;
944        }
945    }
946
947    // Note that we must set the player's new GraphicBufferProducer before
948    // disconnecting the old one.  Otherwise queue/dequeue calls could be made
949    // on the disconnected ANW, which may result in errors.
950    status_t err = p->setVideoSurfaceTexture(bufferProducer);
951
952    mLock.lock();
953    disconnectNativeWindow_l();
954
955    if (err == OK) {
956        mConnectedWindow = anw;
957        mConnectedWindowBinder = binder;
958        mLock.unlock();
959    } else {
960        mLock.unlock();
961        status_t err = nativeWindowDisconnect(
962                anw.get(), "disconnectNativeWindow");
963
964        if (err != OK) {
965            ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
966                    strerror(-err), err);
967        }
968    }
969
970    return err;
971}

创建一个Surface对象:

930        anw = new Surface(bufferProducer, true /* controlledByApp */);
931        status_t err = nativeWindowConnect(anw.get(), "setVideoSurfaceTexture");
950    status_t err = p->setVideoSurfaceTexture(bufferProducer);

这个p 对象就是 MediaPlayerFactory 中定义的 NuPlayer对象;
上面也说过了NuPlayer 是在NuPlayerDriver中定义的;
/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp

377void NuPlayer::setVideoSurfaceTextureAsync(
378        const sp &bufferProducer) {
379    sp msg = new AMessage(kWhatSetVideoSurface, this);
380
381    if (bufferProducer == NULL) {
382        msg->setObject("surface", NULL);
383    } else {
384        msg->setObject("surface", new Surface(bufferProducer, true /* controlledByApp */));
385    }
386
387    msg->post();
388}

发送一个异步消息通知设置Surface成功了;

Surface设置成功了,setDataSource 也设置成功了,接下来开始发起请求了,MediaPlayer发起请求的函数是prepare 或者 prepareAsync 函数,一个是同步请求,一个是异步请求,建议还是使用异步请求,毕竟网络请求有时候比较慢;

下面主要分析MediaPlayer->prepareAsync 执行流程:


MediaPlayer 播放器全面剖析(一)_第5张图片
MediaPlayer->prepareAsync调用流程

/frameworks/av/media/libmedia/mediaplayer.cpp
中持有的mPlayer 对象就是 MediaPlayerService::Client 对象;

273status_t MediaPlayer::prepareAsync_l()
274{
275    if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
276        if (mAudioAttributesParcel != NULL) {
277            mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
278        } else {
279            mPlayer->setAudioStreamType(mStreamType);
280        }
281        mCurrentState = MEDIA_PLAYER_PREPARING;
282        return mPlayer->prepareAsync();
283    }
284    ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
285    return INVALID_OPERATION;
286}

上面两个都是设置一些播放过程中的基本参数,主要是mPlayer->prepareAsync()

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp

306status_t NuPlayerDriver::prepareAsync() {
307    ALOGV("prepareAsync(%p)", this);
308    Mutex::Autolock autoLock(mLock);
309
310    switch (mState) {
311        case STATE_UNPREPARED:
312            mState = STATE_PREPARING;
313            mIsAsyncPrepare = true;
314            mPlayer->prepareAsync();
315            return OK;
316        case STATE_STOPPED:
317            // this is really just paused. handle as seek to start
318            mAtEOS = false;
319            mState = STATE_STOPPED_AND_PREPARING;
320            mIsAsyncPrepare = true;
321            mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
322                    true /* needNotify */);
323            return OK;
324        default:
325            return INVALID_OPERATION;
326    };
327}

源码中看出这儿执行prepareAsync 也是需要看播放器当前的播放状态的,STATE_UNPREPARED 的时候说明播放器之前从没有执行过prepare ;STATE_STOPPED 说明播放器执行了 stop 函数;
其他状态的情况下prepareAsync 可以直接忽略;

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp

371void NuPlayer::prepareAsync() {
372    ALOGV("prepareAsync");
373
374    (new AMessage(kWhatPrepare, this))->post();
375}

NuPlayer 中定义了一个 Handler message处理机制:

548void NuPlayer::onMessageReceived(const sp &msg)

执行到NuPlayer-->prepareAsync(...)中的函数,需要发送一个 :
(new AMessage(kWhatPrepare, this))->post()
消息;

616        case kWhatPrepare:
617        {
618            ALOGV("onMessageReceived kWhatPrepare");
619
620            mSource->prepareAsync();
621            break;
622        }

从上面源码可以看出,这个mSource是 执行setDataSource的时候设置进去的,有3种Source,我们以GenericSource 为例;
/frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp

342void NuPlayer::GenericSource::prepareAsync() {
343    Mutex::Autolock _l(mLock);
344    ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
345
346    if (mLooper == NULL) {
347        mLooper = new ALooper;
348        mLooper->setName("generic");
349        mLooper->start();
350
351        mLooper->registerHandler(this);
352    }
353
354    sp msg = new AMessage(kWhatPrepareAsync, this);
355    msg->post();
356}
583void NuPlayer::GenericSource::onMessageReceived(const sp &msg) {
584    Mutex::Autolock _l(mLock);
585    switch (msg->what()) {
586      case kWhatPrepareAsync:
587      {
588          onPrepareAsync();
589          break;
590      }

这个函数中是执行视频资源网络请求的核心函数;

358void NuPlayer::GenericSource::onPrepareAsync() {
359    ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
360
361    // delayed data source creation
362    if (mDataSource == NULL) {
363        // set to false first, if the extractor
364        // comes back as secure, set it to true then.
365        mIsSecure = false;
366
367        if (!mUri.empty()) {
368            const char* uri = mUri.c_str();
369            String8 contentType;
370
371            if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
372                mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
373                if (mHttpSource == NULL) {
374                    ALOGE("Failed to create http source!");
375                    notifyPreparedAndCleanup(UNKNOWN_ERROR);
376                    return;
377                }
378            }
379
380            mLock.unlock();
381            // This might take long time if connection has some issue.
382            sp dataSource = DataSourceFactory::CreateFromURI(
383                   mHTTPService, uri, &mUriHeaders, &contentType,
384                   static_cast(mHttpSource.get()));
385            mLock.lock();
386            if (!mDisconnected) {
387                mDataSource = dataSource;
388            }
389        } else {
390            if (property_get_bool("media.stagefright.extractremote", true) &&
391                    !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
392                sp binder =
393                        defaultServiceManager()->getService(String16("media.extractor"));
394                if (binder != nullptr) {
395                    ALOGD("FileSource remote");
396                    sp mediaExService(
397                            interface_cast(binder));
398                    sp source =
399                            mediaExService->makeIDataSource(mFd, mOffset, mLength);
400                    ALOGV("IDataSource(FileSource): %p %d %lld %lld",
401                            source.get(), mFd, (long long)mOffset, (long long)mLength);
402                    if (source.get() != nullptr) {
403                        mDataSource = CreateDataSourceFromIDataSource(source);
404                        if (mDataSource != nullptr) {
405                            // Close the local file descriptor as it is not needed anymore.
406                            close(mFd);
407                            mFd = -1;
408                        }
409                    } else {
410                        ALOGW("extractor service cannot make data source");
411                    }
412                } else {
413                    ALOGW("extractor service not running");
414                }
415            }
416            if (mDataSource == nullptr) {
417                ALOGD("FileSource local");
418                mDataSource = new FileSource(mFd, mOffset, mLength);
419            }
420            // TODO: close should always be done on mFd, see the lines following
421            // CreateDataSourceFromIDataSource above,
422            // and the FileSource constructor should dup the mFd argument as needed.
423            mFd = -1;
424        }
425
426        if (mDataSource == NULL) {
427            ALOGE("Failed to create data source!");
428            notifyPreparedAndCleanup(UNKNOWN_ERROR);
429            return;
430        }
431    }
432
433    if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
434        mCachedSource = static_cast(mDataSource.get());
435    }
436
437    // For cached streaming cases, we need to wait for enough
438    // buffering before reporting prepared.
439    mIsStreaming = (mCachedSource != NULL);
440
441    // init extractor from data source
442    status_t err = initFromDataSource();
443
444    if (err != OK) {
445        ALOGE("Failed to init from data source!");
446        notifyPreparedAndCleanup(err);
447        return;
448    }
449
450    if (mVideoTrack.mSource != NULL) {
451        sp meta = getFormatMeta_l(false /* audio */);
452        sp msg = new AMessage;
453        err = convertMetaDataToMessage(meta, &msg);
454        if(err != OK) {
455            notifyPreparedAndCleanup(err);
456            return;
457        }
458        notifyVideoSizeChanged(msg);
459    }
460
461    notifyFlagsChanged(
462            // FLAG_SECURE will be known if/when prepareDrm is called by the app
463            // FLAG_PROTECTED will be known if/when prepareDrm is called by the app
464            FLAG_CAN_PAUSE |
465            FLAG_CAN_SEEK_BACKWARD |
466            FLAG_CAN_SEEK_FORWARD |
467            FLAG_CAN_SEEK);
468
469    finishPrepareAsync();
470
471    ALOGV("onPrepareAsync: Done");
472}

关键的执行片段是:

371            if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
372                mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
373                if (mHttpSource == NULL) {
374                    ALOGE("Failed to create http source!");
375                    notifyPreparedAndCleanup(UNKNOWN_ERROR);
376                    return;
377                }
378            }
379
380            mLock.unlock();
381            // This might take long time if connection has some issue.
382            sp dataSource = DataSourceFactory::CreateFromURI(
383                   mHTTPService, uri, &mUriHeaders, &contentType,
384                   static_cast(mHttpSource.get()));
385            mLock.lock();
386            if (!mDisconnected) {
387                mDataSource = dataSource;
388            }

开始onPrepared 和 onVideoSizeChanged 回调:

450    if (mVideoTrack.mSource != NULL) {
451        sp meta = getFormatMeta_l(false /* audio */);
452        sp msg = new AMessage;
453        err = convertMetaDataToMessage(meta, &msg);
454        if(err != OK) {
455            notifyPreparedAndCleanup(err);
456            return;
457        }
458        notifyVideoSizeChanged(msg);
459    }

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerSource.h

/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp

2487        case Source::kWhatPrepared:
2488        {
2489            ALOGV("NuPlayer::onSourceNotify Source::kWhatPrepared source: %p", mSource.get());
2490            if (mSource == NULL) {
2491                // This is a stale notification from a source that was
2492                // asynchronously preparing when the client called reset().
2493                // We handled the reset, the source is gone.
2494                break;
2495            }
2496
2497            int32_t err;
2498            CHECK(msg->findInt32("err", &err));
2499
2500            if (err != OK) {
2501                // shut down potential secure codecs in case client never calls reset
2502                mDeferredActions.push_back(
2503                        new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
2504                                               FLUSH_CMD_SHUTDOWN /* video */));
2505                processDeferredActions();
2506            } else {
2507                mPrepared = true;
2508            }
2509
2510            sp driver = mDriver.promote();
2511            if (driver != NULL) {
2512                // notify duration first, so that it's definitely set when
2513                // the app received the "prepare complete" callback.
2514                int64_t durationUs;
2515                if (mSource->getDuration(&durationUs) == OK) {
2516                    driver->notifyDuration(durationUs);
2517                }
2518                driver->notifyPrepareCompleted(err);
2519            }
2520
2521            break;
2522        }
2510            sp driver = mDriver.promote();
2511            if (driver != NULL) {
2512                // notify duration first, so that it's definitely set when
2513                // the app received the "prepare complete" callback.
2514                int64_t durationUs;
2515                if (mSource->getDuration(&durationUs) == OK) {
2516                    driver->notifyDuration(durationUs);
2517                }
2518                driver->notifyPrepareCompleted(err);
2519            }

回调了notifyPrepareCompleted 和 notifyDuration

其中/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
继承了
/frameworks/av/media/libmediaplayerservice/include/MediaPlayerInterface.h
所有底层NuPlayer的回调会通过NuPlayerDriver.h 中的sendEvent 到MediaPlayerInterface.h:

282    void        sendEvent(int msg, int ext1=0, int ext2=0,
283                          const Parcel *obj=NULL) {
284        sp listener;
285        {
286            Mutex::Autolock autoLock(mNotifyLock);
287            listener = mListener;
288        }
289
290        if (listener != NULL) {
291            listener->notify(msg, ext1, ext2, obj);
292        }
293    }

这个listener 是MediaPlayerService.cpp中设置进来的,所有还会回调到MediaPlayerService.cpp

1424void MediaPlayerService::Client::notify(
1425        int msg, int ext1, int ext2, const Parcel *obj)
1426{
1427    sp c;
1428    sp nextClient;
1429    status_t errStartNext = NO_ERROR;
1430    {
1431        Mutex::Autolock l(mLock);
1432        c = mClient;
1433        if (msg == MEDIA_PLAYBACK_COMPLETE && mNextClient != NULL) {
1434            nextClient = mNextClient;
1435
1436            if (mAudioOutput != NULL)
1437                mAudioOutput->switchToNextOutput();
1438
1439            errStartNext = nextClient->start();
1440        }
1441    }
1442
1443    if (nextClient != NULL) {
1444        sp nc;
1445        {
1446            Mutex::Autolock l(nextClient->mLock);
1447            nc = nextClient->mClient;
1448        }
1449        if (nc != NULL) {
1450            if (errStartNext == NO_ERROR) {
1451                nc->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
1452            } else {
1453                nc->notify(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN , 0, obj);
1454                ALOGE("gapless:start playback for next track failed, err(%d)", errStartNext);
1455            }
1456        }
1457    }
1458
1459    if (MEDIA_INFO == msg &&
1460        MEDIA_INFO_METADATA_UPDATE == ext1) {
1461        const media::Metadata::Type metadata_type = ext2;
1462
1463        if(shouldDropMetadata(metadata_type)) {
1464            return;
1465        }
1466
1467        // Update the list of metadata that have changed. getMetadata
1468        // also access mMetadataUpdated and clears it.
1469        addNewMetadataUpdate(metadata_type);
1470    }
1471
1472    if (c != NULL) {
1473        ALOGV("[%d] notify (%d, %d, %d)", mConnId, msg, ext1, ext2);
1474        c->notify(msg, ext1, ext2, obj);
1475    }
1476}

/frameworks/av/media/libmedia/mediaplayer.cpp
继承
/frameworks/av/media/libmedia/IMediaPlayerClient.cpp

上层MediaPlayer 所有的回调都会集中在
/frameworks/av/media/libmedia/mediaplayer.cpp
中的notify 函数回调:

848void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
849{
850    ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
851    bool send = true;
852    bool locked = false;
853
854    // TODO: In the future, we might be on the same thread if the app is
855    // running in the same process as the media server. In that case,
856    // this will deadlock.
857    //
858    // The threadId hack below works around this for the care of prepare,
859    // seekTo, start, and reset within the same process.
860    // FIXME: Remember, this is a hack, it's not even a hack that is applied
861    // consistently for all use-cases, this needs to be revisited.
862    if (mLockThreadId != getThreadId()) {
863        mLock.lock();
864        locked = true;
865    }
866
867    // Allows calls from JNI in idle state to notify errors
868    if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
869        ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
870        if (locked) mLock.unlock();   // release the lock when done.
871        return;
872    }
873
874    switch (msg) {
875    case MEDIA_NOP: // interface test message
876        break;
877    case MEDIA_PREPARED:
878        ALOGV("MediaPlayer::notify() prepared");
879        mCurrentState = MEDIA_PLAYER_PREPARED;
880        if (mPrepareSync) {
881            ALOGV("signal application thread");
882            mPrepareSync = false;
883            mPrepareStatus = NO_ERROR;
884            mSignal.signal();
885        }
886        break;
887    case MEDIA_DRM_INFO:
888        ALOGV("MediaPlayer::notify() MEDIA_DRM_INFO(%d, %d, %d, %p)", msg, ext1, ext2, obj);
889        break;
890    case MEDIA_PLAYBACK_COMPLETE:
891        ALOGV("playback complete");
892        if (mCurrentState == MEDIA_PLAYER_IDLE) {
893            ALOGE("playback complete in idle state");
894        }
895        if (!mLoop) {
896            mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
897        }
898        break;
899    case MEDIA_ERROR:
900        // Always log errors.
901        // ext1: Media framework error code.
902        // ext2: Implementation dependant error code.
903        ALOGE("error (%d, %d)", ext1, ext2);
904        mCurrentState = MEDIA_PLAYER_STATE_ERROR;
905        if (mPrepareSync)
906        {
907            ALOGV("signal application thread");
908            mPrepareSync = false;
909            mPrepareStatus = ext1;
910            mSignal.signal();
911            send = false;
912        }
913        break;
914    case MEDIA_INFO:
915        // ext1: Media framework error code.
916        // ext2: Implementation dependant error code.
917        if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
918            ALOGW("info/warning (%d, %d)", ext1, ext2);
919        }
920        break;
921    case MEDIA_SEEK_COMPLETE:
922        ALOGV("Received seek complete");
923        if (mSeekPosition != mCurrentPosition || (mSeekMode != mCurrentSeekMode)) {
924            ALOGV("Executing queued seekTo(%d, %d)", mCurrentPosition, mCurrentSeekMode);
925            mSeekPosition = -1;
926            mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
927            seekTo_l(mCurrentPosition, mCurrentSeekMode);
928        }
929        else {
930            ALOGV("All seeks complete - return to regularly scheduled program");
931            mCurrentPosition = mSeekPosition = -1;
932            mCurrentSeekMode = mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
933        }
934        break;
935    case MEDIA_BUFFERING_UPDATE:
936        ALOGV("buffering %d", ext1);
937        break;
938    case MEDIA_SET_VIDEO_SIZE:
939        ALOGV("New video size %d x %d", ext1, ext2);
940        mVideoWidth = ext1;
941        mVideoHeight = ext2;
942        break;
943    case MEDIA_NOTIFY_TIME:
944        ALOGV("Received notify time message");
945        break;
946    case MEDIA_TIMED_TEXT:
947        ALOGV("Received timed text message");
948        break;
949    case MEDIA_SUBTITLE_DATA:
950        ALOGV("Received subtitle data message");
951        break;
952    case MEDIA_META_DATA:
953        ALOGV("Received timed metadata message");
954        break;
955    default:
956        ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
957        break;
958    }
959
960    sp listener = mListener;
961    if (locked) mLock.unlock();
962
963    // this prevents re-entrant calls into client code
964    if ((listener != 0) && send) {
965        Mutex::Autolock _l(mNotifyLock);
966        ALOGV("callback application");
967        listener->notify(msg, ext1, ext2, obj);
968        ALOGV("back from callback");
969    }
970}

以onPrepared 回调为例:

877    case MEDIA_PREPARED:
878        ALOGV("MediaPlayer::notify() prepared");
879        mCurrentState = MEDIA_PLAYER_PREPARED;
880        if (mPrepareSync) {
881            ALOGV("signal application thread");
882            mPrepareSync = false;
883            mPrepareStatus = NO_ERROR;
884            mSignal.signal();
885        }
886        break;
......
......
......
960    sp listener = mListener;
961    if (locked) mLock.unlock();
962
963    // this prevents re-entrant calls into client code
964    if ((listener != 0) && send) {
965        Mutex::Autolock _l(mNotifyLock);
966        ALOGV("callback application");
967        listener->notify(msg, ext1, ext2, obj);
968        ALOGV("back from callback");
969    }

从上面分析MediaPlayer->setDataSource 和 MediaPlayer->prepareAsync 两个调用流程来看,我们简单总结一下主要调用的类;
/frameworks/base/media/java/android/media/MediaPlayer.java
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
/frameworks/av/media/libmedia/mediaplayer.cpp
/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
/frameworks/av/media/libmediaplayerservice/include/MediaPlayerInterface.h
/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp

将上面的类图再完善一下:


MediaPlayer 播放器全面剖析(一)_第6张图片
MediaPlayer 类关系

感谢关注公众号JeffMony,持续给你带来音视频方面的知识。

MediaPlayer 播放器全面剖析(一)_第7张图片

你可能感兴趣的:(MediaPlayer 播放器全面剖析(一))