]> git.sesse.net Git - mlt/commitdiff
Add the new opengl module (opengl branch).
authorDan Dennedy <dan@dennedy.org>
Thu, 21 Feb 2013 04:25:58 +0000 (20:25 -0800)
committerDan Dennedy <dan@dennedy.org>
Thu, 21 Feb 2013 04:25:58 +0000 (20:25 -0800)
41 files changed:
src/modules/opengl/Makefile [new file with mode: 0644]
src/modules/opengl/configure [new file with mode: 0755]
src/modules/opengl/consumer_xgl.c [new file with mode: 0644]
src/modules/opengl/factory.c [new file with mode: 0644]
src/modules/opengl/fbo_input.cpp [new file with mode: 0644]
src/modules/opengl/fbo_input.h [new file with mode: 0644]
src/modules/opengl/filter_deconvolution_sharpen.cpp [new file with mode: 0644]
src/modules/opengl/filter_deconvolution_sharpen.yml [new file with mode: 0644]
src/modules/opengl/filter_glsl_manager.cpp [new file with mode: 0644]
src/modules/opengl/filter_lift_gamma_gain.cpp [new file with mode: 0644]
src/modules/opengl/filter_lift_gamma_gain.yml [new file with mode: 0644]
src/modules/opengl/filter_movit_blur.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_blur.yml [new file with mode: 0644]
src/modules/opengl/filter_movit_convert.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_crop.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_diffusion.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_diffusion.yml [new file with mode: 0644]
src/modules/opengl/filter_movit_glow.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_glow.yml [new file with mode: 0644]
src/modules/opengl/filter_movit_mirror.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_mirror.yml [new file with mode: 0644]
src/modules/opengl/filter_movit_opacity.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_opacity.yml [new file with mode: 0644]
src/modules/opengl/filter_movit_rect.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_rect.yml [new file with mode: 0644]
src/modules/opengl/filter_movit_resample.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_resize.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_saturation.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_saturation.yml [new file with mode: 0644]
src/modules/opengl/filter_movit_vignette.cpp [new file with mode: 0644]
src/modules/opengl/filter_movit_vignette.yml [new file with mode: 0644]
src/modules/opengl/filter_white_balance.cpp [new file with mode: 0644]
src/modules/opengl/filter_white_balance.yml [new file with mode: 0644]
src/modules/opengl/glsl_manager.h [new file with mode: 0644]
src/modules/opengl/mlt_flip_effect.h [new file with mode: 0644]
src/modules/opengl/mlt_movit_input.cpp [new file with mode: 0644]
src/modules/opengl/mlt_movit_input.h [new file with mode: 0644]
src/modules/opengl/transition_movit_mix.cpp [new file with mode: 0644]
src/modules/opengl/transition_movit_mix.yml [new file with mode: 0644]
src/modules/opengl/transition_movit_overlay.cpp [new file with mode: 0644]
src/modules/opengl/transition_movit_overlay.yml [new file with mode: 0644]

