#include "mlt_service.h"
#include "mlt_filter.h"
#include "mlt_transition.h"
+#include "mlt_multitrack.h"
+#include "mlt_tractor.h"
#include <stdlib.h>
#include <string.h>
struct mlt_field_s
{
- // We extending service here
- struct mlt_service_s parent;
-
// This is the producer we're connected to
mlt_service producer;
-};
-/** Forward declarations
-*/
+ // Multitrack
+ mlt_multitrack multitrack;
-static int service_get_frame( mlt_service service, mlt_frame_ptr frame, int index );
-
-/** Constructor. This service needs to know its producer at construction.
+ // Tractor
+ mlt_tractor tractor;
+};
- When the first filter or transition is planted, we connect it immediately to
- the producer of the field, and all subsequent plants are then connected to the
- previous plant. This immediate connection requires the producer prior to the first
- plant.
+/** Constructor.
- It's a kind of arbitrary decsion - we could generate a dummy service here and
- then connect the dummy in the normal connect manner. Behaviour may change in the
- future (say, constructing a dummy when producer service is NULL). However, the
- current solution is quite clean, if slightly out of sync with the rest of the
- mlt framework.
+ We construct a multitrack and a tractor here.
*/
-mlt_field mlt_field_init( mlt_service producer )
+mlt_field mlt_field_init( )
{
// Initialise the field
mlt_field this = calloc( sizeof( struct mlt_field_s ), 1 );
- // Get the service
- mlt_service service = &this->parent;
+ // Initialise it
+ if ( this != NULL )
+ {
+ // Construct a multitrack
+ this->multitrack = mlt_multitrack_init( );
- // Initialise the service
- mlt_service_init( service, this );
+ // Construct a tractor
+ this->tractor = mlt_tractor_init( );
- // Override the get_frame method
- service->get_frame = service_get_frame;
+ // The first plant will be connected to the mulitrack
+ this->producer = mlt_multitrack_service( this->multitrack );
- // Connect to the producer immediately
- if ( mlt_service_connect_producer( service, producer, 0 ) == 0 )
- this->producer = producer;
+ // Connect the tractor to the multitrack
+ mlt_tractor_connect( this->tractor, this->producer );
+ }
// Return this
return this;
mlt_service mlt_field_service( mlt_field this )
{
- return &this->parent;
+ return mlt_tractor_service( this->tractor );
+}
+
+/** Get the multi track.
+*/
+
+mlt_multitrack mlt_field_multitrack( mlt_field this )
+{
+ return this->multitrack;
}
/** Get the properties associated to this field.
mlt_properties mlt_field_properties( mlt_field this )
{
- return mlt_service_properties( &this->parent );
+ return mlt_service_properties( mlt_field_service( this ) );
}
/** Plant a filter.
// If sucessful, then we'll use this for connecting in the future
if ( result == 0 )
{
- // Update last
+ // This is now the new producer
this->producer = mlt_filter_service( that );
+
+ // Reconnect tractor to new producer
+ mlt_tractor_connect( this->tractor, this->producer );
}
return result;
// If sucessful, then we'll use this for connecting in the future
if ( result == 0 )
{
- // Update last
+ // This is now the new producer
this->producer = mlt_transition_service( that );
+
+ // Reconnect tractor to new producer
+ mlt_tractor_connect( this->tractor, this->producer );
}
return 0;
}
-/** Get a frame.
-*/
-
-static int service_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
-{
- mlt_field this = service->child;
- return mlt_service_get_frame( this->producer, frame, index );
-}
-
/** Close the field.
*/
void mlt_field_close( mlt_field this )
{
- mlt_service_close( &this->parent );
+ mlt_tractor_close( this->tractor );
+ mlt_multitrack_close( this->multitrack );
free( this );
}
#include "mlt_types.h"
-extern mlt_field mlt_field_init( mlt_service producer );
+extern mlt_field mlt_field_init( );
extern mlt_service mlt_field_service( mlt_field this );
+extern mlt_multitrack mlt_field_multitrack( mlt_field this );
extern mlt_properties mlt_field_properties( mlt_field this );
extern int mlt_field_plant_filter( mlt_field this, mlt_filter that, int track );
extern int mlt_field_plant_transition( mlt_field this, mlt_transition that, int a_track, int b_track );
return &this->parent;
}
+mlt_properties mlt_filter_properties( mlt_filter this )
+{
+ return mlt_service_properties( mlt_filter_service( this ) );
+}
+
/** Connect this filter to a producers track. Note that a filter only operates
on a single track, and by default it operates on the entirety of that track.
*/
// track and in/out points
mlt_service producer;
- //int track;
- //mlt_timecode in;
- //mlt_timecode out;
// Protected
void *child;
extern int mlt_filter_init( mlt_filter this, void *child );
extern mlt_service mlt_filter_service( mlt_filter this );
+extern mlt_properties mlt_filter_properties( mlt_filter this );
extern int mlt_filter_connect( mlt_filter this, mlt_service producer, int index );
extern void mlt_filter_set_in_and_out( mlt_filter this, mlt_timecode in, mlt_timecode out );
extern int mlt_filter_get_track( mlt_filter this );
struct mlt_playlist_s
{
struct mlt_producer_s parent;
+ struct mlt_producer_s blank;
+
int size;
int count;
- mlt_producer *list;
- mlt_producer blank;
-
- int virtual_size;
- int virtual_count;
- playlist_entry **virtual_list;
+ playlist_entry **list;
};
/** Forward declarations
// Override the producer get_frame
producer->get_frame = producer_get_frame;
- // Create a producer
- this->blank = calloc( sizeof( struct mlt_producer_s ), 1 );
-
- // Initialise it
- mlt_producer_init( this->blank, NULL );
+ // Initialise blank
+ mlt_producer_init( &this->blank, NULL );
}
return this;
return mlt_producer_service( &this->parent );
}
-/** Store a producer in the playlist.
+/** Append to the virtual playlist.
*/
-static int mlt_playlist_store( mlt_playlist this, mlt_producer producer )
+static int mlt_playlist_virtual_append( mlt_playlist this, mlt_producer producer, mlt_timecode in, mlt_timecode out )
{
- int i;
-
- // If it's already added, return the index
- for ( i = 0; i < this->count; i ++ )
- {
- if ( producer == this->list[ i ] )
- return i;
- }
-
// Check that we have room
if ( this->count >= this->size )
{
- this->list = realloc( this->list, ( this->size + 10 ) * sizeof( mlt_producer ) );
+ int i;
+ this->list = realloc( this->list, ( this->size + 10 ) * sizeof( playlist_entry * ) );
for ( i = this->size; i < this->size + 10; i ++ )
this->list[ i ] = NULL;
this->size += 10;
}
- // Add this producer to the list
- this->list[ this->count ] = producer;
+ this->list[ this->count ] = calloc( sizeof( playlist_entry ), 1 );
+ this->list[ this->count ]->producer = producer;
+ this->list[ this->count ]->in = in;
+ this->list[ this->count ]->playtime = out - in;
- return this->count ++;
-}
-
-/** Append to the virtual playlist.
-*/
-
-static int mlt_playlist_virtual_append( mlt_playlist this, int position, mlt_timecode in, mlt_timecode out )
-{
- // Check that we have room
- if ( this->virtual_count >= this->virtual_size )
- {
- int i;
- this->virtual_list = realloc( this->virtual_list, ( this->virtual_size + 10 ) * sizeof( playlist_entry * ) );
- for ( i = this->virtual_size; i < this->virtual_size + 10; i ++ )
- this->virtual_list[ i ] = NULL;
- this->virtual_size += 10;
- }
-
- this->virtual_list[ this->virtual_count ] = malloc( sizeof( playlist_entry ) );
- this->virtual_list[ this->virtual_count ]->producer = this->list[ position ];
- this->virtual_list[ this->virtual_count ]->in = in;
- this->virtual_list[ this->virtual_count ]->playtime = out - in;
-
- this->virtual_count ++;
+ this->count ++;
return 0;
}
static mlt_producer mlt_playlist_virtual_seek( mlt_playlist this )
{
// Default producer to blank
- mlt_producer producer = this->blank;
+ mlt_producer producer = &this->blank;
// Map playlist position to real producer in virtual playlist
mlt_timecode position = mlt_producer_position( &this->parent );
// Loop through the virtual playlist
int i = 0;
- for ( i = 0; i < this->virtual_count; i ++ )
+ for ( i = 0; i < this->count; i ++ )
{
- if ( position < this->virtual_list[ i ]->playtime )
+ if ( position < this->list[ i ]->playtime )
{
// Found it, now break
- producer = this->virtual_list[ i ]->producer;
- position += this->virtual_list[ i ]->in;
+ producer = this->list[ i ]->producer;
+ position += this->list[ i ]->in;
break;
}
else
{
// Decrement position by length of this entry
- position -= this->virtual_list[ i ]->playtime;
+ position -= this->list[ i ]->playtime;
}
}
int mlt_playlist_append( mlt_playlist this, mlt_producer producer )
{
- // Get the position of the producer in the list
- int position = mlt_playlist_store( this, producer );
-
// Append to virtual list
- mlt_playlist_virtual_append( this, position, 0, mlt_producer_get_playtime( producer ) );
-
- return 0;
+ return mlt_playlist_virtual_append( this, producer, 0, mlt_producer_get_playtime( producer ) );
}
/** Append a blank to the playlist of a given length.
int mlt_playlist_blank( mlt_playlist this, mlt_timecode length )
{
- // Get the position of the producer in the list
- int position = mlt_playlist_store( this, this->blank );
-
// Append to the virtual list
- mlt_playlist_virtual_append( this, position, 0, length );
-
- return 0;
+ return mlt_playlist_virtual_append( this, &this->blank, 0, length );
}
/** Get the current frame.
void mlt_playlist_close( mlt_playlist this )
{
mlt_producer_close( &this->parent );
- mlt_producer_close( this->blank );
- free( this->blank );
+ mlt_producer_close( &this->blank );
free( this );
}
producer_ppm.o \
filter_deinterlace.o \
filter_greyscale.o \
+ filter_resize.o \
transition_composite.o
CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread
cat << EOF >> ../filters.dat
deinterlace libmltcore.so
greyscale libmltcore.so
+resize libmltcore.so
EOF
cat << EOF >> ../transitions.dat
#include "filter_deinterlace.h"
#include "filter_greyscale.h"
+#include "filter_resize.h"
#include "producer_ppm.h"
#include "transition_composite.h"
return filter_deinterlace_init( arg );
if ( !strcmp( id, "greyscale" ) )
return filter_greyscale_init( arg );
+ if ( !strcmp( id, "resize" ) )
+ return filter_resize_init( arg );
return NULL;
}
--- /dev/null
+/*
+ * filter_resize.c -- resizing filter
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * 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_resize.h"
+
+#include <framework/mlt_frame.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+/** Do it :-).
+*/
+
+static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+ int owidth = *width;
+ int oheight = *height;
+ mlt_frame_get_image( this, image, format, &owidth, &oheight, 0 );
+ if ( !strcmp( mlt_properties_get( mlt_frame_properties( this ), "resize.scale" ), "affine" ) )
+ *image = mlt_frame_rescale_yuv422( this, *width, *height );
+ else
+ *image = mlt_frame_resize_yuv422( this, *width, *height );
+ return 0;
+}
+
+/** Filter processing.
+*/
+
+static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
+{
+ mlt_frame_push_get_image( frame, filter_get_image );
+ mlt_properties_set( mlt_frame_properties( frame ), "resize.scale", mlt_properties_get( mlt_filter_properties( this ), "scale" ) );
+ return frame;
+}
+
+/** Constructor for the filter.
+*/
+
+mlt_filter filter_resize_init( void *arg )
+{
+ mlt_filter this = calloc( sizeof( struct mlt_filter_s ), 1 );
+ if ( mlt_filter_init( this, this ) == 0 )
+ {
+ this->process = filter_process;
+ mlt_properties_set( mlt_filter_properties( this ), "scale", "off" );
+ }
+ return this;
+}
+
--- /dev/null
+/*
+ * filter_resize.h -- resizing filter
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * 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_RESIZE_H_
+#define _FILTER_RESIZE_H_
+
+#include <framework/mlt_filter.h>
+
+extern mlt_filter filter_deinterlace_init( void *arg );
+
+#endif
#include "producer_pixbuf.h"
#include <framework/mlt_frame.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
static void producer_close( mlt_producer parent );
producer->get_frame = producer_get_frame;
producer->close = producer_close;
- this->filename = strdup( filename );
- this->counter = -1;
-
// Get the properties interface
mlt_properties properties = mlt_producer_properties( &this->parent );
// Set the default properties
mlt_properties_set_int( properties, "video_standard", mlt_video_standard_pal );
+ mlt_properties_set_double( properties, "ttl", 5 );
+ // Obtain filenames
+ if ( strchr( filename, '%' ) != NULL )
+ {
+ // handle picture sequences
+ int i = 0;
+ int gap = 0;
+ char full[1024];
+
+ while ( gap < 100 )
+ {
+ struct stat buf;
+ snprintf( full, 1023, filename, i ++ );
+ if ( stat( full, &buf ) == 0 )
+ {
+ this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) );
+ this->filenames[ this->count ++ ] = strdup( full );
+ gap = 0;
+ }
+ else
+ {
+ gap ++;
+ }
+ }
+ }
+ else
+ {
+ this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) );
+ this->filenames[ this->count ++ ] = strdup( filename );
+ }
+
+ // Initialise gobject types
g_type_init();
return producer;
// Obtain properties of frame
mlt_properties properties = mlt_frame_properties( *frame );
+ // Get the time to live for each frame
+ double ttl = mlt_properties_get_double( mlt_producer_properties( producer ), "ttl" );
+
+ // Image index
+ int image_idx = ( int )floor( mlt_producer_position( producer ) / ttl ) % this->count;
+
+ // Update timecode on the frame we're creating
+ mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) );
+
// optimization for subsequent iterations on single picture
- if ( this->image != NULL )
+ if ( this->image != NULL && image_idx == this->image_idx )
{
// Set width/height
mlt_properties_set_int( properties, "width", this->width );
mlt_frame_push_get_image( *frame, producer_get_image );
}
- else if ( strchr( this->filename, '%' ) != NULL )
- {
- // handle picture sequences
- char filename[1024];
- filename[1023] = 0;
- int current = this->counter;
- do
- {
- ++this->counter;
- snprintf( filename, 1023, this->filename, this->counter );
- pixbuf = gdk_pixbuf_new_from_file( filename, &error );
- // allow discontinuity in frame numbers up to 99
- error = NULL;
- } while ( pixbuf == NULL && ( this->counter - current ) < 100 );
- }
- else
+ else
{
- pixbuf = gdk_pixbuf_new_from_file( this->filename, &error );
+ free( this->image );
+ free( this->alpha );
+ this->image_idx = image_idx;
+ pixbuf = gdk_pixbuf_new_from_file( this->filenames[ image_idx ], &error );
}
// If we have a pixbuf
if ( pixbuf )
{
// Scale to adjust for sample aspect ratio
- if ( mlt_properties_get_int( properties, "video_stadnard" ) == mlt_video_standard_pal )
+ if ( mlt_properties_get_int( properties, "video_standard" ) == mlt_video_standard_pal )
{
GdkPixbuf *temp = pixbuf;
GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf,
mlt_properties_set_int( properties, "height", this->height );
// Pass alpha and image on properties with or without destructor
- if ( this->counter >= 0 )
- {
- // if picture sequence pass the image and alpha data with destructor
- mlt_properties_set_data( properties, "image", image, 0, free, NULL );
- mlt_properties_set_data( properties, "alpha", alpha, 0, free, NULL );
- }
- else
- {
- // if single picture, reference the image and alpha in the producer
- this->image = image;
- this->alpha = alpha;
+ this->image = image;
+ this->alpha = alpha;
- // pass the image and alpha data without destructor
- mlt_properties_set_data( properties, "image", image, 0, NULL, NULL );
- mlt_properties_set_data( properties, "alpha", alpha, 0, NULL, NULL );
- }
+ // pass the image and alpha data without destructor
+ mlt_properties_set_data( properties, "image", image, 0, NULL, NULL );
+ mlt_properties_set_data( properties, "alpha", alpha, 0, NULL, NULL );
// Set alpha call back
( *frame )->get_alpha_mask = producer_get_alpha_mask;
mlt_frame_push_get_image( *frame, producer_get_image );
}
- // Update timecode on the frame we're creating
- mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) );
-
// Calculate the next timecode
mlt_producer_prepare_next( producer );
static void producer_close( mlt_producer parent )
{
producer_pixbuf this = parent->child;
- if ( this->filename )
- free( this->filename );
if ( this->image )
free( this->image );
if ( this->alpha )
struct producer_pixbuf_s
{
struct mlt_producer_s parent;
- char *filename;
- int counter;
+
+ // File name list
+ char **filenames;
+ int count;
+ int image_idx;
+
int width;
int height;
uint8_t *image;
SDL_UnlockSurface( screen );
}
-void sdl_fill_audio( void *udata, Uint8 *stream, int len )
+void sdl_fill_audio( void *udata, uint8_t *stream, int len )
{
consumer_sdl this = udata;
mlt_service service = NULL;
mlt_consumer consumer = NULL;
mlt_multitrack multitrack = NULL;
- mlt_tractor tractor = NULL;
mlt_producer producer = NULL;
mlt_playlist playlist = NULL;
mlt_field field = NULL;
// Set up containers
playlist = mlt_playlist_init( );
- multitrack = mlt_multitrack_init( );
- tractor = mlt_tractor_init( );
- // Field must be connected on construction
- field = mlt_field_init( mlt_multitrack_service( multitrack ) );
+ // Construct the field
+ field = mlt_field_init( );
mlt_properties properties = mlt_field_properties( field );
mlt_properties_set_int( properties, "registered", 0 );
+ // Get the multitrack from the field
+ multitrack = mlt_field_multitrack( field );
+
// Parse the arguments
for ( i = 1; i < argc; i ++ )
{
consumer= mlt_factory_consumer( "sdl", NULL );
// Connect producer to playlist
- mlt_playlist_append( playlist, producer );
+ if ( producer != NULL )
+ mlt_playlist_append( playlist, producer );
// Connect multitrack to producer
mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist ), 0 );
- // Connect tractor to field
- mlt_tractor_connect( tractor, mlt_field_service( field ) );
-
// Connect consumer to tractor
- mlt_consumer_connect( consumer, mlt_tractor_service( tractor ) );
+ mlt_consumer_connect( consumer, mlt_field_service( field ) );
// Transport functionality
- transport( producer );
+ transport( mlt_multitrack_producer( multitrack ) );
// Close the services
mlt_consumer_close( consumer );
- mlt_tractor_close( tractor );
mlt_field_close( field );
- mlt_multitrack_close( multitrack );
mlt_producer_close( producer );
// Close the factory
#include "mlt_service.h"
#include "mlt_filter.h"
#include "mlt_transition.h"
+#include "mlt_multitrack.h"
+#include "mlt_tractor.h"
#include <stdlib.h>
#include <string.h>
struct mlt_field_s
{
- // We extending service here
- struct mlt_service_s parent;
-
// This is the producer we're connected to
mlt_service producer;
-};
-/** Forward declarations
-*/
+ // Multitrack
+ mlt_multitrack multitrack;
-static int service_get_frame( mlt_service service, mlt_frame_ptr frame, int index );
-
-/** Constructor. This service needs to know its producer at construction.
+ // Tractor
+ mlt_tractor tractor;
+};
- When the first filter or transition is planted, we connect it immediately to
- the producer of the field, and all subsequent plants are then connected to the
- previous plant. This immediate connection requires the producer prior to the first
- plant.
+/** Constructor.
- It's a kind of arbitrary decsion - we could generate a dummy service here and
- then connect the dummy in the normal connect manner. Behaviour may change in the
- future (say, constructing a dummy when producer service is NULL). However, the
- current solution is quite clean, if slightly out of sync with the rest of the
- mlt framework.
+ We construct a multitrack and a tractor here.
*/
-mlt_field mlt_field_init( mlt_service producer )
+mlt_field mlt_field_init( )
{
// Initialise the field
mlt_field this = calloc( sizeof( struct mlt_field_s ), 1 );
- // Get the service
- mlt_service service = &this->parent;
+ // Initialise it
+ if ( this != NULL )
+ {
+ // Construct a multitrack
+ this->multitrack = mlt_multitrack_init( );
- // Initialise the service
- mlt_service_init( service, this );
+ // Construct a tractor
+ this->tractor = mlt_tractor_init( );
- // Override the get_frame method
- service->get_frame = service_get_frame;
+ // The first plant will be connected to the mulitrack
+ this->producer = mlt_multitrack_service( this->multitrack );
- // Connect to the producer immediately
- if ( mlt_service_connect_producer( service, producer, 0 ) == 0 )
- this->producer = producer;
+ // Connect the tractor to the multitrack
+ mlt_tractor_connect( this->tractor, this->producer );
+ }
// Return this
return this;
mlt_service mlt_field_service( mlt_field this )
{
- return &this->parent;
+ return mlt_tractor_service( this->tractor );
+}
+
+/** Get the multi track.
+*/
+
+mlt_multitrack mlt_field_multitrack( mlt_field this )
+{
+ return this->multitrack;
}
/** Get the properties associated to this field.
mlt_properties mlt_field_properties( mlt_field this )
{
- return mlt_service_properties( &this->parent );
+ return mlt_service_properties( mlt_field_service( this ) );
}
/** Plant a filter.
// If sucessful, then we'll use this for connecting in the future
if ( result == 0 )
{
- // Update last
+ // This is now the new producer
this->producer = mlt_filter_service( that );
+
+ // Reconnect tractor to new producer
+ mlt_tractor_connect( this->tractor, this->producer );
}
return result;
// If sucessful, then we'll use this for connecting in the future
if ( result == 0 )
{
- // Update last
+ // This is now the new producer
this->producer = mlt_transition_service( that );
+
+ // Reconnect tractor to new producer
+ mlt_tractor_connect( this->tractor, this->producer );
}
return 0;
}
-/** Get a frame.
-*/
-
-static int service_get_frame( mlt_service service, mlt_frame_ptr frame, int index )
-{
- mlt_field this = service->child;
- return mlt_service_get_frame( this->producer, frame, index );
-}
-
/** Close the field.
*/
void mlt_field_close( mlt_field this )
{
- mlt_service_close( &this->parent );
+ mlt_tractor_close( this->tractor );
+ mlt_multitrack_close( this->multitrack );
free( this );
}
#include "mlt_types.h"
-extern mlt_field mlt_field_init( mlt_service producer );
+extern mlt_field mlt_field_init( );
extern mlt_service mlt_field_service( mlt_field this );
+extern mlt_multitrack mlt_field_multitrack( mlt_field this );
extern mlt_properties mlt_field_properties( mlt_field this );
extern int mlt_field_plant_filter( mlt_field this, mlt_filter that, int track );
extern int mlt_field_plant_transition( mlt_field this, mlt_transition that, int a_track, int b_track );
return &this->parent;
}
+mlt_properties mlt_filter_properties( mlt_filter this )
+{
+ return mlt_service_properties( mlt_filter_service( this ) );
+}
+
/** Connect this filter to a producers track. Note that a filter only operates
on a single track, and by default it operates on the entirety of that track.
*/
// track and in/out points
mlt_service producer;
- //int track;
- //mlt_timecode in;
- //mlt_timecode out;
// Protected
void *child;
extern int mlt_filter_init( mlt_filter this, void *child );
extern mlt_service mlt_filter_service( mlt_filter this );
+extern mlt_properties mlt_filter_properties( mlt_filter this );
extern int mlt_filter_connect( mlt_filter this, mlt_service producer, int index );
extern void mlt_filter_set_in_and_out( mlt_filter this, mlt_timecode in, mlt_timecode out );
extern int mlt_filter_get_track( mlt_filter this );
struct mlt_playlist_s
{
struct mlt_producer_s parent;
+ struct mlt_producer_s blank;
+
int size;
int count;
- mlt_producer *list;
- mlt_producer blank;
-
- int virtual_size;
- int virtual_count;
- playlist_entry **virtual_list;
+ playlist_entry **list;
};
/** Forward declarations
// Override the producer get_frame
producer->get_frame = producer_get_frame;
- // Create a producer
- this->blank = calloc( sizeof( struct mlt_producer_s ), 1 );
-
- // Initialise it
- mlt_producer_init( this->blank, NULL );
+ // Initialise blank
+ mlt_producer_init( &this->blank, NULL );
}
return this;
return mlt_producer_service( &this->parent );
}
-/** Store a producer in the playlist.
+/** Append to the virtual playlist.
*/
-static int mlt_playlist_store( mlt_playlist this, mlt_producer producer )
+static int mlt_playlist_virtual_append( mlt_playlist this, mlt_producer producer, mlt_timecode in, mlt_timecode out )
{
- int i;
-
- // If it's already added, return the index
- for ( i = 0; i < this->count; i ++ )
- {
- if ( producer == this->list[ i ] )
- return i;
- }
-
// Check that we have room
if ( this->count >= this->size )
{
- this->list = realloc( this->list, ( this->size + 10 ) * sizeof( mlt_producer ) );
+ int i;
+ this->list = realloc( this->list, ( this->size + 10 ) * sizeof( playlist_entry * ) );
for ( i = this->size; i < this->size + 10; i ++ )
this->list[ i ] = NULL;
this->size += 10;
}
- // Add this producer to the list
- this->list[ this->count ] = producer;
+ this->list[ this->count ] = calloc( sizeof( playlist_entry ), 1 );
+ this->list[ this->count ]->producer = producer;
+ this->list[ this->count ]->in = in;
+ this->list[ this->count ]->playtime = out - in;
- return this->count ++;
-}
-
-/** Append to the virtual playlist.
-*/
-
-static int mlt_playlist_virtual_append( mlt_playlist this, int position, mlt_timecode in, mlt_timecode out )
-{
- // Check that we have room
- if ( this->virtual_count >= this->virtual_size )
- {
- int i;
- this->virtual_list = realloc( this->virtual_list, ( this->virtual_size + 10 ) * sizeof( playlist_entry * ) );
- for ( i = this->virtual_size; i < this->virtual_size + 10; i ++ )
- this->virtual_list[ i ] = NULL;
- this->virtual_size += 10;
- }
-
- this->virtual_list[ this->virtual_count ] = malloc( sizeof( playlist_entry ) );
- this->virtual_list[ this->virtual_count ]->producer = this->list[ position ];
- this->virtual_list[ this->virtual_count ]->in = in;
- this->virtual_list[ this->virtual_count ]->playtime = out - in;
-
- this->virtual_count ++;
+ this->count ++;
return 0;
}
static mlt_producer mlt_playlist_virtual_seek( mlt_playlist this )
{
// Default producer to blank
- mlt_producer producer = this->blank;
+ mlt_producer producer = &this->blank;
// Map playlist position to real producer in virtual playlist
mlt_timecode position = mlt_producer_position( &this->parent );
// Loop through the virtual playlist
int i = 0;
- for ( i = 0; i < this->virtual_count; i ++ )
+ for ( i = 0; i < this->count; i ++ )
{
- if ( position < this->virtual_list[ i ]->playtime )
+ if ( position < this->list[ i ]->playtime )
{
// Found it, now break
- producer = this->virtual_list[ i ]->producer;
- position += this->virtual_list[ i ]->in;
+ producer = this->list[ i ]->producer;
+ position += this->list[ i ]->in;
break;
}
else
{
// Decrement position by length of this entry
- position -= this->virtual_list[ i ]->playtime;
+ position -= this->list[ i ]->playtime;
}
}
int mlt_playlist_append( mlt_playlist this, mlt_producer producer )
{
- // Get the position of the producer in the list
- int position = mlt_playlist_store( this, producer );
-
// Append to virtual list
- mlt_playlist_virtual_append( this, position, 0, mlt_producer_get_playtime( producer ) );
-
- return 0;
+ return mlt_playlist_virtual_append( this, producer, 0, mlt_producer_get_playtime( producer ) );
}
/** Append a blank to the playlist of a given length.
int mlt_playlist_blank( mlt_playlist this, mlt_timecode length )
{
- // Get the position of the producer in the list
- int position = mlt_playlist_store( this, this->blank );
-
// Append to the virtual list
- mlt_playlist_virtual_append( this, position, 0, length );
-
- return 0;
+ return mlt_playlist_virtual_append( this, &this->blank, 0, length );
}
/** Get the current frame.
void mlt_playlist_close( mlt_playlist this )
{
mlt_producer_close( &this->parent );
- mlt_producer_close( this->blank );
- free( this->blank );
+ mlt_producer_close( &this->blank );
free( this );
}
producer_ppm.o \
filter_deinterlace.o \
filter_greyscale.o \
+ filter_resize.o \
transition_composite.o
CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread
cat << EOF >> ../filters.dat
deinterlace libmltcore.so
greyscale libmltcore.so
+resize libmltcore.so
EOF
cat << EOF >> ../transitions.dat
#include "filter_deinterlace.h"
#include "filter_greyscale.h"
+#include "filter_resize.h"
#include "producer_ppm.h"
#include "transition_composite.h"
return filter_deinterlace_init( arg );
if ( !strcmp( id, "greyscale" ) )
return filter_greyscale_init( arg );
+ if ( !strcmp( id, "resize" ) )
+ return filter_resize_init( arg );
return NULL;
}
--- /dev/null
+/*
+ * filter_resize.c -- resizing filter
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * 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_resize.h"
+
+#include <framework/mlt_frame.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+/** Do it :-).
+*/
+
+static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+ int owidth = *width;
+ int oheight = *height;
+ mlt_frame_get_image( this, image, format, &owidth, &oheight, 0 );
+ if ( !strcmp( mlt_properties_get( mlt_frame_properties( this ), "resize.scale" ), "affine" ) )
+ *image = mlt_frame_rescale_yuv422( this, *width, *height );
+ else
+ *image = mlt_frame_resize_yuv422( this, *width, *height );
+ return 0;
+}
+
+/** Filter processing.
+*/
+
+static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
+{
+ mlt_frame_push_get_image( frame, filter_get_image );
+ mlt_properties_set( mlt_frame_properties( frame ), "resize.scale", mlt_properties_get( mlt_filter_properties( this ), "scale" ) );
+ return frame;
+}
+
+/** Constructor for the filter.
+*/
+
+mlt_filter filter_resize_init( void *arg )
+{
+ mlt_filter this = calloc( sizeof( struct mlt_filter_s ), 1 );
+ if ( mlt_filter_init( this, this ) == 0 )
+ {
+ this->process = filter_process;
+ mlt_properties_set( mlt_filter_properties( this ), "scale", "off" );
+ }
+ return this;
+}
+
--- /dev/null
+/*
+ * filter_resize.h -- resizing filter
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * 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_RESIZE_H_
+#define _FILTER_RESIZE_H_
+
+#include <framework/mlt_filter.h>
+
+extern mlt_filter filter_deinterlace_init( void *arg );
+
+#endif
#include "producer_pixbuf.h"
#include <framework/mlt_frame.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index );
static void producer_close( mlt_producer parent );
producer->get_frame = producer_get_frame;
producer->close = producer_close;
- this->filename = strdup( filename );
- this->counter = -1;
-
// Get the properties interface
mlt_properties properties = mlt_producer_properties( &this->parent );
// Set the default properties
mlt_properties_set_int( properties, "video_standard", mlt_video_standard_pal );
+ mlt_properties_set_double( properties, "ttl", 5 );
+ // Obtain filenames
+ if ( strchr( filename, '%' ) != NULL )
+ {
+ // handle picture sequences
+ int i = 0;
+ int gap = 0;
+ char full[1024];
+
+ while ( gap < 100 )
+ {
+ struct stat buf;
+ snprintf( full, 1023, filename, i ++ );
+ if ( stat( full, &buf ) == 0 )
+ {
+ this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) );
+ this->filenames[ this->count ++ ] = strdup( full );
+ gap = 0;
+ }
+ else
+ {
+ gap ++;
+ }
+ }
+ }
+ else
+ {
+ this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) );
+ this->filenames[ this->count ++ ] = strdup( filename );
+ }
+
+ // Initialise gobject types
g_type_init();
return producer;
// Obtain properties of frame
mlt_properties properties = mlt_frame_properties( *frame );
+ // Get the time to live for each frame
+ double ttl = mlt_properties_get_double( mlt_producer_properties( producer ), "ttl" );
+
+ // Image index
+ int image_idx = ( int )floor( mlt_producer_position( producer ) / ttl ) % this->count;
+
+ // Update timecode on the frame we're creating
+ mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) );
+
// optimization for subsequent iterations on single picture
- if ( this->image != NULL )
+ if ( this->image != NULL && image_idx == this->image_idx )
{
// Set width/height
mlt_properties_set_int( properties, "width", this->width );
mlt_frame_push_get_image( *frame, producer_get_image );
}
- else if ( strchr( this->filename, '%' ) != NULL )
- {
- // handle picture sequences
- char filename[1024];
- filename[1023] = 0;
- int current = this->counter;
- do
- {
- ++this->counter;
- snprintf( filename, 1023, this->filename, this->counter );
- pixbuf = gdk_pixbuf_new_from_file( filename, &error );
- // allow discontinuity in frame numbers up to 99
- error = NULL;
- } while ( pixbuf == NULL && ( this->counter - current ) < 100 );
- }
- else
+ else
{
- pixbuf = gdk_pixbuf_new_from_file( this->filename, &error );
+ free( this->image );
+ free( this->alpha );
+ this->image_idx = image_idx;
+ pixbuf = gdk_pixbuf_new_from_file( this->filenames[ image_idx ], &error );
}
// If we have a pixbuf
if ( pixbuf )
{
// Scale to adjust for sample aspect ratio
- if ( mlt_properties_get_int( properties, "video_stadnard" ) == mlt_video_standard_pal )
+ if ( mlt_properties_get_int( properties, "video_standard" ) == mlt_video_standard_pal )
{
GdkPixbuf *temp = pixbuf;
GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf,
mlt_properties_set_int( properties, "height", this->height );
// Pass alpha and image on properties with or without destructor
- if ( this->counter >= 0 )
- {
- // if picture sequence pass the image and alpha data with destructor
- mlt_properties_set_data( properties, "image", image, 0, free, NULL );
- mlt_properties_set_data( properties, "alpha", alpha, 0, free, NULL );
- }
- else
- {
- // if single picture, reference the image and alpha in the producer
- this->image = image;
- this->alpha = alpha;
+ this->image = image;
+ this->alpha = alpha;
- // pass the image and alpha data without destructor
- mlt_properties_set_data( properties, "image", image, 0, NULL, NULL );
- mlt_properties_set_data( properties, "alpha", alpha, 0, NULL, NULL );
- }
+ // pass the image and alpha data without destructor
+ mlt_properties_set_data( properties, "image", image, 0, NULL, NULL );
+ mlt_properties_set_data( properties, "alpha", alpha, 0, NULL, NULL );
// Set alpha call back
( *frame )->get_alpha_mask = producer_get_alpha_mask;
mlt_frame_push_get_image( *frame, producer_get_image );
}
- // Update timecode on the frame we're creating
- mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) );
-
// Calculate the next timecode
mlt_producer_prepare_next( producer );
static void producer_close( mlt_producer parent )
{
producer_pixbuf this = parent->child;
- if ( this->filename )
- free( this->filename );
if ( this->image )
free( this->image );
if ( this->alpha )
struct producer_pixbuf_s
{
struct mlt_producer_s parent;
- char *filename;
- int counter;
+
+ // File name list
+ char **filenames;
+ int count;
+ int image_idx;
+
int width;
int height;
uint8_t *image;
SDL_UnlockSurface( screen );
}
-void sdl_fill_audio( void *udata, Uint8 *stream, int len )
+void sdl_fill_audio( void *udata, uint8_t *stream, int len )
{
consumer_sdl this = udata;
mlt_service service = NULL;
mlt_consumer consumer = NULL;
mlt_multitrack multitrack = NULL;
- mlt_tractor tractor = NULL;
mlt_producer producer = NULL;
mlt_playlist playlist = NULL;
mlt_field field = NULL;
// Set up containers
playlist = mlt_playlist_init( );
- multitrack = mlt_multitrack_init( );
- tractor = mlt_tractor_init( );
- // Field must be connected on construction
- field = mlt_field_init( mlt_multitrack_service( multitrack ) );
+ // Construct the field
+ field = mlt_field_init( );
mlt_properties properties = mlt_field_properties( field );
mlt_properties_set_int( properties, "registered", 0 );
+ // Get the multitrack from the field
+ multitrack = mlt_field_multitrack( field );
+
// Parse the arguments
for ( i = 1; i < argc; i ++ )
{
consumer= mlt_factory_consumer( "sdl", NULL );
// Connect producer to playlist
- mlt_playlist_append( playlist, producer );
+ if ( producer != NULL )
+ mlt_playlist_append( playlist, producer );
// Connect multitrack to producer
mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist ), 0 );
- // Connect tractor to field
- mlt_tractor_connect( tractor, mlt_field_service( field ) );
-
// Connect consumer to tractor
- mlt_consumer_connect( consumer, mlt_tractor_service( tractor ) );
+ mlt_consumer_connect( consumer, mlt_field_service( field ) );
// Transport functionality
- transport( producer );
+ transport( mlt_multitrack_producer( multitrack ) );
// Close the services
mlt_consumer_close( consumer );
- mlt_tractor_close( tractor );
mlt_field_close( field );
- mlt_multitrack_close( multitrack );
mlt_producer_close( producer );
// Close the factory