static void *consumer_thread( void *arg ) { // Map the argument to the object mlt_consumer consumer = arg; // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Convenience functionality int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); int terminated = 0; // Frame and size mlt_frame frame = NULL; // Loop while running while( !terminated && mlt_properties_get_int( properties, "_running" ) ) { // Get the frame frame = mlt_consumer_rt_frame( consumer ); // Check for termination if ( terminate_on_pause && frame != NULL ) terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; // Check that we have a frame to work with if ( frame ) { avsync_stats* stats = mlt_properties_get_data( properties, "_stats", NULL ); double fps = mlt_properties_get_double( properties, "fps" ); mlt_position pos = mlt_frame_get_position( frame ); if( !strcmp( mlt_properties_get( properties, "report" ), "frame" ) ) { stats->report_frames = 1; } else { stats->report_frames = 0; } detect_flash( frame, pos, fps, stats ); detect_blip( frame, pos, fps, stats ); calculate_sync( stats ); report_results( stats, pos ); // Close the frame mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); mlt_frame_close( frame ); } } // Indicate that the consumer is stopped mlt_properties_set_int( properties, "_running", 0 ); mlt_consumer_stopped( consumer ); return NULL; }
static void *consumer_thread( void *arg ) { mlt_consumer consumer = arg; mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_frame frame = NULL; // Determine whether to stop at end-of-media int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); int terminated = 0; // Loop while running while ( !terminated && !is_stopped( consumer ) ) { // Get the next frame frame = mlt_consumer_rt_frame( consumer ); // Check for termination if ( terminate_on_pause && frame ) terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; // Check that we have a frame to work with if ( frame && !terminated && !is_stopped( consumer ) ) { if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "rendered" ) ) { if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES(frame), "_speed" ) == 0 ) foreach_consumer_refresh( consumer ); foreach_consumer_put( consumer, frame ); } else { int dropped = mlt_properties_get_int( properties, "_dropped" ); mlt_log_info( MLT_CONSUMER_SERVICE(consumer), "dropped frame %d\n", ++dropped ); mlt_properties_set_int( properties, "_dropped", dropped ); } mlt_frame_close( frame ); } else { if ( frame && terminated ) { // Send this termination frame to nested consumers for their cancellation foreach_consumer_put( consumer, frame ); } if ( frame ) mlt_frame_close( frame ); terminated = 1; } } // Indicate that the consumer is stopped mlt_consumer_stopped( consumer ); return NULL; }
static void *run( void *arg ) { // Map the argument to the object DeckLinkConsumer* decklink = (DeckLinkConsumer*) arg; mlt_consumer consumer = decklink->getConsumer(); // Get the properties mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Convenience functionality int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); int terminated = 0; // Frame and size mlt_frame frame = NULL; // Loop while running while ( !terminated && mlt_properties_get_int( properties, "running" ) ) { // Get the frame frame = mlt_consumer_rt_frame( consumer ); // Check for termination if ( terminate_on_pause && frame ) terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; // Check that we have a frame to work with if ( frame ) { decklink->render( frame ); if ( !decklink->isBuffering() ) decklink->wait(); // Close the frame mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); mlt_frame_close( frame ); } } // Indicate that the consumer is stopped decklink->stop(); mlt_properties_set_int( properties, "running", 0 ); mlt_consumer_stopped( consumer ); return NULL; }
static void *video_thread( void *arg ) { // Identify the arg consumer_sdl self = arg; // Obtain time of thread start struct timeval now; int64_t start = 0; int64_t elapsed = 0; struct timespec tm; mlt_frame next = NULL; mlt_properties properties = NULL; double speed = 0; // Get real time flag int real_time = mlt_properties_get_int( self->properties, "real_time" ); #if !defined(__APPLE__) && !defined(_WIN32) if ( setup_sdl_video(self) ) self->running = 0; #endif // Determine start time gettimeofday( &now, NULL ); start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec; while ( self->running ) { // Pop the next frame pthread_mutex_lock( &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); while ( next == NULL && self->running ) { pthread_cond_wait( &self->video_cond, &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); } pthread_mutex_unlock( &self->video_mutex ); if ( !self->running || next == NULL ) break; // Get the properties properties = MLT_FRAME_PROPERTIES( next ); // Get the speed of the frame speed = mlt_properties_get_double( properties, "_speed" ); // Get the current time gettimeofday( &now, NULL ); // Get the elapsed time elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - start; // See if we have to delay the display of the current frame if ( mlt_properties_get_int( properties, "rendered" ) == 1 && self->running ) { // Obtain the scheduled playout time int64_t scheduled = mlt_properties_get_int( properties, "playtime" ); // Determine the difference between the elapsed time and the scheduled playout time int64_t difference = scheduled - elapsed; // Smooth playback a bit if ( real_time && ( difference > 20000 && speed == 1.0 ) ) { tm.tv_sec = difference / 1000000; tm.tv_nsec = ( difference % 1000000 ) * 500; nanosleep( &tm, NULL ); } // Show current frame if not too old if ( !real_time || ( difference > -10000 || speed != 1.0 || mlt_deque_count( self->queue ) < 2 ) ) consumer_play_video( self, next ); // If the queue is empty, recalculate start to allow build up again if ( real_time && ( mlt_deque_count( self->queue ) == 0 && speed == 1.0 ) ) { gettimeofday( &now, NULL ); start = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - scheduled + 20000; } } else { static int dropped = 0; mlt_log_info( MLT_CONSUMER_SERVICE(&self->parent), "dropped video frame %d\n", ++dropped ); } // This frame can now be closed mlt_frame_close( next ); next = NULL; } if ( next != NULL ) mlt_frame_close( next ); mlt_consumer_stopped( &self->parent ); return NULL; }
static void *video_thread( void *arg ) { // Identify the arg consumer_sdl self = arg; // Obtain time of thread start struct timeval now; int64_t start = 0; int64_t elapsed = 0; struct timespec tm; mlt_frame next = NULL; mlt_properties properties = NULL; double speed = 0; // Get real time flag int real_time = mlt_properties_get_int( self->properties, "real_time" ); // Get the current time gettimeofday( &now, NULL ); // Determine start time start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec; while ( self->running ) { // Pop the next frame pthread_mutex_lock( &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); while ( next == NULL && self->running ) { pthread_cond_wait( &self->video_cond, &self->video_mutex ); next = mlt_deque_pop_front( self->queue ); } pthread_mutex_unlock( &self->video_mutex ); if ( !self->running || next == NULL ) break; // Get the properties properties = MLT_FRAME_PROPERTIES( next ); // Get the speed of the frame speed = mlt_properties_get_double( properties, "_speed" ); // Get the current time gettimeofday( &now, NULL ); // Get the elapsed time elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - start; // See if we have to delay the display of the current frame if ( mlt_properties_get_int( properties, "rendered" ) == 1 ) { // Obtain the scheduled playout time int64_t scheduled = mlt_properties_get_int( properties, "playtime" ); // Determine the difference between the elapsed time and the scheduled playout time int64_t difference = scheduled - elapsed; // Smooth playback a bit if ( real_time && ( difference > 20000 && speed == 1.0 ) ) { tm.tv_sec = difference / 1000000; tm.tv_nsec = ( difference % 1000000 ) * 500; nanosleep( &tm, NULL ); } // Show current frame if not too old if ( !real_time || ( difference > -10000 || speed != 1.0 || mlt_deque_count( self->queue ) < 2 ) ) consumer_play_video( self, next ); // If the queue is empty, recalculate start to allow build up again if ( real_time && ( mlt_deque_count( self->queue ) == 0 && speed == 1.0 ) ) { gettimeofday( &now, NULL ); start = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec ) - scheduled + 20000; } } // This frame can now be closed mlt_frame_close( next ); next = NULL; } // This consumer is stopping. But audio has already been played for all // the frames in the queue. Spit out all the frames so that the display has // the option to catch up with the audio. if ( next != NULL ) { consumer_play_video( self, next ); mlt_frame_close( next ); next = NULL; } while ( mlt_deque_count( self->queue ) > 0 ) { next = mlt_deque_pop_front( self->queue ); consumer_play_video( self, next ); mlt_frame_close( next ); next = NULL; } mlt_consumer_stopped( &self->parent ); return NULL; }