From 6ce35f4e77ab6f0c32c3e2c0f39d77bafbc493a1 Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Wed, 24 Aug 2005 06:35:41 +0000 Subject: [PATCH] + Added VMFX module + New filter (shape) which provides alpha manipulations and an alternative wipe mechanism + New producer (pgm) which provides basic functionality for portable grey maps git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@809 d19143bc-622f-0410-bfdd-b5b2a6649095 --- src/modules/fezzik.dict | 2 +- src/modules/vmfx/Makefile | 34 ++++++ src/modules/vmfx/configure | 20 +++ src/modules/vmfx/factory.c | 48 ++++++++ src/modules/vmfx/filter_shape.c | 191 +++++++++++++++++++++++++++++ src/modules/vmfx/filter_shape.h | 28 +++++ src/modules/vmfx/gpl | 0 src/modules/vmfx/producer_pgm.c | 209 ++++++++++++++++++++++++++++++++ src/modules/vmfx/producer_pgm.h | 28 +++++ 9 files changed, 559 insertions(+), 1 deletion(-) create mode 100644 src/modules/vmfx/Makefile create mode 100755 src/modules/vmfx/configure create mode 100644 src/modules/vmfx/factory.c create mode 100644 src/modules/vmfx/filter_shape.c create mode 100644 src/modules/vmfx/filter_shape.h create mode 100644 src/modules/vmfx/gpl create mode 100644 src/modules/vmfx/producer_pgm.c create mode 100644 src/modules/vmfx/producer_pgm.h diff --git a/src/modules/fezzik.dict b/src/modules/fezzik.dict index a26ffe58..2d1ff7c7 100644 --- a/src/modules/fezzik.dict +++ b/src/modules/fezzik.dict @@ -20,7 +20,7 @@ http://*=avformat *.mpeg=mcmpeg,avformat *.mpl=pango *.ogg=vorbis -*.pgm=pixbuf +*.pgm=pgm,pixbuf *.png=pixbuf *.story=westley *.svg=pixbuf diff --git a/src/modules/vmfx/Makefile b/src/modules/vmfx/Makefile new file mode 100644 index 00000000..83e76651 --- /dev/null +++ b/src/modules/vmfx/Makefile @@ -0,0 +1,34 @@ +include ../../../config.mak + +TARGET = ../libmltvmfx$(LIBSUF) + +OBJS = factory.o \ + filter_shape.o \ + producer_pgm.o + +CFLAGS += -I../.. + +LDFLAGS+=-L../../framework -lmlt + +SRCS := $(OBJS:.o=.c) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) + +depend: $(SRCS) + $(CC) -MM $(CFLAGS) $^ 1>.depend + +dist-clean: clean + rm -f .depend + +clean: + rm -f $(OBJS) $(TARGET) + +install: all + install -m 755 $(TARGET) "$(prefix)/share/mlt/modules" + +ifneq ($(wildcard .depend),) +include .depend +endif diff --git a/src/modules/vmfx/configure b/src/modules/vmfx/configure new file mode 100755 index 00000000..f80432ca --- /dev/null +++ b/src/modules/vmfx/configure @@ -0,0 +1,20 @@ +#!/bin/sh + +if [ "$help" != "1" ] +then + +cat << EOF >> ../producers.dat +pgm libmltvmfx$LIBSUF +EOF + +cat << EOF >> ../filters.dat +shape libmltvmfx$LIBSUF +EOF + +cat << EOF >> ../transitions.dat +EOF + +cat << EOF >> ../consumers.dat +EOF + +fi diff --git a/src/modules/vmfx/factory.c b/src/modules/vmfx/factory.c new file mode 100644 index 00000000..b1b809b1 --- /dev/null +++ b/src/modules/vmfx/factory.c @@ -0,0 +1,48 @@ +/* + * factory.c -- the factory method interfaces + * Copyright (C) 2005 Visual Media Fx Inc. + * Author: Charles Yates + * + * 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 + +#include "filter_shape.h" +#include "producer_pgm.h" + +void *mlt_create_producer( char *id, void *arg ) +{ + if ( !strcmp( id, "pgm" ) ) + return producer_pgm_init( arg ); + return NULL; +} + +void *mlt_create_filter( char *id, void *arg ) +{ + if ( !strcmp( id, "shape" ) ) + return filter_shape_init( arg ); + return NULL; +} + +void *mlt_create_transition( char *id, void *arg ) +{ + return NULL; +} + +void *mlt_create_consumer( char *id, void *arg ) +{ + return NULL; +} diff --git a/src/modules/vmfx/filter_shape.c b/src/modules/vmfx/filter_shape.c new file mode 100644 index 00000000..63019474 --- /dev/null +++ b/src/modules/vmfx/filter_shape.c @@ -0,0 +1,191 @@ +/* + * filter_shape.c -- Arbitrary alpha channel shaping + * Copyright (C) 2005 Visual Media Fx Inc. + * Author: Charles Yates + * + * 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 "filter_shape.h" +#include +#include +#include +#include +#include + +inline double smoothstep( const double e1, const double e2, const double a ) +{ + if ( a < e1 ) return 0.0; + if ( a > e2 ) return 1.0; + double v = ( a - e1 ) / ( e2 - e1 ); + return ( v * v * ( 3 - 2 * v ) ); +} + +/** Get the images and apply the luminance of the mask to the alpha of the frame. +*/ + +static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +{ + // Fetch the data from the stack (mix, mask, filter) + double mix = mlt_deque_pop_back_double( MLT_FRAME_IMAGE_STACK( this ) ); + mlt_frame mask = mlt_frame_pop_service( this ); + mlt_filter filter = mlt_frame_pop_service( this ); + + // Obtain the constants + double softness = mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "softness" ); + int use_luminance = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "use_luminance" ); + int invert = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "invert" ) * 255; + + // Render the frame + if ( mlt_frame_get_image( this, image, format, width, height, writable ) == 0 ) + { + // Get the alpha mask of the source + uint8_t *alpha = mlt_frame_get_alpha_mask( this ); + + // Obtain a scaled/distorted mask to match + uint8_t *mask_img = NULL; + mlt_image_format mask_fmt = mlt_image_yuv422; + mlt_properties_set_int( MLT_FRAME_PROPERTIES( mask ), "distort", 1 ); + mlt_properties_pass_list( MLT_FRAME_PROPERTIES( mask ), MLT_FRAME_PROPERTIES( this ), "deinterlace,deinterlace_method,rescale.interp" ); + + if ( mlt_frame_get_image( mask, &mask_img, &mask_fmt, width, height, 0 ) == 0 ) + { + int size = *width * *height; + uint8_t *p = alpha; + double a = 0; + double b = 0; + if ( !use_luminance ) + { + uint8_t *q = mlt_frame_get_alpha_mask( mask ); + while( size -- ) + { + a = ( double )*q ++ / 255.0; + b = 1.0 - smoothstep( a, a + softness, mix ); + *p = ( uint8_t )( *p * b ) ^ invert; + p ++; + } + } + else if ( mix != 1.0 ) + { + uint8_t *q = mask_img; + while( size -- ) + { + a = ( ( double )*q - 16 ) / 235.0; + b = smoothstep( a, a + softness, mix ); + *p = ( uint8_t )( *p * b ) ^ invert; + p ++; + q += 2; + } + } + } + } + + return 0; +} + +/** Filter processing. +*/ + +static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) +{ + // Obtain the shape instance + char *resource = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "resource" ); + mlt_producer producer = mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "instance", NULL ); + + // Get the key framed values + mlt_geometry alpha = mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "_alpha", NULL ); + char *alpha_data = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "mix" ); + double alpha_mix = 0.0; + + // Calculate the position and length + int position = mlt_frame_get_position( frame ) - mlt_filter_get_in( this ); + int in = mlt_filter_get_in( this ); + int out = mlt_filter_get_out( this ); + int length; + + // Special case for attached filters - in/out come through on the frame + if ( out == 0 ) + { + in = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "in" ); + out = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "out" ); + } + + // Duration of the shape + length = out - in + 1; + + // If we haven't created the instance or it's changed + if ( producer == NULL || strcmp( resource, mlt_properties_get( MLT_PRODUCER_PROPERTIES( producer ), "resource" ) ) ) + { + producer = mlt_factory_producer( NULL, resource ); + if ( producer != NULL ) + mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "loop" ); + mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "instance", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); + } + + // Construct the geometry item if needed, otherwise refresh it + if ( alpha == NULL ) + { + alpha = mlt_geometry_init( ); + mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "_alpha", alpha, 0, ( mlt_destructor )mlt_geometry_close, NULL ); + mlt_geometry_parse( alpha, alpha_data, length, 100, 100 ); + } + else + { + mlt_geometry_refresh( alpha, alpha_data, length, 100, 100 ); + } + + // We may still not have a producer in which case, we do nothing + if ( producer != NULL ) + { + mlt_frame mask = NULL; + struct mlt_geometry_item_s item; + mlt_geometry_fetch( alpha, &item, position ); + alpha_mix = item.x; + mlt_properties_pass( MLT_PRODUCER_PROPERTIES( producer ), MLT_FILTER_PROPERTIES( this ), "producer." ); + mlt_producer_seek( producer, position ); + if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &mask, 0 ) == 0 ) + { + char *name = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "_unique_id" ); + mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), name, mask, 0, ( mlt_destructor )mlt_frame_close, NULL ); + mlt_frame_push_service( frame, this ); + mlt_frame_push_service( frame, mask ); + mlt_deque_push_back_double( MLT_FRAME_IMAGE_STACK( frame ), alpha_mix / 100.0 ); + mlt_frame_push_get_image( frame, filter_get_image ); + if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "audio_match" ) ) + mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), "meta.volume", alpha_mix / 100.0 ); + } + } + + return frame; +} + +/** Constructor for the filter. +*/ + +mlt_filter filter_shape_init( char *arg ) +{ + mlt_filter this = mlt_filter_new( ); + if ( this != NULL ) + { + mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "resource", arg ); + mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "mix", "100" ); + mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "audio_match", 1 ); + mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "invert", 0 ); + mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "softness", 0.1 ); + this->process = filter_process; + } + return this; +} + diff --git a/src/modules/vmfx/filter_shape.h b/src/modules/vmfx/filter_shape.h new file mode 100644 index 00000000..57bfc08b --- /dev/null +++ b/src/modules/vmfx/filter_shape.h @@ -0,0 +1,28 @@ +/* + * filter_shape.h -- Arbitrary alpha channel shaping + * Copyright (C) 2005 Visual Media Fx Inc. + * Author: Charles Yates + * + * 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 _FILTER_SHAPE_H_ +#define _FILTER_SHAPE_H_ + +#include + +extern mlt_filter filter_shape_init( char *arg ); + +#endif diff --git a/src/modules/vmfx/gpl b/src/modules/vmfx/gpl new file mode 100644 index 00000000..e69de29b diff --git a/src/modules/vmfx/producer_pgm.c b/src/modules/vmfx/producer_pgm.c new file mode 100644 index 00000000..369f6d9e --- /dev/null +++ b/src/modules/vmfx/producer_pgm.c @@ -0,0 +1,209 @@ +/* + * producer_pgm.c -- PGM producer + * Copyright (C) 2005 Visual Media Fx Inc. + * Author: Charles Yates + * + * 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 "producer_pgm.h" +#include +#include +#include + +static int read_pgm( char *name, uint8_t **image, int *width, int *height, int *maxval ); +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); +static void producer_close( mlt_producer parent ); + +mlt_producer producer_pgm_init( void *resource ) +{ + mlt_producer this = NULL; + uint8_t *image = NULL; + int width = 0; + int height = 0; + int maxval = 0; + + if ( read_pgm( resource, &image, &width, &height, &maxval ) == 0 ) + { + this = calloc( 1, sizeof( struct mlt_producer_s ) ); + if ( this != NULL && mlt_producer_init( this, NULL ) == 0 ) + { + mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); + this->get_frame = producer_get_frame; + this->close = ( mlt_destructor )producer_close; + mlt_properties_set( properties, "resource", resource ); + mlt_properties_set_data( properties, "image", image, 0, mlt_pool_release, NULL ); + mlt_properties_set_int( properties, "real_width", width ); + mlt_properties_set_int( properties, "real_height", height ); + } + else + { + mlt_pool_release( image ); + free( this ); + this = NULL; + } + } + + return this; +} + +/** Load the PGM file. +*/ + +static int read_pgm( char *name, uint8_t **image, int *width, int *height, int *maxval ) +{ + uint8_t *input = NULL; + int error = 0; + FILE *f = fopen( name, "r" ); + char data[ 512 ]; + + // Initialise + *image = NULL; + *width = 0; + *height = 0; + *maxval = 0; + + // Get the magic code + if ( f != NULL && fgets( data, 511, f ) != NULL && data[ 0 ] == 'P' && data[ 1 ] == '5' ) + { + char *p = data + 2; + int i = 0; + int val = 0; + + // PGM Header parser (probably needs to be strengthened) + for ( i = 0; !error && i < 3; i ++ ) + { + if ( *p != '\0' && *p != '\n' ) + val = strtol( p, &p, 10 ); + else + p = NULL; + + while ( error == 0 && p == NULL ) + { + if ( fgets( data, 511, f ) == NULL ) + error = 1; + else if ( data[ 0 ] != '#' ) + val = strtol( data, &p, 10 ); + } + + switch( i ) + { + case 0: *width = val; break; + case 1: *height = val; break; + case 2: *maxval = val; break; + } + } + + if ( !error ) + { + // Determine if this is one or two bytes per pixel + int bpp = *maxval > 255 ? 2 : 1; + int size = *width * *height * bpp; + uint8_t *p; + + // Allocate temporary storage for the data and the image + input = mlt_pool_alloc( *width * *height * bpp ); + *image = mlt_pool_alloc( *width * *height * sizeof( uint8_t ) * 2 ); + p = *image; + + error = *image == NULL || input == NULL; + + if ( !error ) + { + // Read the raw data + error = fread( input, *width * *height * bpp, 1, f ) != 1; + + if ( !error ) + { + // Convert to yuv422 (very lossy - need to extend this to allow 16 bit alpha out) + for ( i = 0; i < size; i += bpp ) + { + *p ++ = 16 + ( input[ i ] * 219 ) / 255; + *p ++ = 128; + } + } + } + } + + if ( error ) + mlt_pool_release( *image ); + mlt_pool_release( input ); + } + else + { + error = 1; + } + + if ( f != NULL ) + fclose( f ); + + return error; +} + +static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +{ + mlt_producer producer = mlt_frame_pop_service( this ); + int real_width = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "real_width" ); + int real_height = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "real_height" ); + int size = real_width * real_height; + uint8_t *image = mlt_pool_alloc( size * 2 ); + uint8_t *source = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( producer ), "image", NULL ); + + mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "image", image, size * 2, mlt_pool_release, NULL ); + + *width = real_width; + *height = real_height; + *format = mlt_image_yuv422; + *buffer = image; + + if ( image != NULL && source != NULL ) + memcpy( image, source, size * 2 ); + + return 0; +} + +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) +{ + // Construct a test frame + *frame = mlt_frame_init( ); + + // Get the frames properties + mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); + + // Pass the data on the frame properties + mlt_properties_pass_list( properties, MLT_PRODUCER_PROPERTIES( producer ), "real_width,real_height" ); + mlt_properties_set_int( properties, "has_image", 1 ); + mlt_properties_set_int( properties, "progressive", 1 ); + mlt_properties_set_double( properties, "aspect_ratio", 1 ); + + // Push the image callback + mlt_frame_push_service( *frame, producer ); + mlt_frame_push_get_image( *frame, producer_get_image ); + + // Update timecode on the frame we're creating + mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); + + // Calculate the next timecode + mlt_producer_prepare_next( producer ); + + return 0; +} + +static void producer_close( mlt_producer parent ) +{ + parent->close = NULL; + mlt_producer_close( parent ); + free( parent ); +} diff --git a/src/modules/vmfx/producer_pgm.h b/src/modules/vmfx/producer_pgm.h new file mode 100644 index 00000000..3c97dddc --- /dev/null +++ b/src/modules/vmfx/producer_pgm.h @@ -0,0 +1,28 @@ +/* + * producer_pgm.h -- PGM producer + * Copyright (C) 2005 Visual Media Fx Inc. + * Author: Charles Yates + * + * 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 PRODUCER_PGM_H_ +#define PRODUCER_PGM_H_ + +#include + +extern mlt_producer producer_pgm_init( void * ); + +#endif -- 2.39.2