diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/MPEG4Extractor.cpp | 112 | ||||
-rw-r--r-- | media/libstagefright/StagefrightMetadataRetriever.cpp | 49 | ||||
-rw-r--r-- | media/libstagefright/include/MPEG4Extractor.h | 6 |
3 files changed, 159 insertions, 8 deletions
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 7b96d01..1ca2d6d 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -262,7 +262,7 @@ static const char *FourCC2MIME(uint32_t fourcc) { MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source) : mDataSource(source), - mHaveMetadata(false), + mInitCheck(NO_INIT), mHasVideo(false), mFirstTrack(NULL), mLastTrack(NULL), @@ -361,8 +361,8 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData( } status_t MPEG4Extractor::readMetaData() { - if (mHaveMetadata) { - return OK; + if (mInitCheck != NO_INIT) { + return mInitCheck; } off64_t offset = 0; @@ -370,17 +370,20 @@ status_t MPEG4Extractor::readMetaData() { while ((err = parseChunk(&offset, 0)) == OK) { } - if (mHaveMetadata) { + if (mInitCheck == OK) { if (mHasVideo) { mFileMetaData->setCString(kKeyMIMEType, "video/mp4"); } else { mFileMetaData->setCString(kKeyMIMEType, "audio/mp4"); } - return OK; + mInitCheck = verifyIfStreamable(); + } else { + mInitCheck = err; } - return err; + CHECK_NE(err, (status_t)NO_INIT); + return mInitCheck; } void MPEG4Extractor::setDrmFlag(bool flag) { @@ -755,7 +758,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return err; } } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) { - mHaveMetadata = true; + mInitCheck = OK; if (!mIsDrm) { return UNKNOWN_ERROR; // Return a dummy error. @@ -2077,6 +2080,101 @@ status_t MPEG4Source::read( } } +MPEG4Extractor::Track *MPEG4Extractor::findTrackByMimePrefix( + const char *mimePrefix) { + for (Track *track = mFirstTrack; track != NULL; track = track->next) { + const char *mime; + if (track->meta != NULL + && track->meta->findCString(kKeyMIMEType, &mime) + && !strncasecmp(mime, mimePrefix, strlen(mimePrefix))) { + return track; + } + } + + return NULL; +} + +status_t MPEG4Extractor::verifyIfStreamable() { + if (!(mDataSource->flags() & DataSource::kIsCachingDataSource)) { + return OK; + } + + Track *audio = findTrackByMimePrefix("audio/"); + Track *video = findTrackByMimePrefix("video/"); + + if (audio == NULL || video == NULL) { + return OK; + } + + sp<SampleTable> audioSamples = audio->sampleTable; + sp<SampleTable> videoSamples = video->sampleTable; + + off64_t maxOffsetDiff = 0; + int64_t maxOffsetTimeUs = -1; + + for (uint32_t i = 0; i < videoSamples->countSamples(); ++i) { + off64_t videoOffset; + uint32_t videoTime; + bool isSync; + CHECK_EQ((status_t)OK, videoSamples->getMetaDataForSample( + i, &videoOffset, NULL, &videoTime, &isSync)); + + int64_t videoTimeUs = (int64_t)(videoTime * 1E6 / video->timescale); + + uint32_t reqAudioTime = (videoTimeUs * audio->timescale) / 1000000; + uint32_t j; + if (audioSamples->findSampleAtTime( + reqAudioTime, &j, SampleTable::kFlagClosest) != OK) { + continue; + } + + off64_t audioOffset; + uint32_t audioTime; + CHECK_EQ((status_t)OK, audioSamples->getMetaDataForSample( + j, &audioOffset, NULL, &audioTime)); + + int64_t audioTimeUs = (int64_t)(audioTime * 1E6 / audio->timescale); + + off64_t offsetDiff = videoOffset - audioOffset; + if (offsetDiff < 0) { + offsetDiff = -offsetDiff; + } + +#if 0 + printf("%s%d/%d videoTime %.2f secs audioTime %.2f secs " + "videoOffset %lld audioOffset %lld offsetDiff %lld\n", + isSync ? "*" : " ", + i, + j, + videoTimeUs / 1E6, + audioTimeUs / 1E6, + videoOffset, + audioOffset, + offsetDiff); +#endif + + if (offsetDiff > maxOffsetDiff) { + maxOffsetDiff = offsetDiff; + maxOffsetTimeUs = videoTimeUs; + } + } + +#if 0 + printf("max offset diff: %lld at video time: %.2f secs\n", + maxOffsetDiff, maxOffsetTimeUs / 1E6); +#endif + + if (maxOffsetDiff < 1024 * 1024) { + return OK; + } + + LOGE("This content is not streamable, " + "max offset diff: %lld at video time: %.2f secs", + maxOffsetDiff, maxOffsetTimeUs / 1E6); + + return ERROR_UNSUPPORTED; +} + static bool LegacySniffMPEG4( const sp<DataSource> &source, String8 *mimeType, float *confidence) { uint8_t header[8]; diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index ea3b801..c371cd0 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -411,6 +411,12 @@ void StagefrightMetadataRetriever::parseMetaData() { mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp)); + bool hasAudio = false; + bool hasVideo = false; + int32_t videoWidth = -1; + int32_t videoHeight = -1; + int32_t audioBitrate = -1; + // The overall duration is the duration of the longest track. int64_t maxDurationUs = 0; for (size_t i = 0; i < numTracks; ++i) { @@ -422,12 +428,55 @@ void StagefrightMetadataRetriever::parseMetaData() { maxDurationUs = durationUs; } } + + const char *mime; + if (trackMeta->findCString(kKeyMIMEType, &mime)) { + if (!hasAudio && !strncasecmp("audio/", mime, 6)) { + hasAudio = true; + + if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) { + audioBitrate = -1; + } + } else if (!hasVideo && !strncasecmp("video/", mime, 6)) { + hasVideo = true; + + CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth)); + CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight)); + } + } } // The duration value is a string representing the duration in ms. sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000); mMetaData.add(METADATA_KEY_DURATION, String8(tmp)); + if (hasAudio) { + mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes")); + } + + if (hasVideo) { + mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes")); + + sprintf(tmp, "%d", videoWidth); + mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp)); + + sprintf(tmp, "%d", videoHeight); + mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp)); + } + + if (numTracks == 1 && hasAudio && audioBitrate >= 0) { + sprintf(tmp, "%ld", audioBitrate); + mMetaData.add(METADATA_KEY_BITRATE, String8(tmp)); + } else { + off64_t sourceSize; + if (mSource->getSize(&sourceSize) == OK) { + int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs); + + sprintf(tmp, "%lld", avgBitRate); + mMetaData.add(METADATA_KEY_BITRATE, String8(tmp)); + } + } + if (numTracks == 1) { const char *fileMIME; CHECK(meta->findCString(kKeyMIMEType, &fileMIME)); diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h index 04e8a6a..d9ef208 100644 --- a/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/include/MPEG4Extractor.h @@ -57,7 +57,7 @@ private: }; sp<DataSource> mDataSource; - bool mHaveMetadata; + status_t mInitCheck; bool mHasVideo; Track *mFirstTrack, *mLastTrack; @@ -90,6 +90,10 @@ private: status_t parseTrackHeader(off64_t data_offset, off64_t data_size); + Track *findTrackByMimePrefix(const char *mimePrefix); + + status_t verifyIfStreamable(); + MPEG4Extractor(const MPEG4Extractor &); MPEG4Extractor &operator=(const MPEG4Extractor &); }; |