diff --git a/api/current.txt b/api/current.txt index 94890213d3a8e..304ccf836d8a1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -21484,6 +21484,7 @@ package android.media { method public void prepareAsync() throws java.lang.IllegalStateException; method public void release(); method public void reset(); + method public void seekTo(int, int) throws java.lang.IllegalStateException; method public void seekTo(int) throws java.lang.IllegalStateException; method public void selectTrack(int) throws java.lang.IllegalStateException; method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException; @@ -21536,6 +21537,10 @@ package android.media { field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3 field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + field public static final int SEEK_CLOSEST = 3; // 0x3 + field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 + field public static final int SEEK_NEXT_SYNC = 1; // 0x1 + field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0 field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1 field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2 } diff --git a/api/system-current.txt b/api/system-current.txt index 2190abb2ef67f..b0275d4a0ed61 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -23051,6 +23051,7 @@ package android.media { method public void prepareAsync() throws java.lang.IllegalStateException; method public void release(); method public void reset(); + method public void seekTo(int, int) throws java.lang.IllegalStateException; method public void seekTo(int) throws java.lang.IllegalStateException; method public void selectTrack(int) throws java.lang.IllegalStateException; method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException; @@ -23103,6 +23104,10 @@ package android.media { field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3 field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + field public static final int SEEK_CLOSEST = 3; // 0x3 + field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 + field public static final int SEEK_NEXT_SYNC = 1; // 0x1 + field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0 field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1 field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2 } diff --git a/api/test-current.txt b/api/test-current.txt index a55fa4e6b7a17..f2694791cce92 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -21571,6 +21571,7 @@ package android.media { method public void prepareAsync() throws java.lang.IllegalStateException; method public void release(); method public void reset(); + method public void seekTo(int, int) throws java.lang.IllegalStateException; method public void seekTo(int) throws java.lang.IllegalStateException; method public void selectTrack(int) throws java.lang.IllegalStateException; method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException; @@ -21623,6 +21624,10 @@ package android.media { field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3 field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; + field public static final int SEEK_CLOSEST = 3; // 0x3 + field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 + field public static final int SEEK_NEXT_SYNC = 1; // 0x1 + field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0 field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1 field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2 } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 36ad90b6026cd..eff5aac0ad2d6 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -127,7 +127,7 @@ import java.lang.ref.WeakReference; * {@link #getVideoWidth()}, {@link #setAudioStreamType(int)}, * {@link #setLooping(boolean)}, * {@link #setVolume(float, float)}, {@link #pause()}, {@link #start()}, - * {@link #stop()}, {@link #seekTo(int)}, {@link #prepare()} or + * {@link #stop()}, {@link #seekTo(int, int)}, {@link #prepare()} or * {@link #prepareAsync()} in the Idle state for both cases. If any of these * methods is called right after a MediaPlayer object is constructed, * the user supplied callback method OnErrorListener.onError() won't be @@ -273,19 +273,22 @@ import java.lang.ref.WeakReference; * * *
+ * When seekTo is finished, the user will be notified via OnSeekComplete supplied by the user.
+ * There is at most one active seekTo processed at any time. If there is a to-be-completed
+ * seekTo, new seekTo requests will be queued in such a way that only the last request
+ * is kept. When current seekTo is completed, the queued request will be processed if
+ * that request is different from just-finished seekTo operation, i.e., the requested
+ * position or mode is different.
+ *
+ * @param msec the offset in milliseconds from the start to seek to.
+ * When seeking to the given time position, there is no guarantee that the data source
+ * has a frame located at the position. When this happens, a frame nearby will be rendered.
+ * If msec is negative, time position zero will be used.
+ * If msec is larger than duration, duration will be used.
+ * @param mode the mode indicating where exactly to seek to.
+ * Use {@link #SEEK_PREVIOUS_SYNC} if one wants to seek to a sync frame
+ * that has a timestamp earlier than or the same as msec. Use
+ * {@link #SEEK_NEXT_SYNC} if one wants to seek to a sync frame
+ * that has a timestamp later than or the same as msec. Use
+ * {@link #SEEK_CLOSEST_SYNC} if one wants to seek to a sync frame
+ * that has a timestamp closest to or the same as msec. Use
+ * {@link #SEEK_CLOSEST} if one wants to seek to a frame that may
+ * or may not be a sync frame but is closest to or the same as msec.
+ * {@link #SEEK_CLOSEST} often has larger performance overhead compared
+ * to the other options if there is no sync frame located at msec.
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized
+ * @throws IllegalArgumentException if the mode is invalid.
+ */
+ public void seekTo(int msec, @SeekMode int mode) throws IllegalStateException {
+ if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
+ final String msg = "Illegal seek mode: " + mode;
+ throw new IllegalArgumentException(msg);
+ }
+ _seekTo(msec, mode);
+ }
+
/**
* Seeks to specified time position.
+ * Same as {@link #seekTo(int, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
*
* @param msec the offset in milliseconds from the start to seek to
* @throws IllegalStateException if the internal player engine has not been
* initialized
*/
- public native void seekTo(int msec) throws IllegalStateException;
+ public void seekTo(int msec) throws IllegalStateException {
+ seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
+ }
/**
* Get current playback position as a {@link MediaTimestamp}.
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index c82570286bbca..c52ed941af854 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -577,15 +577,15 @@ android_media_MediaPlayer_getSyncParams(JNIEnv *env, jobject thiz)
}
static void
-android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec)
+android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec, jint mode)
{
sp