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,
// the default L3.
scoped_ptr<MediaDrmBridge> drm_bridge(
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());
}
......@@ -543,7 +547,7 @@ void BrowserMediaPlayerManager::OnSetMediaKeys(int player_id,
MediaPlayerAndroid* player = GetPlayer(player_id);
MediaDrmBridge* drm_bridge = GetDrmBridge(media_keys_id);
if (!player || !drm_bridge) {
NOTREACHED() << "OnSetMediaKeys(): Player and MediaKeys must be present.";
DVLOG(1) << "OnSetMediaKeys(): Player and MediaKeys must be present.";
return;
}
// TODO(qinmin): add the logic to decide whether we should create the
......
......@@ -399,7 +399,7 @@ void AndroidVideoDecodeAccelerator::Flush() {
bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() {
DCHECK(surface_texture_.get());
media_codec_.reset(media::VideoCodecBridge::Create(codec_));
media_codec_.reset(media::VideoCodecBridge::Create(codec_, false));
if (!media_codec_)
return false;
......
......@@ -141,7 +141,8 @@ class MediaCodecBridge {
private static MediaCodecBridge create(String mime, boolean isSecure) {
MediaCodec mediaCodec = null;
try {
if (isSecure) {
// |isSecure| only applies to video decoders.
if (mime.startsWith("video") && isSecure) {
mediaCodec = MediaCodec.createByCodecName(getSecureDecoderNameForMime(mime));
} else {
mediaCodec = MediaCodec.createDecoderByType(mime);
......
......@@ -59,20 +59,18 @@ class MediaDrmBridge {
return new UUID(mostSigBits, leastSigBits);
}
private MediaDrmBridge(UUID schemeUUID, String securityLevel, int nativeMediaDrmBridge) {
try {
private MediaDrmBridge(UUID schemeUUID, String securityLevel, int nativeMediaDrmBridge)
throws android.media.UnsupportedSchemeException {
mSchemeUUID = schemeUUID;
mMediaDrm = new MediaDrm(schemeUUID);
mHandler = new Handler();
mNativeMediaDrmBridge = nativeMediaDrmBridge;
mMediaDrm.setOnEventListener(new MediaDrmListener());
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);
} 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,12 +144,23 @@ class MediaDrmBridge {
private static MediaDrmBridge create(
byte[] schemeUUID, String securityLevel, int nativeMediaDrmBridge) {
UUID cryptoScheme = getUUIDFromBytes(schemeUUID);
if (cryptoScheme != null && MediaDrm.isCryptoSchemeSupported(cryptoScheme)) {
return new MediaDrmBridge(cryptoScheme, securityLevel, nativeMediaDrmBridge);
}
if (cryptoScheme == null || !MediaDrm.isCryptoSchemeSupported(cryptoScheme)) {
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;
}
/**
* Return the MediaCrypto object if available.
*/
......@@ -167,6 +176,7 @@ class MediaDrmBridge {
private void release() {
if (mMediaCrypto != null) {
mMediaCrypto.release();
mMediaCrypto = null;
}
if (mSessionId != null) {
try {
......@@ -175,10 +185,13 @@ class MediaDrmBridge {
} catch (java.io.UnsupportedEncodingException e) {
Log.e(TAG, "Failed to close session: " + e.toString());
}
mSessionId = null;
}
if (mMediaDrm != null) {
mMediaDrm.release();
mMediaDrm = null;
}
}
/**
* Generate a key request and post an asynchronous task to the native side
......@@ -329,6 +342,10 @@ class MediaDrmBridge {
Log.e(TAG, "failed to provide provision response: " + e.toString());
onKeyError();
return;
} catch (java.lang.IllegalStateException e) {
Log.e(TAG, "failed to provide provision response: " + e.toString());
onKeyError();
return;
}
if (mPendingInitData != null) {
......
......@@ -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();
}
// TODO(xhwang): Support creating secure MediaCodecBridge.
MediaCodecBridge::MediaCodecBridge(const std::string& mime) {
MediaCodecBridge::MediaCodecBridge(const std::string& mime, bool is_secure) {
JNIEnv* env = AttachCurrentThread();
CHECK(env);
DCHECK(!mime.empty());
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() {
......@@ -243,7 +243,8 @@ size_t MediaCodecBridge::FillInputBuffer(
}
AudioCodecBridge::AudioCodecBridge(const std::string& mime)
: MediaCodecBridge(mime) {
// Audio codec doesn't care about security level.
: MediaCodecBridge(mime, false) {
}
bool AudioCodecBridge::Start(
......@@ -401,8 +402,8 @@ void AudioCodecBridge::SetVolume(double volume) {
Java_MediaCodecBridge_setVolume(env, media_codec(), volume);
}
VideoCodecBridge::VideoCodecBridge(const std::string& mime)
: MediaCodecBridge(mime) {
VideoCodecBridge::VideoCodecBridge(const std::string& mime, bool is_secure)
: MediaCodecBridge(mime, is_secure) {
}
bool VideoCodecBridge::Start(
......@@ -436,9 +437,10 @@ AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec codec) {
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);
return mime.empty() ? NULL : new VideoCodecBridge(mime);
return mime.empty() ? NULL : new VideoCodecBridge(mime, is_secure);
}
bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) {
......
......@@ -123,7 +123,7 @@ class MEDIA_EXPORT MediaCodecBridge {
static bool RegisterMediaCodecBridge(JNIEnv* env);
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
// configuring media codec.
......@@ -171,7 +171,7 @@ class MEDIA_EXPORT VideoCodecBridge : public MediaCodecBridge {
public:
// Returns an VideoCodecBridge instance if |codec| is supported, or a NULL
// pointer otherwise.
static VideoCodecBridge* Create(const VideoCodec codec);
static VideoCodecBridge* Create(const VideoCodec codec, bool is_secure);
// Start the video codec bridge.
// TODO(qinmin): Pass codec specific data if available.
......@@ -179,7 +179,7 @@ class MEDIA_EXPORT VideoCodecBridge : public MediaCodecBridge {
jobject media_crypto);
private:
explicit VideoCodecBridge(const std::string& mime);
VideoCodecBridge(const std::string& mime, bool is_secure);
};
} // namespace media
......
......@@ -136,7 +136,7 @@ TEST(MediaCodecBridgeTest, Initialize) {
return;
scoped_ptr<media::MediaCodecBridge> media_codec;
media_codec.reset(VideoCodecBridge::Create(kCodecH264));
media_codec.reset(VideoCodecBridge::Create(kCodecH264, false));
}
TEST(MediaCodecBridgeTest, DoNormal) {
......@@ -235,7 +235,7 @@ TEST(MediaCodecBridgeTest, PresentationTimestampsDoNotDecrease) {
return;
scoped_ptr<VideoCodecBridge> media_codec;
media_codec.reset(VideoCodecBridge::Create(kCodecVP8));
media_codec.reset(VideoCodecBridge::Create(kCodecVP8, false));
EXPECT_TRUE(media_codec->Start(
kCodecVP8, gfx::Size(320, 240), NULL, NULL));
scoped_refptr<DecoderBuffer> buffer =
......@@ -263,7 +263,7 @@ TEST(MediaCodecBridgeTest, PresentationTimestampsDoNotDecrease) {
TEST(MediaCodecBridgeTest, CreateUnsupportedCodec) {
EXPECT_EQ(NULL, AudioCodecBridge::Create(kUnknownAudioCodec));
EXPECT_EQ(NULL, VideoCodecBridge::Create(kUnknownVideoCodec));
EXPECT_EQ(NULL, VideoCodecBridge::Create(kUnknownVideoCodec, false));
}
} // namespace media
......@@ -152,16 +152,22 @@ static MediaDrmBridge::SecurityLevel GetSecurityLevelFromString(
}
// static
MediaDrmBridge* MediaDrmBridge::Create(int media_keys_id,
scoped_ptr<MediaDrmBridge> MediaDrmBridge::Create(
int media_keys_id,
const std::vector<uint8>& scheme_uuid,
const std::string& security_level,
MediaPlayerManager* manager) {
if (!IsAvailable() || scheme_uuid.empty())
return NULL;
scoped_ptr<MediaDrmBridge> media_drm_bridge;
if (IsAvailable() && !scheme_uuid.empty()) {
// TODO(qinmin): check whether the uuid is valid.
return new MediaDrmBridge(
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
......@@ -213,6 +219,7 @@ MediaDrmBridge::MediaDrmBridge(int media_keys_id,
MediaDrmBridge::~MediaDrmBridge() {
JNIEnv* env = AttachCurrentThread();
if (!j_media_drm_.is_null())
Java_MediaDrmBridge_release(env, j_media_drm_.obj());
}
......
......@@ -11,6 +11,7 @@
#include "base/android/scoped_java_ref.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/media_export.h"
#include "media/base/media_keys.h"
......@@ -32,7 +33,8 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys {
// Returns a MediaDrmBridge instance if |scheme_uuid| is supported, or a NULL
// pointer otherwise.
static MediaDrmBridge* Create(int media_keys_id,
static scoped_ptr<MediaDrmBridge> Create(
int media_keys_id,
const std::vector<uint8>& scheme_uuid,
const std::string& security_level,
MediaPlayerManager* manager);
......
......@@ -587,8 +587,12 @@ void MediaSourcePlayer::ConfigureVideoDecoderJob() {
// Android does not allow 2 MediaCodec instances use the same surface.
video_decoder_job_.reset();
// Create the new VideoDecoderJob.
video_decoder_job_.reset(VideoDecoderJob::Create(
video_codec_, gfx::Size(width_, height_), surface_.j_surface().obj(),
bool is_secure = IsProtectedSurfaceRequired();
video_decoder_job_.reset(
VideoDecoderJob::Create(video_codec_,
is_secure,
gfx::Size(width_, height_),
surface_.j_surface().obj(),
media_crypto.obj(),
base::Bind(&MediaPlayerManager::OnReadFromDemuxer,
base::Unretained(manager()),
......
......@@ -24,11 +24,14 @@ class VideoDecoderThread : public base::Thread {
base::LazyInstance<VideoDecoderThread>::Leaky
g_video_decoder_thread = LAZY_INSTANCE_INITIALIZER;
VideoDecoderJob* VideoDecoderJob::Create(
const VideoCodec video_codec, const gfx::Size& size, jobject surface,
jobject media_crypto, const base::Closure& request_data_cb) {
scoped_ptr<VideoCodecBridge> codec(VideoCodecBridge::Create(video_codec));
VideoDecoderJob* VideoDecoderJob::Create(const VideoCodec video_codec,
bool is_secure,
const gfx::Size& size,
jobject surface,
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))
return new VideoDecoderJob(codec.Pass(), request_data_cb);
return NULL;
......
......@@ -20,14 +20,18 @@ class VideoDecoderJob : public MediaDecoderJob {
// Create a new VideoDecoderJob instance.
// |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.
// |media_crypto| - Handle to a Java object responsible for decrypting the
// video data.
// |request_data_cb| - Callback used to request more data for the decoder.
static VideoDecoderJob* Create(
const VideoCodec video_codec, const gfx::Size& size, jobject surface,
jobject media_crypto, const base::Closure& request_data_cb);
static VideoDecoderJob* Create(const VideoCodec video_codec,
bool is_secure,
const gfx::Size& size,
jobject surface,
jobject media_crypto,
const base::Closure& request_data_cb);
private:
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