Android Media Server - MediaPlayer - prepare - 02

时间:2022-10-19 19:19:39

 

 

 

 

 

1.    MediaPlayer::prepare()

………………………………………………………………………………………..

2.    AwesomePlayer::prepareAsync()

Frameworks/av/media/libstagefright/AwesomePlayer.cpp

status_tAwesomePlayer::prepareAsync() {

    ATRACE_CALL();

    Mutex::Autolock autoLock(mLock);

 

    if (mFlags & PREPARING) {

        return UNKNOWN_ERROR;  // async prepare already pending

    }

 

    mIsAsyncPrepare = true;

    return prepareAsync_l();

}

 

status_tAwesomePlayer::prepareAsync_l() {

    if (mFlags & PREPARING) {

        return UNKNOWN_ERROR;  // async prepare already pending

    }

 

    if (!mQueueStarted) {

        mQueue.start();

        mQueueStarted = true;

    }

 

    modifyFlags(PREPARING, SET);

    mAsyncPrepareEvent= new AwesomeEvent(

            this,&AwesomePlayer::onPrepareAsyncEvent);

 

    mQueue.postEvent(mAsyncPrepareEvent);

 

    return OK;

}

 

 

voidAwesomePlayer::onPrepareAsyncEvent() {

    Mutex::Autolock autoLock(mLock);

 

    if (mFlags & PREPARE_CANCELLED) {

        ALOGI("prepare was cancelledbefore doing anything");

        abortPrepare(UNKNOWN_ERROR);

        return;

    }

 

    if (mUri.size() > 0) {

        status_t err =finishSetDataSource_l();

 

        if (err != OK) {

            abortPrepare(err);

            return;

        }

    }

 

    if (mVideoTrack != NULL &&mVideoSource == NULL) {

        status_t err =initVideoDecoder();

 

        if (err != OK) {

            abortPrepare(err);

            return;

        }

    }

 

    if (mAudioTrack != NULL &&mAudioSource == NULL) {

        status_t err =initAudioDecoder();

 

        if (err != OK) {

            abortPrepare(err);

            return;

        }

    }

 

    modifyFlags(PREPARING_CONNECTED, SET);

 

    if (isStreamingHTTP()) {

       postBufferingEvent_l();

    } else {

       finishAsyncPrepare_l();

    }

}

 

 

 

 

 

 

 

3.    AwesomePlayer::finishSetDataSource_l()

Frameworks/av/media/libstagefright/AwesomePlayer.cpp

