summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorapiccion@chromium.org <apiccion@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-04 06:05:21 +0000
committerapiccion@chromium.org <apiccion@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-04 06:05:21 +0000
commitc6584ac8d2e57fa5193c3203e09c13fcf270474c (patch)
treef45dd69825bab98f01ec31d1796f9fe81370ffca
parente8072568409f3d3613d10342bb6273b71fa403f2 (diff)
downloadchromium_src-c6584ac8d2e57fa5193c3203e09c13fcf270474c.zip
chromium_src-c6584ac8d2e57fa5193c3203e09c13fcf270474c.tar.gz
chromium_src-c6584ac8d2e57fa5193c3203e09c13fcf270474c.tar.bz2
Android can play data uri media items.
BUG=324713 Review URL: https://codereview.chromium.org/98563002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238595 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/renderer/media/android/media_info_loader.cc6
-rw-r--r--media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java119
-rw-r--r--media/base/android/media_player_bridge.cc30
-rw-r--r--media/base/android/media_player_bridge.h1
4 files changed, 143 insertions, 13 deletions
diff --git a/content/renderer/media/android/media_info_loader.cc b/content/renderer/media/android/media_info_loader.cc
index ea93304..875265c 100644
--- a/content/renderer/media/android/media_info_loader.cc
+++ b/content/renderer/media/android/media_info_loader.cc
@@ -111,7 +111,11 @@ void MediaInfoLoader::didReceiveResponse(
"Unknown")
<< " " << response.httpStatusCode();
DCHECK(active_loader_.get());
- if (response.httpStatusCode() == kHttpOK || url_.SchemeIsFile()) {
+ if (!url_.SchemeIs("http") && !url_.SchemeIs("https")) {
+ DidBecomeReady(kOk);
+ return;
+ }
+ if (response.httpStatusCode() == kHttpOK) {
DidBecomeReady(kOk);
return;
}
diff --git a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
index fe9407d..1a8f61a 100644
--- a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,22 +7,26 @@ package org.chromium.media;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
+import android.os.AsyncTask;
import android.text.TextUtils;
+import android.util.Base64;
import android.util.Log;
import android.view.Surface;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
-import java.util.Map;
-// A wrapper around android.media.MediaPlayer that allows the native code to use it.
-// See media/base/android/media_player_bridge.cc for the corresponding native code.
+/**
+* A wrapper around android.media.MediaPlayer that allows the native code to use it.
+* See media/base/android/media_player_bridge.cc for the corresponding native code.
+*/
@JNINamespace("media")
public class MediaPlayerBridge {
@@ -30,11 +34,29 @@ public class MediaPlayerBridge {
// Local player to forward this to. We don't initialize it here since the subclass might not
// want it.
+ private LoadDataUriTask mLoadDataUriTask;
private MediaPlayer mPlayer;
+ private long mNativeMediaPlayerBridge;
@CalledByNative
- private static MediaPlayerBridge create() {
- return new MediaPlayerBridge();
+ private static MediaPlayerBridge create(long nativeMediaPlayerBridge) {
+ return new MediaPlayerBridge(nativeMediaPlayerBridge);
+ }
+
+ protected MediaPlayerBridge(long nativeMediaPlayerBridge) {
+ mNativeMediaPlayerBridge = nativeMediaPlayerBridge;
+ }
+
+ protected MediaPlayerBridge() {
+ }
+
+ @CalledByNative
+ protected void destroy() {
+ if (mLoadDataUriTask != null) {
+ mLoadDataUriTask.cancel(true);
+ mLoadDataUriTask = null;
+ }
+ mNativeMediaPlayerBridge = 0;
}
protected MediaPlayer getLocalPlayer() {
@@ -115,10 +137,8 @@ public class MediaPlayerBridge {
Context context, String url, String cookies, boolean hideUrlLog) {
Uri uri = Uri.parse(url);
HashMap<String, String> headersMap = new HashMap<String, String>();
- if (hideUrlLog)
- headersMap.put("x-hide-urls-from-log", "true");
- if (!TextUtils.isEmpty(cookies))
- headersMap.put("Cookie", cookies);
+ if (hideUrlLog) headersMap.put("x-hide-urls-from-log", "true");
+ if (!TextUtils.isEmpty(cookies)) headersMap.put("Cookie", cookies);
try {
getLocalPlayer().setDataSource(context, uri, headersMap);
return true;
@@ -127,6 +147,80 @@ public class MediaPlayerBridge {
}
}
+ @CalledByNative
+ protected boolean setDataUriDataSource(final Context context, final String url) {
+ if (mLoadDataUriTask != null) {
+ mLoadDataUriTask.cancel(true);
+ mLoadDataUriTask = null;
+ }
+
+ if (!url.startsWith("data:")) return false;
+ int headerStop = url.indexOf(',');
+ if (headerStop == -1) return false;
+ String header = url.substring(0, headerStop);
+ final String data = url.substring(headerStop + 1);
+
+ String headerContent = header.substring(5);
+ String headerInfo[] = headerContent.split(";");
+ if (headerInfo.length != 2) return false;
+ if (!"base64".equals(headerInfo[1])) return false;
+
+ mLoadDataUriTask = new LoadDataUriTask(context, data);
+ mLoadDataUriTask.execute();
+ return true;
+ }
+
+ private class LoadDataUriTask extends AsyncTask <Void, Void, Boolean> {
+ private final String mData;
+ private final Context mContext;
+ private File mTempFile;
+
+ public LoadDataUriTask(Context context, String data) {
+ mData = data;
+ mContext = context;
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ try {
+ mTempFile = File.createTempFile("decoded", "mediadata");
+ FileOutputStream fos = new FileOutputStream(mTempFile);
+ fos.write(Base64.decode(mData, Base64.DEFAULT));
+ fos.close();
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (isCancelled()) {
+ deleteFile();
+ return;
+ }
+
+ try {
+ getLocalPlayer().setDataSource(mContext, Uri.fromFile(mTempFile));
+ } catch (IOException e) {
+ result = false;
+ }
+
+ deleteFile();
+ assert (mNativeMediaPlayerBridge != 0);
+ nativeOnDidSetDataUriDataSource(mNativeMediaPlayerBridge, result);
+ }
+
+ private void deleteFile() {
+ if (mTempFile == null) return;
+ if (!mTempFile.delete()) {
+ // File will be deleted when MediaPlayer releases its handler.
+ Log.e(TAG, "Failed to delete temporary file: " + mTempFile);
+ assert (false);
+ }
+ }
+ }
+
protected void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) {
getLocalPlayer().setOnBufferingUpdateListener(listener);
}
@@ -218,4 +312,7 @@ public class MediaPlayerBridge {
}
return new AllowedOperations(canPause, canSeekForward, canSeekBackward);
}
+
+ private native void nativeOnDidSetDataUriDataSource(long nativeMediaPlayerBridge,
+ boolean success);
}
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index 64e2db8..0f79c13 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "base/strings/string_util.h"
#include "jni/MediaPlayerBridge_jni.h"
#include "media/base/android/media_player_manager.h"
#include "media/base/android/media_resource_getter.h"
@@ -45,6 +46,11 @@ MediaPlayerBridge::MediaPlayerBridge(
}
MediaPlayerBridge::~MediaPlayerBridge() {
+ if (!j_media_player_bridge_.is_null()) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ CHECK(env);
+ Java_MediaPlayerBridge_destroy(env, j_media_player_bridge_.obj());
+ }
Release();
}
@@ -72,7 +78,8 @@ void MediaPlayerBridge::CreateJavaMediaPlayerBridge() {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
- j_media_player_bridge_.Reset(Java_MediaPlayerBridge_create(env));
+ j_media_player_bridge_.Reset(Java_MediaPlayerBridge_create(
+ env, reinterpret_cast<intptr_t>(this)));
SetMediaPlayerListener();
}
@@ -144,6 +151,15 @@ void MediaPlayerBridge::SetDataSource(const std::string& url) {
jobject j_context = base::android::GetApplicationContext();
DCHECK(j_context);
+ const std::string data_uri_prefix("data:");
+ if (StartsWithASCII(url, data_uri_prefix, true)) {
+ if (!Java_MediaPlayerBridge_setDataUriDataSource(
+ env, j_media_player_bridge_.obj(), j_context, j_url_string.obj())) {
+ OnMediaError(MEDIA_ERROR_FORMAT);
+ }
+ return;
+ }
+
if (!Java_MediaPlayerBridge_setDataSource(
env, j_media_player_bridge_.obj(), j_context, j_url_string.obj(),
j_cookies.obj(), hide_url_log_)) {
@@ -156,6 +172,18 @@ void MediaPlayerBridge::SetDataSource(const std::string& url) {
OnMediaError(MEDIA_ERROR_FORMAT);
}
+void MediaPlayerBridge::OnDidSetDataUriDataSource(JNIEnv* env, jobject obj,
+ jboolean success) {
+ if (!success) {
+ OnMediaError(MEDIA_ERROR_FORMAT);
+ return;
+ }
+
+ manager()->RequestMediaResources(player_id());
+ if (!Java_MediaPlayerBridge_prepareAsync(env, j_media_player_bridge_.obj()))
+ OnMediaError(MEDIA_ERROR_FORMAT);
+}
+
void MediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
cookies_ = cookies;
ExtractMediaMetadata(url_.spec());
diff --git a/media/base/android/media_player_bridge.h b/media/base/android/media_player_bridge.h
index f47a50d..402cb49 100644
--- a/media/base/android/media_player_bridge.h
+++ b/media/base/android/media_player_bridge.h
@@ -78,6 +78,7 @@ class MEDIA_EXPORT MediaPlayerBridge : public MediaPlayerAndroid {
void OnPlaybackComplete();
void OnMediaInterrupted();
void OnSeekComplete();
+ void OnDidSetDataUriDataSource(JNIEnv* env, jobject obj, jboolean success);
protected:
void SetJavaMediaPlayerBridge(jobject j_media_player_bridge);