am 8c5545ef: Merge "Fix for b/4198446 HC - Support for Widevine Adaptive VOD Fix for b/4075745 libWVStreamControlAPI crashes when dlopened() and dlclosed() Added error logging to diagnose problems such as b/4430078 Playback of newly rented movie fails with "licens

* commit '8c5545ef76f39094b016986c7deec02df682356d':
  Fix for b/4198446 HC - Support for Widevine Adaptive VOD Fix for b/4075745 libWVStreamControlAPI crashes when dlopened() and dlclosed() Added error logging to diagnose problems such as b/4430078 Playback of newly rented     movie fails with "license expired"
This commit is contained in:
Jeffrey Tinker
2011-05-24 12:57:28 -07:00
committed by Android Git Automerger
9 changed files with 140 additions and 22 deletions

View File

@@ -84,11 +84,17 @@ void WVMDrmPluginTest::Run()
exit(-1); exit(-1);
} }
// Remote asset
String8 url; String8 url;
// Remote asset
url = String8("http://seawwws001.cdn.shibboleth.tv/videos/qa/adventures_d_ch_444169.wvm"); url = String8("http://seawwws001.cdn.shibboleth.tv/videos/qa/adventures_d_ch_444169.wvm");
TestAsset(plugin, url); TestAsset(plugin, url);
// Remote asset using widevine:// protocol
url = String8("widevine://seawwws001.cdn.shibboleth.tv/videos/qa/adventures_d_ch_444169.wvm");
TestAsset(plugin, url);
// Local asset // Local asset
url = String8("file:///sdcard/Widevine/trailers_d_ch_444169.wvm"); url = String8("file:///sdcard/Widevine/trailers_d_ch_444169.wvm");
TestAsset(plugin, url); TestAsset(plugin, url);

View File

