3 * \brief interface definition for all service classes
6 * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7 * \author Charles Yates <charles.yates@pandora.be>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "mlt_service.h"
25 #include "mlt_filter.h"
26 #include "mlt_frame.h"
27 #include "mlt_cache.h"
28 #include "mlt_factory.h"
30 #include "mlt_producer.h"
40 The base service implements a null frame producing service - as such,
41 it is functional without extension and will produce test cards frames
42 and PAL sized audio frames.
44 PLEASE DO NOT CHANGE THIS BEHAVIOUR!!! OVERRIDE THE METHODS THAT
45 CONTROL THIS IN EXTENDING CLASSES.
48 /** \brief private service definition */
59 pthread_mutex_t mutex;
66 static void mlt_service_disconnect( mlt_service self );
67 static void mlt_service_connect( mlt_service self, mlt_service that );
68 static int service_get_frame( mlt_service self, mlt_frame_ptr frame, int index );
69 static void mlt_service_property_changed( mlt_listener, mlt_properties owner, mlt_service self, void **args );
71 /** Initialize a service.
73 * \public \memberof mlt_service_s
74 * \param self the service structure to initialize
75 * \param child pointer to the child object for the subclass
76 * \return true if there was an error
79 int mlt_service_init( mlt_service self, void *child )
83 // Initialise everything to NULL
84 memset( self, 0, sizeof( struct mlt_service_s ) );
89 // Generate local space
90 self->local = calloc( 1, sizeof( mlt_service_base ) );
92 // Associate the methods
93 self->get_frame = service_get_frame;
95 // Initialise the properties
96 error = mlt_properties_init( &self->parent, self );
99 self->parent.close = ( mlt_destructor )mlt_service_close;
100 self->parent.close_object = self;
102 mlt_events_init( &self->parent );
103 mlt_events_register( &self->parent, "service-changed", NULL );
104 mlt_events_register( &self->parent, "property-changed", ( mlt_transmitter )mlt_service_property_changed );
105 pthread_mutex_init( &( ( mlt_service_base * )self->local )->mutex, NULL );
111 /** The transmitter for property changes.
113 * Invokes the listener.
115 * \private \memberof mlt_service_s
116 * \param listener a function pointer that will be invoked
117 * \param owner a properties list that will be passed to \p listener
118 * \param self a service that will be passed to \p listener
119 * \param args an array of pointers - the first entry is passed as a string to \p listener
122 static void mlt_service_property_changed( mlt_listener listener, mlt_properties owner, mlt_service self, void **args )
124 if ( listener != NULL )
125 listener( owner, self, ( char * )args[ 0 ] );
128 /** Acquire a mutual exclusion lock on this service.
130 * \public \memberof mlt_service_s
131 * \param self the service to lock
134 #include <execinfo.h>
136 void mlt_service_lock( mlt_service self )
139 pthread_mutex_lock( &( ( mlt_service_base * )self->local )->mutex );
142 /** Release a mutual exclusion lock on this service.
144 * \public \memberof mlt_service_s
145 * \param self the service to unlock
148 void mlt_service_unlock( mlt_service self )
151 pthread_mutex_unlock( &( ( mlt_service_base * )self->local )->mutex );
154 /** Identify the subclass of the service.
156 * \public \memberof mlt_service_s
157 * \param self a service
158 * \return the subclass
161 mlt_service_type mlt_service_identify( mlt_service self )
163 mlt_service_type type = invalid_type;
166 mlt_properties properties = MLT_SERVICE_PROPERTIES( self );
167 char *mlt_type = mlt_properties_get( properties, "mlt_type" );
168 char *resource = mlt_properties_get( properties, "resource" );
169 if ( mlt_type == NULL )
171 else if (resource != NULL && !strcmp( resource, "<playlist>" ) )
172 type = playlist_type;
173 else if (resource != NULL && !strcmp( resource, "<tractor>" ) )
175 else if (resource != NULL && !strcmp( resource, "<multitrack>" ) )
176 type = multitrack_type;
177 else if ( !strcmp( mlt_type, "producer" ) )
178 type = producer_type;
179 else if ( !strcmp( mlt_type, "filter" ) )
181 else if ( !strcmp( mlt_type, "transition" ) )
182 type = transition_type;
183 else if ( !strcmp( mlt_type, "consumer" ) )
184 type = consumer_type;
191 /** Connect a producer to the service.
193 * \public \memberof mlt_service_s
194 * \param self a service
195 * \param producer a producer
196 * \param index which of potentially multiple producers to this service (0 based)
197 * \return > 0 warning, == 0 success, < 0 serious error,
198 * 1 = this service does not accept input,
199 * 2 = the producer is invalid,
200 * 3 = the producer is already registered with self consumer
203 int mlt_service_connect_producer( mlt_service self, mlt_service producer, int index )
207 // Get the service base
208 mlt_service_base *base = self->local;
210 // Special case 'track' index - only works for last filter(s) in a particular chain
211 // but allows a filter to apply to the output frame regardless of which track it comes from
215 // Check if the producer is already registered with this service
216 for ( i = 0; i < base->count; i ++ )
217 if ( base->in[ i ] == producer )
221 if ( index >= base->size )
223 int new_size = base->size + index + 10;
224 base->in = realloc( base->in, new_size * sizeof( mlt_service ) );
225 if ( base->in != NULL )
227 for ( i = base->size; i < new_size; i ++ )
228 base->in[ i ] = NULL;
229 base->size = new_size;
233 // If we have space, assign the input
234 if ( base->in != NULL && index >= 0 && index < base->size )
236 // Get the current service
237 mlt_service current = base->in[ index ];
239 // Increment the reference count on this producer
240 if ( producer != NULL )
241 mlt_properties_inc_ref( MLT_SERVICE_PROPERTIES( producer ) );
243 // Now we disconnect the producer service from its consumer
244 mlt_service_disconnect( producer );
246 // Add the service to index specified
247 base->in[ index ] = producer;
249 // Determine the number of active tracks
250 if ( index >= base->count )
251 base->count = index + 1;
253 // Now we connect the producer to its connected consumer
254 mlt_service_connect( producer, self );
256 // Close the current service
257 mlt_service_close( current );
259 // Inform caller that all went well
268 /** Disconnect a service from its consumer.
270 * \private \memberof mlt_service_s
271 * \param self a service
274 static void mlt_service_disconnect( mlt_service self )
278 // Get the service base
279 mlt_service_base *base = self->local;
286 /** Obtain the consumer a service is connected to.
288 * \public \memberof mlt_service_s
289 * \param self a service
290 * \return the consumer
293 mlt_service mlt_service_consumer( mlt_service self )
295 // Get the service base
296 mlt_service_base *base = self->local;
298 // Return the connected consumer
302 /** Obtain the producer a service is connected to.
304 * \public \memberof mlt_service_s
305 * \param self a service
306 * \return the last-most producer
309 mlt_service mlt_service_producer( mlt_service self )
311 // Get the service base
312 mlt_service_base *base = self->local;
314 // Return the connected producer
315 return base->count > 0 ? base->in[ base->count - 1 ] : NULL;
318 /** Associate a service to a consumer.
320 * Overwrites connection to any existing consumer.
321 * \private \memberof mlt_service_s
322 * \param self a service
323 * \param that a consumer
326 static void mlt_service_connect( mlt_service self, mlt_service that )
330 // Get the service base
331 mlt_service_base *base = self->local;
333 // There's a bit more required here...
338 /** Get the first connected producer.
340 * \public \memberof mlt_service_s
341 * \param self a service
342 * \return the first producer
345 mlt_service mlt_service_get_producer( mlt_service self )
347 mlt_service producer = NULL;
349 // Get the service base
350 mlt_service_base *base = self->local;
352 if ( base->in != NULL )
353 producer = base->in[ 0 ];
358 /** Default implementation of the get_frame virtual function.
360 * \private \memberof mlt_service_s
361 * \param self a service
362 * \param[out] frame a frame by reference
363 * \param index as determined by the producer
367 static int service_get_frame( mlt_service self, mlt_frame_ptr frame, int index )
369 mlt_service_base *base = self->local;
370 if ( index < base->count )
372 mlt_service producer = base->in[ index ];
373 if ( producer != NULL )
374 return mlt_service_get_frame( producer, frame, index );
376 *frame = mlt_frame_init( self );
380 /** Return the properties object.
382 * \public \memberof mlt_service_s
383 * \param self a service
384 * \return the properties
387 mlt_properties mlt_service_properties( mlt_service self )
389 return self != NULL ? &self->parent : NULL;
392 /** Recursively apply attached filters.
394 * \public \memberof mlt_service_s
395 * \param self a service
396 * \param frame a frame
397 * \param index used to track depth of recursion, top caller should supply 0
400 void mlt_service_apply_filters( mlt_service self, mlt_frame frame, int index )
403 mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
404 mlt_properties service_properties = MLT_SERVICE_PROPERTIES( self );
405 mlt_service_base *base = self->local;
406 mlt_position position = mlt_frame_get_position( frame );
407 mlt_position self_in = mlt_properties_get_position( service_properties, "in" );
408 mlt_position self_out = mlt_properties_get_position( service_properties, "out" );
410 if ( index == 0 || mlt_properties_get_int( service_properties, "_filter_private" ) == 0 )
412 // Process the frame with the attached filters
413 for ( i = 0; i < base->filter_count; i ++ )
415 if ( base->filters[ i ] != NULL )
417 mlt_position in = mlt_filter_get_in( base->filters[ i ] );
418 mlt_position out = mlt_filter_get_out( base->filters[ i ] );
419 int disable = mlt_properties_get_int( MLT_FILTER_PROPERTIES( base->filters[ i ] ), "disable" );
420 if ( !disable && ( ( in == 0 && out == 0 ) || ( position >= in && ( position <= out || out == 0 ) ) ) )
422 mlt_properties_set_position( frame_properties, "in", in == 0 ? self_in : in );
423 mlt_properties_set_position( frame_properties, "out", out == 0 ? self_out : out );
424 mlt_filter_process( base->filters[ i ], frame );
425 mlt_service_apply_filters( MLT_FILTER_SERVICE( base->filters[ i ] ), frame, index + 1 );
434 * \public \memberof mlt_service_s
435 * \param self a service
436 * \param[out] frame a frame by reference
437 * \param index as determined by the producer
438 * \return true if there was an error
441 int mlt_service_get_frame( mlt_service self, mlt_frame_ptr frame, int index )
446 mlt_service_lock( self );
448 // Ensure that the frame is NULL
451 // Only process if we have a valid service
452 if ( self != NULL && self->get_frame != NULL )
454 mlt_properties properties = MLT_SERVICE_PROPERTIES( self );
455 mlt_position in = mlt_properties_get_position( properties, "in" );
456 mlt_position out = mlt_properties_get_position( properties, "out" );
457 mlt_position position = mlt_service_identify( self ) == producer_type ? mlt_producer_position( MLT_PRODUCER( self ) ) : -1;
459 result = self->get_frame( self, frame, index );
463 mlt_properties_inc_ref( properties );
464 properties = MLT_FRAME_PROPERTIES( *frame );
466 if ( in >=0 && out > 0 )
468 mlt_properties_set_position( properties, "in", in );
469 mlt_properties_set_position( properties, "out", out );
471 mlt_service_apply_filters( self, *frame, 1 );
472 mlt_deque_push_back( MLT_FRAME_SERVICE_STACK( *frame ), self );
474 if ( mlt_service_identify( self ) == producer_type &&
475 mlt_properties_get_int( MLT_SERVICE_PROPERTIES( self ), "_need_previous_next" ) )
477 // Save the new position from self->get_frame
478 mlt_position new_position = mlt_producer_position( MLT_PRODUCER( self ) );
480 // Get the preceding frame, unfiltered
481 mlt_frame previous_frame;
482 mlt_producer_seek( MLT_PRODUCER(self), position - 1 );
483 result = self->get_frame( self, &previous_frame, index );
485 mlt_properties_set_data( properties, "previous frame",
486 previous_frame, 0, ( mlt_destructor ) mlt_frame_close, NULL );
488 // Get the following frame, unfiltered
489 mlt_frame next_frame;
490 mlt_producer_seek( MLT_PRODUCER(self), position + 1 );
491 result = self->get_frame( self, &next_frame, index );
494 mlt_properties_set_data( properties, "next frame",
495 next_frame, 0, ( mlt_destructor ) mlt_frame_close, NULL );
498 // Restore the new position
499 mlt_producer_seek( MLT_PRODUCER(self), new_position );
504 // Make sure we return a frame
505 if ( *frame == NULL )
506 *frame = mlt_frame_init( self );
508 // Unlock the service
509 mlt_service_unlock( self );
514 /** The service-changed event handler.
516 * \private \memberof mlt_service_s
517 * \param owner ignored
518 * \param self the service on which the "service-changed" event is fired
521 static void mlt_service_filter_changed( mlt_service owner, mlt_service self )
523 mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "service-changed", NULL );
526 /** The property-changed event handler.
528 * \private \memberof mlt_service_s
529 * \param owner ignored
530 * \param self the service on which the "property-changed" event is fired
531 * \param name the name of the property that changed
534 static void mlt_service_filter_property_changed( mlt_service owner, mlt_service self, char *name )
536 mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "property-changed", name, NULL );
541 * \public \memberof mlt_service_s
542 * \param self a service
543 * \param filter the filter to attach
544 * \return true if there was an error
547 int mlt_service_attach( mlt_service self, mlt_filter filter )
553 printf("ATTACHING %p -> %p\n", self, filter);
554 for (i = 0; i < 1024; ++i) buffer[i] = 0;
555 num = backtrace(buffer, 1024);
556 sym = backtrace_symbols(buffer, num);
557 for (i = 0; i < num; ++i) {
558 //printf("%3d: %s\n", sym[i]);
562 int error = self == NULL || filter == NULL;
566 mlt_properties properties = MLT_SERVICE_PROPERTIES( self );
567 mlt_service_base *base = self->local;
569 for ( i = 0; error == 0 && i < base->filter_count; i ++ )
570 if ( base->filters[ i ] == filter )
575 if ( base->filter_count == base->filter_size )
577 base->filter_size += 10;
578 base->filters = realloc( base->filters, base->filter_size * sizeof( mlt_filter ) );
581 if ( base->filters != NULL )
583 mlt_properties props = MLT_FILTER_PROPERTIES( filter );
584 mlt_properties_inc_ref( MLT_FILTER_PROPERTIES( filter ) );
585 base->filters[ base->filter_count ++ ] = filter;
586 mlt_properties_set_data( props, "service", self, 0, NULL, NULL );
587 mlt_events_fire( properties, "service-changed", NULL );
588 mlt_events_fire( props, "service-changed", NULL );
589 mlt_service cp = mlt_properties_get_data( properties, "_cut_parent", NULL );
591 mlt_events_fire( MLT_SERVICE_PROPERTIES(cp), "service-changed", NULL );
592 mlt_events_listen( props, self, "service-changed", ( mlt_listener )mlt_service_filter_changed );
593 mlt_events_listen( props, self, "property-changed", ( mlt_listener )mlt_service_filter_property_changed );
606 * \public \memberof mlt_service_s
607 * \param self a service
608 * \param filter the filter to detach
609 * \return true if there was an error
612 int mlt_service_detach( mlt_service self, mlt_filter filter )
614 int error = self == NULL || filter == NULL;
618 mlt_service_base *base = self->local;
619 mlt_properties properties = MLT_SERVICE_PROPERTIES( self );
621 for ( i = 0; i < base->filter_count; i ++ )
622 if ( base->filters[ i ] == filter )
625 if ( i < base->filter_count )
627 base->filters[ i ] = NULL;
628 for ( i ++ ; i < base->filter_count; i ++ )
629 base->filters[ i - 1 ] = base->filters[ i ];
630 base->filter_count --;
631 mlt_events_disconnect( MLT_FILTER_PROPERTIES( filter ), self );
632 mlt_filter_close( filter );
633 mlt_events_fire( properties, "service-changed", NULL );
639 /** Get the number of filters attached.
641 * \public \memberof mlt_service_s
642 * \param self a service
643 * \return the number of attached filters or -1 if there was an error
646 int mlt_service_filter_count( mlt_service self )
651 mlt_service_base *base = self->local;
652 result = base->filter_count;
657 /** Reorder the attached filters.
659 * \public \memberof mlt_service_s
660 * \param self a service
661 * \param from the current index value of the filter to move
662 * \param to the new index value for the filter specified in \p from
663 * \return true if there was an error
666 int mlt_service_move_filter( mlt_service self, int from, int to )
671 mlt_service_base *base = self->local;
672 if ( from < 0 ) from = 0;
673 if ( from >= base->filter_count ) from = base->filter_count - 1;
674 if ( to < 0 ) to = 0;
675 if ( to >= base->filter_count ) to = base->filter_count - 1;
676 if ( from != to && base->filter_count > 1 )
678 mlt_filter filter = base->filters[from];
682 for ( i = from; i > to; i-- )
683 base->filters[i] = base->filters[i - 1];
687 for ( i = from; i < to; i++ )
688 base->filters[i] = base->filters[i + 1];
690 base->filters[to] = filter;
691 mlt_events_fire( MLT_SERVICE_PROPERTIES(self), "service-changed", NULL );
698 /** Retrieve an attached filter.
700 * \public \memberof mlt_service_s
701 * \param self a service
702 * \param index which one of potentially multiple filters
703 * \return the filter or null if there was an error
706 mlt_filter mlt_service_filter( mlt_service self, int index )
708 mlt_filter filter = NULL;
711 mlt_service_base *base = self->local;
712 if ( index >= 0 && index < base->filter_count )
713 filter = base->filters[ index ];
718 /** Retrieve the profile.
720 * \public \memberof mlt_service_s
721 * \param self a service
722 * \return the profile
725 mlt_profile mlt_service_profile( mlt_service self )
727 return self? mlt_properties_get_data( MLT_SERVICE_PROPERTIES( self ), "_profile", NULL ) : NULL;
730 /** Set the profile for a service.
732 * \public \memberof mlt_service_s
733 * \param self a service
734 * \param profile the profile to set onto the service
737 void mlt_service_set_profile( mlt_service self, mlt_profile profile )
739 mlt_properties_set_data( MLT_SERVICE_PROPERTIES( self ), "_profile", profile, 0, NULL, NULL );
742 /** Destroy a service.
744 * \public \memberof mlt_service_s
745 * \param self the service to destroy
748 void mlt_service_close( mlt_service self )
750 if ( self != NULL && mlt_properties_dec_ref( MLT_SERVICE_PROPERTIES( self ) ) <= 0 )
752 if ( self->close != NULL )
754 self->close( self->close_object );
758 mlt_service_base *base = self->local;
760 int count = base->filter_count;
761 mlt_events_block( MLT_SERVICE_PROPERTIES( self ), self );
763 mlt_service_detach( self, base->filters[ 0 ] );
764 free( base->filters );
765 for ( i = 0; i < base->count; i ++ )
766 if ( base->in[ i ] != NULL )
767 mlt_service_close( base->in[ i ] );
768 self->parent.close = NULL;
770 pthread_mutex_destroy( &base->mutex );
772 mlt_properties_close( &self->parent );
777 /** Release a service's cache items.
779 * \private \memberof mlt_service_s
780 * \param self a service
783 void mlt_service_cache_purge( mlt_service self )
785 mlt_properties caches = mlt_properties_get_data( mlt_global_properties(), "caches", NULL );
789 int i = mlt_properties_count( caches );
792 mlt_cache_purge( mlt_properties_get_data_at( caches, i, NULL ), self );
793 mlt_properties_set_data( mlt_global_properties(), mlt_properties_get_name( caches, i ), NULL, 0, NULL, NULL );
798 /** Lookup the cache object for a service.
800 * \private \memberof mlt_service_s
801 * \param self a service
802 * \param name a name for the object
806 static mlt_cache get_cache( mlt_service self, const char *name )
808 mlt_cache result = NULL;
809 mlt_properties caches = mlt_properties_get_data( mlt_global_properties(), "caches", NULL );
813 caches = mlt_properties_new();
814 mlt_properties_set_data( mlt_global_properties(), "caches", caches, 0, ( mlt_destructor )mlt_properties_close, NULL );
818 result = mlt_properties_get_data( caches, name, NULL );
821 result = mlt_cache_init();
822 mlt_properties_set_data( caches, name, result, 0, ( mlt_destructor )mlt_cache_close, NULL );
829 /** Put an object into a service's cache.
831 * \public \memberof mlt_service_s
832 * \param self a service
833 * \param name a name for the object that is unique to the service class, but not to the instance
834 * \param data an opaque pointer to the object to put into the cache
835 * \param size the number of bytes pointed to by data
836 * \param destructor a function that releases the data
839 void mlt_service_cache_put( mlt_service self, const char *name, void* data, int size, mlt_destructor destructor )
841 mlt_log( self, MLT_LOG_DEBUG, "%s: name %s object %p data %p\n", __FUNCTION__, name, self, data );
842 mlt_cache cache = get_cache( self, name );
845 mlt_cache_put( cache, self, data, size, destructor );
848 /** Get an object from a service's cache.
850 * \public \memberof mlt_service_s
851 * \param self a service
852 * \param name a name for the object that is unique to the service class, but not to the instance
853 * \return a cache item or NULL if an object is not found
854 * \see mlt_cache_item_data
857 mlt_cache_item mlt_service_cache_get( mlt_service self, const char *name )
859 mlt_log( self, MLT_LOG_DEBUG, "%s: name %s object %p\n", __FUNCTION__, name, self );
860 mlt_cache_item result = NULL;
861 mlt_cache cache = get_cache( self, name );
864 result = mlt_cache_get( cache, self );
869 /** Set the number of items to cache for the named cache.
871 * \public \memberof mlt_service_s
872 * \param self a service
873 * \param name a name for the object that is unique to the service class, but not to the instance
874 * \param size the number of items to cache
877 void mlt_service_cache_set_size( mlt_service self, const char *name, int size )
879 mlt_cache cache = get_cache( self, name );
881 mlt_cache_set_size( cache, size );
884 /** Get the current maximum size of the named cache.
886 * \public \memberof mlt_service_s
887 * \param self a service
888 * \param name a name for the object that is unique to the service class, but not to the instance
889 * \return the current maximum number of items to cache or zero if there is an error
892 int mlt_service_cache_get_size( mlt_service self, const char *name )
894 mlt_cache cache = get_cache( self, name );
896 return mlt_cache_get_size( cache );