Add CryptoPluginMode to WV extractor

Allows the WV extractor to run in a mode that is compatible with
the DRM CryptoPlugin HAL API, where decryption is deferred
until the encrypted data is sent through the CryptoPlugin to
the codec.

This patch does:
 (1) Adds a flag mCryptoPluginMode that controls this behavior
     [Note: need framework support to enable/disable this]
 (2) Accumulates information in track metadata to delineate
     crypto unit boundaries for the CryptoPlugin

related-to-bug: 5986621

Change-Id: I3318d5cde38c7b02a7bdb56aca9aece852c9781c
This commit is contained in:
Jeff Tinker
2012-04-13 00:01:05 -07:00
parent aaa8479c34
commit a9f82e979f
8 changed files with 105 additions and 44 deletions

View File

@@ -70,6 +70,7 @@ typedef void (*WVSocketInfoCallback)(int fd, int status, void * context);
// [in] dts - Decode timestamp, 90 KHz clock // [in] dts - Decode timestamp, 90 KHz clock
// [in] pts - Presentation timestamp, 90 KHz clock // [in] pts - Presentation timestamp, 90 KHz clock
// [in] au_end - Indicates end of Access Unit (last CU in frame) // [in] au_end - Indicates end of Access Unit (last CU in frame)
// [in] context - Client context established from WV_Setup
// //
// Returns: // Returns:
// - WV_Status_OK: Decryption succeeded // - WV_Status_OK: Decryption succeeded
@@ -78,7 +79,8 @@ typedef void (*WVSocketInfoCallback)(int fd, int status, void * context);
// - Error code indicating problem. Causes playback to halt. // - Error code indicating problem. Causes playback to halt.
// //
typedef WVStatus (*WVDecryptCallback)(WVEsSelector es_type, void* input, void* output, size_t length, typedef WVStatus (*WVDecryptCallback)(WVEsSelector es_type, void* input, void* output, size_t length,
int key, unsigned long long dts, unsigned long long pts, bool au_end); int key, unsigned long long dts, unsigned long long pts,
bool au_end, void *context);
enum WVDecryptCallbackMode { enum WVDecryptCallbackMode {
WVDecryptCallbackMode_MultiCU = 0, // WVDecryptCallback called repeatedly until buffer exhausted WVDecryptCallbackMode_MultiCU = 0, // WVDecryptCallback called repeatedly until buffer exhausted

View File

@@ -98,7 +98,8 @@ WVMExtractorImpl::WVMExtractorImpl(sp<DataSource> dataSource)
mIsLiveStream(false), mIsLiveStream(false),
mSession(NULL), mSession(NULL),
mSetupStatus(OK), mSetupStatus(OK),
mUIDIsSet(false) mUIDIsSet(false),
mCryptoPluginMode(false)
{ {
dataSource->getDrmInfo(sDecryptHandle, &sDrmManagerClient); dataSource->getDrmInfo(sDecryptHandle, &sDrmManagerClient);
@@ -340,12 +341,18 @@ status_t WVMExtractorImpl::readMetaData()
mVideoSource->delegateDataSource(mDataSource); mVideoSource->delegateDataSource(mDataSource);
mFileMetaData->setCString(kKeyMIMEType, "video/mp4"); mFileMetaData->setCString(kKeyMIMEType, "video/wvm");
mHaveMetaData = true; mHaveMetaData = true;
mInfoListener->configureHeartbeat(); mInfoListener->configureHeartbeat();
if (mCryptoPluginMode) {
// In crypto plugin mode, need to trigger the drm plugin to begin
// license use on playback since the media player isn't involved.
sDrmManagerClient->setPlaybackStatus(sDecryptHandle, Playback::START, 0);
}
return OK; return OK;
} }
@@ -514,6 +521,18 @@ bool WVMExtractorImpl::getAdaptiveStreamingMode() const
return mUseAdaptiveStreaming; return mUseAdaptiveStreaming;
} }
void WVMExtractorImpl::setCryptoPluginMode(bool cryptoPluginMode)
{
//ALOGD("WVMExtractorImpl::setCryptoPluginMode(%d)", cryptoPluginMode);
mCryptoPluginMode = cryptoPluginMode;
}
bool WVMExtractorImpl::getCryptoPluginMode() const
{
//ALOGD("WVMExtractorImpl::getCryptoPluginMode - %d", mCryptoPluginMode);
return mCryptoPluginMode;
}
void WVMExtractorImpl::setUID(uid_t uid) void WVMExtractorImpl::setUID(uid_t uid)
{ {
//ALOGD("WVMExtractorImpl::setUID(%d)", (uint32_t)uid); //ALOGD("WVMExtractorImpl::setUID(%d)", (uint32_t)uid);

View File

@@ -11,6 +11,8 @@
#include "media/stagefright/foundation/ADebug.h" #include "media/stagefright/foundation/ADebug.h"
#include "media/stagefright/MediaErrors.h" #include "media/stagefright/MediaErrors.h"
#include "media/stagefright/MediaDefs.h" #include "media/stagefright/MediaDefs.h"
#include "media/stagefright/MetaData.h"
#include "media/hardware/CryptoAPI.h"
#include "AndroidHooks.h" #include "AndroidHooks.h"
namespace android { namespace android {
@@ -112,19 +114,11 @@ status_t WVMMediaSource::start(MetaData *)
ALOGE("WV_Play returned status %d in WVMMediaSource::start\n", result); ALOGE("WV_Play returned status %d in WVMMediaSource::start\n", result);
return ERROR_IO; return ERROR_IO;
} }
#ifndef REQUIRE_SECURE_BUFFERS
allocBufferGroup();
#else
if (mIsLiveStream) {
allocBufferGroup();
}
#endif
} else {
// audio
allocBufferGroup();
} }
if (!mGroup)
allocBufferGroup();
return OK; return OK;
} }
@@ -239,7 +233,8 @@ status_t WVMMediaSource::read(MediaBuffer **buffer, const ReadOptions *options)
} }
#ifdef REQUIRE_SECURE_BUFFERS #ifdef REQUIRE_SECURE_BUFFERS
sDecryptContext[mESSelector].Initialize(mediaBuf); mDecryptContext.Initialize(mediaBuf);
mEncryptedSizes.clear();
#endif #endif
size_t bytesRead; size_t bytesRead;
@@ -302,7 +297,7 @@ status_t WVMMediaSource::read(MediaBuffer **buffer, const ReadOptions *options)
#ifdef REQUIRE_SECURE_BUFFERS #ifdef REQUIRE_SECURE_BUFFERS
if (mESSelector == WV_EsSelector_Video && !mIsLiveStream) { if (mESSelector == WV_EsSelector_Video && !mIsLiveStream) {
bytesRead = sDecryptContext[mESSelector].mOffset; bytesRead = mDecryptContext.mOffset;
} }
#endif #endif
@@ -326,7 +321,8 @@ status_t WVMMediaSource::read(MediaBuffer **buffer, const ReadOptions *options)
// drop frames up to next sync if requested // drop frames up to next sync if requested
usleep(10000); usleep(10000);
#ifdef REQUIRE_SECURE_BUFFERS #ifdef REQUIRE_SECURE_BUFFERS
sDecryptContext[mESSelector].Initialize(mediaBuf); mDecryptContext.Initialize(mediaBuf);
mEncryptedSizes.clear();
#endif #endif
continue; continue;
} }
@@ -365,6 +361,14 @@ status_t WVMMediaSource::read(MediaBuffer **buffer, const ReadOptions *options)
mediaBuf->set_range(0, bytesRead + offset); mediaBuf->set_range(0, bytesRead + offset);
#ifdef REQUIRE_SECURE_BUFFERS
if (!mIsLiveStream && mEncryptedSizes.size()) {
mediaBuf->meta_data()->setData(kKeyEncryptedSizes, 0, &mEncryptedSizes[0],
mEncryptedSizes.size() * sizeof(size_t));
mediaBuf->meta_data()->setInt32(kKeyCryptoMode, CryptoPlugin::kMode_AES_WV);
}
#endif
#if 0 #if 0
// debug code - log packets to files // debug code - log packets to files
char filename[32]; char filename[32];
@@ -397,41 +401,54 @@ status_t WVMMediaSource::read(MediaBuffer **buffer, const ReadOptions *options)
#ifdef REQUIRE_SECURE_BUFFERS #ifdef REQUIRE_SECURE_BUFFERS
WVMMediaSource::DecryptContext WVMMediaSource::sDecryptContext[2] = {};
WVStatus WVMMediaSource::DecryptCallback(WVEsSelector esType, void* input, void* output, size_t length, WVStatus WVMMediaSource::DecryptCallback(WVEsSelector esType, void* input, void* output, size_t length,
int key, unsigned long long dts, unsigned long long pts, bool au_end) int key, unsigned long long dts, unsigned long long pts, bool au_end,
void *obj)
{ {
//ALOGD("DecryptCallback(type=%d, in=%p, out=%p, len=%d, key=%d\n", //ALOGD("DecryptCallback(type=%d, in=%p, out=%p, len=%d, key=%d\n",
// (int)esType, input, output, length, key); // (int)esType, input, output, length, key);
DecryptContext &context = sDecryptContext[esType]; WVMExtractorImpl *extractor = (WVMExtractorImpl *)obj;
sp<WVMMediaSource> source;
if (esType == WV_EsSelector_Video)
source = extractor->getVideoSource();
else
source = extractor->getAudioSource();
DecryptContext &context = source->getDecryptContext();
OEMCrypto_UINT32 copied = length; OEMCrypto_UINT32 copied = length;
OEMCryptoResult result; OEMCryptoResult result;
WVStatus status; WVStatus status = WV_Status_OK;
unsigned char *iv = NULL; unsigned char *iv = NULL;
if (key) if (extractor->getCryptoPluginMode()) {
iv = context.mIV; // just determine crypto unit boundaries
if (key) {
if (esType == WV_EsSelector_Video) { source->addEncryptedSize(length);
result = OEMCrypto_DecryptVideo(iv, (OEMCrypto_UINT8 *)input, length, }
(OEMCrypto_UINT32)(char *)context.mMediaBuf->data(),
context.mOffset, &copied);
} else { } else {
result = OEMCrypto_DecryptAudio(iv, (OEMCrypto_UINT8 *)input, length, // do decrypt
(OEMCrypto_UINT8 *)context.mMediaBuf->data() + context.mOffset, if (key)
&copied); iv = context.mIV;
}
if (result == OEMCrypto_SUCCESS) { if (esType == WV_EsSelector_Video) {
status = WV_Status_OK; result = OEMCrypto_DecryptVideo(iv, (OEMCrypto_UINT8 *)input, length,
} (OEMCrypto_UINT32)(char *)context.mMediaBuf->data(),
else { context.mOffset, &copied);
status = WV_Status_Unknown; } else {
ALOGD("OEMCrypto decrypt failure: %d", result); result = OEMCrypto_DecryptAudio(iv, (OEMCrypto_UINT8 *)input, length,
} (OEMCrypto_UINT8 *)context.mMediaBuf->data() + context.mOffset,
&copied);
}
context.mOffset += copied; if (result == OEMCrypto_SUCCESS) {
status = WV_Status_OK;
} else {
status = WV_Status_Unknown;
ALOGD("OEMCrypto decrypt failure: %d", result);
}
context.mOffset += copied;
}
return status; return status;
} }

