melted only supports explicit profiles, not auto-profile
[melted] / src / melted / melted_unit.c
1 /*
2 * melted_unit.c -- Playout Implementation
3 * Copyright (C) 2002-2009 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 "melted_unit.h"
41 #include "melted_log.h"
42 #include "melted_local.h"
43
44 #include <framework/mlt.h>
45
46 /* Forward references */
47 static void melted_unit_status_communicate( melted_unit );
48
49 /** Allocate a new playout unit.
50
51 \return A new melted_unit handle.
52 */
53
54 melted_unit melted_unit_init( int index, char *constructor )
55 {
56 melted_unit this = NULL;
57 mlt_consumer consumer = NULL;
58 mlt_profile profile = mlt_profile_init( NULL );
59
60 char *id = strdup( constructor );
61 char *arg = strchr( id, ':' );
62
63 if ( arg != NULL )
64 *arg ++ = '\0';
65
66 profile->is_explicit = 1;
67 consumer = mlt_factory_consumer( profile, id, arg );
68
69 if ( consumer != NULL )
70 {
71 mlt_playlist playlist = mlt_playlist_init( );
72 this = calloc( sizeof( melted_unit_t ), 1 );
73 this->properties = mlt_properties_new( );
74 mlt_properties_init( this->properties, this );
75 mlt_properties_set_int( this->properties, "unit", index );
76 mlt_properties_set_int( this->properties, "generation", 0 );
77 mlt_properties_set( this->properties, "constructor", constructor );
78 mlt_properties_set( this->properties, "id", id );
79 mlt_properties_set( this->properties, "arg", arg );
80 mlt_properties_set_data( this->properties, "producer", mlt_properties_new( ), 0, ( mlt_destructor )mlt_properties_close, NULL );
81 mlt_properties_set_data( this->properties, "consumer", consumer, 0, ( mlt_destructor )mlt_consumer_close, NULL );
82 mlt_properties_set_data( this->properties, "playlist", playlist, 0, ( mlt_destructor )mlt_playlist_close, NULL );
83 mlt_consumer_connect( consumer, MLT_PLAYLIST_SERVICE( playlist ) );
84 }
85
86 return this;
87 }
88
89 static char *strip_root( melted_unit unit, char *file )
90 {
91 mlt_properties properties = unit->properties;
92 char *root = mlt_properties_get( properties, "root" );
93 if ( file != NULL && root != NULL )
94 {
95 int length = strlen( root );
96 if ( root[ length - 1 ] == '/' )
97 length --;
98 if ( !strncmp( file, root, length ) )
99 file += length;
100 }
101 return file;
102 }
103
104 /** Communicate the current status to all threads waiting on the notifier.
105 */
106
107 static void melted_unit_status_communicate( melted_unit unit )
108 {
109 if ( unit != NULL )
110 {
111 mlt_properties properties = unit->properties;
112 char *root_dir = mlt_properties_get( properties, "root" );
113 mvcp_notifier notifier = mlt_properties_get_data( properties, "notifier", NULL );
114 mvcp_status_t status;
115
116 if ( root_dir != NULL && notifier != NULL )
117 {
118 if ( melted_unit_get_status( unit, &status ) == 0 )
119 /* if ( !( ( status.status == unit_playing || status.status == unit_paused ) &&
120 strcmp( status.clip, "" ) &&
121 !strcmp( status.tail_clip, "" ) &&
122 status.position == 0 &&
123 status.in == 0 &&
124 status.out == 0 ) ) */
125 mvcp_notifier_put( notifier, &status );
126 }
127 }
128 }
129
130 /** Set the notifier info
131 */
132
133 void melted_unit_set_notifier( melted_unit this, mvcp_notifier notifier, char *root_dir )
134 {
135 mlt_properties properties = this->properties;
136 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
137 mlt_properties playlist_properties = MLT_PLAYLIST_PROPERTIES( playlist );
138
139 mlt_properties_set( properties, "root", root_dir );
140 mlt_properties_set_data( properties, "notifier", notifier, 0, NULL, NULL );
141 mlt_properties_set_data( playlist_properties, "notifier_arg", this, 0, NULL, NULL );
142 mlt_properties_set_data( playlist_properties, "notifier", melted_unit_status_communicate, 0, NULL, NULL );
143
144 melted_unit_status_communicate( this );
145 }
146
147 /** Create or locate a producer for the file specified.
148 */
149
150 static mlt_producer locate_producer( melted_unit unit, char *file )
151 {
152 // Try to get the profile from the consumer
153 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
154 mlt_properties m_prop = mlt_properties_get_data( unit->properties, "producer", NULL );
155 mlt_producer producer;
156 mlt_profile profile = NULL;
157
158 if ( consumer != NULL )
159 {
160 profile = mlt_service_profile( MLT_CONSUMER_SERVICE( consumer ) );
161 }
162
163 producer = mlt_factory_producer( profile, NULL, file );
164 if( producer )
165 {
166 mlt_properties p_prop = mlt_producer_properties( producer );
167 mlt_properties_inherit ( p_prop, m_prop );
168 }
169
170 return producer;
171 }
172
173 /** Update the generation count.
174 */
175
176 static void update_generation( melted_unit unit )
177 {
178 mlt_properties properties = unit->properties;
179 int generation = mlt_properties_get_int( properties, "generation" );
180 mlt_properties_set_int( properties, "generation", ++ generation );
181 }
182
183 /** Wipe all clips on the playlist for this unit.
184 */
185
186 static void clear_unit( melted_unit unit )
187 {
188 mlt_properties properties = unit->properties;
189 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
190 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
191 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
192
193 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
194 mlt_playlist_clear( playlist );
195 mlt_producer_seek( producer, 0 );
196 mlt_properties_set_int( MLT_CONSUMER_PROPERTIES(consumer), "refresh", 1 );
197 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
198
199 update_generation( unit );
200 }
201
202 /** Wipe all but the playing clip from the unit.
203 */
204
205 static void clean_unit( melted_unit unit )
206 {
207 mlt_properties properties = unit->properties;
208 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
209 mlt_consumer consumer = mlt_properties_get_data( properties, "consumer", NULL );
210 mlt_playlist_clip_info info;
211 int current = mlt_playlist_current_clip( playlist );
212 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
213 mlt_position position = mlt_producer_frame( producer );
214 double speed = mlt_producer_get_speed( producer );
215 mlt_playlist_get_clip_info( playlist, &info, current );
216
217 if ( info.producer != NULL )
218 {
219 mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( info.producer ) );
220 position -= info.start;
221 clear_unit( unit );
222 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
223 mlt_playlist_append_io( playlist, info.producer, info.frame_in, info.frame_out );
224 mlt_producer_seek( producer, position );
225 mlt_producer_set_speed( producer, speed );
226 mlt_properties_set_int( MLT_CONSUMER_PROPERTIES(consumer), "refresh", 1 );
227 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
228 mlt_producer_close( info.producer );
229 }
230
231 update_generation( unit );
232 }
233
234 /** Remove everything up to the current clip from the unit.
235 */
236
237 static void wipe_unit( melted_unit unit )
238 {
239 mlt_properties properties = unit->properties;
240 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
241 mlt_playlist_clip_info info;
242 int current = mlt_playlist_current_clip( playlist );
243 mlt_playlist_get_clip_info( playlist, &info, current );
244
245 if ( info.producer != NULL && info.start > 0 )
246 {
247 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
248 mlt_playlist_remove_region( playlist, 0, info.start - 1 );
249 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
250 }
251
252 update_generation( unit );
253 }
254
255 /** Generate a report on all loaded clips.
256 */
257
258 void melted_unit_report_list( melted_unit unit, mvcp_response response )
259 {
260 int i;
261 mlt_properties properties = unit->properties;
262 int generation = mlt_properties_get_int( properties, "generation" );
263 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
264
265 mvcp_response_printf( response, 1024, "%d\n", generation );
266
267 for ( i = 0; i < mlt_playlist_count( playlist ); i ++ )
268 {
269 mlt_playlist_clip_info info;
270 char *title;
271 mlt_playlist_get_clip_info( playlist , &info, i );
272 title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
273 if ( title == NULL )
274 title = strip_root( unit, info.resource );
275 mvcp_response_printf( response, 10240, "%d \"%s\" %d %d %d %d %.2f\n",
276 i,
277 title,
278 info.frame_in,
279 info.frame_out,
280 info.frame_count,
281 info.length,
282 info.fps );
283 }
284 mvcp_response_printf( response, 1024, "\n" );
285 }
286
287 /** Load a clip into the unit clearing existing play list.
288
289 \todo error handling
290 \param unit A melted_unit handle.
291 \param clip The absolute file name of the clip to load.
292 \param in The starting frame (-1 for 0)
293 \param out The ending frame (-1 for maximum)
294 */
295
296 mvcp_error_code melted_unit_load( melted_unit unit, char *clip, int32_t in, int32_t out, int flush )
297 {
298 // Now try to create a producer
299 mlt_producer instance = locate_producer( unit, clip );
300
301 if ( instance != NULL )
302 {
303 mlt_properties properties = unit->properties;
304 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
305 int original = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( playlist ) );
306 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
307 mlt_playlist_append_io( playlist, instance, in, out );
308 mlt_playlist_remove_region( playlist, 0, original );
309 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
310 melted_log( LOG_DEBUG, "loaded clip %s", clip );
311 update_generation( unit );
312 melted_unit_status_communicate( unit );
313 mlt_producer_close( instance );
314 return mvcp_ok;
315 }
316
317 return mvcp_invalid_file;
318 }
319
320 mvcp_error_code melted_unit_insert( melted_unit unit, char *clip, int index, int32_t in, int32_t out )
321 {
322 mlt_producer instance = locate_producer( unit, clip );
323
324 if ( instance != NULL )
325 {
326 mlt_properties properties = unit->properties;
327 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
328 fprintf( stderr, "inserting clip %s before %d\n", clip, index );
329 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
330 mlt_playlist_insert( playlist, instance, index, in, out );
331 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
332 melted_log( LOG_DEBUG, "inserted clip %s at %d", clip, index );
333 update_generation( unit );
334 melted_unit_status_communicate( unit );
335 mlt_producer_close( instance );
336 return mvcp_ok;
337 }
338
339 return mvcp_invalid_file;
340 }
341
342 mvcp_error_code melted_unit_remove( melted_unit unit, int index )
343 {
344 mlt_properties properties = unit->properties;
345 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
346 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
347 mlt_playlist_remove( playlist, index );
348 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
349 melted_log( LOG_DEBUG, "removed clip at %d", index );
350 update_generation( unit );
351 melted_unit_status_communicate( unit );
352 return mvcp_ok;
353 }
354
355 mvcp_error_code melted_unit_clean( melted_unit unit )
356 {
357 clean_unit( unit );
358 melted_log( LOG_DEBUG, "Cleaned playlist" );
359 melted_unit_status_communicate( unit );
360 return mvcp_ok;
361 }
362
363 mvcp_error_code melted_unit_wipe( melted_unit unit )
364 {
365 wipe_unit( unit );
366 melted_log( LOG_DEBUG, "Wiped playlist" );
367 melted_unit_status_communicate( unit );
368 return mvcp_ok;
369 }
370
371 mvcp_error_code melted_unit_clear( melted_unit unit )
372 {
373 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
374 clear_unit( unit );
375 mlt_consumer_purge( consumer );
376 melted_log( LOG_DEBUG, "Cleared playlist" );
377 melted_unit_status_communicate( unit );
378 return mvcp_ok;
379 }
380
381 mvcp_error_code melted_unit_move( melted_unit unit, int src, int dest )
382 {
383 mlt_properties properties = unit->properties;
384 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
385 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
386 mlt_playlist_move( playlist, src, dest );
387 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
388 melted_log( LOG_DEBUG, "moved clip %d to %d", src, dest );
389 update_generation( unit );
390 melted_unit_status_communicate( unit );
391 return mvcp_ok;
392 }
393
394 /** Add a clip to the unit play list.
395
396 \todo error handling
397 \param unit A melted_unit handle.
398 \param clip The absolute file name of the clip to load.
399 \param in The starting frame (-1 for 0)
400 \param out The ending frame (-1 for maximum)
401 */
402
403 mvcp_error_code melted_unit_append( melted_unit unit, char *clip, int32_t in, int32_t out )
404 {
405 mlt_producer instance = locate_producer( unit, clip );
406
407 if ( instance != NULL )
408 {
409 mlt_properties properties = unit->properties;
410 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
411 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
412 mlt_playlist_append_io( playlist, instance, in, out );
413 melted_log( LOG_DEBUG, "appended clip %s", clip );
414 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
415 update_generation( unit );
416 melted_unit_status_communicate( unit );
417 mlt_producer_close( instance );
418 return mvcp_ok;
419 }
420
421 return mvcp_invalid_file;
422 }
423
424 /** Add an mlt_service to the playlist
425
426 \param unit A melted_unit handle.
427 \param service the service to add
428 */
429
430 mvcp_error_code melted_unit_append_service( melted_unit unit, mlt_service service )
431 {
432 mlt_properties properties = unit->properties;
433 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
434 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
435 mlt_playlist_append( playlist, ( mlt_producer )service );
436 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
437 melted_log( LOG_DEBUG, "appended clip" );
438 update_generation( unit );
439 melted_unit_status_communicate( unit );
440 return mvcp_ok;
441 }
442
443 /** Start playing the unit.
444
445 \todo error handling
446 \param unit A melted_unit handle.
447 \param speed An integer that specifies the playback rate as a
448 percentage multiplied by 100.
449 */
450
451 void melted_unit_play( melted_unit_t *unit, int speed )
452 {
453 mlt_properties properties = unit->properties;
454 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
455 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
456 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
457 mlt_producer_set_speed( producer, ( double )speed / 1000 );
458 mlt_consumer_start( consumer );
459 mlt_properties_set_int( MLT_CONSUMER_PROPERTIES(consumer), "refresh", 1 );
460 melted_unit_status_communicate( unit );
461 }
462
463 /** Stop playback.
464
465 Terminates the consumer and halts playout.
466
467 \param unit A melted_unit handle.
468 */
469
470 void melted_unit_terminate( melted_unit unit )
471 {
472 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
473 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
474 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
475 mlt_producer_set_speed( producer, 0 );
476 mlt_consumer_stop( consumer );
477 melted_unit_status_communicate( unit );
478 }
479
480 /** Query the status of unit playback.
481
482 \param unit A melted_unit handle.
483 \return 1 if the unit is not playing, 0 if playing.
484 */
485
486 int melted_unit_has_terminated( melted_unit unit )
487 {
488 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
489 return mlt_consumer_is_stopped( consumer );
490 }
491
492 /** Transfer the currently loaded clip to another unit
493 */
494
495 int melted_unit_transfer( melted_unit dest_unit, melted_unit src_unit )
496 {
497 int i;
498 mlt_properties dest_properties = dest_unit->properties;
499 mlt_playlist dest_playlist = mlt_properties_get_data( dest_properties, "playlist", NULL );
500 mlt_properties src_properties = src_unit->properties;
501 mlt_playlist src_playlist = mlt_properties_get_data( src_properties, "playlist", NULL );
502 mlt_playlist tmp_playlist = mlt_playlist_init( );
503
504 for ( i = 0; i < mlt_playlist_count( src_playlist ); i ++ )
505 {
506 mlt_playlist_clip_info info;
507 mlt_playlist_get_clip_info( src_playlist, &info, i );
508 if ( info.producer != NULL )
509 mlt_playlist_append_io( tmp_playlist, info.producer, info.frame_in, info.frame_out );
510 }
511
512 clear_unit( src_unit );
513
514 mlt_service_lock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
515
516 for ( i = 0; i < mlt_playlist_count( tmp_playlist ); i ++ )
517 {
518 mlt_playlist_clip_info info;
519 mlt_playlist_get_clip_info( tmp_playlist, &info, i );
520 if ( info.producer != NULL )
521 mlt_playlist_append_io( dest_playlist, info.producer, info.frame_in, info.frame_out );
522 }
523
524 mlt_service_unlock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
525
526 update_generation( dest_unit );
527 melted_unit_status_communicate( dest_unit );
528
529 mlt_playlist_close( tmp_playlist );
530
531 return 0;
532 }
533
534 /** Determine if unit is offline.
535 */
536
537 int melted_unit_is_offline( melted_unit unit )
538 {
539 return 0;
540 }
541
542 /** Obtain the status for a given unit
543 */
544
545 int melted_unit_get_status( melted_unit unit, mvcp_status status )
546 {
547 int error = unit == NULL;
548
549 memset( status, 0, sizeof( mvcp_status_t ) );
550
551 if ( !error )
552 {
553 mlt_properties properties = unit->properties;
554 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
555 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
556 mlt_producer clip = mlt_playlist_current( playlist );
557
558 mlt_playlist_clip_info info;
559 int clip_index = mlt_playlist_current_clip( playlist );
560 mlt_playlist_get_clip_info( playlist, &info, clip_index );
561
562 if ( info.resource != NULL && strcmp( info.resource, "" ) )
563 {
564 char *title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
565 if ( title == NULL )
566 title = strip_root( unit, info.resource );
567 strncpy( status->clip, title, sizeof( status->clip ) );
568 status->speed = (int)( mlt_producer_get_speed( producer ) * 1000.0 );
569 status->fps = info.fps;
570 status->in = info.frame_in;
571 status->out = info.frame_out;
572 status->position = mlt_producer_frame( clip );
573 status->length = mlt_producer_get_length( clip );
574 strncpy( status->tail_clip, title, sizeof( status->tail_clip ) );
575 status->tail_in = info.frame_in;
576 status->tail_out = info.frame_out;
577 status->tail_position = mlt_producer_frame( clip );
578 status->tail_length = mlt_producer_get_length( clip );
579 status->clip_index = mlt_playlist_current_clip( playlist );
580 status->seek_flag = 1;
581 }
582
583 status->generation = mlt_properties_get_int( properties, "generation" );
584
585 if ( melted_unit_has_terminated( unit ) )
586 status->status = unit_stopped;
587 else if ( !strcmp( status->clip, "" ) )
588 status->status = unit_not_loaded;
589 else if ( status->speed == 0 )
590 status->status = unit_paused;
591 else
592 status->status = unit_playing;
593 }
594 else
595 {
596 status->status = unit_undefined;
597 }
598
599 status->unit = mlt_properties_get_int( unit->properties, "unit" );
600
601 return error;
602 }
603
604 /** Change position in the playlist.
605 */
606
607 void melted_unit_change_position( melted_unit unit, int clip, int32_t position )
608 {
609 mlt_properties properties = unit->properties;
610 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
611 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
612 mlt_playlist_clip_info info;
613
614 if ( clip < 0 )
615 {
616 clip = 0;
617 position = 0;
618 }
619 else if ( clip >= mlt_playlist_count( playlist ) )
620 {
621 clip = mlt_playlist_count( playlist ) - 1;
622 position = INT_MAX;
623 }
624
625 if ( mlt_playlist_get_clip_info( playlist, &info, clip ) == 0 )
626 {
627 int32_t frame_start = info.start;
628 int32_t frame_offset = position;
629 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
630
631 if ( frame_offset < 0 )
632 frame_offset = info.frame_out;
633 if ( frame_offset < info.frame_in )
634 frame_offset = info.frame_in;
635 if ( frame_offset >= info.frame_out )
636 frame_offset = info.frame_out;
637
638 mlt_producer_seek( producer, frame_start + frame_offset - info.frame_in );
639 mlt_properties_set_int( MLT_CONSUMER_PROPERTIES(consumer), "refresh", 1 );
640 }
641
642 melted_unit_status_communicate( unit );
643 }
644
645 /** Get the index of the current clip.
646 */
647
648 int melted_unit_get_current_clip( melted_unit unit )
649 {
650 mlt_properties properties = unit->properties;
651 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
652 int clip_index = mlt_playlist_current_clip( playlist );
653 return clip_index;
654 }
655
656 /** Set a clip's in point
657 */
658
659 int melted_unit_set_clip_in( melted_unit unit, int index, int32_t position )
660 {
661 mlt_properties properties = unit->properties;
662 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
663 mlt_playlist_clip_info info;
664 int error = mlt_playlist_get_clip_info( playlist, &info, index );
665
666 if ( error == 0 )
667 {
668 melted_unit_play( unit, 0 );
669 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
670 error = mlt_playlist_resize_clip( playlist, index, position, info.frame_out );
671 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
672 update_generation( unit );
673 melted_unit_change_position( unit, index, 0 );
674 }
675
676 return error;
677 }
678
679 /** Set a clip's out point.
680 */
681
682 int melted_unit_set_clip_out( melted_unit unit, int index, int32_t position )
683 {
684 mlt_properties properties = unit->properties;
685 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
686 mlt_playlist_clip_info info;
687 int error = mlt_playlist_get_clip_info( playlist, &info, index );
688
689 if ( error == 0 )
690 {
691 melted_unit_play( unit, 0 );
692 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
693 error = mlt_playlist_resize_clip( playlist, index, info.frame_in, position );
694 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
695 update_generation( unit );
696 melted_unit_status_communicate( unit );
697 melted_unit_change_position( unit, index, -1 );
698 }
699
700 return error;
701 }
702
703 /** Step by specified position.
704 */
705
706 void melted_unit_step( melted_unit unit, int32_t offset )
707 {
708 mlt_properties properties = unit->properties;
709 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
710 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
711 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
712 mlt_position position = mlt_producer_frame( producer );
713 mlt_producer_seek( producer, position + offset );
714 mlt_properties_set_int( MLT_CONSUMER_PROPERTIES(consumer), "refresh", 1 );
715 }
716
717 /** Set the unit's clip mode regarding in and out points.
718 */
719
720 //void melted_unit_set_mode( melted_unit unit, dv_player_clip_mode mode )
721 //{
722 //dv_player player = melted_unit_get_dv_player( unit );
723 //if ( player != NULL )
724 //dv_player_set_clip_mode( player, mode );
725 //melted_unit_status_communicate( unit );
726 //}
727
728 /** Get the unit's clip mode regarding in and out points.
729 */
730
731 //dv_player_clip_mode melted_unit_get_mode( melted_unit unit )
732 //{
733 //dv_player player = melted_unit_get_dv_player( unit );
734 //return dv_player_get_clip_mode( player );
735 //}
736
737 /** Set the unit's clip mode regarding eof handling.
738 */
739
740 //void melted_unit_set_eof_action( melted_unit unit, dv_player_eof_action action )
741 //{
742 //dv_player player = melted_unit_get_dv_player( unit );
743 //dv_player_set_eof_action( player, action );
744 //melted_unit_status_communicate( unit );
745 //}
746
747 /** Get the unit's clip mode regarding eof handling.
748 */
749
750 //dv_player_eof_action melted_unit_get_eof_action( melted_unit unit )
751 //{
752 //dv_player player = melted_unit_get_dv_player( unit );
753 //return dv_player_get_eof_action( player );
754 //}
755
756 int melted_unit_set( melted_unit unit, char *name_value )
757 {
758 mlt_properties properties = NULL;
759
760 if ( strncmp( name_value, "consumer.", 9 ) )
761 {
762 if ( strncmp( name_value, "producer.", 9 ) )
763 {
764 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
765 properties = MLT_PLAYLIST_PROPERTIES( playlist );
766 }
767 else
768 {
769 properties = mlt_properties_get_data( unit->properties, "producer", NULL );
770 name_value += 9;
771 }
772 }
773 else
774 {
775 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
776 properties = MLT_CONSUMER_PROPERTIES( consumer );
777 name_value += 9;
778 }
779
780 return mlt_properties_parse( properties, name_value );
781 }
782
783 char *melted_unit_get( melted_unit unit, char *name )
784 {
785 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
786 mlt_properties properties = MLT_PLAYLIST_PROPERTIES( playlist );
787 return mlt_properties_get( properties, name );
788 }
789
790 /** Release the unit
791
792 \todo error handling
793 \param unit A melted_unit handle.
794 */
795
796 void melted_unit_close( melted_unit unit )
797 {
798 if ( unit != NULL )
799 {
800 melted_log( LOG_DEBUG, "closing unit..." );
801 melted_unit_terminate( unit );
802 mlt_properties_close( unit->properties );
803 free( unit );
804 melted_log( LOG_DEBUG, "... unit closed." );
805 }
806 }