Merge "Video editor API update - rework for Patch Set 3" into honeycomb
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 002e48b..79c33f5 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -40,6 +40,10 @@
     enum { MIN_BUFFER_SLOTS = 3 };
     enum { NUM_BUFFER_SLOTS = 32 };
 
+    struct FrameAvailableListener : public virtual RefBase {
+        virtual void onFrameAvailable() = 0;
+    };
+
     // tex indicates the name OpenGL texture to which images are to be streamed.
     // This texture name cannot be changed once the SurfaceTexture is created.
     SurfaceTexture(GLuint tex);
@@ -93,6 +97,10 @@
     // functions.
     void getTransformMatrix(float mtx[16]);
 
+    // setFrameAvailableListener sets the listener object that will be notified
+    // when a new frame becomes available.
+    void setFrameAvailableListener(const sp<FrameAvailableListener>& l);
+
 private:
 
     // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
@@ -195,6 +203,11 @@
     // to a buffer, but other processes do.
     Vector<sp<GraphicBuffer> > mAllocdBuffers;
 
+    // mFrameAvailableListener is the listener object that will be called when a
+    // new frame becomes available. If it is not NULL it will be called from
+    // queueBuffer.
+    sp<FrameAvailableListener> mFrameAvailableListener;
+
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 5532052..d783caf 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -100,6 +100,9 @@
     friend class MediaPlayer;
     // for testing
     friend class Test;
+    // videoEditor preview classes
+    friend class VideoEditorPreviewController;
+
     const sp<ISurface>& getISurface() const { return mSurface; }
     
 
@@ -181,6 +184,9 @@
     friend class SoftwareRenderer;
     // this is just to be able to write some unit tests
     friend class Test;
+    // videoEditor preview classes
+    friend class VideoEditorPreviewController;
+    friend class PreviewRenderer;
 
 private:
     friend class SurfaceComposerClient;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 447de76..1dadd53 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -166,6 +166,9 @@
     mLastQueued = buf;
     mLastQueuedCrop = mNextCrop;
     mLastQueuedTransform = mNextTransform;
+    if (mFrameAvailableListener != 0) {
+        mFrameAvailableListener->onFrameAvailable();
+    }
     return OK;
 }
 
@@ -237,43 +240,68 @@
     LOGV("SurfaceTexture::updateTexImage");
     Mutex::Autolock lock(mMutex);
 
-    float* xform = mtxIdentity;
-    switch (mCurrentTransform) {
-        case 0:
-            xform = mtxIdentity;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_FLIP_H:
-            xform = mtxFlipH;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_FLIP_V:
-            xform = mtxFlipV;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_ROT_90:
-            xform = mtxRot90;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_ROT_180:
-            xform = mtxRot180;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_ROT_270:
-            xform = mtxRot270;
-            break;
-        default:
-            LOGE("getTransformMatrix: unknown transform: %d", mCurrentTransform);
+    float xform[16];
+    for (int i = 0; i < 16; i++) {
+        xform[i] = mtxIdentity[i];
+    }
+    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+        float result[16];
+        mtxMul(result, xform, mtxFlipH);
+        for (int i = 0; i < 16; i++) {
+            xform[i] = result[i];
+        }
+    }
+    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+        float result[16];
+        mtxMul(result, xform, mtxFlipV);
+        for (int i = 0; i < 16; i++) {
+            xform[i] = result[i];
+        }
+    }
+    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        float result[16];
+        mtxMul(result, xform, mtxRot90);
+        for (int i = 0; i < 16; i++) {
+            xform[i] = result[i];
+        }
     }
 
     sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
-    float tx = float(mCurrentCrop.left) / float(buf->getWidth());
-    float ty = float(mCurrentCrop.bottom) / float(buf->getHeight());
-    float sx = float(mCurrentCrop.width()) / float(buf->getWidth());
-    float sy = float(mCurrentCrop.height()) / float(buf->getHeight());
+    float tx, ty, sx, sy;
+    if (!mCurrentCrop.isEmpty()) {
+        tx = float(mCurrentCrop.left) / float(buf->getWidth());
+        ty = float(buf->getHeight() - mCurrentCrop.bottom) /
+                float(buf->getHeight());
+        sx = float(mCurrentCrop.width()) / float(buf->getWidth());
+        sy = float(mCurrentCrop.height()) / float(buf->getHeight());
+    } else {
+        tx = 0.0f;
+        ty = 0.0f;
+        sx = 1.0f;
+        sy = 1.0f;
+    }
     float crop[16] = {
-        sx, 0, 0, sx*tx,
-        0, sy, 0, sy*ty,
+        sx, 0, 0, 0,
+        0, sy, 0, 0,
         0, 0, 1, 0,
-        0, 0, 0, 1,
+        sx*tx, sy*ty, 0, 1,
     };
 
