summaryrefslogtreecommitdiffstats
path: root/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libmediaplayerservice/nuplayer/NuPlayer.cpp')
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp361
1 files changed, 63 insertions, 298 deletions
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index c01f16a..405278c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -21,7 +21,9 @@
#include "NuPlayer.h"
#include "HTTPLiveSource.h"
+#include "NuPlayerCCDecoder.h"
#include "NuPlayerDecoder.h"
+#include "NuPlayerDecoderBase.h"
#include "NuPlayerDecoderPassThrough.h"
#include "NuPlayerDriver.h"
#include "NuPlayerRenderer.h"
@@ -52,10 +54,6 @@
namespace android {
-// TODO optimize buffer size for power consumption
-// The offload read buffer size is 32 KB but 24 KB uses less power.
-const size_t NuPlayer::kAggregateBufferSizeBytes = 24 * 1024;
-
struct NuPlayer::Action : public RefBase {
Action() {}
@@ -153,7 +151,6 @@ private:
NuPlayer::NuPlayer()
: mUIDValid(false),
mSourceFlags(0),
- mVideoIsAVC(false),
mOffloadAudio(false),
mAudioDecoderGeneration(0),
mVideoDecoderGeneration(0),
@@ -164,11 +161,8 @@ NuPlayer::NuPlayer()
mScanSourcesGeneration(0),
mPollDurationGeneration(0),
mTimedTextGeneration(0),
- mTimeDiscontinuityPending(false),
mFlushingAudio(NONE),
mFlushingVideo(NONE),
- mNumFramesTotal(0ll),
- mNumFramesDropped(0ll),
mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
mStarted(false) {
clearFlushComplete();
@@ -559,6 +553,12 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
new SimpleAction(&NuPlayer::performScanSources));
}
+ // After a flush wihtout shutdown, decoder is paused.
+ // Don't resume it until source is seeked, otherwise it could
+ // start pulling stale data too soon.
+ mDeferredActions.push_back(
+ new SimpleAction(&NuPlayer::performResumeDecoders));
+
processDeferredActions();
break;
}
@@ -685,16 +685,26 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
int32_t what;
CHECK(msg->findInt32("what", &what));
- if (what == Decoder::kWhatFillThisBuffer) {
- status_t err = feedDecoderInputData(
- audio, msg);
+ if (what == DecoderBase::kWhatInputDiscontinuity) {
+ int32_t formatChange;
+ CHECK(msg->findInt32("formatChange", &formatChange));
- if (err == -EWOULDBLOCK) {
- if (mSource->feedMoreTSData() == OK) {
- msg->post(10 * 1000ll);
- }
+ ALOGV("%s discontinuity: formatChange %d",
+ audio ? "audio" : "video", formatChange);
+
+ if (formatChange) {
+ mDeferredActions.push_back(
+ new FlushDecoderAction(
+ audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
+ audio ? FLUSH_CMD_NONE : FLUSH_CMD_SHUTDOWN));
}
- } else if (what == Decoder::kWhatEOS) {
+
+ mDeferredActions.push_back(
+ new SimpleAction(
+ &NuPlayer::performScanSources));
+
+ processDeferredActions();
+ } else if (what == DecoderBase::kWhatEOS) {
int32_t err;
CHECK(msg->findInt32("err", &err));
@@ -707,12 +717,12 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
}
mRenderer->queueEOS(audio, err);
- } else if (what == Decoder::kWhatFlushCompleted) {
+ } else if (what == DecoderBase::kWhatFlushCompleted) {
ALOGV("decoder %s flush completed", audio ? "audio" : "video");
handleFlushComplete(audio, true /* isDecoder */);
finishFlushIfPossible();
- } else if (what == Decoder::kWhatVideoSizeChanged) {
+ } else if (what == DecoderBase::kWhatVideoSizeChanged) {
sp<AMessage> format;
CHECK(msg->findMessage("format", &format));
@@ -720,7 +730,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
mSource->getFormat(false /* audio */);
updateVideoSize(inputFormat, format);
- } else if (what == Decoder::kWhatShutdownCompleted) {
+ } else if (what == DecoderBase::kWhatShutdownCompleted) {
ALOGV("%s shutdown completed", audio ? "audio" : "video");
if (audio) {
mAudioDecoder.clear();
@@ -737,7 +747,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
}
finishFlushIfPossible();
- } else if (what == Decoder::kWhatError) {
+ } else if (what == DecoderBase::kWhatError) {
status_t err;
if (!msg->findInt32("err", &err) || err == OK) {
err = UNKNOWN_ERROR;
@@ -785,8 +795,6 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
break; // Finish anyways.
}
notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
- } else if (what == Decoder::kWhatRenderBufferTime) {
- renderBuffer(audio, msg);
} else {
ALOGV("Unhandled decoder notification %d '%c%c%c%c'.",
what,
@@ -860,9 +868,11 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
closeAudioSink();
mAudioDecoder.clear();
++mAudioDecoderGeneration;
- mRenderer->flush(true /* audio */);
+ mRenderer->flush(
+ true /* audio */, false /* notifyComplete */);
if (mVideoDecoder != NULL) {
- mRenderer->flush(false /* audio */);
+ mRenderer->flush(
+ false /* audio */, false /* notifyComplete */);
}
performSeek(positionUs, false /* needNotify */);
@@ -913,6 +923,12 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
mDeferredActions.push_back(
new SeekAction(seekTimeUs, needNotify));
+ // After a flush wihtout shutdown, decoder is paused.
+ // Don't resume it until source is seeked, otherwise it could
+ // start pulling stale data too soon.
+ mDeferredActions.push_back(
+ new SimpleAction(&NuPlayer::performResumeDecoders));
+
processDeferredActions();
break;
}
@@ -969,12 +985,9 @@ void NuPlayer::onResume() {
}
void NuPlayer::onStart() {
- mVideoIsAVC = false;
mOffloadAudio = false;
mAudioEOS = false;
mVideoEOS = false;
- mNumFramesTotal = 0;
- mNumFramesDropped = 0;
mStarted = true;
/* instantiate decoders now for secure playback */
@@ -1095,22 +1108,6 @@ void NuPlayer::finishFlushIfPossible() {
ALOGV("both audio and video are flushed now.");
- mPendingAudioAccessUnit.clear();
- mAggregateBuffer.clear();
-
- if (mTimeDiscontinuityPending) {
- mRenderer->signalTimeDiscontinuity();
- mTimeDiscontinuityPending = false;
- }
-
- if (mAudioDecoder != NULL && mFlushingAudio == FLUSHED) {
- mAudioDecoder->signalResume();
- }
-
- if (mVideoDecoder != NULL && mFlushingVideo == FLUSHED) {
- mVideoDecoder->signalResume();
- }
-
mFlushingAudio = NONE;
mFlushingVideo = NONE;
@@ -1163,7 +1160,7 @@ void NuPlayer::closeAudioSink() {
mRenderer->closeAudioSink();
}
-status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
+status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *decoder) {
if (*decoder != NULL) {
return OK;
}
@@ -1177,7 +1174,6 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
if (!audio) {
AString mime;
CHECK(format->findString("mime", &mime));
- mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());
sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, id());
mCCDecoder = new CCDecoder(ccNotify);
@@ -1202,7 +1198,8 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
++mVideoDecoderGeneration;
notify->setInt32("generation", mVideoDecoderGeneration);
- *decoder = new Decoder(notify, mSource, mRenderer, mNativeWindow);
+ *decoder = new Decoder(
+ notify, mSource, mRenderer, mNativeWindow, mCCDecoder);
// enable FRC if high-quality AV sync is requested, even if not
// queuing to native window, as this will even improve textureview
@@ -1243,232 +1240,6 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
return OK;
}
-status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
- sp<AMessage> reply;
- CHECK(msg->findMessage("reply", &reply));
-
- if ((audio && mFlushingAudio != NONE)
- || (!audio && mFlushingVideo != NONE)
- || mSource == NULL) {
- reply->setInt32("err", INFO_DISCONTINUITY);
- reply->post();
- return OK;
- }
-
- sp<ABuffer> accessUnit;
-
- // Aggregate smaller buffers into a larger buffer.
- // The goal is to reduce power consumption.
- // Note this will not work if the decoder requires one frame per buffer.
- bool doBufferAggregation = (audio && mOffloadAudio);
- bool needMoreData = false;
-
- bool dropAccessUnit;
- do {
- status_t err;
- // Did we save an accessUnit earlier because of a discontinuity?
- if (audio && (mPendingAudioAccessUnit != NULL)) {
- accessUnit = mPendingAudioAccessUnit;
- mPendingAudioAccessUnit.clear();
- err = mPendingAudioErr;
- ALOGV("feedDecoderInputData() use mPendingAudioAccessUnit");
- } else {
- err = mSource->dequeueAccessUnit(audio, &accessUnit);
- }
-
- if (err == -EWOULDBLOCK) {
- return err;
- } else if (err != OK) {
- if (err == INFO_DISCONTINUITY) {
- if (doBufferAggregation && (mAggregateBuffer != NULL)) {
- // We already have some data so save this for later.
- mPendingAudioErr = err;
- mPendingAudioAccessUnit = accessUnit;
- accessUnit.clear();
- ALOGD("feedDecoderInputData() save discontinuity for later");
- break;
- }
- int32_t type;
- CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
-
- bool formatChange =
- (audio &&
- (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
- || (!audio &&
- (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
-
- bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
-
- ALOGI("%s discontinuity (formatChange=%d, time=%d)",
- audio ? "audio" : "video", formatChange, timeChange);
-
- mTimeDiscontinuityPending =
- mTimeDiscontinuityPending || timeChange;
-
- bool seamlessFormatChange = false;
- sp<AMessage> newFormat = mSource->getFormat(audio);
- if (formatChange) {
- seamlessFormatChange =
- getDecoder(audio)->supportsSeamlessFormatChange(newFormat);
- // treat seamless format change separately
- formatChange = !seamlessFormatChange;
- }
- bool shutdownOrFlush = formatChange || timeChange;
-
- // We want to queue up scan-sources only once per discontinuity.
- // We control this by doing it only if neither audio nor video are
- // flushing or shutting down. (After handling 1st discontinuity, one
- // of the flushing states will not be NONE.)
- // No need to scan sources if this discontinuity does not result
- // in a flush or shutdown, as the flushing state will stay NONE.
- if (mFlushingAudio == NONE && mFlushingVideo == NONE &&
- shutdownOrFlush) {
- // And we'll resume scanning sources once we're done
- // flushing.
- mDeferredActions.push_front(
- new SimpleAction(
- &NuPlayer::performScanSources));
- }
-
- if (formatChange /* not seamless */) {
- // must change decoder
- flushDecoder(audio, /* needShutdown = */ true);
- } else if (timeChange) {
- // need to flush
- flushDecoder(audio, /* needShutdown = */ false, newFormat);
- err = OK;
- } else if (seamlessFormatChange) {
- // reuse existing decoder and don't flush
- updateDecoderFormatWithoutFlush(audio, newFormat);
- err = OK;
- } else {
- // This stream is unaffected by the discontinuity
- return -EWOULDBLOCK;
- }
- } else if (err == ERROR_END_OF_STREAM
- && doBufferAggregation && (mAggregateBuffer != NULL)) {
- // send out the last bit of aggregated data
- reply->setBuffer("buffer", mAggregateBuffer);
- mAggregateBuffer.clear();
- err = OK;
- }
-
- reply->setInt32("err", err);
- reply->post();
- return OK;
- }
-
- if (!audio) {
- ++mNumFramesTotal;
- }
-
- dropAccessUnit = false;
- if (!audio
- && !(mSourceFlags & Source::FLAG_SECURE)
- && mRenderer->getVideoLateByUs() > 100000ll
- && mVideoIsAVC
- && !IsAVCReferenceFrame(accessUnit)) {
- dropAccessUnit = true;
- ++mNumFramesDropped;
- }
-
- size_t smallSize = accessUnit->size();
- needMoreData = false;
- if (doBufferAggregation && (mAggregateBuffer == NULL)
- // Don't bother if only room for a few small buffers.
- && (smallSize < (kAggregateBufferSizeBytes / 3))) {
- // Create a larger buffer for combining smaller buffers from the extractor.
- mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
- mAggregateBuffer->setRange(0, 0); // start empty
- }
-
- if (doBufferAggregation && (mAggregateBuffer != NULL)) {
- int64_t timeUs;
- int64_t dummy;
- bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs);
- bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy);
- // Will the smaller buffer fit?
- size_t bigSize = mAggregateBuffer->size();
- size_t roomLeft = mAggregateBuffer->capacity() - bigSize;
- // Should we save this small buffer for the next big buffer?
- // If the first small buffer did not have a timestamp then save
- // any buffer that does have a timestamp until the next big buffer.
- if ((smallSize > roomLeft)
- || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) {
- mPendingAudioErr = err;
- mPendingAudioAccessUnit = accessUnit;
- accessUnit.clear();
- } else {
- // Grab time from first small buffer if available.
- if ((bigSize == 0) && smallTimestampValid) {
- mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
- }
- // Append small buffer to the bigger buffer.
- memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
- bigSize += smallSize;
- mAggregateBuffer->setRange(0, bigSize);
-
- // Keep looping until we run out of room in the mAggregateBuffer.
- needMoreData = true;
-
- ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu",
- smallSize, bigSize, mAggregateBuffer->capacity());
- }
- }
- } while (dropAccessUnit || needMoreData);
-
- // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video");
-
-#if 0
- int64_t mediaTimeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("feeding %s input buffer at media time %.2f secs",
- audio ? "audio" : "video",
- mediaTimeUs / 1E6);
-#endif
-
- if (!audio) {
- mCCDecoder->decode(accessUnit);
- }
-
- if (doBufferAggregation && (mAggregateBuffer != NULL)) {
- ALOGV("feedDecoderInputData() reply with aggregated buffer, %zu",
- mAggregateBuffer->size());
- reply->setBuffer("buffer", mAggregateBuffer);
- mAggregateBuffer.clear();
- } else {
- reply->setBuffer("buffer", accessUnit);
- }
-
- reply->post();
-
- return OK;
-}
-
-void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
- // ALOGV("renderBuffer %s", audio ? "audio" : "video");
-
- if ((audio && mFlushingAudio != NONE)
- || (!audio && mFlushingVideo != NONE)) {
- // We're currently attempting to flush the decoder, in order
- // to complete this, the decoder wants all its buffers back,
- // so we don't want any output buffers it sent us (from before
- // we initiated the flush) to be stuck in the renderer's queue.
-
- ALOGV("we're still flushing the %s decoder, sending its output buffer"
- " right back.", audio ? "audio" : "video");
-
- return;
- }
-
- int64_t mediaTimeUs;
- CHECK(msg->findInt64("timeUs", &mediaTimeUs));
-
- if (!audio && mCCDecoder->isSelected()) {
- mCCDecoder->display(mediaTimeUs);
- }
-}
-
void NuPlayer::updateVideoSize(
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat) {
@@ -1549,12 +1320,11 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) {
driver->notifyListener(msg, ext1, ext2, in);
}
-void NuPlayer::flushDecoder(
- bool audio, bool needShutdown, const sp<AMessage> &newFormat) {
+void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
ALOGV("[%s] flushDecoder needShutdown=%d",
audio ? "audio" : "video", needShutdown);
- const sp<Decoder> &decoder = getDecoder(audio);
+ const sp<DecoderBase> &decoder = getDecoder(audio);
if (decoder == NULL) {
ALOGI("flushDecoder %s without decoder present",
audio ? "audio" : "video");
@@ -1565,7 +1335,7 @@ void NuPlayer::flushDecoder(
++mScanSourcesGeneration;
mScanSourcesPending = false;
- decoder->signalFlush(newFormat);
+ decoder->signalFlush();
FlushStatus newStatus =
needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
@@ -1580,25 +1350,7 @@ void NuPlayer::flushDecoder(
ALOGE_IF(mFlushingVideo != NONE,
"video flushDecoder() is called in state %d", mFlushingVideo);
mFlushingVideo = newStatus;
-
- if (mCCDecoder != NULL) {
- mCCDecoder->flush();
- }
- }
-}
-
-void NuPlayer::updateDecoderFormatWithoutFlush(
- bool audio, const sp<AMessage> &format) {
- ALOGV("[%s] updateDecoderFormatWithoutFlush", audio ? "audio" : "video");
-
- const sp<Decoder> &decoder = getDecoder(audio);
- if (decoder == NULL) {
- ALOGI("updateDecoderFormatWithoutFlush %s without decoder present",
- audio ? "audio" : "video");
- return;
}
-
- decoder->signalUpdateFormat(format);
}
void NuPlayer::queueDecoderShutdown(
@@ -1684,8 +1436,13 @@ status_t NuPlayer::getCurrentPosition(int64_t *mediaUs) {
}
void NuPlayer::getStats(int64_t *numFramesTotal, int64_t *numFramesDropped) {
- *numFramesTotal = mNumFramesTotal;
- *numFramesDropped = mNumFramesDropped;
+ sp<DecoderBase> decoder = getDecoder(false /* audio */);
+ if (decoder != NULL) {
+ decoder->getStats(numFramesTotal, numFramesDropped);
+ } else {
+ *numFramesTotal = 0;
+ *numFramesDropped = 0;
+ }
}
sp<MetaData> NuPlayer::getFileMeta() {
@@ -1762,8 +1519,6 @@ void NuPlayer::performDecoderFlush(FlushCommand audio, FlushCommand video) {
return;
}
- mTimeDiscontinuityPending = true;
-
if (audio != FLUSH_CMD_NONE && mAudioDecoder != NULL) {
flushDecoder(true /* audio */, (audio == FLUSH_CMD_SHUTDOWN));
}
@@ -1838,6 +1593,16 @@ void NuPlayer::performSetSurface(const sp<NativeWindowWrapper> &wrapper) {
}
}
+void NuPlayer::performResumeDecoders() {
+ if (mVideoDecoder != NULL) {
+ mVideoDecoder->signalResume();
+ }
+
+ if (mAudioDecoder != NULL) {
+ mAudioDecoder->signalResume();
+ }
+}
+
void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
int32_t what;
CHECK(msg->findInt32("what", &what));