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 "license expired"" into honeycomb-mr2
This commit is contained in:
committed by
Android (Google) Code Review
commit
8c5545ef76
Binary file not shown.
@@ -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);
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
//
|
//
|
||||||
|
|||||||
Binary file not shown.
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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_DRM_NO_LICENSE;
|
mSetupStatus = ERROR_DRM_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);
|
||||||
@@ -144,6 +160,8 @@ status_t WVMExtractorImpl::readMetaData()
|
|||||||
if (mHaveMetaData)
|
if (mHaveMetaData)
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
|
Initialize();
|
||||||
|
|
||||||
if (mSetupStatus != OK)
|
if (mSetupStatus != OK)
|
||||||
return mSetupStatus;
|
return mSetupStatus;
|
||||||
|
|
||||||
@@ -154,11 +172,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;
|
||||||
|
|
||||||
@@ -168,15 +186,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);
|
||||||
@@ -187,6 +211,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);
|
||||||
@@ -398,5 +425,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, ¤tTrack);
|
||||||
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -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,9 +45,13 @@ 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;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~WVMExtractorImpl();
|
virtual ~WVMExtractorImpl();
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t readAVCCMetaData(sp<MetaData> videoMetaData);
|
status_t readAVCCMetaData(sp<MetaData> videoMetaData);
|
||||||
@@ -61,6 +65,9 @@ private:
|
|||||||
sp<WVMInfoListener> mInfoListener;
|
sp<WVMInfoListener> mInfoListener;
|
||||||
|
|
||||||
bool mHaveMetaData;
|
bool mHaveMetaData;
|
||||||
|
bool mUseAdaptiveStreaming;
|
||||||
|
bool mIsLiveStream;
|
||||||
|
bool mAdaptivePrefetching;
|
||||||
|
|
||||||
WVSession *mSession;
|
WVSession *mSession;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user