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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -46,6 +46,7 @@ enum {
|
||||
kKeyDecoderComponent = 'decC', // cstring
|
||||
kKeyBufferID = 'bfID',
|
||||
kKeyMaxInputSize = 'inpS',
|
||||
kKeyThumbnailTime = 'thbT', // int64_t (usecs)
|
||||
};
|
||||
|
||||
enum {
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user