Merge "Support finer seek control on MediaSources." into gingerbread

This commit is contained in:
Andreas Huber
2010-07-21 10:36:08 -07:00
committed by Android (Google) Code Review
31 changed files with 459 additions and 67 deletions

View File

@@ -62,14 +62,21 @@ struct MediaSource : public RefBase {
// a) not request a seek
// b) not be late, i.e. lateness_us = 0
struct ReadOptions {
enum SeekMode {
SEEK_PREVIOUS_SYNC,
SEEK_NEXT_SYNC,
SEEK_CLOSEST_SYNC,
SEEK_CLOSEST,
};
ReadOptions();
// Reset everything back to defaults.
void reset();
void setSeekTo(int64_t time_us);
void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
void clearSeekTo();
bool getSeekTo(int64_t *time_us) const;
bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
void setLateBy(int64_t lateness_us);
int64_t getLateBy() const;
@@ -81,6 +88,7 @@ struct MediaSource : public RefBase {
uint32_t mOptions;
int64_t mSeekTimeUs;
SeekMode mSeekMode;
int64_t mLatenessUs;
};

View File

@@ -46,6 +46,7 @@ enum {
kKeyIsSyncFrame = 'sync', // int32_t (bool)
kKeyIsCodecConfig = 'conf', // int32_t (bool)
kKeyTime = 'time', // int64_t (usecs)
kKeyTargetTime = 'tarT', // int64_t (usecs)
kKeyDuration = 'dura', // int64_t (usecs)
kKeyColorFormat = 'colf',
kKeyPlatformPrivate = 'priv', // pointer

View File

@@ -141,6 +141,8 @@ private:
bool mNoMoreOutputData;
bool mOutputPortSettingsHaveChanged;
int64_t mSeekTimeUs;
ReadOptions::SeekMode mSeekMode;
int64_t mTargetTimeUs;
MediaBuffer *mLeftOverBuffer;

View File

@@ -212,7 +212,8 @@ status_t AMRSource::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
int64_t seekFrame = seekTimeUs / 20000ll; // 20ms per frame.
mCurrentTimeUs = seekFrame * 20000ll;
mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6);

View File

@@ -914,7 +914,8 @@ void AwesomePlayer::onVideoEvent() {
if (mSeeking) {
LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
options.setSeekTo(mSeekTimeUs);
options.setSeekTo(
mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
}
for (;;) {
status_t err = mVideoSource->read(&mVideoBuffer, &options);

View File

@@ -267,7 +267,8 @@ status_t CameraSource::read(
*buffer = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
return ERROR_UNSUPPORTED;
}

View File

@@ -112,7 +112,8 @@ status_t JPEGSource::read(
*out = NULL;
int64_t seekTimeUs;
if (options != NULL && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
return UNKNOWN_ERROR;
}

View File

@@ -586,7 +586,8 @@ status_t MP3Source::read(
*out = NULL;
int64_t seekTimeUs;
if (options != NULL && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
int32_t bitrate;
if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
// bitrate is in bits/sec.

View File

@@ -1468,12 +1468,45 @@ status_t MPEG4Source::read(
*out = NULL;
int64_t targetSampleTimeUs = -1;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
uint32_t findFlags = 0;
switch (mode) {
case ReadOptions::SEEK_PREVIOUS_SYNC:
findFlags = SampleTable::kFlagBefore;
break;
case ReadOptions::SEEK_NEXT_SYNC:
findFlags = SampleTable::kFlagAfter;
break;
case ReadOptions::SEEK_CLOSEST_SYNC:
case ReadOptions::SEEK_CLOSEST:
findFlags = SampleTable::kFlagClosest;
break;
default:
CHECK(!"Should not be here.");
break;
}
uint32_t sampleIndex;
status_t err = mSampleTable->findClosestSample(
status_t err = mSampleTable->findSampleAtTime(
seekTimeUs * mTimescale / 1000000,
&sampleIndex, SampleTable::kSyncSample_Flag);
&sampleIndex, findFlags);
if (mode == ReadOptions::SEEK_CLOSEST) {
// We found the closest sample already, now we want the sync
// sample preceding it (or the sample itself of course), even
// if the subsequent sync sample is closer.
findFlags = SampleTable::kFlagBefore;
}
uint32_t syncSampleIndex;
if (err == OK) {
err = mSampleTable->findSyncSampleNear(
sampleIndex, &syncSampleIndex, findFlags);
}
if (err != OK) {
if (err == ERROR_OUT_OF_RANGE) {
@@ -1487,7 +1520,27 @@ status_t MPEG4Source::read(
return err;
}
mCurrentSampleIndex = sampleIndex;
uint32_t sampleTime;
CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
sampleIndex, NULL, NULL, &sampleTime));
if (mode == ReadOptions::SEEK_CLOSEST) {
targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
}
#if 0
uint32_t syncSampleTime;
CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
syncSampleIndex, NULL, NULL, &syncSampleTime));
LOGI("seek to time %lld us => sample at time %lld us, "
"sync sample at time %lld us",
seekTimeUs,
sampleTime * 1000000ll / mTimescale,
syncSampleTime * 1000000ll / mTimescale);
#endif
mCurrentSampleIndex = syncSampleIndex;
if (mBuffer != NULL) {
mBuffer->release();
mBuffer = NULL;
@@ -1536,6 +1589,12 @@ status_t MPEG4Source::read(
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt64(
kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
mBuffer->meta_data()->setInt64(
kKeyTargetTime, targetSampleTimeUs);
}
++mCurrentSampleIndex;
}
@@ -1632,6 +1691,12 @@ status_t MPEG4Source::read(
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt64(
kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
mBuffer->meta_data()->setInt64(
kKeyTargetTime, targetSampleTimeUs);
}
++mCurrentSampleIndex;
*out = mBuffer;

View File

@@ -34,18 +34,22 @@ void MediaSource::ReadOptions::reset() {
mLatenessUs = 0;
}
void MediaSource::ReadOptions::setSeekTo(int64_t time_us) {
void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
mOptions |= kSeekTo_Option;
mSeekTimeUs = time_us;
mSeekMode = mode;
}
void MediaSource::ReadOptions::clearSeekTo() {
mOptions &= ~kSeekTo_Option;
mSeekTimeUs = 0;
mSeekMode = SEEK_CLOSEST_SYNC;
}
bool MediaSource::ReadOptions::getSeekTo(int64_t *time_us) const {
bool MediaSource::ReadOptions::getSeekTo(
int64_t *time_us, SeekMode *mode) const {
*time_us = mSeekTimeUs;
*mode = mSeekMode;
return (mOptions & kSeekTo_Option) != 0;
}

View File

@@ -1272,6 +1272,8 @@ OMXCodec::OMXCodec(
mNoMoreOutputData(false),
mOutputPortSettingsHaveChanged(false),
mSeekTimeUs(-1),
mSeekMode(ReadOptions::SEEK_CLOSEST_SYNC),
mTargetTimeUs(-1),
mLeftOverBuffer(NULL),
mPaused(false) {
mPortStatus[kPortIndexInput] = ENABLED;
@@ -1640,13 +1642,33 @@ void OMXCodec::on_message(const omx_message &msg) {
kKeyBufferID,
msg.u.extended_buffer_data.buffer);
mFilledBuffers.push_back(i);
mBufferFilled.signal();
if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_EOS) {
CODEC_LOGV("No more output data.");
mNoMoreOutputData = true;
}
if (mTargetTimeUs >= 0) {
CHECK(msg.u.extended_buffer_data.timestamp <= mTargetTimeUs);
if (msg.u.extended_buffer_data.timestamp < mTargetTimeUs) {
CODEC_LOGV(
"skipping output buffer at timestamp %lld us",
msg.u.extended_buffer_data.timestamp);
fillOutputBuffer(info);
break;
}
CODEC_LOGV(
"returning output buffer at target timestamp "
"%lld us",
msg.u.extended_buffer_data.timestamp);
mTargetTimeUs = -1;
}
mFilledBuffers.push_back(i);
mBufferFilled.signal();
}
break;
@@ -2185,12 +2207,24 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
}
MediaSource::ReadOptions options;
options.setSeekTo(mSeekTimeUs);
options.setSeekTo(mSeekTimeUs, mSeekMode);
mSeekTimeUs = -1;
mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;
mBufferFilled.signal();
err = mSource->read(&srcBuffer, &options);
if (err == OK) {
int64_t targetTimeUs;
if (srcBuffer->meta_data()->findInt64(
kKeyTargetTime, &targetTimeUs)
&& targetTimeUs >= 0) {
mTargetTimeUs = targetTimeUs;
} else {
mTargetTimeUs = -1;
}
}
} else if (mLeftOverBuffer) {
srcBuffer = mLeftOverBuffer;
mLeftOverBuffer = NULL;
@@ -2239,7 +2273,7 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
int64_t lastBufferTimeUs;
CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs));
CHECK(timestampUs >= 0);
CHECK(lastBufferTimeUs >= 0);
if (offset == 0) {
timestampUs = lastBufferTimeUs;
@@ -2696,6 +2730,8 @@ status_t OMXCodec::start(MetaData *meta) {
mNoMoreOutputData = false;
mOutputPortSettingsHaveChanged = false;
mSeekTimeUs = -1;
mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;
mTargetTimeUs = -1;
mFilledBuffers.clear();
mPaused = false;
@@ -2790,7 +2826,8 @@ status_t OMXCodec::read(
bool seeking = false;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode seekMode;
if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
seeking = true;
}
@@ -2800,6 +2837,7 @@ status_t OMXCodec::read(
if (seeking) {
CHECK(seekTimeUs >= 0);
mSeekTimeUs = seekTimeUs;
mSeekMode = seekMode;
// There's no reason to trigger the code below, there's
// nothing to flush yet.
@@ -2823,6 +2861,7 @@ status_t OMXCodec::read(
CHECK(seekTimeUs >= 0);
mSeekTimeUs = seekTimeUs;
mSeekMode = seekMode;
mFilledBuffers.clear();

View File

@@ -155,7 +155,8 @@ status_t OggSource::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
off_t pos = seekTimeUs * mExtractor->mImpl->approxBitrate() / 8000000ll;
LOGI("seeking to offset %ld", pos);

View File

@@ -314,8 +314,10 @@ uint32_t abs_difference(uint32_t time1, uint32_t time2) {
return time1 > time2 ? time1 - time2 : time2 - time1;
}
status_t SampleTable::findClosestSample(
status_t SampleTable::findSampleAtTime(
uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
*sample_index = 0;
Mutex::Autolock autoLock(mLock);
uint32_t cur_sample = 0;
@@ -330,16 +332,37 @@ status_t SampleTable::findClosestSample(
uint32_t time1 = time + j * delta;
uint32_t time2 = time1 + delta;
uint32_t sampleTime;
if (i+1 == mTimeToSampleCount
|| (abs_difference(req_time, time1)
< abs_difference(req_time, time2))) {
*sample_index = cur_sample + j;
sampleTime = time1;
} else {
*sample_index = cur_sample + j + 1;
sampleTime = time2;
}
if (flags & kSyncSample_Flag) {
return findClosestSyncSample_l(*sample_index, sample_index);
switch (flags) {
case kFlagBefore:
{
if (sampleTime > req_time && *sample_index > 0) {
--*sample_index;
}
break;
}
case kFlagAfter:
{
if (sampleTime < req_time
&& *sample_index + 1 < mNumSampleSizes) {
++*sample_index;
}
break;
}
default:
break;
}
return OK;
@@ -352,8 +375,10 @@ status_t SampleTable::findClosestSample(
return ERROR_OUT_OF_RANGE;
}
status_t SampleTable::findClosestSyncSample_l(
uint32_t start_sample_index, uint32_t *sample_index) {
status_t SampleTable::findSyncSampleNear(
uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
Mutex::Autolock autoLock(mLock);
*sample_index = 0;
if (mSyncSampleOffset < 0) {
@@ -362,29 +387,124 @@ status_t SampleTable::findClosestSyncSample_l(
return OK;
}
uint32_t x;
uint32_t left = 0;
uint32_t right = mNumSyncSamples;
while (left < right) {
uint32_t mid = (left + right) / 2;
if (mNumSyncSamples == 0) {
*sample_index = 0;
return OK;
}
uint32_t left = 0;
while (left < mNumSyncSamples) {
uint32_t x;
if (mDataSource->readAt(
mSyncSampleOffset + 8 + mid * 4, &x, 4) != 4) {
mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) {
return ERROR_IO;
}
x = ntohl(x);
--x;
if (x < (start_sample_index + 1)) {
left = mid + 1;
} else if (x > (start_sample_index + 1)) {
right = mid;
} else {
if (x >= start_sample_index) {
break;
}
++left;
}
--left;
uint32_t x;
if (mDataSource->readAt(
mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) {
return ERROR_IO;
}
x = ntohl(x);
--x;
if (left + 1 < mNumSyncSamples) {
uint32_t y;
if (mDataSource->readAt(
mSyncSampleOffset + 8 + (left + 1) * 4, &y, 4) != 4) {
return ERROR_IO;
}
y = ntohl(y);
--y;
// 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;
}
}
*sample_index = x - 1;
switch (flags) {
case kFlagBefore:
{
if (x > start_sample_index) {
CHECK(left > 0);
if (mDataSource->readAt(
mSyncSampleOffset + 8 + (left - 1) * 4, &x, 4) != 4) {
return ERROR_IO;
}
x = ntohl(x);
--x;
CHECK(x <= start_sample_index);
}
break;
}
case kFlagAfter:
{
if (x < start_sample_index) {
if (left + 1 >= mNumSyncSamples) {
return ERROR_OUT_OF_RANGE;
}
if (mDataSource->readAt(
mSyncSampleOffset + 8 + (left + 1) * 4, &x, 4) != 4) {
return ERROR_IO;
}
x = ntohl(x);
--x;
CHECK(x >= start_sample_index);
}
break;
}
default:
break;
}
*sample_index = x;
return OK;
}

View File

@@ -93,7 +93,8 @@ status_t ShoutcastSource::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
return ERROR_UNSUPPORTED;
}

View File

@@ -282,7 +282,8 @@ status_t WAVSource::read(
*out = NULL;
int64_t seekTimeUs;
if (options != NULL && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
int64_t pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * 2;
if (pos > mSize) {
pos = mSize;

View File

@@ -159,7 +159,8 @@ status_t AACDecoder::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
CHECK(seekTimeUs >= 0);
mNumSamplesOutput = 0;

View File

@@ -202,7 +202,8 @@ status_t AACEncoder::read(
*out = NULL;
int64_t seekTimeUs;
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs));
ReadOptions::SeekMode mode;
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
MediaBuffer *buffer;
CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);

View File

@@ -117,7 +117,8 @@ status_t AMRNBDecoder::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
CHECK(seekTimeUs >= 0);
mNumSamplesOutput = 0;

View File

@@ -145,7 +145,8 @@ status_t AMRNBEncoder::read(
*out = NULL;
int64_t seekTimeUs;
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs));
ReadOptions::SeekMode mode;
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
while (mNumInputSamples < kNumSamplesPerFrame) {
if (mInputBuffer == NULL) {

View File

@@ -135,7 +135,8 @@ status_t AMRWBDecoder::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode seekMode;
if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
CHECK(seekTimeUs >= 0);
mNumSamplesOutput = 0;

View File

@@ -196,7 +196,8 @@ status_t AMRWBEncoder::read(
*out = NULL;
int64_t seekTimeUs;
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs));
ReadOptions::SeekMode mode;
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
while (mNumInputSamples < kNumSamplesPerFrame) {
if (mInputBuffer == NULL) {

View File

@@ -51,7 +51,9 @@ AVCDecoder::AVCDecoder(const sp<MediaSource> &source)
mInputBuffer(NULL),
mAnchorTimeUs(0),
mNumSamplesOutput(0),
mPendingSeekTimeUs(-1) {
mPendingSeekTimeUs(-1),
mPendingSeekMode(MediaSource::ReadOptions::SEEK_CLOSEST_SYNC),
mTargetTimeUs(-1) {
memset(mHandle, 0, sizeof(tagAVCHandle));
mHandle->AVCObject = NULL;
mHandle->userData = this;
@@ -161,6 +163,8 @@ status_t AVCDecoder::start(MetaData *) {
mAnchorTimeUs = 0;
mNumSamplesOutput = 0;
mPendingSeekTimeUs = -1;
mPendingSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;
mTargetTimeUs = -1;
mStarted = true;
return OK;
@@ -229,11 +233,13 @@ status_t AVCDecoder::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
LOGV("seek requested to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
CHECK(seekTimeUs >= 0);
mPendingSeekTimeUs = seekTimeUs;
mPendingSeekMode = mode;
if (mInputBuffer) {
mInputBuffer->release();
@@ -246,6 +252,8 @@ status_t AVCDecoder::read(
if (mInputBuffer == NULL) {
LOGV("fetching new input buffer.");
bool seeking = false;
if (!mCodecSpecificData.isEmpty()) {
mInputBuffer = mCodecSpecificData.editItemAt(0);
mCodecSpecificData.removeAt(0);
@@ -258,7 +266,9 @@ status_t AVCDecoder::read(
ReadOptions seekOptions;
if (mPendingSeekTimeUs >= 0) {
seekOptions.setSeekTo(mPendingSeekTimeUs);
seeking = true;
seekOptions.setSeekTo(mPendingSeekTimeUs, mPendingSeekMode);
mPendingSeekTimeUs = -1;
}
status_t err = mSource->read(&mInputBuffer, &seekOptions);
@@ -276,6 +286,16 @@ status_t AVCDecoder::read(
mInputBuffer = NULL;
}
}
if (seeking) {
int64_t targetTimeUs;
if (mInputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs)
&& targetTimeUs >= 0) {
mTargetTimeUs = targetTimeUs;
} else {
mTargetTimeUs = -1;
}
}
}
const uint8_t *fragPtr;
@@ -394,9 +414,35 @@ status_t AVCDecoder::read(
CHECK(index >= 0);
CHECK(index < (int32_t)mFrames.size());
*out = mFrames.editItemAt(index);
(*out)->set_range(0, (*out)->size());
(*out)->add_ref();
MediaBuffer *mbuf = mFrames.editItemAt(index);
bool skipFrame = false;
if (mTargetTimeUs >= 0) {
int64_t timeUs;
CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
CHECK(timeUs <= mTargetTimeUs);
if (timeUs < mTargetTimeUs) {
// We're still waiting for the frame with the matching
// timestamp and we won't return the current one.
skipFrame = true;
LOGV("skipping frame at %lld us", timeUs);
} else {
LOGV("found target frame at %lld us", timeUs);
mTargetTimeUs = -1;
}
}
if (!skipFrame) {
*out = mbuf;
(*out)->set_range(0, (*out)->size());
(*out)->add_ref();
} else {
*out = new MediaBuffer(0);
}
// Do _not_ release input buffer yet.

View File

@@ -37,7 +37,8 @@ M4vH263Decoder::M4vH263Decoder(const sp<MediaSource> &source)
mStarted(false),
mHandle(new tagvideoDecControls),
mInputBuffer(NULL),
mNumSamplesOutput(0) {
mNumSamplesOutput(0),
mTargetTimeUs(-1) {
LOGV("M4vH263Decoder");
memset(mHandle, 0, sizeof(tagvideoDecControls));
@@ -146,6 +147,7 @@ status_t M4vH263Decoder::start(MetaData *) {
mSource->start();
mNumSamplesOutput = 0;
mTargetTimeUs = -1;
mStarted = true;
return OK;
@@ -175,8 +177,11 @@ status_t M4vH263Decoder::read(
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
bool seeking = false;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
seeking = true;
CHECK_EQ(PVResetVideoDecoder(mHandle), PV_TRUE);
}
@@ -186,6 +191,16 @@ status_t M4vH263Decoder::read(
return err;
}
if (seeking) {
int64_t targetTimeUs;
if (inputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs)
&& targetTimeUs >= 0) {
mTargetTimeUs = targetTimeUs;
} else {
mTargetTimeUs = -1;
}
}
uint8_t *bitstream =
(uint8_t *) inputBuffer->data() + inputBuffer->range_offset();
@@ -221,17 +236,40 @@ status_t M4vH263Decoder::read(
return INFO_FORMAT_CHANGED;
}
*out = mFrames[mNumSamplesOutput & 0x01];
(*out)->add_ref();
int64_t timeUs;
CHECK(inputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
(*out)->meta_data()->setInt64(kKeyTime, timeUs);
++mNumSamplesOutput;
inputBuffer->release();
inputBuffer = NULL;
bool skipFrame = false;
if (mTargetTimeUs >= 0) {
CHECK(timeUs <= mTargetTimeUs);
if (timeUs < mTargetTimeUs) {
// We're still waiting for the frame with the matching
// timestamp and we won't return the current one.
skipFrame = true;
LOGV("skipping frame at %lld us", timeUs);
} else {
LOGV("found target frame at %lld us", timeUs);
mTargetTimeUs = -1;
}
}
if (skipFrame) {
*out = new MediaBuffer(0);
} else {
*out = mFrames[mNumSamplesOutput & 0x01];
(*out)->add_ref();
(*out)->meta_data()->setInt64(kKeyTime, timeUs);
}
++mNumSamplesOutput;
return OK;
}

View File

@@ -122,7 +122,8 @@ status_t MP3Decoder::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
CHECK(seekTimeUs >= 0);
mNumFramesOutput = 0;

View File

@@ -39,7 +39,8 @@ VPXDecoder::VPXDecoder(const sp<MediaSource> &source)
mStarted(false),
mBufferSize(0),
mCtx(NULL),
mBufferGroup(NULL) {
mBufferGroup(NULL),
mTargetTimeUs(-1) {
sp<MetaData> inputFormat = source->getFormat();
const char *mime;
CHECK(inputFormat->findCString(kKeyMIMEType, &mime));
@@ -94,6 +95,8 @@ status_t VPXDecoder::start(MetaData *) {
mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
mTargetTimeUs = -1;
mStarted = true;
return OK;
@@ -126,6 +129,13 @@ status_t VPXDecoder::read(
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
bool seeking = false;
int64_t seekTimeUs;
ReadOptions::SeekMode seekMode;
if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
seeking = true;
}
MediaBuffer *input;
status_t err = mSource->read(&input, options);
@@ -135,6 +145,16 @@ status_t VPXDecoder::read(
LOGV("read %d bytes from source\n", input->range_length());
if (seeking) {
int64_t targetTimeUs;
if (input->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs)
&& targetTimeUs >= 0) {
mTargetTimeUs = targetTimeUs;
} else {
mTargetTimeUs = -1;
}
}
if (vpx_codec_decode(
(vpx_codec_ctx_t *)mCtx,
(uint8_t *)input->data() + input->range_offset(),
@@ -156,6 +176,29 @@ status_t VPXDecoder::read(
input->release();
input = NULL;
bool skipFrame = false;
if (mTargetTimeUs >= 0) {
CHECK(timeUs <= mTargetTimeUs);
if (timeUs < mTargetTimeUs) {
// We're still waiting for the frame with the matching
// timestamp and we won't return the current one.
skipFrame = true;
LOGV("skipping frame at %lld us", timeUs);
} else {
LOGV("found target frame at %lld us", timeUs);
mTargetTimeUs = -1;
}
}
if (skipFrame) {
*out = new MediaBuffer(0);
return OK;
}
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);

View File

@@ -200,7 +200,8 @@ status_t VorbisDecoder::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
CHECK(seekTimeUs >= 0);
mNumFramesOutput = 0;

View File

@@ -58,6 +58,9 @@ private:
int64_t mAnchorTimeUs;
int64_t mNumSamplesOutput;
int64_t mPendingSeekTimeUs;
MediaSource::ReadOptions::SeekMode mPendingSeekMode;
int64_t mTargetTimeUs;
void addCodecSpecificData(const uint8_t *data, size_t size);

View File

@@ -54,6 +54,7 @@ private:
MediaBuffer *mInputBuffer;
int64_t mNumSamplesOutput;
int64_t mTargetTimeUs;
void allocateFrames(int32_t width, int32_t height);
void releaseFrames();

View File

@@ -63,11 +63,17 @@ public:
uint32_t *decodingTime);
enum {
kSyncSample_Flag = 1
kFlagBefore,
kFlagAfter,
kFlagClosest
};
status_t findClosestSample(
status_t findSampleAtTime(
uint32_t req_time, uint32_t *sample_index, uint32_t flags);
status_t findSyncSampleNear(
uint32_t start_sample_index, uint32_t *sample_index,
uint32_t flags);
status_t findThumbnailSample(uint32_t *sample_index);
protected:
@@ -111,9 +117,6 @@ private:
friend struct SampleIterator;
status_t findClosestSyncSample_l(
uint32_t start_sample_index, uint32_t *sample_index);
status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size);
SampleTable(const SampleTable &);

View File

@@ -48,6 +48,8 @@ private:
void *mCtx;
MediaBufferGroup *mBufferGroup;
int64_t mTargetTimeUs;
sp<MetaData> mFormat;
VPXDecoder(const VPXDecoder &);

View File

@@ -281,7 +281,8 @@ status_t MatroskaSource::read(
*out = NULL;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
mBlockIter.seek(seekTimeUs);
}