Merge "Finer granularity discontinuity support." into ics-mr1
This commit is contained in:
committed by
Android (Google) Code Review
commit
405a4e3403
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user