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 ( resource
== NULL
|| !strcmp( resource
, "<producer>" ) )
128 type
= producer_type
;
129 else if ( !strcmp( resource
, "<playlist>" ) )
130 type
= playlist_type
;
131 else if ( !strcmp( resource
, "<tractor>" ) )
133 else if ( !strcmp( resource
, "<multitrack>" ) )
134 type
= multitrack_type
;
135 else if ( !strcmp( mlt_type
, "producer" ) )
136 type
= producer_type
;
137 else if ( !strcmp( mlt_type
, "filter" ) )
139 else if ( !strcmp( mlt_type
, "transition" ) )
140 type
= transition_type
;
141 else if ( !strcmp( mlt_type
, "consumer" ) )
142 type
= consumer_type
;
149 /** Connect a producer service.
150 Returns: > 0 warning, == 0 success, < 0 serious error
151 1 = this service does not accept input
152 2 = the producer is invalid
153 3 = the producer is already registered with this consumer
156 int mlt_service_connect_producer( mlt_service
this, mlt_service producer
, int index
)
160 // Get the service base
161 mlt_service_base
*base
= this->local
;
163 // Check if the producer is already registered with this service
164 for ( i
= 0; i
< base
->count
; i
++ )
165 if ( base
->in
[ i
] == producer
)
169 if ( index
>= base
->size
)
171 int new_size
= base
->size
+ index
+ 10;
172 base
->in
= realloc( base
->in
, new_size
* sizeof( mlt_service
) );
173 if ( base
->in
!= NULL
)
175 for ( i
= base
->size
; i
< new_size
; i
++ )
176 base
->in
[ i
] = NULL
;
177 base
->size
= new_size
;
181 // If we have space, assign the input
182 if ( base
->in
!= NULL
&& index
>= 0 && index
< base
->size
)
184 // Get the current service
185 mlt_service current
= base
->in
[ index
];
187 // Increment the reference count on this producer
188 if ( producer
!= NULL
)
190 mlt_service_lock( producer
);
191 mlt_properties_inc_ref( MLT_SERVICE_PROPERTIES( producer
) );
192 mlt_service_unlock( producer
);
195 // Now we disconnect the producer service from its consumer
196 mlt_service_disconnect( producer
);
198 // Add the service to index specified
199 base
->in
[ index
] = producer
;
201 // Determine the number of active tracks
202 if ( index
>= base
->count
)
203 base
->count
= index
+ 1;
205 // Now we connect the producer to its connected consumer
206 mlt_service_connect( producer
, this );
208 // Close the current service
209 mlt_service_close( current
);
211 // Inform caller that all went well
220 /** Disconnect this service from its consumer.
223 static void mlt_service_disconnect( mlt_service
this )
227 // Get the service base
228 mlt_service_base
*base
= this->local
;
235 /** Obtain the consumer this service is connected to.
238 mlt_service
mlt_service_consumer( mlt_service
this )
240 // Get the service base
241 mlt_service_base
*base
= this->local
;
243 // Return the connected consumer
247 /** Obtain the producer this service is connected to.
250 mlt_service
mlt_service_producer( mlt_service
this )
252 // Get the service base
253 mlt_service_base
*base
= this->local
;
255 // Return the connected producer
256 return base
->count
> 0 ? base
->in
[ base
->count
- 1 ] : NULL
;
259 /** Associate this service to the consumer.
262 static void mlt_service_connect( mlt_service
this, mlt_service that
)
266 // Get the service base
267 mlt_service_base
*base
= this->local
;
269 // There's a bit more required here...
274 /** Get the first connected producer service.
277 mlt_service
mlt_service_get_producer( mlt_service
this )
279 mlt_service producer
= NULL
;
281 // Get the service base
282 mlt_service_base
*base
= this->local
;
284 if ( base
->in
!= NULL
)
285 producer
= base
->in
[ 0 ];
290 /** Default implementation of get_frame.
293 static int service_get_frame( mlt_service
this, mlt_frame_ptr frame
, int index
)
295 mlt_service_base
*base
= this->local
;
296 if ( index
< base
->count
)
298 mlt_service producer
= base
->in
[ index
];
299 if ( producer
!= NULL
)
300 return mlt_service_get_frame( producer
, frame
, index
);
302 *frame
= mlt_frame_init( );
306 /** Return the properties object.
309 mlt_properties
mlt_service_properties( mlt_service self
)
311 return self
!= NULL ?
&self
->parent
: NULL
;
314 /** Recursively apply attached filters
317 void mlt_service_apply_filters( mlt_service
this, mlt_frame frame
, int index
)
320 mlt_properties frame_properties
= MLT_FRAME_PROPERTIES( frame
);
321 mlt_properties service_properties
= MLT_SERVICE_PROPERTIES( this );
322 mlt_service_base
*base
= this->local
;
323 mlt_position position
= mlt_frame_get_position( frame
);
324 mlt_position this_in
= mlt_properties_get_position( service_properties
, "in" );
325 mlt_position this_out
= mlt_properties_get_position( service_properties
, "out" );
327 if ( index
== 0 || mlt_properties_get_int( service_properties
, "_filter_private" ) == 0 )
329 // Process the frame with the attached filters
330 for ( i
= 0; i
< base
->filter_count
; i
++ )
332 if ( base
->filters
[ i
] != NULL
)
334 mlt_position in
= mlt_filter_get_in( base
->filters
[ i
] );
335 mlt_position out
= mlt_filter_get_out( base
->filters
[ i
] );
336 if ( ( in
== 0 && out
== 0 ) || ( position
>= in
&& ( position
<= out
|| out
== 0 ) ) )
338 mlt_properties_set_position( frame_properties
, "in", in
== 0 ? this_in
: in
);
339 mlt_properties_set_position( frame_properties
, "out", out
== 0 ? this_out
: out
);
340 mlt_filter_process( base
->filters
[ i
], frame
);
341 mlt_service_apply_filters( MLT_FILTER_SERVICE( base
->filters
[ i
] ), frame
, index
+ 1 );
351 int mlt_service_get_frame( mlt_service
this, mlt_frame_ptr frame
, int index
)
353 mlt_service_lock( this );
354 if ( this != NULL
&& this->get_frame
!= NULL
)
357 mlt_properties properties
= MLT_SERVICE_PROPERTIES( this );
358 mlt_position in
= mlt_properties_get_position( properties
, "in" );
359 mlt_position out
= mlt_properties_get_position( properties
, "out" );
360 mlt_properties_inc_ref( properties
);
361 result
= this->get_frame( this, frame
, index
);
364 properties
= MLT_FRAME_PROPERTIES( *frame
);
365 if ( in
>=0 && out
> 0 )
367 mlt_properties_set_position( properties
, "in", in
);
368 mlt_properties_set_position( properties
, "out", out
);
370 mlt_service_apply_filters( this, *frame
, 1 );
371 mlt_deque_push_back( MLT_FRAME_SERVICE_STACK( *frame
), this );
372 mlt_service_unlock( this );
376 mlt_service_unlock( this );
377 mlt_service_close( this );
381 mlt_service_unlock( this );
382 *frame
= mlt_frame_init( );
386 static void mlt_service_filter_changed( mlt_service owner
, mlt_service
this )
388 mlt_events_fire( MLT_SERVICE_PROPERTIES( this ), "service-changed", NULL
);
394 int mlt_service_attach( mlt_service
this, mlt_filter filter
)
396 int error
= this == NULL
|| filter
== NULL
;
400 mlt_properties properties
= MLT_SERVICE_PROPERTIES( this );
401 mlt_service_base
*base
= this->local
;
403 for ( i
= 0; error
== 0 && i
< base
->filter_count
; i
++ )
404 if ( base
->filters
[ i
] == filter
)
409 if ( base
->filter_count
== base
->filter_size
)
411 base
->filter_size
+= 10;
412 base
->filters
= realloc( base
->filters
, base
->filter_size
* sizeof( mlt_filter
) );
415 if ( base
->filters
!= NULL
)
417 mlt_properties props
= MLT_FILTER_PROPERTIES( filter
);
418 mlt_properties_inc_ref( MLT_FILTER_PROPERTIES( filter
) );
419 base
->filters
[ base
->filter_count
++ ] = filter
;
420 mlt_events_fire( properties
, "service-changed", NULL
);
421 mlt_events_listen( props
, this, "service-changed", ( mlt_listener
)mlt_service_filter_changed
);
422 mlt_events_listen( props
, this, "property-changed", ( mlt_listener
)mlt_service_filter_changed
);
436 int mlt_service_detach( mlt_service
this, mlt_filter filter
)
438 int error
= this == NULL
|| filter
== NULL
;
442 mlt_service_base
*base
= this->local
;
443 mlt_properties properties
= MLT_SERVICE_PROPERTIES( this );
445 for ( i
= 0; i
< base
->filter_count
; i
++ )
446 if ( base
->filters
[ i
] == filter
)
449 if ( i
< base
->filter_count
)
451 base
->filters
[ i
] = NULL
;
452 for ( i
++ ; i
< base
->filter_count
; i
++ )
453 base
->filters
[ i
- 1 ] = base
->filters
[ i
];
454 base
->filter_count
--;
455 mlt_events_disconnect( MLT_FILTER_PROPERTIES( filter
), this );
456 mlt_filter_close( filter
);
457 mlt_events_fire( properties
, "service-changed", NULL
);
463 /** Retrieve a filter.
466 mlt_filter
mlt_service_filter( mlt_service
this, int index
)
468 mlt_filter filter
= NULL
;
471 mlt_service_base
*base
= this->local
;
472 if ( index
>= 0 && index
< base
->filter_count
)
473 filter
= base
->filters
[ index
];
478 /** Close the service.
481 void mlt_service_close( mlt_service
this )
483 mlt_service_lock( this );
484 if ( this != NULL
&& mlt_properties_dec_ref( MLT_SERVICE_PROPERTIES( this ) ) <= 0 )
486 mlt_service_unlock( this );
487 if ( this->close
!= NULL
)
489 this->close( this->close_object
);
493 mlt_service_base
*base
= this->local
;
495 int count
= base
->filter_count
;
496 mlt_events_block( MLT_SERVICE_PROPERTIES( this ), this );
498 mlt_service_detach( this, base
->filters
[ 0 ] );
499 free( base
->filters
);
500 for ( i
= 0; i
< base
->count
; i
++ )
501 if ( base
->in
[ i
] != NULL
)
502 mlt_service_close( base
->in
[ i
] );
503 this->parent
.close
= NULL
;
505 pthread_mutex_destroy( &base
->mutex
);
507 mlt_properties_close( &this->parent
);
512 mlt_service_unlock( this );