Bug 3438258 Add SurfaceTexture as MediaPlayer sink

This change enables the use of a SurfaceTexture in place of a Surface
as the video sink for an android.media.MediaPlayer. The new API
MediaPlayer.setTexture is currently hidden.

This includes:
 - New Java and C++ interfaces
 - C++ plumbing and implementation (JNI, Binder)
 - Stagefright AwesomePlayer and NuPlayer use ANativeWindow
   (either Surface or SurfaceTextureClient)

Change-Id: I2b568bee143d9eaf3dfc6cc4533c1bebbd5afc51
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 9c92ace..8b29ea84 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -30,6 +30,7 @@
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.graphics.Bitmap;
+import android.graphics.SurfaceTexture;
 import android.media.AudioManager;
 
 import java.io.FileDescriptor;
@@ -379,6 +380,11 @@
  *     <td>{} </p></td>
  *     <td>This method can be called in any state and calling it does not change
  *         the object state. </p></td></tr>
+ * <tr><td>setTexture </p></td>
+ *     <td>any </p></td>
+ *     <td>{} </p></td>
+ *     <td>This method can be called in any state and calling it does not change
+ *         the object state. </p></td></tr>
  * <tr><td>setLooping </p></td>
  *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
  *         PlaybackCompleted}</p></td>
@@ -503,6 +509,7 @@
     private int mListenerContext; // accessed by native methods
     private Surface mSurface; // accessed by native methods
     private SurfaceHolder  mSurfaceHolder;
+    private SurfaceTexture mSurfaceTexture; // accessed by native methods
     private EventHandler mEventHandler;
     private PowerManager.WakeLock mWakeLock = null;
     private boolean mScreenOnWhilePlaying;
@@ -533,9 +540,10 @@
     }
 
     /*
-     * Update the MediaPlayer ISurface. Call after updating mSurface.
+     * Update the MediaPlayer ISurface and ISurfaceTexture.
+     * Call after updating mSurface and/or mSurfaceTexture.
      */
-    private native void _setVideoSurface();
+    private native void _setVideoSurfaceOrSurfaceTexture();
 
     /**
      * Create a request parcel which can be routed to the native media
@@ -577,12 +585,21 @@
     }
 
     /**
-     * Sets the SurfaceHolder to use for displaying the video portion of the media.
-     * This call is optional. Not calling it when playing back a video will
+     * Sets the {@link SurfaceHolder} to use for displaying the video
+     * portion of the media.  A surface must be set if a display is
+     * needed.  Not calling this method when playing back a video will
      * result in only the audio track being played.
      *
      * @param sh the SurfaceHolder to use for video display
      */
+    /*
+     * This portion of comment has a non-Javadoc prefix so as not to refer to a
+     * hidden method. When unhidden, merge it with the previous javadoc comment.
+     *
+     * Either a surface or surface texture must be set if a display or video sink
+     * is needed.  Not calling this method or {@link #setTexture(SurfaceTexture)}
+     * when playing back a video will result in only the audio track being played.
+     */
     public void setDisplay(SurfaceHolder sh) {
         mSurfaceHolder = sh;
         if (sh != null) {
@@ -590,7 +607,29 @@
         } else {
             mSurface = null;
         }
-        _setVideoSurface();
+        mSurfaceTexture = null;
+        _setVideoSurfaceOrSurfaceTexture();
+        updateSurfaceScreenOn();
+    }
+
+    /**
+     * Sets the {@link SurfaceTexture} to be used as the sink for the
+     * video portion of the media. Either a surface or surface texture
+     * must be set if a video sink is needed.  The same surface texture
+     * can be re-set without harm. Setting a surface texture will un-set
+     * any surface that was set via {@link #setDisplay(SurfaceHolder)}.
+     * Not calling this method or {@link #setDisplay(SurfaceHolder)}
+     * when playing back a video will result in only the audio track
+     * being played. Note that if a SurfaceTexture is used, the value
+     * set via setScreenOnWhilePlaying has no effect.
+     *
+     * @hide
+     */
+    public void setTexture(SurfaceTexture st) {
+        mSurfaceHolder = null;
+        mSurface = null;
+        mSurfaceTexture = st;
+        _setVideoSurfaceOrSurfaceTexture();
         updateSurfaceScreenOn();
     }
 