View File

@@ -34,11 +34,18 @@ public:
virtual sp<MetaData> getMetaData(); virtual sp<MetaData> getMetaData();
virtual int64_t getCachedDurationUs(status_t *finalStatus); virtual int64_t getCachedDurationUs(status_t *finalStatus);
virtual void setAdaptiveStreamingMode(bool adaptive); virtual void setAdaptiveStreamingMode(bool adaptive);
bool getAdaptiveStreamingMode() const; bool getAdaptiveStreamingMode() const;
virtual void setCryptoPluginMode(bool cryptoPluginMode);
bool getCryptoPluginMode() const;
virtual void setUID(uid_t uid); virtual void setUID(uid_t uid);
sp<WVMMediaSource> getAudioSource() const { return mAudioSource; }
sp<WVMMediaSource> getVideoSource() const { return mVideoSource; }
static void SocketInfoCallback(int fd, int op, void *context); static void SocketInfoCallback(int fd, int op, void *context);
static void cleanup(); static void cleanup();
@@ -69,6 +76,14 @@ private:
bool mUIDIsSet; bool mUIDIsSet;
uid_t mUID; uid_t mUID;
//
// if in CryptoPlugin mode, the extractor doesn't decrypt,
// it just accumulates the ranges of data requiring decryption
// into the MediaBuffer's metadata, the decryption happens
// later via the CryptoPlugin
//
bool mCryptoPluginMode;
status_t readMetaData(); status_t readMetaData();
const static size_t kStreamCacheSize = 10 * 1024 * 1024; const static size_t kStreamCacheSize = 10 * 1024 * 1024;