diff --git a/src/modules/opengl/Makefile b/src/modules/opengl/Makefile
new file mode 100644 (file)
index 0000000..10276a9
--- /dev/null
@@ -0,0 +1,77 @@
+CFLAGS += -I../..
+
+LDFLAGS += -L../../framework -lmlt -lm
+
+include ../../../config.mak
+
+TARGET = ../libmltopengl$(LIBSUF)
+
+OBJS = factory.o
+
+CPPOBJS = fbo_input.o
+CPPOBJS += filter_glsl_manager.o
+CPPOBJS += filter_movit_blur.o
+CPPOBJS += filter_movit_convert.o
+CPPOBJS += filter_movit_crop.o
+CPPOBJS += filter_deconvolution_sharpen.o
+CPPOBJS += filter_movit_diffusion.o
+CPPOBJS += filter_movit_glow.o
+CPPOBJS += filter_lift_gamma_gain.o
+CPPOBJS += filter_movit_mirror.o
+CPPOBJS += filter_movit_opacity.o
+CPPOBJS += filter_movit_rect.o
+CPPOBJS += filter_movit_resample.o
+CPPOBJS += filter_movit_resize.o
+CPPOBJS += filter_movit_saturation.o
+CPPOBJS += filter_movit_vignette.o
+CPPOBJS += filter_white_balance.o
+CPPOBJS += mlt_movit_input.o
+CPPOBJS += transition_movit_mix.o
+CPPOBJS += transition_movit_overlay.o
+
+CXXFLAGS += -Wno-deprecated $(CFLAGS)
+CXXFLAGS += `pkg-config --cflags movit 2> /dev/null`
+
+SHADERDIR = `pkg-config --variable=shaderdir movit`
+CXXFLAGS += -DSHADERDIR=\"$(SHADERDIR)\"
+
+LDFLAGS += -L../../mlt++ -lmlt++
+
+ifeq ($(targetos), MinGW)
+       CXXFLAGS += `pkg-config --cflags glew`
+       LDFLAGS += -lmovit `pkg-config --libs-only-L glew` -lglew32 -lopengl32
+else
+       LDFLAGS += `pkg-config --libs movit 2> /dev/null`
+ifeq ($(targetos), Darwin)
+       CXXFLAGS += -FOpenGL
+       LDFLAGS += -framework OpenGL
+else
+       OBJS += consumer_xgl.o
+       LDFLAGS += -lpthread -lGL -lX11
+endif
+endif
+
+SRCS := $(OBJS:.o=.c) $(CPPOBJS:.o=.cpp)
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS) $(CPPOBJS)
+               $(CXX) $(SHFLAGS) -o $@ $(OBJS) $(CPPOBJS) $(LDFLAGS)
+
+depend:        $(SRCS)
+               $(CXX) -MM $(CXXFLAGS) $^ 1>.depend
+
+distclean:     clean
+               rm -f .depend config.h config.mak
+
+clean: 
+               rm -f $(OBJS) $(TARGET) $(CPPOBJS)
+
+install: all
+       install -m 755 $(TARGET) "$(DESTDIR)$(libdir)/mlt"
+       install -d "$(DESTDIR)$(datadir)/mlt/opengl/movit"
+       install -m 644 *.yml "$(DESTDIR)$(datadir)/mlt/opengl"
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/src/modules/opengl/configure b/src/modules/opengl/configure
new file mode 100755 (executable)
index 0000000..3065ba1
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+if [ "$help" != "1" ]
+then
+       if ! $(pkg-config movit)
+       then
+               echo "- movit not found: disabling"
+               touch ../disable-opengl
+               exit 0
+       fi
+
+       echo > config.mak
+       case $targetos in
+       Darwin)
+               ;;
+       MinGW)
+               ;;
+       *)
+               ;;
+       esac
+       exit 0
+fi
diff --git a/src/modules/opengl/consumer_xgl.c b/src/modules/opengl/consumer_xgl.c
new file mode 100644 (file)
index 0000000..6eae9f1
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * consumer_xgl.c
+ * Copyright (C) 2012 Christophe Thommeret
+ * Author: Christophe Thommeret <hftom@free.fr>
+ * Based on Nehe's GLX port by Mihael.Vrbanec@stud.uni-karlsruhe.de
+ * http://nehe.gamedev.net/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+#include <GL/glx.h>
+
+#include <X11/keysym.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <sys/syscall.h>
+
+#include <framework/mlt.h>
+
+
+#define STARTWIDTH 1280
+#define STARTHEIGHT 720
+
+
+extern int XInitThreads();
+
+
+
+typedef struct consumer_xgl_s *consumer_xgl;
+
+struct consumer_xgl_s
+{
+       struct mlt_consumer_s parent;
+       mlt_properties properties;
+       mlt_deque queue;
+       pthread_t thread;
+       int joined;
+       int running;
+       int playing;
+       int xgl_started;
+};
+
+
+typedef struct
+{
+       pthread_t thread;
+       int running;
+} thread_video;
+
+
+typedef struct
+{
+       int width;
+       int height;
+       double aspect_ratio;
+       GLuint texture;
+       pthread_mutex_t mutex;
+       int new;
+       mlt_frame mlt_frame_ref;
+} frame_new;
+
+
+typedef struct
+{
+       int width;
+       int height;
+       GLuint fbo;
+       GLuint texture;
+} fbo;
+
+
+typedef struct
+{
+       Display *dpy;
+    int screen;
+    Window win;
+    GLXContext ctx;
+} HiddenContext;
+
+
+typedef struct
+{
+    Display *dpy;
+    int screen;
+    Window win;
+    GLXContext ctx;
+    XSetWindowAttributes attr;
+    int x, y;
+    unsigned int width, height;
+    unsigned int depth;
+} GLWindow;
+
+
+static GLWindow GLWin;
+static HiddenContext hiddenctx;
+
+static frame_new new_frame;
+static fbo fb;
+static thread_video vthread;
+static consumer_xgl xgl;
+static mlt_filter glsl_manager;
+
+
+
+static void* video_thread( void *arg );
+
+static void update()
+{
+       int _width = GLWin.width;
+       int _height = GLWin.height;
+       GLfloat left, right, top, bottom;
+       GLfloat war = (GLfloat)_width/(GLfloat)_height;
+
+       if ( war < new_frame.aspect_ratio ) {
+               left = -1.0;
+               right = 1.0;
+               top = war / new_frame.aspect_ratio;
+               bottom = -war / new_frame.aspect_ratio;
+       }
+       else {
+               top = 1.0;
+               bottom = -1.0;
+               left = -new_frame.aspect_ratio / war;
+               right = new_frame.aspect_ratio / war;
+       }
+
+       glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+       glLoadIdentity();
+
+       glPushMatrix();
+
+       glTranslatef( _width/2, _height/2, 0 );
+       glScalef( _width/2, _height/2, 1.0 );
+
+       glBindTexture( GL_TEXTURE_2D, fb.texture );
+
+       glBegin( GL_QUADS );
+               glTexCoord2f( 0.0f, 0.0f ); glVertex2f( left, top );
+               glTexCoord2f( 0.0f, 1.0f ); glVertex2f( left, bottom );
+               glTexCoord2f( 1.0f, 1.0f ); glVertex2f( right, bottom );
+               glTexCoord2f( 1.0f, 0.0f ); glVertex2f( right, top );
+       glEnd();
+
+       glPopMatrix();
+       
+       glXSwapBuffers( GLWin.dpy, GLWin.win );
+       
+       if ( !vthread.running ) {
+               pthread_create( &vthread.thread, NULL, video_thread, NULL );
+               vthread.running = 1;
+       }
+}
+
+
+
+static void show_frame()
+{
+//     fprintf(stderr,"show_frame threadID : %ld\n", syscall(SYS_gettid));
+       
+       if ( (fb.width != new_frame.width) || (fb.height != new_frame.height) ) {
+               glDeleteFramebuffers( 1, &fb.fbo );
+               glDeleteTextures( 1, &fb.texture );
+               fb.fbo = 0;
+               fb.width = new_frame.width;
+               fb.height = new_frame.height;
+               glGenFramebuffers( 1, &fb.fbo );
+               glGenTextures( 1, &fb.texture );
+               glBindTexture( GL_TEXTURE_2D, fb.texture );
+               glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, fb.width, fb.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
+               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo );
+               glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.texture, 0 );
+               glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+       }
+
+       glPushAttrib(GL_VIEWPORT_BIT);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+       
+       glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo );
+       
+       glViewport( 0, 0, new_frame.width, new_frame.height );
+       glMatrixMode( GL_PROJECTION );
+       glLoadIdentity();
+       glOrtho( 0.0, new_frame.width, 0.0, new_frame.height, -1.0, 1.0 );
+       glMatrixMode( GL_MODELVIEW );
+       glLoadIdentity();
+
+       glActiveTexture( GL_TEXTURE0 );
+    glBindTexture( GL_TEXTURE_2D, new_frame.texture );
+
+       glBegin( GL_QUADS );
+               glTexCoord2f( 0.0f, 0.0f ); glVertex2f( 0.0f, 0.0f );
+               glTexCoord2f( 0.0f, 1.0f ); glVertex2f( 0.0f, new_frame.height );
+               glTexCoord2f( 1.0f, 1.0f ); glVertex2f( new_frame.width, new_frame.height );
+               glTexCoord2f( 1.0f, 0.0f ); glVertex2f( new_frame.width, 0.0f );
+       glEnd();
+
+       glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+       mlt_events_fire( MLT_CONSUMER_PROPERTIES(&xgl->parent), "consumer-frame-show", new_frame.mlt_frame_ref, NULL );
+       mlt_frame_close( new_frame.mlt_frame_ref );
+       new_frame.mlt_frame_ref = NULL;
+
+       glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glMatrixMode(GL_MODELVIEW);
+    glPopAttrib();
+       
+       update();
+       
+       new_frame.new = 0;
+}
+
+
+
+void* video_thread( void *arg )
+{
+       mlt_frame next = NULL;
+       mlt_consumer consumer = &xgl->parent;
+       mlt_properties consumer_props = MLT_CONSUMER_PROPERTIES( consumer );
+       struct timeval start, end;
+       double duration = 0;
+       
+       gettimeofday( &start, NULL );
+       
+       while ( vthread.running )
+       {
+               // Get a frame from the attached producer
+               next = mlt_consumer_rt_frame( consumer );
+
+               if ( !mlt_properties_get_int( MLT_FILTER_PROPERTIES( glsl_manager ), "glsl_supported" ) ) {
+                       fprintf( stderr, "OpenGL Shading Language is not supported on this machine.\n" );
+                       xgl->running = 0;
+                       break;
+               }
+
+               // Ensure that we have a frame
+               if ( next )
+               {
+                       mlt_properties properties =  MLT_FRAME_PROPERTIES( next );
+                       if ( mlt_properties_get_int( properties, "rendered" ) == 1 )
+                       {
+                               // Get the image, width and height
+                               mlt_image_format vfmt = mlt_image_glsl_texture;
+                               int width = 0, height = 0;
+                               GLuint *image = 0;
+                               int error = mlt_frame_get_image( next, (uint8_t**) &image, &vfmt, &width, &height, 0 );
+                               if ( !error && image && width && height && !new_frame.new ) {
+                                       new_frame.width = width;
+                                       new_frame.height = height;
+                                       new_frame.texture = *image;
+                                       new_frame.mlt_frame_ref = next;
+                                       new_frame.aspect_ratio = ((double)width / (double)height) * mlt_properties_get_double( properties, "aspect_ratio" );
+                                       new_frame.new = 1;
+                                       
+                                       int loop = 200;
+                                       while ( new_frame.new && --loop )
+                                               usleep( 500 );
+                               }
+                               else
+                               {
+                                       mlt_frame_close( next );
+                               }
+                               new_frame.new = 0;
+                               
+                               gettimeofday( &end, NULL );
+                               duration = 1000000.0 / mlt_properties_get_double( consumer_props, "fps" );
+                               duration -= ( end.tv_sec * 1000000 + end.tv_usec ) - ( start.tv_sec * 1000000 + start.tv_usec );
+                               if ( duration > 0 )
+                                       usleep( (int)duration );
+                               gettimeofday( &start, NULL );
+                       }
+                       else
+                       {
+                               mlt_frame_close( next );
+                               static int dropped = 0;
+                               mlt_log_info( MLT_CONSUMER_SERVICE(consumer), "dropped video frame %d\n", ++dropped );
+                       }
+               }
+               else
+                       usleep( 1000 );
+       }
+       mlt_consumer_stopped( consumer );
+       
+       return NULL;
+}
+
+
+
+static void resizeGLScene()
+{
+       glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx );
+       
+       if ( GLWin.height == 0 )
+               GLWin.height = 1;
+       if ( GLWin.width == 0 )
+               GLWin.width = 1;
+       glViewport( 0, 0, GLWin.width, GLWin.height );
+       glMatrixMode( GL_PROJECTION );
+       glLoadIdentity();
+       glOrtho( 0.0, GLWin.width, 0.0, GLWin.height, -1.0, 1.0 );
+       glMatrixMode( GL_MODELVIEW );
+
+       update();
+}
+
+
+
+static void initGL( void )
+{
+       glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx );
+       
+       glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
+       glClearDepth( 1.0f );
+       glDepthFunc( GL_LEQUAL );
+       glEnable( GL_DEPTH_TEST );
+       glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+       glEnable( GL_BLEND );
+       glShadeModel( GL_SMOOTH );
+       glEnable( GL_TEXTURE_2D );
+       glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+
+       typedef int (*GLXSWAPINTERVALSGI) ( int );
+       GLXSWAPINTERVALSGI mglXSwapInterval = (GLXSWAPINTERVALSGI)glXGetProcAddressARB( (const GLubyte*)"glXSwapIntervalSGI" );
+       if ( mglXSwapInterval )
+               mglXSwapInterval( 1 );
+
+       fb.fbo = 0;
+       fb.width = STARTWIDTH;
+       fb.height = STARTHEIGHT;
+       glGenFramebuffers( 1, &fb.fbo );
+       glGenTextures( 1, &fb.texture );
+       glBindTexture( GL_TEXTURE_2D, fb.texture );
+       glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, fb.width, fb.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+       glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+       glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo );
+       glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.texture, 0 );
+       glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+       
+       resizeGLScene();
+}
+
+
+
+static void createGLWindow()
+{
+       const char* title = "OpenGL consumer";
+       int width = STARTWIDTH;
+       int height = STARTHEIGHT;
+       
+       int attrListSgl[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8,
+               GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 16, None };
+
+       int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8,
+               GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 16, None };
+
+       XVisualInfo *vi;
+       Colormap cmap;
+       Atom wmDelete;
+       Window winDummy;
+       unsigned int borderDummy;
+
+       GLWin.dpy = XOpenDisplay( 0 );
+       GLWin.screen = DefaultScreen( GLWin.dpy );
+
+       vi = glXChooseVisual( GLWin.dpy, GLWin.screen, attrListDbl );
+       if ( !vi )
+               vi = glXChooseVisual( GLWin.dpy, GLWin.screen, attrListSgl );
+
+       GLWin.ctx = glXCreateContext( GLWin.dpy, vi, 0, GL_TRUE );
+
+       cmap = XCreateColormap( GLWin.dpy, RootWindow( GLWin.dpy, vi->screen ), vi->visual, AllocNone );
+       GLWin.attr.colormap = cmap;
+       GLWin.attr.border_pixel = 0;
+
+       GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask;
+       GLWin.win = XCreateWindow( GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), 0, 0, width, height,
+               0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr );
+       wmDelete = XInternAtom( GLWin.dpy, "WM_DELETE_WINDOW", True );
+       XSetWMProtocols( GLWin.dpy, GLWin.win, &wmDelete, 1 );
+       XSetStandardProperties( GLWin.dpy, GLWin.win, title, title, None, NULL, 0, NULL );
+       XMapRaised( GLWin.dpy, GLWin.win );
+
+       glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx );
+       XGetGeometry( GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
+               &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth );
+
+       fprintf(stderr, "Direct Rendering: %s\n",glXIsDirect( GLWin.dpy, GLWin.ctx ) ? "true" : "false" );
+       
+       // Verify GLSL works on this machine
+       hiddenctx.ctx = glXCreateContext( GLWin.dpy, vi, GLWin.ctx, GL_TRUE );
+       if ( hiddenctx.ctx ) {
+               hiddenctx.dpy = GLWin.dpy;
+               hiddenctx.screen = GLWin.screen;
+               hiddenctx.win = RootWindow( hiddenctx.dpy, hiddenctx.screen );
+       }
+
+       initGL();
+}
+
+
+
+static void killGLWindow()
+{              
+       if ( GLWin.ctx ) {
+               if ( !glXMakeCurrent( GLWin.dpy, None, NULL ) ) {
+                       printf("Error releasing drawing context : killGLWindow\n");
+               }
+               glXDestroyContext( GLWin.dpy, GLWin.ctx );
+               GLWin.ctx = NULL;
+       }
+       
+       if ( hiddenctx.ctx )
+               glXDestroyContext( hiddenctx.dpy, hiddenctx.ctx );
+
+       XCloseDisplay( GLWin.dpy );
+}
+
+
+
+static void run()
+{
+       XEvent event;
+
+       while ( xgl->running ) {
+               while ( XPending( GLWin.dpy ) > 0 ) {
+                       XNextEvent( GLWin.dpy, &event );
+                       switch ( event.type ) {
+                               case Expose:
+                                       if ( event.xexpose.count != 0 )
+                                               break;
+                                       break;
+                               case ConfigureNotify:
+                                       if ( (event.xconfigure.width != GLWin.width) || (event.xconfigure.height != GLWin.height) ) {
+                                               GLWin.width = event.xconfigure.width;
+                                               GLWin.height = event.xconfigure.height;
+                                               resizeGLScene();
+                                       }
+                                       break;
+                               case KeyPress:
+                                       switch ( XLookupKeysym( &event.xkey, 0 ) ) {
+                                               case XK_Escape:                                                                 
+                                                       xgl->running = 0;
+                                                       break;
+                                               default: {
+                                                       mlt_producer producer = mlt_properties_get_data( xgl->properties, "transport_producer", NULL );
+                                                       char keyboard[ 2 ] = " ";
+                                                       void (*callback)( mlt_producer, char * ) = mlt_properties_get_data( xgl->properties, "transport_callback", NULL );
+                                                       if ( callback != NULL && producer != NULL )
+                                                       {
+                                                               keyboard[ 0 ] = ( char )XLookupKeysym( &event.xkey, 0 );
+                                                               callback( producer, keyboard );
+                                                       }
+                                                       break;
+                                               }
+                                       }
+                                       break;
+                               case ClientMessage:
+                                       if ( *XGetAtomName( GLWin.dpy, event.xclient.message_type ) == *"WM_PROTOCOLS" )
+                                               xgl->running = 0;
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               
+               if ( new_frame.new )
+                       show_frame();
+               else
+                       usleep( 1000 );
+       }
+}
+
+
+
+void start_xgl( consumer_xgl consumer )
+{
+       xgl = consumer;
+       
+       pthread_mutex_init( &new_frame.mutex, NULL );
+       new_frame.aspect_ratio = 16.0 / 9.0;
+       new_frame.new = 0;
+       new_frame.width = STARTWIDTH;
+       new_frame.height = STARTHEIGHT;
+       new_frame.mlt_frame_ref = NULL;
+       
+       vthread.running = 0;
+       
+       createGLWindow();
+       run();
+       if ( vthread.running ) {
+               vthread.running = 0;
+               pthread_join( vthread.thread, NULL );
+       }
+       killGLWindow();
+       xgl->running = 0;
+}
+
+static void on_consumer_thread_started( mlt_properties owner, HiddenContext* context )
+{
+       fprintf(stderr, "%s: %ld\n", __FUNCTION__, syscall(SYS_gettid));
+       // Initialize this thread's OpenGL state
+       glXMakeCurrent( context->dpy, context->win, context->ctx );
+       mlt_events_fire( MLT_FILTER_PROPERTIES(glsl_manager), "init glsl", NULL );
+}
+
+/** Forward references to static functions.
+*/
+
+static int consumer_start( mlt_consumer parent );
+static int consumer_stop( mlt_consumer parent );
+static int consumer_is_stopped( mlt_consumer parent );
+static void consumer_close( mlt_consumer parent );
+static void *consumer_thread( void * );
+
+
+
+/** This is what will be called by the factory - anything can be passed in
+       via the argument, but keep it simple.
+*/
+
+mlt_consumer consumer_xgl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       fprintf(stderr, "consumer_xgl_init\n");
+       // Create the consumer object
+       consumer_xgl this = calloc( sizeof( struct consumer_xgl_s ), 1 );
+
+       // If no malloc'd and consumer init ok
+       if ( this != NULL && mlt_consumer_init( &this->parent, this, profile ) == 0 )
+       {
+               // Create the queue
+               this->queue = mlt_deque_init( );
+
+               // Get the parent consumer object
+               mlt_consumer parent = &this->parent;
+
+               // We have stuff to clean up, so override the close method
+               parent->close = consumer_close;
+
+               // get a handle on properties
+               mlt_service service = MLT_CONSUMER_SERVICE( parent );
+               this->properties = MLT_SERVICE_PROPERTIES( service );
+
+               // Default scaler
+               mlt_properties_set( this->properties, "rescale", "bilinear" );
+               mlt_properties_set( this->properties, "deinterlace_method", "onefield" );
+
+               // default image format
+               mlt_properties_set( this->properties, "mlt_image_format", "glsl" );
+
+               // Default buffer for low latency
+               mlt_properties_set_int( this->properties, "buffer", 1 );
+
+               // Ensure we don't join on a non-running object
+               this->joined = 1;
+               this->xgl_started = 0;
+
+               // Allow thread to be started/stopped
+               parent->start = consumer_start;
+               parent->stop = consumer_stop;
+               parent->is_stopped = consumer_is_stopped;
+
+               // "init glsl" is required to instantiate glsl filters.
+               glsl_manager = mlt_factory_filter( profile, "glsl.manager", NULL );
+               if ( glsl_manager ) {
+                       mlt_events_listen( this->properties, &hiddenctx, "consumer-thread-started", (mlt_listener) on_consumer_thread_started );
+               } else {
+                       mlt_consumer_close( parent );
+                       parent = NULL;
+               }
+
+               // Return the consumer produced
+               return parent;
+       }
+
+       // malloc or consumer init failed
+       free( this );
+
+       // Indicate failure
+       return NULL;
+}
+
+
+
+int consumer_start( mlt_consumer parent )
+{
+       consumer_xgl this = parent->child;
+
+       if ( !this->running )
+       {
+               consumer_stop( parent );
+
+               this->running = 1;
+               this->joined = 0;
+
+               pthread_create( &this->thread, NULL, consumer_thread, this );
+       }
+
+       return 0;
+}
+
+
+
+int consumer_stop( mlt_consumer parent )
+{
+       // Get the actual object
+       consumer_xgl this = parent->child;
+       
+       if ( this->running && this->joined == 0 )
+       {
+               // Kill the thread and clean up
+               this->joined = 1;
+               this->running = 0;
+
+               if ( this->thread )
+                       pthread_join( this->thread, NULL );
+       }
+
+       return 0;
+}
+
+
+
+int consumer_is_stopped( mlt_consumer parent )
+{
+       consumer_xgl this = parent->child;
+       return !this->running;
+}
+
+
+
+static void *consumer_thread( void *arg )
+{
+       // Identify the arg
+       consumer_xgl this = arg;
+
+       XInitThreads();
+       start_xgl( this );
+
+       return NULL;
+}
+
+
+
+/** Callback to allow override of the close method.
+*/
+
+static void consumer_close( mlt_consumer parent )
+{
+       // Get the actual object
+       consumer_xgl this = parent->child;
+
+       // Stop the consumer
+       ///mlt_consumer_stop( parent );
+       mlt_filter_close( glsl_manager );
+
+       // Now clean up the rest
+       mlt_consumer_close( parent );
+
+       // Close the queue
+       mlt_deque_close( this->queue );
+
+       // Finally clean up this
+       free( this );
+}
diff --git a/src/modules/opengl/factory.c b/src/modules/opengl/factory.c
new file mode 100644 (file)
index 0000000..b67273c
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ * factory.c -- the factory method interfaces
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <limits.h>
+#include <framework/mlt.h>
+
+
+
+extern mlt_consumer consumer_xgl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_glsl_manager_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_blur_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_convert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_crop_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_deconvolution_sharpen_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_diffusion_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_glow_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_lift_gamma_gain_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_mirror_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_opacity_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_rect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_resample_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_resize_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_saturation_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_movit_vignette_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_white_balance_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_transition transition_movit_mix_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_transition transition_movit_overlay_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+
+static mlt_properties metadata( mlt_service_type type, const char *id, void *data )
+{
+       char file[ PATH_MAX ];
+       snprintf( file, PATH_MAX, "%s/opengl/%s", mlt_environment( "MLT_DATA" ), (char*) data );
+       return mlt_properties_parse_yaml( file );
+}
+
+MLT_REPOSITORY
+{
+#if !defined(__DARWIN__) && !defined(WIN32)
+       MLT_REGISTER( consumer_type, "xgl", consumer_xgl_init );
+#endif
+       MLT_REGISTER( filter_type, "glsl.manager", filter_glsl_manager_init );
+       MLT_REGISTER( filter_type, "movit.blur", filter_movit_blur_init );
+       MLT_REGISTER( filter_type, "movit.convert", filter_movit_convert_init );
+       MLT_REGISTER( filter_type, "movit.crop", filter_movit_crop_init );
+       MLT_REGISTER( filter_type, "movit.diffusion", filter_movit_diffusion_init );
+       MLT_REGISTER( filter_type, "movit.glow", filter_movit_glow_init );
+       MLT_REGISTER( filter_type, "movit.lift_gamma_gain", filter_lift_gamma_gain_init );
+       MLT_REGISTER( filter_type, "movit.mirror", filter_movit_mirror_init );
+       MLT_REGISTER( filter_type, "movit.opacity", filter_movit_opacity_init );
+       MLT_REGISTER( filter_type, "movit.rect", filter_movit_rect_init );
+       MLT_REGISTER( filter_type, "movit.resample", filter_movit_resample_init );
+       MLT_REGISTER( filter_type, "movit.resize", filter_movit_resize_init );
+       MLT_REGISTER( filter_type, "movit.saturation", filter_movit_saturation_init );
+       MLT_REGISTER( filter_type, "movit.sharpen", filter_deconvolution_sharpen_init );
+       MLT_REGISTER( filter_type, "movit.vignette", filter_movit_vignette_init );
+       MLT_REGISTER( filter_type, "movit.white_balance", filter_white_balance_init );
+       MLT_REGISTER( transition_type, "movit.mix", transition_movit_mix_init );
+       MLT_REGISTER( transition_type, "movit.overlay", transition_movit_overlay_init );
+
+       MLT_REGISTER_METADATA( filter_type, "movit.blur", metadata, "filter_movit_blur.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.diffusion", metadata, "filter_movit_diffusion.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.glow", metadata, "filter_movit_glow.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.lift_gamma_gain", metadata, "filter_lift_gamma_gain.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.mirror", metadata, "filter_movit_mirror.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.opacity", metadata, "filter_movit_opacity.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.rect", metadata, "filter_movit_rect.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.saturation", metadata, "filter_movit_saturation.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.sharpen", metadata, "filter_deconvolution_sharpen.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.vignette", metadata, "filter_movit_vignette.yml" );
+       MLT_REGISTER_METADATA( filter_type, "movit.white_balance", metadata, "filter_white_balance.yml" );
+       MLT_REGISTER_METADATA( transition_type, "movit.mix", metadata, "transition_movit_mix.yml" );
+       MLT_REGISTER_METADATA( transition_type, "movit.overlay", metadata, "transition_movit_overlay.yml" );
+}
diff --git a/src/modules/opengl/fbo_input.cpp b/src/modules/opengl/fbo_input.cpp
new file mode 100644 (file)
index 0000000..fafe333
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * fbo_input.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "fbo_input.h"
+#include <movit/util.h>
+
+// comes from unexported effect_util.h
+extern void set_uniform_int(GLuint glsl_program_num, const std::string &prefix, const std::string &key, int value);
+
+FBOInput::FBOInput(unsigned width, unsigned height)
+       : texture_num(0)
+       , needs_mipmaps(false)
+       , width(width)
+       , height(height)
+{
+       register_int("needs_mipmaps", &needs_mipmaps);
+}
+
+void FBOInput::set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num)
+{
+       glActiveTexture(GL_TEXTURE0 + *sampler_num);
+       check_error();
+       glBindTexture(GL_TEXTURE_2D, texture_num);
+       check_error();
+
+       // Bind it to a sampler.
+       set_uniform_int(glsl_program_num, prefix, "tex", *sampler_num);
+       ++*sampler_num;
+}
+
+std::string FBOInput::output_fragment_shader()
+{
+       return read_file("flat_input.frag");
+//     return "uniform sampler2D PREFIX(tex); vec4 FUNCNAME(vec2 tc) { return texture2D(PREFIX(tex), tc); }\n";
+}
diff --git a/src/modules/opengl/fbo_input.h b/src/modules/opengl/fbo_input.h
new file mode 100644 (file)
index 0000000..0000e03
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * fbo_input.h
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FBO_INPUT_H
+#define FBO_INPUT_H
+
+#include <movit/input.h>
+
+class FBOInput : public Input
+{
+public:
+       FBOInput(unsigned width, unsigned height);
+
+       virtual std::string effect_type_id() const { return "FBOInput"; }
+       void finalize() {}
+       bool can_output_linear_gamma() const { return false; }
+       AlphaHandling alpha_handling() const { return OUTPUT_POSTMULTIPLIED_ALPHA; }
+       std::string output_fragment_shader();
+       void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num);
+       unsigned get_width() const { return width; }
+       unsigned get_height() const { return height; }
+       Colorspace get_color_space() const { return COLORSPACE_sRGB; }
+       GammaCurve get_gamma_curve() const { return GAMMA_sRGB; }
+       void set_texture(GLuint texture) {
+               texture_num = texture;
+       }
+
+private:
+       GLuint texture_num;
+       int needs_mipmaps;
+       unsigned width, height;
+};
+
+#endif // FBO_INPUT_H
diff --git a/src/modules/opengl/filter_deconvolution_sharpen.cpp b/src/modules/opengl/filter_deconvolution_sharpen.cpp
new file mode 100644 (file)
index 0000000..546c489
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * filter_deconvolution_sharpen.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/deconvolution_sharpen_effect.h>
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect )
+                       GlslManager::add_effect( filter, frame, new DeconvolutionSharpenEffect() );
+               if ( effect ) {
+                       mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
+                       bool ok = effect->set_int( "matrix_size", mlt_properties_get_int( filter_props, "matrix_size" ) );
+                       ok |= effect->set_float( "circle_radius", mlt_properties_get_double( filter_props, "circle_radius" ) );
+                       ok |= effect->set_float( "gaussian_radius", mlt_properties_get_double( filter_props, "gaussian_radius" ) );
+                       ok |= effect->set_float( "correlation", mlt_properties_get_double( filter_props, "correlation" ) );
+                       ok |= effect->set_float( "noise", mlt_properties_get_double( filter_props, "noise" ) );
+                       assert(ok);
+               }
+       }
+       return frame;
+}
+
+extern "C" {
+
+mlt_filter filter_deconvolution_sharpen_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+               mlt_properties_set_int( properties, "matrix_size", 5 );
+               mlt_properties_set_double( properties, "circle_radius", 2.0 );
+               mlt_properties_set_double( properties, "gaussian_radius", 0.0 );
+               mlt_properties_set_double( properties, "correlation", 0.95 );
+               mlt_properties_set_double( properties, "noise", 0.01 );
+               filter->process = process;
+       }
+       return filter;
+}
+
+}
diff --git a/src/modules/opengl/filter_deconvolution_sharpen.yml b/src/modules/opengl/filter_deconvolution_sharpen.yml
new file mode 100644 (file)
index 0000000..df0e3d9
--- /dev/null
@@ -0,0 +1,53 @@
+schema_version: 0.1
+type: filter
+identifier: movit.sharpen
+title: Deconvolution Sharpen (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: >
+  Deconvolution Sharpen is a filter that sharpens by way of deconvolution
+  (i.e., trying to reverse the blur kernel, as opposed to just boosting high
+  frequencies), more specifically by FIR Wiener filters. It is the same
+  algorithm as used by the (now largely abandoned) Refocus plug-in for GIMP,
+  and I suspect the same as in Photoshop's “Smart Sharpen” filter.
+  The effect gives generally better results than unsharp masking, but can be very
+  GPU intensive, and requires a fair bit of tweaking to get good results without
+  ringing and/or excessive noise. It should be mentioned that for the larger
+
+parameters:
+  - identifier: matrix_size
+    title: Matrix Size
+    type: integer
+    minimum: 0
+    maximum: 10
+    default: 5
+
+  - identifier: circle_radius
+    title: Circle Radius
+    type: float
+    minimum: 0
+    default: 2
+
+  - identifier: gaussian_radius
+    title: Gaussian Radius
+    type: float
+    minimum: 0
+    default: 0
+
+  - identifier: correlation
+    title: Correlation
+    type: float
+    minimum: 0
+    default: 0.95
+
+  - identifier: noise
+    title: Noise Level
+    type: float
+    minimum: 0
+    default: 0.01
+
diff --git a/src/modules/opengl/filter_glsl_manager.cpp b/src/modules/opengl/filter_glsl_manager.cpp
new file mode 100644 (file)
index 0000000..e894710
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * filter_glsl_manager.cpp
+ * Copyright (C) 2011-2012 Christophe Thommeret <hftom@free.fr>
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string>
+#include "glsl_manager.h"
+#include <movit/init.h>
+#include <movit/effect_chain.h>
+#include "mlt_movit_input.h"
+#include "mlt_flip_effect.h"
+
+extern "C" {
+#include <framework/mlt_factory.h>
+}
+
+#ifdef WIN32
+#define SYS_gettid (224)
+#define syscall(X) (((X == SYS_gettid) && GetCurrentThreadId()) || 0)
+#else
+#include <unistd.h>
+#include <sys/syscall.h>
+#endif
+
+void deleteManager(GlslManager *p)
+{
+       delete p;
+}
+
+GlslManager::GlslManager()
+       : Mlt::Filter( mlt_filter_new() )
+       , pbo(0)
+{
+       mlt_filter filter = get_filter();
+       if ( filter ) {
+               // Set the mlt_filter child in case we choose to override virtual functions.
+               filter->child = this;
+               mlt_properties_set_data(mlt_global_properties(), "glslManager", this, 0,
+                       (mlt_destructor) deleteManager, NULL);
+
+               mlt_events_register( get_properties(), "init glsl", NULL );
+               listen("init glsl", this, (mlt_listener) GlslManager::onInit);
+       }
+}
+
+GlslManager::~GlslManager()
+{
+       mlt_log_debug(get_service(), "%s\n", __FUNCTION__);
+       while (fbo_list.peek_back())
+               delete (glsl_fbo) fbo_list.pop_back();
+       while (texture_list.peek_back())
+               delete (glsl_texture) texture_list.pop_back();
+       delete pbo;
+}
+
+GlslManager* GlslManager::get_instance()
+{
+       return (GlslManager*) mlt_properties_get_data(mlt_global_properties(), "glslManager", 0);
+}
+
+glsl_fbo GlslManager::get_fbo(int width, int height)
+{
+       for (int i = 0; i < fbo_list.count(); ++i) {
+               glsl_fbo fbo = (glsl_fbo) fbo_list.peek(i);
+               if (!fbo->used && (fbo->width == width) && (fbo->height == height)) {
+                       fbo->used = 1;
+                       return fbo;
+               }
+       }
+       GLuint fb = 0;
+       glGenFramebuffers(1, &fb);
+       if (!fb)
+               return NULL;
+
+       glsl_fbo fbo = new glsl_fbo_s;
+       if (!fbo) {
+               glDeleteFramebuffers(1, &fb);
+               return NULL;
+       }
+       fbo->fbo = fb;
+       fbo->width = width;
+       fbo->height = height;
+       fbo->used = 1;
+       fbo_list.push_back(fbo);
+       return fbo;
+}
+
+void GlslManager::release_fbo(glsl_fbo fbo)
+{
+       fbo->used = 0;
+}
+
+glsl_texture GlslManager::get_texture(int width, int height, GLint internal_format)
+{
+       for (int i = 0; i < texture_list.count(); ++i) {
+               glsl_texture tex = (glsl_texture) texture_list.peek(i);
+               if (!tex->used && (tex->width == width) && (tex->height == height) && (tex->internal_format == internal_format)) {
+                       glBindTexture(GL_TEXTURE_2D, tex->texture);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+                       glBindTexture( GL_TEXTURE_2D, 0);
+                       tex->used = 1;
+                       return tex;
+               }
+       }
+       GLuint tex = 0;
+       glGenTextures(1, &tex);
+       if (!tex)
+               return NULL;
+
+       glsl_texture gtex = new glsl_texture_s;
+       if (!gtex) {
+               glDeleteTextures(1, &tex);
+               return NULL;
+       }
+       glBindTexture( GL_TEXTURE_2D, tex );
+       glTexImage2D( GL_TEXTURE_2D, 0, internal_format, width, height, 0, internal_format, GL_UNSIGNED_BYTE, NULL );
+    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+    glBindTexture( GL_TEXTURE_2D, 0 );
+
+       gtex->texture = tex;
+       gtex->width = width;
+       gtex->height = height;
+       gtex->internal_format = internal_format;
+       gtex->used = 1;
+       texture_list.push_back(gtex);
+       return gtex;
+}
+
+void GlslManager::release_texture(glsl_texture texture)
+{
+       texture->used = 0;
+}
+
+glsl_pbo GlslManager::get_pbo(int size)
+{
+       if (!pbo) {
+               GLuint pb = 0;
+               glGenBuffers(1, &pb);
+               if (!pb)
+                       return NULL;
+
+               pbo = new glsl_pbo_s;
+               if (!pbo) {
+                       glDeleteBuffers(1, &pb);
+                       return NULL;
+               }
+               pbo->pbo = pb;
+       }
+       if (size > pbo->size) {
+               glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo->pbo);
+               glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size, NULL, GL_STREAM_DRAW);
+               glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+               pbo->size = size;
+       }
+       return pbo;
+}
+
+void GlslManager::onInit( mlt_properties owner, GlslManager* filter )
+{
+       mlt_log_verbose( filter->get_service(), "%s: %d\n", __FUNCTION__, syscall(SYS_gettid) );
+#ifdef WIN32
+       std::string path = std::string(mlt_environment("MLT_APPDIR")).append("\\share\\movit");
+#elif defined(__DARWIN__) && defined(RELOCATABLE)
+       std::string path = std::string(mlt_environment("MLT_APPDIR")).append("/share/movit");
+#else
+       std::string path = std::string(getenv("MLT_MOVIT_PATH") ? getenv("MLT_MOVIT_PATH") : SHADERDIR);
+#endif
+       ::init_movit( path, mlt_log_get_level() == MLT_LOG_DEBUG? MOVIT_DEBUG_ON : MOVIT_DEBUG_OFF );
+       filter->set( "glsl_supported", movit_initialized );
+}
+
+extern "C" {
+
+mlt_filter filter_glsl_manager_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       GlslManager* g = GlslManager::get_instance();
+       if (g)
+               g->inc_ref();
+       else
+               g = new GlslManager();
+       return g->get_filter();
+}
+
+} // extern "C"
+
+static void deleteChain( EffectChain* chain )
+{
+       delete chain;
+}
+
+bool GlslManager::init_chain( mlt_service service )
+{
+       bool error = true;
+       mlt_properties properties = MLT_SERVICE_PROPERTIES( service );
+       EffectChain* chain = (EffectChain*) mlt_properties_get_data( properties, "movit chain", NULL );
+       if ( !chain ) {
+               mlt_profile profile = mlt_service_profile( service );
+               Input* input = new MltInput( profile->width, profile->height );
+               chain = new EffectChain( profile->display_aspect_num, profile->display_aspect_den );
+               chain->add_input( input );
+               mlt_properties_set_data( properties, "movit chain", chain, 0, (mlt_destructor) deleteChain, NULL );
+               mlt_properties_set_data( properties, "movit input", input, 0, NULL, NULL );
+               mlt_properties_set_int( properties, "_movit finalized", 0 );
+               error = false;
+       }
+       return error;
+}
+
+EffectChain* GlslManager::get_chain( mlt_service service )
+{
+       return (EffectChain*) mlt_properties_get_data( MLT_SERVICE_PROPERTIES(service), "movit chain", NULL );
+}
+
+MltInput *GlslManager::get_input( mlt_service service )
+{
+       return (MltInput*) mlt_properties_get_data( MLT_SERVICE_PROPERTIES(service), "movit input", NULL );
+}
+
+void GlslManager::reset_finalized( mlt_service service )
+{
+       mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_movit finalized", 0 );
+}
+
+Effect* GlslManager::get_effect( mlt_filter filter, mlt_frame frame )
+{
+       mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) );
+       mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
+       char *unique_id = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "_unique_id" );
+       return (Effect*) mlt_properties_get_data( properties, unique_id, NULL );
+}
+
+Effect* GlslManager::add_effect( mlt_filter filter, mlt_frame frame, Effect* effect )
+{
+       mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) );
+       mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
+       char *unique_id = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "_unique_id" );
+       EffectChain* chain = (EffectChain*) mlt_properties_get_data( properties, "movit chain", NULL );
+       chain->add_effect( effect );
+       mlt_properties_set_data( properties, unique_id, effect, 0, NULL, NULL );
+       return effect;
+}
+
+Effect* GlslManager::add_effect( mlt_filter filter, mlt_frame frame, Effect* effect, Effect* input_b )
+{
+       mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) );
+       mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
+       char *unique_id = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "_unique_id" );
+       EffectChain* chain = (EffectChain*) mlt_properties_get_data( properties, "movit chain", NULL );
+       chain->add_effect( effect, chain->last_added_effect(),
+               input_b? input_b : chain->last_added_effect() );
+       mlt_properties_set_data( properties, unique_id, effect, 0, NULL, NULL );
+       return effect;
+}
+
+void GlslManager::render( mlt_service service, void* chain, GLuint fbo, int width, int height )
+{
+       EffectChain* effect_chain = (EffectChain*) chain;
+       mlt_properties properties = MLT_SERVICE_PROPERTIES( service );
+       if ( !mlt_properties_get_int( properties, "_movit finalized" ) ) {
+               mlt_properties_set_int( properties, "_movit finalized", 1 );
+               effect_chain->add_effect( new Mlt::VerticalFlip() );
+               effect_chain->finalize();
+       }
+       effect_chain->render_to_fbo( fbo, width, height );
+}
diff --git a/src/modules/opengl/filter_lift_gamma_gain.cpp b/src/modules/opengl/filter_lift_gamma_gain.cpp
new file mode 100644 (file)
index 0000000..8129063
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * filter_lift_gamma_gain.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/lift_gamma_gain_effect.h>
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect )
+                       effect = GlslManager::add_effect( filter, frame, new LiftGammaGainEffect );
+               if ( effect ) {
+                       mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
+                       RGBTriplet triplet(
+                               mlt_properties_get_double( filter_props, "lift_r" ),
+                               mlt_properties_get_double( filter_props, "lift_g" ),
+                               mlt_properties_get_double( filter_props, "lift_b" )
+                       );
+                       bool ok = effect->set_vec3( "lift", (float*) &triplet );
+                       triplet.r = mlt_properties_get_double( filter_props, "gamma_r" );
+                       triplet.g = mlt_properties_get_double( filter_props, "gamma_g" );
+                       triplet.b = mlt_properties_get_double( filter_props, "gamma_b" );
+                       ok |= effect->set_vec3( "gamma", (float*) &triplet );
+                       triplet.r = mlt_properties_get_double( filter_props, "gain_r" );
+                       triplet.g = mlt_properties_get_double( filter_props, "gain_g" );
+                       triplet.b = mlt_properties_get_double( filter_props, "gain_b" );
+                       ok |= effect->set_vec3( "gain", (float*) &triplet );
+                       assert(ok);
+               }
+       }
+       return frame;
+}
+
+extern "C" {
+
+mlt_filter filter_lift_gamma_gain_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+               mlt_properties_set_double( properties, "lift_r", 0.0 );
+               mlt_properties_set_double( properties, "lift_g", 0.0 );
+               mlt_properties_set_double( properties, "lift_b", 0.0 );
+               mlt_properties_set_double( properties, "gamma_r", 1.0 );
+               mlt_properties_set_double( properties, "gamma_g", 1.0 );
+               mlt_properties_set_double( properties, "gamma_b", 1.0 );
+               mlt_properties_set_double( properties, "gain_r", 1.0 );
+               mlt_properties_set_double( properties, "gain_g", 1.0 );
+               mlt_properties_set_double( properties, "gain_b", 1.0 );
+               filter->process = process;
+       }
+       return filter;
+}
+
+}
diff --git a/src/modules/opengl/filter_lift_gamma_gain.yml b/src/modules/opengl/filter_lift_gamma_gain.yml
new file mode 100644 (file)
index 0000000..09dfed2
--- /dev/null
@@ -0,0 +1,80 @@
+schema_version: 0.1
+type: filter
+identifier: movit.lift_gamma_gain
+title: Lift, Gamma, and Gain (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: >
+  A simple lift/gamma/gain effect, used for color grading.
+notes: >
+  Very roughly speaking, lift=shadows, gamma=midtones and gain=highlights,
+  although all parameters affect the entire curve. Mathematically speaking,
+  it is a bit unusual to look at gamma as a color, but it works pretty well
+  in practice.
+  The classic formula is: output = (gain * (x + lift * (1-x)))^(1/gamma).
+  The lift is actually a case where we actually would _not_ want linear light;
+  since black by definition becomes equal to the lift color, we want lift to
+  be pretty close to black, but in linear light that means lift affects the
+  rest of the curve relatively little. Thus, we actually convert to gamma 2.2
+  before lift, and then back again afterwards. (Gain and gamma are,
+  up to constants, commutative with the de-gamma operation.)
+
+parameters:
+  - identifier: lift_r
+    title: Lift Red
+    type: float
+    minimum: 0.0
+    default: 0.0
+
+  - identifier: lift_g
+    title: Lift Green
+    type: float
+    minimum: 0.0
+    default: 0.0
+
+  - identifier: lift_b
+    title: Lift Blue
+    type: float
+    minimum: 0.0
+    default: 0.0
+
+  - identifier: gamma_r
+    title: Gamma Red
+    type: float
+    minimum: 0.0
+    default: 1.0
+
+  - identifier: gamma_g
+    title: Gamma Green
+    type: float
+    minimum: 0.0
+    default: 1.0
+
+  - identifier: gamma_b
+    title: Gamma Blue
+    type: float
+    minimum: 0.0
+    default: 1.0
+
+  - identifier: gain_r
+    title: Gain Red
+    type: float
+    minimum: 0.0
+    default: 1.0
+
+  - identifier: gain_g
+    title: Gain Green
+    type: float
+    minimum: 0.0
+    default: 1.0
+
+  - identifier: gain_b
+    title: Gain Blue
+    type: float
+    minimum: 0.0
+    default: 1.0
diff --git a/src/modules/opengl/filter_movit_blur.cpp b/src/modules/opengl/filter_movit_blur.cpp
new file mode 100644 (file)
index 0000000..5c66e97
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * filter_movit_blur.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/blur_effect.h>
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect )
+                       effect = GlslManager::add_effect( filter, frame, new BlurEffect() );
+               if ( effect ) {
+                       mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
+                       bool ok = effect->set_float( "radius", mlt_properties_get_double( filter_props, "radius" ) );
+                       assert(ok);
+               }
+       }
+       return frame;
+}
+
+extern "C" {
+
+mlt_filter filter_movit_blur_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+               mlt_properties_set_double( properties, "radius", 3 );
+               filter->process = process;
+       }
+       return filter;
+}
+
+}
diff --git a/src/modules/opengl/filter_movit_blur.yml b/src/modules/opengl/filter_movit_blur.yml
new file mode 100644 (file)
index 0000000..3109af7
--- /dev/null
@@ -0,0 +1,22 @@
+schema_version: 0.1
+type: filter
+identifier: movit.blur
+title: Blur (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: >
+  A separable 2D blur implemented by a combination of mipmap filtering
+  and convolution (essentially giving a convolution with a piecewise linear
+  approximation to the true impulse response).
+
+parameters:
+  - identifier: radius
+    title: Radius
+    type: float
+    minimum: 0
+    default: 3
diff --git a/src/modules/opengl/filter_movit_convert.cpp b/src/modules/opengl/filter_movit_convert.cpp
new file mode 100644 (file)
index 0000000..12c75da
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * filter_movit_convert.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/effect_chain.h>
+#include <movit/util.h>
+#include "mlt_movit_input.h"
+
+
+static void yuv422_to_yuv422p( uint8_t *yuv422, uint8_t *yuv422p, int width, int height )
+{
+       uint8_t *Y = yuv422p;
+       uint8_t *U = Y + width * height;
+       uint8_t *V = U + width * height / 2;
+       int n = width * height / 2 + 1;
+       while ( --n ) {
+               *Y++ = *yuv422++;
+               *U++ = *yuv422++;
+               *Y++ = *yuv422++;
+               *V++ = *yuv422++;
+       }
+}
+
+static int convert_on_cpu( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format )
+{
+       int error = 0;
+       mlt_filter cpu_csc = (mlt_filter) mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "cpu_csc", NULL );
+       if ( cpu_csc ) {
+               int (* save_fp )( mlt_frame self, uint8_t **image, mlt_image_format *input, mlt_image_format output )
+                       = frame->convert_image;
+               frame->convert_image = NULL;
+               mlt_filter_process( cpu_csc, frame );
+               error = frame->convert_image( frame, image, format, output_format );
+               frame->convert_image = save_fp;
+       } else {
+               error = 1;
+       }
+       return error;
+}
+
+static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format )
+{
+       // Nothing to do!
+       if ( *format == output_format )
+               return 0;
+
+       mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
+
+       mlt_log_verbose( NULL, "filter_movit_convert: %s -> %s\n",
+               mlt_image_format_name( *format ), mlt_image_format_name( output_format ) );
+
+       // Use CPU if glsl not initialized or not supported.
+       GlslManager* glsl = GlslManager::get_instance();
+       if ( !glsl || !glsl->get_int("glsl_supported" ) )
+               return convert_on_cpu( frame, image, format, output_format );
+
+       // Do non-GL image conversions on a CPU-based image converter.
+       if ( *format != mlt_image_glsl && output_format != mlt_image_glsl && output_format != mlt_image_glsl_texture )
+               return convert_on_cpu( frame, image, format, output_format );
+
+       int error = 0;
+       int width = mlt_properties_get_int( properties, "width" );
+       int height = mlt_properties_get_int( properties, "height" );
+       int img_size = mlt_image_format_size( *format, width, height, NULL );
+       mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) );
+       mlt_service service = MLT_PRODUCER_SERVICE(producer);
+       EffectChain* chain = GlslManager::get_chain( service );
+       MltInput* input = GlslManager::get_input( service );
+
+       // Use a temporary chain to convert image in RAM to OpenGL texture.
+       if ( output_format == mlt_image_glsl_texture && *format != mlt_image_glsl ) {
+               input = new MltInput( width, height );
+               chain = new EffectChain( width, height );
+               chain->add_input( input );
+       }
+
+       if ( *format != mlt_image_glsl ) {
+               if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { 
+                       input->useFlatInput( chain, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, width, height );
+                       input->set_pixel_data( *image );
+               }
+               else if ( *format == mlt_image_rgb24 ) {
+                       input->useFlatInput( chain, FORMAT_RGB, width, height );
+                       input->set_pixel_data( *image );
+               }
+               else if ( *format == mlt_image_yuv420p ) {
+                       ImageFormat image_format;
+                       YCbCrFormat ycbcr_format;
+                       if ( 709 == mlt_properties_get_int( properties, "colorspace" ) ) {
+                               image_format.color_space = COLORSPACE_REC_709;
+                               image_format.gamma_curve = GAMMA_REC_709;
+                               ycbcr_format.luma_coefficients = YCBCR_REC_709;
+                       } else if ( 576 == mlt_properties_get_int( properties, "height" ) ) {
+                               image_format.color_space = COLORSPACE_REC_601_625;
+                               image_format.gamma_curve = GAMMA_REC_601;
+                               ycbcr_format.luma_coefficients = YCBCR_REC_601;
+                       } else {
+                               image_format.color_space = COLORSPACE_REC_601_525;
+                               image_format.gamma_curve = GAMMA_REC_601;
+                               ycbcr_format.luma_coefficients = YCBCR_REC_601;
+                       }
+                       ycbcr_format.full_range = mlt_properties_get_int( properties, "force_full_luma" );
+                       ycbcr_format.chroma_subsampling_x = ycbcr_format.chroma_subsampling_y = 2;
+                       // TODO: make new frame properties set by producers
+                       ycbcr_format.cb_x_position = ycbcr_format.cr_x_position = 0.0f;
+                       ycbcr_format.cb_y_position = ycbcr_format.cr_y_position = 0.5f;
+                       input->useYCbCrInput( chain, image_format, ycbcr_format, width, height );
+                       input->set_pixel_data( *image );
+               }
+               else if ( *format == mlt_image_yuv422 ) {
+                       ImageFormat image_format;
+                       YCbCrFormat ycbcr_format;
+                       if ( 709 == mlt_properties_get_int( properties, "colorspace" ) ) {
+                               image_format.color_space = COLORSPACE_REC_709;
+                               image_format.gamma_curve = GAMMA_REC_709;
+                               ycbcr_format.luma_coefficients = YCBCR_REC_709;
+                       } else if ( 576 == height ) {
+                               image_format.color_space = COLORSPACE_REC_601_625;
+                               image_format.gamma_curve = GAMMA_REC_601;
+                               ycbcr_format.luma_coefficients = YCBCR_REC_601;
+                       } else {
+                               image_format.color_space = COLORSPACE_REC_601_525;
+                               image_format.gamma_curve = GAMMA_REC_601;
+                               ycbcr_format.luma_coefficients = YCBCR_REC_601;
+                       }
+                       ycbcr_format.full_range = mlt_properties_get_int( properties, "force_full_luma" );
+                       ycbcr_format.chroma_subsampling_x = 2;
+                       ycbcr_format.chroma_subsampling_y = 1;
+                       // TODO: make new frame properties set by producers
+                       ycbcr_format.cb_x_position = ycbcr_format.cr_x_position = 0.0f;
+                       ycbcr_format.cb_y_position = ycbcr_format.cr_y_position = 0.5f;
+                       input->useYCbCrInput( chain, image_format, ycbcr_format, width, height );
+                       
+                       // convert chunky to planar
+                       uint8_t* planar = (uint8_t*) mlt_pool_alloc( img_size );
+                       yuv422_to_yuv422p( *image, planar, width, height );
+                       input->set_pixel_data( planar );
+                       mlt_frame_set_image( frame, planar, img_size, mlt_pool_release );
+               }
+       }
+
+       if ( output_format != mlt_image_glsl ) {
+               glsl_fbo fbo = glsl->get_fbo( width, height );
+
+               if ( output_format == mlt_image_glsl_texture ) {
+                       glsl_texture texture = glsl->get_texture( width, height, GL_RGBA );
+
+                       glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo );
+                       check_error();
+                       glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 );
+                       check_error();
+                       glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+                       check_error();
+
+                       // Using a temporary chain to convert image in RAM to OpenGL texture.
+                       if ( *format != mlt_image_glsl )
+                               GlslManager::reset_finalized( service );
+                       GlslManager::render( service, chain, fbo->fbo, width, height );
+
+                       glFinish();
+                       check_error();
+                       glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+                       check_error();
+                       // Using a temporary chain to convert image in RAM to OpenGL texture.
+                       if ( *format != mlt_image_glsl )
+                               delete chain;
+
+                       *image = (uint8_t*) &texture->texture;
+                       mlt_frame_set_image( frame, *image, 0, NULL );
+                       mlt_properties_set_data( properties, "movit.convert", texture, 0,
+                               (mlt_destructor) GlslManager::release_texture, NULL );
+                       mlt_properties_set_int( properties, "format", output_format );
+                       *format = output_format;
+               }
+               else {
+                       // Use a PBO to hold the data we read back with glReadPixels()
+                       // (Intel/DRI goes into a slow path if we don't read to PBO)
+                       GLenum gl_format = ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl )?
+                               GL_RGBA : GL_RGB;
+                       img_size = width * height * ( gl_format == GL_RGB? 3 : 4 );
+                       glsl_pbo pbo = glsl->get_pbo( img_size );
+                       glsl_texture texture = glsl->get_texture( width, height, gl_format );
+
+                       if ( fbo && pbo && texture ) {
+                               // Set the FBO
+                               glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo );
+                               check_error();
+                               glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 );
+                               check_error();
+                               glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+                               check_error();
+
+                               GlslManager::render( service, chain, fbo->fbo, width, height );
+       
+                               // Read FBO into PBO
+                               glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo );
+                               check_error();
+                               glBufferData( GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ );
+                               check_error();
+                               glReadPixels( 0, 0, width, height, gl_format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0) );
+                               check_error();
+       
+                               // Copy from PBO
+                               uint8_t* buf = (uint8_t*) glMapBuffer( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY );
+                               check_error();
+
+                               if ( output_format == mlt_image_yuv422 || output_format == mlt_image_yuv420p ) {
+                                       *image = buf;
+                                       *format = mlt_image_rgb24;
+                                       error = convert_on_cpu( frame, image, format, output_format );
+                               }
+                               else {
+                                       *image = (uint8_t*) mlt_pool_alloc( img_size );
+                                       mlt_frame_set_image( frame, *image, img_size, mlt_pool_release );
+                                       memcpy( *image, buf, img_size );
+                               }
+       
+                               // Release PBO and FBO
+                               glUnmapBuffer( GL_PIXEL_PACK_BUFFER_ARB );
+                               check_error();
+                               glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, 0 );
+                               check_error();
+                               glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+                               check_error();
+                               glBindTexture( GL_TEXTURE_2D, 0 );
+                               check_error();
+                               GlslManager::release_texture( texture );
+       
+                               mlt_properties_set_int( properties, "format", output_format );
+                               *format = output_format;
+                       }
+                       else {
+                               error = 1;
+                       }
+               }
+               if ( fbo ) GlslManager::release_fbo( fbo );
+       }
+       else {
+               mlt_properties_set_int( properties, "format", output_format );
+               *format = output_format;
+       }
+
+       return error;
+}
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       // Set a default colorspace on the frame if not yet set by the producer.
+       // The producer may still change it during get_image.
+       // This way we do not have to modify each producer to set a valid colorspace.
+       mlt_properties properties = MLT_FRAME_PROPERTIES(frame);
+       if ( mlt_properties_get_int( properties, "colorspace" ) <= 0 )
+               mlt_properties_set_int( properties, "colorspace", mlt_service_profile( MLT_FILTER_SERVICE(filter) )->colorspace );
+
+       frame->convert_image = convert_image;
+
+       mlt_filter cpu_csc = (mlt_filter) mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "cpu_csc", NULL );
+       mlt_properties_inc_ref( MLT_FILTER_PROPERTIES(cpu_csc) );
+       mlt_properties_set_data( properties, "cpu_csc", cpu_csc, 0,
+               (mlt_destructor) mlt_filter_close, NULL );
+
+       return frame;
+}
+
+static mlt_filter create_filter( mlt_profile profile, char *effect )
+{
+       mlt_filter filter = NULL;
+       char *id = strdup( effect );
+       char *arg = strchr( id, ':' );
+       if ( arg != NULL )
+               *arg ++ = '\0';
+
+       // The swscale and avcolor_space filters require resolution as arg to test compatibility
+       if ( !strcmp( effect, "avcolor_space" ) )
+               arg = (char*) profile->width;
+
+       filter = mlt_factory_filter( profile, id, arg );
+       if ( filter )
+               mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "_loader", 1 );
+       free( id );
+       return filter;
+}
+
+extern "C" {
+
+mlt_filter filter_movit_convert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) )
+       {
+               mlt_filter cpu_csc = create_filter( profile, "avcolor_space" );
+               if ( !cpu_csc )
+                       cpu_csc = create_filter( profile, "imageconvert" );
+               if ( cpu_csc )
+                       mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "cpu_csc", cpu_csc, 0,
+                               (mlt_destructor) mlt_filter_close, NULL );
+               filter->process = process;
+       }
+       return filter;
+}
+
+}
diff --git a/src/modules/opengl/filter_movit_crop.cpp b/src/modules/opengl/filter_movit_crop.cpp
new file mode 100644 (file)
index 0000000..1bacd1a
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * filter_movit_crop.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/padding_effect.h>
+
+static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+       int error = 0;
+       mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
+       mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame );
+       mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
+       mlt_image_format requested_format = *format;
+
+       // Correct width/height if necessary
+       *width = mlt_properties_get_int( properties, "crop.original_width" );
+       *height = mlt_properties_get_int( properties, "crop.original_height" );
+       if ( *width == 0 || *height == 0 )
+       {
+               *width = mlt_properties_get_int( properties, "meta.media.width" );
+               *height = mlt_properties_get_int( properties, "meta.media.height" );
+       }
+       if ( *width == 0 || *height == 0 )
+       {
+               *width = profile->width;
+               *height = profile->height;
+       }
+       mlt_properties_set_int( properties, "rescale_width", *width );
+       mlt_properties_set_int( properties, "rescale_height", *height );
+
+       // Get the image as requested
+//     *format = (mlt_image_format) mlt_properties_get_int( MLT_PRODUCER_PROPERTIES(producer), "_movit image_format" );
+       *format = mlt_image_none;
+       error = mlt_frame_get_image( frame, image, format, width, height, writable );
+
+       // Skip processing if requested.
+       if ( requested_format == mlt_image_none )
+               return error;
+
+       if ( !error && *format != mlt_image_glsl && frame->convert_image ) {
+       // Pin the requested format to the first one returned.
+//             mlt_properties_set_int( MLT_PRODUCER_PROPERTIES(producer), "_movit image_format", *format );
+               error = frame->convert_image( frame, image, format, mlt_image_glsl );
+       }
+       if ( !error ) {
+               double left    = mlt_properties_get_double( properties, "crop.left" );
+               double right   = mlt_properties_get_double( properties, "crop.right" );
+               double top     = mlt_properties_get_double( properties, "crop.top" );
+               double bottom  = mlt_properties_get_double( properties, "crop.bottom" );
+               int owidth  = *width - left - right;
+               int oheight = *height - top - bottom;
+               owidth = owidth < 0 ? 0 : owidth;
+               oheight = oheight < 0 ? 0 : oheight;
+
+               mlt_log_debug( MLT_FILTER_SERVICE(filter), "%dx%d -> %dx%d\n", *width, *height, owidth, oheight);
+
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( effect ) {
+                       bool ok = effect->set_int( "width", owidth );
+                       ok |= effect->set_int( "height", oheight );
+                       ok |= effect->set_float( "left", -left );
+                       ok |= effect->set_float( "top", -top );
+                       assert(ok);
+                       *width = owidth;
+                       *height = oheight;
+               }
+       }
+
+       return error;
+}
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) );
+       if ( !GlslManager::init_chain( MLT_PRODUCER_SERVICE(producer) ) ) {
+               Effect* effect = GlslManager::add_effect( filter, frame, new PaddingEffect );
+               RGBATuple border_color( 0.0f, 0.0f, 0.0f, 1.0f );
+               bool ok = effect->set_vec4( "border_color", (float*) &border_color );
+               assert(ok);
+       }
+       mlt_frame_push_service( frame, filter );
+       mlt_frame_push_get_image( frame, get_image );
+       return frame;
+}
+
+extern "C"
+mlt_filter filter_movit_crop_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               filter->process = process;
+       }
+       return filter;
+}
diff --git a/src/modules/opengl/filter_movit_diffusion.cpp b/src/modules/opengl/filter_movit_diffusion.cpp
new file mode 100644 (file)
index 0000000..31d705b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * filter_movit_diffusion.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/diffusion_effect.h>
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect )
+                       effect = GlslManager::add_effect( filter, frame, new DiffusionEffect() );
+               if ( effect ) {
+                       mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
+                       bool ok = effect->set_float( "radius", mlt_properties_get_double( filter_props, "radius" ) );
+                       ok |= effect->set_float( "blurred_mix_amount", mlt_properties_get_double( filter_props, "mix" ) );
+                       assert(ok);
+               }
+       }
+       return frame;
+}
+
+extern "C" {
+
+mlt_filter filter_movit_diffusion_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+               mlt_properties_set_double( properties, "radius", 3.0 );
+               mlt_properties_set_double( properties, "mix", 0.3 );
+               filter->process = process;
+       }
+       return filter;
+}
+
+}
diff --git a/src/modules/opengl/filter_movit_diffusion.yml b/src/modules/opengl/filter_movit_diffusion.yml
new file mode 100644 (file)
index 0000000..e97d123
--- /dev/null
@@ -0,0 +1,35 @@
+schema_version: 0.1
+type: filter
+identifier: movit.diffusion
+title: Diffusion (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: >
+  There are many different effects that go under the name of "diffusion",
+  seemingly all of the inspired by the effect you get when you put a
+  diffusion filter in front of your camera lens. The effect most people
+  want is a general flattening/smoothing of the light, and reduction of
+  fine detail (most notably, blemishes in people's skin), without ruining
+  edges, which a regular blur would do.
+  We do a relatively simple version, sometimes known as "white diffusion",
+  where we first blur the picture, and then overlay it on the original
+  using the original as a matte.
+
+parameters:
+  - identifier: radius
+    title: Blur Radius
+    type: float
+    minimum: 0.0
+    default: 3.0
+
+  - identifier: mix
+    title: Blurriness
+    type: float
+    minimum: 0.0
+    maximum: 1.0
+    default: 0.3
diff --git a/src/modules/opengl/filter_movit_glow.cpp b/src/modules/opengl/filter_movit_glow.cpp
new file mode 100644 (file)
index 0000000..4026477
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * filter_movit_glow.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/glow_effect.h>
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect )
+                       effect = GlslManager::add_effect( filter, frame, new GlowEffect() );
+               if ( effect ) {
+                       mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
+                       bool ok = effect->set_float( "radius", mlt_properties_get_double( filter_props, "radius" ) );
+                       ok |= effect->set_float( "blurred_mix_amount", mlt_properties_get_double( filter_props, "blur_mix" ) );
+                       ok |= effect->set_float( "highlight_cutoff", mlt_properties_get_double( filter_props, "highlight_cutoff" ) );
+                       assert(ok);
+               }
+       }
+       return frame;
+}
+
+extern "C" {
+
+mlt_filter filter_movit_glow_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+               mlt_properties_set_double( properties, "radius", 20.0 );
+               mlt_properties_set_double( properties, "blur_mix", 1.0 );
+               mlt_properties_set_double( properties, "highlight_cutoff", 0.2 );
+               filter->process = process;
+       }
+       return filter;
+}
+
+}
diff --git a/src/modules/opengl/filter_movit_glow.yml b/src/modules/opengl/filter_movit_glow.yml
new file mode 100644 (file)
index 0000000..258f683
--- /dev/null
@@ -0,0 +1,35 @@
+schema_version: 0.1
+type: filter
+identifier: movit.glow
+title: Glow (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: >
+  Cut out the highlights of the image (everything above a certain threshold),
+  blur them, and overlay them onto the original image.
+
+parameters:
+  - identifier: radius
+    title: Radius
+    type: float
+    minimum: 0.0
+    default: 20.0
+
+  - identifier: blur_mix
+    title: Highlight Blurriness
+    type: float
+    minimum: 0.0
+    maximum: 1.0
+    default: 1.0
+
+  - identifier: highlight_cutoff
+    title: Highlight Cutoff Threshold
+    type: float
+    minimum: 0.0
+    maximum: 1.0
+    default: 0.2
diff --git a/src/modules/opengl/filter_movit_mirror.cpp b/src/modules/opengl/filter_movit_mirror.cpp
new file mode 100644 (file)
index 0000000..8b6ab1f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * filter_movit_mirror.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/mirror_effect.h>
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect )
+                       GlslManager::add_effect( filter, frame, new MirrorEffect() );
+       }
+       return frame;
+}
+
+extern "C" {
+
+mlt_filter filter_movit_mirror_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               filter->process = process;
+       }
+       return filter;
+}
+
+}
+
diff --git a/src/modules/opengl/filter_movit_mirror.yml b/src/modules/opengl/filter_movit_mirror.yml
new file mode 100644 (file)
index 0000000..123b343
--- /dev/null
@@ -0,0 +1,12 @@
+schema_version: 0.1
+type: filter
+identifier: movit.mirror
+title: Mirror (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+description: A simple horizontal mirroring.
+tags:
+  - Video
diff --git a/src/modules/opengl/filter_movit_opacity.cpp b/src/modules/opengl/filter_movit_opacity.cpp
new file mode 100644 (file)
index 0000000..6a7333d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * filter_movit_opacity.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/mix_effect.h>
+
+static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+       mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame );
+       mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+       Effect* effect = GlslManager::get_effect( filter, frame );
+       bool ok = effect->set_float( "strength_first", mlt_properties_get_double( properties, "opacity" ) );
+       assert(ok);
+       *format = mlt_image_glsl;
+       return mlt_frame_get_image( frame, image, format, width, height, writable );
+}
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect ) {
+                       effect = GlslManager::add_effect( filter, frame, new MixEffect, 0 );
+                       assert(effect);
+                       bool ok = effect->set_float( "strength_first", 1.0f );
+                       ok |= effect->set_float( "strength_second", 0.0f );
+                       assert(ok);
+               }
+       }
+       mlt_frame_push_service( frame, filter );
+       mlt_frame_push_get_image( frame, get_image );
+       return frame;
+}
+
+extern "C"
+mlt_filter filter_movit_opacity_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+               mlt_properties_set( properties, "opacity", arg? arg : "1" );
+               filter->process = process;
+       }
+       return filter;
+}
diff --git a/src/modules/opengl/filter_movit_opacity.yml b/src/modules/opengl/filter_movit_opacity.yml
new file mode 100644 (file)
index 0000000..fa82b60
--- /dev/null
@@ -0,0 +1,25 @@
+schema_version: 0.1
+type: filter
+identifier: movit.opacity
+title: Opacity (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: Adjust the opacity of an image through the alpha channel.
+notes: >
+  When used in some transitions this will cause this video to be mixed with
+  the other video. If the video this is applied to already has an alpha channel,
+  then this preserves that by multiplying the opacity level with the alpha channel.
+  This filter is especially handy when used in conjunction with movit.overlay.
+
+parameters:
+  - identifier: opacity
+    title: Opacity
+    type: float
+    minimum: 0
+    maximum: 1
+    default: 1
diff --git a/src/modules/opengl/filter_movit_rect.cpp b/src/modules/opengl/filter_movit_rect.cpp
new file mode 100644 (file)
index 0000000..004f2f7
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * filter_movit_rect.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include "glsl_manager.h"
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       // Drive the resize and resample filters on the b_frame for these composite parameters
+       mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
+       mlt_properties frame_props = MLT_FRAME_PROPERTIES(frame);
+       mlt_properties_set( frame_props, "resize.geometry", mlt_properties_get( properties, "geometry" ) );
+       mlt_properties_set( frame_props, "resize.fill", mlt_properties_get( properties, "fill" ) );
+       mlt_properties_set( frame_props, "resize.halign", mlt_properties_get( properties, "halign" ) );
+       mlt_properties_set( frame_props, "resize.valign", mlt_properties_get( properties, "valign" ) );
+       return frame;
+}
+
+extern "C"
+mlt_filter filter_movit_rect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               mlt_properties_set( MLT_FILTER_PROPERTIES(filter), "geometry", arg );
+               mlt_properties_set_int( MLT_FILTER_PROPERTIES(filter), "fill", 1 );
+               filter->process = process;
+       }
+       return filter;
+}
diff --git a/src/modules/opengl/filter_movit_rect.yml b/src/modules/opengl/filter_movit_rect.yml
new file mode 100644 (file)
index 0000000..a077927
--- /dev/null
@@ -0,0 +1,60 @@
+schema_version: 0.1
+type: filter
+identifier: movit.rect
+title: Position and Size (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: >
+  Change the coordinates and scale to fit within a rectangle.
+
+parameters:
+  - identifier: geometry
+    title: Rectangle
+    type: geometry
+    description: > 
+      Keyframable rectangle specification.
+    mutable: yes
+
+  - identifier: fill
+    title: Upscale to Fill
+    description: >
+      Determines whether the image will be scaled up to fill the rectangle
+      or whether the size will be constrained to 100% of the profile
+      resolution.
+    type: integer
+    default: 1
+    minimum: 0
+    maximum: 1
+    mutable: yes
+    widget: checkbox
+
+  - identifier: halign
+    title: Horizontal alignment
+    description: >
+      Set the horizontal alignment within the geometry rectangle.
+    type: string
+    default: left
+    values:
+      - left
+      - center
+      - right
+    mutable: yes
+    widget: combo
+
+  - identifier: valign
+    title: Vertical alignment
+    description: >
+      Set the vertical alignment within the geometry rectangle.
+    type: string
+    default: top
+    values:
+      - top
+      - middle
+      - bottom
+    mutable: yes
+    widget: combo
diff --git a/src/modules/opengl/filter_movit_resample.cpp b/src/modules/opengl/filter_movit_resample.cpp
new file mode 100644 (file)
index 0000000..5ecdfbb
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * filter_movit_resample.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/resample_effect.h>
+
+static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+       int error = 0;
+       mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
+       mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame );
+       mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter );
+       mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
+
+       // Correct width/height if necessary
+       if ( *width == 0 || *height == 0 )
+       {
+               *width = profile->width;
+               *height = profile->height;
+       }
+
+       int iwidth = *width;
+       int iheight = *height;
+       double factor = mlt_properties_get_double( filter_properties, "factor" );
+       factor = factor > 0 ? factor : 1.0;
+       int owidth = *width * factor;
+       int oheight = *height * factor;
+
+       // If meta.media.width/height exist, we want that as minimum information
+       if ( mlt_properties_get_int( properties, "meta.media.width" ) )
+       {
+               iwidth = mlt_properties_get_int( properties, "meta.media.width" );
+               iheight = mlt_properties_get_int( properties, "meta.media.height" );
+       }
+
+       mlt_properties_set_int( properties, "rescale_width", *width );
+       mlt_properties_set_int( properties, "rescale_height", *height );
+
+       // Deinterlace if height is changing to prevent fields mixing on interpolation
+       if ( iheight != oheight )
+               mlt_properties_set_int( properties, "consumer_deinterlace", 1 );
+
+       // Get the image as requested
+       if ( *format != mlt_image_none )
+               *format = mlt_image_glsl;
+       error = mlt_frame_get_image( frame, image, format, &iwidth, &iheight, writable );
+       if ( !error ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( effect ) {
+                       bool ok = effect->set_int( "width", owidth );
+                       ok |= effect->set_int( "height", oheight );
+                       assert(ok);
+                       *width = owidth;
+                       *height = oheight;
+               }
+       }
+
+       return error;
+}
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !GlslManager::get_effect( filter, frame ) )
+               GlslManager::add_effect( filter, frame, new ResampleEffect );
+       mlt_frame_push_service( frame, filter );
+       mlt_frame_push_get_image( frame, get_image );
+       return frame;
+}
+
+extern "C"
+mlt_filter filter_movit_resample_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               filter->process = process;
+       }
+       return filter;
+}
diff --git a/src/modules/opengl/filter_movit_resize.cpp b/src/modules/opengl/filter_movit_resize.cpp
new file mode 100644 (file)
index 0000000..eb433fe
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * filter_movit_resize.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/init.h>
+#include <movit/padding_effect.h>
+
+static float alignment_parse( char* align )
+{
+       int ret = 0.0f;
+
+       if ( align == NULL );
+       else if ( isdigit( align[ 0 ] ) )
+               ret = atoi( align );
+       else if ( align[ 0 ] == 'c' || align[ 0 ] == 'm' )
+               ret = 1.0f;
+       else if ( align[ 0 ] == 'r' || align[ 0 ] == 'b' )
+               ret = 2.0f;
+
+       return ret;
+}
+
+static struct mlt_geometry_item_s get_geometry( mlt_profile profile, mlt_filter filter, mlt_frame frame )
+{
+       mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
+       mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
+       struct mlt_geometry_item_s item;
+       mlt_geometry geometry = (mlt_geometry) mlt_properties_get_data( filter_props, "geometry", NULL );
+       char *string = mlt_properties_get( properties, "resize.geometry" );
+       int length = mlt_filter_get_length2( filter, frame );
+
+       if ( !geometry ) {
+               geometry = mlt_geometry_init();
+               mlt_properties_set_data( filter_props, "geometry", geometry, 0,
+                       (mlt_destructor) mlt_geometry_close, NULL );
+               mlt_geometry_parse( geometry, string, length, profile->width, profile->height );
+       } else {
+               mlt_geometry_refresh( geometry, string, length, profile->width, profile->height );
+       }
+
+       mlt_geometry_fetch( geometry, &item, mlt_filter_get_position( filter, frame ) );
+
+       if ( !mlt_properties_get_int( properties, "resize.fill" ) ) {
+               int x = mlt_properties_get_int( properties, "meta.media.width" );
+               item.w = item.w > x ? x : item.w;
+               x = mlt_properties_get_int( properties, "meta.media.height" );
+               item.h = item.h > x ? x : item.h;
+       }
+
+       return item;
+}
+
+static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+       int error = 0;
+       mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
+       mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame );
+       mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
+
+       // Retrieve the aspect ratio
+       double aspect_ratio = mlt_frame_get_aspect_ratio( frame );
+       double consumer_aspect = mlt_profile_sar( profile );
+
+       // Correct Width/height if necessary
+       if ( *width == 0 || *height == 0 )
+       {
+               *width = profile->width;
+               *height = profile->height;
+       }
+
+       // Assign requested width/height from our subordinate
+       int owidth = *width;
+       int oheight = *height;
+
+       // Use a geometry to compute position and size
+       struct mlt_geometry_item_s geometry_item;
+       geometry_item.x = geometry_item.y = 0.0f;
+       geometry_item.distort = 0;
+       if ( mlt_properties_get( properties, "resize.geometry" ) ) {
+               geometry_item = get_geometry( profile, filter, frame );
+               owidth = lrintf( geometry_item.w );
+               oheight = lrintf( geometry_item.h );
+       }
+
+       // Check for the special case - no aspect ratio means no problem :-)
+       if ( aspect_ratio == 0.0 )
+               aspect_ratio = consumer_aspect;
+
+       // Reset the aspect ratio
+       mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio );
+
+       // Skip processing if requested.
+       char *rescale = mlt_properties_get( properties, "rescale.interp" );
+       if ( *format == mlt_image_none || ( rescale && !strcmp( rescale, "none" ) ) )
+               return mlt_frame_get_image( frame, image, format, width, height, writable );
+
+       if ( mlt_properties_get_int( properties, "distort" ) == 0 &&
+            geometry_item.distort == 0 )
+       {
+               // Normalise the input and out display aspect
+               int normalised_width = profile->width;
+               int normalised_height = profile->height;
+               int real_width = mlt_properties_get_int( properties, "meta.media.width" );
+               int real_height = mlt_properties_get_int( properties, "meta.media.height" );
+               if ( real_width == 0 )
+                       real_width = mlt_properties_get_int( properties, "width" );
+               if ( real_height == 0 )
+                       real_height = mlt_properties_get_int( properties, "height" );
+               double input_ar = aspect_ratio * real_width / real_height;
+               double output_ar = consumer_aspect * owidth / oheight;
+               
+               // Optimised for the input_ar > output_ar case (e.g. widescreen on standard)
+               int scaled_width = lrint( ( input_ar * normalised_width ) / output_ar );
+               int scaled_height = normalised_height;
+
+               // Now ensure that our images fit in the output frame
+               if ( scaled_width > normalised_width )
+               {
+                       scaled_width = normalised_width;
+                       scaled_height = lrint( ( output_ar * normalised_height ) / input_ar );
+               }
+
+               // Now calculate the actual image size that we want
+               owidth = lrint( scaled_width * owidth / normalised_width );
+               oheight = lrint( scaled_height * oheight / normalised_height );
+
+               mlt_log_debug( MLT_FILTER_SERVICE(filter),
+                       "real %dx%d normalised %dx%d output %dx%d sar %f in-dar %f out-dar %f\n",
+                       real_width, real_height, normalised_width, normalised_height, owidth, oheight, aspect_ratio, input_ar, output_ar);
+
+               // Tell frame we have conformed the aspect to the consumer
+               mlt_frame_set_aspect_ratio( frame, consumer_aspect );
+       }
+
+       mlt_properties_set_int( properties, "distort", 0 );
+
+       // Now get the image
+       *format = mlt_image_glsl;
+       error = mlt_frame_get_image( frame, image, format, &owidth, &oheight, writable );
+
+       // Offset the position according to alignment
+       float w = float( *width - owidth );
+       float h = float( *height - oheight );
+       if ( mlt_properties_get( properties, "resize.geometry" ) ) {
+               // default left if geometry supplied
+               geometry_item.x += w * alignment_parse( mlt_properties_get( properties, "resize.halign" ) ) / 2.0f;
+               geometry_item.y += h * alignment_parse( mlt_properties_get( properties, "resize.valign" ) ) / 2.0f;
+       } else {
+               // default center if no geometry
+               geometry_item.x = w * 0.5f;
+               geometry_item.y = h * 0.5f;
+       }
+
+       if ( !error ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( effect ) {
+                       bool ok = effect->set_int( "width", *width );
+                       ok |= effect->set_int( "height", *height );
+                       ok |= effect->set_float( "left", geometry_item.x );
+                       ok |= effect->set_float( "top", geometry_item.y );
+                       assert(ok);
+               }
+       }
+
+       return error;
+}
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !GlslManager::get_effect( filter, frame ) )
+               GlslManager::add_effect( filter, frame, new PaddingEffect );
+       mlt_frame_push_service( frame, filter );
+       mlt_frame_push_get_image( frame, get_image );
+       return frame;
+}
+
+extern "C"
+mlt_filter filter_movit_resize_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) )
+       {
+               filter->process = process;
+       }
+       return filter;
+}
diff --git a/src/modules/opengl/filter_movit_saturation.cpp b/src/modules/opengl/filter_movit_saturation.cpp
new file mode 100644 (file)
index 0000000..1e8f921
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * filter_movit_saturation.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/saturation_effect.h>
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect )
+                       effect = GlslManager::add_effect( filter, frame, new SaturationEffect() );
+               if ( effect ) {
+                       mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
+                       bool ok = effect->set_float( "saturation", mlt_properties_get_double( filter_props, "saturation" ) );
+                       assert(ok);
+               }
+       }
+       return frame;
+}
+
+extern "C" {
+
+mlt_filter filter_movit_saturation_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+               mlt_properties_set( properties, "saturation", arg? arg : "1.0" );
+               filter->process = process;
+       }
+       return filter;
+}
+
+}
diff --git a/src/modules/opengl/filter_movit_saturation.yml b/src/modules/opengl/filter_movit_saturation.yml
new file mode 100644 (file)
index 0000000..535af59
--- /dev/null
@@ -0,0 +1,24 @@
+schema_version: 0.1
+type: filter
+identifier: movit.saturation
+title: Saturation (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: >
+  A simple desaturation/saturation effect. We use the Rec. 709
+  definition of luminance (in linear light, of course) and linearly
+  interpolate between that (saturation=0) and the original signal
+  (saturation=1). Extrapolating that curve further (ie., saturation > 1)
+  gives us increased saturation if so desired.
+
+parameters:
+  - identifier: saturation
+    title: Saturation
+    type: float
+    minimum: 0
+    default: 1
diff --git a/src/modules/opengl/filter_movit_vignette.cpp b/src/modules/opengl/filter_movit_vignette.cpp
new file mode 100644 (file)
index 0000000..b0e33f7
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * filter_movit_vignette.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/vignette_effect.h>
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect ) {
+                       effect = GlslManager::add_effect( filter, frame, new VignetteEffect() );
+               }
+               if ( effect ) {
+                       mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
+                       bool ok = effect->set_float( "radius", mlt_properties_get_double( filter_props, "radius" ) );
+                       ok |= effect->set_float( "inner_radius", mlt_properties_get_double( filter_props, "inner_radius" ) );
+                       assert(ok);
+               }
+       }
+       return frame;
+}
+
+extern "C" {
+
+mlt_filter filter_movit_vignette_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               filter->process = process;
+               mlt_properties_set_double( MLT_FILTER_PROPERTIES(filter), "radius", 0.3 );
+               mlt_properties_set_double( MLT_FILTER_PROPERTIES(filter), "inner_radius", 0.3 );
+       }
+       return filter;
+}
+
+}
diff --git a/src/modules/opengl/filter_movit_vignette.yml b/src/modules/opengl/filter_movit_vignette.yml
new file mode 100644 (file)
index 0000000..3355bd3
--- /dev/null
@@ -0,0 +1,29 @@
+schema_version: 0.1
+type: filter
+identifier: movit.vignette
+title: Vignette (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: >
+  A circular vignette, falling off as cos² of the distance from the center
+  (the classic formula for approximating a real lens).
+
+parameters:
+  - identifier: radius
+    title: Outer Radius
+    type: float
+    minimum: 0.0
+    maximum: 1.0
+    default: 0.3
+
+  - identifier: inner_radius
+    title: Inner Radius
+    type: float
+    minimum: 0.0
+    maximum: 1.0
+    default: 0.3
diff --git a/src/modules/opengl/filter_white_balance.cpp b/src/modules/opengl/filter_white_balance.cpp
new file mode 100644 (file)
index 0000000..e3f1d9c
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * filter_white_balance.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/white_balance_effect.h>
+
+static mlt_frame process( mlt_filter filter, mlt_frame frame )
+{
+       if ( !mlt_frame_is_test_card( frame ) ) {
+               Effect* effect = GlslManager::get_effect( filter, frame );
+               if ( !effect )
+                       effect = GlslManager::add_effect( filter, frame, new WhiteBalanceEffect );
+               if ( effect ) {
+                       mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
+                       int color_int = mlt_properties_get_int( filter_props, "neutral_color" );
+                       RGBTriplet color(
+                               float((color_int >> 24) & 0xff) / 255.0f,
+                               float((color_int >> 16) & 0xff) / 255.0f,
+                               float((color_int >> 8) & 0xff) / 255.0f
+                       );
+                       bool ok = effect->set_vec3( "neutral_color", (float*) &color );
+                       ok |= effect->set_float( "output_color_temperature", mlt_properties_get_double( filter_props, "color_temperature" ) );
+                       assert(ok);
+               }
+       }
+       return frame;
+}
+
+extern "C" {
+
+mlt_filter filter_white_balance_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+
+       if ( glsl && ( filter = mlt_filter_new() ) ) {
+               mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+               mlt_properties_set( properties, "neutral_color", arg? arg : "#7f7f7f" );
+               mlt_properties_set_double( properties, "color_temperature", 6500.0 );
+               filter->process = process;
+       }
+       return filter;
+}
+
+}
diff --git a/src/modules/opengl/filter_white_balance.yml b/src/modules/opengl/filter_white_balance.yml
new file mode 100644 (file)
index 0000000..d090dbe
--- /dev/null
@@ -0,0 +1,27 @@
+schema_version: 0.1
+type: filter
+identifier: movit.white_balance
+title: White Balance (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: Color correction in LMS color space.
+
+parameters:
+  - identifier: neutral_color
+    title: Neutral Color
+    type: string
+    widget: color
+    default: #7f7f7f
+
+  - identifier: color_temperature
+    title: Color Temperature
+    type: float
+    minimum: 1000.0
+    maximum: 15000.0
+    default: 6500.0
+    unit: Kelvin
diff --git a/src/modules/opengl/glsl_manager.h b/src/modules/opengl/glsl_manager.h
new file mode 100644 (file)
index 0000000..1eab9dc
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * glsl_manager.h
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GLSL_MANAGER_H
+#define GLSL_MANAGER_H
+
+#include <GL/glew.h>
+#include <mlt++/MltFilter.h>
+#include <mlt++/MltDeque.h>
+
+#define MAXLISTCOUNT 1024
+typedef struct glsl_list_s *glsl_list;
+struct glsl_list_s
+{
+       void *items[MAXLISTCOUNT];
+       int count;
+
+       int ( *add )( glsl_list, void* );
+       void* ( *at )( glsl_list, int );
+       void* ( *take_at )( glsl_list, int );
+       void* ( *take )( glsl_list, void* );
+};
+
+struct glsl_texture_s
+{
+       int used;
+       GLuint texture;
+       int width;
+       int height;
+       GLint internal_format;
+};
+typedef struct glsl_texture_s *glsl_texture;
+
+struct glsl_fbo_s
+{
+       int used;
+       int width;
+       int height;
+       GLuint fbo;
+};
+typedef struct glsl_fbo_s *glsl_fbo;
+
+struct glsl_pbo_s
+{
+       int size;
+       GLuint pbo;
+};
+typedef struct glsl_pbo_s *glsl_pbo;
+
+class Effect;
+class EffectChain;
+class MltInput;
+
+class GlslManager : public Mlt::Filter
+{
+public:
+       GlslManager();
+       ~GlslManager();
+       static GlslManager* get_instance();
+
+       glsl_fbo get_fbo(int width, int height);
+       static void release_fbo(glsl_fbo);
+       glsl_texture get_texture(int width, int height, GLint internal_format);
+       static void release_texture(glsl_texture);
+       glsl_pbo get_pbo(int size);
+
+       static bool init_chain(mlt_service);
+       static EffectChain* get_chain(mlt_service);
+       static MltInput* get_input(mlt_service);
+       static void reset_finalized(mlt_service);
+       static Effect* get_effect(mlt_filter, mlt_frame);
+       static Effect* add_effect(mlt_filter, mlt_frame, Effect*);
+       static Effect* add_effect(mlt_filter, mlt_frame, Effect*, Effect* input_b);
+       static void render(mlt_service, void *chain, GLuint fbo, int width, int height);
+
+private:
+       static void onInit( mlt_properties owner, GlslManager* filter );
+
+       Mlt::Deque fbo_list;
+       Mlt::Deque texture_list;
+       glsl_pbo  pbo;
+       EffectChain* current_chain;
+};
+
+#endif // GLSL_MANAGER_H
diff --git a/src/modules/opengl/mlt_flip_effect.h b/src/modules/opengl/mlt_flip_effect.h
new file mode 100644 (file)
index 0000000..3fa9b72
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * mlt_flip_effect.h
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MLT_FLIP_EFFECT_H
+#define MLT_FLIP_EFFECT_H
+
+namespace Mlt
+{
+
+class VerticalFlip : public Effect {
+public:
+       VerticalFlip() {}
+       virtual std::string effect_type_id() const { return "MltVerticalFlip"; }
+       std::string output_fragment_shader() {
+               return "vec4 FUNCNAME(vec2 tc) { tc.y = 1.0 - tc.y; return INPUT(tc); }\n";
+       }
+       virtual bool needs_linear_light() const { return false; }
+       virtual bool needs_srgb_primaries() const { return false; }
+       AlphaHandling alpha_handling() const { return DONT_CARE_ALPHA_TYPE; }
+};
+
+} // namespace Mlt
+
+#endif // MLT_FLIP_EFFECT_H
diff --git a/src/modules/opengl/mlt_movit_input.cpp b/src/modules/opengl/mlt_movit_input.cpp
new file mode 100644 (file)
index 0000000..7a1ca03
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * mlt_movit_input.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "mlt_movit_input.h"
+#include "fbo_input.h"
+
+MltInput::MltInput(unsigned width, unsigned height)
+       : m_width(width)
+       , m_height(height)
+       , output_linear_gamma(false)
+       , needs_mipmaps(false)
+       , input(0)
+       , isRGB(true)
+{
+       register_int("output_linear_gamma", &output_linear_gamma);
+       register_int("needs_mipmaps", &needs_mipmaps);
+}
+
+MltInput::~MltInput()
+{
+       delete input;
+}
+
+std::string MltInput::output_fragment_shader()
+{
+       assert(input);
+       return input->output_fragment_shader();
+}
+
+void MltInput::set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num)
+{
+       assert(input);
+       input->set_gl_state(glsl_program_num, prefix, sampler_num);
+}
+
+Effect::AlphaHandling MltInput::alpha_handling() const
+{
+       assert(input);
+       return input->alpha_handling();
+}
+
+void MltInput::finalize()
+{
+       assert(input);
+       bool ok = input->set_int("output_linear_gamma", output_linear_gamma);
+       ok |= input->set_int("needs_mipmaps", needs_mipmaps);
+       assert(ok);
+       input->finalize();
+}
+
+bool MltInput::can_output_linear_gamma() const
+{
+       assert(input);
+       return input->can_output_linear_gamma();
+}
+
+Colorspace MltInput::get_color_space() const
+{
+       assert(input);
+       return input->get_color_space();
+}
+GammaCurve MltInput::get_gamma_curve() const
+{
+       assert(input);
+       return input->get_gamma_curve();
+}
+
+void MltInput::useFlatInput(EffectChain* chain, MovitPixelFormat pix_fmt, unsigned width, unsigned height)
+{
+       if (!input) {
+               m_width = width;
+               m_height = height;
+               ImageFormat image_format;
+               image_format.color_space = COLORSPACE_sRGB;
+               image_format.gamma_curve = GAMMA_sRGB;
+               input = new FlatInput(image_format, pix_fmt, GL_UNSIGNED_BYTE, width, height);
+               chain->add_output(image_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+               chain->set_dither_bits(8);
+       }
+}
+
+void MltInput::useYCbCrInput(EffectChain* chain, const ImageFormat& image_format, const YCbCrFormat& ycbcr_format, unsigned width, unsigned height)
+{
+       if (!input) {
+               m_width = width;
+               m_height = height;
+               input = new YCbCrInput(image_format, ycbcr_format, width, height);
+               ImageFormat output_format;
+               output_format.color_space = COLORSPACE_sRGB;
+               output_format.gamma_curve = GAMMA_sRGB;
+               chain->add_output(output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+               chain->set_dither_bits(8);
+               isRGB = false;
+               m_ycbcr_format = ycbcr_format;
+       }
+}
+
+void MltInput::useFBOInput(EffectChain *chain, GLuint texture)
+{
+       if (!input) {
+               FBOInput* fboInput = new FBOInput(m_width, m_height);
+               input = fboInput;
+               fboInput->set_texture(texture);
+       }
+}
+
+void MltInput::set_pixel_data(const unsigned char* data)
+{
+       assert(input);
+       if (isRGB) {
+               FlatInput* flat = (FlatInput*) input;
+               flat->set_pixel_data(data);
+       } else {
+               YCbCrInput* ycbcr = (YCbCrInput*) input;
+               ycbcr->set_pixel_data(0, data);
+               ycbcr->set_pixel_data(1, &data[m_width * m_height]);
+               ycbcr->set_pixel_data(2, &data[m_width * m_height + (m_width / m_ycbcr_format.chroma_subsampling_x * m_height / m_ycbcr_format.chroma_subsampling_y)]);
+       }
+}
diff --git a/src/modules/opengl/mlt_movit_input.h b/src/modules/opengl/mlt_movit_input.h
new file mode 100644 (file)
index 0000000..2f5de23
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * mlt_movit_input.h
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MLT_MOVIT_INPUT_H
+#define MLT_MOVIT_INPUT_H
+
+#include <movit/flat_input.h>
+#include <movit/ycbcr_input.h>
+#include <movit/effect_chain.h>
+
+class MltInput : public Input
+{
+public:
+       MltInput(unsigned width, unsigned height);
+       ~MltInput();
+
+       // Effect overrides
+       std::string effect_type_id() const { return "MltInput"; }
+       Effect::AlphaHandling alpha_handling() const;
+       std::string output_fragment_shader();
+       void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num);
+
+       // Input ovverrides
+       void finalize();
+       bool can_output_linear_gamma() const;
+       unsigned get_width() const { return m_width; }
+       unsigned get_height() const { return m_height; }
+       Colorspace get_color_space() const;
+       GammaCurve get_gamma_curve() const;
+
+       // Custom methods
+       void useFlatInput(EffectChain* chain, MovitPixelFormat pix_fmt, unsigned width, unsigned height);
+       void useYCbCrInput(EffectChain* chain, const ImageFormat& image_format, const YCbCrFormat& ycbcr_format, unsigned width, unsigned height);
+       void useFBOInput(EffectChain* chain, GLuint texture);
+       void set_pixel_data(const unsigned char* data);
+
+private:
+       unsigned m_width, m_height;
+       int output_linear_gamma, needs_mipmaps;
+       Input *input;
+       bool isRGB;
+       YCbCrFormat m_ycbcr_format;
+};
+
+#endif // MLT_MOVIT_INPUT_H
diff --git a/src/modules/opengl/transition_movit_mix.cpp b/src/modules/opengl/transition_movit_mix.cpp
new file mode 100644 (file)
index 0000000..05d0ce7
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * transition_movit_mix.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/init.h>
+#include <movit/effect_chain.h>
+#include <movit/util.h>
+#include <movit/mix_effect.h>
+#include "mlt_movit_input.h"
+#include "mlt_flip_effect.h"
+
+static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+       int error = 0;
+
+       // Get the b frame from the stack
+       mlt_frame b_frame = (mlt_frame) mlt_frame_pop_frame( a_frame );
+
+       // Get the transition object
+       mlt_transition transition = (mlt_transition) mlt_frame_pop_service( a_frame );
+
+       // Get the properties of the transition
+       mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );
+
+       // Get the properties of the a frame
+       mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
+
+       // Get the movit objects
+       mlt_service service = MLT_TRANSITION_SERVICE( transition );
+       EffectChain* chain = GlslManager::get_chain( service );
+       Effect* effect = (Effect*) mlt_properties_get_data( properties, "movit effect", NULL );
+       MltInput* a_input = GlslManager::get_input( service );
+       MltInput* b_input = (MltInput*) mlt_properties_get_data( properties, "movit input B", NULL );
+       mlt_image_format output_format = *format;
+
+       // Get the transition parameters
+       int reverse = mlt_properties_get_int( properties, "reverse" );
+       double mix = mlt_properties_get( properties, "mix" ) ?
+               mlt_properties_get_double( properties, "mix" ) :
+               mlt_transition_get_progress( transition, a_frame );
+       double inverse = 1.0 - mix;
+
+       // Set the movit parameters
+       bool ok = effect->set_float( "strength_first",  reverse ? mix : inverse );
+       ok     |= effect->set_float( "strength_second", reverse ? inverse : mix );
+       assert( ok );
+
+       // Get the frames' textures
+       GLuint* texture_id[2] = {0, 0};
+       *format = mlt_image_glsl_texture;
+       mlt_frame_get_image( a_frame, (uint8_t**) &texture_id[0], format, width, height, 0 );
+       a_input->useFBOInput( chain, *texture_id[0] );
+       *format = mlt_image_glsl_texture;
+       mlt_frame_get_image( b_frame, (uint8_t**) &texture_id[1], format, width, height, 0 );
+       b_input->useFBOInput( chain, *texture_id[1] );
+
+       // Set resolution to that of the a_frame
+       *width = mlt_properties_get_int( a_props, "width" );
+       *height = mlt_properties_get_int( a_props, "height" );
+
+       // Setup rendering to an FBO
+       GlslManager* glsl = GlslManager::get_instance();
+       glsl_fbo fbo = glsl->get_fbo( *width, *height );
+       if ( output_format == mlt_image_glsl_texture ) {
+               glsl_texture texture = glsl->get_texture( *width, *height, GL_RGBA );
+
+               glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo );
+               check_error();
+               glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 );
+               check_error();
+               glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+               check_error();
+
+               GlslManager::render( service, chain, fbo->fbo, *width, *height );
+
+               glFinish();
+               check_error();
+               glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+               check_error();
+
+               *image = (uint8_t*) &texture->texture;
+               mlt_frame_set_image( a_frame, *image, 0, NULL );
+               mlt_properties_set_data( properties, "movit.convert", texture, 0,
+                       (mlt_destructor) GlslManager::release_texture, NULL );
+               *format = output_format;
+       }
+       else {
+               // Use a PBO to hold the data we read back with glReadPixels()
+               // (Intel/DRI goes into a slow path if we don't read to PBO)
+               GLenum gl_format = ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl )?
+                       GL_RGBA : GL_RGB;
+               int img_size = *width * *height * ( gl_format == GL_RGB? 3 : 4 );
+               glsl_pbo pbo = glsl->get_pbo( img_size );
+               glsl_texture texture = glsl->get_texture( *width, *height, gl_format );
+
+               if ( fbo && pbo && texture ) {
+                       // Set the FBO
+                       glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo );
+                       check_error();
+                       glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 );
+                       check_error();
+                       glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+                       check_error();
+
+                       GlslManager::render( service, chain, fbo->fbo, *width, *height );
+
+                       // Read FBO into PBO
+                       glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo );
+                       check_error();
+                       glBufferData( GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ );
+                       check_error();
+                       glReadPixels( 0, 0, *width, *height, gl_format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0) );
+                       check_error();
+
+                       // Copy from PBO
+                       uint8_t* buf = (uint8_t*) glMapBuffer( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY );
+                       check_error();
+
+                       *format = gl_format == GL_RGBA ? mlt_image_rgb24a : mlt_image_rgb24;
+                       *image = (uint8_t*) mlt_pool_alloc( img_size );
+                       mlt_frame_set_image( a_frame, *image, img_size, mlt_pool_release );
+                       memcpy( *image, buf, img_size );
+
+                       // Release PBO and FBO
+                       glUnmapBuffer( GL_PIXEL_PACK_BUFFER_ARB );
+                       check_error();
+                       glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, 0 );
+                       check_error();
+                       glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+                       check_error();
+                       glBindTexture( GL_TEXTURE_2D, 0 );
+                       check_error();
+                       GlslManager::release_texture( texture );
+               }
+               else {
+                       error = 1;
+               }
+       }
+       if ( fbo ) GlslManager::release_fbo( fbo );
+
+       return error;
+}
+
+static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
+{
+       mlt_service service = MLT_TRANSITION_SERVICE(transition);
+
+       if ( !GlslManager::init_chain( service ) ) {
+               // Create the Movit effect chain
+               EffectChain* chain = GlslManager::get_chain( service );
+               mlt_profile profile = mlt_service_profile( service );
+               Input* b_input = new MltInput( profile->width, profile->height );
+               ImageFormat output_format;
+               output_format.color_space = COLORSPACE_sRGB;
+               output_format.gamma_curve = GAMMA_sRGB;
+               chain->add_input( b_input );
+               chain->add_output( output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED );
+               chain->set_dither_bits( 8 );
+
+               Effect* effect = chain->add_effect( new MixEffect(),
+                       GlslManager::get_input( service ), b_input );
+
+               // Save these new effects on properties for get_image
+               mlt_properties properties = MLT_TRANSITION_PROPERTIES(transition);
+               mlt_properties_set_data( properties, "movit effect", effect, 0, NULL, NULL );
+               mlt_properties_set_data( properties, "movit input B", b_input, 0, NULL, NULL );
+       }
+
+       // Push the transition on to the frame
+       mlt_frame_push_service( a_frame, transition );
+
+       // Push the b_frame on to the stack
+       mlt_frame_push_frame( a_frame, b_frame );
+
+       // Push the transition method
+       mlt_frame_push_get_image( a_frame, get_image );
+
+       return a_frame;
+}
+
+extern "C"
+mlt_transition transition_movit_mix_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_transition transition = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+       if ( glsl && ( transition = mlt_transition_new() ) ) {
+               transition->process = process;
+               mlt_properties_set( MLT_TRANSITION_PROPERTIES( transition ), "mix", arg );
+               
+               // Inform apps and framework that this is a video only transition
+               mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type", 1 );
+       }
+       return transition;
+}
diff --git a/src/modules/opengl/transition_movit_mix.yml b/src/modules/opengl/transition_movit_mix.yml
new file mode 100644 (file)
index 0000000..f814850
--- /dev/null
@@ -0,0 +1,35 @@
+schema_version: 0.1
+type: transition
+identifier: movit.mix
+title: Dissolve (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: A simple video cross-fade or mixing effect.
+
+parameters:
+  - identifier: argument
+    title: Mix Level
+    description: Performs a dissolve if a mix level is not supplied.
+    type: float
+    minimum: 0
+    maximum: 1
+
+  - identifier: mix
+    title: Mix Level
+    description: Performs a dissolve if a mix level is not supplied.
+    type: float
+    minimum: 0
+    maximum: 1
+
+  - identifier: reverse
+    title: Reverse
+    type: integer
+    mutable: yes
+    description: >
+      Reverse the direction of the transition.
+    default: 0
diff --git a/src/modules/opengl/transition_movit_overlay.cpp b/src/modules/opengl/transition_movit_overlay.cpp
new file mode 100644 (file)
index 0000000..7ff55c8
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * transition_movit_overlay.cpp
+ * Copyright (C) 2013 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glsl_manager.h"
+#include <movit/init.h>
+#include <movit/effect_chain.h>
+#include <movit/util.h>
+#include <movit/overlay_effect.h>
+#include "mlt_movit_input.h"
+#include "mlt_flip_effect.h"
+
+static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+       int error = 0;
+
+       // Get the b frame from the stack
+       mlt_frame b_frame = (mlt_frame) mlt_frame_pop_frame( a_frame );
+
+       // Get the transition object
+       mlt_transition transition = (mlt_transition) mlt_frame_pop_service( a_frame );
+
+       // Get the properties of the transition
+       mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );
+
+       // Get the properties of the a frame
+       mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame );
+
+       // Get the movit objects
+       mlt_service service = MLT_TRANSITION_SERVICE( transition );
+       EffectChain* chain = GlslManager::get_chain( service );
+       MltInput* a_input = GlslManager::get_input( service );
+       MltInput* b_input = (MltInput*) mlt_properties_get_data( properties, "movit input B", NULL );
+       mlt_image_format output_format = *format;
+
+       // Get the frames' textures
+       GLuint* texture_id[2] = {0, 0};
+       *format = mlt_image_glsl_texture;
+       mlt_frame_get_image( a_frame, (uint8_t**) &texture_id[0], format, width, height, 0 );
+       a_input->useFBOInput( chain, *texture_id[0] );
+       *format = mlt_image_glsl_texture;
+       mlt_frame_get_image( b_frame, (uint8_t**) &texture_id[1], format, width, height, 0 );
+       b_input->useFBOInput( chain, *texture_id[1] );
+
+       // Set resolution to that of the a_frame
+       *width = mlt_properties_get_int( a_props, "width" );
+       *height = mlt_properties_get_int( a_props, "height" );
+
+       // Setup rendering to an FBO
+       GlslManager* glsl = GlslManager::get_instance();
+       glsl_fbo fbo = glsl->get_fbo( *width, *height );
+       if ( output_format == mlt_image_glsl_texture ) {
+               glsl_texture texture = glsl->get_texture( *width, *height, GL_RGBA );
+
+               glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo );
+               check_error();
+               glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 );
+               check_error();
+               glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+               check_error();
+
+               GlslManager::render( service, chain, fbo->fbo, *width, *height );
+
+               glFinish();
+               check_error();
+               glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+               check_error();
+
+               *image = (uint8_t*) &texture->texture;
+               mlt_frame_set_image( a_frame, *image, 0, NULL );
+               mlt_properties_set_data( properties, "movit.convert", texture, 0,
+                       (mlt_destructor) GlslManager::release_texture, NULL );
+               *format = output_format;
+       }
+       else {
+               // Use a PBO to hold the data we read back with glReadPixels()
+               // (Intel/DRI goes into a slow path if we don't read to PBO)
+               GLenum gl_format = ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl )?
+                       GL_RGBA : GL_RGB;
+               int img_size = *width * *height * ( gl_format == GL_RGB? 3 : 4 );
+               glsl_pbo pbo = glsl->get_pbo( img_size );
+               glsl_texture texture = glsl->get_texture( *width, *height, gl_format );
+
+               if ( fbo && pbo && texture ) {
+                       // Set the FBO
+                       glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo );
+                       check_error();
+                       glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 );
+                       check_error();
+                       glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+                       check_error();
+
+                       GlslManager::render( service, chain, fbo->fbo, *width, *height );
+
+                       // Read FBO into PBO
+                       glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo );
+                       check_error();
+                       glBufferData( GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ );
+                       check_error();
+                       glReadPixels( 0, 0, *width, *height, gl_format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0) );
+                       check_error();
+
+                       // Copy from PBO
+                       uint8_t* buf = (uint8_t*) glMapBuffer( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY );
+                       check_error();
+
+                       *format = gl_format == GL_RGBA ? mlt_image_rgb24a : mlt_image_rgb24;
+                       *image = (uint8_t*) mlt_pool_alloc( img_size );
+                       mlt_frame_set_image( a_frame, *image, img_size, mlt_pool_release );
+                       memcpy( *image, buf, img_size );
+
+                       // Release PBO and FBO
+                       glUnmapBuffer( GL_PIXEL_PACK_BUFFER_ARB );
+                       check_error();
+                       glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, 0 );
+                       check_error();
+                       glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+                       check_error();
+                       glBindTexture( GL_TEXTURE_2D, 0 );
+                       check_error();
+                       GlslManager::release_texture( texture );
+               }
+               else {
+                       error = 1;
+               }
+       }
+       if ( fbo ) GlslManager::release_fbo( fbo );
+
+       return error;
+}
+
+static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
+{
+       mlt_service service = MLT_TRANSITION_SERVICE(transition);
+
+       if ( !GlslManager::init_chain( service ) ) {
+               // Create the Movit effect chain
+               EffectChain* chain = GlslManager::get_chain( service );
+               mlt_profile profile = mlt_service_profile( service );
+               Input* b_input = new MltInput( profile->width, profile->height );
+               ImageFormat output_format;
+               output_format.color_space = COLORSPACE_sRGB;
+               output_format.gamma_curve = GAMMA_sRGB;
+               chain->add_input( b_input );
+               chain->add_output( output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED );
+               chain->set_dither_bits( 8 );
+
+               Effect* effect = chain->add_effect( new OverlayEffect(),
+                       GlslManager::get_input( service ), b_input );
+
+               // Save these new input on properties for get_image
+               mlt_properties_set_data( MLT_TRANSITION_PROPERTIES(transition),
+                       "movit input B", b_input, 0, NULL, NULL );
+       }
+
+       // Push the transition on to the frame
+       mlt_frame_push_service( a_frame, transition );
+
+       // Push the b_frame on to the stack
+       mlt_frame_push_frame( a_frame, b_frame );
+
+       // Push the transition method
+       mlt_frame_push_get_image( a_frame, get_image );
+
+       return a_frame;
+}
+
+extern "C"
+mlt_transition transition_movit_overlay_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_transition transition = NULL;
+       GlslManager* glsl = GlslManager::get_instance();
+       if ( glsl && ( transition = mlt_transition_new() ) ) {
+               transition->process = process;
+               
+               // Inform apps and framework that this is a video only transition
+               mlt_properties_set_int( MLT_TRANSITION_PROPERTIES( transition ), "_transition_type", 1 );
+       }
+       return transition;
+}
diff --git a/src/modules/opengl/transition_movit_overlay.yml b/src/modules/opengl/transition_movit_overlay.yml
new file mode 100644 (file)
index 0000000..0ae18b2
--- /dev/null
@@ -0,0 +1,13 @@
+schema_version: 0.1
+type: transition
+identifier: movit.overlay
+title: Dissolve (GLSL)
+version: 1
+copyright: Dan Dennedy
+creator: Steinar H. Gunderson
+license: GPLv2
+language: en
+tags:
+  - Video
+description: >
+  A simple video overlay or alpha-compositing effect using the Porter-Duff over operation.