@@ -645,6 +684,8 @@
         return null;
     }
 
+    // Note no convenience method to create a MediaPlayer with SurfaceTexture sink.
+
     /**
      * Convenience method to create a MediaPlayer for a given resource id.
      * On success, {@link #prepare()} will already have been called and must not be called again.
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index ca54432..6d074e9 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -35,6 +35,8 @@
 #include "utils/String8.h"
 #include "android_util_Binder.h"
 #include <binder/Parcel.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/ISurfaceTexture.h>
 #include <surfaceflinger/Surface.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -48,8 +50,11 @@
 struct fields_t {
     jfieldID    context;
     jfieldID    surface;
+    jfieldID    surfaceTexture;
     /* actually in android.view.Surface XXX */
     jfieldID    surface_native;
+    // actually in android.graphics.SurfaceTexture
+    jfieldID    surfaceTexture_native;
 
     jmethodID   post_event;
 };
@@ -110,6 +115,13 @@
     return (Surface*)env->GetIntField(clazz, fields.surface_native);
 }
 
+sp<ISurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz)
+{
+    sp<ISurfaceTexture> surfaceTexture(
+        (ISurfaceTexture*)env->GetIntField(clazz, fields.surfaceTexture_native));
+    return surfaceTexture;
+}
+
 static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
 {
     Mutex::Autolock l(sLock);
@@ -288,26 +300,40 @@
     process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
 }
 
-static void setVideoSurface(const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz)
+static void setVideoSurfaceOrSurfaceTexture(
+        const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz, const char *prefix)
 {
+    // The Java MediaPlayer class makes sure that at most one of mSurface and
+    // mSurfaceTexture is non-null.  But just in case, we give priority to
+    // mSurface over mSurfaceTexture.
     jobject surface = env->GetObjectField(thiz, fields.surface);
     if (surface != NULL) {
-        const sp<Surface> native_surface = get_surface(env, surface);
-        LOGV("prepare: surface=%p (id=%d)",
+        sp<Surface> native_surface(get_surface(env, surface));
+        LOGV("%s: surface=%p (id=%d)", prefix,
              native_surface.get(), native_surface->getIdentity());
         mp->setVideoSurface(native_surface);
+    } else {
+        jobject surfaceTexture = env->GetObjectField(thiz, fields.surfaceTexture);
+        if (surfaceTexture != NULL) {
+            sp<ISurfaceTexture> native_surfaceTexture(
+                    getSurfaceTexture(env, surfaceTexture));
+            LOGV("%s: texture=%p (id=%d)", prefix,
+                 native_surfaceTexture.get(), native_surfaceTexture->getIdentity());
+            mp->setVideoSurfaceTexture(native_surfaceTexture);
+        }
     }
 }
 
 static void
-android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz)
+android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture(JNIEnv *env, jobject thiz)
 {
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }
-    setVideoSurface(mp, env, thiz);
+    setVideoSurfaceOrSurfaceTexture(mp, env, thiz,
+            "_setVideoSurfaceOrSurfaceTexture");
 }
 
 static void
@@ -318,7 +344,7 @@
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }
-    setVideoSurface(mp, env, thiz);
+    setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepare");
     process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
 }
 
@@ -330,13 +356,7 @@
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }
-    jobject surface = env->GetObjectField(thiz, fields.surface);
-    if (surface != NULL) {
-        const sp<Surface> native_surface = get_surface(env, surface);
-        LOGV("prepareAsync: surface=%p (id=%d)",
-             native_surface.get(), native_surface->getIdentity());
-        mp->setVideoSurface(native_surface);
-    }
+    setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepareAsync");
     process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
 }
 
@@ -640,9 +660,34 @@
 
     fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I");
     if (fields.surface_native == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface");
+        jniThrowException(env, "java/lang/RuntimeException",
+                "Can't find Surface." ANDROID_VIEW_SURFACE_JNI_ID);
         return;
     }
