bc8adcfb13b26d4e72c1d76e4aa5817eff1b72dd
[melted] / mlt / src / miracle / miracle_unit.c
1 /*
2 * dvunit.c -- DV Transmission Unit Implementation
3 * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
4 * Author: Dan Dennedy <dan@dennedy.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <sys/ioctl.h>
28 #include <sys/mman.h>
29 #include <sys/poll.h>
30 #include <sys/types.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <signal.h>
36
37 #include <libdv/dv1394.h>
38 #include <libraw1394/raw1394.h>
39 #include <libavc1394/avc1394_vcr.h>
40 #include <sys/mman.h>
41
42 #include "dvunit.h"
43 #include "dvframe.h"
44 #include "dvframepool.h"
45 #include "dvqueue.h"
46 #include "dvpump.h"
47 #include "dverror.h"
48 #include "dvplayer.h"
49 #include "raw1394util.h"
50 #include "log.h"
51 #include "dvlocal.h"
52
53 /* Forward references */
54 static void dv_unit_status_communicate( dv_unit );
55
56 /** dv1394 device file names based upon devfs default names. */
57
58 static char *devices[4][4] = {
59 {
60 "/dev/ieee1394/dv/host0/NTSC/in",
61 "/dev/ieee1394/dv/host0/NTSC/out",
62 "/dev/ieee1394/dv/host0/PAL/in",
63 "/dev/ieee1394/dv/host0/PAL/out",
64 },{
65 "/dev/ieee1394/dv/host1/NTSC/in",
66 "/dev/ieee1394/dv/host1/NTSC/out",
67 "/dev/ieee1394/dv/host1/PAL/in",
68 "/dev/ieee1394/dv/host1/PAL/out"
69 },{
70 "/dev/ieee1394/dv/host2/NTSC/in",
71 "/dev/ieee1394/dv/host2/NTSC/out",
72 "/dev/ieee1394/dv/host2/PAL/in",
73 "/dev/ieee1394/dv/host2/PAL/out"
74 },{
75 "/dev/ieee1394/dv/host3/NTSC/in",
76 "/dev/ieee1394/dv/host3/NTSC/out",
77 "/dev/ieee1394/dv/host3/PAL/in",
78 "/dev/ieee1394/dv/host3/PAL/out"
79 }
80 };
81
82 static int device_count[4] = {0,0,0,0};
83
84 /** Allocate a new DV transmission unit.
85
86 \param dv1394d_fd The file descriptor of a dv1394 device file to
87 use for transmission.
88 \param guid The node GUID of the receiving device.
89 \param channel The channel to use for transmission.
90 \return A new dv_unit handle.
91 */
92
93 dv_unit dv_unit_init( octlet_t guid, int channel )
94 {
95 dv_unit unit = malloc( sizeof( dv_unit_t ) );
96 if ( unit != NULL )
97 {
98 int node_id;
99
100 memset( unit, 0, sizeof( dv_unit_t ) );
101 unit->guid = guid;
102 unit->buffer_size = 25;
103 unit->is_terminated = 1;
104 unit->channel = channel;
105 unit->dv1394_fd = -1;
106 unit->n_frames = DV1394_MAX_FRAMES / 2;
107 unit->n_fill = 1;
108
109 /* get a raw1394 handle for plug control */
110 if ( ( node_id = raw1394_find_node( &(unit->raw1394), guid ) ) != -1 )
111 {
112 if ( dv_unit_online( unit ) == 1 )
113 dv1394d_log( LOG_DEBUG, "Added online unit with GUID %08x%08x",
114 (quadlet_t) (unit->guid>>32), (quadlet_t) (unit->guid & 0xffffffff) );
115 else
116 {
117 dv_unit_close( unit );
118 unit = NULL;
119 }
120 }
121 else
122 {
123 dv1394d_log( LOG_DEBUG, "Added offline unit with GUID %08x%08x",
124 (quadlet_t) (unit->guid>>32), (quadlet_t) (unit->guid & 0xffffffff) );
125 }
126 }
127 return unit;
128 }
129
130 /** Allow stdin to feed the unit (redundant now that senddv has been dropped).
131 */
132
133 void dv_unit_allow_stdin( dv_unit unit, int flag )
134 {
135 unit->allow_stdin = flag;
136 }
137
138 /** Override the default buffer/pump size - this must be done prior to the pumps
139 creation.
140 */
141
142 void dv_unit_set_buffer_size( dv_unit unit, int size )
143 {
144 if ( size > 0 )
145 {
146 if ( unit->pump == NULL )
147 unit->buffer_size = size;
148 else
149 unit->buffer_size = dv_pump_resize( unit->pump, size );
150 }
151 }
152
153 int dv_unit_get_buffer_size( dv_unit unit )
154 {
155 return unit->buffer_size;
156 }
157
158 void dv_unit_set_n_frames( dv_unit unit, int size )
159 {
160 if ( size > 0 && size <= DV1394_MAX_FRAMES / 2 )
161 unit->n_frames = size;
162 }
163
164 int dv_unit_get_n_frames( dv_unit unit )
165 {
166 return unit->n_frames;
167 }
168
169 void dv_unit_set_n_fill( dv_unit unit, int size )
170 {
171 unit->n_fill = size;
172 }
173
174 int dv_unit_get_n_fill( dv_unit unit )
175 {
176 return unit->n_fill;
177 }
178
179 /** Set the notifier info
180 */
181
182 void dv_unit_set_notifier( dv_unit this, dv1394_notifier notifier, char *root_dir )
183 {
184 this->notifier = notifier;
185 this->root_dir = root_dir;
186 dv_unit_status_communicate( this );
187 }
188
189 /** Communicate the current status to all threads waiting on the notifier.
190 */
191
192 static void dv_unit_status_communicate( dv_unit unit )
193 {
194 if ( unit != NULL && unit->notifier != NULL && unit->root_dir != NULL )
195 {
196 dv1394_status_t status;
197 if ( dv_unit_get_status( unit, &status ) == 0 )
198 if ( !( ( status.status == unit_playing || status.status == unit_paused ) &&
199 strcmp( status.clip, "" ) &&
200 !strcmp( status.tail_clip, "" ) &&
201 status.position == 0 &&
202 status.in == 0 &&
203 status.out == 0 ) )
204 dv1394_notifier_put( unit->notifier, &status );
205 }
206 }
207
208 /** Load a clip into the unit clearing existing play list.
209
210 \todo error handling
211 \param unit A dv_unit handle.
212 \param clip The absolute file name of the clip to load.
213 \param in The starting frame (-1 for 0)
214 \param out The ending frame (-1 for maximum)
215 */
216
217 dv_error_code dv_unit_load( dv_unit unit, const char *clip, long in, long out, int flush )
218 {
219 dv_player player = dv_unit_get_dv_player( unit );
220 dv_error_code error = dv_player_get_error( player );
221 if ( error == dv_pump_ok )
222 {
223 error = dv_player_replace_file( player, (char*) clip, in, out, flush );
224 dv1394d_log( LOG_DEBUG, "loaded clip %s", clip );
225 if ( unit->is_terminated )
226 dv_unit_status_communicate( unit );
227 }
228 return error;
229 }
230
231 dv_error_code dv_unit_insert( dv_unit unit, const char *clip, int index, long in, long out )
232 {
233 dv_player player = dv_unit_get_dv_player( unit );
234 dv_error_code error = dv_player_get_error( player );
235 if ( error == dv_pump_ok )
236 {
237 error = dv_player_insert_file( player, (char*) clip, index, in, out );
238 dv1394d_log( LOG_DEBUG, "inserted clip %s", clip );
239 if ( unit->is_terminated )
240 dv_unit_status_communicate( unit );
241 }
242 return error;
243 }
244
245 dv_error_code dv_unit_remove( dv_unit unit, int index )
246 {
247 dv_player player = dv_unit_get_dv_player( unit );
248 dv_error_code error = dv_player_get_error( player );
249 if ( error == dv_pump_ok )
250 {
251 error = dv_player_remove_clip( player, index );
252 dv1394d_log( LOG_DEBUG, "removed clip %d", index );
253 if ( unit->is_terminated )
254 dv_unit_status_communicate( unit );
255 }
256 return error;
257 }
258
259 dv_error_code dv_unit_clean( dv_unit unit )
260 {
261 dv_player player = dv_unit_get_dv_player( unit );
262 dv_error_code error = dv_player_get_error( player );
263 if ( error == dv_pump_ok )
264 {
265 error = dv_player_clean( player );
266 dv1394d_log( LOG_DEBUG, "Cleaned playlist" );
267 if ( unit->is_terminated )
268 dv_unit_status_communicate( unit );
269 }
270 return error;
271 }
272
273 dv_error_code dv_unit_move( dv_unit unit, int src, int dest )
274 {
275 dv_player player = dv_unit_get_dv_player( unit );
276 dv_error_code error = dv_player_get_error( player );
277 if ( error == dv_pump_ok )
278 {
279 error = dv_player_move_clip( player, src, dest );
280 dv1394d_log( LOG_DEBUG, "moved clip %d to %d", src, dest );
281 if ( unit->is_terminated )
282 dv_unit_status_communicate( unit );
283 }
284 return error;
285 }
286
287 /** Add a clip to the unit play list.
288
289 \todo error handling
290 \param unit A dv_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 dv_error_code dv_unit_append( dv_unit unit, const char *clip, long in, long out )
297 {
298 dv_player player = dv_unit_get_dv_player( unit );
299 dv_error_code error = dv_player_add_file( player, (char*) clip, in, out );
300 dv_unit_status_communicate( unit );
301 return error;
302 }
303
304 void *output_cleanup( void *arg )
305 {
306 dv_unit unit = arg;
307 if ( unit != NULL && unit->mmap != NULL )
308 {
309 unit->is_terminated = 1;
310 dv_unit_status_communicate( unit );
311 munmap( unit->mmap, unit->mmap_length );
312 /* this actually stops transmission as opposed to allowing the
313 last frame to loop in the OHCI DMA context. */
314 ioctl( unit->dv1394_fd, DV1394_SHUTDOWN, NULL );
315 }
316
317 return NULL;
318 }
319
320 /** The dv1394 transmission thread.
321
322 \param arg A dv_unit handle.
323 */
324
325 static void *output( void *arg )
326 {
327 dv_unit unit = arg;
328 dv_frame frames[ DV1394_MAX_FRAMES ];
329 int frames_dropped = 0; /* count of total frames dropped (repeated) */
330 struct dv1394_status status;
331 char errstr[64];
332 int n_fill = unit->n_fill;
333 int n_frames = unit->n_frames;
334
335 /* Determine the number of frames to wait for/fill on each iteration */
336 if ( n_fill < 1 )
337 n_fill = 1;
338 else if ( n_fill > unit->n_frames )
339 n_fill = n_frames / 2;
340
341 unit->mmap = mmap( NULL,unit->mmap_length,PROT_WRITE,MAP_SHARED,unit->dv1394_fd,0 );
342 if ( unit->mmap == MAP_FAILED || unit->mmap == NULL )
343 {
344 perror( "mmap" );
345 return NULL;
346 }
347
348 pthread_cleanup_push( output_cleanup, (void *)arg );
349
350 while ( dv_pump_get_available_output_count( unit->pump ) ||
351 !( dv_unit_has_terminated( unit ) || dv_pump_has_terminated( unit->pump) ) )
352 {
353 int available = 0;
354
355 if ( ioctl( unit->dv1394_fd, DV1394_WAIT_FRAMES, n_fill ) < 0)
356 perror( "DV1394_WAIT_FRAMES" );
357
358 pthread_testcancel();
359
360 /* update the status for the next iteration and detect dropped frames */
361 if ( ioctl( unit->dv1394_fd, DV1394_GET_STATUS, &status ) >= 0)
362 {
363 pthread_testcancel();
364
365 /*
366 printf( "dv1394 status: active=%02d, #clear=%02d, first clear=%02d\n",
367 status.active_frame, status.n_clear_frames, status.first_clear_frame);
368 */
369
370 /* report dropped frames */
371 if( status.dropped_frames > 0 )
372 {
373 frames_dropped += status.dropped_frames;
374 dv1394d_log( LOG_WARNING, "dv1394 repeated %d frames with %d available.",
375 status.dropped_frames, dv_pump_get_available_output_count( unit->pump ) );
376 }
377
378 available = dv_pump_get_output_block( unit->pump, (void **)frames, n_fill );
379
380 dv_unit_status_communicate( unit );
381
382 /* The only time we get 0 frames is when the unit is being stopped. */
383 if ( available != 0 )
384 {
385 int size = dv_frame_size( frames[ 0 ] );
386 int pos = status.first_clear_frame;
387 int index = 0;
388
389 for ( index = 0; index < available; index ++ )
390 memcpy( unit->mmap + ( ( pos + index ) % n_frames ) * size, dv_frame_data( frames[ index ] ), size );
391
392 if ( ioctl( unit->dv1394_fd, DV1394_SUBMIT_FRAMES, available ) >= 0)
393 {
394 for ( index = 0; index < available - 1; index ++ )
395 {
396 dv_frame_clear_error( frames[ index ] );
397 dv_frame_id_clear( dv_frame_get_id( frames[ index ] ) );
398 }
399 dv_pump_return_output_block( unit->pump );
400 pthread_testcancel();
401 }
402 else
403 {
404 dv1394d_log( LOG_ERR, "failed to write frames to dv1394: %s.", strerror_r( errno, errstr, 63 ) );
405 dv_pump_terminate( unit->pump );
406 dv_pump_flush( unit->pump );
407 pthread_testcancel();
408 }
409 }
410 }
411 else
412 {
413 dv1394d_log( LOG_ERR, "failed to get dv1394 status: %s.", strerror_r( errno, errstr, 63 ) );
414 dv_pump_return_used_output( unit->pump );
415 }
416 }
417
418 if ( frames_dropped > 0 )
419 dv1394d_log( LOG_WARNING, "dv1394 repeated %d frames total during this transmission.", frames_dropped );
420
421 pthread_cleanup_pop( 1 );
422
423 return NULL;
424 }
425
426 /** Start playing the clip.
427
428 Start a dv-pump and commence dv1394 transmission.
429
430 \todo error handling
431 \param unit A dv_unit handle.
432 \param speed An integer that specifies the playback rate as a
433 percentage multiplied by 100.
434 */
435
436 void dv_unit_play( dv_unit_t *unit, int speed )
437 {
438 dv_player player = dv_unit_get_dv_player( unit );
439
440 if ( unit->is_terminated == 1 && ( dv_player_get_total_frames( player ) > 0 || unit->allow_stdin ) )
441 {
442 int retval;
443 dv_frame frame = NULL;
444 struct dv1394_init setup =
445 {
446 api_version: DV1394_API_VERSION,
447 channel: unit->channel,
448 /* this only sets the *requested* size of the ringbuffer,
449 in frames */
450 n_frames: unit->n_frames,
451 /* we set the format later */
452 cip_n: unit->dv1394_cip_n,
453 cip_d: unit->dv1394_cip_d,
454 syt_offset: unit->dv1394_syt_offset
455 };
456 pthread_attr_t attr;
457
458 if ( unit->in == NULL )
459 {
460 if ( !unit->allow_stdin || dv_player_get_total_frames( player ) != 0 )
461 unit->in = dv_player_get_dv_input( player );
462 else
463 unit->in = dv_input_init( unit->pump );
464 }
465 else
466 {
467 dv_input_join_thread( unit->in );
468 pthread_join( unit->out, NULL );
469 }
470
471 unit->is_terminated = 0;
472 dv_pump_restart( unit->pump );
473 dv_input_start_thread( unit->in );
474 dv_player_set_speed( player, (double) speed/1000.0 );
475
476 /* first we read a little data to see if this is PAL or NTSC
477 so we can initialize dv1394 properly */
478 frame = dv_pump_get_available_output( unit->pump );
479
480 /* initialize dv1394 */
481 setup.format = dv_frame_is_pal(frame) ? DV1394_PAL : DV1394_NTSC;
482
483 retval = ioctl( unit->dv1394_fd, DV1394_INIT, &setup );
484 if (retval < 0)
485 {
486 perror( "DV1394_INIT" );
487 return;
488 }
489
490 unit->mmap_length = unit->n_frames * dv_frame_size( frame );
491
492 pthread_attr_init( &attr );
493 pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
494 pthread_attr_setinheritsched( &attr, PTHREAD_INHERIT_SCHED );
495 pthread_create( &unit->out, &attr, output, unit );
496 }
497 else
498 {
499 dv_player_set_speed( player, (double) speed/1000.0 );
500 }
501 dv_unit_status_communicate( unit );
502 }
503
504 /** Stop playback.
505
506 Terminates the dv_pump and halts dv1394 transmission.
507
508 \param unit A dv_unit handle.
509 */
510
511 void dv_unit_terminate( dv_unit unit )
512 {
513 unit->is_terminated = 1;
514 if ( unit->pump != NULL )
515 {
516 dv_pump_terminate( unit->pump );
517 dv_pump_flush( unit->pump );
518 }
519 }
520
521 /** Query the status of unit playback.
522
523 \param unit A dv_unit handle.
524 \return 1 if the unit is not playing, 0 if playing.
525 */
526
527 int dv_unit_has_terminated( dv_unit unit )
528 {
529 return unit->is_terminated;
530 }
531
532 /** Get the dv_player from the dv_unit.
533
534 \param unit A dv_unit handle.
535 \return A dv_player handle.
536 */
537
538 dv_player dv_unit_get_dv_player( dv_unit unit )
539 {
540 if ( unit != NULL )
541 {
542 if ( unit->pump == NULL )
543 {
544 unit->pump = dv_pump_init( unit->buffer_size );
545 if ( unit->pump != NULL )
546 unit->player = dv_player_init( unit->pump );
547 }
548 return unit->player;
549 }
550 return NULL;
551 }
552
553
554 /** Transfer the currently loaded clip to another unit
555 */
556
557 int dv_unit_transfer( dv_unit dest_unit, dv_unit src_unit )
558 {
559 dv_player src_player = dv_unit_get_dv_player( src_unit );
560 dv_player dest_player = dv_unit_get_dv_player( dest_unit );
561
562 if( dest_player != NULL && src_player != NULL )
563 dv_player_replace_player( dest_player, src_player );
564
565 return 0;
566 }
567
568 /** Get the guid associated to this unit.
569 */
570
571 octlet_t dv_unit_get_guid( dv_unit unit )
572 {
573 return unit->guid;
574 }
575
576 /** Get the node id associated to this unit.
577 */
578
579 int dv_unit_get_nodeid( dv_unit unit )
580 {
581 return (unit->node_id & 0x3f);
582 }
583
584 /** Get the channel associated to this unit.
585 */
586
587 int dv_unit_get_channel( dv_unit unit )
588 {
589 return (unit->channel);
590 }
591
592 /** Turn unit online.
593 */
594
595 int dv_unit_online( dv_unit unit )
596 {
597 int result = 0;
598 int port, node_id;
599
600 if ( unit->raw1394 != NULL )
601 raw1394_close( unit->raw1394 );
602
603 node_id = raw1394_find_node( &(unit->raw1394), unit->guid );
604 if ( node_id != -1 )
605 {
606 unit->node_id = 0xffc0 | node_id;
607 port = dv_unit_get_port( unit );
608
609 unit->dv1394_fd = open( devices[ port ][ device_count[port] ], O_RDWR );
610 if ( unit->dv1394_fd < 0 )
611 {
612 dv1394d_log( LOG_ERR, "failed to open dv1394 device - %s\n", devices[ port ][ device_count[port] ] );
613 dv_unit_close( unit );
614 }
615 else
616 {
617 device_count[ port ] ++;
618 if ( establish_p2p_connection( unit->raw1394, unit->node_id, (unsigned int *) &(unit->channel) ) )
619 {
620 avc1394_vcr_record( unit->raw1394, unit->node_id );
621 unit->online = 1;
622 dv_unit_status_communicate( unit );
623 result = 1;
624 }
625 }
626 }
627
628 return result;
629 }
630
631 /** Turn unit offline.
632 */
633
634 void dv_unit_offline( dv_unit unit )
635 {
636 if ( unit->online == 1 )
637 {
638 if ( unit->is_terminated == 0 )
639 dv_unit_terminate( unit );
640 unit->online = 0;
641 if ( unit->raw1394 != NULL )
642 {
643 avc1394_vcr_stop( unit->raw1394, unit->node_id );
644 break_p2p_connection( unit->raw1394, unit->node_id, unit->channel );
645 }
646 if ( unit->dv1394_fd > -1 )
647 {
648 close( unit->dv1394_fd );
649 device_count[ dv_unit_get_port( unit ) ] --;
650 }
651 dv_unit_status_communicate( unit );
652 dv1394d_log( LOG_DEBUG, "Unit with GUID %08x%08x is now offline.",
653 (quadlet_t) (unit->guid>>32), (quadlet_t) (unit->guid & 0xffffffff) );
654 }
655 }
656
657 /** Determine if unit is offline.
658 */
659
660 int dv_unit_is_offline( dv_unit unit )
661 {
662 return (unit->online == 0);
663 }
664
665 /** Obtain the status for a given unit
666 */
667
668 int dv_unit_get_status( dv_unit unit, dv1394_status status )
669 {
670 int error = -1;
671
672 memset( status, 0, sizeof( dv1394_status_t ) );
673
674 if ( unit != NULL )
675 {
676 dv_player player = dv_unit_get_dv_player( unit );
677
678 error = 0;
679
680 if ( player != NULL )
681 {
682 dv_frame head = dv_pump_get_head( player->pump );
683 dv_frame tail = dv_pump_get_tail( player->pump );
684
685 status->speed = (int)( dv_player_get_speed( player ) * 1000.0 );
686 status->fps = dv_player_frames_per_second( player, 0 );
687
688 if ( head != NULL )
689 {
690 dv_frame_id id = dv_frame_get_id( head );
691 if ( id->resource != NULL )
692 {
693 const char *resource = id->resource;
694 if ( resource != NULL && unit->root_dir != NULL )
695 resource += strlen( unit->root_dir ) - ( unit->root_dir[ strlen( unit->root_dir ) - 1 ] == '/' );
696 strncpy( status->clip, resource, sizeof( status->clip ) );
697 }
698 else
699 {
700 char *title = dv_player_get_name( player, dv_player_get_clip_containing( player, 0 ), unit->root_dir );
701 if ( title != NULL )
702 strncpy( status->clip, title, sizeof( status->clip ) );
703 }
704
705 status->position = id->relative;
706 status->in = id->in;
707 status->out = id->out;
708 status->length = id->length;
709 status->seek_flag = id->seek_flag;
710 }
711 else
712 {
713 char *title = dv_player_get_name( player, dv_player_get_clip_containing( player, 0 ), unit->root_dir );
714 if ( title != NULL )
715 strncpy( status->clip, title, sizeof( status->clip ) );
716 }
717
718 if ( tail != NULL )
719 {
720 dv_frame_id id = dv_frame_get_id( tail );
721 const char *resource = id->resource;
722 if ( resource != NULL && unit->root_dir != NULL )
723 resource += strlen( unit->root_dir ) - ( unit->root_dir[ strlen( unit->root_dir ) - 1 ] == '/' );
724 if ( resource != NULL )
725 strncpy( status->tail_clip, resource, sizeof( status->clip ) );
726 status->tail_position = id->relative;
727 status->tail_in = id->in;
728 status->tail_out = id->out;
729 status->tail_length = id->length;
730 }
731
732 status->generation = player->generation;
733 status->clip_index = dv_unit_get_current_clip( unit );
734 }
735
736 if ( dv_unit_is_offline( unit ) )
737 status->status = unit_offline;
738 else if ( !strcmp( status->clip, "" ) )
739 status->status = unit_not_loaded;
740 else if ( dv_unit_has_terminated( unit ) )
741 status->status = unit_stopped;
742 else if ( status->speed == 0 )
743 status->status = unit_paused;
744 else
745 status->status = unit_playing;
746 }
747 else
748 {
749 status->status = unit_undefined;
750 }
751
752 status->unit = unit->unit;
753
754 return error;
755 }
756
757 /** Change position in the playlist.
758 */
759
760 void dv_unit_change_position( dv_unit unit, int clip, long position )
761 {
762 dv_player player = dv_unit_get_dv_player( unit );
763 dv_player_set_clip_position( player, clip, position );
764 dv_unit_status_communicate( unit );
765 }
766
767 /** Change speed.
768 */
769
770 void dv_unit_change_speed( dv_unit unit, int speed )
771 {
772 if ( dv_unit_has_terminated( unit ) )
773 dv_unit_change_position( unit, 0, 0 );
774 else
775 dv_unit_play( unit, speed );
776 }
777
778 int dv_unit_get_current_clip( dv_unit unit )
779 {
780 dv_player player = dv_unit_get_dv_player( unit );
781 unsigned long position = dv_player_get_position( player );
782 return dv_player_get_clip_containing( player, position );
783 }
784
785 /** Set a clip's in point
786 */
787
788 int dv_unit_set_clip_in( dv_unit unit, int index, long position )
789 {
790 int error = 0;
791 dv_player player = dv_unit_get_dv_player( unit );
792
793 if ( player != NULL )
794 {
795 dv_unit_change_speed( unit, 0 );
796 if ( dv_player_set_in_point( player, index, (unsigned long) position ) == position )
797 dv_player_set_clip_position( player, index, position );
798 else
799 error = -2;
800 }
801 else
802 {
803 error = -1;
804 }
805
806 dv_unit_status_communicate( unit );
807
808 return error;
809
810 }
811
812 /** Set a clip's out point.
813 */
814
815 int dv_unit_set_clip_out( dv_unit unit, int index, long position )
816 {
817 int error = 0;
818 dv_player player = dv_unit_get_dv_player( unit );
819
820 if ( player != NULL )
821 {
822 dv_unit_change_speed( unit, 0 );
823 if ( dv_player_set_out_point( player, index, position ) == position )
824 dv_player_set_clip_position( player, index, position );
825 else
826 error = -2;
827 }
828 else
829 {
830 error = -1;
831 }
832
833 dv_unit_status_communicate( unit );
834
835 return error;
836 }
837
838 /** Step by specified position.
839 */
840
841 void dv_unit_step( dv_unit unit, int offset )
842 {
843 dv_player player = dv_unit_get_dv_player( unit );
844 dv_player_change_position( player, dv_seek_relative, offset );
845 }
846
847 /** Set the unit's clip mode regarding in and out points.
848 */
849
850 void dv_unit_set_mode( dv_unit unit, dv_player_clip_mode mode )
851 {
852 dv_player player = dv_unit_get_dv_player( unit );
853 if ( player != NULL )
854 dv_player_set_clip_mode( player, mode );
855 dv_unit_status_communicate( unit );
856 }
857
858 /** Get the unit's clip mode regarding in and out points.
859 */
860
861 dv_player_clip_mode dv_unit_get_mode( dv_unit unit )
862 {
863 dv_player player = dv_unit_get_dv_player( unit );
864 return dv_player_get_clip_mode( player );
865 }
866
867 /** Set the unit's clip mode regarding eof handling.
868 */
869
870 void dv_unit_set_eof_action( dv_unit unit, dv_player_eof_action action )
871 {
872 dv_player player = dv_unit_get_dv_player( unit );
873 dv_player_set_eof_action( player, action );
874 dv_unit_status_communicate( unit );
875 }
876
877 /** Get the unit's clip mode regarding eof handling.
878 */
879
880 dv_player_eof_action dv_unit_get_eof_action( dv_unit unit )
881 {
882 dv_player player = dv_unit_get_dv_player( unit );
883 return dv_player_get_eof_action( player );
884 }
885
886 /** Release the unit
887
888 \todo error handling
889 \param unit A dv_unit handle.
890 */
891
892 void dv_unit_close( dv_unit unit )
893 {
894 if ( unit != NULL )
895 {
896 dv1394d_log( LOG_DEBUG, "closing unit..." );
897 dv_unit_offline( unit );
898 if ( unit->pump != NULL )
899 {
900 dv_pump_terminate( unit->pump );
901 dv_pump_flush( unit->pump );
902 dv_pump_return_used_output( unit->pump );
903 dv_input_join_thread( unit->in );
904 if ( !unit->is_terminated )
905 pthread_join( unit->out, NULL );
906 dv_pump_close( unit->pump );
907 unit->pump = NULL;
908 }
909 raw1394_close( unit->raw1394 );
910 free( unit );
911 dv1394d_log( LOG_DEBUG, "... unit closed." );
912 }
913 }
914
915 /** Get the raw1394 port associated to this unit.
916 */
917
918 int dv_unit_get_port( dv_unit unit )
919 {
920 if ( unit->raw1394 != NULL )
921 return (int) raw1394_get_userdata( unit->raw1394 );
922 else
923 return -1;
924 }
925
926 /** Set the dv1394 file descriptor for the unit.
927 */
928
929 void dv_unit_set_dv1394_fd( dv_unit unit, int fd )
930 {
931 unit->dv1394_fd = fd;
932 }
933
934 /** Get the dv1394 syt_offset (timestamp latency) property.
935 */
936
937 unsigned int dv_unit_get_syt_offset( dv_unit unit )
938 {
939 return unit->dv1394_syt_offset;
940 }
941
942 /** Get the dv1394 cip_n (timing numerator) property.
943 */
944
945 unsigned int dv_unit_get_cip_n( dv_unit unit )
946 {
947 return unit->dv1394_cip_n;
948 }
949
950 /** Get the dv1394 cip_d (timing denominator) property.
951 */
952
953 unsigned int dv_unit_get_cip_d( dv_unit unit )
954 {
955 return unit->dv1394_cip_d;
956 }
957
958 /** Set the dv1394 syt_offset (timestamp latency) property.
959
960 Stops and restarts the unit if playing.
961 */
962
963 void dv_unit_set_syt_offset( dv_unit unit, unsigned int syt_offset )
964 {
965 int restart = !unit->is_terminated;
966 int speed = (int)( dv_player_get_speed( dv_unit_get_dv_player(unit) ) * 1000.0 );
967
968 dv_unit_terminate( unit );
969 unit->dv1394_syt_offset = syt_offset;
970 if ( restart )
971 dv_unit_play( unit, speed );
972 }
973
974 /** Set the dv1394 cip_n (timing numerator) property.
975
976 Stops and restarts the unit if playing.
977 */
978
979 void dv_unit_set_cip_n( dv_unit unit, unsigned int cip_n )
980 {
981 int restart = !unit->is_terminated;
982 int speed = (int)( dv_player_get_speed( dv_unit_get_dv_player(unit) ) * 1000.0 );
983
984 dv_unit_terminate( unit );
985 unit->dv1394_cip_n = cip_n;
986 if ( restart )
987 dv_unit_play( unit, speed );
988 }
989
990 /** Set the dv1394 cip_d (timing denominator) property.
991
992 Stops and restarts the unit if playing.
993 */
994
995 void dv_unit_set_cip_d( dv_unit unit, unsigned int cip_d )
996 {
997 int restart = !unit->is_terminated;
998 int speed = (int)( dv_player_get_speed( dv_unit_get_dv_player(unit) ) * 1000.0 );
999
1000 dv_unit_terminate( unit );
1001 unit->dv1394_cip_d = cip_d;
1002 if ( restart )
1003 dv_unit_play( unit, speed );
1004 }
1005
1006 /** Terminate, but only the output thread and close dv1394.
1007 */
1008
1009 void dv_unit_suspend( dv_unit unit )
1010 {
1011 if ( unit->is_terminated == 0 )
1012 {
1013 unit->is_terminated = 1;
1014 unit->is_suspended = 1;
1015 dv_pump_terminate( unit->pump );
1016 dv_pump_flush( unit->pump );
1017 pthread_cancel( unit->out );
1018 }
1019 if ( unit->dv1394_fd > -1 )
1020 {
1021 close( unit->dv1394_fd );
1022 device_count[ dv_unit_get_port( unit ) ] --;
1023 }
1024 unit->dv1394_fd = -1;
1025 dv_unit_status_communicate( unit );
1026 }
1027
1028
1029 /** Restore unit on the bus, re-open dv1394, start playback if pump is running.
1030 */
1031
1032 void dv_unit_restore( dv_unit unit )
1033 {
1034 int result = 0;
1035 int port, node_id;
1036
1037 if ( unit->raw1394 != NULL )
1038 raw1394_close( unit->raw1394 );
1039
1040 node_id = raw1394_find_node( &(unit->raw1394), unit->guid );
1041 if ( node_id != -1 )
1042 {
1043 unit->node_id = 0xffc0 | node_id;
1044 port = dv_unit_get_port( unit );
1045
1046 unit->dv1394_fd = open( devices[ port ][ device_count[port] ], O_RDWR );
1047 if ( unit->dv1394_fd < 0 )
1048 {
1049 dv1394d_log( LOG_ERR, "failed to open dv1394 device - %s\n", devices[ port ][ device_count[port] ] );
1050 dv_unit_close( unit );
1051 }
1052 else
1053 {
1054 device_count[ port ] ++;
1055 break_p2p_connection( unit->raw1394, unit->node_id, unit->channel );
1056 if ( establish_p2p_connection( unit->raw1394, unit->node_id, (unsigned int *) &(unit->channel) ) )
1057 {
1058 avc1394_vcr_record( unit->raw1394, unit->node_id );
1059 unit->online = 1;
1060 result = 1;
1061 }
1062 }
1063 }
1064 if ( unit->is_suspended == 1 )
1065 {
1066 int retval;
1067 dv_frame frame = dv_pump_get_available_output( unit->pump );
1068 struct dv1394_init setup =
1069 {
1070 api_version: DV1394_API_VERSION,
1071 channel: unit->channel,
1072 /* this only sets the *requested* size of the ringbuffer,
1073 in frames */
1074 n_frames: unit->n_frames,
1075 format: dv_frame_is_pal(frame) ? DV1394_PAL : DV1394_NTSC,
1076 cip_n: unit->dv1394_cip_n,
1077 cip_d: unit->dv1394_cip_d,
1078 syt_offset: unit->dv1394_syt_offset
1079 };
1080 pthread_attr_t attr;
1081
1082 dv_input_join_thread( unit->in );
1083 unit->is_terminated = 0;
1084 unit->is_suspended = 0;
1085 dv_pump_restart( unit->pump );
1086 dv_input_start_thread( unit->in );
1087
1088 /* initialize dv1394 */
1089 retval = ioctl( unit->dv1394_fd, DV1394_INIT, &setup );
1090 if ( retval < 0 )
1091 return;
1092
1093 pthread_attr_init( &attr );
1094 pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
1095 pthread_attr_setinheritsched( &attr, PTHREAD_INHERIT_SCHED );
1096 /* pthread_attr_setschedpolicy( &attr, SCHED_RR ); */
1097 pthread_create( &unit->out, &attr, output, unit );
1098 }
1099 dv_unit_status_communicate( unit );
1100 }