am e981c334: Extract video thumbnails from the largest sync sample among the first 20.
Merge commit 'e981c33446a98d5ccc0d73c1a840696d77cf0732' into eclair-mr2-plus-aosp * commit 'e981c33446a98d5ccc0d73c1a840696d77cf0732': Extract video thumbnails from the largest sync sample among the first 20.
This commit is contained in:
@@ -30,7 +30,7 @@ public:
|
|||||||
|
|
||||||
virtual size_t countTracks();
|
virtual size_t countTracks();
|
||||||
virtual sp<MediaSource> getTrack(size_t index);
|
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);
|
static sp<MetaData> makeAMRFormat(bool isWide);
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
|
|
||||||
virtual size_t countTracks();
|
virtual size_t countTracks();
|
||||||
virtual sp<MediaSource> getTrack(size_t index);
|
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:
|
protected:
|
||||||
virtual ~MP3Extractor();
|
virtual ~MP3Extractor();
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public:
|
|||||||
|
|
||||||
size_t countTracks();
|
size_t countTracks();
|
||||||
sp<MediaSource> getTrack(size_t index);
|
sp<MediaSource> getTrack(size_t index);
|
||||||
sp<MetaData> getTrackMetaData(size_t index);
|
sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~MPEG4Extractor();
|
virtual ~MPEG4Extractor();
|
||||||
@@ -44,6 +44,7 @@ private:
|
|||||||
sp<MetaData> meta;
|
sp<MetaData> meta;
|
||||||
uint32_t timescale;
|
uint32_t timescale;
|
||||||
sp<SampleTable> sampleTable;
|
sp<SampleTable> sampleTable;
|
||||||
|
bool includes_expensive_metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
sp<DataSource> mDataSource;
|
sp<DataSource> mDataSource;
|
||||||
|
|||||||
@@ -33,7 +33,12 @@ public:
|
|||||||
|
|
||||||
virtual size_t countTracks() = 0;
|
virtual size_t countTracks() = 0;
|
||||||
virtual sp<MediaSource> getTrack(size_t index) = 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:
|
protected:
|
||||||
MediaExtractor() {}
|
MediaExtractor() {}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ enum {
|
|||||||
kKeyDecoderComponent = 'decC', // cstring
|
kKeyDecoderComponent = 'decC', // cstring
|
||||||
kKeyBufferID = 'bfID',
|
kKeyBufferID = 'bfID',
|
||||||
kKeyMaxInputSize = 'inpS',
|
kKeyMaxInputSize = 'inpS',
|
||||||
|
kKeyThumbnailTime = 'thbT', // int64_t (usecs)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
|
||||||
|
i, MediaExtractor::kIncludeExtensiveMetaData);
|
||||||
|
|
||||||
sp<MediaSource> source = mExtractor->getTrack(i);
|
sp<MediaSource> source = mExtractor->getTrack(i);
|
||||||
|
|
||||||
if (source.get() == NULL) {
|
if (source.get() == NULL) {
|
||||||
@@ -132,6 +135,12 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
|
|||||||
// Read one output buffer, ignore format change notifications
|
// Read one output buffer, ignore format change notifications
|
||||||
// and spurious empty buffers.
|
// and spurious empty buffers.
|
||||||
|
|
||||||
|
MediaSource::ReadOptions options;
|
||||||
|
int64_t thumbNailTime;
|
||||||
|
if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
|
||||||
|
options.setSeekTo(thumbNailTime);
|
||||||
|
}
|
||||||
|
|
||||||
MediaBuffer *buffer = NULL;
|
MediaBuffer *buffer = NULL;
|
||||||
status_t err;
|
status_t err;
|
||||||
do {
|
do {
|
||||||
@@ -139,7 +148,8 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
|
|||||||
buffer->release();
|
buffer->release();
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
}
|
}
|
||||||
err = decoder->read(&buffer);
|
err = decoder->read(&buffer, &options);
|
||||||
|
options.clearSeekTo();
|
||||||
} while (err == INFO_FORMAT_CHANGED
|
} while (err == INFO_FORMAT_CHANGED
|
||||||
|| (buffer != NULL && buffer->range_length() == 0));
|
|| (buffer != NULL && buffer->range_length() == 0));
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ sp<MediaSource> AMRExtractor::getTrack(size_t index) {
|
|||||||
return new AMRSource(mDataSource, mIsWide);
|
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) {
|
if (mInitCheck != OK || index != 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ sp<MediaSource> MP3Extractor::getTrack(size_t index) {
|
|||||||
mMeta, mDataSource, mFirstFramePos, mFixedHeader);
|
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) {
|
if (mFirstFramePos < 0 || index != 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,7 +179,8 @@ size_t MPEG4Extractor::countTracks() {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
|
sp<MetaData> MPEG4Extractor::getTrackMetaData(
|
||||||
|
size_t index, uint32_t flags) {
|
||||||
status_t err;
|
status_t err;
|
||||||
if ((err = readMetaData()) != OK) {
|
if ((err = readMetaData()) != OK) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -199,6 +200,25 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
|
|||||||
return NULL;
|
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;
|
return track->meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,6 +373,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
|
|||||||
mLastTrack = track;
|
mLastTrack = track;
|
||||||
|
|
||||||
track->meta = new MetaData;
|
track->meta = new MetaData;
|
||||||
|
track->includes_expensive_metadata = false;
|
||||||
track->timescale = 0;
|
track->timescale = 0;
|
||||||
track->sampleTable = new SampleTable(mDataSource);
|
track->sampleTable = new SampleTable(mDataSource);
|
||||||
track->meta->setCString(kKeyMIMEType, "application/octet-stream");
|
track->meta->setCString(kKeyMIMEType, "application/octet-stream");
|
||||||
|
|||||||
@@ -1943,9 +1943,24 @@ status_t OMXCodec::read(
|
|||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool seeking = false;
|
||||||
|
int64_t seekTimeUs;
|
||||||
|
if (options && options->getSeekTo(&seekTimeUs)) {
|
||||||
|
seeking = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mInitialBufferSubmit) {
|
if (mInitialBufferSubmit) {
|
||||||
mInitialBufferSubmit = false;
|
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();
|
drainInputBuffers();
|
||||||
|
|
||||||
if (mState == EXECUTING) {
|
if (mState == EXECUTING) {
|
||||||
@@ -1955,8 +1970,7 @@ status_t OMXCodec::read(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t seekTimeUs;
|
if (seeking) {
|
||||||
if (options && options->getSeekTo(&seekTimeUs)) {
|
|
||||||
CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
|
CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
|
||||||
|
|
||||||
mSignalledEOS = false;
|
mSignalledEOS = false;
|
||||||
|
|||||||
@@ -575,5 +575,52 @@ status_t SampleTable::findClosestSyncSample(
|
|||||||
return OK;
|
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
|
} // namespace android
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ public:
|
|||||||
status_t findClosestSyncSample(
|
status_t findClosestSyncSample(
|
||||||
uint32_t start_sample_index, uint32_t *sample_index);
|
uint32_t start_sample_index, uint32_t *sample_index);
|
||||||
|
|
||||||
|
status_t findThumbnailSample(uint32_t *sample_index);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~SampleTable();
|
~SampleTable();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user