Example #1
0
static void foreach_consumer_stop( mlt_consumer consumer )
{
    mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
    mlt_consumer nested = NULL;
    char key[30];
    int index = 0;
    struct timespec tm = { 0, 1000 * 1000 };

    do {
        snprintf( key, sizeof(key), "%d.consumer", index++ );
        nested = mlt_properties_get_data( properties, key, NULL );
        if ( nested )
        {
            // Let consumer with terminate_on_pause stop on their own
            if ( mlt_properties_get_int( MLT_CONSUMER_PROPERTIES(nested), "terminate_on_pause" ) )
            {
                // Send additional dummy frame to unlatch nested consumer's threads
                mlt_consumer_put_frame( nested, mlt_frame_init( MLT_CONSUMER_SERVICE(consumer) ) );
                // wait for stop
                while ( !mlt_consumer_is_stopped( nested ) )
                    nanosleep( &tm, NULL );
            }
            else
            {
                mlt_consumer_stop( nested );
            }
        }
    } while ( nested );
}
Example #2
0
static void *consumer_thread( void *arg )
{
	// Identify the arg
	consumer_sdl self = arg;

	// Get the consumer
	mlt_consumer consumer = &self->parent;

	// Get the properties
	mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );

	// internal intialization
	mlt_frame frame = NULL;
	int last_position = -1;
	int eos = 0;
	int eos_threshold = 20;
	if ( self->play )
		eos_threshold = eos_threshold + mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( self->play ), "buffer" );

	// Determine if the application is dealing with the preview
	int preview_off = mlt_properties_get_int( properties, "preview_off" );

	pthread_mutex_lock( &self->refresh_mutex );
	self->refresh_count = 0;
	pthread_mutex_unlock( &self->refresh_mutex );

	// Loop until told not to
	while( self->running )
	{
		// Get a frame from the attached producer
		frame = mlt_consumer_get_frame( consumer );

		// Ensure that we have a frame
		if ( self->running && frame != NULL )
		{
			// Get the speed of the frame
			double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" );

			// Lock during the operation
			mlt_service_lock( MLT_CONSUMER_SERVICE( consumer ) );

			// Get refresh request for the current frame
			int refresh = mlt_properties_get_int( properties, "refresh" );

			// Decrement refresh and clear changed
			mlt_events_block( properties, properties );
			mlt_properties_set_int( properties, "refresh", 0 );
			mlt_events_unblock( properties, properties );

			// Unlock after the operation
			mlt_service_unlock( MLT_CONSUMER_SERVICE( consumer ) );

			// Set the changed property on this frame for the benefit of still
			mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "refresh", refresh );

			// Make sure the recipient knows that this frame isn't really rendered
			mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 0 );

			// Optimisation to reduce latency
			if ( speed == 1.0 )
			{
				if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) )
					mlt_consumer_purge( self->play );
				last_position = mlt_frame_get_position( frame );
			}
			else
			{
				//mlt_consumer_purge( self->play );
				last_position = -1;
			}

			// If we aren't playing normally, then use the still
			if ( speed != 1 )
			{
				mlt_producer producer = MLT_PRODUCER( mlt_service_get_producer( MLT_CONSUMER_SERVICE( consumer ) ) );
				mlt_position duration = producer? mlt_producer_get_playtime( producer ) : -1;
				int pause = 0;

#ifndef SKIP_WAIT_EOS
				if ( self->active == self->play )
				{
					// Do not interrupt the play consumer near the end
					if ( duration - self->last_position > eos_threshold )
					{
						// Get a new frame at the sought position
						mlt_frame_close( frame );
						if ( producer )
							mlt_producer_seek( producer, self->last_position );
						frame = mlt_consumer_get_frame( consumer );
						pause = 1;
					}
					else
					{
						// Send frame with speed 0 to stop it
						if ( frame && !mlt_consumer_is_stopped( self->play ) )
						{
							mlt_consumer_put_frame( self->play, frame );
							frame = NULL;
							eos = 1;
						}

						// Check for end of stream
						if ( mlt_consumer_is_stopped( self->play ) )
						{
							// Stream has ended
							mlt_log_verbose( MLT_CONSUMER_SERVICE( consumer ), "END OF STREAM\n" );
							pause = 1;
							eos = 0; // reset eos indicator
						}
						else
						{
							// Prevent a tight busy loop
							struct timespec tm = { 0, 100000L }; // 100 usec
							nanosleep( &tm, NULL );
						}
					}
				}
#else
				pause = self->active == self->play;
#endif
				if ( pause )
				{
					// Start the still consumer
					if ( !mlt_consumer_is_stopped( self->play ) )
						mlt_consumer_stop( self->play );
					self->last_speed = speed;
					self->active = self->still;
					self->ignore_change = 0;
					mlt_consumer_start( self->still );
				}
				// Send the frame to the active child
				if ( frame && !eos )
				{
					mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "refresh", 1 );
					if ( self->active )
						mlt_consumer_put_frame( self->active, frame );
				}
				if ( pause && speed == 0.0 )
				{
					mlt_events_fire( properties, "consumer-sdl-paused", NULL );
				}
			}
			// Allow a little grace time before switching consumers on speed changes
			else if ( self->ignore_change -- > 0 && self->active != NULL && !mlt_consumer_is_stopped( self->active ) )
			{
				mlt_consumer_put_frame( self->active, frame );
			}
			// Otherwise use the normal player
			else
			{
				if ( !mlt_consumer_is_stopped( self->still ) )
					mlt_consumer_stop( self->still );
				if ( mlt_consumer_is_stopped( self->play ) )
				{
					self->last_speed = speed;
					self->active = self->play;
					self->ignore_change = 0;
					mlt_consumer_start( self->play );
				}
				if ( self->play )
					mlt_consumer_put_frame( self->play, frame );
			}

			// Copy the rectangle info from the active consumer
			if ( self->running && preview_off == 0 && self->active )
			{
				mlt_properties active = MLT_CONSUMER_PROPERTIES( self->active );
				mlt_service_lock( MLT_CONSUMER_SERVICE( consumer ) );
				mlt_properties_set_int( properties, "rect_x", mlt_properties_get_int( active, "rect_x" ) );
				mlt_properties_set_int( properties, "rect_y", mlt_properties_get_int( active, "rect_y" ) );
				mlt_properties_set_int( properties, "rect_w", mlt_properties_get_int( active, "rect_w" ) );
				mlt_properties_set_int( properties, "rect_h", mlt_properties_get_int( active, "rect_h" ) );
				mlt_service_unlock( MLT_CONSUMER_SERVICE( consumer ) );
			}

			if ( self->active == self->still )
			{
				pthread_mutex_lock( &self->refresh_mutex );
				if ( self->running && speed == 0 && self->refresh_count <= 0 )
				{
					mlt_events_fire( properties, "consumer-sdl-paused", NULL );
					pthread_cond_wait( &self->refresh_cond, &self->refresh_mutex );
				}
				self->refresh_count --;
				pthread_mutex_unlock( &self->refresh_mutex );
			}
		}
		else
		{
			if ( frame ) mlt_frame_close( frame );
			mlt_consumer_put_frame( self->active, NULL );
			self->running = 0;
		}
	}

	if ( self->play ) mlt_consumer_stop( self->play );
	if ( self->still ) mlt_consumer_stop( self->still );

	return NULL;
}
Example #3
0
static void foreach_consumer_put( mlt_consumer consumer, mlt_frame frame )
{
    mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
    mlt_consumer nested = NULL;
    char key[30];
    int index = 0;

    do {
        snprintf( key, sizeof(key), "%d.consumer", index++ );
        nested = mlt_properties_get_data( properties, key, NULL );
        if ( nested )
        {
            mlt_properties nested_props = MLT_CONSUMER_PROPERTIES(nested);
            double self_fps = mlt_properties_get_double( properties, "fps" );
            double nested_fps = mlt_properties_get_double( nested_props, "fps" );
            mlt_position nested_pos = mlt_properties_get_position( nested_props, "_multi_position" );
            mlt_position self_pos = mlt_frame_get_position( frame );
            double self_time = self_pos / self_fps;
            double nested_time = nested_pos / nested_fps;

            // get the audio for the current frame
            uint8_t *buffer = NULL;
            mlt_audio_format format = mlt_audio_s16;
            int channels = mlt_properties_get_int( properties, "channels" );
            int frequency = mlt_properties_get_int( properties, "frequency" );
            int current_samples = mlt_sample_calculator( self_fps, frequency, self_pos );
            mlt_frame_get_audio( frame, (void**) &buffer, &format, &frequency, &channels, &current_samples );
            int current_size = mlt_audio_format_size( format, current_samples, channels );

            // get any leftover audio
            int prev_size = 0;
            uint8_t *prev_buffer = mlt_properties_get_data( nested_props, "_multi_audio", &prev_size );
            uint8_t *new_buffer = NULL;
            if ( prev_size > 0 )
            {
                new_buffer = mlt_pool_alloc( prev_size + current_size );
                memcpy( new_buffer, prev_buffer, prev_size );
                memcpy( new_buffer + prev_size, buffer, current_size );
                buffer = new_buffer;
            }
            current_size += prev_size;
            current_samples += mlt_properties_get_int( nested_props, "_multi_samples" );

            while ( nested_time <= self_time )
            {
                // put ideal number of samples into cloned frame
                int deeply = index > 1 ? 1 : 0;
                mlt_frame clone_frame = mlt_frame_clone( frame, deeply );
                int nested_samples = mlt_sample_calculator( nested_fps, frequency, nested_pos );
                // -10 is an optimization to avoid tiny amounts of leftover samples
                nested_samples = nested_samples > current_samples - 10 ? current_samples : nested_samples;
                int nested_size = mlt_audio_format_size( format, nested_samples, channels );
                if ( nested_size > 0 )
                {
                    prev_buffer = mlt_pool_alloc( nested_size );
                    memcpy( prev_buffer, buffer, nested_size );
                }
                else
                {
                    prev_buffer = NULL;
                    nested_size = 0;
                }
                mlt_frame_set_audio( clone_frame, prev_buffer, format, nested_size, mlt_pool_release );
                mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_samples", nested_samples );
                mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_frequency", frequency );
                mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_channels", channels );

                // chomp the audio
                current_samples -= nested_samples;
                current_size -= nested_size;
                buffer += nested_size;

                // send frame to nested consumer
                mlt_consumer_put_frame( nested, clone_frame );
                mlt_properties_set_position( nested_props, "_multi_position", ++nested_pos );
                nested_time = nested_pos / nested_fps;
            }

            // save any remaining audio
            if ( current_size > 0 )
            {
                prev_buffer = mlt_pool_alloc( current_size );
                memcpy( prev_buffer, buffer, current_size );
            }
            else
            {
                prev_buffer = NULL;
                current_size = 0;
            }
            mlt_pool_release( new_buffer );
            mlt_properties_set_data( nested_props, "_multi_audio", prev_buffer, current_size, mlt_pool_release, NULL );
            mlt_properties_set_int( nested_props, "_multi_samples", current_samples );
        }
    } while ( nested );
}