Extract video thumbnails from the largest sync sample among the first 20.

Also fixes OMXCodec seek behaviour on the very first call to OMXCodec::read()
This commit is contained in:
Andreas Huber
2009-10-22 13:49:30 -07:00
parent d278ffc098
commit e981c33446
12 changed files with 111 additions and 10 deletions

View File

@@ -30,7 +30,7 @@ public:
virtual size_t countTracks();
virtual sp<MediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
static sp<MetaData> makeAMRFormat(bool isWide);

View File

@@ -32,7 +32,7 @@ public:
virtual size_t countTracks();
virtual sp<MediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
protected:
virtual ~MP3Extractor();

View File

@@ -33,7 +33,7 @@ public:
size_t countTracks();
sp<MediaSource> getTrack(size_t index);
sp<MetaData> getTrackMetaData(size_t index);
sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
protected:
virtual ~MPEG4Extractor();
@@ -44,6 +44,7 @@ private:
sp<MetaData> meta;
uint32_t timescale;
sp<SampleTable> sampleTable;
bool includes_expensive_metadata;
};
sp<DataSource> mDataSource;

View File

@@ -33,7 +33,12 @@ public:
virtual size_t countTracks() = 0;
virtual sp<MediaSource> getTrack(size_t index) = 0;
virtual sp<MetaData> getTrackMetaData(size_t index) = 0;
enum GetTrackMetaDataFlags {
kIncludeExtensiveMetaData = 1
};
virtual sp<MetaData> getTrackMetaData(
size_t index, uint32_t flags = 0) = 0;
protected:
MediaExtractor() {}

View File

@@ -46,6 +46,7 @@ enum {
kKeyDecoderComponent = 'decC', // cstring
kKeyBufferID = 'bfID',
kKeyMaxInputSize = 'inpS',
kKeyThumbnailTime = 'thbT', // int64_t (usecs)
};
enum {

View File

@@ -108,6 +108,9 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
return NULL;
}
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
i, MediaExtractor::kIncludeExtensiveMetaData);
sp<MediaSource> source = mExtractor->getTrack(i);
if (source.get() == NULL) {
@@ -132,6 +135,12 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
// Read one output buffer, ignore format change notifications
// and spurious empty buffers.
MediaSource::ReadOptions options;
int64_t thumbNailTime;
if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
options.setSeekTo(thumbNailTime);
}
MediaBuffer *buffer = NULL;
status_t err;
do {
@@ -139,7 +148,8 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
buffer->release();
buffer = NULL;
}
err = decoder->read(&buffer);
err = decoder->read(&buffer, &options);
options.clearSeekTo();
} while (err == INFO_FORMAT_CHANGED
|| (buffer != NULL && buffer->range_length() == 0));

View File

@@ -86,7 +86,7 @@ sp<MediaSource> AMRExtractor::getTrack(size_t index) {
return new AMRSource(mDataSource, mIsWide);
}
sp<MetaData> AMRExtractor::getTrackMetaData(size_t index) {
sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
if (mInitCheck != OK || index != 0) {
return NULL;
}

View File

@@ -393,7 +393,7 @@ sp<MediaSource> MP3Extractor::getTrack(size_t index) {
mMeta, mDataSource, mFirstFramePos, mFixedHeader);
}
sp<MetaData> MP3Extractor::getTrackMetaData(size_t index) {
sp<MetaData> MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) {
if (mFirstFramePos < 0 || index != 0) {
return NULL;
}

View File

@@ -179,7 +179,8 @@ size_t MPEG4Extractor::countTracks() {
return n;
}
sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
sp<MetaData> MPEG4Extractor::getTrackMetaData(
size_t index, uint32_t flags) {
status_t err;
if ((err = readMetaData()) != OK) {
return NULL;
@@ -199,6 +200,25 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
return NULL;
}
if ((flags & kIncludeExtensiveMetaData)
&& !track->includes_expensive_metadata) {
track->includes_expensive_metadata = true;
const char *mime;
CHECK(track->meta->findCString(kKeyMIMEType, &mime));
if (!strncasecmp("video/", mime, 6)) {
uint32_t sampleIndex;
uint32_t sampleTime;
if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
&& track->sampleTable->getDecodingTime(
sampleIndex, &sampleTime) == OK) {
track->meta->setInt64(
kKeyThumbnailTime,
((int64_t)sampleTime * 1000000) / track->timescale);
}
}
}
return track->meta;
}
@@ -353,6 +373,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
mLastTrack = track;
track->meta = new MetaData;
track->includes_expensive_metadata = false;
track->timescale = 0;
track->sampleTable = new SampleTable(mDataSource);
track->meta->setCString(kKeyMIMEType, "application/octet-stream");

View File

@@ -1943,9 +1943,24 @@ status_t OMXCodec::read(
return UNKNOWN_ERROR;
}
bool seeking = false;
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
seeking = true;
}
if (mInitialBufferSubmit) {
mInitialBufferSubmit = false;
if (seeking) {
CHECK(seekTimeUs >= 0);
mSeekTimeUs = seekTimeUs;
// There's no reason to trigger the code below, there's
// nothing to flush yet.
seeking = false;
}
drainInputBuffers();
if (mState == EXECUTING) {
@@ -1955,8 +1970,7 @@ status_t OMXCodec::read(
}
}
int64_t seekTimeUs;
if (options && options->getSeekTo(&seekTimeUs)) {
if (seeking) {
CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
mSignalledEOS = false;

View File

@@ -575,5 +575,52 @@ status_t SampleTable::findClosestSyncSample(
return OK;
}
status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
if (mSyncSampleOffset < 0) {
// All samples are sync-samples.
*sample_index = 0;
return OK;
}
uint32_t bestSampleIndex = 0;
size_t maxSampleSize = 0;
static const size_t kMaxNumSyncSamplesToScan = 20;
// Consider the first kMaxNumSyncSamplesToScan sync samples and
// pick the one with the largest (compressed) size as the thumbnail.
size_t numSamplesToScan = mNumSyncSamples;
if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
numSamplesToScan = kMaxNumSyncSamplesToScan;
}
for (size_t i = 0; i < numSamplesToScan; ++i) {
uint32_t x;
if (mDataSource->read_at(
mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) {
return ERROR_IO;
}
x = ntohl(x);
--x;
// Now x is a sample index.
size_t sampleSize;
status_t err = getSampleSize(x, &sampleSize);
if (err != OK) {
return err;
}
if (i == 0 || sampleSize > maxSampleSize) {
bestSampleIndex = x;
maxSampleSize = sampleSize;
}
}
*sample_index = bestSampleIndex;
return OK;
}
} // namespace android

View File

@@ -75,6 +75,8 @@ public:
status_t findClosestSyncSample(
uint32_t start_sample_index, uint32_t *sample_index);
status_t findThumbnailSample(uint32_t *sample_index);
protected:
~SampleTable();