summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorLajos Molnar <lajos@google.com>2014-07-17 10:52:36 -0700
committerLajos Molnar <lajos@google.com>2014-07-22 11:55:19 -0700
commitc75fa318ee6a775c6201424e952561e6b9d695e2 (patch)
tree63c3dda569781e3a04dac92ef133dda6d7050f6c /media
parent2e25819fffbb23d42541ead1bf735f3a02fa0330 (diff)
downloadframeworks_av-c75fa318ee6a775c6201424e952561e6b9d695e2.zip
frameworks_av-c75fa318ee6a775c6201424e952561e6b9d695e2.tar.gz
frameworks_av-c75fa318ee6a775c6201424e952561e6b9d695e2.tar.bz2
stagefright: Fix seeking in MPEG4 container - do not merge
- seek based on user-visible timestamp - seek to previous, next and closest exactly - also update OggExtractor seek to same logic Bug: 12786906 Change-Id: I2d5e1fbff6469b6f081a284be2222a4cb50aa754
Diffstat (limited to 'media')
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp2
-rw-r--r--media/libstagefright/OggExtractor.cpp14
-rw-r--r--media/libstagefright/SampleTable.cpp191
-rw-r--r--media/libstagefright/include/SampleTable.h10
4 files changed, 97 insertions, 120 deletions
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 362cd6b..7d3a838 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -3284,7 +3284,7 @@ status_t MPEG4Source::read(
uint32_t sampleIndex;
status_t err = mSampleTable->findSampleAtTime(
- seekTimeUs * mTimescale / 1000000,
+ seekTimeUs, 1000000, mTimescale,
&sampleIndex, findFlags);
if (mode == ReadOptions::SEEK_CLOSEST) {
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index f3eeb03..1965ef9 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -320,22 +320,26 @@ status_t MyVorbisExtractor::seekToTime(int64_t timeUs) {
}
size_t left = 0;
- size_t right = mTableOfContents.size();
- while (left < right) {
- size_t center = left / 2 + right / 2 + (left & right & 1);
+ size_t right_plus_one = mTableOfContents.size();
+ while (left < right_plus_one) {
+ size_t center = left + (right_plus_one - left) / 2;
const TOCEntry &entry = mTableOfContents.itemAt(center);
if (timeUs < entry.mTimeUs) {
- right = center;
+ right_plus_one = center;
} else if (timeUs > entry.mTimeUs) {
left = center + 1;
} else {
- left = right = center;
+ left = center;
break;
}
}
+ if (left == mTableOfContents.size()) {
+ --left;
+ }
+
const TOCEntry &entry = mTableOfContents.itemAt(left);
ALOGV("seeking to entry %d / %d at offset %lld",
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index d9858d7..318555e 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -520,83 +520,72 @@ void SampleTable::buildSampleEntriesTable() {
}
status_t SampleTable::findSampleAtTime(
- uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
+ uint64_t req_time, uint64_t scale_num, uint64_t scale_den,
+ uint32_t *sample_index, uint32_t flags) {
buildSampleEntriesTable();
uint32_t left = 0;
- uint32_t right = mNumSampleSizes;
- while (left < right) {
- uint32_t center = (left + right) / 2;
- uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime;
+ uint32_t right_plus_one = mNumSampleSizes;
+ while (left < right_plus_one) {
+ uint32_t center = left + (right_plus_one - left) / 2;
+ uint64_t centerTime =
+ getSampleTime(center, scale_num, scale_den);
if (req_time < centerTime) {
- right = center;
+ right_plus_one = center;
} else if (req_time > centerTime) {
left = center + 1;
} else {
- left = center;
- break;
+ *sample_index = mSampleTimeEntries[center].mSampleIndex;
+ return OK;
}
}
- if (left == mNumSampleSizes) {
+ uint32_t closestIndex = left;
+
+ if (closestIndex == mNumSampleSizes) {
if (flags == kFlagAfter) {
return ERROR_OUT_OF_RANGE;
}
-
- --left;
+ flags = kFlagBefore;
+ } else if (closestIndex == 0) {
+ if (flags == kFlagBefore) {
+ // normally we should return out of range, but that is
+ // treated as end-of-stream. instead return first sample
+ //
+ // return ERROR_OUT_OF_RANGE;
+ }
+ flags = kFlagAfter;
}
- uint32_t closestIndex = left;
-
switch (flags) {
case kFlagBefore:
{
- while (closestIndex > 0
- && mSampleTimeEntries[closestIndex].mCompositionTime
- > req_time) {
- --closestIndex;
- }
+ --closestIndex;
break;
}
case kFlagAfter:
{
- while (closestIndex + 1 < mNumSampleSizes
- && mSampleTimeEntries[closestIndex].mCompositionTime
- < req_time) {
- ++closestIndex;
- }
+ // nothing to do
break;
}
default:
{
CHECK(flags == kFlagClosest);
-
- if (closestIndex > 0) {
- // Check left neighbour and pick closest.
- uint32_t absdiff1 =
- abs_difference(
- mSampleTimeEntries[closestIndex].mCompositionTime,
- req_time);
-
- uint32_t absdiff2 =
- abs_difference(
- mSampleTimeEntries[closestIndex - 1].mCompositionTime,
- req_time);
-
- if (absdiff1 > absdiff2) {
- closestIndex = closestIndex - 1;
- }
+ // pick closest based on timestamp. use abs_difference for safety
+ if (abs_difference(
+ getSampleTime(closestIndex, scale_num, scale_den), req_time) >
+ abs_difference(
+ req_time, getSampleTime(closestIndex - 1, scale_num, scale_den))) {
+ --closestIndex;
}
-
break;
}
}
*sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
-
return OK;
}
@@ -618,109 +607,85 @@ status_t SampleTable::findSyncSampleNear(
}
uint32_t left = 0;
- uint32_t right = mNumSyncSamples;
- while (left < right) {
- uint32_t center = left + (right - left) / 2;
+ uint32_t right_plus_one = mNumSyncSamples;
+ while (left < right_plus_one) {
+ uint32_t center = left + (right_plus_one - left) / 2;
uint32_t x = mSyncSamples[center];
if (start_sample_index < x) {
- right = center;
+ right_plus_one = center;
} else if (start_sample_index > x) {
left = center + 1;
} else {
- left = center;
- break;
+ *sample_index = x;
+ return OK;
}
}
+
if (left == mNumSyncSamples) {
if (flags == kFlagAfter) {
ALOGE("tried to find a sync frame after the last one: %d", left);
return ERROR_OUT_OF_RANGE;
}
- left = left - 1;
+ flags = kFlagBefore;
}
+ else if (left == 0) {
+ if (flags == kFlagBefore) {
+ ALOGE("tried to find a sync frame before the first one: %d", left);
- // Now ssi[left] is the sync sample index just before (or at)
- // start_sample_index.
- // Also start_sample_index < ssi[left + 1], if left + 1 < mNumSyncSamples.
-
- uint32_t x = mSyncSamples[left];
-
- if (left + 1 < mNumSyncSamples) {
- uint32_t y = mSyncSamples[left + 1];
-
- // our sample lies between sync samples x and y.
-
- status_t err = mSampleIterator->seekTo(start_sample_index);
- if (err != OK) {
- return err;
- }
-
- uint32_t sample_time = mSampleIterator->getSampleTime();
-
- err = mSampleIterator->seekTo(x);
- if (err != OK) {
- return err;
- }
- uint32_t x_time = mSampleIterator->getSampleTime();
-
- err = mSampleIterator->seekTo(y);
- if (err != OK) {
- return err;
- }
-
- uint32_t y_time = mSampleIterator->getSampleTime();
-
- if (abs_difference(x_time, sample_time)
- > abs_difference(y_time, sample_time)) {
- // Pick the sync sample closest (timewise) to the start-sample.
- x = y;
- ++left;
+ // normally we should return out of range, but that is
+ // treated as end-of-stream. instead seek to first sync
+ //
+ // return ERROR_OUT_OF_RANGE;
}
+ flags = kFlagAfter;
}
+ // Now ssi[left - 1] <(=) start_sample_index <= ssi[left]
switch (flags) {
case kFlagBefore:
{
- if (x > start_sample_index) {
- CHECK(left > 0);
-
- x = mSyncSamples[left - 1];
-
- if (x > start_sample_index) {
- // The table of sync sample indices was not sorted
- // properly.
- return ERROR_MALFORMED;
- }
- }
+ --left;
break;
}
-
case kFlagAfter:
{
- if (x < start_sample_index) {
- if (left + 1 >= mNumSyncSamples) {
- return ERROR_OUT_OF_RANGE;
- }
-
- x = mSyncSamples[left + 1];
-
- if (x < start_sample_index) {
- // The table of sync sample indices was not sorted
- // properly.
- return ERROR_MALFORMED;
- }
- }
-
+ // nothing to do
break;
}
-
default:
+ {
+ // this route is not used, but implement it nonetheless
+ CHECK(flags == kFlagClosest);
+
+ status_t err = mSampleIterator->seekTo(start_sample_index);
+ if (err != OK) {
+ return err;
+ }
+ uint32_t sample_time = mSampleIterator->getSampleTime();
+
+ err = mSampleIterator->seekTo(mSyncSamples[left]);
+ if (err != OK) {
+ return err;
+ }
+ uint32_t upper_time = mSampleIterator->getSampleTime();
+
+ err = mSampleIterator->seekTo(mSyncSamples[left - 1]);
+ if (err != OK) {
+ return err;
+ }
+ uint32_t lower_time = mSampleIterator->getSampleTime();
+
+ // use abs_difference for safety
+ if (abs_difference(upper_time, sample_time) >
+ abs_difference(sample_time, lower_time)) {
+ --left;
+ }
break;
+ }
}
- *sample_index = x;
-
+ *sample_index = mSyncSamples[left];
return OK;
}
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 847dff7..ed91adc 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -74,7 +74,8 @@ public:
kFlagClosest
};
status_t findSampleAtTime(
- uint32_t req_time, uint32_t *sample_index, uint32_t flags);
+ uint64_t req_time, uint64_t scale_num, uint64_t scale_den,
+ uint32_t *sample_index, uint32_t flags);
status_t findSyncSampleNear(
uint32_t start_sample_index, uint32_t *sample_index,
@@ -137,6 +138,13 @@ private:
friend struct SampleIterator;
+ // normally we don't round
+ inline uint64_t getSampleTime(
+ size_t sample_index, uint64_t scale_num, uint64_t scale_den) const {
+ return (mSampleTimeEntries[sample_index].mCompositionTime
+ * scale_num) / scale_den;
+ }
+
status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size);
uint32_t getCompositionTimeOffset(uint32_t sampleIndex);