]> git.sesse.net Git - mlt/blob - src/miracle/miracle_unit.c
avformat/factory.c, jackrack/jack_rack.c, jackrack/plugin_settings.c, vmfx/filter_chr...
[mlt] / src / miracle / miracle_unit.c
1 /*
2  * miracle_unit.c -- Transmission Unit Implementation
3  * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
4  * Author: Dan Dennedy <dan@dennedy.org>
5  *
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.
10  *
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.
15  *
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.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <sys/ioctl.h>
28 #include <sys/mman.h>
29 #include <sys/poll.h>
30 #include <sys/types.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <signal.h>
36 #include <limits.h>
37
38 #include <sys/mman.h>
39
40 #include "miracle_unit.h"
41 #include "miracle_log.h"
42 #include "miracle_local.h"
43
44 #include <framework/mlt.h>
45
46 /* Forward references */
47 static void miracle_unit_status_communicate( miracle_unit );
48
49 /** Allocate a new DV transmission unit.
50
51     \return A new miracle_unit handle.
52 */
53
54 miracle_unit miracle_unit_init( int index, char *constructor )
55 {
56         miracle_unit this = NULL;
57         mlt_consumer consumer = NULL;
58
59         char *id = strdup( constructor );
60         char *arg = strchr( id, ':' );
61
62         if ( arg != NULL )
63                 *arg ++ = '\0';
64
65         consumer = mlt_factory_consumer( id, arg );
66
67         if ( consumer != NULL )
68         {
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 ) );
81         }
82
83         return this;
84 }
85
86 static char *strip_root( miracle_unit unit, char *file )
87 {
88         mlt_properties properties = unit->properties;
89         char *root = mlt_properties_get( properties, "root" );
90         if ( file != NULL && root != NULL )
91         {
92                 int length = strlen( root );
93                 if ( root[ length - 1 ] == '/' )
94                         length --;
95                 if ( !strncmp( file, root, length ) )
96                         file += length;
97         }
98         return file;
99 }
100
101 /** Communicate the current status to all threads waiting on the notifier.
102 */
103
104 static void miracle_unit_status_communicate( miracle_unit unit )
105 {
106         if ( unit != NULL )
107         {
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;
112
113                 if ( root_dir != NULL && notifier != NULL )
114                 {
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 && 
120                                                 status.in == 0 && 
121                                                 status.out == 0 ) ) */
122                                         valerie_notifier_put( notifier, &status );
123                 }
124         }
125 }
126
127 /** Set the notifier info
128 */
129
130 void miracle_unit_set_notifier( miracle_unit this, valerie_notifier notifier, char *root_dir )
131 {
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 );
135
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 );
140
141         miracle_unit_status_communicate( this );
142 }
143
144 /** Create or locate a producer for the file specified.
145 */
146
147 static mlt_producer locate_producer( miracle_unit unit, char *file )
148 {
149         return mlt_factory_producer( "fezzik", file );
150 }
151
152 /** Update the generation count.
153 */
154
155 static void update_generation( miracle_unit unit )
156 {
157         mlt_properties properties = unit->properties;
158         int generation = mlt_properties_get_int( properties, "generation" );
159         mlt_properties_set_int( properties, "generation", ++ generation );
160 }
161
162 /** Wipe all clips on the playlist for this unit.
163 */
164
165 static void clear_unit( miracle_unit unit )
166 {
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 );
170
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 ) );
175
176         update_generation( unit );
177 }
178
179 /** Wipe all but the playing clip from the unit.
180 */
181
182 static void clean_unit( miracle_unit unit )
183 {
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 );
192
193         if ( info.producer != NULL )
194         {
195                 mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( info.producer ) );
196                 position -= info.start;
197                 clear_unit( unit );
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 );
204         }
205         
206         update_generation( unit );
207 }
208
209 /** Remove everything up to the current clip from the unit.
210 */
211
212 static void wipe_unit( miracle_unit unit )
213 {
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 );
219
220         if ( info.producer != NULL && info.start > 0 )
221         {
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 ) );
225         }
226         
227         update_generation( unit );
228 }
229
230 /** Generate a report on all loaded clips.
231 */
232
233 void miracle_unit_report_list( miracle_unit unit, valerie_response response )
234 {
235         int i;
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 );
239
240         valerie_response_printf( response, 1024, "%d\n", generation );
241                 
242         for ( i = 0; i < mlt_playlist_count( playlist ); i ++ )
243         {
244                 mlt_playlist_clip_info info;
245                 char *title;
246                 mlt_playlist_get_clip_info( playlist , &info, i );
247                 title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
248                 if ( title == NULL )
249                         title = strip_root( unit, info.resource );
250                 valerie_response_printf( response, 10240, "%d \"%s\" %d %d %d %d %.2f\n", 
251                                                                  i, 
252                                                                  title,
253                                                                  info.frame_in, 
254                                                                  info.frame_out,
255                                                                  info.frame_count, 
256                                                                  info.length, 
257                                                                  info.fps );
258         }
259         valerie_response_printf( response, 1024, "\n" );
260 }
261
262 /** Load a clip into the unit clearing existing play list.
263
264     \todo error handling
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)
269 */
270
271 valerie_error_code miracle_unit_load( miracle_unit unit, char *clip, int32_t in, int32_t out, int flush )
272 {
273         // Now try to create a producer
274         mlt_producer instance = locate_producer( unit, clip );
275
276         if ( instance != NULL )
277         {
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 );
289                 return valerie_ok;
290         }
291
292         return valerie_invalid_file;
293 }
294
295 valerie_error_code miracle_unit_insert( miracle_unit unit, char *clip, int index, int32_t in, int32_t out )
296 {
297         mlt_producer instance = locate_producer( unit, clip );
298
299         if ( instance != NULL )
300         {
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 );
311                 return valerie_ok;
312         }
313
314         return valerie_invalid_file;
315 }
316
317 valerie_error_code miracle_unit_remove( miracle_unit unit, int index )
318 {
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 );
327         return valerie_ok;
328 }
329
330 valerie_error_code miracle_unit_clean( miracle_unit unit )
331 {
332         clean_unit( unit );
333         miracle_log( LOG_DEBUG, "Cleaned playlist" );
334         miracle_unit_status_communicate( unit );
335         return valerie_ok;
336 }
337
338 valerie_error_code miracle_unit_wipe( miracle_unit unit )
339 {
340         wipe_unit( unit );
341         miracle_log( LOG_DEBUG, "Wiped playlist" );
342         miracle_unit_status_communicate( unit );
343         return valerie_ok;
344 }
345
346 valerie_error_code miracle_unit_clear( miracle_unit unit )
347 {
348         mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
349         clear_unit( unit );
350         mlt_consumer_purge( consumer );
351         miracle_log( LOG_DEBUG, "Cleared playlist" );
352         miracle_unit_status_communicate( unit );
353         return valerie_ok;
354 }
355
356 valerie_error_code miracle_unit_move( miracle_unit unit, int src, int dest )
357 {
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 );
366         return valerie_ok;
367 }
368
369 /** Add a clip to the unit play list.
370
371     \todo error handling
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)
376 */
377
378 valerie_error_code miracle_unit_append( miracle_unit unit, char *clip, int32_t in, int32_t out )
379 {
380         mlt_producer instance = locate_producer( unit, clip );
381
382         if ( instance != NULL )
383         {
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 );
393                 return valerie_ok;
394         }
395
396         return valerie_invalid_file;
397 }
398
399 /** Add an mlt_service to the playlist
400
401     \param unit A miracle_unit handle.
402     \param service the service to add
403 */
404
405 valerie_error_code miracle_unit_append_service( miracle_unit unit, mlt_service service )
406 {
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 );
415         return valerie_ok;
416 }
417
418 /** Start playing the unit.
419
420     \todo error handling
421     \param unit A miracle_unit handle.
422     \param speed An integer that specifies the playback rate as a
423                  percentage multiplied by 100.
424 */
425
426 void miracle_unit_play( miracle_unit_t *unit, int speed )
427 {
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 );
435 }
436
437 /** Stop playback.
438
439     Terminates the dv_pump and halts dv1394 transmission.
440
441     \param unit A miracle_unit handle.
442 */
443
444 void miracle_unit_terminate( miracle_unit unit )
445 {
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 );
452 }
453
454 /** Query the status of unit playback.
455
456     \param unit A miracle_unit handle.
457     \return 1 if the unit is not playing, 0 if playing.
458 */
459
460 int miracle_unit_has_terminated( miracle_unit unit )
461 {
462         mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
463         return mlt_consumer_is_stopped( consumer );
464 }
465
466 /** Transfer the currently loaded clip to another unit
467 */
468
469 int miracle_unit_transfer( miracle_unit dest_unit, miracle_unit src_unit )
470 {
471         int i;
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( );
477
478         for ( i = 0; i < mlt_playlist_count( src_playlist ); i ++ )
479         {
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 );
484         }
485
486         clear_unit( src_unit );
487
488         mlt_service_lock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
489
490         for ( i = 0; i < mlt_playlist_count( tmp_playlist ); i ++ )
491         {
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 );
496         }
497
498         mlt_service_unlock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
499
500         update_generation( dest_unit );
501         miracle_unit_status_communicate( dest_unit );
502
503         mlt_playlist_close( tmp_playlist );
504
505         return 0;
506 }
507
508 /** Determine if unit is offline.
509 */
510
511 int miracle_unit_is_offline( miracle_unit unit )
512 {
513         return 0;
514 }
515
516 /** Obtain the status for a given unit
517 */
518
519 int miracle_unit_get_status( miracle_unit unit, valerie_status status )
520 {
521         int error = unit == NULL;
522
523         memset( status, 0, sizeof( valerie_status_t ) );
524
525         if ( !error )
526         {
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 );
531
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 );
535
536                 if ( info.resource != NULL && strcmp( info.resource, "" ) )
537                 {
538                         char *title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
539                         if ( title == NULL )
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;
555                 }
556
557                 status->generation = mlt_properties_get_int( properties, "generation" );
558
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;
565                 else
566                         status->status = unit_playing;
567         }
568         else
569         {
570                 status->status = unit_undefined;
571         }
572
573         status->unit = mlt_properties_get_int( unit->properties, "unit" );
574
575         return error;
576 }
577
578 /** Change position in the playlist.
579 */
580
581 void miracle_unit_change_position( miracle_unit unit, int clip, int32_t position )
582 {
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;
587
588         if ( clip < 0 )
589         {
590                 clip = 0;
591                 position = 0;
592         }
593         else if ( clip >= mlt_playlist_count( playlist ) )
594         {
595                 clip = mlt_playlist_count( playlist ) - 1;
596                 position = INT_MAX;
597         }
598
599         if ( mlt_playlist_get_clip_info( playlist, &info, clip ) == 0 )
600         {
601                 int32_t frame_start = info.start;
602                 int32_t frame_offset = position;
603
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;
610                 
611                 mlt_producer_seek( producer, frame_start + frame_offset - info.frame_in );
612         }
613
614         miracle_unit_status_communicate( unit );
615 }
616
617 /** Get the index of the current clip.
618 */
619
620 int     miracle_unit_get_current_clip( miracle_unit unit )
621 {
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 );
625         return clip_index;
626 }
627
628 /** Set a clip's in point
629 */
630
631 int miracle_unit_set_clip_in( miracle_unit unit, int index, int32_t position )
632 {
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 );
637
638         if ( error == 0 )
639         {
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 );
646         }
647
648         return error;
649 }
650
651 /** Set a clip's out point.
652 */
653
654 int miracle_unit_set_clip_out( miracle_unit unit, int index, int32_t position )
655 {
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 );
660
661         if ( error == 0 )
662         {
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 );
670         }
671
672         return error;
673 }
674
675 /** Step by specified position.
676 */
677
678 void miracle_unit_step( miracle_unit unit, int32_t offset )
679 {
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 );
685 }
686
687 /** Set the unit's clip mode regarding in and out points.
688 */
689
690 //void miracle_unit_set_mode( miracle_unit unit, dv_player_clip_mode mode )
691 //{
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 );
696 //}
697
698 /** Get the unit's clip mode regarding in and out points.
699 */
700
701 //dv_player_clip_mode miracle_unit_get_mode( miracle_unit unit )
702 //{
703         //dv_player player = miracle_unit_get_dv_player( unit );
704         //return dv_player_get_clip_mode( player );
705 //}
706
707 /** Set the unit's clip mode regarding eof handling.
708 */
709
710 //void miracle_unit_set_eof_action( miracle_unit unit, dv_player_eof_action action )
711 //{
712         //dv_player player = miracle_unit_get_dv_player( unit );
713         //dv_player_set_eof_action( player, action );
714         //miracle_unit_status_communicate( unit );
715 //}
716
717 /** Get the unit's clip mode regarding eof handling.
718 */
719
720 //dv_player_eof_action miracle_unit_get_eof_action( miracle_unit unit )
721 //{
722         //dv_player player = miracle_unit_get_dv_player( unit );
723         //return dv_player_get_eof_action( player );
724 //}
725
726 int miracle_unit_set( miracle_unit unit, char *name_value )
727 {
728         mlt_properties properties = NULL;
729
730         if ( strncmp( name_value, "consumer.", 9 ) )
731         {
732                 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
733                 properties = MLT_PLAYLIST_PROPERTIES( playlist );
734         }
735         else
736         {
737                 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
738                 properties = MLT_CONSUMER_PROPERTIES( consumer );
739                 name_value += 9;
740         }
741
742         return mlt_properties_parse( properties, name_value );
743 }
744
745 char *miracle_unit_get( miracle_unit unit, char *name )
746 {
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 );
750 }
751
752 /** Release the unit
753
754     \todo error handling
755     \param unit A miracle_unit handle.
756 */
757
758 void miracle_unit_close( miracle_unit unit )
759 {
760         if ( unit != NULL )
761         {
762                 miracle_log( LOG_DEBUG, "closing unit..." );
763                 miracle_unit_terminate( unit );
764                 mlt_properties_close( unit->properties );
765                 free( unit );
766                 miracle_log( LOG_DEBUG, "... unit closed." );
767         }
768 }
769