#include <framework/mlt_frame.h>
#include <framework/mlt_cache.h>
#include <framework/mlt_log.h>
+#include <framework/mlt_tokeniser.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
-#include "config.h"
-
#ifdef USE_EXIF
#include <libexif/exif-data.h>
#endif
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
+#include <ctype.h>
// this protects concurrent access to gdk_pixbuf
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
mlt_producer producer_pixbuf_init( char *filename )
{
- producer_pixbuf self = calloc( sizeof( struct producer_pixbuf_s ), 1 );
+ producer_pixbuf self = calloc( 1, sizeof( struct producer_pixbuf_s ) );
if ( self != NULL && mlt_producer_init( &self->parent, self ) == 0 )
{
mlt_producer producer = &self->parent;
mlt_properties_set_int( properties, "ttl", 25 );
mlt_properties_set_int( properties, "aspect_ratio", 1 );
mlt_properties_set_int( properties, "progressive", 1 );
+ mlt_properties_set_int( properties, "seekable", 1 );
+ mlt_properties_set_int( properties, "loop", 1 );
// Validate the resource
if ( filename )
mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
mlt_properties_set_data( frame_properties, "producer_pixbuf", self, 0, NULL, NULL );
mlt_frame_set_position( frame, mlt_producer_position( producer ) );
- mlt_properties_set_position( frame_properties, "pixbuf_position", mlt_producer_position( producer ) );
refresh_pixbuf( self, frame );
+ mlt_cache_item_close( self->pixbuf_cache );
mlt_frame_close( frame );
}
}
return result;
}
-static int load_sequence( producer_pixbuf self, mlt_properties properties, const char *filename )
+static int load_sequence_sprintf( producer_pixbuf self, mlt_properties properties, const char *filename )
{
int result = 0;
return result;
}
+static int load_sequence_deprecated( producer_pixbuf self, mlt_properties properties, const char *filename )
+{
+ int result = 0;
+ const char *start;
+
+ // This approach is deprecated in favor of the begin querystring parameter.
+ // Obtain filenames with pattern containing a begin value, e.g. foo%1234d.png
+ if ( ( start = strchr( filename, '%' ) ) )
+ {
+ const char *end = ++start;
+ while ( isdigit( *end ) ) end++;
+ if ( end > start && ( end[0] == 'd' || end[0] == 'i' || end[0] == 'u' ) )
+ {
+ int n = end - start;
+ char *s = calloc( 1, n + 1 );
+ strncpy( s, start, n );
+ mlt_properties_set( properties, "begin", s );
+ free( s );
+ s = calloc( 1, strlen( filename ) + 2 );
+ strncpy( s, filename, start - filename );
+ sprintf( s + ( start - filename ), ".%d%s", n, end );
+ result = load_sequence_sprintf( self, properties, s );
+ free( s );
+ }
+ }
+ return result;
+}
+
+static int load_sequence_querystring( producer_pixbuf self, mlt_properties properties, const char *filename )
+{
+ int result = 0;
+
+ // Obtain filenames with pattern and begin value in query string
+ if ( strchr( filename, '%' ) && strchr( filename, '?' ) )
+ {
+ // Split filename into pattern and query string
+ char *s = strdup( filename );
+ char *querystring = strrchr( s, '?' );
+ *querystring++ = '\0';
+ if ( strstr( filename, "begin=" ) )
+ mlt_properties_set( properties, "begin", strstr( querystring, "begin=" ) + 6 );
+ else if ( strstr( filename, "begin:" ) )
+ mlt_properties_set( properties, "begin", strstr( querystring, "begin:" ) + 6 );
+ // Coerce to an int value so serialization does not have any extra query string cruft
+ mlt_properties_set_int( properties, "begin", mlt_properties_get_int( properties, "begin" ) );
+ result = load_sequence_sprintf( self, properties, s );
+ free( s );
+ }
+ return result;
+}
+
static int load_folder( producer_pixbuf self, mlt_properties properties, const char *filename )
{
int result = 0;
self->filenames = mlt_properties_new( );
if (!load_svg( self, properties, filename ) &&
- !load_sequence( self, properties, filename ) &&
+ !load_sequence_querystring( self, properties, filename ) &&
+ !load_sequence_sprintf( self, properties, filename ) &&
+ !load_sequence_deprecated( self, properties, filename ) &&
!load_folder( self, properties, filename ) )
{
mlt_properties_set( self->filenames, "0", filename );
double ttl = mlt_properties_get_int( producer_props, "ttl" );
// Get the original position of this frame
- mlt_position position = mlt_properties_get_position( properties, "pixbuf_position" );
+ mlt_position position = mlt_frame_original_position( frame );
position += mlt_producer_get_in( producer );
// Image index
- int current_idx = ( int )floor( ( double )position / ttl ) % self->count;
+ int loop = mlt_properties_get_int( producer_props, "loop" );
+ int current_idx;
+ if (loop) {
+ current_idx = ( int )floor( ( double )position / ttl ) % self->count;
+ } else {
+ current_idx = MIN(( double )position / ttl, self->count - 1);
+ }
// Key for the cache
char image_key[ 10 ];
if ( self->pixbuf && ( !self->image || ( format != mlt_image_none && format != self->format ) ) )
{
char *interps = mlt_properties_get( properties, "rescale.interp" );
+ if ( interps ) interps = strdup( interps );
int interp = GDK_INTERP_BILINEAR;
- if ( strcmp( interps, "nearest" ) == 0 )
+ if ( !interps ) {
+ // Keep bilinear by default
+ }
+ else if ( strcmp( interps, "nearest" ) == 0 )
interp = GDK_INTERP_NEAREST;
else if ( strcmp( interps, "tiles" ) == 0 )
interp = GDK_INTERP_TILES;
else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 )
interp = GDK_INTERP_HYPER;
+ if ( interps ) free( interps );
// Note - the original pixbuf is already safe and ready for destruction
pthread_mutex_lock( &g_mutex );
int dst_stride = self->width * ( has_alpha ? 4 : 3 );
int image_size = dst_stride * ( height + 1 );
self->image = mlt_pool_alloc( image_size );
+ self->alpha = NULL;
self->format = has_alpha ? mlt_image_rgb24a : mlt_image_rgb24;
if ( src_stride != dst_stride )
}
}
+ // Update the cache
mlt_cache_item_close( self->image_cache );
mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "pixbuf.image", self->image, image_size, mlt_pool_release );
self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.image" );
self->image_idx = current_idx;
mlt_cache_item_close( self->alpha_cache );
- mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "pixbuf.alpha", self->alpha, width * height, mlt_pool_release );
- self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.alpha" );
+ self->alpha_cache = NULL;
+ if ( self->alpha )
+ {
+ mlt_service_cache_put( MLT_PRODUCER_SERVICE( producer ), "pixbuf.alpha", self->alpha, width * height, mlt_pool_release );
+ self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.alpha" );
+ }
// Finished with pixbuf now
g_object_unref( pixbuf );
mlt_producer producer = &self->parent;
// Use the width and height suggested by the rescale filter because we can do our own scaling.
- *width = mlt_properties_get_int( properties, "rescale_width" );
- *height = mlt_properties_get_int( properties, "rescale_height" );
+ if ( mlt_properties_get_int( properties, "rescale_width" ) > 0 )
+ *width = mlt_properties_get_int( properties, "rescale_width" );
+ if ( mlt_properties_get_int( properties, "rescale_height" ) > 0 )
+ *height = mlt_properties_get_int( properties, "rescale_height" );
// Restore pixbuf and image
mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) );
// Update timecode on the frame we're creating
mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
- // Ensure that we have a way to obtain the position in the get_image
- mlt_properties_set_position( properties, "pixbuf_position", mlt_producer_position( producer ) );
-
// Refresh the pixbuf
self->pixbuf_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "pixbuf.pixbuf" );
self->pixbuf = mlt_cache_item_data( self->pixbuf_cache, NULL );