CFLAGS += -I.. -rdynamic
-LDFLAGS += -L../miracle -lmiracle -L../valerie -lvalerie -L../miracle -lmiracle
+LDFLAGS += -L../miracle -lmiracle -L../valerie -lvalerie -L../miracle -lmiracle -L../framework -lmlt
SRCS := $(OBJS:.o=.c)
// Get the properties of the consumer
mlt_properties properties = mlt_consumer_properties( this );
+ char *service = mlt_properties_get( properties, "mlt_service" );
+
// Get the width and height
int width = mlt_properties_get_int( properties, "width" );
int height = mlt_properties_get_int( properties, "height" );
while ( this->ahead )
{
// Put the current frame into the queue
+ time_difference( &ante );
pthread_mutex_lock( &this->mutex );
while( this->ahead && mlt_deque_count( this->queue ) >= buffer )
pthread_cond_wait( &this->cond, &this->mutex );
mlt_deque_push_back( this->queue, frame );
pthread_cond_broadcast( &this->cond );
pthread_mutex_unlock( &this->mutex );
- time_wait += time_difference( &ante );
+ time_wait = time_difference( &ante );
// Get the next frame
frame = mlt_consumer_get_frame( this );
count = 1;
}
+ //fprintf( stderr, "%s: %d %d %lld %lld\n", service, mlt_deque_count( this->queue ), buffer, ( time_frame + time_image ) / count, ( time_wait / count ) );
+
// Get the image
- if ( ( time_frame + time_image ) / count < ( 40000 - ( time_wait / count ) ) )
+ if ( ( time_frame + time_image ) / count < 40000 )
{
// Get the image, mark as rendered and time it
mlt_frame_get_image( frame, &image, &this->format, &width, &height, 0 );
}
else
{
+ fprintf( stderr, "Dropped a frame for %s\n", service );
+
// Increment the number of sequentially skipped frames
skipped ++;
+ time_wait = 0;
+
// If we've reached an unacceptable level, reset everything
if ( skipped > 10 )
{
skipped = 0;
time_frame = 0;
time_image = 0;
- time_wait = 0;
count = 0;
}
}
int buffer = mlt_properties_get_int( properties, "buffer" );
consumer_read_ahead_start( this );
if ( buffer > 1 )
- size = buffer / 2;
+ size = buffer;
}
// Get frame from queue
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
-
+#include <sys/time.h>
#include <math.h>
// avformat header files
avcodec_close(&st->codec);
}
+static inline long time_difference( struct timeval *time1 )
+{
+ struct timeval time2;
+ gettimeofday( &time2, NULL );
+ return time2.tv_sec * 1000000 + time2.tv_usec - time1->tv_sec * 1000000 - time1->tv_usec;
+}
+
/** The main thread - the argument is simply the consumer.
*/
// Get the terminate on pause property
int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" );
+ // Determine if feed is slow (for realtime stuff)
+ int real_time_output = mlt_properties_get_int( properties, "real_time" );
+
+ // Time structures
+ struct timeval ante;
+
// Get the frame rate
int fps = mlt_properties_get_double( properties, "fps" );
// Loop variable
int i;
+ // Frames despatched
+ long int frames = 0;
+ long int total_time = 0;
+
// Determine the format
AVOutputFormat *fmt = NULL;
char *filename = mlt_properties_get( properties, "target" );
}
}
- if ( url_is_streamed( &oc->pb ) )
- fprintf( stderr, "FUCK!\n" );
-
// Write the stream header, if any
if ( mlt_properties_get_int( properties, "running" ) )
av_write_header( oc );
if ( audio_st == NULL && video_st == NULL )
mlt_properties_set_int( properties, "running", 0 );
+ // Get the starting time (can ignore the times above)
+ gettimeofday( &ante, NULL );
+
// Loop while running
while( mlt_properties_get_int( properties, "running" ) )
{
// Check that we have a frame to work with
if ( frame != NULL )
{
+ // Increment frames despatched
+ frames ++;
+
// Default audio args
frame_properties = mlt_frame_properties( frame );
samples = mlt_sample_calculator( fps, frequency, count );
mlt_frame_get_audio( frame, &pcm, &aud_fmt, &frequency, &channels, &samples );
sample_fifo_append( fifo, pcm, samples * channels );
+ total_time += ( samples * 1000000 ) / frequency;
}
// Encode the image
}
}
}
+
+ if ( real_time_output && frames % 25 == 0 )
+ {
+ long passed = time_difference( &ante );
+ long pending = ( ( ( long )sample_fifo_used( fifo ) * 1000 ) / frequency ) * 1000;
+ passed -= pending;
+ if ( passed < total_time )
+ {
+ long total = ( total_time - passed );
+ struct timespec t = { total / 1000000, ( total % 1000000 ) * 1000 };
+ nanosleep( &t, NULL );
+ }
+ }
}
// close each codec
mlt_properties_set_position( properties, "length", frames - 1 );
}
+ // Check if we're seekable
+ mlt_properties_set_int( properties, "seekable", av_seek_frame( context, -1, 0 ) == 0 );
+
// Find default audio and video streams
find_default_streams( context, &audio_index, &video_index );
// Get the audio_index
int index = mlt_properties_get_int( properties, "audio_index" );
+ // Get the seekable status
+ int seekable = mlt_properties_get_int( properties, "seekable" );
+
// Obtain the expected frame numer
mlt_position expected = mlt_properties_get_position( properties, "audio_expected" );
// Flag for paused (silence)
int paused = 0;
- int locked = 0;
// Lock the mutex now
avformat_lock( );
else
{
// Set to the real timecode
- av_seek_frame( context, -1, real_timecode * 1000000.0 );
+ if ( !seekable || av_seek_frame( context, -1, real_timecode * 1000000.0 ) != 0 )
+ paused = 1;
// Clear the usage in the audio buffer
audio_used = 0;
-
- locked = 1;
}
}
mlt_properties_set_double( properties, "discrepancy", discrepancy );
}
- if ( !ignore && discrepancy * current_pts <= ( real_timecode - 0.02 ) )
+ if ( seekable && ( !ignore && discrepancy * current_pts <= ( real_timecode - 0.02 ) ) )
ignore = 1;
}
mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
}
- // Regardless of speed, we expect to get the next frame (cos we ain't too bright)
- mlt_properties_set_position( properties, "audio_expected", position + 1 );
+ // Regardless of speed (other than paused), we expect to get the next frame
+ if ( !paused )
+ mlt_properties_set_position( properties, "audio_expected", position + 1 );
// Unlock the mutex now
avformat_unlock( );
}
}
}
+ else if ( !strcmp( mirror, "xdiagonal" ) )
+ {
+ uint8_t *end = ( uint8_t *)*image + *width * *height * 2;
+ uint8_t *p = NULL;
+ uint8_t *q = NULL;
+ int i;
+ int j;
+ for ( i = 0; i < *height; i ++ )
+ {
+ p = ( uint8_t * )*image + ( i + 1 ) * *width * 2;
+ q = end - ( i + 1 ) * *width * 2;
+ j = ( ( *width * ( *height - i ) ) / *height ) / 2;
+ if ( !reverse )
+ {
+ while ( j -- )
+ {
+ *q ++ = *( p - 2 );
+ *q ++ = *( p - 3 );
+ *q ++ = *( p - 4 );
+ *q ++ = *( p - 1 );
+ p -= 4;
+ }
+ }
+ else
+ {
+ while ( j -- )
+ {
+ *( p - 2 ) = *q ++;
+ *( p - 3 ) = *q ++;
+ *( p - 4 ) = *q ++;
+ *( p - 1 ) = *q ++;
+ p -= 4;
+ }
+ }
+ }
+ }
else if ( !strcmp( mirror, "flip" ) )
{
uint8_t t[ 4 ];
# The names of the services on the right dictate the preference used (if unavailable
# the second and third are applied as applicable).
-deinterlace=deinterlace,avdeinterlace
+deinterlace=avdeinterlace
rescaler=mcrescale,gtkrescale,rescale
resizer=resize
-resampler=resample,soxresample,avresample
+resampler=soxresample,avresample
}
}
- // Close the frame
- mlt_frame_close( frame );
-
return 0;
}
struct timespec tm;
mlt_frame next = NULL;
mlt_frame frame = NULL;
+ mlt_properties properties = NULL;
if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) < 0 )
{
// Ensure that we have a frame
if ( frame != NULL )
{
+ // Get the frame properties
+ properties = mlt_frame_properties( frame );
+
// Play audio
init_audio = consumer_play_audio( this, frame, init_audio, &duration );
- if ( this->playing )
+ // Determine the start time now
+ if ( this->playing && start == 0 )
{
// Get the current time
gettimeofday( &now, NULL );
- // Determine elapsed time
- if ( start == 0 )
- start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec;
- else
- elapsed = ( ( int64_t )now.tv_sec * 1000000 + now.tv_usec) - start;
+ // Determine start time
+ start = ( int64_t )now.tv_sec * 1000000 + now.tv_usec;
}
// Set playtime for this frame
- mlt_properties_set_position( mlt_frame_properties( frame ), "playtime", playtime );
+ mlt_properties_set_position( properties, "playtime", playtime );
// Push this frame to the back of the queue
mlt_deque_push_back( this->queue, frame );
playtime += ( duration * 1000 );
}
- if ( this->playing )
+ // Pop the next frame
+ next = mlt_deque_pop_front( this->queue );
+
+ while ( next != NULL && this->playing )
{
- // Pop the next frame
- next = mlt_deque_pop_front( this->queue );
+ // Get the properties
+ properties = mlt_frame_properties( next );
+
+ // 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 ( next != NULL && mlt_properties_get_int( mlt_frame_properties( next ), "rendered" ) == 1 )
+ if ( mlt_properties_get_int( properties, "rendered" ) == 1 )
{
- mlt_position scheduled = mlt_properties_get_position( mlt_frame_properties( next ), "playtime" ) + 5000;
- if ( scheduled > elapsed && mlt_deque_count( this->queue ) > 25 )
+ // Obtain the scheduled playout time
+ mlt_position scheduled = mlt_properties_get_position( properties, "playtime" );
+
+ // Determine the difference between the elapsed time and the scheduled playout time
+ mlt_position difference = scheduled - elapsed;
+
+ // If the frame is quite some way in the future, go get another
+ if ( difference > 80000 && mlt_deque_count( this->queue ) < 6 )
+ break;
+
+ // Smooth playback a bit
+ if ( difference > 20000 && mlt_properties_get_double( properties, "_speed" ) == 1.0 )
{
- tm.tv_sec = ( scheduled - elapsed ) / 1000000;
- tm.tv_nsec = ( ( scheduled - elapsed ) % 1000000 ) * 1000;
+ tm.tv_sec = difference / 1000000;
+ tm.tv_nsec = ( difference % 1000000 ) * 1000;
nanosleep( &tm, NULL );
+ }
- // Show current frame
+ // Show current frame if not too old
+ if ( difference > -10000 || mlt_properties_get_double( properties, "_speed" ) != 1.0 )
consumer_play_video( this, next );
- }
- else if ( scheduled > elapsed )
- {
- // More time to kill
- mlt_deque_push_front( this->queue, next );
- }
else
- {
- // Show current frame
- consumer_play_video( this, next );
- }
- }
- else
- {
- // This is an unrendered frame - just close it
- mlt_frame_close( next );
+ start = start - difference;
}
+
+ // This is an unrendered frame - just close it
+ mlt_frame_close( next );
+
+ // Pop the next frame
+ next = mlt_deque_pop_front( this->queue );
}
+
+ if ( next != NULL )
+ mlt_deque_push_front( this->queue, next );
}
// internal cleanup