2 * mlt_service.c -- interface for all service classes
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include "mlt_service.h"
23 #include "mlt_filter.h"
24 #include "mlt_frame.h"
32 The base service implements a null frame producing service - as such,
33 it is functional without extension and will produce test cards frames
34 and PAL sized audio frames.
36 PLEASE DO NOT CHANGE THIS BEHAVIOUR!!! OVERRIDE THE METHODS THAT
37 CONTROL THIS IN EXTENDING CLASSES.
40 /** Private service definition.
52 pthread_mutex_t mutex
;
59 static void mlt_service_disconnect( mlt_service
this );
60 static void mlt_service_connect( mlt_service
this, mlt_service that
);
61 static int service_get_frame( mlt_service
this, mlt_frame_ptr frame
, int index
);
62 static void mlt_service_property_changed( mlt_listener
, mlt_properties owner
, mlt_service
this, void **args
);
67 int mlt_service_init( mlt_service
this, void *child
)
71 // Initialise everything to NULL
72 memset( this, 0, sizeof( struct mlt_service_s
) );
77 // Generate local space
78 this->local
= calloc( sizeof( mlt_service_base
), 1 );
80 // Associate the methods
81 this->get_frame
= service_get_frame
;
83 // Initialise the properties
84 error
= mlt_properties_init( &this->parent
, this );
87 this->parent
.close
= ( mlt_destructor
)mlt_service_close
;
88 this->parent
.close_object
= this;
90 mlt_events_init( &this->parent
);
91 mlt_events_register( &this->parent
, "service-changed", NULL
);
92 mlt_events_register( &this->parent
, "property-changed", ( mlt_transmitter
)mlt_service_property_changed
);
93 pthread_mutex_init( &( ( mlt_service_base
* )this->local
)->mutex
, NULL
);
99 static void mlt_service_property_changed( mlt_listener listener
, mlt_properties owner
, mlt_service
this, void **args
)
101 if ( listener
!= NULL
)
102 listener( owner
, this, ( char * )args
[ 0 ] );
105 void mlt_service_lock( mlt_service
this )
108 pthread_mutex_lock( &( ( mlt_service_base
* )this->local
)->mutex
);
111 void mlt_service_unlock( mlt_service
this )
114 pthread_mutex_unlock( &( ( mlt_service_base
* )this->local
)->mutex
);
117 mlt_service_type
mlt_service_identify( mlt_service
this )
119 mlt_service_type type
= invalid_type
;
122 mlt_properties properties
= mlt_service_properties( this );
123 char *mlt_type
= mlt_properties_get( properties
, "mlt_type" );
124 char *resource
= mlt_properties_get( properties
, "resource" );
125 if ( mlt_type
== NULL
)
127 else if ( !strcmp( mlt_type
, "producer" ) )
128 type
= producer_type
;
129 else if ( !strcmp( mlt_type
, "mlt_producer" ) )
131 if ( resource
== NULL
|| !strcmp( resource
, "<producer>" ) )
132 type
= producer_type
;
133 else if ( !strcmp( resource
, "<playlist>" ) )
134 type
= playlist_type
;
135 else if ( !strcmp( resource
, "<tractor>" ) )
137 else if ( !strcmp( resource
, "<multitrack>" ) )
138 type
= multitrack_type
;
140 else if ( !strcmp( mlt_type
, "filter" ) )
142 else if ( !strcmp( mlt_type
, "transition" ) )
143 type
= transition_type
;
144 else if ( !strcmp( mlt_type
, "consumer" ) )
145 type
= consumer_type
;
152 /** Connect a producer service.
153 Returns: > 0 warning, == 0 success, < 0 serious error
154 1 = this service does not accept input
155 2 = the producer is invalid
156 3 = the producer is already registered with this consumer
159 int mlt_service_connect_producer( mlt_service
this, mlt_service producer
, int index
)
163 // Get the service base
164 mlt_service_base
*base
= this->local
;
166 // Check if the producer is already registered with this service
167 for ( i
= 0; i
< base
->count
; i
++ )
168 if ( base
->in
[ i
] == producer
)
172 if ( index
>= base
->size
)
174 int new_size
= base
->size
+ index
+ 10;
175 base
->in
= realloc( base
->in
, new_size
* sizeof( mlt_service
) );
176 if ( base
->in
!= NULL
)
178 for ( i
= base
->size
; i
< new_size
; i
++ )
179 base
->in
[ i
] = NULL
;
180 base
->size
= new_size
;
184 // If we have space, assign the input
185 if ( base
->in
!= NULL
&& index
>= 0 && index
< base
->size
)
187 // Get the current service
188 mlt_service current
= base
->in
[ index
];
190 // Increment the reference count on this producer
191 if ( producer
!= NULL
)
193 mlt_service_lock( producer
);
194 mlt_properties_inc_ref( mlt_service_properties( producer
) );
195 mlt_service_unlock( producer
);
198 // Now we disconnect the producer service from its consumer
199 mlt_service_disconnect( producer
);
201 // Add the service to index specified
202 base
->in
[ index
] = producer
;
204 // Determine the number of active tracks
205 if ( index
>= base
->count
)
206 base
->count
= index
+ 1;
208 // Now we connect the producer to its connected consumer
209 mlt_service_connect( producer
, this );
211 // Close the current service
212 mlt_service_close( current
);
214 // Inform caller that all went well
223 /** Disconnect this service from its consumer.
226 static void mlt_service_disconnect( mlt_service
this )
230 // Get the service base
231 mlt_service_base
*base
= this->local
;
238 /** Obtain the consumer this service is connected to.
241 mlt_service
mlt_service_consumer( mlt_service
this )
243 // Get the service base
244 mlt_service_base
*base
= this->local
;
246 // Return the connected consumer
250 /** Obtain the producer this service is connected to.
253 mlt_service
mlt_service_producer( mlt_service
this )
255 // Get the service base
256 mlt_service_base
*base
= this->local
;
258 // Return the connected producer
259 return base
->count
> 0 ? base
->in
[ base
->count
- 1 ] : NULL
;
262 /** Associate this service to the consumer.
265 static void mlt_service_connect( mlt_service
this, mlt_service that
)
269 // Get the service base
270 mlt_service_base
*base
= this->local
;
272 // There's a bit more required here...
277 /** Get the first connected producer service.
280 mlt_service
mlt_service_get_producer( mlt_service
this )
282 mlt_service producer
= NULL
;
284 // Get the service base
285 mlt_service_base
*base
= this->local
;
287 if ( base
->in
!= NULL
)
288 producer
= base
->in
[ 0 ];
293 /** Default implementation of get_frame.
296 static int service_get_frame( mlt_service
this, mlt_frame_ptr frame
, int index
)
298 mlt_service_base
*base
= this->local
;
299 if ( index
< base
->count
)
301 mlt_service producer
= base
->in
[ index
];
302 if ( producer
!= NULL
)
303 return mlt_service_get_frame( producer
, frame
, index
);
305 *frame
= mlt_frame_init( );
309 /** Return the properties object.
312 mlt_properties
mlt_service_properties( mlt_service self
)
314 return self
!= NULL ?
&self
->parent
: NULL
;
317 /** Recursively apply attached filters
320 void mlt_service_apply_filters( mlt_service
this, mlt_frame frame
, int index
)
323 mlt_properties frame_properties
= mlt_frame_properties( frame
);
324 mlt_properties service_properties
= mlt_service_properties( this );
325 mlt_service_base
*base
= this->local
;
326 mlt_position position
= mlt_frame_get_position( frame
);
327 mlt_position this_in
= mlt_properties_get_position( service_properties
, "in" );
328 mlt_position this_out
= mlt_properties_get_position( service_properties
, "out" );
330 if ( index
== 0 || mlt_properties_get_int( service_properties
, "_filter_private" ) == 0 )
332 // Process the frame with the attached filters
333 for ( i
= 0; i
< base
->filter_count
; i
++ )
335 if ( base
->filters
[ i
] != NULL
)
337 mlt_position in
= mlt_filter_get_in( base
->filters
[ i
] );
338 mlt_position out
= mlt_filter_get_out( base
->filters
[ i
] );
339 if ( ( in
== 0 && out
== 0 ) || ( position
>= in
&& ( position
<= out
|| out
== 0 ) ) )
341 mlt_properties_set_position( frame_properties
, "in", in
== 0 ? this_in
: in
);
342 mlt_properties_set_position( frame_properties
, "out", out
== 0 ? this_out
: out
);
343 mlt_filter_process( base
->filters
[ i
], frame
);
344 mlt_service_apply_filters( mlt_filter_service( base
->filters
[ i
] ), frame
, index
+ 1 );
354 int mlt_service_get_frame( mlt_service
this, mlt_frame_ptr frame
, int index
)
356 mlt_service_lock( this );
357 if ( this != NULL
&& this->get_frame
!= NULL
)
361 mlt_properties properties
= mlt_service_properties( this );
362 mlt_position in
= mlt_properties_get_position( properties
, "in" );
363 mlt_position out
= mlt_properties_get_position( properties
, "out" );
364 mlt_properties_inc_ref( properties
);
365 mlt_service_unlock( this );
366 result
= this->get_frame( this, frame
, index
);
369 properties
= mlt_frame_properties( *frame
);
370 if ( in
>=0 && out
> 0 )
372 mlt_properties_set_position( properties
, "in", in
);
373 mlt_properties_set_position( properties
, "out", out
);
375 mlt_service_apply_filters( this, *frame
, 1 );
376 sprintf( uniq
, "gf_%p", this );
377 if ( mlt_properties_get_data( properties
, uniq
, NULL
) != NULL
)
378 fprintf( stderr
, "%s is not unique in this frame\n", uniq
);
379 mlt_properties_set_data( properties
, uniq
, this, 0, ( mlt_destructor
)mlt_service_close
, NULL
);
383 fprintf( stderr
, "Ugh case\n" );
384 mlt_service_close( this );
388 mlt_service_unlock( this );
389 *frame
= mlt_frame_init( );
393 static void mlt_service_filter_changed( mlt_service owner
, mlt_service
this )
395 mlt_events_fire( mlt_service_properties( this ), "service-changed", NULL
);
401 int mlt_service_attach( mlt_service
this, mlt_filter filter
)
403 int error
= this == NULL
|| filter
== NULL
;
407 mlt_properties properties
= mlt_service_properties( this );
408 mlt_service_base
*base
= this->local
;
410 for ( i
= 0; error
== 0 && i
< base
->filter_count
; i
++ )
411 if ( base
->filters
[ i
] == filter
)
416 if ( base
->filter_count
== base
->filter_size
)
418 base
->filter_size
+= 10;
419 base
->filters
= realloc( base
->filters
, base
->filter_size
* sizeof( mlt_filter
) );
422 if ( base
->filters
!= NULL
)
424 mlt_properties props
= mlt_filter_properties( filter
);
425 mlt_properties_inc_ref( mlt_filter_properties( filter
) );
426 base
->filters
[ base
->filter_count
++ ] = filter
;
427 mlt_events_fire( properties
, "service-changed", NULL
);
428 mlt_events_listen( props
, this, "service-changed", ( mlt_listener
)mlt_service_filter_changed
);
429 mlt_events_listen( props
, this, "property-changed", ( mlt_listener
)mlt_service_filter_changed
);
443 int mlt_service_detach( mlt_service
this, mlt_filter filter
)
445 int error
= this == NULL
|| filter
== NULL
;
449 mlt_service_base
*base
= this->local
;
450 mlt_properties properties
= mlt_service_properties( this );
452 for ( i
= 0; i
< base
->filter_count
; i
++ )
453 if ( base
->filters
[ i
] == filter
)
456 if ( i
< base
->filter_count
)
458 base
->filters
[ i
] = NULL
;
459 for ( i
++ ; i
< base
->filter_count
; i
++ )
460 base
->filters
[ i
- 1 ] = base
->filters
[ i
];
461 base
->filter_count
--;
462 mlt_events_disconnect( mlt_filter_properties( filter
), this );
463 mlt_filter_close( filter
);
464 mlt_events_fire( properties
, "service-changed", NULL
);
470 /** Retrieve a filter.
473 mlt_filter
mlt_service_filter( mlt_service
this, int index
)
475 mlt_filter filter
= NULL
;
478 mlt_service_base
*base
= this->local
;
479 if ( index
>= 0 && index
< base
->filter_count
)
480 filter
= base
->filters
[ index
];
485 /** Close the service.
488 void mlt_service_close( mlt_service
this )
490 mlt_service_lock( this );
491 if ( this != NULL
&& mlt_properties_dec_ref( mlt_service_properties( this ) ) <= 0 )
493 mlt_service_unlock( this );
494 if ( this->close
!= NULL
)
496 this->close( this->close_object
);
500 mlt_service_base
*base
= this->local
;
502 int count
= base
->filter_count
;
503 mlt_events_block( mlt_service_properties( this ), this );
505 mlt_service_detach( this, base
->filters
[ 0 ] );
506 free( base
->filters
);
507 for ( i
= 0; i
< base
->count
; i
++ )
508 if ( base
->in
[ i
] != NULL
)
509 mlt_service_close( base
->in
[ i
] );
510 this->parent
.close
= NULL
;
512 pthread_mutex_destroy( &base
->mutex
);
514 mlt_properties_close( &this->parent
);
519 mlt_service_unlock( this );