Handle mkv file without cue point

Some mkv or mka files don't have any cue point, especially mka file
which is transformed from ffmpeg. When user plays such mkv or mka file,
user cannot seek to correct position.

To handle this issue, we ignore cues and load clusters. When we seek
and find that it has no cue point, we call seekwithoutcue function,
which will find correct position from loaded clusters.

Bug: 123150866
Test: Test with a mkv or mka file without CUES and check if we can
can seek to correct position and play normally.

Change-Id: I77cb64ebee6261545ab3eff6a38538d854408b47
gugelfrei
Iris Chang 6 years ago committed by Marco Nelissen
parent bb08e4d99b
commit 2641ec2a91

@ -119,6 +119,9 @@ private:
const mkvparser::BlockEntry *mBlockEntry;
long mBlockEntryIndex;
unsigned long mTrackType;
void seekwithoutcue_l(int64_t seekTimeUs, int64_t *actualFrameTimeUs);
void advance_l();
BlockIterator(const BlockIterator &);
@ -290,6 +293,7 @@ BlockIterator::BlockIterator(
mCluster(NULL),
mBlockEntry(NULL),
mBlockEntryIndex(0) {
mTrackType = mExtractor->mSegment->GetTracks()->GetTrackByNumber(trackNum)->GetType();
reset();
}
@ -442,12 +446,14 @@ void BlockIterator::seek(
}
if (!pCues) {
ALOGE("No Cues in file");
ALOGV("No Cues in file,seek without cue data");
seekwithoutcue_l(seekTimeUs, actualFrameTimeUs);
return;
}
}
else if (!pSH) {
ALOGE("No SeekHead");
ALOGV("No SeekHead, seek without cue data");
seekwithoutcue_l(seekTimeUs, actualFrameTimeUs);
return;
}
@ -456,7 +462,9 @@ void BlockIterator::seek(
while (!pCues->DoneParsing()) {
pCues->LoadCuePoint();
pCP = pCues->GetLast();
CHECK(pCP);
ALOGV("pCP = %s", pCP == NULL ? "NULL" : "not NULL");
if (pCP == NULL)
continue;
size_t trackCount = mExtractor->mTracks.size();
for (size_t index = 0; index < trackCount; ++index) {
@ -494,6 +502,7 @@ void BlockIterator::seek(
// Always *search* based on the video track, but finalize based on mTrackNum
if (!pTP) {
ALOGE("Did not locate the video track for seeking");
seekwithoutcue_l(seekTimeUs, actualFrameTimeUs);
return;
}
@ -537,6 +546,31 @@ int64_t BlockIterator::blockTimeUs() const {
return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
}
void BlockIterator::seekwithoutcue_l(int64_t seekTimeUs, int64_t *actualFrameTimeUs) {
mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
const long status = mCluster->GetFirst(mBlockEntry);
if (status < 0) { // error
ALOGE("get last blockenry failed!");
mCluster = NULL;
return;
}
mBlockEntryIndex = 0;
while (!eos() && ((block()->GetTrackNumber() != mTrackNum) || (blockTimeUs() < seekTimeUs))) {
advance_l();
}
// video track will seek to the next key frame.
if (mTrackType == 1) {
while (!eos() && ((block()->GetTrackNumber() != mTrackNum) ||
!mBlockEntry->GetBlock()->IsKey())) {
advance_l();
}
}
*actualFrameTimeUs = blockTimeUs();
ALOGV("seekTimeUs:%lld, actualFrameTimeUs:%lld, tracknum:%lld",
(long long)seekTimeUs, (long long)*actualFrameTimeUs, (long long)mTrackNum);
}
////////////////////////////////////////////////////////////////////////////////
static unsigned U24_AT(const uint8_t *ptr) {
@ -956,17 +990,56 @@ MatroskaExtractor::MatroskaExtractor(DataSourceHelper *source)
return;
}
// from mkvparser::Segment::Load(), but stop at first cluster
ret = mSegment->ParseHeaders();
if (ret == 0) {
long len;
ret = mSegment->LoadCluster(pos, len);
if (ret >= 1) {
// no more clusters
ret = 0;
if (mIsLiveStreaming) {
// from mkvparser::Segment::Load(), but stop at first cluster
ret = mSegment->ParseHeaders();
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;
}
} else {
ret = mSegment->ParseHeaders();
if (ret < 0) {
ALOGE("Segment parse header return fail %lld", ret);
delete mSegment;
mSegment = NULL;
return;
} else if (ret == 0) {
const mkvparser::Cues* mCues = mSegment->GetCues();
const mkvparser::SeekHead* mSH = mSegment->GetSeekHead();
if ((mCues == NULL) && (mSH != NULL)) {
size_t count = mSH->GetCount();
const mkvparser::SeekHead::Entry* mEntry;
for (size_t index = 0; index < count; index++) {
mEntry = mSH->GetEntry(index);
if (mEntry->id == 0x0C53BB6B) { // Cues ID
long len;
long long pos;
mSegment->ParseCues(mEntry->pos, pos, len);
mCues = mSegment->GetCues();
ALOGV("find cue data by seekhead");
break;
}
}
}
if (mCues) {
long len;
ret = mSegment->LoadCluster(pos, len);
ALOGV("has Cue data, Cluster num=%ld", mSegment->GetCount());
} else {
long status_Load = mSegment->Load();
ALOGW("no Cue data,Segment Load status:%ld",status_Load);
}
} else if (ret > 0) {
ret = mkvparser::E_BUFFER_NOT_FULL;
}
} else if (ret > 0) {
ret = mkvparser::E_BUFFER_NOT_FULL;
}
if (ret < 0) {

Loading…
Cancel
Save