@@ -52,10 +52,9 @@ public class ConfigXMLParser {
Element asset = assetlist.getChild("asset"); Element asset = assetlist.getChild("asset");
asset.setEndElementListener(new EndElementListener() { asset.setEndElementListener(new EndElementListener() {
public void end() { public void end() {
if (currentAssetDescriptor.getUri().indexOf("http") != -1 if (currentAssetDescriptor.getUri().indexOf(".wvm") != -1
&& (currentAssetDescriptor.getUri().indexOf(".wvm") != -1 || !currentAssetDescriptor.getUri().substring(currentAssetDescriptor
|| !currentAssetDescriptor.getUri().substring(currentAssetDescriptor .getUri().lastIndexOf("/")).contains(".")) {
.getUri().lastIndexOf("/")).contains("."))) {
assetDescriptors.add(currentAssetDescriptor.copy()); assetDescriptors.add(currentAssetDescriptor.copy());
} }
} }

View File

@@ -83,12 +83,13 @@ public class HttpParser extends Thread {
String assetPath = null; String assetPath = null;
String title = null; String title = null;
String imagePath = null; String imagePath = null;
start = htmlText.indexOf(":", start); start = htmlText.indexOf("href=\"", start);
if (start == -1) { if (start == -1) {
break; break;
} else { } else {
start += "href=\"".length();
end = htmlText.indexOf("\"", start); end = htmlText.indexOf("\"", start);
assetPath = "http" + htmlText.substring(start, end); assetPath = htmlText.substring(start, end);
start = end + 1; start = end + 1;
start = htmlText.indexOf("\"", start) + 1; start = htmlText.indexOf("\"", start) + 1;
end = htmlText.indexOf("\"", start); end = htmlText.indexOf("\"", start);

View File

@@ -1020,6 +1020,27 @@ WV_Info_GetAudioBitrate(WVSession *session, unsigned long *bitRate);
CLIENT_API WVStatus CLIENT_API WVStatus
WV_Info_CurrentBandwidth(WVSession *session, unsigned long *bandwidth); WV_Info_CurrentBandwidth(WVSession *session, unsigned long *bandwidth);
//
// METHOD: WV_Info_BytesBuffered
//
// This method retrieves information about the adaptive streaming buffer level
// for the media stream that was setup on the specified session.
//
// Parameters:
// [in] session - The session to query
//
// [out] bytesBuffered - The number of bytes currently queued in the adaptive
// streaming buffer
//
// Returns:
// WV_Status_OK on success, otherwise one of the WVStatus values
// indicating the specific error.
//
CLIENT_API WVStatus
WV_Info_BytesBuffered(WVSession *session, unsigned long long *bytesBuffered);
// //
// METHOD: WV_Info_GetAdaptiveBitrates // METHOD: WV_Info_GetAdaptiveBitrates
// //

View File

@@ -8,13 +8,14 @@ LOCAL_SRC_FILES:= \
WVMLogging.cpp \ WVMLogging.cpp \
WVMExtractorImpl.cpp \ WVMExtractorImpl.cpp \
WVMFileSource.cpp \ WVMFileSource.cpp \
WVMMediaSource.cpp \ WVMMediaSource.cpp \
WVMInfoListener.cpp WVMInfoListener.cpp
LOCAL_C_INCLUDES:= \ LOCAL_C_INCLUDES:= \
bionic \ bionic \
bionic/libstdc++ \ bionic/libstdc++ \
external/stlport/stlport \ external/stlport/stlport \
frameworks/base/media/libstagefright/include \
vendor/widevine/proprietary/streamcontrol/include \ vendor/widevine/proprietary/streamcontrol/include \
vendor/widevine/proprietary/wvm/include vendor/widevine/proprietary/wvm/include

View File

@@ -76,7 +76,7 @@ static int _cb2(char *in, char *out, int length, char *iv)
namespace android { namespace android {
// DLL entry - construct an extractor and return it // DLL entry - construct an extractor and return it
MediaExtractor *GetInstance(sp<DataSource> dataSource) { WVMLoadableExtractor *GetInstance(sp<DataSource> dataSource) {
return new WVMExtractorImpl(dataSource); return new WVMExtractorImpl(dataSource);
} }
@@ -84,6 +84,8 @@ WVMExtractorImpl::WVMExtractorImpl(sp<DataSource> dataSource)
: mFileMetaData(new MetaData()), : mFileMetaData(new MetaData()),
mDataSource(dataSource), mDataSource(dataSource),
mHaveMetaData(false), mHaveMetaData(false),
mUseAdaptiveStreaming(false),
mIsLiveStream(false),
mSession(NULL), mSession(NULL),
mSetupStatus(OK) mSetupStatus(OK)
{ {
@@ -102,12 +104,16 @@ WVMExtractorImpl::WVMExtractorImpl(sp<DataSource> dataSource)
} else } else
mSetupStatus = ERROR_NO_LICENSE; mSetupStatus = ERROR_NO_LICENSE;
WVCredentials credentials;
// Set an info listener to handle messages from the drm plugin // Set an info listener to handle messages from the drm plugin
mInfoListener = new WVMInfoListener(); mInfoListener = new WVMInfoListener();
sDrmManagerClient->setOnInfoListener(mInfoListener); sDrmManagerClient->setOnInfoListener(mInfoListener);
}
void WVMExtractorImpl::Initialize()
{
//LOGD("WVMExtractorImpl::Initialize(%d)\n", getAdaptiveStreamingMode());
WVCredentials credentials;
WVStatus result = WV_Initialize(NULL); WVStatus result = WV_Initialize(NULL);
if (result != WV_Status_OK) { if (result != WV_Status_OK) {
@@ -117,10 +123,20 @@ WVMExtractorImpl::WVMExtractorImpl(sp<DataSource> dataSource)
// Enable for debugging HTTP messages // Enable for debugging HTTP messages
// WV_SetLogging(WV_Logging_HTTP); // WV_SetLogging(WV_Logging_HTTP);
mFileSource = new WVMFileSource(dataSource); if (mDataSource->getUri().size() > 0 && getAdaptiveStreamingMode()) {
result = WV_Setup(mSession, mFileSource.get(), // Use the URI - streaming case, only for widevine:// protocol
"RAW/RAW/RAW;destination=getdata", credentials, result = WV_Setup(mSession, mDataSource->getUri().string(),
WV_OutputFormat_ES, kStreamCacheSize); "RAW/RAW/RAW;destination=getdata", credentials,
WV_OutputFormat_ES, kStreamCacheSize);
mIsLiveStream = (mDataSource->getUri().getPathExtension().find(".m3u8") == 0);
} else {
// No URI supplied or not adaptive, pull data from the stagefright data source.
mFileSource = new WVMFileSource(mDataSource);
result = WV_Setup(mSession, mFileSource.get(),
"RAW/RAW/RAW;destination=getdata", credentials,
WV_OutputFormat_ES, kStreamCacheSize);
}
if (result != WV_Status_OK) { if (result != WV_Status_OK) {
LOGE("WV_Setup returned status %d in WVMMediaSource::start\n", result); LOGE("WV_Setup returned status %d in WVMMediaSource::start\n", result);
@@ -152,6 +168,8 @@ status_t WVMExtractorImpl::readMetaData()
if (mHaveMetaData) if (mHaveMetaData)
return OK; return OK;
Initialize();
if (mSetupStatus != OK) if (mSetupStatus != OK)
return mSetupStatus; return mSetupStatus;
@@ -162,11 +180,11 @@ status_t WVMExtractorImpl::readMetaData()
unsigned short level; unsigned short level;
unsigned short width, height; unsigned short width, height;
float aspect, frameRate; float aspect, frameRate;
unsigned long bitRate; unsigned long videoBitRate;
WVStatus result = WV_Info_GetVideoConfiguration(mSession, &videoType, &videoStreamID, WVStatus result = WV_Info_GetVideoConfiguration(mSession, &videoType, &videoStreamID,
&videoProfile, &level, &width, &height, &videoProfile, &level, &width, &height,
&aspect, &frameRate, &bitRate); &aspect, &frameRate, &videoBitRate);
if (result != WV_Status_OK) if (result != WV_Status_OK)
return ERROR_MALFORMED; return ERROR_MALFORMED;
@@ -176,15 +194,21 @@ status_t WVMExtractorImpl::readMetaData()
unsigned short audioProfile; unsigned short audioProfile;
unsigned short numChannels; unsigned short numChannels;
unsigned long sampleRate; unsigned long sampleRate;
unsigned long audioBitRate;
result = WV_Info_GetAudioConfiguration(mSession, &audioType, &audioStreamID, &audioProfile, result = WV_Info_GetAudioConfiguration(mSession, &audioType, &audioStreamID, &audioProfile,
&numChannels, &sampleRate, &bitRate); &numChannels, &sampleRate, &audioBitRate);
if (result != WV_Status_OK) if (result != WV_Status_OK)
return ERROR_MALFORMED; return ERROR_MALFORMED;
std::string durationString = WV_Info_GetDuration(mSession, "sec"); std::string durationString = WV_Info_GetDuration(mSession, "sec");
if (durationString == "") { if (durationString == "") {
return ERROR_MALFORMED; // We won't have a duration for live streams, and Stagefright doesn't seem to
// have a way to represent that. Give a default duration of 1 hour for now.
if (mIsLiveStream)
durationString = "3600";
else
return ERROR_MALFORMED;
} }
int64_t duration = (int64_t)(strtod(durationString.c_str(), NULL) * 1000000); int64_t duration = (int64_t)(strtod(durationString.c_str(), NULL) * 1000000);
@@ -195,6 +219,9 @@ status_t WVMExtractorImpl::readMetaData()
audioMetaData->setInt64(kKeyDuration, duration); audioMetaData->setInt64(kKeyDuration, duration);
videoMetaData->setInt64(kKeyDuration, duration); videoMetaData->setInt64(kKeyDuration, duration);
audioMetaData->setInt32(kKeyBitRate, audioBitRate);
videoMetaData->setInt32(kKeyBitRate, videoBitRate);
switch(videoType) { switch(videoType) {
case WV_VideoType_H264: case WV_VideoType_H264:
videoMetaData->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); videoMetaData->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
@@ -406,5 +433,61 @@ sp<MetaData> WVMExtractorImpl::getMetaData() {
return mFileMetaData; return mFileMetaData;
} }
int64_t WVMExtractorImpl::getCachedDurationUs(status_t *finalStatus) {
const size_t kMaxEncodedRates = 10;
unsigned long encodedRates[kMaxEncodedRates];
size_t ratesReturned, currentTrack;
uint64_t durationUs = 0;
WVStatus status = WV_Info_GetAdaptiveBitrates(mSession, encodedRates, kMaxEncodedRates,
&ratesReturned, &currentTrack);
if (status == WV_Status_OK) {
if (currentTrack == kMaxEncodedRates || ratesReturned == 0) {
*finalStatus = ERROR_IO;
} else {
unsigned long long bytesBuffered;
status = WV_Info_BytesBuffered(mSession, &bytesBuffered);
if (status == WV_Status_OK) {
*finalStatus = OK;
durationUs = 8000000LL * bytesBuffered / encodedRates[currentTrack];
} else if (status == WV_Status_End_Of_Media) {
*finalStatus = ERROR_END_OF_STREAM;
}
// Log the current adaptive rate every 5 seconds
// FIXME: need to see if there is a way to send this info to the app
time_t now = time(0);
static time_t lastLogTime = now;
if (now > lastLogTime + 5) {
lastLogTime = now;
LOGI("using adaptive track #%d, rate=%ld\n",
currentTrack, encodedRates[currentTrack]);
}
}
} else {
*finalStatus = ERROR_IO;
}
// Scale the duration to account for Stagefright's conservative buffering.
// This provides much more responsive operation and due to the ability to
// adapt, we don't need to prebuffer so much data. Based on testing, 2x
// is a reasonable compromise between faster startup time and additional
// pauses after playback starts.
return durationUs * 2;
}
void WVMExtractorImpl::setAdaptiveStreamingMode(bool adaptive)
{
//LOGD("WVMExtractorImpl::setAdaptiveStreamingMode(%d)", adaptive);
mUseAdaptiveStreaming = adaptive;
}
bool WVMExtractorImpl::getAdaptiveStreamingMode() const
{
//LOGD("WVMExtractorImpl::getAdaptiveStreamingMode - %d", mUseAdaptiveStreaming);
return mUseAdaptiveStreaming;
}
} // namespace android } // namespace android

View File

@@ -21,7 +21,7 @@
#include "AndroidConfig.h" #include "AndroidConfig.h"
#include "WVStreamControlAPI.h" #include "WVStreamControlAPI.h"
#include "WVMInfoListener.h" #include "WVMInfoListener.h"
#include <media/stagefright/MediaExtractor.h> #include "WVMExtractor.h"
#include <media/stagefright/DataSource.h> #include <media/stagefright/DataSource.h>
#include <utils/RefBase.h> #include <utils/RefBase.h>
@@ -30,13 +30,13 @@
namespace android { namespace android {
MediaExtractor *GetInstance(sp<DataSource> dataSource); WVMLoadableExtractor *GetInstance(sp<DataSource> dataSource);
class WVMMediaSource; class WVMMediaSource;
class WVMFileSource; class WVMFileSource;
class WVMExtractorImpl : public MediaExtractor { class WVMExtractorImpl : public WVMLoadableExtractor {
public: public:
WVMExtractorImpl(sp<DataSource> dataSource); WVMExtractorImpl(sp<DataSource> dataSource);
@@ -45,11 +45,15 @@ public:
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags); virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData(); virtual sp<MetaData> getMetaData();
virtual int64_t getCachedDurationUs(status_t *finalStatus);
virtual void setAdaptiveStreamingMode(bool adaptive);
bool getAdaptiveStreamingMode() const;
static void cleanup(); static void cleanup();
protected: protected:
virtual ~WVMExtractorImpl(); virtual ~WVMExtractorImpl();
void Initialize();
private: private:
status_t readAVCCMetaData(sp<MetaData> videoMetaData); status_t readAVCCMetaData(sp<MetaData> videoMetaData);
@@ -63,6 +67,9 @@ private:
sp<WVMInfoListener> mInfoListener; sp<WVMInfoListener> mInfoListener;
bool mHaveMetaData; bool mHaveMetaData;
bool mUseAdaptiveStreaming;
bool mIsLiveStream;
bool mAdaptivePrefetching;
WVSession *mSession; WVSession *mSession;