--- /dev/null
+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
--- /dev/null
+#!/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
--- /dev/null
+/*
+ * 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 );
+}
--- /dev/null
+/*
+ * 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" );
+}
--- /dev/null
+/*
+ * 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";
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+
+}
--- /dev/null
+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
+
--- /dev/null
+/*
+ * 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 );
+}
--- /dev/null
+/*
+ * 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;
+}
+
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
+
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
+
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
+
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
+
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
+
+}
+
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
+
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
+
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
+
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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)]);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+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.