Commit d04658e1 authored by xhwang@chromium.org's avatar xhwang@chromium.org

Support creating secure decoder in MediaCodecBridge.

BUG=163552
TEST=L1 doesn't fully work due to mediaDrm issues. L3 still works well.

Review URL: https://chromiumcodereview.appspot.com/23480036

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221906 0039d316-1c4b-4281-b951-d872f2087c98
parent 6e463eb8
...@@ -524,7 +524,11 @@ void BrowserMediaPlayerManager::AddDrmBridge(int media_keys_id, ...@@ -524,7 +524,11 @@ void BrowserMediaPlayerManager::AddDrmBridge(int media_keys_id,
// the default L3. // the default L3.
scoped_ptr<MediaDrmBridge> drm_bridge( scoped_ptr<MediaDrmBridge> drm_bridge(
MediaDrmBridge::Create(media_keys_id, uuid, "L3", this)); MediaDrmBridge::Create(media_keys_id, uuid, "L3", this));
DCHECK(drm_bridge) << "failed to create drm bridge. "; if (!drm_bridge) {
DVLOG(1) << "failed to create drm bridge.";
return;
}
drm_bridges_.push_back(drm_bridge.release()); drm_bridges_.push_back(drm_bridge.release());
} }
...@@ -543,7 +547,7 @@ void BrowserMediaPlayerManager::OnSetMediaKeys(int player_id, ...@@ -543,7 +547,7 @@ void BrowserMediaPlayerManager::OnSetMediaKeys(int player_id,
MediaPlayerAndroid* player = GetPlayer(player_id); MediaPlayerAndroid* player = GetPlayer(player_id);
MediaDrmBridge* drm_bridge = GetDrmBridge(media_keys_id); MediaDrmBridge* drm_bridge = GetDrmBridge(media_keys_id);
if (!player || !drm_bridge) { if (!player || !drm_bridge) {
NOTREACHED() << "OnSetMediaKeys(): Player and MediaKeys must be present."; DVLOG(1) << "OnSetMediaKeys(): Player and MediaKeys must be present.";
return; return;
} }
// TODO(qinmin): add the logic to decide whether we should create the // TODO(qinmin): add the logic to decide whether we should create the
......
...@@ -399,7 +399,7 @@ void AndroidVideoDecodeAccelerator::Flush() { ...@@ -399,7 +399,7 @@ void AndroidVideoDecodeAccelerator::Flush() {
bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() { bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() {
DCHECK(surface_texture_.get()); DCHECK(surface_texture_.get());
media_codec_.reset(media::VideoCodecBridge::Create(codec_)); media_codec_.reset(media::VideoCodecBridge::Create(codec_, false));
if (!media_codec_) if (!media_codec_)
return false; return false;
......
...@@ -141,7 +141,8 @@ class MediaCodecBridge { ...@@ -141,7 +141,8 @@ class MediaCodecBridge {
private static MediaCodecBridge create(String mime, boolean isSecure) { private static MediaCodecBridge create(String mime, boolean isSecure) {
MediaCodec mediaCodec = null; MediaCodec mediaCodec = null;
try { try {
if (isSecure) { // |isSecure| only applies to video decoders.
if (mime.startsWith("video") && isSecure) {
mediaCodec = MediaCodec.createByCodecName(getSecureDecoderNameForMime(mime)); mediaCodec = MediaCodec.createByCodecName(getSecureDecoderNameForMime(mime));
} else { } else {
mediaCodec = MediaCodec.createDecoderByType(mime); mediaCodec = MediaCodec.createDecoderByType(mime);
......
...@@ -59,20 +59,18 @@ class MediaDrmBridge { ...@@ -59,20 +59,18 @@ class MediaDrmBridge {
return new UUID(mostSigBits, leastSigBits); return new UUID(mostSigBits, leastSigBits);
} }
private MediaDrmBridge(UUID schemeUUID, String securityLevel, int nativeMediaDrmBridge) { private MediaDrmBridge(UUID schemeUUID, String securityLevel, int nativeMediaDrmBridge)
try { throws android.media.UnsupportedSchemeException {
mSchemeUUID = schemeUUID; mSchemeUUID = schemeUUID;
mMediaDrm = new MediaDrm(schemeUUID); mMediaDrm = new MediaDrm(schemeUUID);
mHandler = new Handler(); mHandler = new Handler();
mNativeMediaDrmBridge = nativeMediaDrmBridge; mNativeMediaDrmBridge = nativeMediaDrmBridge;
mMediaDrm.setOnEventListener(new MediaDrmListener()); mMediaDrm.setOnEventListener(new MediaDrmListener());
mMediaDrm.setPropertyString(PRIVACY_MODE, "enable"); mMediaDrm.setPropertyString(PRIVACY_MODE, "enable");
String currentSecurityLevel = mMediaDrm.getPropertyString(SECURITY_LEVEL);
Log.e(TAG, "Security level: current " + currentSecurityLevel + ", new " + securityLevel);
if (!securityLevel.equals(currentSecurityLevel))
mMediaDrm.setPropertyString(SECURITY_LEVEL, securityLevel); mMediaDrm.setPropertyString(SECURITY_LEVEL, securityLevel);
} catch (android.media.UnsupportedSchemeException e) {
Log.e(TAG, "Unsupported DRM scheme: " + e.toString());
} catch (java.lang.IllegalArgumentException e) {
Log.e(TAG, "Failed to set DRM properties: " + e.toString());
}
} }
/** /**
...@@ -146,10 +144,21 @@ class MediaDrmBridge { ...@@ -146,10 +144,21 @@ class MediaDrmBridge {
private static MediaDrmBridge create( private static MediaDrmBridge create(
byte[] schemeUUID, String securityLevel, int nativeMediaDrmBridge) { byte[] schemeUUID, String securityLevel, int nativeMediaDrmBridge) {
UUID cryptoScheme = getUUIDFromBytes(schemeUUID); UUID cryptoScheme = getUUIDFromBytes(schemeUUID);
if (cryptoScheme != null && MediaDrm.isCryptoSchemeSupported(cryptoScheme)) { if (cryptoScheme == null || !MediaDrm.isCryptoSchemeSupported(cryptoScheme)) {
return new MediaDrmBridge(cryptoScheme, securityLevel, nativeMediaDrmBridge); return null;
} }
return null;
MediaDrmBridge media_drm_bridge = null;
try {
media_drm_bridge = new MediaDrmBridge(
cryptoScheme, securityLevel, nativeMediaDrmBridge);
} catch (android.media.UnsupportedSchemeException e) {
Log.e(TAG, "Unsupported DRM scheme: " + e.toString());
} catch (java.lang.IllegalArgumentException e) {
Log.e(TAG, "Failed to create MediaDrmBridge: " + e.toString());
}
return media_drm_bridge;
} }
/** /**
...@@ -167,6 +176,7 @@ class MediaDrmBridge { ...@@ -167,6 +176,7 @@ class MediaDrmBridge {
private void release() { private void release() {
if (mMediaCrypto != null) { if (mMediaCrypto != null) {
mMediaCrypto.release(); mMediaCrypto.release();
mMediaCrypto = null;
} }
if (mSessionId != null) { if (mSessionId != null) {
try { try {
...@@ -175,9 +185,12 @@ class MediaDrmBridge { ...@@ -175,9 +185,12 @@ class MediaDrmBridge {
} catch (java.io.UnsupportedEncodingException e) { } catch (java.io.UnsupportedEncodingException e) {
Log.e(TAG, "Failed to close session: " + e.toString()); Log.e(TAG, "Failed to close session: " + e.toString());
} }
mSessionId = null;
}
if (mMediaDrm != null) {
mMediaDrm.release();
mMediaDrm = null;
} }
mMediaDrm.release();
mMediaDrm = null;
} }
/** /**
...@@ -329,6 +342,10 @@ class MediaDrmBridge { ...@@ -329,6 +342,10 @@ class MediaDrmBridge {
Log.e(TAG, "failed to provide provision response: " + e.toString()); Log.e(TAG, "failed to provide provision response: " + e.toString());
onKeyError(); onKeyError();
return; return;
} catch (java.lang.IllegalStateException e) {
Log.e(TAG, "failed to provide provision response: " + e.toString());
onKeyError();
return;
} }
if (mPendingInitData != null) { if (mPendingInitData != null) {
......
...@@ -88,14 +88,14 @@ bool MediaCodecBridge::CanDecode(const std::string& codec, bool is_secure) { ...@@ -88,14 +88,14 @@ bool MediaCodecBridge::CanDecode(const std::string& codec, bool is_secure) {
return !Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure).is_null(); return !Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure).is_null();
} }
// TODO(xhwang): Support creating secure MediaCodecBridge. MediaCodecBridge::MediaCodecBridge(const std::string& mime, bool is_secure) {
MediaCodecBridge::MediaCodecBridge(const std::string& mime) {
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
CHECK(env); CHECK(env);
DCHECK(!mime.empty()); DCHECK(!mime.empty());
ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
j_media_codec_.Reset(Java_MediaCodecBridge_create(env, j_mime.obj(), false)); j_media_codec_.Reset(
Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure));
} }
MediaCodecBridge::~MediaCodecBridge() { MediaCodecBridge::~MediaCodecBridge() {
...@@ -243,7 +243,8 @@ size_t MediaCodecBridge::FillInputBuffer( ...@@ -243,7 +243,8 @@ size_t MediaCodecBridge::FillInputBuffer(
} }
AudioCodecBridge::AudioCodecBridge(const std::string& mime) AudioCodecBridge::AudioCodecBridge(const std::string& mime)
: MediaCodecBridge(mime) { // Audio codec doesn't care about security level.
: MediaCodecBridge(mime, false) {
} }
bool AudioCodecBridge::Start( bool AudioCodecBridge::Start(
...@@ -401,8 +402,8 @@ void AudioCodecBridge::SetVolume(double volume) { ...@@ -401,8 +402,8 @@ void AudioCodecBridge::SetVolume(double volume) {
Java_MediaCodecBridge_setVolume(env, media_codec(), volume); Java_MediaCodecBridge_setVolume(env, media_codec(), volume);
} }
VideoCodecBridge::VideoCodecBridge(const std::string& mime) VideoCodecBridge::VideoCodecBridge(const std::string& mime, bool is_secure)
: MediaCodecBridge(mime) { : MediaCodecBridge(mime, is_secure) {
} }
bool VideoCodecBridge::Start( bool VideoCodecBridge::Start(
...@@ -436,9 +437,10 @@ AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec codec) { ...@@ -436,9 +437,10 @@ AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec codec) {
return mime.empty() ? NULL : new AudioCodecBridge(mime); return mime.empty() ? NULL : new AudioCodecBridge(mime);
} }
VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec codec) { VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec codec,
bool is_secure) {
const std::string mime = VideoCodecToMimeType(codec); const std::string mime = VideoCodecToMimeType(codec);
return mime.empty() ? NULL : new VideoCodecBridge(mime); return mime.empty() ? NULL : new VideoCodecBridge(mime, is_secure);
} }
bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) {
......
...@@ -123,7 +123,7 @@ class MEDIA_EXPORT MediaCodecBridge { ...@@ -123,7 +123,7 @@ class MEDIA_EXPORT MediaCodecBridge {
static bool RegisterMediaCodecBridge(JNIEnv* env); static bool RegisterMediaCodecBridge(JNIEnv* env);
protected: protected:
explicit MediaCodecBridge(const std::string& mime); MediaCodecBridge(const std::string& mime, bool is_secure);
// Calls start() against the media codec instance. Used in StartXXX() after // Calls start() against the media codec instance. Used in StartXXX() after
// configuring media codec. // configuring media codec.
...@@ -171,7 +171,7 @@ class MEDIA_EXPORT VideoCodecBridge : public MediaCodecBridge { ...@@ -171,7 +171,7 @@ class MEDIA_EXPORT VideoCodecBridge : public MediaCodecBridge {
public: public:
// Returns an VideoCodecBridge instance if |codec| is supported, or a NULL // Returns an VideoCodecBridge instance if |codec| is supported, or a NULL
// pointer otherwise. // pointer otherwise.
static VideoCodecBridge* Create(const VideoCodec codec); static VideoCodecBridge* Create(const VideoCodec codec, bool is_secure);
// Start the video codec bridge. // Start the video codec bridge.
// TODO(qinmin): Pass codec specific data if available. // TODO(qinmin): Pass codec specific data if available.
...@@ -179,7 +179,7 @@ class MEDIA_EXPORT VideoCodecBridge : public MediaCodecBridge { ...@@ -179,7 +179,7 @@ class MEDIA_EXPORT VideoCodecBridge : public MediaCodecBridge {
jobject media_crypto); jobject media_crypto);
private: private:
explicit VideoCodecBridge(const std::string& mime); VideoCodecBridge(const std::string& mime, bool is_secure);
}; };
} // namespace media } // namespace media
......
...@@ -136,7 +136,7 @@ TEST(MediaCodecBridgeTest, Initialize) { ...@@ -136,7 +136,7 @@ TEST(MediaCodecBridgeTest, Initialize) {
return; return;
scoped_ptr<media::MediaCodecBridge> media_codec; scoped_ptr<media::MediaCodecBridge> media_codec;
media_codec.reset(VideoCodecBridge::Create(kCodecH264)); media_codec.reset(VideoCodecBridge::Create(kCodecH264, false));
} }
TEST(MediaCodecBridgeTest, DoNormal) { TEST(MediaCodecBridgeTest, DoNormal) {
...@@ -235,7 +235,7 @@ TEST(MediaCodecBridgeTest, PresentationTimestampsDoNotDecrease) { ...@@ -235,7 +235,7 @@ TEST(MediaCodecBridgeTest, PresentationTimestampsDoNotDecrease) {
return; return;
scoped_ptr<VideoCodecBridge> media_codec; scoped_ptr<VideoCodecBridge> media_codec;
media_codec.reset(VideoCodecBridge::Create(kCodecVP8)); media_codec.reset(VideoCodecBridge::Create(kCodecVP8, false));
EXPECT_TRUE(media_codec->Start( EXPECT_TRUE(media_codec->Start(
kCodecVP8, gfx::Size(320, 240), NULL, NULL)); kCodecVP8, gfx::Size(320, 240), NULL, NULL));
scoped_refptr<DecoderBuffer> buffer = scoped_refptr<DecoderBuffer> buffer =
...@@ -263,7 +263,7 @@ TEST(MediaCodecBridgeTest, PresentationTimestampsDoNotDecrease) { ...@@ -263,7 +263,7 @@ TEST(MediaCodecBridgeTest, PresentationTimestampsDoNotDecrease) {
TEST(MediaCodecBridgeTest, CreateUnsupportedCodec) { TEST(MediaCodecBridgeTest, CreateUnsupportedCodec) {
EXPECT_EQ(NULL, AudioCodecBridge::Create(kUnknownAudioCodec)); EXPECT_EQ(NULL, AudioCodecBridge::Create(kUnknownAudioCodec));
EXPECT_EQ(NULL, VideoCodecBridge::Create(kUnknownVideoCodec)); EXPECT_EQ(NULL, VideoCodecBridge::Create(kUnknownVideoCodec, false));
} }
} // namespace media } // namespace media
...@@ -152,16 +152,22 @@ static MediaDrmBridge::SecurityLevel GetSecurityLevelFromString( ...@@ -152,16 +152,22 @@ static MediaDrmBridge::SecurityLevel GetSecurityLevelFromString(
} }
// static // static
MediaDrmBridge* MediaDrmBridge::Create(int media_keys_id, scoped_ptr<MediaDrmBridge> MediaDrmBridge::Create(
const std::vector<uint8>& scheme_uuid, int media_keys_id,
const std::string& security_level, const std::vector<uint8>& scheme_uuid,
MediaPlayerManager* manager) { const std::string& security_level,
if (!IsAvailable() || scheme_uuid.empty()) MediaPlayerManager* manager) {
return NULL; scoped_ptr<MediaDrmBridge> media_drm_bridge;
// TODO(qinmin): check whether the uuid is valid. if (IsAvailable() && !scheme_uuid.empty()) {
return new MediaDrmBridge( // TODO(qinmin): check whether the uuid is valid.
media_keys_id, scheme_uuid, security_level, manager); media_drm_bridge.reset(
new MediaDrmBridge(media_keys_id, scheme_uuid, security_level, manager));
if (media_drm_bridge->j_media_drm_.is_null())
media_drm_bridge.reset();
}
return media_drm_bridge.Pass();
} }
// static // static
...@@ -213,7 +219,8 @@ MediaDrmBridge::MediaDrmBridge(int media_keys_id, ...@@ -213,7 +219,8 @@ MediaDrmBridge::MediaDrmBridge(int media_keys_id,
MediaDrmBridge::~MediaDrmBridge() { MediaDrmBridge::~MediaDrmBridge() {
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
Java_MediaDrmBridge_release(env, j_media_drm_.obj()); if (!j_media_drm_.is_null())
Java_MediaDrmBridge_release(env, j_media_drm_.obj());
} }
bool MediaDrmBridge::GenerateKeyRequest(const std::string& type, bool MediaDrmBridge::GenerateKeyRequest(const std::string& type,
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
#include "media/base/media_keys.h" #include "media/base/media_keys.h"
...@@ -32,10 +33,11 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys { ...@@ -32,10 +33,11 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys {
// Returns a MediaDrmBridge instance if |scheme_uuid| is supported, or a NULL // Returns a MediaDrmBridge instance if |scheme_uuid| is supported, or a NULL
// pointer otherwise. // pointer otherwise.
static MediaDrmBridge* Create(int media_keys_id, static scoped_ptr<MediaDrmBridge> Create(
const std::vector<uint8>& scheme_uuid, int media_keys_id,
const std::string& security_level, const std::vector<uint8>& scheme_uuid,
MediaPlayerManager* manager); const std::string& security_level,
MediaPlayerManager* manager);
// Checks whether MediaDRM is available. // Checks whether MediaDRM is available.
static bool IsAvailable(); static bool IsAvailable();
......
...@@ -587,13 +587,17 @@ void MediaSourcePlayer::ConfigureVideoDecoderJob() { ...@@ -587,13 +587,17 @@ void MediaSourcePlayer::ConfigureVideoDecoderJob() {
// Android does not allow 2 MediaCodec instances use the same surface. // Android does not allow 2 MediaCodec instances use the same surface.
video_decoder_job_.reset(); video_decoder_job_.reset();
// Create the new VideoDecoderJob. // Create the new VideoDecoderJob.
video_decoder_job_.reset(VideoDecoderJob::Create( bool is_secure = IsProtectedSurfaceRequired();
video_codec_, gfx::Size(width_, height_), surface_.j_surface().obj(), video_decoder_job_.reset(
media_crypto.obj(), VideoDecoderJob::Create(video_codec_,
base::Bind(&MediaPlayerManager::OnReadFromDemuxer, is_secure,
base::Unretained(manager()), gfx::Size(width_, height_),
player_id(), surface_.j_surface().obj(),
DemuxerStream::VIDEO))); media_crypto.obj(),
base::Bind(&MediaPlayerManager::OnReadFromDemuxer,
base::Unretained(manager()),
player_id(),
DemuxerStream::VIDEO)));
if (video_decoder_job_) if (video_decoder_job_)
reconfig_video_decoder_ = false; reconfig_video_decoder_ = false;
......
...@@ -24,11 +24,14 @@ class VideoDecoderThread : public base::Thread { ...@@ -24,11 +24,14 @@ class VideoDecoderThread : public base::Thread {
base::LazyInstance<VideoDecoderThread>::Leaky base::LazyInstance<VideoDecoderThread>::Leaky
g_video_decoder_thread = LAZY_INSTANCE_INITIALIZER; g_video_decoder_thread = LAZY_INSTANCE_INITIALIZER;
VideoDecoderJob* VideoDecoderJob::Create(const VideoCodec video_codec,
VideoDecoderJob* VideoDecoderJob::Create( bool is_secure,
const VideoCodec video_codec, const gfx::Size& size, jobject surface, const gfx::Size& size,
jobject media_crypto, const base::Closure& request_data_cb) { jobject surface,
scoped_ptr<VideoCodecBridge> codec(VideoCodecBridge::Create(video_codec)); jobject media_crypto,
const base::Closure& request_data_cb) {
scoped_ptr<VideoCodecBridge> codec(
VideoCodecBridge::Create(video_codec, is_secure));
if (codec && codec->Start(video_codec, size, surface, media_crypto)) if (codec && codec->Start(video_codec, size, surface, media_crypto))
return new VideoDecoderJob(codec.Pass(), request_data_cb); return new VideoDecoderJob(codec.Pass(), request_data_cb);
return NULL; return NULL;
......
...@@ -20,14 +20,18 @@ class VideoDecoderJob : public MediaDecoderJob { ...@@ -20,14 +20,18 @@ class VideoDecoderJob : public MediaDecoderJob {
// Create a new VideoDecoderJob instance. // Create a new VideoDecoderJob instance.
// |video_codec| - The video format the object needs to decode. // |video_codec| - The video format the object needs to decode.
// |size| - The natrual size of the output frames. // |is_secure| - Whether secure decoding is required.
// |size| - The natural size of the output frames.
// |surface| - The surface to render the frames to. // |surface| - The surface to render the frames to.
// |media_crypto| - Handle to a Java object responsible for decrypting the // |media_crypto| - Handle to a Java object responsible for decrypting the
// video data. // video data.
// |request_data_cb| - Callback used to request more data for the decoder. // |request_data_cb| - Callback used to request more data for the decoder.
static VideoDecoderJob* Create( static VideoDecoderJob* Create(const VideoCodec video_codec,
const VideoCodec video_codec, const gfx::Size& size, jobject surface, bool is_secure,
jobject media_crypto, const base::Closure& request_data_cb); const gfx::Size& size,
jobject surface,
jobject media_crypto,
const base::Closure& request_data_cb);
private: private:
VideoDecoderJob(scoped_ptr<VideoCodecBridge> video_codec_bridge, VideoDecoderJob(scoped_ptr<VideoCodecBridge> video_codec_bridge,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment