Merge "Various improvements to nuplayer playback"

This commit is contained in:
Andreas Huber
2011-09-16 10:50:51 -07:00
committed by Android (Google) Code Review
12 changed files with 148 additions and 62 deletions

View File

@@ -299,7 +299,12 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
sampleRate, numChannels);
mAudioSink->close();
CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
CHECK_EQ(mAudioSink->open(
sampleRate,
numChannels,
AUDIO_FORMAT_PCM_16_BIT,
8 /* bufferCount */),
(status_t)OK);
mAudioSink->start();
mRenderer->signalAudioSinkChanged();

View File

@@ -70,19 +70,19 @@ private:
struct StreamingSource;
enum {
kWhatSetDataSource,
kWhatSetVideoNativeWindow,
kWhatSetAudioSink,
kWhatMoreDataQueued,
kWhatStart,
kWhatScanSources,
kWhatVideoNotify,
kWhatAudioNotify,
kWhatRendererNotify,
kWhatReset,
kWhatSeek,
kWhatPause,
kWhatResume,
kWhatSetDataSource = '=DaS',
kWhatSetVideoNativeWindow = '=NaW',
kWhatSetAudioSink = '=AuS',
kWhatMoreDataQueued = 'more',
kWhatStart = 'strt',
kWhatScanSources = 'scan',
kWhatVideoNotify = 'vidN',
kWhatAudioNotify = 'audN',
kWhatRendererNotify = 'renN',
kWhatReset = 'rset',
kWhatSeek = 'seek',
kWhatPause = 'paus',
kWhatResume = 'rsme',
};
wp<NuPlayerDriver> mDriver;

View File

@@ -59,8 +59,21 @@ void NuPlayer::Decoder::configure(const sp<MetaData> &meta) {
format->setObject("native-window", mNativeWindow);
}
// Current video decoders do not return from OMX_FillThisBuffer
// quickly, violating the OpenMAX specs, until that is remedied
// we need to invest in an extra looper to free the main event
// queue.
bool needDedicatedLooper = !strncasecmp(mime, "video/", 6);
mCodec = new ACodec;
looper()->registerHandler(mCodec);
if (needDedicatedLooper && mCodecLooper == NULL) {
mCodecLooper = new ALooper;
mCodecLooper->setName("NuPlayerDecoder");
mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
}
(needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec);
mCodec->setNotificationMessage(notifyMsg);
mCodec->initiateSetup(format);

View File

@@ -43,13 +43,14 @@ protected:
private:
enum {
kWhatCodecNotify,
kWhatCodecNotify = 'cdcN',
};
sp<AMessage> mNotify;
sp<NativeWindowWrapper> mNativeWindow;
sp<ACodec> mCodec;
sp<ALooper> mCodecLooper;
Vector<sp<ABuffer> > mCSD;
size_t mCSDIndex;

View File

