Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0de171b0 authored by Ted Bonkenburg's avatar Ted Bonkenburg
Browse files

Add support for creating a Surface from a a SurfaceTexture.

The Surface is already using SurfaceTexture internally and it is parcelable. This
is intended to replace and phase out ParcelSurfaceTexture in favor of creating a
new Surface.java object from an existing SurfaceTexture.

Change-Id: I8e2dd86614523da6abed6403e1d705a68fa19fdf
parent 7699c18a
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -161,6 +161,9 @@ public class Surface implements Parcelable {
     */
    public static final int FLAGS_ORIENTATION_ANIMATION_DISABLE = 0x000000001;

    // The mSurfaceControl will only be present for Surfaces used by the window
    // server or system processes. When this class is parceled we defer to the
    // mSurfaceControl to do the parceling. Otherwise we parcel the mNativeSurface.
    @SuppressWarnings("unused")
    private int mSurfaceControl;
    @SuppressWarnings("unused")
@@ -202,6 +205,19 @@ public class Surface implements Parcelable {
    native private static void nativeClassInit();
    static { nativeClassInit(); }

    /**
     * Create Surface from a SurfaceTexture.
     *
     * @param surfaceTexture The {@link SurfaceTexture} that is updated by this Surface.
     * @hide
     */
    public Surface(SurfaceTexture surfaceTexture) {
        if (DEBUG_RELEASE) {
            mCreationStack = new Exception();
        }
        mCanvas = new CompatibleCanvas();
        initFromSurfaceTexture(surfaceTexture);
    }
    
    /**
     * create a surface
@@ -505,5 +521,7 @@ public class Surface implements Parcelable {

    private native void init(Parcel source);

    private native void initFromSurfaceTexture(SurfaceTexture surfaceTexture);

    private native int getIdentity();
}
+34 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include "android/graphics/GraphicsJNI.h"

#include <binder/IMemory.h>
#include <gui/SurfaceTexture.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/Surface.h>
#include <ui/Region.h>
@@ -38,6 +39,7 @@
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
#include <utils/misc.h>


@@ -244,6 +246,19 @@ static void Surface_init(
    setSurfaceControl(env, clazz, surface);
}

static void Surface_initFromSurfaceTexture(
        JNIEnv* env, jobject clazz, jobject jst)
{
    sp<ISurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, jst));
    sp<Surface> surface(new Surface(st));
    if (surface == NULL) {
        jniThrowException(env, OutOfResourcesException, NULL);
        return;
    }
    setSurfaceControl(env, clazz, NULL);
    setSurface(env, clazz, surface);
}

static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
{
    Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel);
@@ -761,10 +776,26 @@ static void Surface_writeToParcel(
        return;
    }

    // The Java instance may have a SurfaceControl (in the case of the
    // WindowManager or a system app). In that case, we defer to the
    // SurfaceControl to send its ISurface. Otherwise, if the Surface is
    // available we let it parcel itself. Finally, if the Surface is also
    // NULL we fall back to using the SurfaceControl path which sends an
    // empty surface; this matches legacy behavior.
    const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
    if (control != NULL) {
        SurfaceControl::writeSurfaceToParcel(control, parcel);
    } else {
        sp<Surface> surface(Surface_getSurface(env, clazz));
        if (surface != NULL) {
            Surface::writeToParcel(surface, parcel);
        } else {
            SurfaceControl::writeSurfaceToParcel(NULL, parcel);
        }
    }
    if (flags & PARCELABLE_WRITE_RETURN_VALUE) {
        setSurfaceControl(env, clazz, 0);
        setSurfaceControl(env, clazz, NULL);
        setSurface(env, clazz, NULL);
    }
}

@@ -784,6 +815,7 @@ static JNINativeMethod gSurfaceMethods[] = {
    {"nativeClassInit",     "()V",  (void*)nativeClassInit },
    {"init",                "(Landroid/view/SurfaceSession;ILjava/lang/String;IIIII)V",  (void*)Surface_init },
    {"init",                "(Landroid/os/Parcel;)V",  (void*)Surface_initParcel },
    {"initFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)V", (void*)Surface_initFromSurfaceTexture },
    {"getIdentity",         "()I",  (void*)Surface_getIdentity },
    {"destroy",             "()V",  (void*)Surface_destroy },
    {"release",             "()V",  (void*)Surface_release },
+5 −2
Original line number Diff line number Diff line
@@ -122,7 +122,10 @@ public:
        uint32_t    reserved[2];
    };

    explicit Surface(const sp<ISurfaceTexture>& st);

    static status_t writeToParcel(const sp<Surface>& control, Parcel* parcel);

    static sp<Surface> readFromParcel(const Parcel& data);
    static bool isValid(const sp<Surface>& surface) {
        return (surface != 0) && surface->isValid();
@@ -147,14 +150,14 @@ private:
    Surface& operator = (Surface& rhs);
    Surface(const Surface& rhs);

    Surface(const sp<SurfaceControl>& control);
    explicit Surface(const sp<SurfaceControl>& control);
    Surface(const Parcel& data, const sp<IBinder>& ref);
    ~Surface();

    /*
     *  private stuff...
     */
    void init();
    void init(const sp<ISurfaceTexture>& surfaceTexture);

    static void cleanCachedSurfacesLocked();

+42 −14
Original line number Diff line number Diff line
@@ -184,6 +184,7 @@ status_t SurfaceControl::writeSurfaceToParcel(
        identity = control->mIdentity;
    }
    parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
    parcel->writeStrongBinder(NULL);  // NULL ISurfaceTexture in this case.
    parcel->writeInt32(identity);
    return NO_ERROR;
}
@@ -192,7 +193,8 @@ sp<Surface> SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
        sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this));
        mSurfaceData = new Surface(surface_control);
    }
    return mSurfaceData;
}
@@ -208,31 +210,58 @@ Surface::Surface(const sp<SurfaceControl>& surface)
      mSurface(surface->mSurface),
      mIdentity(surface->mIdentity)
{
    init();
    sp<ISurfaceTexture> st;
    if (mSurface != NULL) {
        st = mSurface->getSurfaceTexture();
    }
    init(st);
}

Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
    : SurfaceTextureClient()
{
    mSurface = interface_cast<ISurface>(ref);
    sp<IBinder> st_binder(parcel.readStrongBinder());
    sp<ISurfaceTexture> st;
    if (st_binder != NULL) {
        st = interface_cast<ISurfaceTexture>(st_binder);
    } else if (mSurface != NULL) {
        st = mSurface->getSurfaceTexture();
    }

    mIdentity   = parcel.readInt32();
    init();
    init(st);
}