status_tAwesomePlayer::finishSetDataSource_l() {

    ATRACE_CALL();

    sp<DataSource> dataSource;

 

    bool isWidevineStreaming = false;

    if (!strncasecmp("widevine://",mUri.string(), 11)) {

        isWidevineStreaming = true;

 

        String8 newURI =String8("http://");

        newURI.append(mUri.string() + 11);

 

       mUri = newURI;

    }

 

    AStringsniffedMIME;

 

    if (!strncasecmp("http://",mUri.string(), 7)

            ||!strncasecmp("https://", mUri.string(), 8)

            || isWidevineStreaming) {

        mConnectingDataSource =HTTPBase::Create(

                (mFlags & INCOGNITO)

                    ? HTTPBase::kFlagIncognito

                    : 0);

 

        if (mUIDValid) {

           mConnectingDataSource->setUID(mUID);

        }

 

        String8 cacheConfig;

        bool disconnectAtHighwatermark;

       NuCachedSource2::RemoveCacheSpecificHeaders(

                &mUriHeaders,&cacheConfig, &disconnectAtHighwatermark);

 

        mLock.unlock();

        status_t err =mConnectingDataSource->connect(mUri, &mUriHeaders);

        mLock.lock();

 

        if (err != OK) {

            mConnectingDataSource.clear();

 

           ALOGI("mConnectingDataSource->connect() returned %d", err);

            return err;

        }

 

        if (!isWidevineStreaming) {

            // The widevine extractor does itsown caching.

 

#if 0

            mCachedSource = newNuCachedSource2(

                    new ThrottledSource(

                        mConnectingDataSource,50 * 1024 /* bytes/sec */));

#else

           mCachedSource = new NuCachedSource2(

                   mConnectingDataSource,

                   cacheConfig.isEmpty() ? NULL : cacheConfig.string(),

                   disconnectAtHighwatermark);

#endif

 

            dataSource = mCachedSource;

        } else {

            dataSource = mConnectingDataSource;

        }

 

        mConnectingDataSource.clear();

 

        String8contentType = dataSource->getMIMEType();

 

        if (strncasecmp(contentType.string(),"audio/", 6)) {

            // We're not doing this for streamsthat appear to be audio-only

            // streams to ensure that even lowbandwidth streams start

            // playing back fairly instantly.

 

            // We're going to prefill the cachebefore trying to instantiate

            // the extractor below, as thelatter is an operation that otherwise

            // could block on the datasourcefor a significant amount of time.

            // During that time we'd be unableto abort the preparation phase

            // without this prefill.

            if (mCachedSource != NULL) {

                // We're going to prefill thecache before trying to instantiate

                // the extractor below, as thelatter is an operation that otherwise

                // could block on thedatasource for a significant amount of time.

                // During that time we'd beunable to abort the preparation phase

                // without this prefill.

 

                mLock.unlock();

 

                // Initially make sure we haveat least 192 KB for the sniff

                // to complete withoutblocking.

                static const size_tkMinBytesForSniffing = 192 * 1024;

 

                off64_t metaDataSize = -1ll;

                for (;;) {

                    status_t finalStatus;

                    size_t cachedDataRemaining=

                       mCachedSource->approxDataRemaining(&finalStatus);

 

                    if (finalStatus != OK

                            || (metaDataSize>= 0

                                &&cachedDataRemaining >= metaDataSize)

                            || (mFlags &PREPARE_CANCELLED)) {

                        break;

                    }

 

                    ALOGV("now cached %dbytes of data", cachedDataRemaining);

 

                    if (metaDataSize < 0

                            &&cachedDataRemaining >= kMinBytesForSniffing) {

                        String8 tmp;

                        float confidence;

                        sp<AMessage>meta;

                       if (!dataSource->sniff(&tmp, &confidence, &meta)) {

                            mLock.lock();

                            returnUNKNOWN_ERROR;

                        }

 

                        // We successfullyidentified the file's extractor to

                        // be, remember thismime type so we don't have to

                        // sniff it again whenwe call MediaExtractor::Create()

                        // below.

                       sniffedMIME = tmp.string();

 

                        if (meta == NULL

                                ||!meta->findInt64(

                                   "meta-data-size", &metaDataSize)) {

                            metaDataSize =kHighWaterMarkBytes;

                        }

 

                        CHECK_GE(metaDataSize, 0ll);

                       ALOGV("metaDataSize = %lld bytes", metaDataSize);

                    }

 

                    usleep(200000);

                }

 

                mLock.lock();

            }

 

            if (mFlags & PREPARE_CANCELLED){

                ALOGI("Prepare cancelledwhile waiting for initial cache fill.");

                return UNKNOWN_ERROR;

            }

        }

    } else {

        dataSource =DataSource::CreateFromURI(mUri.string(), &mUriHeaders);

    }

 

    if (dataSource == NULL) {

        return UNKNOWN_ERROR;

    }

 

   sp<MediaExtractor> extractor;

 

    if (isWidevineStreaming) {

        String8 mimeType;

        float confidence;

        sp<AMessage> dummy;

        bool success;

 

        // SniffWVM is potentially blockingsince it may require network access.

        // Do not call it with mLock held.

        mLock.unlock();

        success =SniffWVM(dataSource, &mimeType, &confidence, &dummy);

        mLock.lock();

 

        if (!success

                || strcasecmp(

                    mimeType.string(),MEDIA_MIMETYPE_CONTAINER_WVM)) {

            return ERROR_UNSUPPORTED;

        }

 

        mWVMExtractor =new WVMExtractor(dataSource);

       mWVMExtractor->setAdaptiveStreamingMode(true);

 

        if (mUIDValid)

            mWVMExtractor->setUID(mUID);

        extractor = mWVMExtractor;

    } else {

        extractor =MediaExtractor::Create(

               dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());

 

        if (extractor == NULL) {

            return UNKNOWN_ERROR;

        }

    }

 

    if (extractor->getDrmFlag()) {

        checkDrmStatus(dataSource);

    }

 

    status_t err =setDataSource_l(extractor);

 

    if (err != OK) {

        mWVMExtractor.clear();

 

        return err;

    }

 

    return OK;

}

 

 