+
+    fields.surfaceTexture = env->GetFieldID(clazz, "mSurfaceTexture",
+            "Landroid/graphics/SurfaceTexture;");
+    if (fields.surfaceTexture == NULL) {
+        jniThrowException(env, "java/lang/RuntimeException",
+                "Can't find MediaPlayer.mSurfaceTexture");
+        return;
+    }
+
+    jclass surfaceTexture = env->FindClass("android/graphics/SurfaceTexture");
+    if (surfaceTexture == NULL) {
+        jniThrowException(env, "java/lang/RuntimeException",
+                "Can't find android/graphics/SurfaceTexture");
+        return;
+    }
+
+    fields.surfaceTexture_native = env->GetFieldID(surfaceTexture,
+            ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
+    if (fields.surfaceTexture_native == NULL) {
+        jniThrowException(env, "java/lang/RuntimeException",
+                "Can't find SurfaceTexture." ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
+        return;
+    }
+
 }
 
 static void
@@ -746,7 +791,7 @@
     {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},
     {"setDataSource",       "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders},
     {"setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
-    {"_setVideoSurface",    "()V",                              (void *)android_media_MediaPlayer_setVideoSurface},
+    {"_setVideoSurfaceOrSurfaceTexture", "()V",                 (void *)android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture},
     {"prepare",             "()V",                              (void *)android_media_MediaPlayer_prepare},
     {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
     {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 74fb531..fd4c6c6 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -37,7 +37,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat \
-        libsurfaceflinger_client libcamera_client libstagefright_foundation
+        libsurfaceflinger_client libcamera_client libstagefright_foundation \
+        libgui
 
 LOCAL_MODULE:= libmedia
 
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index c287c0a..2399216 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -23,6 +23,7 @@
 #include <media/IMediaPlayer.h>
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/Surface.h>
+#include <gui/ISurfaceTexture.h>
 
 namespace android {
 
@@ -45,7 +46,8 @@
     SET_METADATA_FILTER,
     GET_METADATA,
     SET_AUX_EFFECT_SEND_LEVEL,
-    ATTACH_AUX_EFFECT
+    ATTACH_AUX_EFFECT,
+    SET_VIDEO_SURFACETEXTURE,
 };
 
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -64,6 +66,7 @@
         remote()->transact(DISCONNECT, data, &reply);
     }
 
+    // pass the buffered Surface to the media player service
     status_t setVideoSurface(const sp<Surface>& surface)
     {
         Parcel data, reply;
@@ -73,6 +76,17 @@
         return reply.readInt32();
     }
 
+    // pass the buffered ISurfaceTexture to the media player service
+    status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        sp<IBinder> b(surfaceTexture->asBinder());
+        data.writeStrongBinder(b);
+        remote()->transact(SET_VIDEO_SURFACETEXTURE, data, &reply);
+        return reply.readInt32();
+    }
+
     status_t prepareAsync()
     {
         Parcel data, reply;
@@ -220,6 +234,7 @@
         remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
         return reply.readInt32();
     }
+
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -241,6 +256,13 @@
             reply->writeInt32(setVideoSurface(surface));
             return NO_ERROR;
         } break;
+        case SET_VIDEO_SURFACETEXTURE: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            sp<ISurfaceTexture> surfaceTexture =
+                    interface_cast<ISurfaceTexture>(data.readStrongBinder());
+            reply->writeInt32(setVideoSurfaceTexture(surfaceTexture));
+            return NO_ERROR;
+        } break;
         case PREPARE_ASYNC: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             reply->writeInt32(prepareAsync());
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 87c8fe4..0ee0249a 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -201,6 +201,16 @@
     return mPlayer->setVideoSurface(surface);
 }
 
+status_t MediaPlayer::setVideoSurfaceTexture(
+        const sp<ISurfaceTexture>& surfaceTexture)
+{
+    LOGV("setVideoSurfaceTexture");
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == 0) return NO_INIT;
+
+    return mPlayer->setVideoSurfaceTexture(surfaceTexture);
+}
+
 // must call with lock held
 status_t MediaPlayer::prepareAsync_l()
 {
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index f7f0d95..e65f6d8 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -32,7 +32,8 @@
 	libstagefright        			\
 	libstagefright_omx    			\
 	libstagefright_foundation               \
-	libsurfaceflinger_client
+	libsurfaceflinger_client                \
+	libgui
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_rtsp                     \
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8c6f76b..ec6188f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -935,6 +935,15 @@
     return p->setVideoSurface(surface);
 }
 
