Loading media/libstagefright/NuMediaExtractor.cpp +163 −76 Original line number Diff line number Diff line Loading @@ -40,13 +40,23 @@ namespace android { NuMediaExtractor::Sample::Sample() : mBuffer(NULL), mSampleTimeUs(-1ll) { } NuMediaExtractor::Sample::Sample(MediaBuffer *buffer, int64_t timeUs) : mBuffer(buffer), mSampleTimeUs(timeUs) { } NuMediaExtractor::NuMediaExtractor() : mTotalBitrate(-1ll), mDurationUs(-1ll) { } NuMediaExtractor::~NuMediaExtractor() { releaseTrackSamples(); releaseAllTrackSamples(); for (size_t i = 0; i < mSelectedTracks.size(); ++i) { TrackInfo *info = &mSelectedTracks.editItemAt(i); Loading Loading @@ -288,7 +298,8 @@ status_t NuMediaExtractor::getFileFormat(sp<AMessage> *format) const { return OK; } status_t NuMediaExtractor::selectTrack(size_t index) { status_t NuMediaExtractor::selectTrack(size_t index, int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) { Mutex::Autolock autoLock(mLock); if (mImpl == NULL) { Loading @@ -311,31 +322,56 @@ status_t NuMediaExtractor::selectTrack(size_t index) { sp<IMediaSource> source = mImpl->getTrack(index); if (source == nullptr) { ALOGE("track %zu is empty", index); return ERROR_MALFORMED; } status_t ret = source->start(); if (ret != OK) { ALOGE("track %zu failed to start", index); return ret; } sp<MetaData> meta = source->getFormat(); if (meta == NULL) { ALOGE("track %zu has no meta data", index); return ERROR_MALFORMED; } const char *mime; if (!meta->findCString(kKeyMIMEType, &mime)) { ALOGE("track %zu has no mime type in meta data", index); return ERROR_MALFORMED; } ALOGV("selectTrack, track[%zu]: %s", index, mime); mSelectedTracks.push(); TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1); info->mSource = source; info->mTrackIndex = index; if (!strncasecmp(mime, "audio/", 6)) { info->mTrackType = MEDIA_TRACK_TYPE_AUDIO; info->mMaxFetchCount = 64; } else if (!strncasecmp(mime, "video/", 6)) { info->mTrackType = MEDIA_TRACK_TYPE_VIDEO; info->mMaxFetchCount = 8; } else { info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN; info->mMaxFetchCount = 1; } info->mFinalResult = OK; info->mSample = NULL; info->mSampleTimeUs = -1ll; releaseTrackSamples(info); info->mTrackFlags = 0; const char *mime; CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime)); if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { info->mTrackFlags |= kIsVorbis; } if (startTimeUs >= 0) { fetchTrackSamples(info, startTimeUs, mode); } return OK; } Loading Loading @@ -366,12 +402,7 @@ status_t NuMediaExtractor::unselectTrack(size_t index) { TrackInfo *info = &mSelectedTracks.editItemAt(i); if (info->mSample != NULL) { info->mSample->release(); info->mSample = NULL; info->mSampleTimeUs = -1ll; } releaseTrackSamples(info); CHECK_EQ((status_t)OK, info->mSource->stop()); Loading @@ -380,79 +411,136 @@ status_t NuMediaExtractor::unselectTrack(size_t index) { return OK; } void NuMediaExtractor::releaseTrackSamples() { for (size_t i = 0; i < mSelectedTracks.size(); ++i) { TrackInfo *info = &mSelectedTracks.editItemAt(i); void NuMediaExtractor::releaseOneSample(TrackInfo *info) { if (info == NULL || info->mSamples.empty()) { return; } auto it = info->mSamples.begin(); if (it->mBuffer != NULL) { it->mBuffer->release(); } info->mSamples.erase(it); } if (info->mSample != NULL) { info->mSample->release(); info->mSample = NULL; void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) { if (info == NULL) { return; } info->mSampleTimeUs = -1ll; auto it = info->mSamples.begin(); while (it != info->mSamples.end()) { if (it->mBuffer != NULL) { it->mBuffer->release(); } it = info->mSamples.erase(it); } } void NuMediaExtractor::releaseAllTrackSamples() { for (size_t i = 0; i < mSelectedTracks.size(); ++i) { releaseTrackSamples(&mSelectedTracks.editItemAt(i)); } } ssize_t NuMediaExtractor::fetchTrackSamples( ssize_t NuMediaExtractor::fetchAllTrackSamples( int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) { TrackInfo *minInfo = NULL; ssize_t minIndex = -1; for (size_t i = 0; i < mSelectedTracks.size(); ++i) { TrackInfo *info = &mSelectedTracks.editItemAt(i); fetchTrackSamples(info, seekTimeUs, mode); if (seekTimeUs >= 0ll) { info->mFinalResult = OK; if (info->mSamples.empty()) { continue; } if (info->mSample != NULL) { info->mSample->release(); info->mSample = NULL; info->mSampleTimeUs = -1ll; if (minInfo == NULL) { minInfo = info; minIndex = i; } else { auto it = info->mSamples.begin(); auto itMin = minInfo->mSamples.begin(); if (it->mSampleTimeUs < itMin->mSampleTimeUs) { minInfo = info; minIndex = i; } } else if (info->mFinalResult != OK) { continue; } } return minIndex; } void NuMediaExtractor::fetchTrackSamples(TrackInfo *info, int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) { if (info == NULL) { return; } if (info->mSample == NULL) { MediaSource::ReadOptions options; if (seekTimeUs >= 0ll) { options.setSeekTo(seekTimeUs, mode); info->mFinalResult = OK; releaseTrackSamples(info); } else if (info->mFinalResult != OK || !info->mSamples.empty()) { return; } status_t err = info->mSource->read(&info->mSample, &options); if (err != OK) { CHECK(info->mSample == NULL); status_t err = OK; Vector<MediaBuffer *> mediaBuffers; if (info->mSource->supportReadMultiple()) { options.setNonBlocking(); err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options); } else { MediaBuffer *mbuf = NULL; err = info->mSource->read(&mbuf, &options); if (err == OK && mbuf != NULL) { mediaBuffers.push_back(mbuf); } } info->mFinalResult = err; if (info->mFinalResult != ERROR_END_OF_STREAM) { ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err); if (err != OK && err != ERROR_END_OF_STREAM) { ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err); size_t count = mediaBuffers.size(); for (size_t id = 0; id < count; ++id) { MediaBuffer *mbuf = mediaBuffers[id]; if (mbuf != NULL) { mbuf->release(); } } return; } info->mSampleTimeUs = -1ll; size_t count = mediaBuffers.size(); bool releaseRemaining = false; for (size_t id = 0; id < count; ++id) { int64_t timeUs; MediaBuffer *mbuf = mediaBuffers[id]; if (mbuf == NULL) { continue; } else { CHECK(info->mSample != NULL); CHECK(info->mSample->meta_data()->findInt64( kKeyTime, &info->mSampleTimeUs)); } if (releaseRemaining) { mbuf->release(); continue; } if (minInfo == NULL || info->mSampleTimeUs < minInfo->mSampleTimeUs) { minInfo = info; minIndex = i; if (mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) { info->mSamples.emplace_back(mbuf, timeUs); } else { mbuf->meta_data()->dumpToLog(); info->mFinalResult = ERROR_MALFORMED; mbuf->release(); releaseRemaining = true; } } return minIndex; } status_t NuMediaExtractor::seekTo( int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(timeUs, mode); ssize_t minIndex = fetchAllTrackSamples(timeUs, mode); if (minIndex < 0) { return ERROR_END_OF_STREAM; Loading @@ -464,7 +552,7 @@ status_t NuMediaExtractor::seekTo( status_t NuMediaExtractor::advance() { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; Loading @@ -472,28 +560,26 @@ status_t NuMediaExtractor::advance() { TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); info->mSample->release(); info->mSample = NULL; info->mSampleTimeUs = -1ll; releaseOneSample(info); return OK; } status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) { status_t NuMediaExtractor::appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer) { int32_t numPageSamples; if (!info->mSample->meta_data()->findInt32( if (!mbuf->meta_data()->findInt32( kKeyValidSamples, &numPageSamples)) { numPageSamples = -1; } memcpy((uint8_t *)buffer->data() + info->mSample->range_length(), memcpy((uint8_t *)buffer->data() + mbuf->range_length(), &numPageSamples, sizeof(numPageSamples)); uint32_t type; const void *data; size_t size, size2; if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) { if (mbuf->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) { // Signal numPageSamples (a plain int32_t) is appended at the end, // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes if (SIZE_MAX - size < sizeof(int32_t)) { Loading @@ -511,9 +597,9 @@ status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp< int32_t zero = 0; memcpy(adata, data, size); memcpy(adata + size, &zero, sizeof(zero)); info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize); mbuf->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize); if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) { if (mbuf->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) { if (size2 != size) { return ERROR_MALFORMED; } Loading @@ -526,7 +612,7 @@ status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp< // append sizeof(numPageSamples) to plain sizes. int32_t int32Size = sizeof(numPageSamples); memcpy(adata + size, &int32Size, sizeof(int32Size)); info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize); mbuf->meta_data()->setData(kKeyPlainSizes, type, adata, newSize); } return OK; Loading @@ -535,7 +621,7 @@ status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp< status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; Loading @@ -543,7 +629,8 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); size_t sampleSize = info->mSample->range_length(); auto it = info->mSamples.begin(); size_t sampleSize = it->mBuffer->range_length(); if (info->mTrackFlags & kIsVorbis) { // Each sample's data is suffixed by the number of page samples Loading @@ -556,14 +643,14 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { } const uint8_t *src = (const uint8_t *)info->mSample->data() + info->mSample->range_offset(); (const uint8_t *)it->mBuffer->data() + it->mBuffer->range_offset(); memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length()); memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length()); status_t err = OK; if (info->mTrackFlags & kIsVorbis) { err = appendVorbisNumPageSamples(info, buffer); err = appendVorbisNumPageSamples(it->mBuffer, buffer); } if (err == OK) { Loading @@ -576,7 +663,7 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; Loading @@ -591,14 +678,14 @@ status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; } TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); *sampleTimeUs = info->mSampleTimeUs; *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs; return OK; } Loading @@ -608,14 +695,14 @@ status_t NuMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) { *sampleMeta = NULL; ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; } TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); *sampleMeta = info->mSample->meta_data(); *sampleMeta = info->mSamples.begin()->mBuffer->meta_data(); return OK; } Loading media/libstagefright/include/media/stagefright/NuMediaExtractor.h +29 −6 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ #ifndef NU_MEDIA_EXTRACTOR_H_ #define NU_MEDIA_EXTRACTOR_H_ #include <list> #include <media/mediaplayer.h> #include <media/stagefright/foundation/ABase.h> #include <media/IMediaExtractor.h> #include <media/MediaSource.h> Loading Loading @@ -67,7 +69,9 @@ struct NuMediaExtractor : public RefBase { status_t getFileFormat(sp<AMessage> *format) const; status_t selectTrack(size_t index); status_t selectTrack(size_t index, int64_t startTimeUs = -1ll, MediaSource::ReadOptions::SeekMode mode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); status_t unselectTrack(size_t index); status_t seekTo( Loading @@ -75,8 +79,12 @@ struct NuMediaExtractor : public RefBase { MediaSource::ReadOptions::SeekMode mode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); // Each selected track has a read pointer. // advance() advances the read pointer with the lowest timestamp. status_t advance(); // readSampleData() reads the sample with the lowest timestamp. status_t readSampleData(const sp<ABuffer> &buffer); status_t getSampleTrackIndex(size_t *trackIndex); status_t getSampleTime(int64_t *sampleTimeUs); status_t getSampleMeta(sp<MetaData> *sampleMeta); Loading @@ -96,12 +104,20 @@ private: kMaxTrackCount = 16384, }; struct Sample { Sample(); Sample(MediaBuffer *buffer, int64_t timeUs); MediaBuffer *mBuffer; int64_t mSampleTimeUs; }; struct TrackInfo { sp<IMediaSource> mSource; size_t mTrackIndex; media_track_type mTrackType; size_t mMaxFetchCount; status_t mFinalResult; MediaBuffer *mSample; int64_t mSampleTimeUs; std::list<Sample> mSamples; uint32_t mTrackFlags; // bitmask of "TrackFlags" }; Loading @@ -117,16 +133,23 @@ private: int64_t mTotalBitrate; // in bits/sec int64_t mDurationUs; ssize_t fetchTrackSamples( ssize_t fetchAllTrackSamples( int64_t seekTimeUs = -1ll, MediaSource::ReadOptions::SeekMode mode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); void fetchTrackSamples( TrackInfo *info, int64_t seekTimeUs = -1ll, MediaSource::ReadOptions::SeekMode mode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); void releaseTrackSamples(); void releaseOneSample(TrackInfo *info); void releaseTrackSamples(TrackInfo *info); void releaseAllTrackSamples(); bool getTotalBitrate(int64_t *bitRate) const; status_t updateDurationAndBitrate(); status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer); status_t appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer); DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor); }; Loading Loading
media/libstagefright/NuMediaExtractor.cpp +163 −76 Original line number Diff line number Diff line Loading @@ -40,13 +40,23 @@ namespace android { NuMediaExtractor::Sample::Sample() : mBuffer(NULL), mSampleTimeUs(-1ll) { } NuMediaExtractor::Sample::Sample(MediaBuffer *buffer, int64_t timeUs) : mBuffer(buffer), mSampleTimeUs(timeUs) { } NuMediaExtractor::NuMediaExtractor() : mTotalBitrate(-1ll), mDurationUs(-1ll) { } NuMediaExtractor::~NuMediaExtractor() { releaseTrackSamples(); releaseAllTrackSamples(); for (size_t i = 0; i < mSelectedTracks.size(); ++i) { TrackInfo *info = &mSelectedTracks.editItemAt(i); Loading Loading @@ -288,7 +298,8 @@ status_t NuMediaExtractor::getFileFormat(sp<AMessage> *format) const { return OK; } status_t NuMediaExtractor::selectTrack(size_t index) { status_t NuMediaExtractor::selectTrack(size_t index, int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) { Mutex::Autolock autoLock(mLock); if (mImpl == NULL) { Loading @@ -311,31 +322,56 @@ status_t NuMediaExtractor::selectTrack(size_t index) { sp<IMediaSource> source = mImpl->getTrack(index); if (source == nullptr) { ALOGE("track %zu is empty", index); return ERROR_MALFORMED; } status_t ret = source->start(); if (ret != OK) { ALOGE("track %zu failed to start", index); return ret; } sp<MetaData> meta = source->getFormat(); if (meta == NULL) { ALOGE("track %zu has no meta data", index); return ERROR_MALFORMED; } const char *mime; if (!meta->findCString(kKeyMIMEType, &mime)) { ALOGE("track %zu has no mime type in meta data", index); return ERROR_MALFORMED; } ALOGV("selectTrack, track[%zu]: %s", index, mime); mSelectedTracks.push(); TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1); info->mSource = source; info->mTrackIndex = index; if (!strncasecmp(mime, "audio/", 6)) { info->mTrackType = MEDIA_TRACK_TYPE_AUDIO; info->mMaxFetchCount = 64; } else if (!strncasecmp(mime, "video/", 6)) { info->mTrackType = MEDIA_TRACK_TYPE_VIDEO; info->mMaxFetchCount = 8; } else { info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN; info->mMaxFetchCount = 1; } info->mFinalResult = OK; info->mSample = NULL; info->mSampleTimeUs = -1ll; releaseTrackSamples(info); info->mTrackFlags = 0; const char *mime; CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime)); if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { info->mTrackFlags |= kIsVorbis; } if (startTimeUs >= 0) { fetchTrackSamples(info, startTimeUs, mode); } return OK; } Loading Loading @@ -366,12 +402,7 @@ status_t NuMediaExtractor::unselectTrack(size_t index) { TrackInfo *info = &mSelectedTracks.editItemAt(i); if (info->mSample != NULL) { info->mSample->release(); info->mSample = NULL; info->mSampleTimeUs = -1ll; } releaseTrackSamples(info); CHECK_EQ((status_t)OK, info->mSource->stop()); Loading @@ -380,79 +411,136 @@ status_t NuMediaExtractor::unselectTrack(size_t index) { return OK; } void NuMediaExtractor::releaseTrackSamples() { for (size_t i = 0; i < mSelectedTracks.size(); ++i) { TrackInfo *info = &mSelectedTracks.editItemAt(i); void NuMediaExtractor::releaseOneSample(TrackInfo *info) { if (info == NULL || info->mSamples.empty()) { return; } auto it = info->mSamples.begin(); if (it->mBuffer != NULL) { it->mBuffer->release(); } info->mSamples.erase(it); } if (info->mSample != NULL) { info->mSample->release(); info->mSample = NULL; void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) { if (info == NULL) { return; } info->mSampleTimeUs = -1ll; auto it = info->mSamples.begin(); while (it != info->mSamples.end()) { if (it->mBuffer != NULL) { it->mBuffer->release(); } it = info->mSamples.erase(it); } } void NuMediaExtractor::releaseAllTrackSamples() { for (size_t i = 0; i < mSelectedTracks.size(); ++i) { releaseTrackSamples(&mSelectedTracks.editItemAt(i)); } } ssize_t NuMediaExtractor::fetchTrackSamples( ssize_t NuMediaExtractor::fetchAllTrackSamples( int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) { TrackInfo *minInfo = NULL; ssize_t minIndex = -1; for (size_t i = 0; i < mSelectedTracks.size(); ++i) { TrackInfo *info = &mSelectedTracks.editItemAt(i); fetchTrackSamples(info, seekTimeUs, mode); if (seekTimeUs >= 0ll) { info->mFinalResult = OK; if (info->mSamples.empty()) { continue; } if (info->mSample != NULL) { info->mSample->release(); info->mSample = NULL; info->mSampleTimeUs = -1ll; if (minInfo == NULL) { minInfo = info; minIndex = i; } else { auto it = info->mSamples.begin(); auto itMin = minInfo->mSamples.begin(); if (it->mSampleTimeUs < itMin->mSampleTimeUs) { minInfo = info; minIndex = i; } } else if (info->mFinalResult != OK) { continue; } } return minIndex; } void NuMediaExtractor::fetchTrackSamples(TrackInfo *info, int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) { if (info == NULL) { return; } if (info->mSample == NULL) { MediaSource::ReadOptions options; if (seekTimeUs >= 0ll) { options.setSeekTo(seekTimeUs, mode); info->mFinalResult = OK; releaseTrackSamples(info); } else if (info->mFinalResult != OK || !info->mSamples.empty()) { return; } status_t err = info->mSource->read(&info->mSample, &options); if (err != OK) { CHECK(info->mSample == NULL); status_t err = OK; Vector<MediaBuffer *> mediaBuffers; if (info->mSource->supportReadMultiple()) { options.setNonBlocking(); err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options); } else { MediaBuffer *mbuf = NULL; err = info->mSource->read(&mbuf, &options); if (err == OK && mbuf != NULL) { mediaBuffers.push_back(mbuf); } } info->mFinalResult = err; if (info->mFinalResult != ERROR_END_OF_STREAM) { ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err); if (err != OK && err != ERROR_END_OF_STREAM) { ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err); size_t count = mediaBuffers.size(); for (size_t id = 0; id < count; ++id) { MediaBuffer *mbuf = mediaBuffers[id]; if (mbuf != NULL) { mbuf->release(); } } return; } info->mSampleTimeUs = -1ll; size_t count = mediaBuffers.size(); bool releaseRemaining = false; for (size_t id = 0; id < count; ++id) { int64_t timeUs; MediaBuffer *mbuf = mediaBuffers[id]; if (mbuf == NULL) { continue; } else { CHECK(info->mSample != NULL); CHECK(info->mSample->meta_data()->findInt64( kKeyTime, &info->mSampleTimeUs)); } if (releaseRemaining) { mbuf->release(); continue; } if (minInfo == NULL || info->mSampleTimeUs < minInfo->mSampleTimeUs) { minInfo = info; minIndex = i; if (mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) { info->mSamples.emplace_back(mbuf, timeUs); } else { mbuf->meta_data()->dumpToLog(); info->mFinalResult = ERROR_MALFORMED; mbuf->release(); releaseRemaining = true; } } return minIndex; } status_t NuMediaExtractor::seekTo( int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(timeUs, mode); ssize_t minIndex = fetchAllTrackSamples(timeUs, mode); if (minIndex < 0) { return ERROR_END_OF_STREAM; Loading @@ -464,7 +552,7 @@ status_t NuMediaExtractor::seekTo( status_t NuMediaExtractor::advance() { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; Loading @@ -472,28 +560,26 @@ status_t NuMediaExtractor::advance() { TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); info->mSample->release(); info->mSample = NULL; info->mSampleTimeUs = -1ll; releaseOneSample(info); return OK; } status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) { status_t NuMediaExtractor::appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer) { int32_t numPageSamples; if (!info->mSample->meta_data()->findInt32( if (!mbuf->meta_data()->findInt32( kKeyValidSamples, &numPageSamples)) { numPageSamples = -1; } memcpy((uint8_t *)buffer->data() + info->mSample->range_length(), memcpy((uint8_t *)buffer->data() + mbuf->range_length(), &numPageSamples, sizeof(numPageSamples)); uint32_t type; const void *data; size_t size, size2; if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) { if (mbuf->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) { // Signal numPageSamples (a plain int32_t) is appended at the end, // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes if (SIZE_MAX - size < sizeof(int32_t)) { Loading @@ -511,9 +597,9 @@ status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp< int32_t zero = 0; memcpy(adata, data, size); memcpy(adata + size, &zero, sizeof(zero)); info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize); mbuf->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize); if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) { if (mbuf->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) { if (size2 != size) { return ERROR_MALFORMED; } Loading @@ -526,7 +612,7 @@ status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp< // append sizeof(numPageSamples) to plain sizes. int32_t int32Size = sizeof(numPageSamples); memcpy(adata + size, &int32Size, sizeof(int32Size)); info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize); mbuf->meta_data()->setData(kKeyPlainSizes, type, adata, newSize); } return OK; Loading @@ -535,7 +621,7 @@ status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp< status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; Loading @@ -543,7 +629,8 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); size_t sampleSize = info->mSample->range_length(); auto it = info->mSamples.begin(); size_t sampleSize = it->mBuffer->range_length(); if (info->mTrackFlags & kIsVorbis) { // Each sample's data is suffixed by the number of page samples Loading @@ -556,14 +643,14 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { } const uint8_t *src = (const uint8_t *)info->mSample->data() + info->mSample->range_offset(); (const uint8_t *)it->mBuffer->data() + it->mBuffer->range_offset(); memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length()); memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length()); status_t err = OK; if (info->mTrackFlags & kIsVorbis) { err = appendVorbisNumPageSamples(info, buffer); err = appendVorbisNumPageSamples(it->mBuffer, buffer); } if (err == OK) { Loading @@ -576,7 +663,7 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; Loading @@ -591,14 +678,14 @@ status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { Mutex::Autolock autoLock(mLock); ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; } TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); *sampleTimeUs = info->mSampleTimeUs; *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs; return OK; } Loading @@ -608,14 +695,14 @@ status_t NuMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) { *sampleMeta = NULL; ssize_t minIndex = fetchTrackSamples(); ssize_t minIndex = fetchAllTrackSamples(); if (minIndex < 0) { return ERROR_END_OF_STREAM; } TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); *sampleMeta = info->mSample->meta_data(); *sampleMeta = info->mSamples.begin()->mBuffer->meta_data(); return OK; } Loading
media/libstagefright/include/media/stagefright/NuMediaExtractor.h +29 −6 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ #ifndef NU_MEDIA_EXTRACTOR_H_ #define NU_MEDIA_EXTRACTOR_H_ #include <list> #include <media/mediaplayer.h> #include <media/stagefright/foundation/ABase.h> #include <media/IMediaExtractor.h> #include <media/MediaSource.h> Loading Loading @@ -67,7 +69,9 @@ struct NuMediaExtractor : public RefBase { status_t getFileFormat(sp<AMessage> *format) const; status_t selectTrack(size_t index); status_t selectTrack(size_t index, int64_t startTimeUs = -1ll, MediaSource::ReadOptions::SeekMode mode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); status_t unselectTrack(size_t index); status_t seekTo( Loading @@ -75,8 +79,12 @@ struct NuMediaExtractor : public RefBase { MediaSource::ReadOptions::SeekMode mode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); // Each selected track has a read pointer. // advance() advances the read pointer with the lowest timestamp. status_t advance(); // readSampleData() reads the sample with the lowest timestamp. status_t readSampleData(const sp<ABuffer> &buffer); status_t getSampleTrackIndex(size_t *trackIndex); status_t getSampleTime(int64_t *sampleTimeUs); status_t getSampleMeta(sp<MetaData> *sampleMeta); Loading @@ -96,12 +104,20 @@ private: kMaxTrackCount = 16384, }; struct Sample { Sample(); Sample(MediaBuffer *buffer, int64_t timeUs); MediaBuffer *mBuffer; int64_t mSampleTimeUs; }; struct TrackInfo { sp<IMediaSource> mSource; size_t mTrackIndex; media_track_type mTrackType; size_t mMaxFetchCount; status_t mFinalResult; MediaBuffer *mSample; int64_t mSampleTimeUs; std::list<Sample> mSamples; uint32_t mTrackFlags; // bitmask of "TrackFlags" }; Loading @@ -117,16 +133,23 @@ private: int64_t mTotalBitrate; // in bits/sec int64_t mDurationUs; ssize_t fetchTrackSamples( ssize_t fetchAllTrackSamples( int64_t seekTimeUs = -1ll, MediaSource::ReadOptions::SeekMode mode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); void fetchTrackSamples( TrackInfo *info, int64_t seekTimeUs = -1ll, MediaSource::ReadOptions::SeekMode mode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); void releaseTrackSamples(); void releaseOneSample(TrackInfo *info); void releaseTrackSamples(TrackInfo *info); void releaseAllTrackSamples(); bool getTotalBitrate(int64_t *bitRate) const; status_t updateDurationAndBitrate(); status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer); status_t appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer); DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor); }; Loading