diff options
author | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-06 01:53:42 +0000 |
---|---|---|
committer | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-06 01:53:42 +0000 |
commit | 81a476c9ce1088345db02cf1647399d0e673d487 (patch) | |
tree | cc02b33218315fd4a66d3c4358bb7184558644c5 /media | |
parent | a23988918d76f545a05b55287928d905430fd211 (diff) | |
download | chromium_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.gyp | 33 | ||||
-rw-r--r-- | media/base/android/java/media.xml | 56 | ||||
-rw-r--r-- | media/base/android/java/org/chromium/media/MediaPlayerListener.java | 149 | ||||
-rw-r--r-- | media/base/android/media_player_bridge.cc | 346 | ||||
-rw-r--r-- | media/base/android/media_player_bridge.h | 148 | ||||
-rw-r--r-- | media/media.gyp | 40 |
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', |