From ba935b798fa57c7541cfa274021c330d1cdf7874 Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Tue, 30 Dec 2003 16:14:49 +0000 Subject: [PATCH] More sdl experimental mods, pixbuf writable work around and minor fixes git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@30 d19143bc-622f-0410-bfdd-b5b2a6649095 --- mlt/src/framework/mlt_frame.c | 13 ++- mlt/src/framework/mlt_multitrack.c | 6 + mlt/src/inigo/inigo.c | 4 +- mlt/src/modules/ffmpeg/producer_ffmpeg.c | 10 +- mlt/src/modules/gtk2/producer_pixbuf.c | 47 +++++++- mlt/src/modules/sdl/consumer_sdl.c | 188 ++++++++++++++++++------------ src/framework/mlt_frame.c | 13 ++- src/framework/mlt_multitrack.c | 6 + src/inigo/inigo.c | 4 +- src/modules/ffmpeg/producer_ffmpeg.c | 10 +- src/modules/gtk2/producer_pixbuf.c | 47 +++++++- src/modules/sdl/consumer_sdl.c | 188 ++++++++++++++++++------------ 12 files changed, 372 insertions(+), 164 deletions(-) diff --git a/mlt/src/framework/mlt_frame.c b/mlt/src/framework/mlt_frame.c index 69c717b..368e861 100644 --- a/mlt/src/framework/mlt_frame.c +++ b/mlt/src/framework/mlt_frame.c @@ -475,6 +475,11 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input int istride = iwidth * 2; int ostride = owidth * 2; + iwidth = iwidth - ( iwidth % 4 ); + owidth = owidth - ( owidth % 4 ); + iheight = iheight - ( iheight % 2 ); + oheight = oheight - ( oheight % 2 ); + // Coordinates (0,0 is middle of output) int y; @@ -486,7 +491,7 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input // Output pointers uint8_t *out_line = output; - uint8_t *out_ptr; + uint8_t *out_ptr = out_line; // Calculate a middle and possibly invalid pointer in the input uint8_t *in_middle = input + istride * ( iheight / 2 ) + ( iwidth / 2 ) * 2; @@ -506,8 +511,8 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range ); // We're in the input range for this row. - memcpy( out_ptr, in_middle + in_line, 4 * in_x_range ); - out_ptr += 4 * in_x_range; + memcpy( out_ptr, in_middle + in_line, 2 * iwidth ); + out_ptr += 2 * iwidth; // Fill the outer part with black out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range ); @@ -586,6 +591,8 @@ uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ) int istride = iwidth * 2; int ostride = owidth * 2; + iwidth = iwidth - ( iwidth % 4 ); + // Coordinates (0,0 is middle of output) int y, x; diff --git a/mlt/src/framework/mlt_multitrack.c b/mlt/src/framework/mlt_multitrack.c index 82fdf0f..2e44f5b 100644 --- a/mlt/src/framework/mlt_multitrack.c +++ b/mlt/src/framework/mlt_multitrack.c @@ -221,6 +221,12 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int ind // Get the frame from the producer mlt_service_get_frame( mlt_producer_service( producer ), frame, 0 ); + + // Indicate speed of this producer + mlt_properties producer_properties = mlt_producer_properties( parent ); + double speed = mlt_properties_get_double( producer_properties, "speed" ); + mlt_properties properties = mlt_frame_properties( *frame ); + mlt_properties_set_double( properties, "speed", speed ); } else { diff --git a/mlt/src/inigo/inigo.c b/mlt/src/inigo/inigo.c index fcb377d..ce64232 100644 --- a/mlt/src/inigo/inigo.c +++ b/mlt/src/inigo/inigo.c @@ -55,7 +55,7 @@ void transport_action( mlt_producer producer, char *value ) mlt_producer_seek( producer, 0 ); break; case '1': - mlt_producer_set_speed( producer, -5 ); + mlt_producer_set_speed( producer, -10 ); break; case '2': mlt_producer_set_speed( producer, -2.5 ); @@ -79,7 +79,7 @@ void transport_action( mlt_producer producer, char *value ) mlt_producer_set_speed( producer, 2.5 ); break; case '9': - mlt_producer_set_speed( producer, 5 ); + mlt_producer_set_speed( producer, 10 ); break; } } diff --git a/mlt/src/modules/ffmpeg/producer_ffmpeg.c b/mlt/src/modules/ffmpeg/producer_ffmpeg.c index db529fb..de829cd 100644 --- a/mlt/src/modules/ffmpeg/producer_ffmpeg.c +++ b/mlt/src/modules/ffmpeg/producer_ffmpeg.c @@ -175,6 +175,8 @@ FILE *producer_ffmpeg_run_audio( producer_ffmpeg this ) static void producer_ffmpeg_position( producer_ffmpeg this, uint64_t requested, int *skip ) { + *skip = 0; + if ( this->open && requested > this->expected ) { // Skip the following n frames @@ -313,8 +315,10 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Read it while( skip -- ) { - fread( this->buffer, width * height * 3 / 2, 1, video ); - read_ffmpeg_header( this, &width, &height ); + if ( fread( this->buffer, width * height * 3 / 2, 1, video ) == 1 ) + read_ffmpeg_header( this, &width, &height ); + else + skip = 0; } fread( this->buffer, width * height * 3 / 2, 1, video ); @@ -366,7 +370,7 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i mlt_properties_set_double( properties, "speed", speed ); // Set the out point on the producer - mlt_producer_set_in_and_out( &this->parent, mlt_producer_get_in( &this->parent ), mlt_producer_position( &this->parent ) + 0.1 ); + mlt_producer_set_in_and_out( &this->parent, mlt_producer_get_in( &this->parent ), mlt_producer_position( &this->parent ) + 1 ); // Update timecode on the frame we're creating mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); diff --git a/mlt/src/modules/gtk2/producer_pixbuf.c b/mlt/src/modules/gtk2/producer_pixbuf.c index 484f83a..b8a792d 100644 --- a/mlt/src/modules/gtk2/producer_pixbuf.c +++ b/mlt/src/modules/gtk2/producer_pixbuf.c @@ -29,6 +29,7 @@ #include #include #include +#include static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); @@ -39,6 +40,15 @@ typedef enum SIGNAL_FORMAT_NTSC } mlt_signal_format; +static int filter_files( const struct dirent *de ) +{ + if ( de->d_name[ 0 ] != '.' ) + return 1; + else + return 0; +} + + mlt_producer producer_pixbuf_init( const char *filename ) { producer_pixbuf this = calloc( sizeof( struct producer_pixbuf_s ), 1 ); @@ -80,6 +90,34 @@ mlt_producer producer_pixbuf_init( const char *filename ) } } } + else if ( strstr( filename, "/.all." ) != NULL ) + { + char *dir_name = strdup( filename ); + char *extension = strrchr( filename, '.' ); + *( strstr( dir_name, "/.all." ) + 1 ) = '\0'; + char fullname[ 1024 ]; + strcpy( fullname, dir_name ); + struct dirent **de = NULL; + int n = scandir( fullname, &de, filter_files, alphasort ); + int i; + struct stat info; + + for (i = 0; i < n; i++ ) + { + snprintf( fullname, 1023, "%s%s", dir_name, de[i]->d_name ); + + if ( lstat( fullname, &info ) == 0 && + ( S_ISREG( info.st_mode ) || ( strstr( fullname, extension ) && info.st_mode | S_IXUSR ) ) ) + { + this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) ); + this->filenames[ this->count ++ ] = strdup( fullname ); + } + free( de[ i ] ); + } + + free( de ); + free( dir_name ); + } else { this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) ); @@ -111,8 +149,12 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma *height = mlt_properties_get_int( properties, "height" ); // Clone if necessary - if ( writable ) + // NB: Cloning is necessary with this producer (due to processing of images ahead of use) + // The fault is not in the design of mlt, but in the implementation of pixbuf... + //if ( writable ) { + size = *width * *height * 2; + // Clone our image uint8_t *copy = malloc( size ); memcpy( copy, image, size ); @@ -176,7 +218,6 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Stack the get image callback mlt_frame_push_get_image( *frame, producer_get_image ); - } else { @@ -212,6 +253,8 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Store width and height this->width = gdk_pixbuf_get_width( pixbuf ); this->height = gdk_pixbuf_get_height( pixbuf ); + this->width -= this->width % 4; + this->height -= this->height % 2; // Allocate/define image and alpha uint8_t *image = malloc( this->width * this->height * 2 ); diff --git a/mlt/src/modules/sdl/consumer_sdl.c b/mlt/src/modules/sdl/consumer_sdl.c index eae3097..59061af 100644 --- a/mlt/src/modules/sdl/consumer_sdl.c +++ b/mlt/src/modules/sdl/consumer_sdl.c @@ -40,12 +40,13 @@ struct consumer_sdl_s int video; pthread_t thread; int running; - uint8_t audio_buffer[ 4096 * 6 ]; + uint8_t audio_buffer[ 4096 * 3 ]; int audio_avail; pthread_mutex_t audio_mutex; pthread_cond_t audio_cond; int window_width; int window_height; + float aspect_ratio; int width; int height; int playing; @@ -94,20 +95,25 @@ mlt_consumer consumer_sdl_init( char *arg ) // process actual param if ( arg == NULL || !strcmp( arg, "PAL" ) ) { - this->window_width = 720; - this->window_height = 576; + this->width = 720; + this->height = 576; } else if ( !strcmp( arg, "NTSC" ) ) { - this->window_width = 720; - this->window_height = 480; + this->width = 720; + this->height = 480; } - else if ( sscanf( arg, "%dx%d", &this->window_width, &this->window_height ) != 2 ) + else if ( sscanf( arg, "%dx%d", &this->width, &this->height ) != 2 ) { - this->window_width = 720; - this->window_height = 576; + this->width = 720; + this->height = 576; } + // Default window size and aspect ratio + this->aspect_ratio = 4.0 / 3.0; + this->window_width = (int)( (float)this->height * this->aspect_ratio ) + 1; + this->window_height = this->height; + // Create the the thread pthread_create( &this->thread, NULL, consumer_thread, this ); @@ -181,6 +187,69 @@ void sdl_fill_audio( void *udata, uint8_t *stream, int len ) pthread_mutex_unlock( &this->audio_mutex ); } +static int consumer_play_audio( consumer_sdl this, mlt_frame frame, int init_audio ) +{ + mlt_audio_format afmt = mlt_audio_pcm; + int channels; + int samples; + int frequency; + int16_t *pcm; + int bytes; + + mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); + + if ( init_audio == 1 ) + { + SDL_AudioSpec request; + SDL_AudioSpec got; + + // specify audio format + memset( &request, 0, sizeof( SDL_AudioSpec ) ); + this->playing = 0; + request.freq = frequency; + request.format = AUDIO_S16; + request.channels = channels; + request.samples = 1024; + request.callback = sdl_fill_audio; + request.userdata = (void *)this; + if ( SDL_OpenAudio( &request, &got ) != 0 ) + { + fprintf( stderr, "SDL failed to open audio: %s\n", SDL_GetError() ); + init_audio = 2; + } + else + { + if ( got.size != 0 ) + { + SDL_PauseAudio( 0 ); + init_audio = 0; + } + } + } + + if ( init_audio == 0 ) + { + bytes = ( samples * channels * 2 ); + pthread_mutex_lock( &this->audio_mutex ); + while ( bytes > ( sizeof( this->audio_buffer) - this->audio_avail ) ) + pthread_cond_wait( &this->audio_cond, &this->audio_mutex ); + mlt_properties properties = mlt_frame_properties( frame ); + if ( mlt_properties_get_double( properties, "speed" ) == 1 ) + memcpy( &this->audio_buffer[ this->audio_avail ], pcm, bytes ); + else + memset( &this->audio_buffer[ this->audio_avail ], 0, bytes ); + this->audio_avail += bytes; + pthread_cond_broadcast( &this->audio_cond ); + pthread_mutex_unlock( &this->audio_mutex ); + } + else + { + this->playing = 1; + } + + return init_audio; +} + /** Threaded wrapper for pipe. */ @@ -207,7 +276,6 @@ static void *consumer_thread( void *arg ) SDL_Overlay *sdl_overlay = NULL; uint8_t *buffer = NULL; int init_audio = 1; - int bytes; if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) < 0 ) { @@ -221,46 +289,13 @@ static void *consumer_thread( void *arg ) // Get a frame from the service (should never return anything other than 0) if ( mlt_service_get_frame( service, &frame, 0 ) == 0 ) { + init_audio = consumer_play_audio( this, frame, init_audio ); + mlt_image_format vfmt = mlt_image_yuv422; int width = this->width, height = this->height; uint8_t *image; - - mlt_audio_format afmt = mlt_audio_pcm; - int channels; - int samples; - int frequency; - int16_t *pcm; int changed = 0; - mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); - if ( init_audio == 1 ) - { - SDL_AudioSpec request; - - // specify audio format - request.freq = frequency; - request.format = AUDIO_S16; - request.channels = channels; - request.samples = 2048; - request.callback = sdl_fill_audio; - request.userdata = (void *)this; - if ( SDL_OpenAudio( &request, NULL ) < 0 ) - { - fprintf( stderr, "SDL failed to open audio: %s\n", SDL_GetError() ); - break; - } - SDL_PauseAudio( 0 ); - init_audio = 0; - } - bytes = ( samples * channels * 2 ); - pthread_mutex_lock( &this->audio_mutex ); - while ( bytes > ( sizeof( this->audio_buffer) - this->audio_avail ) ) - pthread_cond_wait( &this->audio_cond, &this->audio_mutex ); - memcpy( &this->audio_buffer[ this->audio_avail ], pcm, bytes ); - this->audio_avail += bytes; - pthread_cond_broadcast( &this->audio_cond ); - pthread_mutex_unlock( &this->audio_mutex ); - if ( this->count == this->size ) { this->size += 25; @@ -320,37 +355,50 @@ static void *consumer_thread( void *arg ) if ( sdl_screen == NULL || changed ) { double aspect_ratio = mlt_frame_get_aspect_ratio( frame ); - + if ( mlt_properties_get_double( properties, "aspect_ratio" ) ) aspect_ratio = mlt_properties_get_double( properties, "aspect_ratio" ); + int full_width = height * aspect_ratio + 1; + int full_height = height; + float scale_width = (float)full_width / (float)this->window_width; + float scale_height = (float)full_height / (float)this->window_height; + float display_aspect_ratio = (float)this->window_width / (float)this->window_height; + + SDL_Rect rect; + + if ( aspect_ratio == 1 ) + { + rect.w = this->window_width; + rect.h = this->window_height; + } + else if ( this->window_width < this->window_height * aspect_ratio ) + { + rect.w = this->window_width; + rect.h = this->window_width / aspect_ratio; + } + else + { + rect.w = this->window_height * aspect_ratio; + rect.h = this->window_height; + } + + rect.x = ( this->window_width - rect.w ) / 2; + rect.y = ( this->window_height - rect.h ) / 2; + + // Force an overlay recreation + if ( sdl_overlay != NULL ) + SDL_FreeYUVOverlay( sdl_overlay ); + // open SDL window with video overlay, if possible sdl_screen = SDL_SetVideoMode( this->window_width, this->window_height, 0, sdl_flags ); if ( sdl_screen != NULL ) { - SDL_Rect rect; - if ( this->window_width < this->window_height * aspect_ratio ) - { - rect.w = this->window_width; - rect.h = this->window_width / aspect_ratio; - } - else - { - rect.w = this->window_height * aspect_ratio; - rect.h = this->window_height; - } - - rect.x = ( this->window_width - rect.w ) / 2; - rect.y = ( this->window_height - rect.h ) / 2; - SDL_SetClipRect( sdl_screen, &rect ); - // Force an overlay recreation - if ( sdl_overlay != NULL ) - SDL_FreeYUVOverlay( sdl_overlay ); sdl_lock_display(); - sdl_overlay = SDL_CreateYUVOverlay( this->width, this->height, SDL_YUY2_OVERLAY, sdl_screen ); + sdl_overlay = SDL_CreateYUVOverlay( this->width - (this->width % 4), this->height- (this->height % 2 ), SDL_YUY2_OVERLAY, sdl_screen ); sdl_unlock_display(); } } @@ -358,15 +406,11 @@ static void *consumer_thread( void *arg ) if ( sdl_screen != NULL && sdl_overlay != NULL ) { buffer = sdl_overlay->pixels[ 0 ]; - if ( sdl_lock_display() ) + if ( SDL_LockYUVOverlay( sdl_overlay ) >= 0 ) { - if ( SDL_LockYUVOverlay( sdl_overlay ) >= 0 ) - { - mlt_resize_yuv422( buffer, this->width, this->height, image, width, height ); - SDL_UnlockYUVOverlay( sdl_overlay ); - SDL_DisplayYUVOverlay( sdl_overlay, &sdl_screen->clip_rect ); - } - sdl_unlock_display(); + mlt_resize_yuv422( buffer, this->width - (this->width % 4 ), this->height- (this->height % 2 ), image, width, height ); + SDL_UnlockYUVOverlay( sdl_overlay ); + SDL_DisplayYUVOverlay( sdl_overlay, &sdl_screen->clip_rect ); } } } diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c index 69c717b..368e861 100644 --- a/src/framework/mlt_frame.c +++ b/src/framework/mlt_frame.c @@ -475,6 +475,11 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input int istride = iwidth * 2; int ostride = owidth * 2; + iwidth = iwidth - ( iwidth % 4 ); + owidth = owidth - ( owidth % 4 ); + iheight = iheight - ( iheight % 2 ); + oheight = oheight - ( oheight % 2 ); + // Coordinates (0,0 is middle of output) int y; @@ -486,7 +491,7 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input // Output pointers uint8_t *out_line = output; - uint8_t *out_ptr; + uint8_t *out_ptr = out_line; // Calculate a middle and possibly invalid pointer in the input uint8_t *in_middle = input + istride * ( iheight / 2 ) + ( iwidth / 2 ) * 2; @@ -506,8 +511,8 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range ); // We're in the input range for this row. - memcpy( out_ptr, in_middle + in_line, 4 * in_x_range ); - out_ptr += 4 * in_x_range; + memcpy( out_ptr, in_middle + in_line, 2 * iwidth ); + out_ptr += 2 * iwidth; // Fill the outer part with black out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range ); @@ -586,6 +591,8 @@ uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ) int istride = iwidth * 2; int ostride = owidth * 2; + iwidth = iwidth - ( iwidth % 4 ); + // Coordinates (0,0 is middle of output) int y, x; diff --git a/src/framework/mlt_multitrack.c b/src/framework/mlt_multitrack.c index 82fdf0f..2e44f5b 100644 --- a/src/framework/mlt_multitrack.c +++ b/src/framework/mlt_multitrack.c @@ -221,6 +221,12 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int ind // Get the frame from the producer mlt_service_get_frame( mlt_producer_service( producer ), frame, 0 ); + + // Indicate speed of this producer + mlt_properties producer_properties = mlt_producer_properties( parent ); + double speed = mlt_properties_get_double( producer_properties, "speed" ); + mlt_properties properties = mlt_frame_properties( *frame ); + mlt_properties_set_double( properties, "speed", speed ); } else { diff --git a/src/inigo/inigo.c b/src/inigo/inigo.c index fcb377d..ce64232 100644 --- a/src/inigo/inigo.c +++ b/src/inigo/inigo.c @@ -55,7 +55,7 @@ void transport_action( mlt_producer producer, char *value ) mlt_producer_seek( producer, 0 ); break; case '1': - mlt_producer_set_speed( producer, -5 ); + mlt_producer_set_speed( producer, -10 ); break; case '2': mlt_producer_set_speed( producer, -2.5 ); @@ -79,7 +79,7 @@ void transport_action( mlt_producer producer, char *value ) mlt_producer_set_speed( producer, 2.5 ); break; case '9': - mlt_producer_set_speed( producer, 5 ); + mlt_producer_set_speed( producer, 10 ); break; } } diff --git a/src/modules/ffmpeg/producer_ffmpeg.c b/src/modules/ffmpeg/producer_ffmpeg.c index db529fb..de829cd 100644 --- a/src/modules/ffmpeg/producer_ffmpeg.c +++ b/src/modules/ffmpeg/producer_ffmpeg.c @@ -175,6 +175,8 @@ FILE *producer_ffmpeg_run_audio( producer_ffmpeg this ) static void producer_ffmpeg_position( producer_ffmpeg this, uint64_t requested, int *skip ) { + *skip = 0; + if ( this->open && requested > this->expected ) { // Skip the following n frames @@ -313,8 +315,10 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Read it while( skip -- ) { - fread( this->buffer, width * height * 3 / 2, 1, video ); - read_ffmpeg_header( this, &width, &height ); + if ( fread( this->buffer, width * height * 3 / 2, 1, video ) == 1 ) + read_ffmpeg_header( this, &width, &height ); + else + skip = 0; } fread( this->buffer, width * height * 3 / 2, 1, video ); @@ -366,7 +370,7 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i mlt_properties_set_double( properties, "speed", speed ); // Set the out point on the producer - mlt_producer_set_in_and_out( &this->parent, mlt_producer_get_in( &this->parent ), mlt_producer_position( &this->parent ) + 0.1 ); + mlt_producer_set_in_and_out( &this->parent, mlt_producer_get_in( &this->parent ), mlt_producer_position( &this->parent ) + 1 ); // Update timecode on the frame we're creating mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); diff --git a/src/modules/gtk2/producer_pixbuf.c b/src/modules/gtk2/producer_pixbuf.c index 484f83a..b8a792d 100644 --- a/src/modules/gtk2/producer_pixbuf.c +++ b/src/modules/gtk2/producer_pixbuf.c @@ -29,6 +29,7 @@ #include #include #include +#include static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); @@ -39,6 +40,15 @@ typedef enum SIGNAL_FORMAT_NTSC } mlt_signal_format; +static int filter_files( const struct dirent *de ) +{ + if ( de->d_name[ 0 ] != '.' ) + return 1; + else + return 0; +} + + mlt_producer producer_pixbuf_init( const char *filename ) { producer_pixbuf this = calloc( sizeof( struct producer_pixbuf_s ), 1 ); @@ -80,6 +90,34 @@ mlt_producer producer_pixbuf_init( const char *filename ) } } } + else if ( strstr( filename, "/.all." ) != NULL ) + { + char *dir_name = strdup( filename ); + char *extension = strrchr( filename, '.' ); + *( strstr( dir_name, "/.all." ) + 1 ) = '\0'; + char fullname[ 1024 ]; + strcpy( fullname, dir_name ); + struct dirent **de = NULL; + int n = scandir( fullname, &de, filter_files, alphasort ); + int i; + struct stat info; + + for (i = 0; i < n; i++ ) + { + snprintf( fullname, 1023, "%s%s", dir_name, de[i]->d_name ); + + if ( lstat( fullname, &info ) == 0 && + ( S_ISREG( info.st_mode ) || ( strstr( fullname, extension ) && info.st_mode | S_IXUSR ) ) ) + { + this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) ); + this->filenames[ this->count ++ ] = strdup( fullname ); + } + free( de[ i ] ); + } + + free( de ); + free( dir_name ); + } else { this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) ); @@ -111,8 +149,12 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma *height = mlt_properties_get_int( properties, "height" ); // Clone if necessary - if ( writable ) + // NB: Cloning is necessary with this producer (due to processing of images ahead of use) + // The fault is not in the design of mlt, but in the implementation of pixbuf... + //if ( writable ) { + size = *width * *height * 2; + // Clone our image uint8_t *copy = malloc( size ); memcpy( copy, image, size ); @@ -176,7 +218,6 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Stack the get image callback mlt_frame_push_get_image( *frame, producer_get_image ); - } else { @@ -212,6 +253,8 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Store width and height this->width = gdk_pixbuf_get_width( pixbuf ); this->height = gdk_pixbuf_get_height( pixbuf ); + this->width -= this->width % 4; + this->height -= this->height % 2; // Allocate/define image and alpha uint8_t *image = malloc( this->width * this->height * 2 ); diff --git a/src/modules/sdl/consumer_sdl.c b/src/modules/sdl/consumer_sdl.c index eae3097..59061af 100644 --- a/src/modules/sdl/consumer_sdl.c +++ b/src/modules/sdl/consumer_sdl.c @@ -40,12 +40,13 @@ struct consumer_sdl_s int video; pthread_t thread; int running; - uint8_t audio_buffer[ 4096 * 6 ]; + uint8_t audio_buffer[ 4096 * 3 ]; int audio_avail; pthread_mutex_t audio_mutex; pthread_cond_t audio_cond; int window_width; int window_height; + float aspect_ratio; int width; int height; int playing; @@ -94,20 +95,25 @@ mlt_consumer consumer_sdl_init( char *arg ) // process actual param if ( arg == NULL || !strcmp( arg, "PAL" ) ) { - this->window_width = 720; - this->window_height = 576; + this->width = 720; + this->height = 576; } else if ( !strcmp( arg, "NTSC" ) ) { - this->window_width = 720; - this->window_height = 480; + this->width = 720; + this->height = 480; } - else if ( sscanf( arg, "%dx%d", &this->window_width, &this->window_height ) != 2 ) + else if ( sscanf( arg, "%dx%d", &this->width, &this->height ) != 2 ) { - this->window_width = 720; - this->window_height = 576; + this->width = 720; + this->height = 576; } + // Default window size and aspect ratio + this->aspect_ratio = 4.0 / 3.0; + this->window_width = (int)( (float)this->height * this->aspect_ratio ) + 1; + this->window_height = this->height; + // Create the the thread pthread_create( &this->thread, NULL, consumer_thread, this ); @@ -181,6 +187,69 @@ void sdl_fill_audio( void *udata, uint8_t *stream, int len ) pthread_mutex_unlock( &this->audio_mutex ); } +static int consumer_play_audio( consumer_sdl this, mlt_frame frame, int init_audio ) +{ + mlt_audio_format afmt = mlt_audio_pcm; + int channels; + int samples; + int frequency; + int16_t *pcm; + int bytes; + + mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); + + if ( init_audio == 1 ) + { + SDL_AudioSpec request; + SDL_AudioSpec got; + + // specify audio format + memset( &request, 0, sizeof( SDL_AudioSpec ) ); + this->playing = 0; + request.freq = frequency; + request.format = AUDIO_S16; + request.channels = channels; + request.samples = 1024; + request.callback = sdl_fill_audio; + request.userdata = (void *)this; + if ( SDL_OpenAudio( &request, &got ) != 0 ) + { + fprintf( stderr, "SDL failed to open audio: %s\n", SDL_GetError() ); + init_audio = 2; + } + else + { + if ( got.size != 0 ) + { + SDL_PauseAudio( 0 ); + init_audio = 0; + } + } + } + + if ( init_audio == 0 ) + { + bytes = ( samples * channels * 2 ); + pthread_mutex_lock( &this->audio_mutex ); + while ( bytes > ( sizeof( this->audio_buffer) - this->audio_avail ) ) + pthread_cond_wait( &this->audio_cond, &this->audio_mutex ); + mlt_properties properties = mlt_frame_properties( frame ); + if ( mlt_properties_get_double( properties, "speed" ) == 1 ) + memcpy( &this->audio_buffer[ this->audio_avail ], pcm, bytes ); + else + memset( &this->audio_buffer[ this->audio_avail ], 0, bytes ); + this->audio_avail += bytes; + pthread_cond_broadcast( &this->audio_cond ); + pthread_mutex_unlock( &this->audio_mutex ); + } + else + { + this->playing = 1; + } + + return init_audio; +} + /** Threaded wrapper for pipe. */ @@ -207,7 +276,6 @@ static void *consumer_thread( void *arg ) SDL_Overlay *sdl_overlay = NULL; uint8_t *buffer = NULL; int init_audio = 1; - int bytes; if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) < 0 ) { @@ -221,46 +289,13 @@ static void *consumer_thread( void *arg ) // Get a frame from the service (should never return anything other than 0) if ( mlt_service_get_frame( service, &frame, 0 ) == 0 ) { + init_audio = consumer_play_audio( this, frame, init_audio ); + mlt_image_format vfmt = mlt_image_yuv422; int width = this->width, height = this->height; uint8_t *image; - - mlt_audio_format afmt = mlt_audio_pcm; - int channels; - int samples; - int frequency; - int16_t *pcm; int changed = 0; - mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); - if ( init_audio == 1 ) - { - SDL_AudioSpec request; - - // specify audio format - request.freq = frequency; - request.format = AUDIO_S16; - request.channels = channels; - request.samples = 2048; - request.callback = sdl_fill_audio; - request.userdata = (void *)this; - if ( SDL_OpenAudio( &request, NULL ) < 0 ) - { - fprintf( stderr, "SDL failed to open audio: %s\n", SDL_GetError() ); - break; - } - SDL_PauseAudio( 0 ); - init_audio = 0; - } - bytes = ( samples * channels * 2 ); - pthread_mutex_lock( &this->audio_mutex ); - while ( bytes > ( sizeof( this->audio_buffer) - this->audio_avail ) ) - pthread_cond_wait( &this->audio_cond, &this->audio_mutex ); - memcpy( &this->audio_buffer[ this->audio_avail ], pcm, bytes ); - this->audio_avail += bytes; - pthread_cond_broadcast( &this->audio_cond ); - pthread_mutex_unlock( &this->audio_mutex ); - if ( this->count == this->size ) { this->size += 25; @@ -320,37 +355,50 @@ static void *consumer_thread( void *arg ) if ( sdl_screen == NULL || changed ) { double aspect_ratio = mlt_frame_get_aspect_ratio( frame ); - + if ( mlt_properties_get_double( properties, "aspect_ratio" ) ) aspect_ratio = mlt_properties_get_double( properties, "aspect_ratio" ); + int full_width = height * aspect_ratio + 1; + int full_height = height; + float scale_width = (float)full_width / (float)this->window_width; + float scale_height = (float)full_height / (float)this->window_height; + float display_aspect_ratio = (float)this->window_width / (float)this->window_height; + + SDL_Rect rect; + + if ( aspect_ratio == 1 ) + { + rect.w = this->window_width; + rect.h = this->window_height; + } + else if ( this->window_width < this->window_height * aspect_ratio ) + { + rect.w = this->window_width; + rect.h = this->window_width / aspect_ratio; + } + else + { + rect.w = this->window_height * aspect_ratio; + rect.h = this->window_height; + } + + rect.x = ( this->window_width - rect.w ) / 2; + rect.y = ( this->window_height - rect.h ) / 2; + + // Force an overlay recreation + if ( sdl_overlay != NULL ) + SDL_FreeYUVOverlay( sdl_overlay ); + // open SDL window with video overlay, if possible sdl_screen = SDL_SetVideoMode( this->window_width, this->window_height, 0, sdl_flags ); if ( sdl_screen != NULL ) { - SDL_Rect rect; - if ( this->window_width < this->window_height * aspect_ratio ) - { - rect.w = this->window_width; - rect.h = this->window_width / aspect_ratio; - } - else - { - rect.w = this->window_height * aspect_ratio; - rect.h = this->window_height; - } - - rect.x = ( this->window_width - rect.w ) / 2; - rect.y = ( this->window_height - rect.h ) / 2; - SDL_SetClipRect( sdl_screen, &rect ); - // Force an overlay recreation - if ( sdl_overlay != NULL ) - SDL_FreeYUVOverlay( sdl_overlay ); sdl_lock_display(); - sdl_overlay = SDL_CreateYUVOverlay( this->width, this->height, SDL_YUY2_OVERLAY, sdl_screen ); + sdl_overlay = SDL_CreateYUVOverlay( this->width - (this->width % 4), this->height- (this->height % 2 ), SDL_YUY2_OVERLAY, sdl_screen ); sdl_unlock_display(); } } @@ -358,15 +406,11 @@ static void *consumer_thread( void *arg ) if ( sdl_screen != NULL && sdl_overlay != NULL ) { buffer = sdl_overlay->pixels[ 0 ]; - if ( sdl_lock_display() ) + if ( SDL_LockYUVOverlay( sdl_overlay ) >= 0 ) { - if ( SDL_LockYUVOverlay( sdl_overlay ) >= 0 ) - { - mlt_resize_yuv422( buffer, this->width, this->height, image, width, height ); - SDL_UnlockYUVOverlay( sdl_overlay ); - SDL_DisplayYUVOverlay( sdl_overlay, &sdl_screen->clip_rect ); - } - sdl_unlock_display(); + mlt_resize_yuv422( buffer, this->width - (this->width % 4 ), this->height- (this->height % 2 ), image, width, height ); + SDL_UnlockYUVOverlay( sdl_overlay ); + SDL_DisplayYUVOverlay( sdl_overlay, &sdl_screen->clip_rect ); } } } -- 1.7.4.4