@@ -118,9 +118,24 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
mDrainAudioQueuePending = false;
onDrainAudioQueue();
if (onDrainAudioQueue()) {
uint32_t numFramesPlayed;
CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
(status_t)OK);
postDrainAudioQueue();
uint32_t numFramesPendingPlayout =
mNumFramesWritten - numFramesPlayed;
// This is how long the audio sink will have data to
// play back.
int64_t delayUs =
mAudioSink->msecsPerFrame()
* numFramesPendingPlayout * 1000ll;
// Let's give it more data after about half that time
// has elapsed.
postDrainAudioQueue(delayUs / 2);
}
break;
}
@@ -182,7 +197,7 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
}
}
void NuPlayer::Renderer::postDrainAudioQueue() {
void NuPlayer::Renderer::postDrainAudioQueue(int64_t delayUs) {
if (mDrainAudioQueuePending || mSyncQueues || mPaused) {
return;
}
@@ -194,19 +209,33 @@ void NuPlayer::Renderer::postDrainAudioQueue() {
mDrainAudioQueuePending = true;
sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
msg->setInt32("generation", mAudioQueueGeneration);
msg->post();
msg->post(delayUs);
}
void NuPlayer::Renderer::signalAudioSinkChanged() {
(new AMessage(kWhatAudioSinkChanged, id()))->post();
}
void NuPlayer::Renderer::onDrainAudioQueue() {
for (;;) {
if (mAudioQueue.empty()) {
break;
}
bool NuPlayer::Renderer::onDrainAudioQueue() {
uint32_t numFramesPlayed;
CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
ssize_t numFramesAvailableToWrite =
mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
#if 0
if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
LOGI("audio sink underrun");
} else {
LOGV("audio queue has %d frames left to play",
mAudioSink->frameCount() - numFramesAvailableToWrite);
}
#endif
size_t numBytesAvailableToWrite =
numFramesAvailableToWrite * mAudioSink->frameSize();
while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
QueueEntry *entry = &*mAudioQueue.begin();
if (entry->mBuffer == NULL) {
@@ -216,20 +245,7 @@ void NuPlayer::Renderer::onDrainAudioQueue() {
mAudioQueue.erase(mAudioQueue.begin());
entry = NULL;
return;
}
uint32_t numFramesPlayed;
CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
ssize_t numFramesAvailableToWrite =
mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
size_t numBytesAvailableToWrite =
numFramesAvailableToWrite * mAudioSink->frameSize();
if (numBytesAvailableToWrite == 0) {
break;
return false;
}
if (entry->mOffset == 0) {
@@ -274,10 +290,14 @@ void NuPlayer::Renderer::onDrainAudioQueue() {
entry = NULL;
}
mNumFramesWritten += copy / mAudioSink->frameSize();
numBytesAvailableToWrite -= copy;
size_t copiedFrames = copy / mAudioSink->frameSize();
mNumFramesWritten += copiedFrames;
}
notifyPosition();
return !mAudioQueue.empty();
}
void NuPlayer::Renderer::postDrainVideoQueue() {
@@ -344,7 +364,14 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
int64_t mediaTimeUs;
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
LOGI("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
int64_t realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
int64_t lateByUs = ALooper::GetNowUs() - realTimeUs;
if (lateByUs > 40000) {
LOGI("video late by %lld us (%.2f secs)", lateByUs, lateByUs / 1E6);
} else {
LOGV("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
}
#endif
entry->mNotifyConsumed->setInt32("render", true);

View File

@@ -45,9 +45,9 @@ struct NuPlayer::Renderer : public AHandler {
void resume();
enum {
kWhatEOS,
kWhatFlushComplete,
kWhatPosition,
kWhatEOS = 'eos ',
kWhatFlushComplete = 'fluC',
kWhatPosition = 'posi',
};
protected:
@@ -57,14 +57,14 @@ protected:
private:
enum {
kWhatDrainAudioQueue,
kWhatDrainVideoQueue,
kWhatQueueBuffer,
kWhatQueueEOS,
kWhatFlush,
kWhatAudioSinkChanged,
kWhatPause,
kWhatResume,
kWhatDrainAudioQueue = 'draA',
kWhatDrainVideoQueue = 'draV',
kWhatQueueBuffer = 'queB',
kWhatQueueEOS = 'qEOS',
kWhatFlush = 'flus',
kWhatAudioSinkChanged = 'auSC',
kWhatPause = 'paus',
kWhatResume = 'resm',
};
struct QueueEntry {
@@ -102,8 +102,8 @@ private:
int64_t mLastPositionUpdateUs;
void onDrainAudioQueue();
void postDrainAudioQueue();
bool onDrainAudioQueue();
void postDrainAudioQueue(int64_t delayUs = 0);
void onDrainVideoQueue();
void postDrainVideoQueue();

View File

@@ -52,7 +52,7 @@ bool NuPlayer::StreamingSource::feedMoreTSData() {
return false;
}
for (int32_t i = 0; i < 10; ++i) {
for (int32_t i = 0; i < 50; ++i) {
char buffer[188];
sp<AMessage> extra;
ssize_t n = mStreamListener->read(buffer, sizeof(buffer), &extra);

View File

@@ -1377,8 +1377,13 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
memcpy(info->mData->data(), buffer->data(), buffer->size());
}
LOGV("[%s] calling emptyBuffer %p",
mCodec->mComponentName.c_str(), bufferID);
if (flags & OMX_BUFFERFLAG_CODECCONFIG) {
LOGV("[%s] calling emptyBuffer %p w/ codec specific data",
mCodec->mComponentName.c_str(), bufferID);
} else {
LOGV("[%s] calling emptyBuffer %p w/ time %lld us",
mCodec->mComponentName.c_str(), bufferID, timeUs);
}
CHECK_EQ(mCodec->mOMX->emptyBuffer(
mCodec->mNode,
@@ -1396,7 +1401,7 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
LOGV("[%s] Signalling EOS on the input port",
mCodec->mComponentName.c_str());
LOGV("[%s] calling emptyBuffer %p",
LOGV("[%s] calling emptyBuffer %p signalling EOS",
mCodec->mComponentName.c_str(), bufferID);
CHECK_EQ(mCodec->mOMX->emptyBuffer(
@@ -1457,8 +1462,8 @@ bool ACodec::BaseState::onOMXFillBufferDone(
int64_t timeUs,
void *platformPrivate,
void *dataPtr) {
LOGV("[%s] onOMXFillBufferDone %p",
mCodec->mComponentName.c_str(), bufferID);
LOGV("[%s] onOMXFillBufferDone %p time %lld us",
mCodec->mComponentName.c_str(), bufferID, timeUs);
ssize_t index;
BufferInfo *info =
@@ -1686,7 +1691,11 @@ void ACodec::UninitializedState::onSetup(
++matchIndex) {
componentName = matchingCodecs.itemAt(matchIndex).string();
pid_t tid = androidGetTid();
int prevPriority = androidGetThreadPriority(tid);
androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
status_t err = omx->allocateNode(componentName.c_str(), observer, &node);
androidSetThreadPriority(tid, prevPriority);
if (err == OK) {
break;

View File

@@ -74,10 +74,32 @@ bool logMessageHandler(
return false;
}
struct AutoPrioritySaver {
AutoPrioritySaver()
: mTID(androidGetTid()),
mPrevPriority(androidGetThreadPriority(mTID)) {
androidSetThreadPriority(mTID, ANDROID_PRIORITY_NORMAL);
}
~AutoPrioritySaver() {
androidSetThreadPriority(mTID, mPrevPriority);
}
private:
pid_t mTID;
int mPrevPriority;
DISALLOW_EVIL_CONSTRUCTORS(AutoPrioritySaver);
};
static void InitializeNetworkThreadIfNecessary() {
Mutex::Autolock autoLock(gNetworkThreadLock);
if (gNetworkThread == NULL) {
// Make sure any threads spawned by the chromium framework are
// running at normal priority instead of inheriting this thread's.
AutoPrioritySaver saver;
gNetworkThread = new base::Thread("network");
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;

View File

@@ -385,6 +385,15 @@ AString AMessage::debugString(int32_t indent) const {
item.u.refValue)->debugString(
indent + strlen(item.mName) + 14).c_str());
break;
case kTypeRect:
tmp = StringPrintf(
"Rect %s(%d, %d, %d, %d)",
item.mName,
item.u.rectValue.mLeft,
item.u.rectValue.mTop,
item.u.rectValue.mRight,
item.u.rectValue.mBottom);
break;
default:
TRESPASS();
}

View File

@@ -85,7 +85,7 @@ OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
: mOwner(owner),
mDone(false) {
mThread = new CallbackDispatcherThread(this);
mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_AUDIO);
mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND);
}
OMX::CallbackDispatcher::~CallbackDispatcher() {

View File

@@ -42,7 +42,7 @@ SimpleSoftOMXComponent::SimpleSoftOMXComponent(
mLooper->start(
false, // runOnCallingThread
false, // canCallJava
PRIORITY_AUDIO);
ANDROID_PRIORITY_FOREGROUND);
}
void SimpleSoftOMXComponent::prepareForDestruction() {