summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-06 01:53:42 +0000
committerqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-06 01:53:42 +0000
commit81a476c9ce1088345db02cf1647399d0e673d487 (patch)
treecc02b33218315fd4a66d3c4358bb7184558644c5 /media
parenta23988918d76f545a05b55287928d905430fd211 (diff)
downloadchromium_src-81a476c9ce1088345db02cf1647399d0e673d487.zip
chromium_src-81a476c9ce1088345db02cf1647399d0e673d487.tar.gz
chromium_src-81a476c9ce1088345db02cf1647399d0e673d487.tar.bz2
Adding android mediaplayer implementation to chromium
This is initial step to upstream html5 video stack for chrome on android BUG= TEST= Review URL: http://codereview.chromium.org/9699012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@131064 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/android/java/java.gyp33
-rw-r--r--media/base/android/java/media.xml56
-rw-r--r--media/base/android/java/org/chromium/media/MediaPlayerListener.java149
-rw-r--r--media/base/android/media_player_bridge.cc346
-rw-r--r--media/base/android/media_player_bridge.h148
-rw-r--r--media/media.gyp40
6 files changed, 770 insertions, 2 deletions
diff --git a/media/base/android/java/java.gyp b/media/base/android/java/java.gyp
new file mode 100644
index 0000000..14717f13
--- /dev/null
+++ b/media/base/android/java/java.gyp
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'media_java',
+ 'message': 'building media java sources',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'media_java',
+ 'inputs': [
+ 'media.xml',
+ 'org/chromium/media/MediaPlayerListener.java',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/base/android/java/java.gyp:base_java',
+ ],
+ 'outputs': [
+ 'dist/lib/chromium_media.jar',
+ ],
+ 'action': [
+ 'ant',
+ '-buildfile',
+ 'media.xml',
+ ]
+ },
+ ],
+ },
+ ],
+}
diff --git a/media/base/android/java/media.xml b/media/base/android/java/media.xml
new file mode 100644
index 0000000..28a8ef1
--- /dev/null
+++ b/media/base/android/java/media.xml
@@ -0,0 +1,56 @@
+<!-- Copyright (c) 2012 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.
+-->
+<project name="Media" default="dist" basedir=".">
+ <description>
+ building media java source code with ant
+ </description>
+ <!-- set global properties for this build -->
+ <property environment="env"/>
+ <property name="sdk.dir" location="${env.ANDROID_SDK_ROOT}"/>
+ <property name="sdk.version" value="${env.ANDROID_SDK_VERSION}"/>
+ <property name="src" location="."/>
+ <property name="build" location="build"/>
+ <property name="dist" location="dist"/>
+
+ <condition property="location.base"
+ value="${sdk.dir}"
+ else="${sdk.dir}/platforms/android-${sdk.version}">
+ <isset property="env.ANDROID_BUILD_TOP"/>
+ </condition>
+
+ <target name="init">
+ <!-- Create the time stamp -->
+ <tstamp/>
+ <!-- Create the build directory structure used by compile -->
+ <mkdir dir="${build}"/>
+ </target>
+
+ <target name="compile" depends="init"
+ description="compile the source " >
+ <!-- Compile the java code from ${src} into ${build} -->
+ <javac srcdir="${src}" destdir="${build}">
+ <classpath>
+ <path location="${location.base}/android.jar"/>
+ </classpath>
+ </javac>
+ </target>
+
+ <target name="dist" depends="compile"
+ description="generate the distribution" >
+ <!-- Create the distribution directory -->
+ <mkdir dir="${dist}/lib"/>
+
+ <!-- Put everything in ${build} into the chromium_media.jar file -->
+ <jar jarfile="${dist}/lib/chromium_media.jar" basedir="${build}"/>
+ </target>
+
+ <target name="clean"
+ description="clean up" >
+ <!-- Delete the ${build} and ${dist} directory trees -->
+ <delete dir="${build}"/>
+ <delete dir="${dist}"/>
+ </target>
+</project>
diff --git a/media/base/android/java/org/chromium/media/MediaPlayerListener.java b/media/base/android/java/org/chromium/media/MediaPlayerListener.java
new file mode 100644
index 0000000..fd56599
--- /dev/null
+++ b/media/base/android/java/org/chromium/media/MediaPlayerListener.java
@@ -0,0 +1,149 @@
+// Copyright (c) 2012 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.
+
+package org.chromium.media;
+
+import android.media.MediaPlayer;
+
+import org.chromium.base.CalledByNative;
+
+// This class implements all the listener interface for android mediaplayer.
+// Callbacks will be sent to the native class for processing.
+class MediaPlayerListener implements MediaPlayer.OnPreparedListener,
+ MediaPlayer.OnCompletionListener,
+ MediaPlayer.OnBufferingUpdateListener,
+ MediaPlayer.OnSeekCompleteListener,
+ MediaPlayer.OnVideoSizeChangedListener,
+ MediaPlayer.OnErrorListener,
+ MediaPlayer.OnInfoListener {
+ // These values are mirrored as enums in media/base/android/media_player_bridge.h.
+ // Please ensure they stay in sync.
+ private static final int MEDIA_ERROR_UNKNOWN = 0;
+ private static final int MEDIA_ERROR_SERVER_DIED = 1;
+ private static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 2;
+
+ private static final int MEDIA_INFO_UNKNOWN = 0;
+ private static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 1;
+ private static final int MEDIA_INFO_BUFFERING_START = 2;
+ private static final int MEDIA_INFO_BUFFERING_END = 3;
+ private static final int MEDIA_INFO_BAD_INTERLEAVING = 4;
+ private static final int MEDIA_INFO_NOT_SEEKABLE = 5;
+ private static final int MEDIA_INFO_METADATA_UPDATE = 6;
+
+ // Used to determine the class instance to dispatch the native call to.
+ private int mNativeMediaPlayerBridge = 0;
+
+ private MediaPlayerListener(int nativeMediaPlayerBridge) {
+ mNativeMediaPlayerBridge = nativeMediaPlayerBridge;
+ }
+
+ @Override
+ public boolean onInfo(MediaPlayer mp, int what, int extra) {
+ int infoType;
+ switch (what) {
+ case MediaPlayer.MEDIA_INFO_UNKNOWN:
+ infoType = MEDIA_INFO_UNKNOWN;
+ break;
+ case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
+ infoType = MEDIA_INFO_VIDEO_TRACK_LAGGING;
+ break;
+ case MediaPlayer.MEDIA_INFO_BUFFERING_START:
+ infoType = MEDIA_INFO_BUFFERING_START;
+ break;
+ case MediaPlayer.MEDIA_INFO_BUFFERING_END:
+ infoType = MEDIA_INFO_BUFFERING_END;
+ break;
+ case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:
+ infoType = MEDIA_INFO_BAD_INTERLEAVING;
+ break;
+ case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
+ infoType = MEDIA_INFO_NOT_SEEKABLE;
+ break;
+ case MediaPlayer.MEDIA_INFO_METADATA_UPDATE:
+ infoType = MEDIA_INFO_METADATA_UPDATE;
+ break;
+ default:
+ infoType = MEDIA_INFO_UNKNOWN;
+ break;
+ }
+ nativeOnMediaInfo(mNativeMediaPlayerBridge, infoType);
+ return true;
+ }
+
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ int errorType;
+ switch (what) {
+ case MediaPlayer.MEDIA_ERROR_UNKNOWN:
+ errorType = MEDIA_ERROR_UNKNOWN;
+ break;
+ case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
+ errorType = MEDIA_ERROR_SERVER_DIED;
+ break;
+ case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
+ errorType = MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK;
+ break;
+ default:
+ errorType = MEDIA_ERROR_UNKNOWN;
+ break;
+ }
+ nativeOnMediaError(mNativeMediaPlayerBridge, errorType);
+ return true;
+ }
+
+ @Override
+ public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
+ nativeOnVideoSizeChanged(mNativeMediaPlayerBridge, width, height);
+ }
+
+ @Override
+ public void onSeekComplete(MediaPlayer mp) {
+ nativeOnSeekComplete(mNativeMediaPlayerBridge);
+ }
+
+ @Override
+ public void onBufferingUpdate(MediaPlayer mp, int percent) {
+ nativeOnBufferingUpdate(mNativeMediaPlayerBridge, percent);
+ }
+
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ nativeOnPlaybackComplete(mNativeMediaPlayerBridge);
+ }
+
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ nativeOnMediaPrepared(mNativeMediaPlayerBridge);
+ }
+
+ @CalledByNative
+ private static MediaPlayerListener create(int nativeMediaPlayerBridge) {
+ return new MediaPlayerListener(nativeMediaPlayerBridge);
+ }
+
+ /**
+ * See media/base/android/media_player_bridge.cc for all the following functions.
+ */
+ private native void nativeOnMediaError(
+ int nativePtr /* media::MediaPlayerBridge */,
+ int errorType);
+
+ private native void nativeOnMediaInfo(
+ int nativePtr /* media::MediaPlayerBridge */,
+ int infoType);
+
+ private native void nativeOnVideoSizeChanged(
+ int nativePtr /* media::MediaPlayerBridge */,
+ int width, int height);
+
+ private native void nativeOnBufferingUpdate(
+ int nativePtr /* media::MediaPlayerBridge */,
+ int percent);
+
+ private native void nativeOnMediaPrepared(int nativePtr /* media::MediaPlayerBridge */);
+
+ private native void nativeOnPlaybackComplete(int nativePtr /* media::MediaPlayerBridge */);
+
+ private native void nativeOnSeekComplete(int nativePtr /* media::MediaPlayerBridge */);
+}
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
new file mode 100644
index 0000000..11955b8
--- /dev/null
+++ b/media/base/android/media_player_bridge.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2012 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.
+
+#include "media/base/android/media_player_bridge.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+
+// Auto generated jni class from MediaPlayerListener.java.
+// Check base/android/jni_generator/golden_sample_for_tests_jni.h for example.
+#include "jni/media_player_listener_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::CheckException;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::GetClass;
+using base::android::GetMethodID;
+using base::android::JavaRef;
+using base::android::ScopedJavaLocalRef;
+
+// These constants are from the android source tree and need to be kept in
+// sync with android/media/MediaMetadata.java.
+static const jint kPauseAvailable = 1;
+static const jint kSeekBackwardAvailable = 2;
+static const jint kSeekForwardAvailable = 3;
+
+// This needs to be kept in sync with android.os.PowerManager
+static const int kAndroidFullWakeLock = 26;
+
+namespace media {
+
+MediaPlayerBridge::MediaPlayerBridge() {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ j_media_player_class_.Reset(GetClass(env, "android/media/MediaPlayer"));
+
+ jmethodID constructor = GetMethodID(env,
+ j_media_player_class_,
+ "<init>",
+ "()V");
+ ScopedJavaLocalRef<jobject> tmp(env,
+ env->NewObject(j_media_player_class_.obj(), constructor));
+ j_media_player_.Reset(tmp);
+
+ ScopedJavaLocalRef<jobject> j_listener(
+ Java_MediaPlayerListener_create(env,
+ reinterpret_cast<intptr_t>(this)));
+ DCHECK(!j_listener.is_null());
+
+ // Set it as the various listeners.
+ const char* listeners[] = {
+ "OnBufferingUpdateListener",
+ "OnCompletionListener",
+ "OnErrorListener",
+ "OnInfoListener",
+ "OnPreparedListener",
+ "OnSeekCompleteListener",
+ "OnVideoSizeChangedListener",
+ };
+ for (unsigned int i = 0; i < arraysize(listeners); ++i) {
+ std::string signature = StringPrintf("(Landroid/media/MediaPlayer$%s;)V",
+ listeners[i]);
+ std::string method_name = StringPrintf("set%s", listeners[i]);
+ jmethodID method = GetMethodID(env,
+ j_media_player_class_,
+ method_name.c_str(),
+ signature.c_str());
+ env->CallVoidMethod(j_media_player_.obj(), method, j_listener.obj());
+ CheckException(env);
+ }
+}
+
+MediaPlayerBridge::~MediaPlayerBridge() {
+ CallVoidMethod("release");
+}
+
+void MediaPlayerBridge::SetDataSource(
+ const std::string& url,
+ const std::map<std::string, std::string>& headers) {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ // Create a Java String for the URL.
+ ScopedJavaLocalRef<jstring> j_url_string = ConvertUTF8ToJavaString(env, url);
+
+ // Create the android.net.Uri object.
+ ScopedJavaLocalRef<jclass> cls(GetClass(env, "android/net/Uri"));
+ jmethodID method = GetStaticMethodID(env, cls,
+ "parse", "(Ljava/lang/String;)Landroid/net/Uri;");
+ ScopedJavaLocalRef<jobject> j_uri(env,
+ env->CallStaticObjectMethod(cls.obj(), method, j_url_string.obj()));
+
+ // Create the java.util.Map.
+ cls.Reset(GetClass(env, "java/util/HashMap"));
+ jmethodID constructor = GetMethodID(env, cls, "<init>", "()V");
+ ScopedJavaLocalRef<jobject> j_map(env,
+ env->NewObject(cls.obj(), constructor));
+ jmethodID put_method = GetMethodID(env, cls, "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+ // Fill the Map with the headers.
+ for (HeadersMap::const_iterator iter = headers.begin();
+ iter != headers.end(); ++iter) {
+ ScopedJavaLocalRef<jstring> key = ConvertUTF8ToJavaString(env, iter->first);
+ ScopedJavaLocalRef<jstring> value =
+ ConvertUTF8ToJavaString(env, iter->second);
+ ScopedJavaLocalRef<jobject> result(env,
+ env->CallObjectMethod(j_map.obj(), put_method, key.obj(), value.obj()));
+ }
+
+ jobject j_context = base::android::GetApplicationContext();
+ DCHECK(j_context);
+
+ // Finally- Call the setDataSource method.
+ jmethodID set_data_source =
+ GetMethodID(env, j_media_player_class_, "setDataSource",
+ "(Landroid/content/Context;Landroid/net/Uri;Ljava/util/Map;)V");
+ DCHECK(set_data_source);
+ env->CallVoidMethod(j_media_player_.obj(), set_data_source, j_context,
+ j_uri.obj(), j_map.obj());
+ CheckException(env);
+}
+
+void MediaPlayerBridge::SetVideoSurface(jobject surface) {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jmethodID method = GetMethodID(env,
+ j_media_player_class_,
+ "setSurface",
+ "(Landroid/view/Surface;)V");
+ env->CallVoidMethod(j_media_player_.obj(), method, surface);
+ CheckException(env);
+}
+
+void MediaPlayerBridge::Prepare(const MediaInfoCB& media_info_cb,
+ const MediaErrorCB& media_error_cb,
+ const VideoSizeChangedCB& video_size_changed_cb,
+ const BufferingUpdateCB& buffering_update_cb,
+ const base::Closure& media_prepared_cb) {
+ media_info_cb_ = media_info_cb;
+ media_error_cb_ = media_error_cb,
+ video_size_changed_cb_ = video_size_changed_cb;
+ buffering_update_cb_ = buffering_update_cb;
+ media_prepared_cb_ = media_prepared_cb;
+ CallVoidMethod("prepareAsync");
+}
+
+void MediaPlayerBridge::Start(const base::Closure& playback_complete_cb) {
+ playback_complete_cb_ = playback_complete_cb;
+ CallVoidMethod("start");
+}
+
+void MediaPlayerBridge::Pause() {
+ CallVoidMethod("pause");
+}
+
+void MediaPlayerBridge::Stop() {
+ CallVoidMethod("stop");
+}
+
+bool MediaPlayerBridge::IsPlaying() {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jmethodID method = GetMethodID(env,
+ j_media_player_class_,
+ "isPlaying",
+ "()Z");
+ jint result = env->CallBooleanMethod(j_media_player_.obj(), method);
+ CheckException(env);
+
+ return result;
+}
+
+int MediaPlayerBridge::GetVideoWidth() {
+ return CallIntMethod("getVideoWidth");
+}
+
+int MediaPlayerBridge::GetVideoHeight() {
+ return CallIntMethod("getVideoHeight");
+}
+
+void MediaPlayerBridge::SeekTo(base::TimeDelta time,
+ const base::Closure& seek_complete_cb) {
+ seek_complete_cb_ = seek_complete_cb;
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jmethodID method = GetMethodID(env, j_media_player_class_, "seekTo", "(I)V");
+ DCHECK(method);
+ env->CallVoidMethod(j_media_player_.obj(), method, time.InMilliseconds());
+ CheckException(env);
+}
+
+base::TimeDelta MediaPlayerBridge::GetCurrentTime() {
+ return base::TimeDelta::FromMilliseconds(CallIntMethod("getCurrentPosition"));
+}
+
+base::TimeDelta MediaPlayerBridge::GetDuration() {
+ return base::TimeDelta::FromMilliseconds(CallIntMethod("getDuration"));
+}
+
+void MediaPlayerBridge::Reset() {
+ CallVoidMethod("reset");
+}
+
+void MediaPlayerBridge::SetVolume(float left_volume, float right_volume) {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jmethodID method = GetMethodID(env,
+ j_media_player_class_,
+ "setVolume",
+ "(FF)V");
+ DCHECK(method);
+ env->CallVoidMethod(j_media_player_.obj(), method,
+ left_volume, right_volume);
+ CheckException(env);
+}
+
+void MediaPlayerBridge::SetStayAwakeWhilePlaying() {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jobject j_context = base::android::GetApplicationContext();
+ DCHECK(j_context);
+ jint j_mode = kAndroidFullWakeLock;
+ jmethodID method = GetMethodID(env, j_media_player_class_,
+ "setWakeMode", "(Landroid/content/Context;I)V");
+ env->CallVoidMethod(j_media_player_.obj(), method, j_context, j_mode);
+ CheckException(env);
+}
+
+void MediaPlayerBridge::OnMediaError(JNIEnv* /* env */,
+ jobject /* obj */,
+ jint error_type) {
+ media_error_cb_.Run(error_type);
+}
+
+void MediaPlayerBridge::OnMediaInfo(JNIEnv* /* env */,
+ jobject /* obj */,
+ jint info_type) {
+ media_info_cb_.Run(info_type);
+}
+
+void MediaPlayerBridge::OnVideoSizeChanged(JNIEnv* /* env */,
+ jobject /* obj */,
+ jint width,
+ jint height) {
+ video_size_changed_cb_.Run(width, height);
+}
+
+void MediaPlayerBridge::OnBufferingUpdate(JNIEnv* /* env */,
+ jobject /* obj */,
+ jint percent) {
+ buffering_update_cb_.Run(percent);
+}
+
+void MediaPlayerBridge::OnPlaybackComplete(JNIEnv* /* env */,
+ jobject /* obj */) {
+ playback_complete_cb_.Run();
+}
+
+void MediaPlayerBridge::OnSeekComplete(JNIEnv* /* env */,
+ jobject /* obj */) {
+ seek_complete_cb_.Run();
+}
+
+void MediaPlayerBridge::OnMediaPrepared(JNIEnv* /* env */,
+ jobject /* obj */) {
+ media_prepared_cb_.Run();
+}
+
+void MediaPlayerBridge::GetMetadata(bool* can_pause,
+ bool* can_seek_forward,
+ bool* can_seek_backward) {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jmethodID method = GetMethodID(env,
+ j_media_player_class_,
+ "getMetadata",
+ "(ZZ)Landroid/media/Metadata;");
+ ScopedJavaLocalRef<jobject> j_metadata(env,
+ env->CallObjectMethod(j_media_player_.obj(),
+ method, JNI_FALSE, JNI_FALSE));
+ CheckException(env);
+ if (j_metadata.is_null())
+ return;
+
+ ScopedJavaLocalRef<jclass> cls(GetClass(env, "android/media/Metadata"));
+ jmethodID get_boolean = GetMethodID(env, cls, "getBoolean", "(I)Z");
+ *can_pause = env->CallBooleanMethod(j_metadata.obj(),
+ get_boolean,
+ kPauseAvailable);
+ CheckException(env);
+ *can_seek_backward = env->CallBooleanMethod(j_metadata.obj(),
+ get_boolean,
+ kSeekBackwardAvailable);
+ CheckException(env);
+ *can_seek_forward = env->CallBooleanMethod(j_metadata.obj(),
+ get_boolean,
+ kSeekForwardAvailable);
+ CheckException(env);
+}
+
+// ---- JNI Helpers for repeated call patterns. ----
+
+void MediaPlayerBridge::CallVoidMethod(std::string method_name) {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jmethodID method = GetMethodID(env,
+ j_media_player_class_,
+ method_name.c_str(),
+ "()V");
+ env->CallVoidMethod(j_media_player_.obj(), method);
+ CheckException(env);
+}
+
+int MediaPlayerBridge::CallIntMethod(std::string method_name) {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ jmethodID method = GetMethodID(env,
+ j_media_player_class_,
+ method_name.c_str(),
+ "()I");
+ jint j_result = env->CallIntMethod(j_media_player_.obj(), method);
+ CheckException(env);
+ return j_result;
+}
+
+bool MediaPlayerBridge::RegisterMediaPlayerListener(JNIEnv* env) {
+ bool ret = RegisterNativesImpl(env);
+ DCHECK(g_MediaPlayerListener_clazz);
+ return ret;
+}
+
+} // namespace media
diff --git a/media/base/android/media_player_bridge.h b/media/base/android/media_player_bridge.h
new file mode 100644
index 0000000..6499e46
--- /dev/null
+++ b/media/base/android/media_player_bridge.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2012 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.
+
+#ifndef MEDIA_BASE_ANDROID_MEDIA_PLAYER_BRIDGE_H_
+#define MEDIA_BASE_ANDROID_MEDIA_PLAYER_BRIDGE_H_
+
+#include <jni.h>
+#include <map>
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time.h"
+
+namespace media {
+
+// This class serves as a bridge for native code to call java functions inside
+// android mediaplayer class. For more information on android mediaplayer, check
+// http://developer.android.com/reference/android/media/MediaPlayer.html
+// To use this class, follow the state diagram listed in the above url.
+// Here is the normal work flow for this class:
+// 1. Call SetDataSource() to set the media url.
+// 2. Call Prepare() to prepare the player for playback. This is a non
+// blocking call.
+// 3. When Prepare() succeeds, OnMediaPrepared() will get called.
+// 4. Call Start(), Pause(), SeekTo() to play/pause/seek the media.
+class MediaPlayerBridge {
+ public:
+ // Error types for MediaErrorCB.
+ enum MediaErrorType {
+ MEDIA_ERROR_UNKNOWN,
+ MEDIA_ERROR_SERVER_DIED,
+ MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK,
+ };
+
+ // Info types for MediaInfoCB.
+ enum MediaInfoType {
+ MEDIA_INFO_UNKNOWN,
+ MEDIA_INFO_VIDEO_TRACK_LAGGING,
+ MEDIA_INFO_BUFFERING_START,
+ MEDIA_INFO_BUFFERING_END,
+ MEDIA_INFO_BAD_INTERLEAVING,
+ MEDIA_INFO_NOT_SEEKABLE,
+ MEDIA_INFO_METADATA_UPDATE,
+ };
+
+ // Callback when video info is received. Args: info type.
+ typedef base::Callback<void(int)> MediaInfoCB;
+
+ // Callback when error happens. Args: error type.
+ typedef base::Callback<void(int)> MediaErrorCB;
+
+ // Callback when video size has changed. Args: width, height.
+ typedef base::Callback<void(int,int)> VideoSizeChangedCB;
+
+ // Callback when buffering has changed. Args: percentage of the media.
+ typedef base::Callback<void(int)> BufferingUpdateCB;
+
+ MediaPlayerBridge();
+ ~MediaPlayerBridge();
+
+ typedef std::map<std::string, std::string> HeadersMap;
+ void SetDataSource(const std::string& url, const HeadersMap& headers);
+
+ void SetVideoSurface(jobject surface);
+
+ // Prepare the player for playback, asynchronously. When succeeds,
+ // OnMediaPrepared() will be called. Otherwise, OnMediaError() will
+ // be called with an error type.
+ void Prepare(const MediaInfoCB& media_info_cb,
+ const MediaErrorCB& media_error_cb,
+ const VideoSizeChangedCB& video_size_changed_cb,
+ const BufferingUpdateCB& buffering_update_cb,
+ const base::Closure& media_prepared_cb);
+
+ // Start playing the media.
+ void Start(const base::Closure& playback_complete_cb);
+
+ // Pause the media.
+ void Pause();
+
+ // Stop the media playback. Needs to call Prepare() again to play the media.
+ void Stop();
+
+ // Seek to a particular position. When succeeds, OnSeekComplete() will be
+ // called. Otherwise, nothing will happen.
+ void SeekTo(base::TimeDelta time, const base::Closure& seek_complete_cb);
+
+ // Reset the player. Needs to call SetDataSource() again after this call.
+ void Reset();
+
+ // Set the player volume.
+ void SetVolume(float leftVolume, float rightVolume);
+
+ // Get the media information from the player.
+ int GetVideoWidth();
+ int GetVideoHeight();
+ base::TimeDelta GetCurrentTime();
+ base::TimeDelta GetDuration();
+ bool IsPlaying();
+
+ // Get metadata from the media.
+ void GetMetadata(bool* can_pause,
+ bool* can_seek_forward,
+ bool* can_seek_backward);
+
+ // Set the device to stay awake when player is playing.
+ void SetStayAwakeWhilePlaying();
+
+ // Called by the Java MediaPlayerListener and mirrored to corresponding
+ // callbacks.
+ void OnMediaError(JNIEnv* /* env */, jobject /* obj */, jint error_type);
+ void OnMediaInfo(JNIEnv* /* env */, jobject /* obj */, jint info_type);
+ void OnVideoSizeChanged(JNIEnv* /* env */, jobject /* obj */,
+ jint width, jint height);
+ void OnBufferingUpdate(JNIEnv* /* env */, jobject /* obj */, jint percent);
+ void OnPlaybackComplete(JNIEnv* /* env */, jobject /* obj */);
+ void OnSeekComplete(JNIEnv* /* env */, jobject /* obj */);
+ void OnMediaPrepared(JNIEnv* /* env */, jobject /* obj */);
+
+ // Register MediaPlayerListener in the system library loader.
+ static bool RegisterMediaPlayerListener(JNIEnv* env);
+
+ private:
+ void CallVoidMethod(std::string method_name);
+ int CallIntMethod(std::string method_name);
+
+ // Callbacks when events are received.
+ MediaInfoCB media_info_cb_;
+ MediaErrorCB media_error_cb_;
+ VideoSizeChangedCB video_size_changed_cb_;
+ BufferingUpdateCB buffering_update_cb_;
+ base::Closure playback_complete_cb_;
+ base::Closure seek_complete_cb_;
+ base::Closure media_prepared_cb_;
+
+ // Java MediaPlayer class and instance.
+ base::android::ScopedJavaGlobalRef<jclass> j_media_player_class_;
+ base::android::ScopedJavaGlobalRef<jobject> j_media_player_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaPlayerBridge);
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_ANDROID_MEDIA_PLAYER_BRIDGE_H_
diff --git a/media/media.gyp b/media/media.gyp
index 47d1337..30649c9 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -911,8 +911,44 @@
},
],
}],
- # Android does not use ffmpeg, so disable the targets which require it.
- ['OS!="android"', {
+ ['OS == "android"', {
+ 'targets': [
+ {
+ 'target_name': 'player_android',
+ 'type': 'static_library',
+ 'sources': [
+ 'base/android/media_player_bridge.cc',
+ 'base/android/media_player_bridge.h',
+ ],
+ 'dependencies': [
+ '../base/base.gyp:base',
+ ],
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)/media',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'generate-jni-headers',
+ 'inputs': [
+ '../base/android/jni_generator/jni_generator.py',
+ 'base/android/java/org/chromium/media/MediaPlayerListener.java',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/media/jni/media_player_listener_jni.h',
+ ],
+ 'action': [
+ 'python',
+ '<(DEPTH)/base/android/jni_generator/jni_generator.py',
+ '-o',
+ '<@(_inputs)',
+ '<@(_outputs)',
+ ],
+ },
+ ],
+ },
+ ],
+ }, { # OS != "android"'
+ # Android does not use ffmpeg, so disable the targets which require it.
'targets': [
{
'target_name': 'ffmpeg_unittests',