diff options
author | Lajos Molnar <lajos@google.com> | 2014-07-17 14:29:51 -0700 |
---|---|---|
committer | Lajos Molnar <lajos@google.com> | 2014-07-17 21:14:52 -0700 |
commit | 095248375e29adde961ec2a44989ecb3a6dda6a2 (patch) | |
tree | 41c5e1378f8c7274b257837a4356efc54436d330 /media/libmediaplayerservice/nuplayer | |
parent | cc227036b05f7c2f960a89c567a61f9decefe742 (diff) | |
download | frameworks_av-095248375e29adde961ec2a44989ecb3a6dda6a2.zip frameworks_av-095248375e29adde961ec2a44989ecb3a6dda6a2.tar.gz frameworks_av-095248375e29adde961ec2a44989ecb3a6dda6a2.tar.bz2 |
nuplayer: support widevine sources
- handle widevine:// scheme
- add separate looper for renderer (as it can block initial buffer
handling if all buffers are used)
- initiate secure codecs before source is started
- don't read secure buffers
- share ACodec's input buffers with Widevine source
on the decoder side
- keep track of mediabuffers released by widevine source
- keep track of dequeued input buffers (for safety)
- release mediabuffer when buffer is subsequently dequeued. (This
was hardcoded into OMXCodec to do this when buffer-empties message
was handled, but MediaCodec does not support such functionality.)
Bug: 15699665
Change-Id: I4a369443294e45c644be8b0257010e52db1d7c9b
Diffstat (limited to 'media/libmediaplayerservice/nuplayer')
5 files changed, 185 insertions, 2 deletions
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 88c59bf..6ccd27a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -36,6 +36,7 @@ #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MetaData.h> @@ -221,6 +222,10 @@ void NuPlayer::setDataSourceAsync( || strstr(url, ".sdp?"))) { source = new RTSPSource( notify, httpService, url, headers, mUIDValid, mUID, true); + } else if ((!strncasecmp(url, "widevine://", 11))) { + source = new GenericSource(notify, httpService, url, headers, + true /* isWidevine */, mUIDValid, mUID); + mSourceFlags |= Source::FLAG_SECURE; } else { source = new GenericSource(notify, httpService, url, headers); } @@ -512,6 +517,17 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { mNumFramesDropped = 0; mStarted = true; + /* instantiate decoders now for secure playback */ + if (mSourceFlags & Source::FLAG_SECURE) { + if (mNativeWindow != NULL) { + instantiateDecoder(false, &mVideoDecoder); + } + + if (mAudioSink != NULL) { + instantiateDecoder(true, &mAudioDecoder); + } + } + mSource->start(); uint32_t flags = 0; @@ -540,7 +556,10 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { new AMessage(kWhatRendererNotify, id()), flags); - looper()->registerHandler(mRenderer); + mRendererLooper = new ALooper; + mRendererLooper->setName("NuPlayerRenderer"); + mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO); + mRendererLooper->registerHandler(mRenderer); postScanSources(); break; @@ -1055,6 +1074,10 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, id()); mCCDecoder = new CCDecoder(ccNotify); + + if (mSourceFlags & Source::FLAG_SECURE) { + format->setInt32("secure", true); + } } sp<AMessage> notify = @@ -1073,6 +1096,28 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { (*decoder)->init(); (*decoder)->configure(format); + // allocate buffers to decrypt widevine source buffers + if (!audio && (mSourceFlags & Source::FLAG_SECURE)) { + Vector<sp<ABuffer> > inputBufs; + CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK); + + Vector<MediaBuffer *> mediaBufs; + for (size_t i = 0; i < inputBufs.size(); i++) { + const sp<ABuffer> &buffer = inputBufs[i]; + MediaBuffer *mbuf = new MediaBuffer(buffer->data(), buffer->size()); + mediaBufs.push(mbuf); + } + + status_t err = mSource->setBuffers(audio, mediaBufs); + if (err != OK) { + for (size_t i = 0; i < mediaBufs.size(); ++i) { + mediaBufs[i]->release(); + } + mediaBufs.clear(); + ALOGE("Secure source didn't support secure mediaBufs."); + return err; + } + } return OK; } @@ -1184,6 +1229,7 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { dropAccessUnit = false; if (!audio + && !(mSourceFlags & Source::FLAG_SECURE) && mVideoLateByUs > 100000ll && mVideoIsAVC && !IsAVCReferenceFrame(accessUnit)) { @@ -1497,6 +1543,13 @@ void NuPlayer::performReset() { ++mScanSourcesGeneration; mScanSourcesPending = false; + if (mRendererLooper != NULL) { + if (mRenderer != NULL) { + mRendererLooper->unregisterHandler(mRenderer->id()); + } + mRendererLooper->stop(); + mRendererLooper.clear(); + } mRenderer.clear(); if (mSource != NULL) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index d7c00aa..c04e277 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -125,6 +125,7 @@ private: sp<Decoder> mAudioDecoder; sp<CCDecoder> mCCDecoder; sp<Renderer> mRenderer; + sp<ALooper> mRendererLooper; List<sp<Action> > mDeferredActions; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index dd73cc4..1b9bafb 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -26,6 +26,7 @@ #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaCodec.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> @@ -54,6 +55,22 @@ NuPlayer::Decoder::Decoder( NuPlayer::Decoder::~Decoder() { } +static +status_t PostAndAwaitResponse( + const sp<AMessage> &msg, sp<AMessage> *response) { + status_t err = msg->postAndAwaitResponse(response); + + if (err != OK) { + return err; + } + + if (!(*response)->findInt32("err", &err)) { + err = OK; + } + + return err; +} + void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { CHECK(mCodec == NULL); @@ -72,8 +89,20 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get()); mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); + int32_t secure = 0; + if (format->findInt32("secure", &secure) && secure != 0) { + if (mCodec != NULL) { + mCodec->getName(&mComponentName); + mComponentName.append(".secure"); + mCodec->release(); + ALOGI("[%s] creating", mComponentName.c_str()); + mCodec = MediaCodec::CreateByComponentName( + mCodecLooper, mComponentName.c_str()); + } + } if (mCodec == NULL) { - ALOGE("Failed to create %s decoder", mime.c_str()); + ALOGE("Failed to create %s%s decoder", + (secure ? "secure " : ""), mime.c_str()); handleError(UNKNOWN_ERROR); return; } @@ -107,6 +136,7 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { // the following should work after start CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers)); + releaseAndResetMediaBuffers(); CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers)); ALOGV("[%s] got %zu input and %zu output buffers", mComponentName.c_str(), @@ -117,6 +147,18 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { mPaused = false; } +void NuPlayer::Decoder::releaseAndResetMediaBuffers() { + for (size_t i = 0; i < mMediaBuffers.size(); i++) { + if (mMediaBuffers[i] != NULL) { + mMediaBuffers[i]->release(); + mMediaBuffers.editItemAt(i) = NULL; + } + } + mMediaBuffers.resize(mInputBuffers.size()); + mInputBufferIsDequeued.clear(); + mInputBufferIsDequeued.resize(mInputBuffers.size()); +} + void NuPlayer::Decoder::requestCodecNotification() { if (mCodec != NULL) { sp<AMessage> reply = new AMessage(kWhatCodecNotify, id()); @@ -141,6 +183,14 @@ void NuPlayer::Decoder::configure(const sp<AMessage> &format) { msg->post(); } +status_t NuPlayer::Decoder::getInputBuffers(Vector<sp<ABuffer> > *buffers) const { + sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, id()); + msg->setPointer("buffers", buffers); + + sp<AMessage> response; + return PostAndAwaitResponse(msg, &response); +} + void NuPlayer::Decoder::handleError(int32_t err) { sp<AMessage> notify = mNotify->dup(); @@ -163,6 +213,12 @@ bool NuPlayer::Decoder::handleAnInputBuffer() { CHECK_LT(bufferIx, mInputBuffers.size()); + if (mMediaBuffers[bufferIx] != NULL) { + mMediaBuffers[bufferIx]->release(); + mMediaBuffers.editItemAt(bufferIx) = NULL; + } + mInputBufferIsDequeued.editItemAt(bufferIx) = true; + sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id()); reply->setSize("buffer-ix", bufferIx); reply->setInt32("generation", mBufferGeneration); @@ -183,6 +239,44 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) { sp<ABuffer> buffer; bool hasBuffer = msg->findBuffer("buffer", &buffer); + + // handle widevine classic source - that fills an arbitrary input buffer + MediaBuffer *mediaBuffer = NULL; + if (hasBuffer && buffer->meta()->findPointer( + "mediaBuffer", (void **)&mediaBuffer)) { + if (mediaBuffer == NULL) { + // received no actual buffer + ALOGW("[%s] received null MediaBuffer %s", + mComponentName.c_str(), msg->debugString().c_str()); + buffer = NULL; + } else { + // likely filled another buffer than we requested: adjust buffer index + size_t ix; + for (ix = 0; ix < mInputBuffers.size(); ix++) { + const sp<ABuffer> &buf = mInputBuffers[ix]; + if (buf->data() == mediaBuffer->data()) { + // all input buffers are dequeued on start, hence the check + CHECK(mInputBufferIsDequeued[ix]); + ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu", + mComponentName.c_str(), ix, bufferIx); + + // TRICKY: need buffer for the metadata, so instead, set + // codecBuffer to the same (though incorrect) buffer to + // avoid a memcpy into the codecBuffer + codecBuffer = buffer; + codecBuffer->setRange( + mediaBuffer->range_offset(), + mediaBuffer->range_length()); + bufferIx = ix; + break; + } + } + CHECK(ix < mInputBuffers.size()); + } + } + + mInputBufferIsDequeued.editItemAt(bufferIx) = false; + if (buffer == NULL /* includes !hasBuffer */) { int32_t streamErr = ERROR_END_OF_STREAM; CHECK(msg->findInt32("err", &streamErr) || !hasBuffer); @@ -236,6 +330,11 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) { mComponentName.c_str(), err); handleError(err); } + + if (mediaBuffer != NULL) { + CHECK(mMediaBuffers[bufferIx] == NULL); + mMediaBuffers.editItemAt(bufferIx) = mediaBuffer; + } } } @@ -352,6 +451,8 @@ void NuPlayer::Decoder::onFlush() { return; } + releaseAndResetMediaBuffers(); + sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatFlushCompleted); notify->post(); @@ -379,6 +480,8 @@ void NuPlayer::Decoder::onShutdown() { mComponentName = "decoder"; } + releaseAndResetMediaBuffers(); + if (err != OK) { ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err); handleError(err); @@ -403,6 +506,23 @@ void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) { break; } + case kWhatGetInputBuffers: + { + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + Vector<sp<ABuffer> > *dstBuffers; + CHECK(msg->findPointer("buffers", (void **)&dstBuffers)); + + dstBuffers->clear(); + for (size_t i = 0; i < mInputBuffers.size(); i++) { + dstBuffers->push(mInputBuffers[i]); + } + + (new AMessage)->postReply(replyID); + break; + } + case kWhatCodecNotify: { if (!isStaleReply(msg)) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 4fa0dbd..c6fc237 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -26,6 +26,7 @@ namespace android { struct ABuffer; struct MediaCodec; +struct MediaBuffer; struct NuPlayer::Decoder : public AHandler { Decoder(const sp<AMessage> ¬ify, @@ -34,6 +35,7 @@ struct NuPlayer::Decoder : public AHandler { virtual void configure(const sp<AMessage> &format); virtual void init(); + status_t getInputBuffers(Vector<sp<ABuffer> > *dstBuffers) const; virtual void signalFlush(); virtual void signalResume(); virtual void initiateShutdown(); @@ -60,6 +62,7 @@ private: enum { kWhatCodecNotify = 'cdcN', kWhatConfigure = 'conf', + kWhatGetInputBuffers = 'gInB', kWhatInputBufferFilled = 'inpF', kWhatRenderBuffer = 'rndr', kWhatFlush = 'flus', @@ -77,11 +80,14 @@ private: Vector<sp<ABuffer> > mInputBuffers; Vector<sp<ABuffer> > mOutputBuffers; + Vector<bool> mInputBufferIsDequeued; + Vector<MediaBuffer *> mMediaBuffers; void handleError(int32_t err); bool handleAnInputBuffer(); bool handleAnOutputBuffer(); + void releaseAndResetMediaBuffers(); void requestCodecNotification(); bool isStaleReply(const sp<AMessage> &msg); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index f520ff7..8592ec2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -26,6 +26,8 @@ #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MetaData.h> +#include <inttypes.h> + namespace android { // static @@ -502,6 +504,7 @@ void NuPlayer::Renderer::postDrainVideoQueue() { } } + ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); msg->post(delayUs); mDrainVideoQueuePending = true; |