-    mtxMul(mtx, crop, xform);
+    float mtxBeforeFlipV[16];
+    mtxMul(mtxBeforeFlipV, crop, xform);
+
+    // SurfaceFlinger expects the top of its window textures to be at a Y
+    // coordinate of 0, so SurfaceTexture must behave the same way.  We don't
+    // want to expose this to applications, however, so we must add an
+    // additional vertical flip to the transform after all the other transforms.
+    mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
+}
+
+void SurfaceTexture::setFrameAvailableListener(
+        const sp<FrameAvailableListener>& l) {
+    LOGV("SurfaceTexture::setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = l;
 }
 
 void SurfaceTexture::freeAllBuffers() {
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 386cc5d..ed36171 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -62,6 +62,8 @@
         "EGL_KHR_image_base "
         "EGL_KHR_image_pixmap "
         "EGL_KHR_gl_texture_2D_image "
+        "EGL_KHR_gl_texture_cubemap_image "
+        "EGL_KHR_gl_renderbuffer_image "
         "EGL_KHR_fence_sync "
         "EGL_ANDROID_image_native_buffer "
         "EGL_ANDROID_swap_rectangle "
@@ -1471,6 +1473,29 @@
     return result;
 }
 
+// Note: Similar implementations of these functions also exist in
+// gl2.cpp and gl.cpp, and are used by applications that call the
+// exported entry points directly.
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+
+static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
+static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
+
+static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
+{
+    GLeglImageOES implImage =
+        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+    glEGLImageTargetTexture2DOES_impl(target, implImage);
+}
+
+static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
+{
+    GLeglImageOES implImage =
+        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+    glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
+}
+
 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
 {
     // eglGetProcAddress() could be the very first function called
@@ -1531,6 +1556,16 @@
             }
             if (found) {
                 addr = gExtensionForwarders[slot];
+
+                if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
+                    glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
+                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
+                }
+                if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
+                    glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
+                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
+                }
+
                 gGLExtentionMap.add(name, addr);
                 gGLExtentionSlot++;
             }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 154b822..65ad956 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2132,6 +2132,9 @@
     sh = (!sh) ? hw_h : sh;
     const size_t size = sw * sh * 4;
 
+    LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
+            sw, sh, minLayerZ, maxLayerZ);
+
     // make sure to clear all GL error flags
     while ( glGetError() != GL_NO_ERROR ) ;
 
@@ -2146,6 +2149,9 @@
             GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
 
     GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
+
+    LOGD("screenshot: FBO created, status=0x%x", status);
+
     if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
 
         // invert everything, b/c glReadPixel() below will invert the FB
@@ -2161,6 +2167,8 @@
         glClearColor(0,0,0,1);
         glClear(GL_COLOR_BUFFER_BIT);
 
+        LOGD("screenshot: glClear() issued");
+
         const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
         const size_t count = layers.size();
         for (size_t i=0 ; i<count ; ++i) {
@@ -2171,6 +2179,8 @@
             }
         }
 
+        LOGD("screenshot: All layers rendered");
+
         // XXX: this is needed on tegra
         glScissor(0, 0, sw, sh);
 
@@ -2185,6 +2195,10 @@
                     new MemoryHeapBase(size, 0, "screen-capture") );
             void* const ptr = base->getBase();
             if (ptr) {
+
+                LOGD("screenshot: about to call glReadPixels(0,0,%d,%d,...,%p)",
+                        sw, sh, ptr);
+
                 // capture the screen with glReadPixels()
                 glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
                 if (glGetError() == GL_NO_ERROR) {
@@ -2197,25 +2211,32 @@
             } else {
                 result = NO_MEMORY;
             }
+
+            LOGD("screenshot: glReadPixels() returned %s", strerror(result));
+
         }
         glEnable(GL_SCISSOR_TEST);
         glViewport(0, 0, hw_w, hw_h);
         glMatrixMode(GL_PROJECTION);
         glPopMatrix();
         glMatrixMode(GL_MODELVIEW);
-
-
     } else {
         result = BAD_VALUE;
     }
 
+    LOGD("screenshot: about to release FBO resources");
+
     // release FBO resources
     glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
     glDeleteRenderbuffersOES(1, &tname);
     glDeleteFramebuffersOES(1, &name);
 
+    LOGD("screenshot: about to call compositionComplete()");
+
     hw.compositionComplete();
 
+    LOGD("screenshot: result = %s", strerror(result));
+
     return result;
 }