diff options
Diffstat (limited to 'media/libstagefright')
-rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 139 | ||||
-rw-r--r-- | media/libstagefright/WVMExtractor.cpp | 19 | ||||
-rw-r--r-- | media/libstagefright/include/AwesomePlayer.h | 6 | ||||
-rw-r--r-- | media/libstagefright/include/WVMExtractor.h | 20 |
4 files changed, 155 insertions, 29 deletions
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 027a1ce..3694329 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -24,10 +24,12 @@ #include "include/ARTSPController.h" #include "include/AwesomePlayer.h" +#include "include/DRMExtractor.h" #include "include/SoftwareRenderer.h" #include "include/NuCachedSource2.h" #include "include/ThrottledSource.h" #include "include/MPEG2TSExtractor.h" +#include "include/WVMExtractor.h" #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> @@ -447,6 +449,7 @@ void AwesomePlayer::reset_l() { cancelPlayerEvents(); + mWVMExtractor.clear(); mCachedSource.clear(); mAudioTrack.clear(); mVideoTrack.clear(); @@ -554,6 +557,11 @@ bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) { *durationUs = cachedDataRemaining * 8000000ll / bitrate; *eos = (finalStatus != OK); return true; + } else if (mWVMExtractor != NULL) { + status_t finalStatus; + *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus); + *eos = (finalStatus != OK); + return true; } return false; @@ -646,6 +654,30 @@ void AwesomePlayer::onBufferingUpdate() { } } } + } else if (mWVMExtractor != NULL) { + status_t finalStatus; + + int64_t cachedDurationUs + = mWVMExtractor->getCachedDurationUs(&finalStatus); + + bool eos = (finalStatus != OK); + + if (eos) { + if (finalStatus == ERROR_END_OF_STREAM) { + notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); + } + if (mFlags & PREPARING) { + LOGV("cache has reached EOS, prepare is done."); + finishAsyncPrepare_l(); + } + } else { + int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; + if (percentage > 100) { + percentage = 100; + } + + notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); + } } int64_t cachedDurationUs; @@ -1320,7 +1352,7 @@ void AwesomePlayer::onVideoEvent() { mVideoBuffer = NULL; } - if (mSeeking == SEEK && mCachedSource != NULL && mAudioSource != NULL + if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL && !(mFlags & SEEK_PREVIEW)) { // We're going to seek the video source first, followed by // the audio source. @@ -1654,8 +1686,19 @@ status_t AwesomePlayer::prepareAsync_l() { status_t AwesomePlayer::finishSetDataSource_l() { 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; + } + if (!strncasecmp("http://", mUri.string(), 7) - || !strncasecmp("https://", mUri.string(), 8)) { + || !strncasecmp("https://", mUri.string(), 8) + || isWidevineStreaming) { mConnectingDataSource = new NuHTTPDataSource( (mFlags & INCOGNITO) ? NuHTTPDataSource::kFlagIncognito : 0); @@ -1670,40 +1713,49 @@ status_t AwesomePlayer::finishSetDataSource_l() { return err; } + if (!isWidevineStreaming) { + // The widevine extractor does its own caching. + #if 0 - mCachedSource = new NuCachedSource2( - new ThrottledSource( - mConnectingDataSource, 50 * 1024 /* bytes/sec */)); + mCachedSource = new NuCachedSource2( + new ThrottledSource( + mConnectingDataSource, 50 * 1024 /* bytes/sec */)); #else - mCachedSource = new NuCachedSource2(mConnectingDataSource); + mCachedSource = new NuCachedSource2(mConnectingDataSource); #endif + + dataSource = mCachedSource; + } else { + dataSource = mConnectingDataSource; + } + mConnectingDataSource.clear(); - dataSource = mCachedSource; + if (mCachedSource != NULL) { + // 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. - // 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. + mLock.unlock(); - mLock.unlock(); + for (;;) { + status_t finalStatus; + size_t cachedDataRemaining = + mCachedSource->approxDataRemaining(&finalStatus); - for (;;) { - status_t finalStatus; - size_t cachedDataRemaining = - mCachedSource->approxDataRemaining(&finalStatus); + if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes + || (mFlags & PREPARE_CANCELLED)) { + break; + } - if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes - || (mFlags & PREPARE_CANCELLED)) { - break; + usleep(200000); } - usleep(200000); + mLock.lock(); } - mLock.lock(); - if (mFlags & PREPARE_CANCELLED) { LOGI("Prepare cancelled while waiting for initial cache fill."); return UNKNOWN_ERROR; @@ -1740,10 +1792,29 @@ status_t AwesomePlayer::finishSetDataSource_l() { return UNKNOWN_ERROR; } - sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); + sp<MediaExtractor> extractor; - if (extractor == NULL) { - return UNKNOWN_ERROR; + if (isWidevineStreaming) { + String8 mimeType; + float confidence; + sp<AMessage> dummy; + bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy); + + if (!success + || strcasecmp( + mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { + return ERROR_UNSUPPORTED; + } + + mWVMExtractor = new WVMExtractor(dataSource); + mWVMExtractor->setAdaptiveStreamingMode(true); + extractor = mWVMExtractor; + } else { + extractor = MediaExtractor::Create(dataSource); + + if (extractor == NULL) { + return UNKNOWN_ERROR; + } } dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient); @@ -1754,7 +1825,15 @@ status_t AwesomePlayer::finishSetDataSource_l() { } } - return setDataSource_l(extractor); + status_t err = setDataSource_l(extractor); + + if (err != OK) { + mWVMExtractor.clear(); + + return err; + } + + return OK; } void AwesomePlayer::abortPrepare(status_t err) { @@ -1815,7 +1894,7 @@ void AwesomePlayer::onPrepareAsyncEvent() { mFlags |= PREPARING_CONNECTED; - if (mCachedSource != NULL || mRTSPController != NULL) { + if (isStreamingHTTP() || mRTSPController != NULL) { postBufferingEvent_l(); } else { finishAsyncPrepare_l(); @@ -1852,4 +1931,8 @@ void AwesomePlayer::postAudioSeekComplete() { postCheckAudioStatusEvent_l(); } +bool AwesomePlayer::isStreamingHTTP() const { + return mCachedSource != NULL || mWVMExtractor != NULL; +} + } // namespace android diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp index 7c72852..83a1eaa 100644 --- a/media/libstagefright/WVMExtractor.cpp +++ b/media/libstagefright/WVMExtractor.cpp @@ -45,7 +45,8 @@ namespace android { static Mutex gWVMutex; WVMExtractor::WVMExtractor(const sp<DataSource> &source) - : mDataSource(source) { + : mDataSource(source), + mUseAdaptiveStreaming(false) { { Mutex::Autolock autoLock(gWVMutex); if (gVendorLibHandle == NULL) { @@ -100,5 +101,21 @@ sp<MetaData> WVMExtractor::getMetaData() { return mImpl->getMetaData(); } +int64_t WVMExtractor::getCachedDurationUs(status_t *finalStatus) { + // TODO: Fill this with life. + + *finalStatus = OK; + + return 0; +} + +void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) { + mUseAdaptiveStreaming = adaptive; +} + +bool WVMExtractor::getAdaptiveStreamingMode() const { + return mUseAdaptiveStreaming; +} + } //namespace android diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 4e6f75c..3a21f25 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -44,6 +44,8 @@ struct ARTSPController; class DrmManagerClinet; class DecryptHandle; +struct WVMExtractor; + struct AwesomeRenderer : public RefBase { AwesomeRenderer() {} @@ -219,6 +221,8 @@ private: DrmManagerClient *mDrmManagerClient; DecryptHandle *mDecryptHandle; + sp<WVMExtractor> mWVMExtractor; + status_t setDataSource_l( const char *uri, const KeyedVector<String8, String8> *headers = NULL); @@ -268,6 +272,8 @@ private: status_t startAudioPlayer_l(); + bool isStreamingHTTP() const; + AwesomePlayer(const AwesomePlayer &); AwesomePlayer &operator=(const AwesomePlayer &); }; diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h index 0da45a8..62e5aa5 100644 --- a/media/libstagefright/include/WVMExtractor.h +++ b/media/libstagefright/include/WVMExtractor.h @@ -19,6 +19,7 @@ #define WVM_EXTRACTOR_H_ #include <media/stagefright/MediaExtractor.h> +#include <utils/Errors.h> namespace android { @@ -33,12 +34,31 @@ public: virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags); virtual sp<MetaData> getMetaData(); + // Return the amount of data cached from the current + // playback positiion (in us). + // While more data is still being fetched *finalStatus == OK, + // Once fetching is completed (no more data available), *finalStatus != OK + // If fetching completed normally (i.e. reached EOS instead of IO error) + // *finalStatus == ERROR_END_OF_STREAM + int64_t getCachedDurationUs(status_t *finalStatus); + + // Set to use adaptive streaming mode by the WV component. + // If adaptive == true, adaptive streaming mode will be used. + // Default mode is non-adaptive streaming mode. + // Should set to use adaptive streaming mode only if widevine:// protocol + // is used. + void setAdaptiveStreamingMode(bool adaptive); + + // Retrieve the adaptive streaming mode used by the WV component. + bool getAdaptiveStreamingMode() const; + protected: virtual ~WVMExtractor(); private: sp<DataSource> mDataSource; sp<MediaExtractor> mImpl; + bool mUseAdaptiveStreaming; WVMExtractor(const WVMExtractor &); WVMExtractor &operator=(const WVMExtractor &); |