Frameworks/av/media/libstagefright/MediaExtract.cpp

// static

sp<MediaExtractor>MediaExtractor::Create(

        const sp<DataSource> &source,const char *mime) {

    sp<AMessage> meta;

 

    String8 tmp;

    if (mime == NULL) {

        float confidence;

        if(!source->sniff(&tmp, &confidence, &meta)) {

            ALOGV("FAILED to autodetectmedia content.");

 

            return NULL;

        }

 

        mime =tmp.string();

        ALOGV("Autodetected media contentas '%s' with confidence %.2f",

             mime, confidence);

    }

 

    bool isDrm = false;

    // DRM MIME type syntax is"drm+type+original" where

    // type is "es_based" or"container_based" and

    // original is the content's cleartext MIMEtype

    if (!strncmp(mime, "drm+", 4)) {

        const char *originalMime =strchr(mime+4, '+');

        if (originalMime == NULL) {

            // second + not found

            return NULL;

        }

        ++originalMime;

        if (!strncmp(mime,"drm+es_based+", 13)) {

            // DRMExtractor sets containermetadata kKeyIsDRM to 1

            return new DRMExtractor(source,originalMime);

        } else if (!strncmp(mime,"drm+container_based+", 20)) {

            mime = originalMime;

            isDrm = true;

        } else {

            return NULL;

        }

    }

 

    MediaExtractor *ret = NULL;

    if (!strcasecmp(mime,MEDIA_MIMETYPE_CONTAINER_MPEG4)

            || !strcasecmp(mime,"audio/mp4")) {

        ret = newMPEG4Extractor(source);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_MPEG)) {

        ret = new MP3Extractor(source, meta);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AMR_NB)

            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)){

        ret = new AMRExtractor(source);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_FLAC)) {

        ret = new FLACExtractor(source);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_CONTAINER_WAV)) {

        ret = new WAVExtractor(source);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_CONTAINER_OGG)) {

        ret = new OggExtractor(source);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {

        ret = new MatroskaExtractor(source);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {

        ret = new MPEG2TSExtractor(source);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_CONTAINER_WVM)) {

        // Return now.  WVExtractor should not have the DrmFlag setin the block below.

        return new WVMExtractor(source);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {

        ret = new AACExtractor(source, meta);

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {

        ret = newMPEG2PSExtractor(source);

    }

 

    if (ret != NULL) {

       if (isDrm) {

           ret->setDrmFlag(true);

       } else {

           ret->setDrmFlag(false);

       }

    }

 

    return ret;

}

 

status_tAwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {

    // Attempt to approximate overall streambitrate by summing all

    // tracks' individual bitrates, if not allof them advertise bitrate,

    // we have to fail.

 

    int64_t totalBitRate = 0;

 

    mExtractor =extractor;

    for (size_t i = 0; i <extractor->countTracks(); ++i) {

        sp<MetaData> meta =extractor->getTrackMetaData(i);

 

        int32_t bitrate;

        if (!meta->findInt32(kKeyBitRate,&bitrate)) {

            const char *mime;

            CHECK(meta->findCString(kKeyMIMEType,&mime));

            ALOGV("track of type '%s' doesnot publish bitrate", mime);

 

            totalBitRate = -1;

            break;

        }

 

        totalBitRate += bitrate;

    }

 

    mBitrate =totalBitRate;

 

    ALOGV("mBitrate = %lld bits/sec",mBitrate);

 

    {

        Mutex::Autolock autoLock(mStatsLock);

        mStats.mBitrate = mBitrate;

        mStats.mTracks.clear();

        mStats.mAudioTrackIndex = -1;

        mStats.mVideoTrackIndex = -1;

    }

 

    bool haveAudio = false;

    boolhaveVideo = false;

    for (size_t i = 0; i <extractor->countTracks(); ++i) {

       sp<MetaData> meta = extractor->getTrackMetaData(i);

 

        const char *_mime;

       CHECK(meta->findCString(kKeyMIMEType, &_mime));

 

        String8 mime = String8(_mime);

 

        if (!haveVideo &&!strncasecmp(mime.string(), "video/", 6)) {

           setVideoSource(extractor->getTrack(i));

            haveVideo = true;

 

            // Set the presentation/displaysize

            int32_t displayWidth, displayHeight;

            bool success =meta->findInt32(kKeyDisplayWidth, &displayWidth);

            if (success) {

                success =meta->findInt32(kKeyDisplayHeight, &displayHeight);

            }

            if (success) {

                mDisplayWidth = displayWidth;

                mDisplayHeight = displayHeight;

            }

 

            {

                Mutex::AutolockautoLock(mStatsLock);

                mStats.mVideoTrackIndex =mStats.mTracks.size();

                mStats.mTracks.push();

                TrackStat *stat =

                   &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);

                stat->mMIME = mime.string();

            }

        } else if (!haveAudio &&!strncasecmp(mime.string(), "audio/", 6)) {

            setAudioSource(extractor->getTrack(i));

            haveAudio = true;

            mActiveAudioTrackIndex = i;

 

            {

                Mutex::AutolockautoLock(mStatsLock);

                mStats.mAudioTrackIndex =mStats.mTracks.size();

                mStats.mTracks.push();

                TrackStat *stat =

                   &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);

                stat->mMIME = mime.string();

            }

 

            if (!strcasecmp(mime.string(),MEDIA_MIMETYPE_AUDIO_VORBIS)) {

                // Only do this for vorbisaudio, none of the other audio

                // formats even support thisringtone specific hack and

                // retrieving the metadata onsome extractors may turn out

                // to be very expensive.

                sp<MetaData> fileMeta =extractor->getMetaData();

                int32_t loop;

                if (fileMeta != NULL

                        &&fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {

                    modifyFlags(AUTO_LOOPING, SET);

                }

            }

        } else if (!strcasecmp(mime.string(),MEDIA_MIMETYPE_TEXT_3GPP)) {

            addTextSource_l(i,extractor->getTrack(i));

        }

    }

 

    if (!haveAudio && !haveVideo) {

        if (mWVMExtractor != NULL) {

            returnmWVMExtractor->getError();

        } else {

            return UNKNOWN_ERROR;

        }

    }

 

    mExtractorFlags = extractor->flags();

 

    return OK;

}

 

 

4.    AwesomePlayer::initVideoDecoder ()

Frameworks/av/media/libstagefright/AwesomePlayer.cpp

status_tAwesomePlayer::initVideoDecoder(uint32_t flags) {

    ATRACE_CALL();

 

#ifdefDEBUG_HDCP

    // For debugging, we allow a systemproperty to control the protected usage.

    // In case of uninitialized or unexpectedproperty, we default to "DRM only".

    bool setProtectionBit = false;

    char value[PROPERTY_VALUE_MAX];

    if(property_get("persist.sys.hdcp_checking", value, NULL)) {

        if (!strcmp(value, "never")){

            // nop

        } else if (!strcmp(value,"always")) {

            setProtectionBit = true;

        } else if (!strcmp(value,"drm-only")) {

            if (mDecryptHandle != NULL) {

                setProtectionBit = true;

            }

        // property value is empty, orunexpected value

        } else {

            if (mDecryptHandle != NULL) {

                setProtectionBit = true;

            }

        }

    // can' read property value

    } else {

        if (mDecryptHandle != NULL) {

            setProtectionBit = true;

        }

    }

    // note that usage bit is already cleared,so no need to clear it in the "else" case

    if (setProtectionBit) {

        flags |=OMXCodec::kEnableGrallocUsageProtected;

    }

#else

    if (mDecryptHandle != NULL) {

        flags |=OMXCodec::kEnableGrallocUsageProtected;

    }

#endif

    ALOGV("initVideoDecoderflags=0x%x", flags);

    mVideoSource =OMXCodec::Create(

           mClient.interface(), mVideoTrack->getFormat(),

            false, //createEncoder

           mVideoTrack,

            NULL,flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);

 

    if (mVideoSource != NULL) {

        int64_t durationUs;

        if(mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {

            Mutex::AutolockautoLock(mMiscStateLock);

            if (mDurationUs < 0 ||durationUs > mDurationUs) {

                mDurationUs = durationUs;

            }

        }

 

        status_t err =mVideoSource->start();

 

        if (err != OK) {

            ALOGE("failed to start videosource");

            mVideoSource.clear();

            return err;

        }

    }

 

    if (mVideoSource != NULL) {

        const char *componentName;

        CHECK(mVideoSource->getFormat()

                ->findCString(kKeyDecoderComponent,&componentName));

 

        {

            Mutex::AutolockautoLock(mStatsLock);

            TrackStat *stat =&mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);

 

            stat->mDecoderName =componentName;

        }

 

        static const char *kPrefix ="OMX.Nvidia.";

        static const char *kSuffix =".decode";

        static const size_t kSuffixLength =strlen(kSuffix);

 

        size_t componentNameLength =strlen(componentName);

 

        if (!strncmp(componentName, kPrefix, strlen(kPrefix))

                && componentNameLength>= kSuffixLength

                &&!strcmp(&componentName[

                    componentNameLength -kSuffixLength], kSuffix)) {

            modifyFlags(SLOW_DECODER_HACK,SET);

        }

    }

 

    return mVideoSource != NULL ? OK :UNKNOWN_ERROR;

}

 

 

5.    AwesomePlayer::initAudioDecoder ()

Frameworks/av/media/libstagefright/AwesomePlayer.cpp

status_tAwesomePlayer::initAudioDecoder() {

    ATRACE_CALL();

 

    sp<MetaData>meta = mAudioTrack->getFormat();

 

    const char *mime;

    CHECK(meta->findCString(kKeyMIMEType,&mime));

 

    if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_RAW)) {

        mAudioSource =mAudioTrack;

    } else {

        mAudioSource =OMXCodec::Create(

               mClient.interface(), mAudioTrack->getFormat(),

                false,// createEncoder

               mAudioTrack);

    }

 

    if (mAudioSource != NULL) {

        int64_t durationUs;

        if(mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {

            Mutex::Autolock autoLock(mMiscStateLock);

            if (mDurationUs < 0 ||durationUs > mDurationUs) {

                mDurationUs = durationUs;

            }

        }

 

        status_t err =mAudioSource->start();

 

        if (err != OK) {

            mAudioSource.clear();

            return err;

        }

    } else if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_QCELP)) {

        // For legacy reasons we're simplygoing to ignore the absence

        // of an audio decoder for QCELPinstead of aborting playback

        // altogether.

        return OK;

    }

 

    if (mAudioSource != NULL) {

        Mutex::Autolock autoLock(mStatsLock);

        TrackStat *stat =&mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);

        const char *component;

        if (!mAudioSource->getFormat()

               ->findCString(kKeyDecoderComponent, &component)) {

            component = "none";

        }

 

        stat->mDecoderName = component;

    }

 

    return mAudioSource != NULL ? OK :UNKNOWN_ERROR;

}

 

