Initial import of Widevine Common Encryption DRM engine

Builds libwvmdrmengine.so, which is loaded by the new
MediaDrm APIs to support playback of Widevine/CENC
protected content.

Change-Id: I6f57dd37083dfd96c402cb9dd137c7d74edc8f1c
This commit is contained in:
Jeff Tinker
2013-03-21 17:39:02 -07:00
parent 38334efbe7
commit 1a8aa0dd05
211 changed files with 51913 additions and 144 deletions

View File

@@ -0,0 +1,15 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := MediaDrmAPITest
LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.widevine.test"
>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-sdk android:minSdkVersion="12"></uses-sdk>
<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@android:style/Theme.Holo.NoActionBar">
<activity android:name="MediaDrmAPITest"
android:label="@string/app_name"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,2 @@
# Project target.
target=android-IceCreamSandwich

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
</TabHost>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">MediaDrmAPI Test</string>
</resources>

View File

@@ -0,0 +1,173 @@
/*
* (c)Copyright 2011 Widevine Technologies, Inc
*/
package com.widevine.test;
import android.app.TabActivity;
import android.os.Bundle;
import android.os.AsyncTask;
import android.media.MediaDrm;
import android.util.Log;
import java.util.concurrent.TimeUnit;
import java.util.UUID;
import java.util.Arrays;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
public class MediaDrmAPITest extends TabActivity {
private final String TAG = "MediaDrmAPITest";
private class PostRequestTask extends AsyncTask<String, Void, Void> {
private byte[] mDrmRequest;
private byte[] mResponseBody;
public PostRequestTask(byte[] drmRequest) {
mDrmRequest = drmRequest;
}
protected Void doInBackground(String... urls) {
mResponseBody = postRequest(urls[0], mDrmRequest);
Log.d(TAG, "response length=" + mResponseBody.length);
return null;
}
public byte[] getResponseBody() {
return mResponseBody;
}
}
private byte[] postRequest(String url, byte[] drmRequest) {
Log.d(TAG, "PostRequest url=" + url);
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
try {
// Add data
ByteArrayEntity entity = new ByteArrayEntity(drmRequest);
entity.setChunked(true);
httppost.setEntity(entity);
httppost.setHeader("User-Agent", "Widevine CDM v1.0");
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
byte[] responseBody;
int responseCode = response.getStatusLine().getStatusCode();
if (responseCode == 200) {
responseBody = EntityUtils.toByteArray(response.getEntity());
} else {
Log.d(TAG, "Server returned HTTP error code " + responseCode);
return null;
}
return responseBody;
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static byte[] hexToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
// validate the response body and return the drmResponse blob
private byte[] parseResponseBody(byte[] responseBody) {
String bodyString = null;
try {
bodyString = new String(responseBody, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (bodyString == null) {
return null;
}
if (!bodyString.startsWith("GLS/")) {
Log.e(TAG, "Invalid response from server, expected GLS/");
return null;
}
if (!bodyString.startsWith("GLS/1.")) {
Log.e(TAG, "Invalid server version, expected 1.x");
return null;
}
int drmMessageOffset = bodyString.indexOf("\r\n\r\n");
if (drmMessageOffset == -1) {
Log.e(TAG, "Invalid server response, could not locate drm message");
return null;
}
return Arrays.copyOfRange(responseBody, drmMessageOffset + 4, responseBody.length);
}
static final UUID kWidevineScheme = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
static final String kClientAuth = "?source=YOUTUBE&video_id=EGHC6OHNbOo&oauth=ya.gtsqawidevine";
static final String kServerUrl = "https://jmt17.google.com/video-dev/license/GetCencLicense";
static final String kPort = "80";
static final byte[] kKeyId = hexToByteArray(// blob size and pssh
"000000347073736800000000" +
// Widevine system id
"edef8ba979d64acea3c827dcd51d21ed00000014" +
// pssh data
"08011210e02562e04cd55351b14b3d748d36ed8e");
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
MediaDrm drm = new MediaDrm(kWidevineScheme);
byte[] sessionId = drm.openSession();
MediaDrm.LicenseRequest drmRequest;
drmRequest = drm.getLicenseRequest(sessionId, kKeyId, "video/mp4",
MediaDrm.MEDIA_DRM_LICENSE_TYPE_STREAMING, null);
PostRequestTask postTask = new PostRequestTask(drmRequest.data);
postTask.execute(kServerUrl + ":" + kPort + kClientAuth);
// wait for post task to complete
byte[] responseBody;
long startTime = System.currentTimeMillis();
do {
responseBody = postTask.getResponseBody();
} while (responseBody == null && System.currentTimeMillis() - startTime < 5000);
if (responseBody == null) {
Log.d(TAG, "No response from license server!");
} else {
byte[] drmResponse = parseResponseBody(responseBody);
drm.provideLicenseResponse(sessionId, drmResponse);
drm.closeSession(sessionId);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}