Merge "Finer granularity discontinuity support." into ics-mr1

This commit is contained in:
Andreas Huber
2011-11-29 14:08:13 -08:00
committed by Android (Google) Code Review
7 changed files with 153 additions and 62 deletions

View File

@@ -54,6 +54,7 @@ NuPlayer::NuPlayer()
mVideoEOS(false), mVideoEOS(false),
mScanSourcesPending(false), mScanSourcesPending(false),
mScanSourcesGeneration(0), mScanSourcesGeneration(0),
mTimeDiscontinuityPending(false),
mFlushingAudio(NONE), mFlushingAudio(NONE),
mFlushingVideo(NONE), mFlushingVideo(NONE),
mResetInProgress(false), mResetInProgress(false),
@@ -477,6 +478,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
break; break;
} }
mTimeDiscontinuityPending = true;
if (mAudioDecoder != NULL) { if (mAudioDecoder != NULL) {
flushDecoder(true /* audio */, true /* needShutdown */); flushDecoder(true /* audio */, true /* needShutdown */);
} }
@@ -540,7 +543,10 @@ void NuPlayer::finishFlushIfPossible() {
LOGV("both audio and video are flushed now."); LOGV("both audio and video are flushed now.");
mRenderer->signalTimeDiscontinuity(); if (mTimeDiscontinuityPending) {
mRenderer->signalTimeDiscontinuity();
mTimeDiscontinuityPending = false;
}
if (mAudioDecoder != NULL) { if (mAudioDecoder != NULL) {
mAudioDecoder->signalResume(); mAudioDecoder->signalResume();
@@ -663,10 +669,15 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
bool formatChange = bool formatChange =
type == ATSParser::DISCONTINUITY_FORMATCHANGE; (audio &&
(type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
|| (!audio &&
(type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
LOGV("%s discontinuity (formatChange=%d)", bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
audio ? "audio" : "video", formatChange);
LOGI("%s discontinuity (formatChange=%d, time=%d)",
audio ? "audio" : "video", formatChange, timeChange);
if (audio) { if (audio) {
mSkipRenderingAudioUntilMediaTimeUs = -1; mSkipRenderingAudioUntilMediaTimeUs = -1;
@@ -674,26 +685,45 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
mSkipRenderingVideoUntilMediaTimeUs = -1; mSkipRenderingVideoUntilMediaTimeUs = -1;
} }
sp<AMessage> extra; if (timeChange) {
if (accessUnit->meta()->findMessage("extra", &extra) sp<AMessage> extra;
&& extra != NULL) { if (accessUnit->meta()->findMessage("extra", &extra)
int64_t resumeAtMediaTimeUs; && extra != NULL) {
if (extra->findInt64( int64_t resumeAtMediaTimeUs;
"resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { if (extra->findInt64(
LOGI("suppressing rendering of %s until %lld us", "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
audio ? "audio" : "video", resumeAtMediaTimeUs); LOGI("suppressing rendering of %s until %lld us",
audio ? "audio" : "video", resumeAtMediaTimeUs);
if (audio) { if (audio) {
mSkipRenderingAudioUntilMediaTimeUs = mSkipRenderingAudioUntilMediaTimeUs =
resumeAtMediaTimeUs; resumeAtMediaTimeUs;
} else { } else {
mSkipRenderingVideoUntilMediaTimeUs = mSkipRenderingVideoUntilMediaTimeUs =
resumeAtMediaTimeUs; resumeAtMediaTimeUs;
}
} }
} }
} }
flushDecoder(audio, formatChange); mTimeDiscontinuityPending =
mTimeDiscontinuityPending || timeChange;
if (formatChange || timeChange) {
flushDecoder(audio, formatChange);
} else {
// This stream is unaffected by the discontinuity
if (audio) {
mFlushingAudio = FLUSHED;
} else {
mFlushingVideo = FLUSHED;
}
finishFlushIfPossible();
return -EWOULDBLOCK;
}
} }
reply->setInt32("err", err); reply->setInt32("err", err);
@@ -794,6 +824,11 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
} }
void NuPlayer::flushDecoder(bool audio, bool needShutdown) { void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) {
LOGI("flushDecoder %s without decoder present",
audio ? "audio" : "video");
}
// Make sure we don't continue to scan sources until we finish flushing. // Make sure we don't continue to scan sources until we finish flushing.
++mScanSourcesGeneration; ++mScanSourcesGeneration;
mScanSourcesPending = false; mScanSourcesPending = false;

View File

@@ -112,6 +112,10 @@ private:
SHUT_DOWN, SHUT_DOWN,
}; };
// Once the current flush is complete this indicates whether the
// notion of time has changed.
bool mTimeDiscontinuityPending;
FlushStatus mFlushingAudio; FlushStatus mFlushingAudio;
FlushStatus mFlushingVideo; FlushStatus mFlushingVideo;
bool mResetInProgress; bool mResetInProgress;

View File

@@ -123,6 +123,9 @@ private:
void extractAACFrames(const sp<ABuffer> &buffer); void extractAACFrames(const sp<ABuffer> &buffer);
bool isAudio() const;
bool isVideo() const;
DISALLOW_EVIL_CONSTRUCTORS(Stream); DISALLOW_EVIL_CONSTRUCTORS(Stream);
}; };
@@ -401,7 +404,7 @@ ATSParser::Stream::Stream(
case STREAMTYPE_H264: case STREAMTYPE_H264:
mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::H264); mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::H264);
break; break;
case STREAMTYPE_MPEG2_AUDIO_ATDS: case STREAMTYPE_MPEG2_AUDIO_ADTS:
mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::AAC); mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::AAC);
break; break;
case STREAMTYPE_MPEG1_AUDIO: case STREAMTYPE_MPEG1_AUDIO:
@@ -486,6 +489,31 @@ status_t ATSParser::Stream::parse(
return OK; return OK;
} }
bool ATSParser::Stream::isVideo() const {
switch (mStreamType) {
case STREAMTYPE_H264:
case STREAMTYPE_MPEG1_VIDEO:
case STREAMTYPE_MPEG2_VIDEO:
case STREAMTYPE_MPEG4_VIDEO:
return true;
default:
return false;
}
}
bool ATSParser::Stream::isAudio() const {
switch (mStreamType) {
case STREAMTYPE_MPEG1_AUDIO:
case STREAMTYPE_MPEG2_AUDIO:
case STREAMTYPE_MPEG2_AUDIO_ADTS:
return true;
default:
return false;
}
}
void ATSParser::Stream::signalDiscontinuity( void ATSParser::Stream::signalDiscontinuity(
DiscontinuityType type, const sp<AMessage> &extra) { DiscontinuityType type, const sp<AMessage> &extra) {
if (mQueue == NULL) { if (mQueue == NULL) {
@@ -495,34 +523,34 @@ void ATSParser::Stream::signalDiscontinuity(
mPayloadStarted = false; mPayloadStarted = false;
mBuffer->setRange(0, 0); mBuffer->setRange(0, 0);
switch (type) { bool clearFormat = false;
case DISCONTINUITY_SEEK: if (isAudio()) {
case DISCONTINUITY_FORMATCHANGE: if (type & DISCONTINUITY_AUDIO_FORMAT) {
{ clearFormat = true;
bool isASeek = (type == DISCONTINUITY_SEEK);
mQueue->clear(!isASeek);
uint64_t resumeAtPTS;
if (extra != NULL
&& extra->findInt64(
IStreamListener::kKeyResumeAtPTS,
(int64_t *)&resumeAtPTS)) {
int64_t resumeAtMediaTimeUs =
mProgram->convertPTSToTimestamp(resumeAtPTS);
extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs);
}
if (mSource != NULL) {
mSource->queueDiscontinuity(type, extra);
}
break;
} }
} else {
if (type & DISCONTINUITY_VIDEO_FORMAT) {
clearFormat = true;
}
}
default: mQueue->clear(clearFormat);
TRESPASS();
break; if (type & DISCONTINUITY_TIME) {
uint64_t resumeAtPTS;
if (extra != NULL
&& extra->findInt64(
IStreamListener::kKeyResumeAtPTS,
(int64_t *)&resumeAtPTS)) {
int64_t resumeAtMediaTimeUs =
mProgram->convertPTSToTimestamp(resumeAtPTS);
extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs);
}
}
if (mSource != NULL) {
mSource->queueDiscontinuity(type, extra);
} }
} }
@@ -764,10 +792,7 @@ sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
switch (type) { switch (type) {
case VIDEO: case VIDEO:
{ {
if (mStreamType == STREAMTYPE_H264 if (isVideo()) {
|| mStreamType == STREAMTYPE_MPEG1_VIDEO
|| mStreamType == STREAMTYPE_MPEG2_VIDEO
|| mStreamType == STREAMTYPE_MPEG4_VIDEO) {
return mSource; return mSource;
} }
break; break;
@@ -775,9 +800,7 @@ sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
case AUDIO: case AUDIO:
{ {
if (mStreamType == STREAMTYPE_MPEG1_AUDIO if (isAudio()) {
|| mStreamType == STREAMTYPE_MPEG2_AUDIO
|| mStreamType == STREAMTYPE_MPEG2_AUDIO_ATDS) {
return mSource; return mSource;
} }
break; break;

View File

@@ -33,9 +33,18 @@ struct MediaSource;
struct ATSParser : public RefBase { struct ATSParser : public RefBase {
enum DiscontinuityType { enum DiscontinuityType {
DISCONTINUITY_NONE, DISCONTINUITY_NONE = 0,
DISCONTINUITY_SEEK, DISCONTINUITY_TIME = 1,
DISCONTINUITY_FORMATCHANGE DISCONTINUITY_AUDIO_FORMAT = 2,
DISCONTINUITY_VIDEO_FORMAT = 4,
DISCONTINUITY_SEEK = DISCONTINUITY_TIME,
// For legacy reasons this also implies a time discontinuity.
DISCONTINUITY_FORMATCHANGE =
DISCONTINUITY_AUDIO_FORMAT
| DISCONTINUITY_VIDEO_FORMAT
| DISCONTINUITY_TIME,
}; };
enum Flags { enum Flags {
@@ -71,7 +80,7 @@ struct ATSParser : public RefBase {
STREAMTYPE_MPEG2_VIDEO = 0x02, STREAMTYPE_MPEG2_VIDEO = 0x02,
STREAMTYPE_MPEG1_AUDIO = 0x03, STREAMTYPE_MPEG1_AUDIO = 0x03,
STREAMTYPE_MPEG2_AUDIO = 0x04, STREAMTYPE_MPEG2_AUDIO = 0x04,
STREAMTYPE_MPEG2_AUDIO_ATDS = 0x0f, STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f,
STREAMTYPE_MPEG4_VIDEO = 0x10, STREAMTYPE_MPEG4_VIDEO = 0x10,
STREAMTYPE_H264 = 0x1b, STREAMTYPE_H264 = 0x1b,
}; };

View File

@@ -29,8 +29,17 @@
namespace android { namespace android {
AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta) AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta)
: mFormat(meta), : mIsAudio(false),
mFormat(meta),
mEOSResult(OK) { mEOSResult(OK) {
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
if (!strncasecmp("audio/", mime, 6)) {
mIsAudio = true;
} else {
CHECK(!strncasecmp("video/", mime, 6));
}
} }
void AnotherPacketSource::setFormat(const sp<MetaData> &meta) { void AnotherPacketSource::setFormat(const sp<MetaData> &meta) {
@@ -67,8 +76,7 @@ status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
int32_t discontinuity; int32_t discontinuity;
if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) { if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) {
if (wasFormatChange(discontinuity)) {
if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) {
mFormat.clear(); mFormat.clear();
} }
@@ -96,7 +104,7 @@ status_t AnotherPacketSource::read(
int32_t discontinuity; int32_t discontinuity;
if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) { if (wasFormatChange(discontinuity)) {
mFormat.clear(); mFormat.clear();
} }
@@ -117,6 +125,15 @@ status_t AnotherPacketSource::read(
return mEOSResult; return mEOSResult;
} }
bool AnotherPacketSource::wasFormatChange(
int32_t discontinuityType) const {
if (mIsAudio) {
return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
}
return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
}
void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
int32_t damaged; int32_t damaged;
if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {

View File

@@ -61,10 +61,13 @@ private:
Mutex mLock; Mutex mLock;
Condition mCondition; Condition mCondition;
bool mIsAudio;
sp<MetaData> mFormat; sp<MetaData> mFormat;
List<sp<ABuffer> > mBuffers; List<sp<ABuffer> > mBuffers;
status_t mEOSResult; status_t mEOSResult;
bool wasFormatChange(int32_t discontinuityType) const;
DISALLOW_EVIL_CONSTRUCTORS(AnotherPacketSource); DISALLOW_EVIL_CONSTRUCTORS(AnotherPacketSource);
}; };

View File

@@ -543,7 +543,7 @@ MPEG2PSExtractor::Track::Track(
case ATSParser::STREAMTYPE_H264: case ATSParser::STREAMTYPE_H264:
mode = ElementaryStreamQueue::H264; mode = ElementaryStreamQueue::H264;
break; break;
case ATSParser::STREAMTYPE_MPEG2_AUDIO_ATDS: case ATSParser::STREAMTYPE_MPEG2_AUDIO_ADTS:
mode = ElementaryStreamQueue::AAC; mode = ElementaryStreamQueue::AAC;
break; break;
case ATSParser::STREAMTYPE_MPEG1_AUDIO: case ATSParser::STREAMTYPE_MPEG1_AUDIO: