Try to fix segfault (3306947).
[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 #include <time.h>
38
39 #include <sys/mman.h>
40
41 #include "melted_unit.h"
42 #include "melted_log.h"
43 #include "melted_local.h"
44
45 #include <framework/mlt.h>
46
47 /* Forward references */
48 static void melted_unit_status_communicate( melted_unit );
49
50 /** Allocate a new playout unit.
51
52 \return A new melted_unit handle.
53 */
54
55 melted_unit melted_unit_init( int index, char *constructor )
56 {
57 melted_unit this = NULL;
58 mlt_consumer consumer = NULL;
59
60 char *id = strdup( constructor );
61 char *arg = strchr( id, ':' );
62
63 if ( arg != NULL )
64 *arg ++ = '\0';
65
66 consumer = mlt_factory_consumer( NULL, id, arg );
67
68 if ( consumer != NULL )
69 {
70 mlt_playlist playlist = mlt_playlist_init( );
71 this = calloc( sizeof( melted_unit_t ), 1 );
72 this->properties = mlt_properties_new( );
73 mlt_properties_init( this->properties, this );
74 mlt_properties_set_int( this->properties, "unit", index );
75 mlt_properties_set_int( this->properties, "generation", 0 );
76 mlt_properties_set( this->properties, "constructor", constructor );
77 mlt_properties_set( this->properties, "id", id );
78 mlt_properties_set( this->properties, "arg", arg );
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_profile profile = NULL;
153
154 if ( consumer != NULL )
155 {
156 profile = mlt_service_profile( MLT_CONSUMER_SERVICE( consumer ) );
157 }
158 return mlt_factory_producer( profile, NULL, file );
159 }
160
161 /** Update the generation count.
162 */
163
164 static void update_generation( melted_unit unit )
165 {
166 mlt_properties properties = unit->properties;
167 int generation = mlt_properties_get_int( properties, "generation" );
168 mlt_properties_set_int( properties, "generation", ++ generation );
169 }
170
171 /** Wipe all clips on the playlist for this unit.
172 */
173
174 static void clear_unit( melted_unit unit )
175 {
176 mlt_properties properties = unit->properties;
177 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
178 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
179
180 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
181 mlt_playlist_clear( playlist );
182 mlt_producer_seek( producer, 0 );
183 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
184
185 update_generation( unit );
186 }
187
188 /** Wipe all but the playing clip from the unit.
189 */
190
191 static void clean_unit( melted_unit unit )
192 {
193 mlt_properties properties = unit->properties;
194 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
195 mlt_playlist_clip_info info;
196 int current = mlt_playlist_current_clip( playlist );
197 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
198 mlt_position position = mlt_producer_frame( producer );
199 double speed = mlt_producer_get_speed( producer );
200 mlt_playlist_get_clip_info( playlist, &info, current );
201
202 if ( info.producer != NULL )
203 {
204 mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( info.producer ) );
205 position -= info.start;
206 clear_unit( unit );
207 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
208 mlt_playlist_append_io( playlist, info.producer, info.frame_in, info.frame_out );
209 mlt_producer_seek( producer, position );
210 mlt_producer_set_speed( producer, speed );
211 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
212 mlt_producer_close( info.producer );
213 }
214
215 update_generation( unit );
216 }
217
218 /** Remove everything up to the current clip from the unit.
219 */
220
221 static void wipe_unit( melted_unit unit )
222 {
223 mlt_properties properties = unit->properties;
224 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
225 mlt_playlist_clip_info info;
226 int current = mlt_playlist_current_clip( playlist );
227 mlt_playlist_get_clip_info( playlist, &info, current );
228
229 if ( info.producer != NULL && info.start > 0 )
230 {
231 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
232 mlt_playlist_remove_region( playlist, 0, info.start - 1 );
233 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
234 }
235
236 update_generation( unit );
237 }
238
239 /** Generate a report on all loaded clips.
240 */
241
242 void melted_unit_report_list( melted_unit unit, mvcp_response response )
243 {
244 int i;
245 mlt_properties properties = unit->properties;
246 int generation = mlt_properties_get_int( properties, "generation" );
247 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
248
249 mvcp_response_printf( response, 1024, "%d\n", generation );
250
251 for ( i = 0; i < mlt_playlist_count( playlist ); i ++ )
252 {
253 mlt_playlist_clip_info info;
254 char *title;
255 mlt_playlist_get_clip_info( playlist , &info, i );
256 title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
257 if ( title == NULL )
258 title = strip_root( unit, info.resource );
259 mvcp_response_printf( response, 10240, "%d \"%s\" %d %d %d %d %.2f\n",
260 i,
261 title,
262 info.frame_in,
263 info.frame_out,
264 info.frame_count,
265 info.length,
266 info.fps );
267 }
268 mvcp_response_printf( response, 1024, "\n" );
269 }
270
271 /** Load a clip into the unit clearing existing play list.
272
273 \todo error handling
274 \param unit A melted_unit handle.
275 \param clip The absolute file name of the clip to load.
276 \param in The starting frame (-1 for 0)
277 \param out The ending frame (-1 for maximum)
278 */
279
280 mvcp_error_code melted_unit_load( melted_unit unit, char *clip, int32_t in, int32_t out, int flush )
281 {
282 // Now try to create a producer
283 mlt_producer instance = locate_producer( unit, clip );
284
285 if ( instance != NULL )
286 {
287 mlt_properties properties = unit->properties;
288 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
289 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
290 int original = mlt_producer_get_playtime( producer );
291 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
292 double speed = mlt_producer_get_speed( producer );
293 struct timespec tm = { 1, 0 };
294
295 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
296 mlt_playlist_append_io( playlist, instance, in, out );
297 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
298 // We try to ensure all frames from producers that will be removed are closed.
299 mlt_producer_seek( producer, original );
300 mlt_consumer_purge( consumer );
301
302 melted_log( LOG_DEBUG, "loaded clip %s", clip );
303 update_generation( unit );
304 melted_unit_status_communicate( unit );
305 mlt_producer_close( instance );
306
307 // Give more time for those frames to be closed - there could still be some
308 // in the consumer plugin that were not purged from the base consumer buffer.
309 nanosleep( &tm, NULL );
310 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
311 mlt_playlist_remove_region( playlist, 0, original );
312 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
313
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 melted_unit_status_communicate( unit );
460 }
461
462 /** Stop playback.
463
464 Terminates the consumer and halts playout.
465
466 \param unit A melted_unit handle.
467 */
468
469 void melted_unit_terminate( melted_unit unit )
470 {
471 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
472 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
473 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
474 mlt_producer_set_speed( producer, 0 );
475 mlt_consumer_stop( consumer );
476 melted_unit_status_communicate( unit );
477 }
478
479 /** Query the status of unit playback.
480
481 \param unit A melted_unit handle.
482 \return 1 if the unit is not playing, 0 if playing.
483 */
484
485 int melted_unit_has_terminated( melted_unit unit )
486 {
487 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
488 return mlt_consumer_is_stopped( consumer );
489 }
490
491 /** Transfer the currently loaded clip to another unit
492 */
493
494 int melted_unit_transfer( melted_unit dest_unit, melted_unit src_unit )
495 {
496 int i;
497 mlt_properties dest_properties = dest_unit->properties;
498 mlt_playlist dest_playlist = mlt_properties_get_data( dest_properties, "playlist", NULL );
499 mlt_properties src_properties = src_unit->properties;
500 mlt_playlist src_playlist = mlt_properties_get_data( src_properties, "playlist", NULL );
501 mlt_playlist tmp_playlist = mlt_playlist_init( );
502
503 for ( i = 0; i < mlt_playlist_count( src_playlist ); i ++ )
504 {
505 mlt_playlist_clip_info info;
506 mlt_playlist_get_clip_info( src_playlist, &info, i );
507 if ( info.producer != NULL )
508 mlt_playlist_append_io( tmp_playlist, info.producer, info.frame_in, info.frame_out );
509 }
510
511 clear_unit( src_unit );
512
513 mlt_service_lock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
514
515 for ( i = 0; i < mlt_playlist_count( tmp_playlist ); i ++ )
516 {
517 mlt_playlist_clip_info info;
518 mlt_playlist_get_clip_info( tmp_playlist, &info, i );
519 if ( info.producer != NULL )
520 mlt_playlist_append_io( dest_playlist, info.producer, info.frame_in, info.frame_out );
521 }
522
523 mlt_service_unlock( MLT_PLAYLIST_SERVICE( dest_playlist ) );
524
525 update_generation( dest_unit );
526 melted_unit_status_communicate( dest_unit );
527
528 mlt_playlist_close( tmp_playlist );
529
530 return 0;
531 }
532
533 /** Determine if unit is offline.
534 */
535
536 int melted_unit_is_offline( melted_unit unit )
537 {
538 return 0;
539 }
540
541 /** Obtain the status for a given unit
542 */
543
544 int melted_unit_get_status( melted_unit unit, mvcp_status status )
545 {
546 int error = unit == NULL;
547
548 memset( status, 0, sizeof( mvcp_status_t ) );
549
550 if ( !error )
551 {
552 mlt_properties properties = unit->properties;
553 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
554 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
555 mlt_producer clip = mlt_playlist_current( playlist );
556
557 mlt_playlist_clip_info info;
558 int clip_index = mlt_playlist_current_clip( playlist );
559 mlt_playlist_get_clip_info( playlist, &info, clip_index );
560
561 if ( info.resource != NULL && strcmp( info.resource, "" ) )
562 {
563 char *title = mlt_properties_get( MLT_PRODUCER_PROPERTIES( info.producer ), "title" );
564 if ( title == NULL )
565 title = strip_root( unit, info.resource );
566 strncpy( status->clip, title, sizeof( status->clip ) );
567 status->speed = (int)( mlt_producer_get_speed( producer ) * 1000.0 );
568 status->fps = mlt_producer_get_fps( producer );
569 status->in = info.frame_in;
570 status->out = info.frame_out;
571 status->position = mlt_producer_frame( clip );
572 status->length = mlt_producer_get_length( clip );
573 strncpy( status->tail_clip, title, sizeof( status->tail_clip ) );
574 status->tail_in = info.frame_in;
575 status->tail_out = info.frame_out;
576 status->tail_position = mlt_producer_frame( clip );
577 status->tail_length = mlt_producer_get_length( clip );
578 status->clip_index = mlt_playlist_current_clip( playlist );
579 status->seek_flag = 1;
580 }
581
582 status->generation = mlt_properties_get_int( properties, "generation" );
583
584 if ( melted_unit_has_terminated( unit ) )
585 status->status = unit_stopped;
586 else if ( !strcmp( status->clip, "" ) )
587 status->status = unit_not_loaded;
588 else if ( status->speed == 0 )
589 status->status = unit_paused;
590 else
591 status->status = unit_playing;
592 }
593 else
594 {
595 status->status = unit_undefined;
596 }
597
598 status->unit = mlt_properties_get_int( unit->properties, "unit" );
599
600 return error;
601 }
602
603 /** Change position in the playlist.
604 */
605
606 void melted_unit_change_position( melted_unit unit, int clip, int32_t position )
607 {
608 mlt_properties properties = unit->properties;
609 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
610 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
611 mlt_playlist_clip_info info;
612
613 if ( clip < 0 )
614 {
615 clip = 0;
616 position = 0;
617 }
618 else if ( clip >= mlt_playlist_count( playlist ) )
619 {
620 clip = mlt_playlist_count( playlist ) - 1;
621 position = INT_MAX;
622 }
623
624 if ( mlt_playlist_get_clip_info( playlist, &info, clip ) == 0 )
625 {
626 int32_t frame_start = info.start;
627 int32_t frame_offset = position;
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 }
638
639 melted_unit_status_communicate( unit );
640 }
641
642 /** Get the index of the current clip.
643 */
644
645 int melted_unit_get_current_clip( melted_unit unit )
646 {
647 mlt_properties properties = unit->properties;
648 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
649 int clip_index = mlt_playlist_current_clip( playlist );
650 return clip_index;
651 }
652
653 /** Set a clip's in point
654 */
655
656 int melted_unit_set_clip_in( melted_unit unit, int index, int32_t position )
657 {
658 mlt_properties properties = unit->properties;
659 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
660 mlt_playlist_clip_info info;
661 int error = mlt_playlist_get_clip_info( playlist, &info, index );
662
663 if ( error == 0 )
664 {
665 melted_unit_play( unit, 0 );
666 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
667 error = mlt_playlist_resize_clip( playlist, index, position, info.frame_out );
668 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
669 update_generation( unit );
670 melted_unit_change_position( unit, index, 0 );
671 }
672
673 return error;
674 }
675
676 /** Set a clip's out point.
677 */
678
679 int melted_unit_set_clip_out( melted_unit unit, int index, int32_t position )
680 {
681 mlt_properties properties = unit->properties;
682 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
683 mlt_playlist_clip_info info;
684 int error = mlt_playlist_get_clip_info( playlist, &info, index );
685
686 if ( error == 0 )
687 {
688 melted_unit_play( unit, 0 );
689 mlt_service_lock( MLT_PLAYLIST_SERVICE( playlist ) );
690 error = mlt_playlist_resize_clip( playlist, index, info.frame_in, position );
691 mlt_service_unlock( MLT_PLAYLIST_SERVICE( playlist ) );
692 update_generation( unit );
693 melted_unit_status_communicate( unit );
694 melted_unit_change_position( unit, index, -1 );
695 }
696
697 return error;
698 }
699
700 /** Step by specified position.
701 */
702
703 void melted_unit_step( melted_unit unit, int32_t offset )
704 {
705 mlt_properties properties = unit->properties;
706 mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL );
707 mlt_producer producer = MLT_PLAYLIST_PRODUCER( playlist );
708 mlt_position position = mlt_producer_frame( producer );
709 mlt_producer_seek( producer, position + offset );
710 }
711
712 /** Set the unit's clip mode regarding in and out points.
713 */
714
715 //void melted_unit_set_mode( melted_unit unit, dv_player_clip_mode mode )
716 //{
717 //dv_player player = melted_unit_get_dv_player( unit );
718 //if ( player != NULL )
719 //dv_player_set_clip_mode( player, mode );
720 //melted_unit_status_communicate( unit );
721 //}
722
723 /** Get the unit's clip mode regarding in and out points.
724 */
725
726 //dv_player_clip_mode melted_unit_get_mode( melted_unit unit )
727 //{
728 //dv_player player = melted_unit_get_dv_player( unit );
729 //return dv_player_get_clip_mode( player );
730 //}
731
732 /** Set the unit's clip mode regarding eof handling.
733 */
734
735 //void melted_unit_set_eof_action( melted_unit unit, dv_player_eof_action action )
736 //{
737 //dv_player player = melted_unit_get_dv_player( unit );
738 //dv_player_set_eof_action( player, action );
739 //melted_unit_status_communicate( unit );
740 //}
741
742 /** Get the unit's clip mode regarding eof handling.
743 */
744
745 //dv_player_eof_action melted_unit_get_eof_action( melted_unit unit )
746 //{
747 //dv_player player = melted_unit_get_dv_player( unit );
748 //return dv_player_get_eof_action( player );
749 //}
750
751 int melted_unit_set( melted_unit unit, char *name_value )
752 {
753 mlt_properties properties = NULL;
754
755 if ( strncmp( name_value, "consumer.", 9 ) )
756 {
757 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
758 properties = MLT_PLAYLIST_PROPERTIES( playlist );
759 }
760 else
761 {
762 mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL );
763 properties = MLT_CONSUMER_PROPERTIES( consumer );
764 name_value += 9;
765 }
766
767 return mlt_properties_parse( properties, name_value );
768 }
769
770 char *melted_unit_get( melted_unit unit, char *name )
771 {
772 mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL );
773 mlt_properties properties = MLT_PLAYLIST_PROPERTIES( playlist );
774 return mlt_properties_get( properties, name );
775 }
776
777 /** Release the unit
778
779 \todo error handling
780 \param unit A melted_unit handle.
781 */
782
783 void melted_unit_close( melted_unit unit )
784 {
785 if ( unit != NULL )
786 {
787 melted_log( LOG_DEBUG, "closing unit..." );
788 melted_unit_terminate( unit );
789 mlt_properties_close( unit->properties );
790 free( unit );
791 melted_log( LOG_DEBUG, "... unit closed." );
792 }
793 }