]> git.sesse.net Git - mlt/blob - src/miracle/miracle_unit.c
Merge ../mlt++
[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( NULL, 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         // Try to get the profile from the consumer
150         mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
151         mlt_profile profile = NULL;
152
153         if ( consumer != NULL )
154         {
155                 profile = mlt_service_profile( MLT_CONSUMER_SERVICE( consumer ) );
156         }
157         return mlt_factory_producer( profile, "fezzik", file );
158 }
159
160 /** Update the generation count.
161 */
162
163 static void update_generation( miracle_unit unit )
164 {
165         mlt_properties properties = unit->properties;
166         int generation = mlt_properties_get_int( properties, "generation" );
167         mlt_properties_set_int( properties, "generation", ++ generation );
168 }
169
170 /** Wipe all clips on the playlist for this unit.
171 */
172
173 static void clear_unit( miracle_unit unit )
174 {
175         mlt_properties properties = unit->properties;
176         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
177         mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
178
179         mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
180         mlt_playlist_clear( playlist );
181         mlt_producer_seek( producer, 0 );
182         mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
183
184         update_generation( unit );
185 }
186
187 /** Wipe all but the playing clip from the unit.
188 */
189
190 static void clean_unit( miracle_unit unit )
191 {
192         mlt_properties properties = unit->properties;
193         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
194         mlt_playlist_clip_info info;
195         int current = mlt_playlist_current_clip( playlist );
196         mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
197         mlt_position position = mlt_producer_frame( producer );
198         double speed = mlt_producer_get_speed( producer );
199         mlt_playlist_get_clip_info( playlist, &info, current );
200
201         if ( info.producer != NULL )
202         {
203                 mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( info.producer ) );
204                 position -= info.start;
205                 clear_unit( unit );
206                 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
207                 mlt_playlist_append_io( playlist, info.producer, info.frame_in, info.frame_out );
208                 mlt_producer_seek( producer, position );
209                 mlt_producer_set_speed( producer, speed );
210                 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
211                 mlt_producer_close( info.producer );
212         }
213         
214         update_generation( unit );
215 }
216
217 /** Remove everything up to the current clip from the unit.
218 */
219
220 static void wipe_unit( miracle_unit unit )
221 {
222         mlt_properties properties = unit->properties;
223         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
224         mlt_playlist_clip_info info;
225         int current = mlt_playlist_current_clip( playlist );
226         mlt_playlist_get_clip_info( playlist, &info, current );
227
228         if ( info.producer != NULL && info.start > 0 )
229         {
230                 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
231                 mlt_playlist_remove_region( playlist, 0, info.start - 1 );
232                 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
233         }
234         
235         update_generation( unit );
236 }
237
238 /** Generate a report on all loaded clips.
239 */
240
241 void miracle_unit_report_list( miracle_unit unit, valerie_response response )
242 {
243         int i;
244         mlt_properties properties = unit->properties;
245         int generation = mlt_properties_get_int( properties, "generation" );
246         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
247
248         valerie_response_printf( response, 1024, "%d\n", generation );
249                 
250         for ( i = 0; i < mlt_playlist_count( playlist ); i ++ )
251         {
252                 mlt_playlist_clip_info info;
253                 char *title;
254                 mlt_playlist_get_clip_info( playlist , &info, i );
255                 title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
256                 if ( title == NULL )
257                         title = strip_root( unit, info.resource );
258                 valerie_response_printf( response, 10240, "%d \"%s\" %d %d %d %d %.2f\n", 
259                                                                  i, 
260                                                                  title,
261                                                                  info.frame_in, 
262                                                                  info.frame_out,
263                                                                  info.frame_count, 
264                                                                  info.length, 
265                                                                  info.fps );
266         }
267         valerie_response_printf( response, 1024, "\n" );
268 }
269
270 /** Load a clip into the unit clearing existing play list.
271
272     \todo error handling
273     \param unit A miracle_unit handle.
274     \param clip The absolute file name of the clip to load.
275     \param in   The starting frame (-1 for 0)
276         \param out  The ending frame (-1 for maximum)
277 */
278
279 valerie_error_code miracle_unit_load( miracle_unit unit, char *clip, int32_t in, int32_t out, int flush )
280 {
281         // Now try to create a producer
282         mlt_producer instance = locate_producer( unit, clip );
283
284         if ( instance != NULL )
285         {
286                 mlt_properties properties = unit->properties;
287                 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
288                 int original = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( playlist ) );
289                 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
290                 mlt_playlist_append_io( playlist, instance, in, out );
291                 mlt_playlist_remove_region( playlist, 0, original );
292                 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
293                 miracle_log( LOG_DEBUG, "loaded clip %s", clip );
294                 update_generation( unit );
295                 miracle_unit_status_communicate( unit );
296                 mlt_producer_close( instance );
297                 return valerie_ok;
298         }
299
300         return valerie_invalid_file;
301 }
302
303 valerie_error_code miracle_unit_insert( miracle_unit unit, char *clip, int index, int32_t in, int32_t out )
304 {
305         mlt_producer instance = locate_producer( unit, clip );
306
307         if ( instance != NULL )
308         {
309                 mlt_properties properties = unit->properties;
310                 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
311                 fprintf( stderr, "inserting clip %s before %d\n", clip, index );
312                 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
313                 mlt_playlist_insert( playlist, instance, index, in, out );
314                 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
315                 miracle_log( LOG_DEBUG, "inserted clip %s at %d", clip, index );
316                 update_generation( unit );
317                 miracle_unit_status_communicate( unit );
318                 mlt_producer_close( instance );
319                 return valerie_ok;
320         }
321
322         return valerie_invalid_file;
323 }
324
325 valerie_error_code miracle_unit_remove( miracle_unit unit, int index )
326 {
327         mlt_properties properties = unit->properties;
328         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
329         mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
330         mlt_playlist_remove( playlist, index );
331         mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
332         miracle_log( LOG_DEBUG, "removed clip at %d", index );
333         update_generation( unit );
334         miracle_unit_status_communicate( unit );
335         return valerie_ok;
336 }
337
338 valerie_error_code miracle_unit_clean( miracle_unit unit )
339 {
340         clean_unit( unit );
341         miracle_log( LOG_DEBUG, "Cleaned playlist" );
342         miracle_unit_status_communicate( unit );
343         return valerie_ok;
344 }
345
346 valerie_error_code miracle_unit_wipe( miracle_unit unit )
347 {
348         wipe_unit( unit );
349         miracle_log( LOG_DEBUG, "Wiped playlist" );
350         miracle_unit_status_communicate( unit );
351         return valerie_ok;
352 }
353
354 valerie_error_code miracle_unit_clear( miracle_unit unit )
355 {
356         mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
357         clear_unit( unit );
358         mlt_consumer_purge( consumer );
359         miracle_log( LOG_DEBUG, "Cleared playlist" );
360         miracle_unit_status_communicate( unit );
361         return valerie_ok;
362 }
363
364 valerie_error_code miracle_unit_move( miracle_unit unit, int src, int dest )
365 {
366         mlt_properties properties = unit->properties;
367         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
368         mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
369         mlt_playlist_move( playlist, src, dest );
370         mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
371         miracle_log( LOG_DEBUG, "moved clip %d to %d", src, dest );
372         update_generation( unit );
373         miracle_unit_status_communicate( unit );
374         return valerie_ok;
375 }
376
377 /** Add a clip to the unit play list.
378
379     \todo error handling
380     \param unit A miracle_unit handle.
381     \param clip The absolute file name of the clip to load.
382     \param in   The starting frame (-1 for 0)
383         \param out  The ending frame (-1 for maximum)
384 */
385
386 valerie_error_code miracle_unit_append( miracle_unit unit, char *clip, int32_t in, int32_t out )
387 {
388         mlt_producer instance = locate_producer( unit, clip );
389
390         if ( instance != NULL )
391         {
392                 mlt_properties properties = unit->properties;
393                 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
394                 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
395                 mlt_playlist_append_io( playlist, instance, in, out );
396                 miracle_log( LOG_DEBUG, "appended clip %s", clip );
397                 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
398                 update_generation( unit );
399                 miracle_unit_status_communicate( unit );
400                 mlt_producer_close( instance );
401                 return valerie_ok;
402         }
403
404         return valerie_invalid_file;
405 }
406
407 /** Add an mlt_service to the playlist
408
409     \param unit A miracle_unit handle.
410     \param service the service to add
411 */
412
413 valerie_error_code miracle_unit_append_service( miracle_unit unit, mlt_service service )
414 {
415         mlt_properties properties = unit->properties;
416         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
417         mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
418         mlt_playlist_append( playlist, ( mlt_producer )service );
419         mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
420         miracle_log( LOG_DEBUG, "appended clip" );
421         update_generation( unit );
422         miracle_unit_status_communicate( unit );
423         return valerie_ok;
424 }
425
426 /** Start playing the unit.
427
428     \todo error handling
429     \param unit A miracle_unit handle.
430     \param speed An integer that specifies the playback rate as a
431                  percentage multiplied by 100.
432 */
433
434 void miracle_unit_play( miracle_unit_t *unit, int speed )
435 {
436         mlt_properties properties = unit->properties;
437         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
438         mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
439         mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
440         mlt_producer_set_speed( producer, ( double )speed / 1000 );
441         mlt_consumer_start( consumer );
442         miracle_unit_status_communicate( unit );
443 }
444
445 /** Stop playback.
446
447     Terminates the dv_pump and halts dv1394 transmission.
448
449     \param unit A miracle_unit handle.
450 */
451
452 void miracle_unit_terminate( miracle_unit unit )
453 {
454         mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
455         mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
456         mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
457         mlt_producer_set_speed( producer, 0 );
458         mlt_consumer_stop( consumer );
459         miracle_unit_status_communicate( unit );
460 }
461
462 /** Query the status of unit playback.
463
464     \param unit A miracle_unit handle.
465     \return 1 if the unit is not playing, 0 if playing.
466 */
467
468 int miracle_unit_has_terminated( miracle_unit unit )
469 {
470         mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
471         return mlt_consumer_is_stopped( consumer );
472 }
473
474 /** Transfer the currently loaded clip to another unit
475 */
476
477 int miracle_unit_transfer( miracle_unit dest_unit, miracle_unit src_unit )
478 {
479         int i;
480         mlt_properties dest_properties = dest_unit->properties;
481         mlt_playlist dest_playlist = mlt_properties_get_data( dest_properties, "playlist", NULL );
482         mlt_properties src_properties = src_unit->properties;
483         mlt_playlist src_playlist = mlt_properties_get_data( src_properties, "playlist", NULL );
484         mlt_playlist tmp_playlist = mlt_playlist_init( );
485
486         for ( i = 0; i < mlt_playlist_count( src_playlist ); i ++ )
487         {
488                 mlt_playlist_clip_info info;
489                 mlt_playlist_get_clip_info( src_playlist, &info, i );
490                 if ( info.producer != NULL )
491                         mlt_playlist_append_io( tmp_playlist, info.producer, info.frame_in, info.frame_out );
492         }
493
494         clear_unit( src_unit );
495
496         mlt_service_lock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
497
498         for ( i = 0; i < mlt_playlist_count( tmp_playlist ); i ++ )
499         {
500                 mlt_playlist_clip_info info;
501                 mlt_playlist_get_clip_info( tmp_playlist, &info, i );
502                 if ( info.producer != NULL )
503                         mlt_playlist_append_io( dest_playlist, info.producer, info.frame_in, info.frame_out );
504         }
505
506         mlt_service_unlock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
507
508         update_generation( dest_unit );
509         miracle_unit_status_communicate( dest_unit );
510
511         mlt_playlist_close( tmp_playlist );
512
513         return 0;
514 }
515
516 /** Determine if unit is offline.
517 */
518
519 int miracle_unit_is_offline( miracle_unit unit )
520 {
521         return 0;
522 }
523
524 /** Obtain the status for a given unit
525 */
526
527 int miracle_unit_get_status( miracle_unit unit, valerie_status status )
528 {
529         int error = unit == NULL;
530
531         memset( status, 0, sizeof( valerie_status_t ) );
532
533         if ( !error )
534         {
535                 mlt_properties properties = unit->properties;
536                 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
537                 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
538                 mlt_producer clip = mlt_playlist_current( playlist );
539
540                 mlt_playlist_clip_info info;
541                 int clip_index = mlt_playlist_current_clip( playlist );
542                 mlt_playlist_get_clip_info( playlist, &info, clip_index );
543
544                 if ( info.resource != NULL && strcmp( info.resource, "" ) )
545                 {
546                         char *title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
547                         if ( title == NULL )
548                                 title = strip_root( unit, info.resource );
549                         strncpy( status->clip, title, sizeof( status->clip ) );
550                         status->speed = (int)( mlt_producer_get_speed( producer ) * 1000.0 );
551                         status->fps = mlt_producer_get_fps( producer );
552                         status->in = info.frame_in;
553                         status->out = info.frame_out;
554                         status->position = mlt_producer_frame( clip );
555                         status->length = mlt_producer_get_length( clip );
556                         strncpy( status->tail_clip, title, sizeof( status->tail_clip ) );
557                         status->tail_in = info.frame_in;
558                         status->tail_out = info.frame_out;
559                         status->tail_position = mlt_producer_frame( clip );
560                         status->tail_length = mlt_producer_get_length( clip );
561                         status->clip_index = mlt_playlist_current_clip( playlist );
562                         status->seek_flag = 1;
563                 }
564
565                 status->generation = mlt_properties_get_int( properties, "generation" );
566
567                 if ( miracle_unit_has_terminated( unit ) )
568                         status->status = unit_stopped;
569                 else if ( !strcmp( status->clip, "" ) )
570                         status->status = unit_not_loaded;
571                 else if ( status->speed == 0 )
572                         status->status = unit_paused;
573                 else
574                         status->status = unit_playing;
575         }
576         else
577         {
578                 status->status = unit_undefined;
579         }
580
581         status->unit = mlt_properties_get_int( unit->properties, "unit" );
582
583         return error;
584 }
585
586 /** Change position in the playlist.
587 */
588
589 void miracle_unit_change_position( miracle_unit unit, int clip, int32_t position )
590 {
591         mlt_properties properties = unit->properties;
592         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
593         mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
594         mlt_playlist_clip_info info;
595
596         if ( clip < 0 )
597         {
598                 clip = 0;
599                 position = 0;
600         }
601         else if ( clip >= mlt_playlist_count( playlist ) )
602         {
603                 clip = mlt_playlist_count( playlist ) - 1;
604                 position = INT_MAX;
605         }
606
607         if ( mlt_playlist_get_clip_info( playlist, &info, clip ) == 0 )
608         {
609                 int32_t frame_start = info.start;
610                 int32_t frame_offset = position;
611
612                 if ( frame_offset < 0 )
613                         frame_offset = info.frame_out;
614                 if ( frame_offset < info.frame_in )
615                         frame_offset = info.frame_in;
616                 if ( frame_offset >= info.frame_out )
617                         frame_offset = info.frame_out;
618                 
619                 mlt_producer_seek( producer, frame_start + frame_offset - info.frame_in );
620         }
621
622         miracle_unit_status_communicate( unit );
623 }
624
625 /** Get the index of the current clip.
626 */
627
628 int     miracle_unit_get_current_clip( miracle_unit unit )
629 {
630         mlt_properties properties = unit->properties;
631         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
632         int clip_index = mlt_playlist_current_clip( playlist );
633         return clip_index;
634 }
635
636 /** Set a clip's in point
637 */
638
639 int miracle_unit_set_clip_in( miracle_unit unit, int index, int32_t position )
640 {
641         mlt_properties properties = unit->properties;
642         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
643         mlt_playlist_clip_info info;
644         int error = mlt_playlist_get_clip_info( playlist, &info, index );
645
646         if ( error == 0 )
647         {
648                 miracle_unit_play( unit, 0 );
649                 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
650                 error = mlt_playlist_resize_clip( playlist, index, position, info.frame_out );
651                 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
652                 update_generation( unit );
653                 miracle_unit_change_position( unit, index, 0 );
654         }
655
656         return error;
657 }
658
659 /** Set a clip's out point.
660 */
661
662 int miracle_unit_set_clip_out( miracle_unit unit, int index, int32_t position )
663 {
664         mlt_properties properties = unit->properties;
665         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
666         mlt_playlist_clip_info info;
667         int error = mlt_playlist_get_clip_info( playlist, &info, index );
668
669         if ( error == 0 )
670         {
671                 miracle_unit_play( unit, 0 );
672                 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
673                 error = mlt_playlist_resize_clip( playlist, index, info.frame_in, position );
674                 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
675                 update_generation( unit );
676                 miracle_unit_status_communicate( unit );
677                 miracle_unit_change_position( unit, index, -1 );
678         }
679
680         return error;
681 }
682
683 /** Step by specified position.
684 */
685
686 void miracle_unit_step( miracle_unit unit, int32_t offset )
687 {
688         mlt_properties properties = unit->properties;
689         mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
690         mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
691         mlt_position position = mlt_producer_frame( producer );
692         mlt_producer_seek( producer, position + offset );
693 }
694
695 /** Set the unit's clip mode regarding in and out points.
696 */
697
698 //void miracle_unit_set_mode( miracle_unit unit, dv_player_clip_mode mode )
699 //{
700         //dv_player player = miracle_unit_get_dv_player( unit );
701         //if ( player != NULL )
702                 //dv_player_set_clip_mode( player, mode );
703         //miracle_unit_status_communicate( unit );
704 //}
705
706 /** Get the unit's clip mode regarding in and out points.
707 */
708
709 //dv_player_clip_mode miracle_unit_get_mode( miracle_unit unit )
710 //{
711         //dv_player player = miracle_unit_get_dv_player( unit );
712         //return dv_player_get_clip_mode( player );
713 //}
714
715 /** Set the unit's clip mode regarding eof handling.
716 */
717
718 //void miracle_unit_set_eof_action( miracle_unit unit, dv_player_eof_action action )
719 //{
720         //dv_player player = miracle_unit_get_dv_player( unit );
721         //dv_player_set_eof_action( player, action );
722         //miracle_unit_status_communicate( unit );
723 //}
724
725 /** Get the unit's clip mode regarding eof handling.
726 */
727
728 //dv_player_eof_action miracle_unit_get_eof_action( miracle_unit unit )
729 //{
730         //dv_player player = miracle_unit_get_dv_player( unit );
731         //return dv_player_get_eof_action( player );
732 //}
733
734 int miracle_unit_set( miracle_unit unit, char *name_value )
735 {
736         mlt_properties properties = NULL;
737
738         if ( strncmp( name_value, "consumer.", 9 ) )
739         {
740                 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
741                 properties = MLT_PLAYLIST_PROPERTIES( playlist );
742         }
743         else
744         {
745                 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
746                 properties = MLT_CONSUMER_PROPERTIES( consumer );
747                 name_value += 9;
748         }
749
750         return mlt_properties_parse( properties, name_value );
751 }
752
753 char *miracle_unit_get( miracle_unit unit, char *name )
754 {
755         mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
756         mlt_properties properties = MLT_PLAYLIST_PROPERTIES( playlist );
757         return mlt_properties_get( properties, name );
758 }
759
760 /** Release the unit
761
762     \todo error handling
763     \param unit A miracle_unit handle.
764 */
765
766 void miracle_unit_close( miracle_unit unit )
767 {
768         if ( unit != NULL )
769         {
770                 miracle_log( LOG_DEBUG, "closing unit..." );
771                 miracle_unit_terminate( unit );
772                 mlt_properties_close( unit->properties );
773                 free( unit );
774                 miracle_log( LOG_DEBUG, "... unit closed." );
775         }
776 }
777