X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=mlt%2Fsrc%2Fmodules%2Fsdl%2Fconsumer_sdl.c;h=43bb247f6bc780f4be3a41cf11eeb57f51bfa94b;hb=f724a3318ee2e9c595a31ea788320f089909f777;hp=c75237e7d10eb0e824ee9760e3e676860115e8a9;hpb=fc579010c07e3daa94db446a9623d9bb996892d2;p=melted diff --git a/mlt/src/modules/sdl/consumer_sdl.c b/mlt/src/modules/sdl/consumer_sdl.c index c75237e..43bb247 100644 --- a/mlt/src/modules/sdl/consumer_sdl.c +++ b/mlt/src/modules/sdl/consumer_sdl.c @@ -46,6 +46,12 @@ struct consumer_sdl_s pthread_cond_t audio_cond; int window_width; int window_height; + int width; + int height; + int playing; + mlt_frame *queue; + int size; + int count; }; /** Forward references to static functions. @@ -53,13 +59,13 @@ struct consumer_sdl_s static void consumer_close( mlt_consumer parent ); static void *consumer_thread( void * ); -static void consumer_get_dimensions( int *width, int *height ); +static int consumer_get_dimensions( int *width, int *height ); /** This is what will be called by the factory - anything can be passed in via the argument, but keep it simple. */ -mlt_consumer consumer_sdl_init( void *dummy ) +mlt_consumer consumer_sdl_init( char *arg ) { // Create the consumer object consumer_sdl this = calloc( sizeof( struct consumer_sdl_s ), 1 ); @@ -85,8 +91,23 @@ mlt_consumer consumer_sdl_init( void *dummy ) pthread_mutex_init( &this->audio_mutex, NULL ); pthread_cond_init( &this->audio_cond, NULL); - // TODO: process actual param - + // process actual param + if ( arg == NULL || !strcmp( arg, "PAL" ) ) + { + this->width = 720; + this->height = 576; + } + else if ( !strcmp( arg, "NTSC" ) ) + { + this->width = 720; + this->height = 480; + } + else if ( sscanf( arg, "%dx%d", &this->width, &this->height ) != 2 ) + { + this->width = 720; + this->height = 576; + } + // Create the the thread pthread_create( &this->thread, NULL, consumer_thread, this ); @@ -114,7 +135,7 @@ static void sdl_unlock_display( ) SDL_UnlockSurface( screen ); } -void sdl_fill_audio( void *udata, Uint8 *stream, int len ) +void sdl_fill_audio( void *udata, uint8_t *stream, int len ) { consumer_sdl this = udata; @@ -123,7 +144,7 @@ void sdl_fill_audio( void *udata, Uint8 *stream, int len ) pthread_mutex_lock( &this->audio_mutex ); - // Experimental - block until audio received + // Block until audio received while ( this->running && len > this->audio_avail ) pthread_cond_wait( &this->audio_cond, &this->audio_mutex ); @@ -152,6 +173,10 @@ void sdl_fill_audio( void *udata, Uint8 *stream, int len ) // No audio left this->audio_avail = 0; } + + // We're definitely playing now + this->playing = 1; + pthread_cond_broadcast( &this->audio_cond ); pthread_mutex_unlock( &this->audio_mutex ); } @@ -170,6 +195,9 @@ static void *consumer_thread( void *arg ) // Get the service assoicated to the consumer mlt_service service = mlt_consumer_service( consumer ); + // Get the properties of this consumer + mlt_properties properties = this->properties; + // Define a frame pointer mlt_frame frame; @@ -194,7 +222,7 @@ static void *consumer_thread( void *arg ) if ( mlt_service_get_frame( service, &frame, 0 ) == 0 ) { mlt_image_format vfmt = mlt_image_yuv422; - int width, height; + int width = this->width, height = this->height; uint8_t *image; mlt_audio_format afmt = mlt_audio_pcm; @@ -202,6 +230,7 @@ static void *consumer_thread( void *arg ) int samples; int frequency; int16_t *pcm; + int changed = 0; mlt_frame_get_audio( frame, &pcm, &afmt, &frequency, &channels, &samples ); if ( init_audio == 1 ) @@ -212,7 +241,7 @@ static void *consumer_thread( void *arg ) request.freq = frequency; request.format = AUDIO_S16; request.channels = channels; - request.samples = 1024; + request.samples = 2048; request.callback = sdl_fill_audio; request.userdata = (void *)this; if ( SDL_OpenAudio( &request, NULL ) < 0 ) @@ -232,67 +261,131 @@ static void *consumer_thread( void *arg ) pthread_cond_broadcast( &this->audio_cond ); pthread_mutex_unlock( &this->audio_mutex ); - // Get the image, width and height - mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); - if ( width != this->window_width || height != this->window_height ) + if ( this->count == this->size ) + { + this->size += 25; + this->queue = realloc( this->queue, sizeof( mlt_frame ) * this->size ); + } + this->queue[ this->count ++ ] = frame; + + if ( this->playing ) { - SDL_Rect rect; - this->window_width = rect.w = width; - this->window_height = rect.h = height; + // We're working on the oldest frame now + frame = this->queue[ 0 ]; + + // Shunt the frames in the queue down + int i = 0; + for ( i = 1; i < this->count; i ++ ) + this->queue[ i - 1 ] = this->queue[ i ]; + this->count --; + + // Get the image, width and height + mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); - // open SDL window with video overlay, if possible - if ( sdl_screen == NULL ) - sdl_screen = SDL_SetVideoMode( width, height, 0, sdl_flags ); if ( sdl_screen != NULL ) { - rect.x = rect.y = 0; + SDL_Event event; + changed = consumer_get_dimensions( &this->window_width, &this->window_height ); - // XXX: this is a little hack until we have some sort of aspect - // ratio property on images. - if ( rect.h <= 486 ) + while ( SDL_PollEvent( &event ) ) { - rect.w = 640; - rect.x = ( 720 - 640 ) / 2; + switch( event.type ) + { + case SDL_VIDEORESIZE: + this->window_width = event.resize.w; + this->window_height = event.resize.h; + changed = 1; + break; + case SDL_KEYDOWN: + { + mlt_producer producer = mlt_properties_get_data( properties, "transport_producer", NULL ); + void (*callback)( mlt_producer, char * ) = mlt_properties_get_data( properties, "transport_callback", NULL ); + if ( callback != NULL && producer != NULL ) + callback( producer, SDL_GetKeyName(event.key.keysym.sym) ); + } + break; + } } - else + + if ( width != this->width || height != this->height ) { - rect.h = 540; - rect.y = ( 576 - 540 ) / 2; + this->width = width; + this->height = height; + changed = 1; } + } - SDL_SetClipRect( sdl_screen, &rect ); + 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" ); + + if ( this->window_width == 0 || this->window_height == 0 ) + { + this->window_width = width; + this->window_height = height; + } + + // 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( width, height, SDL_YUY2_OVERLAY, sdl_screen ); - sdl_unlock_display(); + // 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_unlock_display(); + } } - } - if ( sdl_screen != NULL && sdl_overlay != NULL ) - { - buffer = sdl_overlay->pixels[ 0 ]; - if ( sdl_lock_display() ) + if ( sdl_screen != NULL && sdl_overlay != NULL ) { - if ( SDL_LockYUVOverlay( sdl_overlay ) >= 0 ) + buffer = sdl_overlay->pixels[ 0 ]; + if ( sdl_lock_display() ) { - memcpy( buffer, image, width * height * 2 ); - SDL_UnlockYUVOverlay( sdl_overlay ); - SDL_DisplayYUVOverlay( sdl_overlay, &sdl_screen->clip_rect ); + 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(); } - sdl_unlock_display(); } } else { - // TODO: allocate buffer? + frame = NULL; } // Close the frame - mlt_frame_close( frame ); + if ( frame != NULL ) + mlt_frame_close( frame ); + + if ( this->count ) + mlt_frame_get_image( this->queue[ this->count - 1 ], &image, &vfmt, &width, &height, 0 ); } else { @@ -310,8 +403,10 @@ static void *consumer_thread( void *arg ) return NULL; } -static void consumer_get_dimensions( int *width, int *height ) +static int consumer_get_dimensions( int *width, int *height ) { + int changed = 0; + // SDL windows manager structure SDL_SysWMinfo wm; @@ -334,11 +429,16 @@ static void consumer_get_dimensions( int *width, int *height ) XWindowAttributes attr; XGetWindowAttributes( display, window, &attr ); + // Determine whether window has changed + changed = *width != attr.width || *height != attr.height; + // Return width and height *width = attr.width; *height = attr.height; } } + + return changed; } /** Callback to allow override of the close method.