2 * miracle_unit.c -- Transmission Unit Implementation
3 * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
4 * Author: Dan Dennedy <dan@dennedy.org>
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.
27 #include <sys/ioctl.h>
30 #include <sys/types.h>
40 #include "miracle_unit.h"
41 #include "miracle_log.h"
42 #include "miracle_local.h"
44 #include <framework/mlt.h>
46 /* Forward references */
47 static void miracle_unit_status_communicate( miracle_unit );
49 /** Allocate a new DV transmission unit.
51 \return A new miracle_unit handle.
54 miracle_unit miracle_unit_init( int index, char *constructor )
56 miracle_unit this = NULL;
57 mlt_consumer consumer = NULL;
59 char *id = strdup( constructor );
60 char *arg = strchr( id, ':' );
65 consumer = mlt_factory_consumer( id, arg );
67 if ( consumer != NULL )
69 mlt_playlist playlist = mlt_playlist_init( );
70 this = calloc( sizeof( miracle_unit_t ), 1 );
71 this->properties = mlt_properties_new( );
72 mlt_properties_init( this->properties, this );
73 mlt_properties_set_int( this->properties, "unit", index );
74 mlt_properties_set_int( this->properties, "generation", 0 );
75 mlt_properties_set( this->properties, "constructor", constructor );
76 mlt_properties_set( this->properties, "id", id );
77 mlt_properties_set( this->properties, "arg", arg );
78 mlt_properties_set_data( this->properties, "consumer", consumer, 0, ( mlt_destructor )mlt_consumer_close, NULL );
79 mlt_properties_set_data( this->properties, "playlist", playlist, 0, ( mlt_destructor )mlt_playlist_close, NULL );
80 mlt_consumer_connect( consumer, MLT_PLAYLIST_SERVICE( playlist ) );
86 static char *strip_root( miracle_unit unit, char *file )
88 mlt_properties properties = unit->properties;
89 char *root = mlt_properties_get( properties, "root" );
90 if ( file != NULL && root != NULL )
92 int length = strlen( root );
93 if ( root[ length - 1 ] == '/' )
95 if ( !strncmp( file, root, length ) )
101 /** Communicate the current status to all threads waiting on the notifier.
104 static void miracle_unit_status_communicate( miracle_unit unit )
108 mlt_properties properties = unit->properties;
109 char *root_dir = mlt_properties_get( properties, "root" );
110 valerie_notifier notifier = mlt_properties_get_data( properties, "notifier", NULL );
111 valerie_status_t status;
113 if ( root_dir != NULL && notifier != NULL )
115 if ( miracle_unit_get_status( unit, &status ) == 0 )
116 /* if ( !( ( status.status == unit_playing || status.status == unit_paused ) &&
117 strcmp( status.clip, "" ) &&
118 !strcmp( status.tail_clip, "" ) &&
119 status.position == 0 &&
121 status.out == 0 ) ) */
122 valerie_notifier_put( notifier, &status );
127 /** Set the notifier info
130 void miracle_unit_set_notifier( miracle_unit this, valerie_notifier notifier, char *root_dir )
132 mlt_properties properties = this->properties;
133 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
134 mlt_properties playlist_properties = MLT_PLAYLIST_PROPERTIES( playlist );
136 mlt_properties_set( properties, "root", root_dir );
137 mlt_properties_set_data( properties, "notifier", notifier, 0, NULL, NULL );
138 mlt_properties_set_data( playlist_properties, "notifier_arg", this, 0, NULL, NULL );
139 mlt_properties_set_data( playlist_properties, "notifier", miracle_unit_status_communicate, 0, NULL, NULL );
141 miracle_unit_status_communicate( this );
144 /** Create or locate a producer for the file specified.
147 static mlt_producer locate_producer( miracle_unit unit, char *file )
149 return mlt_factory_producer( "fezzik", file );
152 /** Update the generation count.
155 static void update_generation( miracle_unit unit )
157 mlt_properties properties = unit->properties;
158 int generation = mlt_properties_get_int( properties, "generation" );
159 mlt_properties_set_int( properties, "generation", ++ generation );
162 /** Wipe all clips on the playlist for this unit.
165 static void clear_unit( miracle_unit unit )
167 mlt_properties properties = unit->properties;
168 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
169 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
171 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
172 mlt_playlist_clear( playlist );
173 mlt_producer_seek( producer, 0 );
174 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
176 update_generation( unit );
179 /** Wipe all but the playing clip from the unit.
182 static void clean_unit( miracle_unit unit )
184 mlt_properties properties = unit->properties;
185 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
186 mlt_playlist_clip_info info;
187 int current = mlt_playlist_current_clip( playlist );
188 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
189 mlt_position position = mlt_producer_frame( producer );
190 double speed = mlt_producer_get_speed( producer );
191 mlt_playlist_get_clip_info( playlist, &info, current );
193 if ( info.producer != NULL )
195 mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( info.producer ) );
196 position -= info.start;
198 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
199 mlt_playlist_append_io( playlist, info.producer, info.frame_in, info.frame_out );
200 mlt_producer_seek( producer, position );
201 mlt_producer_set_speed( producer, speed );
202 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
203 mlt_producer_close( info.producer );
206 update_generation( unit );
209 /** Remove everything up to the current clip from the unit.
212 static void wipe_unit( miracle_unit unit )
214 mlt_properties properties = unit->properties;
215 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
216 mlt_playlist_clip_info info;
217 int current = mlt_playlist_current_clip( playlist );
218 mlt_playlist_get_clip_info( playlist, &info, current );
220 if ( info.producer != NULL && info.start > 0 )
222 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
223 mlt_playlist_remove_region( playlist, 0, info.start - 1 );
224 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
227 update_generation( unit );
230 /** Generate a report on all loaded clips.
233 void miracle_unit_report_list( miracle_unit unit, valerie_response response )
236 mlt_properties properties = unit->properties;
237 int generation = mlt_properties_get_int( properties, "generation" );
238 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
240 valerie_response_printf( response, 1024, "%d\n", generation );
242 for ( i = 0; i < mlt_playlist_count( playlist ); i ++ )
244 mlt_playlist_clip_info info;
246 mlt_playlist_get_clip_info( playlist , &info, i );
247 title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
249 title = strip_root( unit, info.resource );
250 valerie_response_printf( response, 10240, "%d \"%s\" %d %d %d %d %.2f\n",
259 valerie_response_printf( response, 1024, "\n" );
262 /** Load a clip into the unit clearing existing play list.
265 \param unit A miracle_unit handle.
266 \param clip The absolute file name of the clip to load.
267 \param in The starting frame (-1 for 0)
268 \param out The ending frame (-1 for maximum)
271 valerie_error_code miracle_unit_load( miracle_unit unit, char *clip, int32_t in, int32_t out, int flush )
273 // Now try to create a producer
274 mlt_producer instance = locate_producer( unit, clip );
276 if ( instance != NULL )
278 mlt_properties properties = unit->properties;
279 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
280 int original = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( playlist ) );
281 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
282 mlt_playlist_append_io( playlist, instance, in, out );
283 mlt_playlist_remove_region( playlist, 0, original );
284 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
285 miracle_log( LOG_DEBUG, "loaded clip %s", clip );
286 update_generation( unit );
287 miracle_unit_status_communicate( unit );
288 mlt_producer_close( instance );
292 return valerie_invalid_file;
295 valerie_error_code miracle_unit_insert( miracle_unit unit, char *clip, int index, int32_t in, int32_t out )
297 mlt_producer instance = locate_producer( unit, clip );
299 if ( instance != NULL )
301 mlt_properties properties = unit->properties;
302 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
303 fprintf( stderr, "inserting clip %s before %d\n", clip, index );
304 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
305 mlt_playlist_insert( playlist, instance, index, in, out );
306 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
307 miracle_log( LOG_DEBUG, "inserted clip %s at %d", clip, index );
308 update_generation( unit );
309 miracle_unit_status_communicate( unit );
310 mlt_producer_close( instance );
314 return valerie_invalid_file;
317 valerie_error_code miracle_unit_remove( miracle_unit unit, int index )
319 mlt_properties properties = unit->properties;
320 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
321 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
322 mlt_playlist_remove( playlist, index );
323 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
324 miracle_log( LOG_DEBUG, "removed clip at %d", index );
325 update_generation( unit );
326 miracle_unit_status_communicate( unit );
330 valerie_error_code miracle_unit_clean( miracle_unit unit )
333 miracle_log( LOG_DEBUG, "Cleaned playlist" );
334 miracle_unit_status_communicate( unit );
338 valerie_error_code miracle_unit_wipe( miracle_unit unit )
341 miracle_log( LOG_DEBUG, "Wiped playlist" );
342 miracle_unit_status_communicate( unit );
346 valerie_error_code miracle_unit_clear( miracle_unit unit )
348 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
350 mlt_consumer_purge( consumer );
351 miracle_log( LOG_DEBUG, "Cleared playlist" );
352 miracle_unit_status_communicate( unit );
356 valerie_error_code miracle_unit_move( miracle_unit unit, int src, int dest )
358 mlt_properties properties = unit->properties;
359 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
360 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
361 mlt_playlist_move( playlist, src, dest );
362 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
363 miracle_log( LOG_DEBUG, "moved clip %d to %d", src, dest );
364 update_generation( unit );
365 miracle_unit_status_communicate( unit );
369 /** Add a clip to the unit play list.
372 \param unit A miracle_unit handle.
373 \param clip The absolute file name of the clip to load.
374 \param in The starting frame (-1 for 0)
375 \param out The ending frame (-1 for maximum)
378 valerie_error_code miracle_unit_append( miracle_unit unit, char *clip, int32_t in, int32_t out )
380 mlt_producer instance = locate_producer( unit, clip );
382 if ( instance != NULL )
384 mlt_properties properties = unit->properties;
385 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
386 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
387 mlt_playlist_append_io( playlist, instance, in, out );
388 miracle_log( LOG_DEBUG, "appended clip %s", clip );
389 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
390 update_generation( unit );
391 miracle_unit_status_communicate( unit );
392 mlt_producer_close( instance );
396 return valerie_invalid_file;
399 /** Add an mlt_service to the playlist
401 \param unit A miracle_unit handle.
402 \param service the service to add
405 valerie_error_code miracle_unit_append_service( miracle_unit unit, mlt_service service )
407 mlt_properties properties = unit->properties;
408 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
409 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
410 mlt_playlist_append( playlist, ( mlt_producer )service );
411 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
412 miracle_log( LOG_DEBUG, "appended clip" );
413 update_generation( unit );
414 miracle_unit_status_communicate( unit );
418 /** Start playing the unit.
421 \param unit A miracle_unit handle.
422 \param speed An integer that specifies the playback rate as a
423 percentage multiplied by 100.
426 void miracle_unit_play( miracle_unit_t *unit, int speed )
428 mlt_properties properties = unit->properties;
429 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
430 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
431 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
432 mlt_producer_set_speed( producer, ( double )speed / 1000 );
433 mlt_consumer_start( consumer );
434 miracle_unit_status_communicate( unit );
439 Terminates the dv_pump and halts dv1394 transmission.
441 \param unit A miracle_unit handle.
444 void miracle_unit_terminate( miracle_unit unit )
446 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
447 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
448 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
449 mlt_producer_set_speed( producer, 0 );
450 mlt_consumer_stop( consumer );
451 miracle_unit_status_communicate( unit );
454 /** Query the status of unit playback.
456 \param unit A miracle_unit handle.
457 \return 1 if the unit is not playing, 0 if playing.
460 int miracle_unit_has_terminated( miracle_unit unit )
462 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
463 return mlt_consumer_is_stopped( consumer );
466 /** Transfer the currently loaded clip to another unit
469 int miracle_unit_transfer( miracle_unit dest_unit, miracle_unit src_unit )
472 mlt_properties dest_properties = dest_unit->properties;
473 mlt_playlist dest_playlist = mlt_properties_get_data( dest_properties, "playlist", NULL );
474 mlt_properties src_properties = src_unit->properties;
475 mlt_playlist src_playlist = mlt_properties_get_data( src_properties, "playlist", NULL );
476 mlt_playlist tmp_playlist = mlt_playlist_init( );
478 for ( i = 0; i < mlt_playlist_count( src_playlist ); i ++ )
480 mlt_playlist_clip_info info;
481 mlt_playlist_get_clip_info( src_playlist, &info, i );
482 if ( info.producer != NULL )
483 mlt_playlist_append_io( tmp_playlist, info.producer, info.frame_in, info.frame_out );
486 clear_unit( src_unit );
488 mlt_service_lock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
490 for ( i = 0; i < mlt_playlist_count( tmp_playlist ); i ++ )
492 mlt_playlist_clip_info info;
493 mlt_playlist_get_clip_info( tmp_playlist, &info, i );
494 if ( info.producer != NULL )
495 mlt_playlist_append_io( dest_playlist, info.producer, info.frame_in, info.frame_out );
498 mlt_service_unlock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
500 update_generation( dest_unit );
501 miracle_unit_status_communicate( dest_unit );
503 mlt_playlist_close( tmp_playlist );
508 /** Determine if unit is offline.
511 int miracle_unit_is_offline( miracle_unit unit )
516 /** Obtain the status for a given unit
519 int miracle_unit_get_status( miracle_unit unit, valerie_status status )
521 int error = unit == NULL;
523 memset( status, 0, sizeof( valerie_status_t ) );
527 mlt_properties properties = unit->properties;
528 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
529 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
530 mlt_producer clip = mlt_playlist_current( playlist );
532 mlt_playlist_clip_info info;
533 int clip_index = mlt_playlist_current_clip( playlist );
534 mlt_playlist_get_clip_info( playlist, &info, clip_index );
536 if ( info.resource != NULL && strcmp( info.resource, "" ) )
538 char *title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
540 title = strip_root( unit, info.resource );
541 strncpy( status->clip, title, sizeof( status->clip ) );
542 status->speed = (int)( mlt_producer_get_speed( producer ) * 1000.0 );
543 status->fps = mlt_producer_get_fps( producer );
544 status->in = info.frame_in;
545 status->out = info.frame_out;
546 status->position = mlt_producer_frame( clip );
547 status->length = mlt_producer_get_length( clip );
548 strncpy( status->tail_clip, title, sizeof( status->tail_clip ) );
549 status->tail_in = info.frame_in;
550 status->tail_out = info.frame_out;
551 status->tail_position = mlt_producer_frame( clip );
552 status->tail_length = mlt_producer_get_length( clip );
553 status->clip_index = mlt_playlist_current_clip( playlist );
554 status->seek_flag = 1;
557 status->generation = mlt_properties_get_int( properties, "generation" );
559 if ( miracle_unit_has_terminated( unit ) )
560 status->status = unit_stopped;
561 else if ( !strcmp( status->clip, "" ) )
562 status->status = unit_not_loaded;
563 else if ( status->speed == 0 )
564 status->status = unit_paused;
566 status->status = unit_playing;
570 status->status = unit_undefined;
573 status->unit = mlt_properties_get_int( unit->properties, "unit" );
578 /** Change position in the playlist.
581 void miracle_unit_change_position( miracle_unit unit, int clip, int32_t position )
583 mlt_properties properties = unit->properties;
584 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
585 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
586 mlt_playlist_clip_info info;
593 else if ( clip >= mlt_playlist_count( playlist ) )
595 clip = mlt_playlist_count( playlist ) - 1;
599 if ( mlt_playlist_get_clip_info( playlist, &info, clip ) == 0 )
601 int32_t frame_start = info.start;
602 int32_t frame_offset = position;
604 if ( frame_offset < 0 )
605 frame_offset = info.frame_out;
606 if ( frame_offset < info.frame_in )
607 frame_offset = info.frame_in;
608 if ( frame_offset >= info.frame_out )
609 frame_offset = info.frame_out;
611 mlt_producer_seek( producer, frame_start + frame_offset - info.frame_in );
614 miracle_unit_status_communicate( unit );
617 /** Get the index of the current clip.
620 int miracle_unit_get_current_clip( miracle_unit unit )
622 mlt_properties properties = unit->properties;
623 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
624 int clip_index = mlt_playlist_current_clip( playlist );
628 /** Set a clip's in point
631 int miracle_unit_set_clip_in( miracle_unit unit, int index, int32_t position )
633 mlt_properties properties = unit->properties;
634 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
635 mlt_playlist_clip_info info;
636 int error = mlt_playlist_get_clip_info( playlist, &info, index );
640 miracle_unit_play( unit, 0 );
641 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
642 error = mlt_playlist_resize_clip( playlist, index, position, info.frame_out );
643 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
644 update_generation( unit );
645 miracle_unit_change_position( unit, index, 0 );
651 /** Set a clip's out point.
654 int miracle_unit_set_clip_out( miracle_unit unit, int index, int32_t position )
656 mlt_properties properties = unit->properties;
657 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
658 mlt_playlist_clip_info info;
659 int error = mlt_playlist_get_clip_info( playlist, &info, index );
663 miracle_unit_play( unit, 0 );
664 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
665 error = mlt_playlist_resize_clip( playlist, index, info.frame_in, position );
666 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
667 update_generation( unit );
668 miracle_unit_status_communicate( unit );
669 miracle_unit_change_position( unit, index, -1 );
675 /** Step by specified position.
678 void miracle_unit_step( miracle_unit unit, int32_t offset )
680 mlt_properties properties = unit->properties;
681 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
682 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
683 mlt_position position = mlt_producer_frame( producer );
684 mlt_producer_seek( producer, position + offset );
687 /** Set the unit's clip mode regarding in and out points.
690 //void miracle_unit_set_mode( miracle_unit unit, dv_player_clip_mode mode )
692 //dv_player player = miracle_unit_get_dv_player( unit );
693 //if ( player != NULL )
694 //dv_player_set_clip_mode( player, mode );
695 //miracle_unit_status_communicate( unit );
698 /** Get the unit's clip mode regarding in and out points.
701 //dv_player_clip_mode miracle_unit_get_mode( miracle_unit unit )
703 //dv_player player = miracle_unit_get_dv_player( unit );
704 //return dv_player_get_clip_mode( player );
707 /** Set the unit's clip mode regarding eof handling.
710 //void miracle_unit_set_eof_action( miracle_unit unit, dv_player_eof_action action )
712 //dv_player player = miracle_unit_get_dv_player( unit );
713 //dv_player_set_eof_action( player, action );
714 //miracle_unit_status_communicate( unit );
717 /** Get the unit's clip mode regarding eof handling.
720 //dv_player_eof_action miracle_unit_get_eof_action( miracle_unit unit )
722 //dv_player player = miracle_unit_get_dv_player( unit );
723 //return dv_player_get_eof_action( player );
726 int miracle_unit_set( miracle_unit unit, char *name_value )
728 mlt_properties properties = NULL;
730 if ( strncmp( name_value, "consumer.", 9 ) )
732 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
733 properties = MLT_PLAYLIST_PROPERTIES( playlist );
737 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
738 properties = MLT_CONSUMER_PROPERTIES( consumer );
742 return mlt_properties_parse( properties, name_value );
745 char *miracle_unit_get( miracle_unit unit, char *name )
747 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
748 mlt_properties properties = MLT_PLAYLIST_PROPERTIES( playlist );
749 return mlt_properties_get( properties, name );
755 \param unit A miracle_unit handle.
758 void miracle_unit_close( miracle_unit unit )
762 miracle_log( LOG_DEBUG, "closing unit..." );
763 miracle_unit_terminate( unit );
764 mlt_properties_close( unit->properties );
766 miracle_log( LOG_DEBUG, "... unit closed." );