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