Surface::Surface(const sp<ISurfaceTexture>& st)
    : SurfaceTextureClient(),
      mSurface(NULL),
      mIdentity(0)
{
    init(st);
}

status_t Surface::writeToParcel(
        const sp<Surface>& surface, Parcel* parcel)
{
    sp<ISurface> sur;
    sp<ISurfaceTexture> st;
    uint32_t identity = 0;
    if (Surface::isValid(surface)) {
        sur      = surface->mSurface;
        st       = surface->getISurfaceTexture();
        identity = surface->mIdentity;
    } else if (surface != 0 && surface->mSurface != 0) {
        LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
             "mSurface = %p, mIdentity = %d",
             surface->mSurface.get(), surface->mIdentity);
    } else if (surface != 0 &&
            (surface->mSurface != NULL ||
             surface->getISurfaceTexture() != NULL)) {
        LOGE("Parceling invalid surface with non-NULL ISurface/ISurfaceTexture as NULL: "
             "mSurface = %p, surfaceTexture = %p, mIdentity = %d, ",
             surface->mSurface.get(), surface->getISurfaceTexture().get(),
             surface->mIdentity);
    }
    parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);

    parcel->writeStrongBinder(sur != NULL ? sur->asBinder() : NULL);
    parcel->writeStrongBinder(st != NULL ? st->asBinder() : NULL);
    parcel->writeInt32(identity);
    return NO_ERROR;

@@ -249,7 +278,7 @@ sp<Surface> Surface::readFromParcel(const Parcel& data) {
       surface = new Surface(data, binder);
       sCachedSurfaces.add(binder, surface);
    }
    if (surface->mSurface == 0) {
    if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
        surface = 0;
    }
    cleanCachedSurfacesLocked();
@@ -267,10 +296,9 @@ void Surface::cleanCachedSurfacesLocked() {
    }
}

void Surface::init()
void Surface::init(const sp<ISurfaceTexture>& surfaceTexture)
{
    if (mSurface != NULL) {
        sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
    if (mSurface != NULL || surfaceTexture != NULL) {
        LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
        if (surfaceTexture != NULL) {
            setISurfaceTexture(surfaceTexture);
+25 −4
Original line number Diff line number Diff line
@@ -611,7 +611,7 @@ public class MediaPlayer
     * needed.  Not calling this method when playing back a video will
     * result in only the audio track being played.
     *
     * Either a surface or surface texture must be set if a display or video sink
     * Either a surface holder or surface 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.
     *
@@ -629,6 +629,27 @@ public class MediaPlayer
        updateSurfaceScreenOn();
    }

    /**
     * Sets the {@link Surface} to be used as the sink for the video portion of
     * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but does not
     * support {@link #setScreenOnWhilePlaying(boolean)} or {@link #updateSurfaceScreenOn()}.
     * Setting a Surface will un-set any Surface or SurfaceHolder that was previously set.
     *
     * @param surface The {@link Surface} to be used for the video portion of the media.
     *
     * @hide Pending review by API council.
     */
    public void setSurface(Surface surface) {
        if (mScreenOnWhilePlaying && surface != null && mSurface != null) {
            Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
        }
        mSurfaceHolder = null;
        mSurface = surface;
        mParcelSurfaceTexture = null;  // TODO(tedbo): Remove.
        _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
@@ -665,7 +686,7 @@ public class MediaPlayer
     * @param pst The {@link ParcelSurfaceTexture} to be used as the sink for
     * the video portion of the media.
     *
     * @hide Pending review by API council.
     * @hide Pending removal when there are no more callers.
     */
    public void setParcelSurfaceTexture(ParcelSurfaceTexture pst) {
        if (mScreenOnWhilePlaying && pst != null && mParcelSurfaceTexture == null) {
@@ -1000,8 +1021,8 @@ public class MediaPlayer
     */
    public void setScreenOnWhilePlaying(boolean screenOn) {
        if (mScreenOnWhilePlaying != screenOn) {
            if (screenOn && mParcelSurfaceTexture != null) {
                Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for SurfaceTexture");
            if (screenOn && mSurfaceHolder == null) {
                Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder");
            }
            mScreenOnWhilePlaying = screenOn;
            updateSurfaceScreenOn();