Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d354d8d1 authored by Chong Zhang's avatar Chong Zhang
Browse files

move cache prefill to GenericSource's message handler

This allows prepareAsync to be terminated by reset promptly.

It also makes it easier to do buffer update as GenericSource
can access the cache status now.

Bug: 16892748
Bug: 17182378

Change-Id: Ia55c04a810fd805041cb2025f6739afa5120b5ed
parent 111333ea
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ public:
            const sp<IMediaHTTPService> &httpService,
            const char *uri,
            const KeyedVector<String8, String8> *headers = NULL,
            AString *sniffedMIME = NULL);
            String8 *contentType = NULL);

    DataSource() {}

@@ -102,10 +102,6 @@ protected:
    virtual ~DataSource() {}

private:
    enum {
        kDefaultMetaSize = 200000,
    };

    static Mutex gSnifferMutex;
    static List<SnifferFunc> gSniffers;
    static bool gSniffersRegistered;
+123 −24
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include "../../libstagefright/include/NuCachedSource2.h"
#include "../../libstagefright/include/WVMExtractor.h"

namespace android {
@@ -47,7 +48,8 @@ NuPlayer::GenericSource::GenericSource(
      mAudioIsVorbis(false),
      mIsWidevine(false),
      mUIDValid(uidValid),
      mUID(uid) {
      mUID(uid),
      mMetaDataSize(-1ll) {
    resetDataSource();
    DataSource::RegisterDefaultSniffers();
}
@@ -92,18 +94,18 @@ status_t NuPlayer::GenericSource::setDataSource(
    return OK;
}

status_t NuPlayer::GenericSource::initFromDataSource(
        const sp<DataSource> &dataSource,
        const char* mime) {
status_t NuPlayer::GenericSource::initFromDataSource() {
    sp<MediaExtractor> extractor;

    CHECK(mDataSource != NULL);

    if (mIsWidevine) {
        String8 mimeType;
        float confidence;
        sp<AMessage> dummy;
        bool success;

        success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
        success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
        if (!success
                || strcasecmp(
                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
@@ -111,14 +113,15 @@ status_t NuPlayer::GenericSource::initFromDataSource(
            return UNKNOWN_ERROR;
        }

        sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource);
        sp<WVMExtractor> wvmExtractor = new WVMExtractor(mDataSource);
        wvmExtractor->setAdaptiveStreamingMode(true);
        if (mUIDValid) {
            wvmExtractor->setUID(mUID);
        }
        extractor = wvmExtractor;
    } else {
        extractor = MediaExtractor::Create(dataSource, mime);
        extractor = MediaExtractor::Create(mDataSource,
                mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
    }

    if (extractor == NULL) {
@@ -213,34 +216,49 @@ void NuPlayer::GenericSource::prepareAsync() {

void NuPlayer::GenericSource::onPrepareAsync() {
    // delayed data source creation
    AString sniffedMIME;
    sp<DataSource> dataSource;

    if (mDataSource == NULL) {
        if (!mUri.empty()) {
            mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);

        dataSource = DataSource::CreateFromURI(
               mHTTPService, mUri.c_str(), &mUriHeaders, &sniffedMIME);
            mDataSource = DataSource::CreateFromURI(
                   mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType);
        } else {
            // set to false first, if the extractor
            // comes back as secure, set it to true then.
            mIsWidevine = false;

        dataSource = new FileSource(mFd, mOffset, mLength);
            mDataSource = new FileSource(mFd, mOffset, mLength);
        }

    if (dataSource == NULL) {
        if (mDataSource == NULL) {
            ALOGE("Failed to create data source!");
        notifyPrepared(UNKNOWN_ERROR);
            notifyPreparedAndCleanup(UNKNOWN_ERROR);
            return;
        }

        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
            mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
        }
    }

    // check initial caching status
    status_t err = prefillCacheIfNecessary();
    if (err != OK) {
        if (err == -EAGAIN) {
            (new AMessage(kWhatPrepareAsync, id()))->post(200000);
        } else {
            ALOGE("Failed to prefill data cache!");
            notifyPreparedAndCleanup(UNKNOWN_ERROR);
        }
        return;
    }

    status_t err = initFromDataSource(
            dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
    // init extrator from data source
    err = initFromDataSource();

    if (err != OK) {
        ALOGE("Failed to init from data source!");
        notifyPrepared(err);
        notifyPreparedAndCleanup(err);
        return;
    }

@@ -258,6 +276,87 @@ void NuPlayer::GenericSource::onPrepareAsync() {
    notifyPrepared();
}

void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
    if (err != OK) {
        mMetaDataSize = -1ll;
        mContentType = "";
        mSniffedMIME = "";
        mDataSource.clear();
        mCachedSource.clear();
    }
    notifyPrepared(err);
}

status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
    CHECK(mDataSource != NULL);

    if (mCachedSource == NULL) {
        // no prefill if the data source is not cached
        return OK;
    }

    // We're not doing this for streams that appear to be audio-only
    // streams to ensure that even low bandwidth streams start
    // playing back fairly instantly.
    if (!strncasecmp(mContentType.string(), "audio/", 6)) {
        return OK;
    }

    // We're going to prefill the cache before trying to instantiate
    // the extractor below, as the latter is an operation that otherwise
    // could block on the datasource for a significant amount of time.
    // During that time we'd be unable to abort the preparation phase
    // without this prefill.

    // Initially make sure we have at least 192 KB for the sniff
    // to complete without blocking.
    static const size_t kMinBytesForSniffing = 192 * 1024;
    static const size_t kDefaultMetaSize = 200000;

    status_t finalStatus;

    size_t cachedDataRemaining =
            mCachedSource->approxDataRemaining(&finalStatus);

    if (finalStatus != OK || (mMetaDataSize >= 0
            && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
        ALOGV("stop caching, status %d, "
                "metaDataSize %lld, cachedDataRemaining %zu",
                finalStatus, mMetaDataSize, cachedDataRemaining);
        return OK;
    }

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

    if (mMetaDataSize < 0
            && cachedDataRemaining >= kMinBytesForSniffing) {
        String8 tmp;
        float confidence;
        sp<AMessage> meta;
        if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
            return UNKNOWN_ERROR;
        }

        // We successfully identified the file's extractor to
        // be, remember this mime type so we don't have to
        // sniff it again when we call MediaExtractor::Create()
        mSniffedMIME = tmp.string();

        if (meta == NULL
                || !meta->findInt64("meta-data-size",
                        reinterpret_cast<int64_t*>(&mMetaDataSize))) {
            mMetaDataSize = kDefaultMetaSize;
        }

        if (mMetaDataSize < 0ll) {
            ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
            return UNKNOWN_ERROR;
        }
    }

    return -EAGAIN;
}

void NuPlayer::GenericSource::start() {
    ALOGI("start");

+12 −4
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ struct DataSource;
struct IMediaHTTPService;
struct MediaSource;
class MediaBuffer;
struct NuCachedSource2;

struct NuPlayer::GenericSource : public NuPlayer::Source {
    GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid);
@@ -105,14 +106,21 @@ private:
    int64_t mOffset;
    int64_t mLength;

    sp<ALooper> mLooper;
    sp<DataSource> mDataSource;
    sp<NuCachedSource2> mCachedSource;
    String8 mContentType;
    AString mSniffedMIME;
    off64_t mMetaDataSize;

    sp<ALooper> mLooper;

    void resetDataSource();

    status_t initFromDataSource(
            const sp<DataSource> &dataSource,
            const char *mime);
    status_t initFromDataSource();

    status_t prefillCacheIfNecessary();

    void notifyPreparedAndCleanup(status_t err);

    void onPrepareAsync();

+7 −70
Original line number Diff line number Diff line
@@ -186,9 +186,9 @@ sp<DataSource> DataSource::CreateFromURI(
        const sp<IMediaHTTPService> &httpService,
        const char *uri,
        const KeyedVector<String8, String8> *headers,
        AString *sniffedMIME) {
    if (sniffedMIME != NULL) {
        *sniffedMIME = "";
        String8 *contentType) {
    if (contentType != NULL) {
        *contentType = "";
    }

    bool isWidevine = !strncasecmp("widevine://", uri, 11);
@@ -226,77 +226,14 @@ sp<DataSource> DataSource::CreateFromURI(
        }

        if (!isWidevine) {
            String8 contentType = httpSource->getMIMEType();
            if (contentType != NULL) {
                *contentType = httpSource->getMIMEType();
            }

            sp<NuCachedSource2> cachedSource = new NuCachedSource2(
            source = new NuCachedSource2(
                    httpSource,
                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
                    disconnectAtHighwatermark);

            if (strncasecmp(contentType.string(), "audio/", 6)) {
                // We're not doing this for streams that appear to be audio-only
                // streams to ensure that even low bandwidth streams start
                // playing back fairly instantly.

                // We're going to prefill the cache before trying to instantiate
                // the extractor below, as the latter is an operation that otherwise
                // could block on the datasource for a significant amount of time.
                // During that time we'd be unable to abort the preparation phase
                // without this prefill.

                // Initially make sure we have at least 192 KB for the sniff
                // to complete without blocking.
                static const size_t kMinBytesForSniffing = 192 * 1024;

                off64_t metaDataSize = -1ll;
                for (;;) {
                    status_t finalStatus;
                    size_t cachedDataRemaining =
                            cachedSource->approxDataRemaining(&finalStatus);

                    if (finalStatus != OK || (metaDataSize >= 0
                            && (off64_t)cachedDataRemaining >= metaDataSize)) {
                        ALOGV("stop caching, status %d, "
                                "metaDataSize %lld, cachedDataRemaining %zu",
                                finalStatus, metaDataSize, cachedDataRemaining);
                        break;
                    }

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

                    if (metaDataSize < 0
                            && cachedDataRemaining >= kMinBytesForSniffing) {
                        String8 tmp;
                        float confidence;
                        sp<AMessage> meta;
                        if (!cachedSource->sniff(&tmp, &confidence, &meta)) {
                            return NULL;
                        }

                        // We successfully identified the file's extractor to
                        // be, remember this mime type so we don't have to
                        // sniff it again when we call MediaExtractor::Create()
                        if (sniffedMIME != NULL) {
                            *sniffedMIME = tmp.string();
                        }

                        if (meta == NULL
                                || !meta->findInt64("meta-data-size",
                                     reinterpret_cast<int64_t*>(&metaDataSize))) {
                            metaDataSize = kDefaultMetaSize;
                        }

                        if (metaDataSize < 0ll) {
                            ALOGE("invalid metaDataSize = %lld bytes", metaDataSize);
                            return NULL;
                        }
                    }

                    usleep(200000);
                }
            }

            source = cachedSource;
        } else {
            // We do not want that prefetching, caching, datasource wrapper
            // in the widevine:// case.