summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/matroska/MatroskaExtractor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/matroska/MatroskaExtractor.cpp')
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp139
1 files changed, 110 insertions, 29 deletions
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 0e4dd2b..2587ec7 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -20,8 +20,6 @@
#include "MatroskaExtractor.h"
-#include "mkvparser.hpp"
-
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/DataSource.h>
@@ -89,7 +87,7 @@ private:
////////////////////////////////////////////////////////////////////////////////
struct BlockIterator {
- BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum);
+ BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum, unsigned long index);
bool eos() const;
@@ -106,6 +104,7 @@ struct BlockIterator {
private:
MatroskaExtractor *mExtractor;
long long mTrackNum;
+ unsigned long mIndex;
const mkvparser::Cluster *mCluster;
const mkvparser::BlockEntry *mBlockEntry;
@@ -157,6 +156,53 @@ private:
MatroskaSource &operator=(const MatroskaSource &);
};
+const mkvparser::Track* MatroskaExtractor::TrackInfo::getTrack() const {
+ return mExtractor->mSegment->GetTracks()->GetTrackByNumber(mTrackNum);
+}
+
+// This function does exactly the same as mkvparser::Cues::Find, except that it
+// searches in our own track based vectors. We should not need this once mkvparser
+// adds the same functionality.
+const mkvparser::CuePoint::TrackPosition *MatroskaExtractor::TrackInfo::find(
+ long long timeNs) const {
+ ALOGV("mCuePoints.size %zu", mCuePoints.size());
+ if (mCuePoints.empty()) {
+ return NULL;
+ }
+
+ const mkvparser::CuePoint* cp = mCuePoints.itemAt(0);
+ const mkvparser::Track* track = getTrack();
+ if (timeNs <= cp->GetTime(mExtractor->mSegment)) {
+ return cp->Find(track);
+ }
+
+ // Binary searches through relevant cues; assumes cues are ordered by timecode.
+ // If we do detect out-of-order cues, return NULL.
+ size_t lo = 0;
+ size_t hi = mCuePoints.size();
+ while (lo < hi) {
+ const size_t mid = lo + (hi - lo) / 2;
+ const mkvparser::CuePoint* const midCp = mCuePoints.itemAt(mid);
+ const long long cueTimeNs = midCp->GetTime(mExtractor->mSegment);
+ if (cueTimeNs <= timeNs) {
+ lo = mid + 1;
+ } else {
+ hi = mid;
+ }
+ }
+
+ if (lo == 0) {
+ return NULL;
+ }
+
+ cp = mCuePoints.itemAt(lo - 1);
+ if (cp->GetTime(mExtractor->mSegment) > timeNs) {
+ return NULL;
+ }
+
+ return cp->Find(track);
+}
+
MatroskaSource::MatroskaSource(
const sp<MatroskaExtractor> &extractor, size_t index)
: mExtractor(extractor),
@@ -164,7 +210,8 @@ MatroskaSource::MatroskaSource(
mType(OTHER),
mIsAudio(false),
mBlockIter(mExtractor.get(),
- mExtractor->mTracks.itemAt(index).mTrackNum),
+ mExtractor->mTracks.itemAt(index).mTrackNum,
+ index),
mNALSizeLen(0) {
sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
@@ -214,9 +261,10 @@ sp<MetaData> MatroskaSource::getFormat() {
////////////////////////////////////////////////////////////////////////////////
BlockIterator::BlockIterator(
- MatroskaExtractor *extractor, unsigned long trackNum)
+ MatroskaExtractor *extractor, unsigned long trackNum, unsigned long index)
: mExtractor(extractor),
mTrackNum(trackNum),
+ mIndex(index),
mCluster(NULL),
mBlockEntry(NULL),
mBlockEntryIndex(0) {
@@ -315,7 +363,7 @@ void BlockIterator::seek(
*actualFrameTimeUs = -1ll;
- const int64_t seekTimeNs = seekTimeUs * 1000ll;
+ const int64_t seekTimeNs = seekTimeUs * 1000ll - mExtractor->mSeekPreRollNs;
mkvparser::Segment* const pSegment = mExtractor->mSegment;
@@ -364,9 +412,20 @@ void BlockIterator::seek(
}
const mkvparser::CuePoint* pCP;
+ mkvparser::Tracks const *pTracks = pSegment->GetTracks();
+ unsigned long int trackCount = pTracks->GetTracksCount();
while (!pCues->DoneParsing()) {
pCues->LoadCuePoint();
pCP = pCues->GetLast();
+ CHECK(pCP);
+
+ for (size_t index = 0; index < trackCount; ++index) {
+ const mkvparser::Track *pTrack = pTracks->GetTrackByIndex(index);
+ if (pTrack && pTrack->GetType() == 1 && pCP->Find(pTrack)) { // VIDEO_TRACK
+ MatroskaExtractor::TrackInfo& track = mExtractor->mTracks.editItemAt(index);
+ track.mCuePoints.push_back(pCP);
+ }
+ }
if (pCP->GetTime(pSegment) >= seekTimeNs) {
ALOGV("Parsed past relevant Cue");
@@ -374,22 +433,25 @@ void BlockIterator::seek(
}
}
- // The Cue index is built around video keyframes
- mkvparser::Tracks const *pTracks = pSegment->GetTracks();
- const mkvparser::Track *pTrack = NULL;
- for (size_t index = 0; index < pTracks->GetTracksCount(); ++index) {
- pTrack = pTracks->GetTrackByIndex(index);
- if (pTrack && pTrack->GetType() == 1) { // VIDEO_TRACK
- ALOGV("Video track located at %zu", index);
- break;
+ const mkvparser::CuePoint::TrackPosition *pTP = NULL;
+ const mkvparser::Track *thisTrack = pTracks->GetTrackByIndex(mIndex);
+ if (thisTrack->GetType() == 1) { // video
+ MatroskaExtractor::TrackInfo& track = mExtractor->mTracks.editItemAt(mIndex);
+ pTP = track.find(seekTimeNs);
+ } else {
+ // The Cue index is built around video keyframes
+ for (size_t index = 0; index < trackCount; ++index) {
+ const mkvparser::Track *pTrack = pTracks->GetTrackByIndex(index);
+ if (pTrack && pTrack->GetType() == 1 && pCues->Find(seekTimeNs, pTrack, pCP, pTP)) {
+ ALOGV("Video track located at %zu", index);
+ break;
+ }
}
}
+
// Always *search* based on the video track, but finalize based on mTrackNum
- const mkvparser::CuePoint::TrackPosition* pTP;
- if (pTrack && pTrack->GetType() == 1) {
- pCues->Find(seekTimeNs, pTrack, pCP, pTP);
- } else {
+ if (!pTP) {
ALOGE("Did not locate the video track for seeking");
return;
}
@@ -410,10 +472,13 @@ void BlockIterator::seek(
if (isAudio || block()->IsKey()) {
// Accept the first key frame
- *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL;
- ALOGV("Requested seek point: %" PRId64 " actual: %" PRId64,
- seekTimeUs, *actualFrameTimeUs);
- break;
+ int64_t frameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL;
+ if (thisTrack->GetType() == 1 || frameTimeUs >= seekTimeUs) {
+ *actualFrameTimeUs = frameTimeUs;
+ ALOGV("Requested seek point: %" PRId64 " actual: %" PRId64,
+ seekTimeUs, *actualFrameTimeUs);
+ break;
+ }
}
}
}
@@ -630,7 +695,8 @@ MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
mReader(new DataSourceReader(mDataSource)),
mSegment(NULL),
mExtractedThumbnails(false),
- mIsWebm(false) {
+ mIsWebm(false),
+ mSeekPreRollNs(0) {
off64_t size;
mIsLiveStreaming =
(mDataSource->flags()
@@ -656,14 +722,22 @@ MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
return;
}
+ // from mkvparser::Segment::Load(), but stop at first cluster
ret = mSegment->ParseHeaders();
- CHECK_EQ(ret, 0);
-
- long len;
- ret = mSegment->LoadCluster(pos, len);
- CHECK_EQ(ret, 0);
+ if (ret == 0) {
+ long len;
+ ret = mSegment->LoadCluster(pos, len);
+ if (ret >= 1) {
+ // no more clusters
+ ret = 0;
+ }
+ } else if (ret > 0) {
+ ret = mkvparser::E_BUFFER_NOT_FULL;
+ }
if (ret < 0) {
+ ALOGW("Corrupt %s source: %s", mIsWebm ? "webm" : "matroska",
+ uriDebugString(mDataSource->getUri()).c_str());
delete mSegment;
mSegment = NULL;
return;
@@ -921,6 +995,12 @@ void MatroskaExtractor::addTracks() {
err = addVorbisCodecInfo(
meta, codecPrivate, codecPrivateSize);
+ } else if (!strcmp("A_OPUS", codecID)) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
+ meta->setData(kKeyOpusHeader, 0, codecPrivate, codecPrivateSize);
+ meta->setInt64(kKeyOpusCodecDelay, track->GetCodecDelay());
+ meta->setInt64(kKeyOpusSeekPreRoll, track->GetSeekPreRoll());
+ mSeekPreRollNs = track->GetSeekPreRoll();
} else if (!strcmp("A_MPEG/L3", codecID)) {
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
} else {
@@ -949,6 +1029,7 @@ void MatroskaExtractor::addTracks() {
TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1);
trackInfo->mTrackNum = track->GetNumber();
trackInfo->mMeta = meta;
+ trackInfo->mExtractor = this;
}
}
@@ -963,7 +1044,7 @@ void MatroskaExtractor::findThumbnails() {
continue;
}
- BlockIterator iter(this, info->mTrackNum);
+ BlockIterator iter(this, info->mTrackNum, i);
int32_t j = 0;
int64_t thumbnailTimeUs = 0;
size_t maxBlockSize = 0;