diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index 940470dcec5f0..b3815c4f24ac6 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -14,11 +14,12 @@ struct MemoryDealer; struct ACodec : public AHierarchicalStateMachine { enum { - kWhatFillThisBuffer = 'fill', - kWhatDrainThisBuffer = 'drai', - kWhatEOS = 'eos ', - kWhatShutdownCompleted = 'scom', - kWhatFlushCompleted = 'fcom', + kWhatFillThisBuffer = 'fill', + kWhatDrainThisBuffer = 'drai', + kWhatEOS = 'eos ', + kWhatShutdownCompleted = 'scom', + kWhatFlushCompleted = 'fcom', + kWhatOutputFormatChanged = 'outC', }; ACodec(); diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h index 941f6b9ffe367..91ec60c894f3a 100644 --- a/include/media/stagefright/foundation/AMessage.h +++ b/include/media/stagefright/foundation/AMessage.h @@ -64,6 +64,9 @@ struct AMessage : public RefBase { void post(int64_t delayUs = 0); + // Performs a deep-copy of "this", contained messages are in turn "dup'ed". + // Warning: RefBase items, i.e. "objects" are _not_ copied but only have + // their refcount incremented. sp dup() const; AString debugString(int32_t indent = 0) const; diff --git a/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp b/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp index 89a5e698b5a34..9738e331f9365 100644 --- a/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp +++ b/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp @@ -166,6 +166,9 @@ private: sp mDecoder; sp mNotify; bool mEOS; + bool mSentFormat; + + void sendFormatChange(); DISALLOW_EVIL_CONSTRUCTORS(WrapperReader); }; @@ -174,7 +177,8 @@ DecoderWrapper::WrapperReader::WrapperReader( const sp &decoder, const sp ¬ify) : mDecoder(decoder), mNotify(notify), - mEOS(false) { + mEOS(false), + mSentFormat(false) { } DecoderWrapper::WrapperReader::~WrapperReader() { @@ -215,12 +219,17 @@ void DecoderWrapper::WrapperReader::onMessageReceived( MediaBuffer *src; status_t err = mDecoder->read(&src, &options); - sp notify = mNotify->dup(); - - sp realNotify; - CHECK(notify->findMessage("real-notify", &realNotify)); - if (err == OK) { + if (!mSentFormat) { + sendFormatChange(); + mSentFormat = true; + } + + sp notify = mNotify->dup(); + + sp realNotify; + CHECK(notify->findMessage("real-notify", &realNotify)); + realNotify->setInt32("what", ACodec::kWhatDrainThisBuffer); sp dst = new ABuffer(src->range_length()); @@ -236,12 +245,23 @@ void DecoderWrapper::WrapperReader::onMessageReceived( dst->meta()->setInt64("timeUs", timeUs); realNotify->setObject("buffer", dst); + + notify->post(); + } else if (err == INFO_FORMAT_CHANGED) { + sendFormatChange(); + + readMore(false /* flush */); } else { + sp notify = mNotify->dup(); + + sp realNotify; + CHECK(notify->findMessage("real-notify", &realNotify)); + realNotify->setInt32("what", ACodec::kWhatEOS); mEOS = true; - } - notify->post(); + notify->post(); + } break; } @@ -251,6 +271,46 @@ void DecoderWrapper::WrapperReader::onMessageReceived( } } +void DecoderWrapper::WrapperReader::sendFormatChange() { + sp notify = mNotify->dup(); + + sp realNotify; + CHECK(notify->findMessage("real-notify", &realNotify)); + + realNotify->setInt32("what", ACodec::kWhatOutputFormatChanged); + + sp meta = mDecoder->getFormat(); + + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + realNotify->setString("mime", mime); + + if (!strncasecmp("audio/", mime, 6)) { + int32_t numChannels; + CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); + + int32_t sampleRate; + CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); + + realNotify->setInt32("channel-count", numChannels); + realNotify->setInt32("sample-rate", sampleRate); + } else { + CHECK(!strncasecmp("video/", mime, 6)); + + int32_t width, height; + CHECK(meta->findInt32(kKeyWidth, &width)); + CHECK(meta->findInt32(kKeyHeight, &height)); + + realNotify->setInt32("width", width); + realNotify->setInt32("height", height); + } + + notify->post(); + + mSentFormat = true; +} + //////////////////////////////////////////////////////////////////////////////// DecoderWrapper::DecoderWrapper() @@ -327,24 +387,33 @@ void DecoderWrapper::onMessageReceived(const sp &msg) { case kWhatFillBufferDone: { - CHECK_GT(mNumPendingDecodes, 0); - --mNumPendingDecodes; - - if (mFlushing) { - completeFlushIfPossible(); - break; - } - sp notify; CHECK(msg->findMessage("real-notify", ¬ify)); - sp reply = - new AMessage(kWhatOutputBufferDrained, id()); + int32_t what; + CHECK(notify->findInt32("what", &what)); + + if (what == ACodec::kWhatDrainThisBuffer) { + CHECK_GT(mNumPendingDecodes, 0); + --mNumPendingDecodes; + + sp reply = + new AMessage(kWhatOutputBufferDrained, id()); + + notify->setMessage("reply", reply); + + ++mNumOutstandingOutputBuffers; + } else if (what == ACodec::kWhatEOS) { + CHECK_GT(mNumPendingDecodes, 0); + --mNumPendingDecodes; + + if (mFlushing) { + completeFlushIfPossible(); + break; + } + } - notify->setMessage("reply", reply); notify->post(); - - ++mNumOutstandingOutputBuffers; break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 403029a79031b..e99c24a05acef 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -198,6 +198,21 @@ void NuPlayer::onMessageReceived(const sp &msg) { mFlushingAudio = NONE; mFlushingVideo = NONE; } + } else if (what == ACodec::kWhatOutputFormatChanged) { + CHECK(audio); + + int32_t numChannels; + CHECK(codecRequest->findInt32("channel-count", &numChannels)); + + int32_t sampleRate; + CHECK(codecRequest->findInt32("sample-rate", &sampleRate)); + + LOGI("Audio output format changed to %d Hz, %d channels", + sampleRate, numChannels); + + mAudioSink->close(); + CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK); + mAudioSink->start(); } else { CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer); @@ -365,18 +380,6 @@ status_t NuPlayer::instantiateDecoder( const sp &meta = source->getFormat(); (*decoder)->configure(meta); - if (audio) { - int32_t sampleRate; - int32_t channelCount; - CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); - CHECK(meta->findInt32(kKeyChannelCount, &channelCount)); - - channelCount = 2; // XXX - - CHECK_EQ(mAudioSink->open(sampleRate, channelCount), (status_t)OK); - mAudioSink->start(); - } - return OK; } diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp index 7da9cb80c61df..0e40acc505d20 100644 --- a/media/libstagefright/foundation/AMessage.cpp +++ b/media/libstagefright/foundation/AMessage.cpp @@ -224,13 +224,22 @@ sp AMessage::dup() const { } case kTypeObject: - case kTypeMessage: { to->u.refValue = from->u.refValue; to->u.refValue->incStrong(msg.get()); break; } + case kTypeMessage: + { + sp copy = + static_cast(from->u.refValue)->dup(); + + to->u.refValue = copy.get(); + to->u.refValue->incStrong(msg.get()); + break; + } + default: { to->u = from->u;