mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
mlt_multitrack multitrack = mlt_properties_get_data( properties, "multitrack", NULL );
mlt_consumer consumer = mlt_properties_get_data( properties, "transport_consumer", NULL );
+ mlt_properties jack = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES( consumer ), "jack_filter", NULL );
+ mlt_position position = mlt_producer_position( producer );
mlt_properties_set_int( properties, "stats_off", 1 );
case 'q':
case 'Q':
mlt_properties_set_int( properties, "done", 1 );
+ mlt_events_fire( jack, "jack-stop", NULL );
break;
case '0':
+ position = 0;
mlt_producer_set_speed( producer, 1 );
- mlt_producer_seek( producer, 0 );
+ mlt_producer_seek( producer, position );
+ mlt_consumer_purge( consumer );
+ mlt_events_fire( jack, "jack-seek", &position, NULL );
break;
case '1':
mlt_producer_set_speed( producer, -10 );
break;
case '5':
mlt_producer_set_speed( producer, 0 );
+ mlt_consumer_purge( consumer );
+ mlt_events_fire( jack, "jack-stop", NULL );
break;
case '6':
case ' ':
- mlt_producer_set_speed( producer, 1 );
+ if ( !jack || mlt_producer_get_speed( producer ) != 0 )
+ mlt_producer_set_speed( producer, 1 );
+ mlt_consumer_purge( consumer );
+ mlt_events_fire( jack, "jack-start", NULL );
break;
case '7':
mlt_producer_set_speed( producer, 2 );
fprintf( stderr, "\n" );
for ( i = 0; 1; i ++ )
{
- mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_start, i );
- if ( time == last )
+ position = mlt_multitrack_clip( multitrack, mlt_whence_relative_start, i );
+ if ( position == last )
break;
- last = time;
- fprintf( stderr, "%d: %d\n", i, (int)time );
+ last = position;
+ fprintf( stderr, "%d: %d\n", i, (int)position );
}
}
break;
case 'g':
if ( multitrack != NULL )
{
- mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 0 );
- mlt_producer_seek( producer, time );
+ position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 0 );
+ mlt_producer_seek( producer, position );
+ mlt_consumer_purge( consumer );
+ mlt_events_fire( jack, "jack-seek", &position, NULL );
}
break;
case 'H':
if ( producer != NULL )
{
- mlt_position position = mlt_producer_position( producer );
- mlt_producer_seek( producer, position - ( mlt_producer_get_fps( producer ) * 60 ) );
+ position -= mlt_producer_get_fps( producer ) * 60;
+ mlt_consumer_purge( consumer );
+ mlt_producer_seek( producer, position );
+ mlt_events_fire( jack, "jack-seek", &position, NULL );
}
break;
case 'h':
if ( producer != NULL )
{
- mlt_position position = mlt_producer_position( producer );
+ position--;
mlt_producer_set_speed( producer, 0 );
- mlt_producer_seek( producer, position - 1 );
+ mlt_consumer_purge( consumer );
+ mlt_producer_seek( producer, position );
+ mlt_events_fire( jack, "jack-stop", NULL );
+ mlt_events_fire( jack, "jack-seek", &position, NULL );
}
break;
case 'j':
if ( multitrack != NULL )
{
- mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 1 );
- mlt_producer_seek( producer, time );
+ position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, 1 );
+ mlt_consumer_purge( consumer );
+ mlt_producer_seek( producer, position );
+ mlt_events_fire( jack, "jack-seek", &position, NULL );
}
break;
case 'k':
if ( multitrack != NULL )
{
- mlt_position time = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, -1 );
- mlt_producer_seek( producer, time );
+ position = mlt_multitrack_clip( multitrack, mlt_whence_relative_current, -1 );
+ mlt_consumer_purge( consumer );
+ mlt_producer_seek( producer, position );
+ mlt_events_fire( jack, "jack-seek", &position, NULL );
}
break;
case 'l':
if ( producer != NULL )
{
- mlt_position position = mlt_producer_position( producer );
+ position++;
+ mlt_consumer_purge( consumer );
if ( mlt_producer_get_speed( producer ) != 0 )
+ {
mlt_producer_set_speed( producer, 0 );
+ mlt_events_fire( jack, "jack-stop", NULL );
+ }
else
- mlt_producer_seek( producer, position + 1 );
+ {
+ mlt_producer_seek( producer, position );
+ mlt_events_fire( jack, "jack-seek", &position, NULL );
+ }
}
break;
case 'L':
if ( producer != NULL )
{
- mlt_position position = mlt_producer_position( producer );
- mlt_producer_seek( producer, position + ( mlt_producer_get_fps( producer ) * 60 ) );
+ position += mlt_producer_get_fps( producer ) * 60;
+ mlt_consumer_purge( consumer );
+ mlt_producer_seek( producer, position );
+ mlt_events_fire( jack, "jack-seek", &position, NULL );
}
break;
}
mlt_properties_set_int( properties, "stats_off", 0 );
}
+static void on_jack_started( mlt_properties owner, mlt_consumer consumer, mlt_position *position )
+{
+ mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL );
+ if ( producer )
+ {
+ if ( mlt_producer_get_speed( producer ) != 0 )
+ {
+ mlt_properties jack = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES( consumer ), "jack_filter", NULL );
+ mlt_events_fire( jack, "jack-stop", NULL );
+ }
+ else
+ {
+ mlt_producer_set_speed( producer, 1 );
+ mlt_consumer_purge( consumer );
+ mlt_producer_seek( producer, *position );
+ mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 );
+ }
+ }
+}
+
+static void on_jack_stopped( mlt_properties owner, mlt_consumer consumer, mlt_position *position )
+{
+ mlt_producer producer = mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "transport_producer", NULL );
+ if ( producer )
+ {
+ mlt_producer_set_speed( producer, 0 );
+ mlt_consumer_purge( consumer );
+ mlt_producer_seek( producer, *position );
+ mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( consumer ), "refresh", 1 );
+ }
+}
+
+static void setup_jack_transport( mlt_consumer consumer, mlt_profile profile )
+{
+ mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
+ mlt_filter jack = mlt_factory_filter( profile, "jackrack", NULL );
+ mlt_properties jack_properties = MLT_FILTER_PROPERTIES(jack);
+
+ mlt_service_attach( MLT_CONSUMER_SERVICE(consumer), jack );
+ mlt_properties_set_int( properties, "audio_off", 1 );
+ mlt_properties_set_data( properties, "jack_filter", jack, 0, (mlt_destructor) mlt_filter_close, NULL );
+// mlt_properties_set( jack_properties, "out_1", "system:playback_1" );
+// mlt_properties_set( jack_properties, "out_2", "system:playback_2" );
+ mlt_events_listen( jack_properties, consumer, "jack-started", (mlt_listener) on_jack_started );
+ mlt_events_listen( jack_properties, consumer, "jack-stopped", (mlt_listener) on_jack_stopped );
+}
+
static mlt_consumer create_consumer( mlt_profile profile, char *id )
{
char *myid = id ? strdup( id ) : NULL;
// Parse the arguments
for ( i = 1; i < argc; i ++ )
{
- if ( !strcmp( argv[ i ], "-serialise" ) )
+ if ( !strcmp( argv[ i ], "-jack" ) )
+ {
+ setup_jack_transport( consumer, profile );
+ }
+ else if ( !strcmp( argv[ i ], "-serialise" ) )
{
if ( store != stdout )
i ++;
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <framework/mlt_filter.h>
-#include <framework/mlt_frame.h>
-#include <framework/mlt_log.h>
+#include <framework/mlt.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_LEN 204800 * 6
+static void jack_started_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args )
+{
+ listener( owner, service, (mlt_position*) args[0] );
+}
+
+static void jack_stopped_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args )
+{
+ listener( owner, service, (mlt_position*) args[0] );
+}
+
+static void jack_seek_transmitter( mlt_listener listener, mlt_properties owner, mlt_service service, void **args )
+{
+ listener( owner, service, (mlt_position*) args[0] );
+}
+
+#define JACKSTATE(x) (x==JackTransportStopped?"stopped":x==JackTransportStarting?"starting":x==JackTransportRolling?"rolling":"unknown")
+
+static int jack_sync( jack_transport_state_t state, jack_position_t *jack_pos, void *arg )
+{
+ mlt_filter filter = (mlt_filter) arg;
+ mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+ mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) );
+ mlt_position position = mlt_profile_fps( profile ) * jack_pos->frame / jack_pos->frame_rate + 0.5;
+ int result = 1;
+
+ mlt_log_verbose( MLT_FILTER_SERVICE(filter), "%s frame %u rate %u pos %d last_pos %d\n",
+ JACKSTATE(state), jack_pos->frame, jack_pos->frame_rate, position,
+ mlt_properties_get_position( properties, "_last_pos" ) );
+ if ( state == JackTransportStopped )
+ {
+ mlt_events_fire( properties, "jack-stopped", &position, NULL );
+ mlt_properties_set_int( properties, "_sync_guard", 0 );
+ }
+ else if ( state == JackTransportStarting )
+ {
+ result = 0;
+ if ( !mlt_properties_get_int( properties, "_sync_guard" ) )
+ {
+ mlt_properties_set_int( properties, "_sync_guard", 1 );
+ mlt_events_fire( properties, "jack-started", &position, NULL );
+ }
+ else if ( position >= mlt_properties_get_position( properties, "_last_pos" ) - 2 )
+ {
+ mlt_properties_set_int( properties, "_sync_guard", 0 );
+ result = 1;
+ }
+ }
+ else
+ {
+ mlt_properties_set_int( properties, "_sync_guard", 0 );
+ }
+
+ return result;
+}
+
+static void on_jack_start( mlt_properties owner, mlt_properties properties )
+{
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL );
+ jack_transport_start( jack_client );
+}
+
+static void on_jack_stop( mlt_properties owner, mlt_properties properties )
+{
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL );
+ jack_transport_stop( jack_client );
+}
+
+static void on_jack_seek( mlt_properties owner, mlt_filter filter, mlt_position *position )
+{
+ mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+
+
+ mlt_properties_set_int( properties, "_sync_guard", 1 );
+ mlt_properties_set_position( properties, "_jack_seek", *position );
+ return;
+
+
+ mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) );
+ jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL );
+ jack_nframes_t jack_frame = jack_get_sample_rate( jack_client );
+ jack_frame *= *position / mlt_profile_fps( profile );
+
+ fprintf(stderr, "%s: %d\n", __FUNCTION__, *position);
+ jack_transport_locate( jack_client, jack_frame );
+}
+
static void initialise_jack_ports( mlt_properties properties )
{
int i;
jack_ringbuffer_read( input_buffers[j], (char*)( q + j * *samples ), size );
}
+ // Do JACK seeking if requested
+ mlt_position pos = mlt_frame_get_position( frame );
+ mlt_properties_set_position( filter_properties, "_last_pos", pos );
+ if ( pos == mlt_properties_get_position( filter_properties, "_jack_seek" ) )
+ {
+ jack_client_t *jack_client = mlt_properties_get_data( filter_properties, "jack_client", NULL );
+ jack_position_t jack_pos;
+ jack_transport_query( jack_client, &jack_pos );
+ double fps = mlt_profile_fps( mlt_service_profile( MLT_FILTER_SERVICE(filter) ) );
+ jack_nframes_t jack_frame = jack_pos.frame_rate * pos / fps;
+ jack_transport_locate( jack_client, jack_frame );
+ mlt_properties_set_position( filter_properties, "_jack_seek", -1 );
+ }
+
return 0;
}
char name[14];
snprintf( name, sizeof( name ), "mlt%d", getpid() );
- jack_client_t *jack_client = jack_client_new( name );
+ jack_client_t *jack_client = jack_client_open( name, JackNullOption, NULL );
if ( jack_client )
{
mlt_properties properties = MLT_FILTER_PROPERTIES( this );
pthread_cond_t *output_ready = mlt_pool_alloc( sizeof( pthread_cond_t ) );
jack_set_process_callback( jack_client, jack_process, this );
+ jack_set_sync_callback( jack_client, jack_sync, this );
+ jack_set_sync_timeout( jack_client, 5000000 );
//TODO: jack_on_shutdown( jack_client, jack_shutdown_cb, this );
this->process = filter_process;
this->close = filter_close;
mlt_properties_set_data( properties, "output_ready", output_ready, 0, mlt_pool_release, NULL );
mlt_properties_set_int( properties, "_sync", 1 );
mlt_properties_set_int( properties, "channels", 2 );
+
+ mlt_events_register( properties, "jack-started", (mlt_transmitter) jack_started_transmitter );
+ mlt_events_register( properties, "jack-stopped", (mlt_transmitter) jack_stopped_transmitter );
+ mlt_events_register( properties, "jack-start", NULL );
+ mlt_events_register( properties, "jack-stop", NULL );
+ mlt_events_register( properties, "jack-seek", (mlt_transmitter) jack_seek_transmitter );
+ mlt_events_listen( properties, properties, "jack-start", (mlt_listener) on_jack_start );
+ mlt_events_listen( properties, properties, "jack-stop", (mlt_listener) on_jack_stop );
+ mlt_events_listen( properties, this, "jack-seek", (mlt_listener) on_jack_seek );
+ mlt_properties_set_position( properties, "_jack_seek", -1 );
}
}
return this;