+status_t MediaPlayerService::Client::setVideoSurfaceTexture(
+        const sp<ISurfaceTexture>& surfaceTexture)
+{
+    LOGV("[%d] setVideoSurfaceTexture(%p)", mConnId, surfaceTexture.get());
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == 0) return UNKNOWN_ERROR;
+    return p->setVideoSurfaceTexture(surfaceTexture);
+}
+
 status_t MediaPlayerService::Client::invoke(const Parcel& request,
                                             Parcel *reply)
 {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 9f41db0..1175ed0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -236,6 +236,8 @@
         // IMediaPlayer interface
         virtual void            disconnect();
         virtual status_t        setVideoSurface(const sp<Surface>& surface);
+        virtual status_t        setVideoSurfaceTexture(
+                                        const sp<ISurfaceTexture>& surfaceTexture);
         virtual status_t        prepareAsync();
         virtual status_t        start();
         virtual status_t        stop();
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index aa8f3f0e..a98231c 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -36,6 +36,9 @@
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
     virtual status_t    setVideoSurface(const sp<Surface>& surface) { return UNKNOWN_ERROR; }
+    virtual status_t    setVideoSurfaceTexture(
+                                const sp<ISurfaceTexture>& surfaceTexture)
+                            { return UNKNOWN_ERROR; }
     virtual status_t    prepare();
     virtual status_t    prepareAsync();
     virtual status_t    start();
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index da564dc..fdb4754 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -55,6 +55,14 @@
     return OK;
 }
 
+status_t StagefrightPlayer::setVideoSurfaceTexture(
+        const sp<ISurfaceTexture> &surfaceTexture) {
+    LOGV("setVideoSurfaceTexture");
+
+    mPlayer->setSurfaceTexture(surfaceTexture);
+    return OK;
+}
+
 status_t StagefrightPlayer::prepare() {
     return mPlayer->prepare();
 }
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index fc72bfb..e2796d2 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -39,6 +39,8 @@
     virtual status_t setDataSource(const sp<IStreamSource> &source);
 
     virtual status_t setVideoSurface(const sp<Surface> &surface);
+    virtual status_t setVideoSurfaceTexture(
+            const sp<ISurfaceTexture> &surfaceTexture);
     virtual status_t prepare();
     virtual status_t prepareAsync();
     virtual status_t start();
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
index 6abd8e3..d9c3db3 100644
--- a/media/libmediaplayerservice/TestPlayerStub.h
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -78,6 +78,10 @@
     virtual status_t setVideoSurface(const android::sp<android::Surface>& s)  {
         return mPlayer->setVideoSurface(s);
     }
+    virtual status_t setVideoSurfaceTexture(
+            const android::sp<android::ISurfaceTexture>& st)  {
+        return mPlayer->setVideoSurfaceTexture(st);
+    }
     virtual status_t prepare() {return mPlayer->prepare();}
     virtual status_t prepareAsync()  {return mPlayer->prepareAsync();}
     virtual status_t start()  {return mPlayer->start();}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 1fcf92b..48b517e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -37,6 +37,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <surfaceflinger/Surface.h>
+#include <gui/ISurfaceTexture.h>
 
 namespace android {
 
@@ -76,8 +77,16 @@
 }
 
 void NuPlayer::setVideoSurface(const sp<Surface> &surface) {
-    sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, id());
-    msg->setObject("surface", surface);
+    sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id());
+    msg->setObject("native-window", new NativeWindowWrapper(surface));
+    msg->post();
+}
+
+void NuPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
+    sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id());
+    sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ?
+                new SurfaceTextureClient(surfaceTexture) : NULL);
+    msg->setObject("native-window", new NativeWindowWrapper(surfaceTextureClient));
     msg->post();
 }
 
@@ -144,14 +153,14 @@
             break;
         }
 
-        case kWhatSetVideoSurface:
+        case kWhatSetVideoNativeWindow:
         {
-            LOGV("kWhatSetVideoSurface");
+            LOGV("kWhatSetVideoNativeWindow");
 
             sp<RefBase> obj;
-            CHECK(msg->findObject("surface", &obj));
+            CHECK(msg->findObject("native-window", &obj));
 
-            mSurface = static_cast<Surface *>(obj.get());
+            mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get());
             break;
         }
 
@@ -529,7 +538,8 @@
         new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify,
                      id());
 
