summaryrefslogtreecommitdiffstats
path: root/media/libmediaplayerservice/nuplayer
diff options
context:
space:
mode:
authorLajos Molnar <lajos@google.com>2014-07-17 14:29:51 -0700
committerLajos Molnar <lajos@google.com>2014-07-17 21:14:52 -0700
commit095248375e29adde961ec2a44989ecb3a6dda6a2 (patch)
tree41c5e1378f8c7274b257837a4356efc54436d330 /media/libmediaplayerservice/nuplayer
parentcc227036b05f7c2f960a89c567a61f9decefe742 (diff)
downloadframeworks_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')
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp55
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h1
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp122
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h6
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp3
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> &notify,
@@ -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;