2 * mlt_producer.c -- abstraction for all producer services
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_producer.h"
23 #include "mlt_factory.h"
24 #include "mlt_frame.h"
30 /** Forward references.
33 static int producer_get_frame( mlt_service
this, mlt_frame_ptr frame
, int index
);
34 static void mlt_producer_property_changed( mlt_service owner
, mlt_producer
this, char *name
);
39 int mlt_producer_init( mlt_producer
this, void *child
)
41 // Check that we haven't received NULL
42 int error
= this == NULL
;
44 // Continue if no error
47 // Initialise the producer
48 memset( this, 0, sizeof( struct mlt_producer_s
) );
50 // Associate with the child
53 // Initialise the service
54 if ( mlt_service_init( &this->parent
, this ) == 0 )
56 // Get the normalisation preference
57 char *normalisation
= mlt_environment( "MLT_NORMALISATION" );
59 // The parent is the service
60 mlt_service parent
= &this->parent
;
62 // Define the parent close
63 parent
->close
= ( mlt_destructor
)mlt_producer_close
;
64 parent
->close_object
= this;
66 // For convenience, we'll assume the close_object is this
67 this->close_object
= this;
69 // Get the properties of the parent
70 mlt_properties properties
= mlt_service_properties( parent
);
72 // Set the default properties
73 mlt_properties_set( properties
, "mlt_type", "mlt_producer" );
74 mlt_properties_set_position( properties
, "_position", 0.0 );
75 mlt_properties_set_double( properties
, "_frame", 0 );
76 if ( normalisation
== NULL
|| strcmp( normalisation
, "NTSC" ) )
78 mlt_properties_set_double( properties
, "fps", 25.0 );
79 mlt_properties_set_double( properties
, "aspect_ratio", 72.0 / 79.0 );
83 mlt_properties_set_double( properties
, "fps", 30000.0 / 1001.0 );
84 mlt_properties_set_double( properties
, "aspect_ratio", 128.0 / 117.0 );
86 mlt_properties_set_double( properties
, "_speed", 1.0 );
87 mlt_properties_set_position( properties
, "in", 0 );
88 mlt_properties_set_position( properties
, "out", 14999 );
89 mlt_properties_set_position( properties
, "length", 15000 );
90 mlt_properties_set( properties
, "eof", "pause" );
91 mlt_properties_set( properties
, "resource", "<producer>" );
93 // Override service get_frame
94 parent
->get_frame
= producer_get_frame
;
96 mlt_events_listen( properties
, this, "property-changed", ( mlt_listener
)mlt_producer_property_changed
);
97 mlt_events_register( properties
, "producer-changed", NULL
);
104 /** Listener for property changes.
107 static void mlt_producer_property_changed( mlt_service owner
, mlt_producer
this, char *name
)
109 if ( !strcmp( name
, "in" ) || !strcmp( name
, "out" ) || !strcmp( name
, "length" ) )
110 mlt_events_fire( mlt_producer_properties( this ), "producer-changed", NULL
);
113 /** Create a new producer.
116 mlt_producer
mlt_producer_new( )
118 mlt_producer
this = malloc( sizeof( struct mlt_producer_s
) );
119 mlt_producer_init( this, NULL
);
123 /** Get the parent service object.
126 mlt_service
mlt_producer_service( mlt_producer
this )
128 return this != NULL ?
&this->parent
: NULL
;
131 /** Get the producer properties.
134 mlt_properties
mlt_producer_properties( mlt_producer
this )
136 return mlt_service_properties( &this->parent
);
139 /** Seek to a specified position.
142 int mlt_producer_seek( mlt_producer
this, mlt_position position
)
144 // Determine eof handling
145 char *eof
= mlt_properties_get( mlt_producer_properties( this ), "eof" );
146 int use_points
= 1 - mlt_properties_get_int( mlt_producer_properties( this ), "ignore_points" );
153 else if ( use_points
&& !strcmp( eof
, "pause" ) && position
>= mlt_producer_get_playtime( this ) )
155 mlt_producer_set_speed( this, 0 );
156 position
= mlt_producer_get_playtime( this ) - 1;
158 else if ( use_points
&& !strcmp( eof
, "loop" ) && position
>= mlt_producer_get_playtime( this ) )
160 position
= position
% mlt_producer_get_playtime( this );
164 mlt_properties_set_position( mlt_producer_properties( this ), "_position", position
);
166 // Calculate the absolute frame
167 mlt_properties_set_position( mlt_producer_properties( this ), "_frame", use_points
* mlt_producer_get_in( this ) + position
);
172 /** Get the current position (relative to in point).
175 mlt_position
mlt_producer_position( mlt_producer
this )
177 return mlt_properties_get_position( mlt_producer_properties( this ), "_position" );
180 /** Get the current position (relative to start of producer).
183 mlt_position
mlt_producer_frame( mlt_producer
this )
185 return mlt_properties_get_position( mlt_producer_properties( this ), "_frame" );
188 /** Set the playing speed.
191 int mlt_producer_set_speed( mlt_producer
this, double speed
)
193 return mlt_properties_set_double( mlt_producer_properties( this ), "_speed", speed
);
196 /** Get the playing speed.
199 double mlt_producer_get_speed( mlt_producer
this )
201 return mlt_properties_get_double( mlt_producer_properties( this ), "_speed" );
204 /** Get the frames per second.
207 double mlt_producer_get_fps( mlt_producer
this )
209 return mlt_properties_get_double( mlt_producer_properties( this ), "fps" );
212 /** Set the in and out points.
215 int mlt_producer_set_in_and_out( mlt_producer
this, mlt_position in
, mlt_position out
)
217 mlt_properties properties
= mlt_producer_properties( this );
219 // Correct ins and outs if necessary
222 else if ( in
> mlt_producer_get_length( this ) )
223 in
= mlt_producer_get_length( this );
227 else if ( out
> mlt_producer_get_length( this ) )
228 out
= mlt_producer_get_length( this );
230 // Swap ins and outs if wrong
239 mlt_events_block( properties
, properties
);
240 mlt_properties_set_position( properties
, "in", in
);
241 mlt_properties_set_position( properties
, "out", out
);
242 mlt_events_unblock( properties
, properties
);
243 mlt_events_fire( properties
, "producer-changed", NULL
);
248 /** Get the in point.
251 mlt_position
mlt_producer_get_in( mlt_producer
this )
253 return mlt_properties_get_position( mlt_producer_properties( this ), "in" );
256 /** Get the out point.
259 mlt_position
mlt_producer_get_out( mlt_producer
this )
261 return mlt_properties_get_position( mlt_producer_properties( this ), "out" );
264 /** Get the total play time.
267 mlt_position
mlt_producer_get_playtime( mlt_producer
this )
269 return mlt_producer_get_out( this ) - mlt_producer_get_in( this ) + 1;
272 /** Get the total length of the producer.
275 mlt_position
mlt_producer_get_length( mlt_producer
this )
277 return mlt_properties_get_position( mlt_producer_properties( this ), "length" );
280 /** Prepare for next frame.
283 void mlt_producer_prepare_next( mlt_producer
this )
285 mlt_producer_seek( this, mlt_producer_position( this ) + mlt_producer_get_speed( this ) );
291 static int producer_get_frame( mlt_service service
, mlt_frame_ptr frame
, int index
)
294 mlt_producer
this = service
->child
;
296 // Determine eof handling
297 char *eof
= mlt_properties_get( mlt_producer_properties( this ), "eof" );
299 // A properly instatiated producer will have a get_frame method...
300 if ( this->get_frame
== NULL
|| ( !strcmp( eof
, "continue" ) && mlt_producer_position( this ) > mlt_producer_get_out( this ) ) )
302 // Generate a test frame
303 *frame
= mlt_frame_init( );
306 result
= mlt_frame_set_position( *frame
, mlt_producer_position( this ) );
308 // Mark as a test card
309 mlt_properties_set_int( mlt_frame_properties( *frame
), "test_image", 1 );
310 mlt_properties_set_int( mlt_frame_properties( *frame
), "test_audio", 1 );
312 // Calculate the next position
313 mlt_producer_prepare_next( this );
317 mlt_properties properties
= mlt_producer_properties( this );
318 mlt_filter
*filters
= mlt_properties_get_data( properties
, "_filters", NULL
);
319 int count
= mlt_properties_get_int( properties
, "_filter_count" );
322 // Get the frame from the implementation
323 result
= this->get_frame( this, frame
, index
);
325 // Process the frame with the attached filters
326 for ( i
= 0; i
< count
; i
++ )
327 if ( filters
[ i
] != NULL
)
328 mlt_filter_process( filters
[ i
], *frame
);
331 // Copy the fps and speed of the producer onto the frame
332 mlt_properties properties
= mlt_frame_properties( *frame
);
333 mlt_properties_set_double( properties
, "fps", mlt_producer_get_fps( this ) );
334 double speed
= mlt_producer_get_speed( this );
335 mlt_properties_set_double( properties
, "_speed", speed
);
336 mlt_properties_set_int( properties
, "test_audio", mlt_frame_is_test_audio( *frame
) );
337 mlt_properties_set_int( properties
, "test_image", mlt_frame_is_test_card( *frame
) );
345 int mlt_producer_attach( mlt_producer
this, mlt_filter filter
)
347 int error
= this == NULL
|| filter
== NULL
;
352 mlt_properties properties
= mlt_producer_properties( this );
353 mlt_filter
*filters
= mlt_properties_get_data( properties
, "_filters", &size
);
354 int count
= mlt_properties_get_int( properties
, "_filter_count" );
356 for ( i
= 0; error
== 0 && i
< count
; i
++ )
357 if ( filters
[ i
] == filter
)
365 filters
= realloc( filters
, size
* sizeof( mlt_filter
) );
366 mlt_properties_set_data( properties
, "_filters", filters
, size
, NULL
, NULL
);
369 if ( filters
!= NULL
)
371 mlt_properties_inc_ref( mlt_filter_properties( filter
) );
372 filters
[ count
++ ] = filter
;
373 mlt_properties_set_int( properties
, "_filter_count", count
);
387 int mlt_producer_detach( mlt_producer
this, mlt_filter filter
)
389 int error
= this == NULL
|| filter
== NULL
;
394 mlt_properties properties
= mlt_producer_properties( this );
395 mlt_filter
*filters
= mlt_properties_get_data( properties
, "_filters", &size
);
396 int count
= mlt_properties_get_int( properties
, "_filter_count" );
398 for ( i
= 0; i
< count
; i
++ )
399 if ( filters
[ i
] == filter
)
404 mlt_filter filter
= filters
[ i
];
406 for ( i
++ ; i
< count
; i
++ )
407 filters
[ i
- 1 ] = filters
[ i
];
408 mlt_properties_set_int( properties
, "_filter_count", -- count
);
409 mlt_filter_close( filter
);
415 /** Retrieve a filter.
418 mlt_filter
mlt_producer_filter( mlt_producer
this, int index
)
420 mlt_filter filter
= NULL
;
423 mlt_properties properties
= mlt_producer_properties( this );
424 mlt_filter
*filters
= mlt_properties_get_data( properties
, "_filters", NULL
);
425 int count
= mlt_properties_get_int( properties
, "_filter_count" );
426 if ( index
>= 0 && index
< count
)
427 filter
= filters
[ index
];
432 /** Close the producer.
435 void mlt_producer_close( mlt_producer
this )
437 if ( this != NULL
&& mlt_properties_dec_ref( mlt_producer_properties( this ) ) <= 0 )
439 mlt_properties properties
= mlt_producer_properties( this );
440 mlt_filter
*filters
= mlt_properties_get_data( properties
, "_filters", NULL
);
441 int count
= mlt_properties_get_int( properties
, "_filter_count" );
444 mlt_producer_detach( this, filters
[ 0 ] );
446 this->parent
.close
= NULL
;
448 if ( this->close
!= NULL
)
449 this->close( this->close_object
);
451 mlt_service_close( &this->parent
);