diff options
Diffstat (limited to 'media/libstagefright')
18 files changed, 420 insertions, 66 deletions
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index b45e5d3..fb7a871 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -24,11 +24,13 @@ #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/TimedTextPlayer.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(); @@ -545,6 +548,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; @@ -637,6 +645,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; @@ -1425,7 +1457,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. @@ -1760,8 +1792,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 = HTTPBase::Create( (mFlags & INCOGNITO) ? HTTPBase::kFlagIncognito @@ -1778,16 +1821,24 @@ 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; String8 contentType = dataSource->getMIMEType(); @@ -1801,28 +1852,35 @@ status_t AwesomePlayer::finishSetDataSource_l() { // 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. + 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. + + mLock.unlock(); + + for (;;) { + status_t finalStatus; + size_t cachedDataRemaining = + mCachedSource->approxDataRemaining(&finalStatus); + + if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes + || (mFlags & PREPARE_CANCELLED)) { + break; + } - mLock.unlock(); - - for (;;) { - status_t finalStatus; - size_t cachedDataRemaining = - mCachedSource->approxDataRemaining(&finalStatus); - - 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; + if (mFlags & PREPARE_CANCELLED) { + LOGI("Prepare cancelled while waiting for initial cache fill."); + return UNKNOWN_ERROR; + } } } else if (!strncasecmp("rtsp://", mUri.string(), 7)) { if (mLooper == NULL) { @@ -1856,10 +1914,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); @@ -1871,7 +1948,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) { @@ -1932,7 +2017,7 @@ void AwesomePlayer::onPrepareAsyncEvent() { mFlags |= PREPARING_CONNECTED; - if (mCachedSource != NULL || mRTSPController != NULL) { + if (isStreamingHTTP() || mRTSPController != NULL) { postBufferingEvent_l(); } else { finishAsyncPrepare_l(); @@ -1985,4 +2070,9 @@ status_t AwesomePlayer::setParameter(int key, const Parcel &request) { status_t AwesomePlayer::getParameter(int key, Parcel *reply) { return OK; } + +bool AwesomePlayer::isStreamingHTTP() const { + return mCachedSource != NULL || mWVMExtractor != NULL; +} + } // namespace android diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index c79d02e..6692809 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -2171,6 +2171,9 @@ static bool isCompatibleBrand(uint32_t fourcc) { // Just give these file types a chance. FOURCC('q', 't', ' ', ' '), // Apple's QuickTime FOURCC('M', 'S', 'N', 'V'), // Sony's PSP + + FOURCC('3', 'g', '2', 'a'), // 3GPP2 + FOURCC('3', 'g', '2', 'b'), }; for (size_t i = 0; diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index fd60f06..f6a8b17 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -33,6 +33,7 @@ #include <media/stagefright/MediaSource.h> #include <media/stagefright/Utils.h> #include <media/mediarecorder.h> +#include <cutils/properties.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -257,7 +258,11 @@ MPEG4Writer::MPEG4Writer(const char *filename) mOffset(0), mMdatOffset(0), mEstimatedMoovBoxSize(0), - mInterleaveDurationUs(1000000) { + mInterleaveDurationUs(1000000), + mLatitudex10000(0), + mLongitudex10000(0), + mAreGeoTagsAvailable(false), + mStartTimeOffsetMs(-1) { mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR); if (mFd >= 0) { @@ -276,7 +281,11 @@ MPEG4Writer::MPEG4Writer(int fd) mOffset(0), mMdatOffset(0), mEstimatedMoovBoxSize(0), - mInterleaveDurationUs(1000000) { + mInterleaveDurationUs(1000000), + mLatitudex10000(0), + mLongitudex10000(0), + mAreGeoTagsAvailable(false), + mStartTimeOffsetMs(-1) { } MPEG4Writer::~MPEG4Writer() { @@ -724,6 +733,9 @@ void MPEG4Writer::writeMvhdBox(int64_t durationUs) { void MPEG4Writer::writeMoovBox(int64_t durationUs) { beginBox("moov"); writeMvhdBox(durationUs); + if (mAreGeoTagsAvailable) { + writeUdtaBox(); + } int32_t id = 1; for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it, ++id) { @@ -732,7 +744,7 @@ void MPEG4Writer::writeMoovBox(int64_t durationUs) { endBox(); // moov } -void MPEG4Writer::writeFtypBox(const MetaData *param) { +void MPEG4Writer::writeFtypBox(MetaData *param) { beginBox("ftyp"); int32_t fileType; @@ -749,7 +761,27 @@ void MPEG4Writer::writeFtypBox(const MetaData *param) { endBox(); } +static bool isTestModeEnabled() { +#if (PROPERTY_VALUE_MAX < 5) +#error "PROPERTY_VALUE_MAX must be at least 5" +#endif + + // Test mode is enabled only if rw.media.record.test system + // property is enabled. + char value[PROPERTY_VALUE_MAX]; + if (property_get("rw.media.record.test", value, NULL) && + (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) { + return true; + } + return false; +} + void MPEG4Writer::sendSessionSummary() { + // Send session summary only if test mode is enabled + if (!isTestModeEnabled()) { + return; + } + for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); it != mChunkInfos.end(); ++it) { int trackNum = it->mTrack->getTrackId() << 28; @@ -921,6 +953,77 @@ void MPEG4Writer::writeFourcc(const char *s) { write(s, 1, 4); } + +// Written in +/-DD.DDDD format +void MPEG4Writer::writeLatitude(int degreex10000) { + bool isNegative = (degreex10000 < 0); + char sign = isNegative? '-': '+'; + + // Handle the whole part + char str[9]; + int wholePart = degreex10000 / 10000; + if (wholePart == 0) { + snprintf(str, 5, "%c%.2d.", sign, wholePart); + } else { + snprintf(str, 5, "%+.2d.", wholePart); + } + + // Handle the fractional part + int fractionalPart = degreex10000 - (wholePart * 10000); + if (fractionalPart < 0) { + fractionalPart = -fractionalPart; + } + snprintf(&str[4], 5, "%.4d", fractionalPart); + + // Do not write the null terminator + write(str, 1, 8); +} + +// Written in +/- DDD.DDDD format +void MPEG4Writer::writeLongitude(int degreex10000) { + bool isNegative = (degreex10000 < 0); + char sign = isNegative? '-': '+'; + + // Handle the whole part + char str[10]; + int wholePart = degreex10000 / 10000; + if (wholePart == 0) { + snprintf(str, 6, "%c%.3d.", sign, wholePart); + } else { + snprintf(str, 6, "%+.3d.", wholePart); + } + + // Handle the fractional part + int fractionalPart = degreex10000 - (wholePart * 10000); + if (fractionalPart < 0) { + fractionalPart = -fractionalPart; + } + snprintf(&str[5], 5, "%.4d", fractionalPart); + + // Do not write the null terminator + write(str, 1, 9); +} + +/* + * Geodata is stored according to ISO-6709 standard. + * latitudex10000 is latitude in degrees times 10000, and + * longitudex10000 is longitude in degrees times 10000. + * The range for the latitude is in [-90, +90], and + * The range for the longitude is in [-180, +180] + */ +status_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) { + // Is latitude or longitude out of range? + if (latitudex10000 < -900000 || latitudex10000 > 900000 || + longitudex10000 < -1800000 || longitudex10000 > 1800000) { + return BAD_VALUE; + } + + mLatitudex10000 = latitudex10000; + mLongitudex10000 = longitudex10000; + mAreGeoTagsAvailable = true; + return OK; +} + void MPEG4Writer::write(const void *data, size_t size) { write(data, 1, size); } @@ -1345,10 +1448,15 @@ status_t MPEG4Writer::Track::start(MetaData *params) { * session, and it also helps eliminate the "recording" sound for * camcorder applications. * - * Ideally, this platform-specific value should be defined - * in media_profiles.xml file + * If client does not set the start time offset, we fall back to + * use the default initial delay value. */ - startTimeUs += kInitialDelayTimeUs; + int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; + if (startTimeOffsetUs < 0) { // Start time offset was not set + startTimeOffsetUs = kInitialDelayTimeUs; + } + startTimeUs += startTimeOffsetUs; + LOGI("Start time offset: %lld us", startTimeOffsetUs); } meta->setInt64(kKeyTime, startTimeUs); @@ -2140,6 +2248,12 @@ status_t MPEG4Writer::Track::threadEntry() { } void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { + + // Send track summary only if test mode is enabled. + if (!isTestModeEnabled()) { + return; + } + int trackNum = (mTrackId << 28); mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, @@ -2154,13 +2268,24 @@ void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES, mNumSamples); - // The system delay time excluding the requested initial delay that - // is used to eliminate the recording sound. - int64_t initialDelayUs = - mFirstSampleTimeRealUs - mStartTimeRealUs - kInitialDelayTimeUs; - mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, + { + // The system delay time excluding the requested initial delay that + // is used to eliminate the recording sound. + int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; + if (startTimeOffsetUs < 0) { // Start time offset was not set + startTimeOffsetUs = kInitialDelayTimeUs; + } + int64_t initialDelayUs = + mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs; + + mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS, (initialDelayUs) / 1000); + } + + mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, + trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES, + mMdatSizeBytes / 1024); if (hasMultipleTracks) { mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, @@ -2491,7 +2616,7 @@ void MPEG4Writer::Track::writeTkhdBox(time_t now) { mOwner->writeInt32(0x07); // version=0, flags=7 mOwner->writeInt32(now); // creation time mOwner->writeInt32(now); // modification time - mOwner->writeInt32(mTrackId); + mOwner->writeInt32(mTrackId + 1); // track id starts with 1 mOwner->writeInt32(0); // reserved int64_t trakDurationUs = getDurationUs(); int32_t mvhdTimeScale = mOwner->getTimeScale(); @@ -2722,4 +2847,29 @@ void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) { mOwner->endBox(); // stco or co64 } +void MPEG4Writer::writeUdtaBox() { + beginBox("udta"); + writeGeoDataBox(); + endBox(); +} + +/* + * Geodata is stored according to ISO-6709 standard. + */ +void MPEG4Writer::writeGeoDataBox() { + beginBox("\xA9xyz"); + /* + * For historical reasons, any user data start + * with "\0xA9", must be followed by its assoicated + * language code. + * 0x0012: locale en + * 0x15c7: language 5575 + */ + writeInt32(0x001215c7); + writeLatitude(mLatitudex10000); + writeLongitude(mLongitudex10000); + writeInt8(0x2F); + endBox(); +} + } // namespace android diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp index aac94a6..884f3b4 100644 --- a/media/libstagefright/MetaData.cpp +++ b/media/libstagefright/MetaData.cpp @@ -83,7 +83,7 @@ bool MetaData::setRect( return setData(key, TYPE_RECT, &r, sizeof(r)); } -bool MetaData::findCString(uint32_t key, const char **value) const { +bool MetaData::findCString(uint32_t key, const char **value) { uint32_t type; const void *data; size_t size; @@ -96,7 +96,7 @@ bool MetaData::findCString(uint32_t key, const char **value) const { return true; } -bool MetaData::findInt32(uint32_t key, int32_t *value) const { +bool MetaData::findInt32(uint32_t key, int32_t *value) { uint32_t type; const void *data; size_t size; @@ -111,7 +111,7 @@ bool MetaData::findInt32(uint32_t key, int32_t *value) const { return true; } -bool MetaData::findInt64(uint32_t key, int64_t *value) const { +bool MetaData::findInt64(uint32_t key, int64_t *value) { uint32_t type; const void *data; size_t size; @@ -126,7 +126,7 @@ bool MetaData::findInt64(uint32_t key, int64_t *value) const { return true; } -bool MetaData::findFloat(uint32_t key, float *value) const { +bool MetaData::findFloat(uint32_t key, float *value) { uint32_t type; const void *data; size_t size; @@ -141,7 +141,7 @@ bool MetaData::findFloat(uint32_t key, float *value) const { return true; } -bool MetaData::findPointer(uint32_t key, void **value) const { +bool MetaData::findPointer(uint32_t key, void **value) { uint32_t type; const void *data; size_t size; @@ -159,7 +159,7 @@ bool MetaData::findPointer(uint32_t key, void **value) const { bool MetaData::findRect( uint32_t key, int32_t *left, int32_t *top, - int32_t *right, int32_t *bottom) const { + int32_t *right, int32_t *bottom) { uint32_t type; const void *data; size_t size; diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index cd5bdfb..0f0ffd4 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -4077,10 +4077,10 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { numChannels, params.nChannels); } - if (sampleRate != params.nSamplingRate) { + if (sampleRate != (int32_t)params.nSamplingRate) { LOGW("Codec outputs at different sampling rate than " "what the input stream contains (contains data at " - "%d Hz, codec outputs %d Hz)", + "%d Hz, codec outputs %lu Hz)", sampleRate, params.nSamplingRate); } @@ -4203,6 +4203,14 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { break; } } + + // If the input format contains rotation information, flag the output + // format accordingly. + + int32_t rotationDegrees; + if (mSource->getFormat()->findInt32(kKeyRotation, &rotationDegrees)) { + mOutputFormat->setInt32(kKeyRotation, rotationDegrees); + } } status_t OMXCodec::pause() { 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/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk index 5ef54fd..359a2ec 100644 --- a/media/libstagefright/codecs/aacdec/Android.mk +++ b/media/libstagefright/codecs/aacdec/Android.mk @@ -176,6 +176,6 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright_omx libstagefright_foundation libutils LOCAL_MODULE := libstagefright_soft_aacdec -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk index 296cae4..5862abc 100644 --- a/media/libstagefright/codecs/amrnb/dec/Android.mk +++ b/media/libstagefright/codecs/amrnb/dec/Android.mk @@ -79,6 +79,6 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright_amrnb_common LOCAL_MODULE := libstagefright_soft_amrdec -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/avc/dec/Android.mk b/media/libstagefright/codecs/avc/dec/Android.mk index afecdc4..4d4533b 100644 --- a/media/libstagefright/codecs/avc/dec/Android.mk +++ b/media/libstagefright/codecs/avc/dec/Android.mk @@ -50,7 +50,7 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils LOCAL_MODULE := libstagefright_soft_avcdec -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk index b6953bc..6e98559 100644 --- a/media/libstagefright/codecs/g711/dec/Android.mk +++ b/media/libstagefright/codecs/g711/dec/Android.mk @@ -26,6 +26,6 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils LOCAL_MODULE := libstagefright_soft_g711dec -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk index 65b642c..f1bec08 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk +++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk @@ -71,6 +71,6 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils LOCAL_MODULE := libstagefright_soft_mpeg4dec -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk index 2d35183..229988e 100644 --- a/media/libstagefright/codecs/mp3dec/Android.mk +++ b/media/libstagefright/codecs/mp3dec/Android.mk @@ -77,6 +77,6 @@ LOCAL_STATIC_LIBRARIES := \ libstagefright_mp3dec LOCAL_MODULE := libstagefright_soft_mp3dec -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk index 1b3088f..832b885 100644 --- a/media/libstagefright/codecs/on2/dec/Android.mk +++ b/media/libstagefright/codecs/on2/dec/Android.mk @@ -37,7 +37,7 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils LOCAL_MODULE := libstagefright_soft_vpxdec -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk index 06f0079..9251229 100644 --- a/media/libstagefright/codecs/vorbis/dec/Android.mk +++ b/media/libstagefright/codecs/vorbis/dec/Android.mk @@ -32,7 +32,7 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright_foundation libutils LOCAL_MODULE := libstagefright_soft_vorbisdec -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk index 62ba40f..702a7b4 100644 --- a/media/libstagefright/colorconversion/Android.mk +++ b/media/libstagefright/colorconversion/Android.mk @@ -9,6 +9,10 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/base/include/media/stagefright/openmax \ $(TOP)/hardware/msm7k +ifneq ($(filter crespo crespo4g,$(TARGET_DEVICE)),) +LOCAL_CFLAGS += -DTHIS_IS_CRESPO=1 +endif + LOCAL_MODULE:= libstagefright_color_conversion include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp index ee86148..1828ac8 100644 --- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp +++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp @@ -56,9 +56,23 @@ SoftwareRenderer::SoftwareRenderer( } int halFormat; + size_t bufWidth, bufHeight; + switch (mColorFormat) { +#ifndef THIS_IS_CRESPO + case OMX_COLOR_FormatYUV420Planar: + { + halFormat = HAL_PIXEL_FORMAT_YV12; + bufWidth = (mWidth + 1) & ~1; + bufHeight = (mHeight + 1) & ~1; + break; + } +#endif + default: halFormat = HAL_PIXEL_FORMAT_RGB_565; + bufWidth = mWidth; + bufHeight = mHeight; mConverter = new ColorConverter( mColorFormat, OMX_COLOR_Format16bitRGB565); @@ -75,13 +89,17 @@ SoftwareRenderer::SoftwareRenderer( native_window_set_usage( mNativeWindow.get(), GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN - | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP)); + | GRALLOC_USAGE_HW_TEXTURE +#ifndef THIS_IS_CRESPO + | GRALLOC_USAGE_EXTERNAL_DISP +#endif + )); // Width must be multiple of 32??? CHECK_EQ(0, native_window_set_buffers_geometry( mNativeWindow.get(), - mCropRight - mCropLeft + 1, - mCropBottom - mCropTop + 1, + bufWidth, + bufHeight, halFormat)); uint32_t transform; @@ -97,6 +115,14 @@ SoftwareRenderer::SoftwareRenderer( CHECK_EQ(0, native_window_set_buffers_transform( mNativeWindow.get(), transform)); } + + android_native_rect_t crop; + crop.left = mCropLeft; + crop.top = mCropTop; + crop.right = mCropRight + 1; + crop.bottom = mCropBottom + 1; + + CHECK_EQ(0, native_window_set_crop(mNativeWindow.get(), &crop)); } SoftwareRenderer::~SoftwareRenderer() { @@ -104,6 +130,11 @@ SoftwareRenderer::~SoftwareRenderer() { mConverter = NULL; } +static int ALIGN(int x, int y) { + // y must be a power of 2. + return (x + y - 1) & ~(y - 1); +} + void SoftwareRenderer::render( const void *data, size_t size, void *platformPrivate) { ANativeWindowBuffer *buf; @@ -127,14 +158,40 @@ void SoftwareRenderer::render( mConverter->convert( data, mWidth, mHeight, - mCropLeft, mCropTop, mCropRight, mCropBottom, + 0, 0, mWidth - 1, mHeight - 1, dst, buf->stride, buf->height, - 0, 0, - mCropRight - mCropLeft, - mCropBottom - mCropTop); + 0, 0, mWidth - 1, mHeight - 1); } else { - TRESPASS(); + CHECK_EQ(mColorFormat, OMX_COLOR_FormatYUV420Planar); + + const uint8_t *src_y = (const uint8_t *)data; + const uint8_t *src_u = (const uint8_t *)data + mWidth * mHeight; + const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2); + + uint8_t *dst_y = (uint8_t *)dst; + size_t dst_y_size = buf->stride * buf->height; + size_t dst_c_stride = ALIGN(buf->stride / 2, 16); + size_t dst_c_size = dst_c_stride * buf->height / 2; + uint8_t *dst_v = dst_y + dst_y_size; + uint8_t *dst_u = dst_v + dst_c_size; + + for (int y = 0; y < mHeight; ++y) { + memcpy(dst_y, src_y, mWidth); + + src_y += mWidth; + dst_y += buf->stride; + } + + for (int y = 0; y < (mHeight + 1) / 2; ++y) { + memcpy(dst_u, src_u, (mWidth + 1) / 2); + memcpy(dst_v, src_v, (mWidth + 1) / 2); + + src_u += mWidth / 2; + src_v += mWidth / 2; + dst_u += dst_c_stride; + dst_v += dst_c_stride; + } } CHECK_EQ(0, mapper.unlock(buf->handle)); diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 835d2bb..3c9a121 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -45,6 +45,7 @@ class DrmManagerClinet; class DecryptHandle; class TimedTextPlayer; +struct WVMExtractor; struct AwesomeRenderer : public RefBase { AwesomeRenderer() {} @@ -231,6 +232,8 @@ private: int64_t mLastVideoTimeUs; TimedTextPlayer *mTextPlayer; + sp<WVMExtractor> mWVMExtractor; + status_t setDataSource_l( const char *uri, const KeyedVector<String8, String8> *headers = NULL); @@ -286,6 +289,8 @@ private: void shutdownVideoDecoder_l(); void setNativeWindow_l(const sp<ANativeWindow> &native); + 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 &); |