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