6.    AwesomePlayer::postBufferingEvent_l()

Frameworks/av/media/libstagefright/AwesomePlayer.cpp

 

7.    AwesomePlayer::finishAsyncPrepare_l ()

Frameworks/av/media/libstagefright/AwesomePlayer.cpp

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MediaPlayer::start() 作类似的调用过程

 

1.      MediaPlayerService::Client::start()

Frameworks/av/media/libmediaplayerservice/MediaPlayerService.h

Frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

 

status_tMediaPlayerService::Client::start()

{

    ALOGV("[%d] start", mConnId);

 

// p 是一个 StageFrightPlayer对象

 

    sp<MediaPlayerBase> p = getPlayer();

    if (p == 0) return UNKNOWN_ERROR;

    p->setLooping(mLoop);

 

// 调用StageFrightPlayer对象的start()

 

    returnp->start();

}

 

2.      StagefrightPlayer::start ()

Frameworks/av/media/libmediaplayerservice/StageFrightPlayer.cpp

status_tStagefrightPlayer::start() {

    ALOGV("start");

 

//  调用AwesomePlayerplay()

 

    returnmPlayer->play();

}

 

3.      AwesomePlayer::play ()

Frameworks/av/media/libstagefright/AwesomePlayer.cpp

status_tAwesomePlayer::play() {

    ATRACE_CALL();

 

    Mutex::Autolock autoLock(mLock);

 

    modifyFlags(CACHE_UNDERRUN, CLEAR);

 

    return play_l();

}

 

