diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/matroska/MatroskaExtractor.cpp | 110 |
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; |