View File

@@ -38,6 +38,8 @@ public:
virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers); virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers);
virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL); virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL);
void addEncryptedSize(size_t size) { mEncryptedSizes.push_back(size); }
static int sLastError; static int sLastError;
#ifdef REQUIRE_SECURE_BUFFERS #ifdef REQUIRE_SECURE_BUFFERS
@@ -53,10 +55,13 @@ public:
static const int kCryptoBlockSize = 16; static const int kCryptoBlockSize = 16;
unsigned char mIV[kCryptoBlockSize]; unsigned char mIV[kCryptoBlockSize];
}; };
static WVStatus DecryptCallback(WVEsSelector esType, void* input, void* output, size_t length,
int key, unsigned long long dts, unsigned long long pts, bool au_end);
static DecryptContext sDecryptContext[2]; // audio vs. video static WVStatus DecryptCallback(WVEsSelector esType, void* input, void* output, size_t length,
int key, unsigned long long dts, unsigned long long pts,
bool au_end, void *context);
DecryptContext& getDecryptContext() { return mDecryptContext; }
private:
DecryptContext mDecryptContext;
#endif #endif
protected: protected:
@@ -74,6 +79,7 @@ private:
bool mLogOnce; bool mLogOnce;
bool mIsLiveStream; bool mIsLiveStream;
bool mNewSegment; bool mNewSegment;
bool mCryptoPluginMode;
MediaBufferGroup *mGroup; MediaBufferGroup *mGroup;
@@ -83,6 +89,8 @@ private:
sp<WVMFileSource> mFileSource; sp<WVMFileSource> mFileSource;
sp<DataSource> mDataSource; sp<DataSource> mDataSource;
Vector<size_t> mEncryptedSizes;
void allocBufferGroup(); void allocBufferGroup();
WVMMediaSource(const WVMMediaSource &); WVMMediaSource(const WVMMediaSource &);