status_tAwesomePlayer::play_l() {

    modifyFlags(SEEK_PREVIEW, CLEAR);

 

    if (mFlags & PLAYING) {

        return OK;

    }

 

    if (!(mFlags & PREPARED)) {

        status_t err = prepare_l();

 

        if (err != OK) {

            return err;

        }

    }

 

    modifyFlags(PLAYING, SET);

    modifyFlags(FIRST_FRAME, SET);

 

    if (mDecryptHandle != NULL) {

        int64_t position;

        getPosition(&position);

       mDrmManagerClient->setPlaybackStatus(mDecryptHandle,

                Playback::START, position /1000);

    }

 

    if (mAudioSource != NULL) {

        if (mAudioPlayer == NULL) {

            if (mAudioSink != NULL) {

                bool allowDeepBuffering;

                int64_t cachedDurationUs;

                bool eos;

                if (mVideoSource == NULL

                        && (mDurationUs> AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US ||

                        (getCachedDuration_l(&cachedDurationUs,&eos) &&

                        cachedDurationUs >AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) {

                    allowDeepBuffering = true;

                } else {

                    allowDeepBuffering = false;

                }

 

               mAudioPlayer = new AudioPlayer(mAudioSink, allowDeepBuffering, this);

               mAudioPlayer->setSource(mAudioSource);

 

                mTimeSource = mAudioPlayer;

 

                // If there was a seek requestbefore we ever started,

                // honor the request now.

                // Make sure to do this beforestarting the audio player

                // to avoid a race condition.

                seekAudioIfNecessary_l();

            }

        }

 

        CHECK(!(mFlags & AUDIO_RUNNING));

 

        if (mVideoSource == NULL) {

            // We don't want to post an errornotification at this point,

            // the error returned fromMediaPlayer::start() will suffice.

 

            status_t err = startAudioPlayer_l(

                    false /*sendErrorNotification */);

 

            if (err != OK) {

                delete mAudioPlayer;

                mAudioPlayer = NULL;

 

                modifyFlags((PLAYING |FIRST_FRAME), CLEAR);

 

                if (mDecryptHandle != NULL) {

                   mDrmManagerClient->setPlaybackStatus(

                            mDecryptHandle,Playback::STOP, 0);

                }

 

                return err;

            }

        }

    }

 

    if (mTimeSource == NULL &&mAudioPlayer == NULL) {

        mTimeSource = &mSystemTimeSource;

    }

 

    if (mVideoSource != NULL) {

        // Kick off video playback

       postVideoEvent_l();

 

        if (mAudioSource != NULL &&mVideoSource != NULL) {

            postVideoLagEvent_l();

        }

    }

 

    if (mFlags & AT_EOS) {

        // Legacy behaviour, if a streamfinishes playing and then

        // is started again, we play from thestart...

        seekTo_l(0);

    }

 

    uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted

        |IMediaPlayerService::kBatteryDataTrackDecoder;

    if ((mAudioSource != NULL) &&(mAudioSource != mAudioTrack)) {

        params |=IMediaPlayerService::kBatteryDataTrackAudio;

    }

    if (mVideoSource != NULL) {

        params |=IMediaPlayerService::kBatteryDataTrackVideo;

    }

    addBatteryData(params);

 

    return OK;

}

 

4.      AwesomePlayer::postVideoEvent_l()

Frameworks/av/media/libstagefright/AwesomePlayer.cpp

voidAwesomePlayer::postVideoEvent_l(int64_t delayUs) {

    ATRACE_CALL();

 

    if (mVideoEventPending) {

        return;

    }

 

    mVideoEventPending = true;

   mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 :delayUs);

}

 

 

 

 

 

 

 

 

 

 

voidAwesomePlayer::onVideoEvent() {

    ATRACE_CALL();

    Mutex::Autolock autoLock(mLock);

    if (!mVideoEventPending) {

        // The event has been cancelled inreset_l() but had already

        // been scheduled for execution at thattime.

        return;

    }

    mVideoEventPending = false;

 

    if (mSeeking != NO_SEEK) {

        if (mVideoBuffer) {

            mVideoBuffer->release();

            mVideoBuffer = NULL;

        }

 

        if (mSeeking == SEEK &&isStreamingHTTP() && mAudioSource != NULL

                && !(mFlags &SEEK_PREVIEW)) {

            // We're going to seek the video sourcefirst, followed by

            // the audio source.

            // In order to avoid jumps in theDataSource offset caused by

            // the audio codec prefetching datafrom the old locations

            // while the video codec is alreadyreading data from the new

            // locations, we'll"pause" the audio source, causing it to

            // stop reading input data until asubsequent seek.

 

            if (mAudioPlayer != NULL &&(mFlags & AUDIO_RUNNING)) {

                mAudioPlayer->pause();

 

                modifyFlags(AUDIO_RUNNING,CLEAR);

            }

            mAudioSource->pause();

        }

    }

 

    if (!mVideoBuffer) {

        MediaSource::ReadOptions options;

        if (mSeeking != NO_SEEK) {

            ALOGV("seeking to %lld us(%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);

 

            options.setSeekTo(

                    mSeekTimeUs,

                    mSeeking == SEEK_VIDEO_ONLY

                        ? MediaSource::ReadOptions::SEEK_NEXT_SYNC

                        :MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);

        }

        for (;;) {

            status_terr = mVideoSource->read(&mVideoBuffer, &options);

            options.clearSeekTo();

 

            if (err != OK) {

                CHECK(mVideoBuffer == NULL);

 

                if (err == INFO_FORMAT_CHANGED){

                    ALOGV("VideoSourcesignalled format change.");

 

                    notifyVideoSize_l();

 

                    if (mVideoRenderer != NULL){

                        mVideoRendererIsPreview= false;

                        initRenderer_l();

                    }

                    continue;

                }

 

                // So video playback iscomplete, but we may still have

                // a seek request pending thatneeds to be applied

                // to the audio track.

                if (mSeeking != NO_SEEK) {

                    ALOGV("video streamended while seeking!");

                }

                finishSeekIfNecessary(-1);

 

                if (mAudioPlayer != NULL

                        && !(mFlags& (AUDIO_RUNNING | SEEK_PREVIEW))) {

                    startAudioPlayer_l();

                }

 

                modifyFlags(VIDEO_AT_EOS, SET);

                postStreamDoneEvent_l(err);

                return;

            }

 

            if (mVideoBuffer->range_length()== 0) {

                // Some decoders, notably thePV AVC software decoder

                // return spurious emptybuffers that we just want to ignore.

 

                mVideoBuffer->release();

                mVideoBuffer = NULL;

                continue;

            }

 

            break;

        }

 

        {

            Mutex::AutolockautoLock(mStatsLock);

            ++mStats.mNumVideoFramesDecoded;

        }

    }

 

    int64_t timeUs;

   CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime,&timeUs));

 

    mLastVideoTimeUs = timeUs;

 

    if (mSeeking == SEEK_VIDEO_ONLY) {

        if (mSeekTimeUs > timeUs) {

            ALOGI("XXX mSeekTimeUs = %lldus, timeUs = %lld us",

                 mSeekTimeUs, timeUs);

        }

    }

 

    {

        Mutex::AutolockautoLock(mMiscStateLock);

        mVideoTimeUs = timeUs;

    }

 

    SeekType wasSeeking = mSeeking;

    finishSeekIfNecessary(timeUs);

 

    if (mAudioPlayer != NULL &&!(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {

        status_t err = startAudioPlayer_l();

        if (err != OK) {

            ALOGE("Starting the audio playerfailed w/ err %d", err);

            return;

        }

    }

 

    if ((mFlags & TEXTPLAYER_INITIALIZED)

            && !(mFlags &(TEXT_RUNNING | SEEK_PREVIEW))) {

        mTextDriver->start();

        modifyFlags(TEXT_RUNNING, SET);

    }

 

    TimeSource *ts =

        ((mFlags & AUDIO_AT_EOS) ||!(mFlags & AUDIOPLAYER_STARTED))

            ? &mSystemTimeSource :mTimeSource;

 

    if (mFlags & FIRST_FRAME) {

        modifyFlags(FIRST_FRAME, CLEAR);

        mSinceLastDropped = 0;

        mTimeSourceDeltaUs =ts->getRealTimeUs() - timeUs;

    }

 

    int64_t realTimeUs, mediaTimeUs;

    if (!(mFlags & AUDIO_AT_EOS) &&mAudioPlayer != NULL

        &&mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {

        mTimeSourceDeltaUs = realTimeUs -mediaTimeUs;

    }

 

    if (wasSeeking == SEEK_VIDEO_ONLY) {

        int64_t nowUs = ts->getRealTimeUs()- mTimeSourceDeltaUs;

 

        int64_t latenessUs = nowUs - timeUs;

 

        ATRACE_INT("Video Lateness(ms)", latenessUs / 1E3);

 

        if (latenessUs > 0) {

            ALOGI("after SEEK_VIDEO_ONLYwe're late by %.2f secs", latenessUs / 1E6);

        }

    }

 

    if (wasSeeking == NO_SEEK) {

        // Let's display the first frame afterseeking right away.

 

        int64_t nowUs = ts->getRealTimeUs()- mTimeSourceDeltaUs;

 

        int64_t latenessUs = nowUs - timeUs;

 

        ATRACE_INT("Video Lateness(ms)", latenessUs / 1E3);

 

        if (latenessUs > 500000ll

                && mAudioPlayer != NULL

                && mAudioPlayer->getMediaTimeMapping(

                    &realTimeUs,&mediaTimeUs)) {

            if (mWVMExtractor == NULL) {

                ALOGI("we're much too late(%.2f secs), video skipping ahead",

                     latenessUs / 1E6);

 

                mVideoBuffer->release();

                mVideoBuffer = NULL;

 

                mSeeking = SEEK_VIDEO_ONLY;

                mSeekTimeUs = mediaTimeUs;

 

                postVideoEvent_l();

                return;

            } else {

                // The widevine extractordoesn't deal well with seeking

                // audio and videoindependently. We'll just have to wait

                // until the decoder catchesup, which won't be long at all.

                ALOGI("we're very late(%.2f secs)", latenessUs / 1E6);

            }

        }

 

        if (latenessUs > 40000) {

            // We're more than 40ms late.

            ALOGV("we're late by %lld us(%.2f secs)",

                 latenessUs, latenessUs / 1E6);

 

            if (!(mFlags & SLOW_DECODER_HACK)

                    || mSinceLastDropped >FRAME_DROP_FREQ)

            {

                ALOGV("we're late by %lldus (%.2f secs) dropping "

                     "one after %dframes",

                     latenessUs, latenessUs /1E6, mSinceLastDropped);

 

                mSinceLastDropped = 0;

                mVideoBuffer->release();

                mVideoBuffer = NULL;

 

                {

                    Mutex::AutolockautoLock(mStatsLock);

                   ++mStats.mNumVideoFramesDropped;

                }

 

               postVideoEvent_l();

                return;

            }

        }

 

        if (latenessUs < -10000) {

            // We're more than 10ms early.

            postVideoEvent_l(10000);

            return;

        }

    }

 

    if ((mNativeWindow != NULL)

            && (mVideoRendererIsPreview|| mVideoRenderer == NULL)) {

        mVideoRendererIsPreview = false;

 

       initRenderer_l();

    }

 

    if (mVideoRenderer != NULL) {

        mSinceLastDropped++;

        mVideoRenderer->render(mVideoBuffer);

        if (!mVideoRenderingStarted) {

            mVideoRenderingStarted = true;

            notifyListener_l(MEDIA_INFO,MEDIA_INFO_RENDERING_START);

        }

 

    }

 

    mVideoBuffer->release();

    mVideoBuffer = NULL;

 

    if (wasSeeking != NO_SEEK &&(mFlags & SEEK_PREVIEW)) {

        modifyFlags(SEEK_PREVIEW, CLEAR);

        return;

    }

 

    postVideoEvent_l();

}