-    *decoder = new Decoder(notify, audio ? NULL : mSurface);
+    *decoder = audio ? new Decoder(notify) :
+                       new Decoder(notify, mNativeWindow);
     looper()->registerHandler(*decoder);
 
     (*decoder)->configure(meta);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index bb65162..e7c6a42 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -20,6 +20,9 @@
 
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/NativeWindowWrapper.h>
+#include <gui/SurfaceTextureClient.h>
+#include <surfaceflinger/Surface.h>
 
 namespace android {
 
@@ -38,6 +41,7 @@
             const char *url, const KeyedVector<String8, String8> *headers);
 
     void setVideoSurface(const sp<Surface> &surface);
+    void setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture);
     void setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink);
     void start();
 
@@ -65,7 +69,7 @@
 
     enum {
         kWhatSetDataSource,
-        kWhatSetVideoSurface,
+        kWhatSetVideoNativeWindow,
         kWhatSetAudioSink,
         kWhatMoreDataQueued,
         kWhatStart,
@@ -81,7 +85,7 @@
 
     wp<NuPlayerDriver> mDriver;
     sp<Source> mSource;
-    sp<Surface> mSurface;
+    sp<NativeWindowWrapper> mNativeWindow;
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<Decoder> mVideoDecoder;
     sp<Decoder> mAudioDecoder;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 761dfa4..517acc9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -31,13 +31,15 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 #include <surfaceflinger/Surface.h>
+#include <gui/ISurfaceTexture.h>
 
 namespace android {
 
 NuPlayer::Decoder::Decoder(
-        const sp<AMessage> &notify, const sp<Surface> &surface)
+        const sp<AMessage> &notify,
+        const sp<NativeWindowWrapper> &nativeWindow)
     : mNotify(notify),
-      mSurface(surface) {
+      mNativeWindow(nativeWindow) {
 }
 
 NuPlayer::Decoder::~Decoder() {
@@ -55,8 +57,8 @@
 
     sp<AMessage> format = makeFormat(meta);
 
-    if (mSurface != NULL) {
-        format->setObject("surface", mSurface);
+    if (mNativeWindow != NULL) {
+        format->setObject("native-window", mNativeWindow);
     }
 
     if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 3874cfe..732f090 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -28,7 +28,8 @@
 struct DecoderWrapper;
 
 struct NuPlayer::Decoder : public AHandler {
-    Decoder(const sp<AMessage> &notify, const sp<Surface> &surface = NULL);
+    Decoder(const sp<AMessage> &notify,
+            const sp<NativeWindowWrapper> &nativeWindow = NULL);
 
     void configure(const sp<MetaData> &meta);
 
@@ -47,7 +48,7 @@
     };
 
     sp<AMessage> mNotify;
-    sp<Surface> mSurface;
+    sp<NativeWindowWrapper> mNativeWindow;
 
     sp<ACodec> mCodec;
     sp<DecoderWrapper> mWrapper;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index ac19a2f..0eca958 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -86,6 +86,13 @@
     return OK;
 }
 
+status_t NuPlayerDriver::setVideoSurfaceTexture(
+        const sp<ISurfaceTexture> &surfaceTexture) {
+    mPlayer->setVideoSurfaceTexture(surfaceTexture);
+
+    return OK;
+}
+
 status_t NuPlayerDriver::prepare() {
     return OK;
 }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index e3a5de4..67d0f3e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -36,6 +36,8 @@
     virtual status_t setDataSource(const sp<IStreamSource> &source);
 
     virtual status_t setVideoSurface(const sp<Surface> &surface);
+    virtual status_t setVideoSurfaceTexture(
+            const sp<ISurfaceTexture> &surfaceTexture);
     virtual status_t prepare();
     virtual status_t prepareAsync();
     virtual status_t start();
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 505d9d4..b0ae3d8 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -11,9 +11,11 @@
 #include <media/stagefright/foundation/AMessage.h>
 
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/NativeWindowWrapper.h>
 #include <media/stagefright/OMXClient.h>
 
 #include <surfaceflinger/Surface.h>
+#include <gui/SurfaceTextureClient.h>
 
 #include <OMX_Component.h>
 
@@ -1633,8 +1635,11 @@
     mCodec->configureCodec(mime.c_str(), msg);
 
     sp<RefBase> obj;
-    if (msg->findObject("surface", &obj)) {
-        mCodec->mNativeWindow = static_cast<Surface *>(obj.get());
+    if (msg->findObject("native-window", &obj)) {
+        sp<NativeWindowWrapper> nativeWindow(
+                static_cast<NativeWindowWrapper *>(obj.get()));
+        CHECK(nativeWindow != NULL);
+        mCodec->mNativeWindow = nativeWindow->getNativeWindow();
     }
 
     CHECK_EQ((status_t)OK, mCodec->initNativeWindow());
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 80eb59f..88069e9 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -74,7 +74,8 @@
         libcamera_client \
         libdrmframework  \
         libcrypto        \
-        libssl
+        libssl           \
+        libgui
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_color_conversion \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 1b63ab2..36623f6 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -43,6 +43,8 @@
 #include <media/stagefright/OMXCodec.h>
 
 #include <surfaceflinger/Surface.h>
+#include <gui/ISurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
 
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -83,8 +85,8 @@
 
 struct AwesomeLocalRenderer : public AwesomeRenderer {
     AwesomeLocalRenderer(
-            const sp<Surface> &surface, const sp<MetaData> &meta)
-        : mTarget(new SoftwareRenderer(surface, meta)) {
+            const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
+        : mTarget(new SoftwareRenderer(nativeWindow, meta)) {
     }
 
     virtual void render(MediaBuffer *buffer) {
@@ -889,7 +891,7 @@
 }
 
 void AwesomePlayer::initRenderer_l() {
-    if (mSurface == NULL) {
+    if (mNativeWindow == NULL) {
         return;
     }
 
@@ -920,13 +922,13 @@
         // directly to ANativeBuffers, so we must use a renderer that
         // just pushes those buffers to the ANativeWindow.
         mVideoRenderer =
-            new AwesomeNativeWindowRenderer(mSurface, rotationDegrees);
+            new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
     } else {
         // Other decoders are instantiated locally and as a consequence
         // allocate their buffers in local address space.  This renderer
         // then performs a color conversion and copy to get the data
         // into the ANativeBuffer.
-        mVideoRenderer = new AwesomeLocalRenderer(mSurface, meta);
+        mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
     }
 }
 
@@ -986,6 +988,17 @@
     Mutex::Autolock autoLock(mLock);
 
     mSurface = surface;
+    mNativeWindow = surface;
+}
+
+void AwesomePlayer::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
+    Mutex::Autolock autoLock(mLock);
+
+    mSurface.clear();
+    if (surfaceTexture != NULL) {
+        mNativeWindow = new SurfaceTextureClient(surfaceTexture);
+    }
+
 }
 
 void AwesomePlayer::setAudioSink(
@@ -1164,7 +1177,7 @@
             mClient.interface(), mVideoTrack->getFormat(),
             false, // createEncoder
             mVideoTrack,
-            NULL, flags, USE_SURFACE_ALLOC ? mSurface : NULL);
+            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
 
     if (mVideoSource != NULL) {
         int64_t durationUs;
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 70408d7..31afc43 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -26,14 +26,15 @@
 #include <surfaceflinger/Surface.h>
 #include <ui/android_native_buffer.h>
 #include <ui/GraphicBufferMapper.h>
+#include <gui/ISurfaceTexture.h>
 
 namespace android {
 
 SoftwareRenderer::SoftwareRenderer(
-        const sp<Surface> &surface, const sp<MetaData> &meta)
+        const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
     : mConverter(NULL),
       mYUVMode(None),
-      mSurface(surface) {
+      mNativeWindow(nativeWindow) {
     int32_t tmp;
     CHECK(meta->findInt32(kKeyColorFormat, &tmp));
     mColorFormat = (OMX_COLOR_FORMATTYPE)tmp;
@@ -65,22 +66,22 @@
             break;
     }
 
-    CHECK(mSurface.get() != NULL);
+    CHECK(mNativeWindow != NULL);
     CHECK(mWidth > 0);
     CHECK(mHeight > 0);
     CHECK(mConverter == NULL || mConverter->isValid());
 
     CHECK_EQ(0,
             native_window_set_usage(
-            mSurface.get(),
+            mNativeWindow.get(),
             GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
             | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
 
-    CHECK_EQ(0, native_window_set_buffer_count(mSurface.get(), 2));
+    CHECK_EQ(0, native_window_set_buffer_count(mNativeWindow.get(), 2));
 
     // Width must be multiple of 32???
     CHECK_EQ(0, native_window_set_buffers_geometry(
-                mSurface.get(),
+                mNativeWindow.get(),
                 mCropRight - mCropLeft + 1,
                 mCropBottom - mCropTop + 1,
                 halFormat));
@@ -96,7 +97,7 @@
 
     if (transform) {
         CHECK_EQ(0, native_window_set_buffers_transform(
-                    mSurface.get(), transform));
+                    mNativeWindow.get(), transform));
     }
 }
 
@@ -109,12 +110,12 @@
         const void *data, size_t size, void *platformPrivate) {
     android_native_buffer_t *buf;
     int err;
-    if ((err = mSurface->dequeueBuffer(mSurface.get(), &buf)) != 0) {
+    if ((err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf)) != 0) {
         LOGW("Surface::dequeueBuffer returned error %d", err);
         return;
     }
 
-    CHECK_EQ(0, mSurface->lockBuffer(mSurface.get(), buf));
+    CHECK_EQ(0, mNativeWindow->lockBuffer(mNativeWindow.get(), buf));
 
     GraphicBufferMapper &mapper = GraphicBufferMapper::get();
 
@@ -140,7 +141,7 @@
 
     CHECK_EQ(0, mapper.unlock(buf->handle));
 
-    if ((err = mSurface->queueBuffer(mSurface.get(), buf)) != 0) {
+    if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf)) != 0) {
         LOGW("Surface::queueBuffer returned error %d", err);
     }
     buf = NULL;
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 1497732..0e36492 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -36,6 +36,7 @@
 struct MediaExtractor;
 struct MediaSource;
 struct NuCachedSource2;
+struct ISurfaceTexture;
 
 struct ALooper;
 struct ARTSPController;
@@ -80,6 +81,7 @@
     bool isPlaying() const;
 
     void setSurface(const sp<Surface> &surface);
+    void setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture);
     void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
     status_t setLooping(bool shouldLoop);
 
@@ -133,6 +135,7 @@
     wp<MediaPlayerBase> mListener;
 
     sp<Surface> mSurface;
+    sp<ANativeWindow> mNativeWindow;
     sp<MediaPlayerBase::AudioSink> mAudioSink;
 
     SystemTimeSource mSystemTimeSource;
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index 90d3fe1..78037b97 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -20,16 +20,16 @@
 
 #include <media/stagefright/ColorConverter.h>
 #include <utils/RefBase.h>
+#include <ui/android_native_buffer.h>
 
 namespace android {
 
 struct MetaData;
-class Surface;
 
 class SoftwareRenderer {
 public:
     SoftwareRenderer(
-            const sp<Surface> &surface, const sp<MetaData> &meta);
+            const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta);
 
     ~SoftwareRenderer();
 
@@ -44,7 +44,7 @@
     OMX_COLOR_FORMATTYPE mColorFormat;
     ColorConverter *mConverter;
     YUVMode mYUVMode;
-    sp<Surface> mSurface;
+    sp<ANativeWindow> mNativeWindow;
     int32_t mWidth, mHeight;
     int32_t mCropLeft, mCropTop, mCropRight, mCropBottom;
 
diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp
index 1e3731e..d571106 100644
--- a/media/tests/players/invoke_mock_media_player.cpp
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -25,8 +25,8 @@
 #include <utils/Errors.h>
 
 using android::INVALID_OPERATION;
-using android::ISurface;
 using android::Surface;
+using android::ISurfaceTexture;
 using android::MediaPlayerBase;
 using android::OK;
 using android::Parcel;
@@ -69,6 +69,8 @@
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) {return OK;}
     virtual status_t    setVideoSurface(const sp<Surface>& surface) {return OK;}
+    virtual status_t    setVideoSurfaceTexture(
+                                const sp<ISurfaceTexture>& surfaceTexture) {return OK;}
     virtual status_t    prepare() {return OK;}
     virtual status_t    prepareAsync() {return OK;}
     virtual status_t    start() {return OK;}