summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/matroska
diff options
context:
space:
mode:
authorJohann <johannkoenig@google.com>2012-03-29 16:54:03 -0700
committerJohann <johannkoenig@google.com>2012-04-02 15:13:59 -0700
commit10f0fe7bcd60bdb0eceb905e84ac11555e8c1b9d (patch)
treee0f6b017d61bd2f4b5c9ef3ae0e42045a6898f98 /media/libstagefright/matroska
parent73d227557ba5192735356bacab9f77b44980793b (diff)
downloadframeworks_av-10f0fe7bcd60bdb0eceb905e84ac11555e8c1b9d.zip
frameworks_av-10f0fe7bcd60bdb0eceb905e84ac11555e8c1b9d.tar.gz
frameworks_av-10f0fe7bcd60bdb0eceb905e84ac11555e8c1b9d.tar.bz2
Use Cues to seek Matroska files
On the first seek, load the Cues element. Parse it incrementally until the desired seek point can be located. This allows files to begin playing immediately. However, the Browser still seeks to 0 before playing embedded YouTube files. Because YouTube stores the cues at the end of the file, this causes it to seek, load the cues, then begin playing. It is still better than the previous behavior which blocked until the entire file was loaded. BUG=5921311 Change-Id: Iad2abc64ded3b4e2c2d2c478a969f68450754282
Diffstat (limited to 'media/libstagefright/matroska')
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp110
1 files changed, 97 insertions, 13 deletions
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index a0db719..8657d7f 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -313,11 +313,99 @@ void BlockIterator::seek(
*actualFrameTimeUs = -1ll;
- int64_t seekTimeNs = seekTimeUs * 1000ll;
+ const int64_t seekTimeNs = seekTimeUs * 1000ll;
+
+ mkvparser::Segment* const pSegment = mExtractor->mSegment;
+
+ // Special case the 0 seek to avoid loading Cues when the application
+ // extraneously seeks to 0 before playing.
+ if (seekTimeNs <= 0) {
+ ALOGV("Seek to beginning: %lld", seekTimeUs);
+ mCluster = pSegment->GetFirst();
+ mBlockEntryIndex = 0;
+ do {
+ advance_l();
+ } while (!eos() && block()->GetTrackNumber() != mTrackNum);
+ return;
+ }
- mCluster = mExtractor->mSegment->FindCluster(seekTimeNs);
- mBlockEntry = NULL;
- mBlockEntryIndex = 0;
+ ALOGV("Seeking to: %lld", seekTimeUs);
+
+ // If the Cues have not been located then find them.
+ const mkvparser::Cues* pCues = pSegment->GetCues();
+ const mkvparser::SeekHead* pSH = pSegment->GetSeekHead();
+ if (!pCues && pSH) {
+ const size_t count = pSH->GetCount();
+ const mkvparser::SeekHead::Entry* pEntry;
+ ALOGV("No Cues yet");
+
+ for (size_t index = 0; index < count; index++) {
+ pEntry = pSH->GetEntry(index);
+
+ if (pEntry->id == 0x0C53BB6B) { // Cues ID
+ long len; long long pos;
+ pSegment->ParseCues(pEntry->pos, pos, len);
+ pCues = pSegment->GetCues();
+ // Pull one cue point to fix loop below
+ ALOGV("Loading Cue points");
+ pCues->LoadCuePoint();
+ break;
+ }
+ }
+
+ if (!pCues) {
+ ALOGE("No Cues in file");
+ return;
+ }
+ }
+ else if (!pSH) {
+ ALOGE("No SeekHead");
+ return;
+ }
+
+ const mkvparser::CuePoint* pCP;
+ while (!pCues->DoneParsing()) {
+ // Make sure we don't have the necessary Cue already.
+ // If one Cue hadn't been loaded it would need to pre-emptively
+ // load one every time (until they are all loaded).
+ pCP = pCues->GetLast();
+ if (pCP->GetTime(pSegment) >= seekTimeNs) {
+ ALOGV("Located segment");
+ break;
+ }
+
+ pCues->LoadCuePoint();
+ }
+
+ // Find the video track for seeking. It doesn't make sense to search the
+ // audio track because we'd still want to make sure we're jumping to a
+ // keyframe in the video track.
+ 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 %d", index);
+ break;
+ }
+ }
+
+ const mkvparser::CuePoint::TrackPosition* pTP;
+ if (pTrack) {
+ pCues->Find(seekTimeNs, pTrack, pCP, pTP);
+ } else {
+ ALOGE("Did not locate a VIDEO_TRACK");
+ return;
+ }
+
+ mCluster = pSegment->FindOrPreloadCluster(pTP->m_pos);
+ if (pTP->m_block > 0) {
+ // m_block starts at 1, but mBlockEntryIndex is expected to start at 0
+ mBlockEntryIndex = pTP->m_block - 1;
+ } else {
+ ALOGE("m_block must be > 0");
+ return;
+ }
long prevKeyFrameBlockEntryIndex = -1;
@@ -593,16 +681,12 @@ MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
return;
}
- if (isLiveStreaming()) {
- ret = mSegment->ParseHeaders();
- CHECK_EQ(ret, 0);
+ ret = mSegment->ParseHeaders();
+ CHECK_EQ(ret, 0);
- long len;
- ret = mSegment->LoadCluster(pos, len);
- CHECK_EQ(ret, 0);
- } else {
- ret = mSegment->Load();
- }
+ long len;
+ ret = mSegment->LoadCluster(pos, len);
+ CHECK_EQ(ret, 0);
if (ret < 0) {
delete mSegment;