Added ref_count method to properties; temporary work around for test card; titles...
[melted] / src / modules / sdl / consumer_sdl_still.c
index 105d887..998d3e0 100644 (file)
@@ -176,6 +176,8 @@ static int consumer_start( mlt_consumer parent )
                        mlt_properties_set_int( this->properties, "height", this->height );
                }
 
+               //this->width = this->height * this->display_aspect;
+
                // Inherit the scheduling priority
                pthread_attr_init( &thread_attributes );
                pthread_attr_setinheritsched( &thread_attributes, PTHREAD_INHERIT_SCHED );
@@ -198,9 +200,6 @@ static int consumer_stop( mlt_consumer parent )
 
                pthread_join( this->thread, NULL );
                this->joined = 1;
-
-               mlt_frame_close( parent->put );
-               parent->put = NULL;
        }
 
        return 0;
@@ -225,16 +224,143 @@ static void sdl_unlock_display( )
                SDL_UnlockSurface( screen );
 }
 
+static inline void display_1( SDL_Surface *screen, SDL_Rect rect, uint8_t *image, int width, int height )
+{
+       // Generate the affine transform scaling values
+       int scale_width = ( width << 16 ) / rect.w;
+       int scale_height = ( height << 16 ) / rect.h;
+       int stride = width * 3;
+       int x, y, row_index;
+       uint8_t *q, *row;
+
+       // Constants defined for clarity and optimisation
+       int scanlength = screen->pitch;
+       uint8_t *start = ( uint8_t * )screen->pixels + rect.y * scanlength + rect.x;
+       uint8_t *p;
+
+       // Iterate through the screen using a very basic scaling algorithm
+       for ( y = 0; y < rect.h; y ++ )
+       {
+               p = start;
+               row_index = ( scale_height * y ) >> 16;
+               row = image + stride * row_index;
+               for ( x = 0; x < rect.w; x ++ )
+               {
+                       q = row + ( ( ( scale_width * x ) >> 16 ) * 3 );
+                       *p ++ = SDL_MapRGB( screen->format, *q, *( q + 1 ), *( q + 2 ) );
+               }
+               start += scanlength;
+       }
+}
+
+static inline void display_2( SDL_Surface *screen, SDL_Rect rect, uint8_t *image, int width, int height )
+{
+       // Generate the affine transform scaling values
+       int scale_width = ( width << 16 ) / rect.w;
+       int scale_height = ( height << 16 ) / rect.h;
+       int stride = width * 3;
+       int x, y, row_index;
+       uint8_t *q, *row;
+
+       // Constants defined for clarity and optimisation
+       int scanlength = screen->pitch / 2;
+       uint16_t *start = ( uint16_t * )screen->pixels + rect.y * scanlength + rect.x;
+       uint16_t *p;
+
+       // Iterate through the screen using a very basic scaling algorithm
+       for ( y = 0; y < rect.h; y ++ )
+       {
+               p = start;
+               row_index = ( scale_height * y ) >> 16;
+               row = image + stride * row_index;
+               for ( x = 0; x < rect.w; x ++ )
+               {
+                       q = row + ( ( ( scale_width * x ) >> 16 ) * 3 );
+                       *p ++ = SDL_MapRGB( screen->format, *q, *( q + 1 ), *( q + 2 ) );
+               }
+               start += scanlength;
+       }
+}
+
+static inline void display_3( SDL_Surface *screen, SDL_Rect rect, uint8_t *image, int width, int height )
+{
+       // Generate the affine transform scaling values
+       int scale_width = ( width << 16 ) / rect.w;
+       int scale_height = ( height << 16 ) / rect.h;
+       int stride = width * 3;
+       int x, y, row_index;
+       uint8_t *q, *row;
+
+       // Constants defined for clarity and optimisation
+       int scanlength = screen->pitch;
+       uint8_t *start = ( uint8_t * )screen->pixels + rect.y * scanlength + rect.x;
+       uint8_t *p;
+       uint32_t pixel;
+
+       // Iterate through the screen using a very basic scaling algorithm
+       for ( y = 0; y < rect.h; y ++ )
+       {
+               p = start;
+               row_index = ( scale_height * y ) >> 16;
+               row = image + stride * row_index;
+               for ( x = 0; x < rect.w; x ++ )
+               {
+                       q = row + ( ( ( scale_width * x ) >> 16 ) * 3 );
+                       pixel = SDL_MapRGB( screen->format, *q, *( q + 1 ), *( q + 2 ) );
+                       *p ++ = (pixel & 0xFF0000) >> 16;
+                       *p ++ = (pixel & 0x00FF00) >> 8;
+                       *p ++ = (pixel & 0x0000FF);
+               }
+               start += scanlength;
+       }
+}
+
+static inline void display_4( SDL_Surface *screen, SDL_Rect rect, uint8_t *image, int width, int height )
+{
+       // Generate the affine transform scaling values
+       int scale_width = ( width << 16 ) / rect.w;
+       int scale_height = ( height << 16 ) / rect.h;
+       int stride = width * 3;
+       int x, y, row_index;
+       uint8_t *q, *row;
+
+       // Constants defined for clarity and optimisation
+       int scanlength = screen->pitch / 4;
+       uint32_t *start = ( uint32_t * )screen->pixels + rect.y * scanlength + rect.x;
+       uint32_t *p;
+
+       // Iterate through the screen using a very basic scaling algorithm
+       for ( y = 0; y < rect.h; y ++ )
+       {
+               p = start;
+               row_index = ( scale_height * y ) >> 16;
+               row = image + stride * row_index;
+               for ( x = 0; x < rect.w; x ++ )
+               {
+                       q = row + ( ( ( scale_width * x ) >> 16 ) * 3 );
+                       *p ++ = SDL_MapRGB( screen->format, *q, *( q + 1 ), *( q + 2 ) );
+               }
+               start += scanlength;
+       }
+}
+
 static int consumer_play_video( consumer_sdl this, mlt_frame frame )
 {
        // Get the properties of this consumer
        mlt_properties properties = this->properties;
 
        mlt_image_format vfmt = mlt_image_rgb24;
-       int width = this->width, height = this->height;
-       uint8_t *image;
+       int height = this->height;
+       int width = this->width;
+       uint8_t *image = NULL;
        int changed = 0;
 
+       void ( *lock )( void ) = mlt_properties_get_data( properties, "app_lock", NULL );
+       void ( *unlock )( void ) = mlt_properties_get_data( properties, "app_unlock", NULL );
+
+       if ( lock != NULL ) lock( );
+
+       sdl_lock_display();
        
        // Handle events
        if ( this->sdl_screen != NULL )
@@ -273,68 +399,79 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame )
                }
        }
 
-       if ( width != this->width || height != this->height || 
-                ( ( int )( this->last_frame_aspect * 1000 ) != ( int )( mlt_frame_get_aspect_ratio( frame ) * 1000 ) &&
-                ( mlt_frame_get_aspect_ratio( frame ) != 1.0 || this->last_frame_aspect == 0.0 ) ) )
-
+       if ( this->sdl_screen == NULL || changed || mlt_properties_get_int( properties, "changed" ) == 2 )
        {
-               this->width = width;
-               this->height = height;
-               this->last_frame_aspect = mlt_frame_get_aspect_ratio( frame );
+               // open SDL window 
+               this->sdl_screen = SDL_SetVideoMode( this->window_width, this->window_height, 0, this->sdl_flags );
+               if ( consumer_get_dimensions( &this->window_width, &this->window_height ) )
+                       this->sdl_screen = SDL_SetVideoMode( this->window_width, this->window_height, 0, this->sdl_flags );
+
                changed = 1;
+               mlt_properties_set_int( properties, "changed", 0 );
+       }
+       else
+       {
+               changed = mlt_properties_get_int( properties, "changed" ) | mlt_properties_get_int( mlt_frame_properties( frame ), "refresh" );
+               mlt_properties_set_int( properties, "changed", 0 );
        }
 
-       if ( this->sdl_screen == NULL || changed )
+       
+       if ( changed == 0 &&
+                this->last_position == mlt_frame_get_position( frame ) &&
+                this->last_producer == mlt_properties_get_data( mlt_frame_properties( frame ), "_producer", NULL ) )
        {
-               // Determine frame's display aspect ratio
-               float frame_aspect = mlt_frame_get_aspect_ratio( frame ) * this->width / this->height;
-               
-               // Determine window's new display aspect ratio
-               float this_aspect = ( float )this->window_width / this->window_height;
+               sdl_unlock_display( );
+               if ( unlock != NULL )
+                       unlock( );
+               return 0;
+       }
+
+       // Update last frame shown info
+       this->last_position = mlt_frame_get_position( frame );
+       this->last_producer = mlt_properties_get_data( mlt_frame_properties( frame ), "_producer", NULL );
+
+       // Get the image, width and height
+       if ( image == NULL )
+       {
+               mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
+
+               // I would like to provide upstream scaling here, but this is incorrect
+               // Something? (or everything?) is too sensitive to aspect ratio
+               //width = this->rect.w;
+               //height = this->rect.h;
+               //mlt_properties_set( mlt_frame_properties( frame ), "distort", "true" );
+               //mlt_properties_set_int( mlt_frame_properties( frame ), "normalised_width", width );
+               //mlt_properties_set_int( mlt_frame_properties( frame ), "normalised_height", height );
+
+               mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 );
+       }
 
-               // If using hardware scaler
-               if ( mlt_properties_get( properties, "rescale" ) != NULL &&
-                       !strcmp( mlt_properties_get( properties, "rescale" ), "none" ) )
+       if ( image != NULL )
+       {
+               char *rescale = mlt_properties_get( properties, "rescale" );
+               if ( rescale != NULL && strcmp( rescale, "none" ) )
                {
-                       // Special case optimisation to negate odd effect of sample aspect ratio
-                       // not corresponding exactly with image resolution.
-                       if ( ( (int)( this_aspect * 1000 ) == (int)( this->display_aspect * 1000 ) ) && 
-                                ( (int)( mlt_frame_get_aspect_ratio( frame ) * 1000 ) == (int)( this->aspect_ratio * 1000 ) ) )
+                       float this_aspect = this->display_aspect / ( ( float )this->window_width / ( float )this->window_height );
+                       this->rect.w = this_aspect * this->window_width;
+                       this->rect.h = this->window_height;
+                       if ( this->rect.w > this->window_width )
                        {
                                this->rect.w = this->window_width;
-                               this->rect.h = this->window_height;
-                       }
-                       else
-                       {
-                               // Use hardware scaler to normalise display aspect ratio
-                               this->rect.w = frame_aspect / this_aspect * this->window_width;
-                               this->rect.h = this->window_height;
-                               if ( this->rect.w > this->window_width )
-                               {
-                                       this->rect.w = this->window_width;
-                                       this->rect.h = this_aspect / frame_aspect * this->window_height;
-                               }
+                               this->rect.h = ( 1.0 / this_aspect ) * this->window_height;
                        }
                }
-               // Special case optimisation to negate odd effect of sample aspect ratio
-               // not corresponding exactly with image resolution.
-               else if ( (int)( this_aspect * 1000 ) == (int)( this->display_aspect * 1000 ) ) 
-               {
-                       this->rect.w = this->window_width;
-                       this->rect.h = this->window_height;
-               }
-               // Use hardware scaler to normalise sample aspect ratio
-               else if ( this->window_height * this->display_aspect > this->window_width )
-               {
-                       this->rect.w = this->window_width;
-                       this->rect.h = this->window_width / this->display_aspect;
-               }
                else
                {
-                       this->rect.w = this->window_height * this->display_aspect;
+                       float frame_aspect = mlt_frame_get_aspect_ratio( frame ) * width / height;
+                       this->rect.w = frame_aspect * this->window_height;
                        this->rect.h = this->window_height;
+                       if ( this->rect.w > this->window_width )
+                       {
+                               this->rect.w = this->window_width;
+                               this->rect.h = ( 1.0 / frame_aspect ) * this->window_width;
+                       }
                }
-               
+
                this->rect.x = ( this->window_width - this->rect.w ) / 2;
                this->rect.y = ( this->window_height - this->rect.h ) / 2;
 
@@ -342,95 +479,40 @@ static int consumer_play_video( consumer_sdl this, mlt_frame frame )
                mlt_properties_set_int( this->properties, "rect_y", this->rect.y );
                mlt_properties_set_int( this->properties, "rect_w", this->rect.w );
                mlt_properties_set_int( this->properties, "rect_h", this->rect.h );
-               
-               // open SDL window 
-               sdl_lock_display();
-               this->sdl_screen = SDL_SetVideoMode( this->window_width, this->window_height, 16, this->sdl_flags );
-               consumer_get_dimensions( &this->window_width, &this->window_height );
-               sdl_unlock_display();
-               changed = 1;
-       }
-               
-       if ( mlt_properties_get_int( properties, "changed" ) )
-       {
-               sdl_lock_display();
-               this->sdl_screen = SDL_SetVideoMode( this->window_width, this->window_height, 16, this->sdl_flags );
-               SDL_SetClipRect( this->sdl_screen, &this->rect );
-               SDL_Flip( this->sdl_screen );
-               consumer_get_dimensions( &this->window_width, &this->window_height );
-               sdl_unlock_display();
-               mlt_properties_set_int( properties, "changed", 0 );
-               changed = 1;
        }
-
-       if ( changed == 0 &&
-                this->last_position == mlt_frame_get_position( frame ) &&
-                this->last_producer == mlt_properties_get_data( mlt_frame_properties( frame ), "_producer", NULL ) )
-               return 0;
-
-       // Update last frame shown info
-       this->last_position = mlt_frame_get_position( frame );
-       this->last_producer = mlt_properties_get_data( mlt_frame_properties( frame ), "_producer", NULL );
-
-       // Get the image, width and height
-       mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
-       mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 );
        
        if ( this->sdl_screen != NULL )
        {
-               sdl_lock_display();
-
-               // Calculate the scan length
-               int scanlength = this->sdl_screen->pitch / 2;
-
-               // Obtain the clip rect from the screen
-               SDL_Rect rect = this->rect;
+               memset( this->sdl_screen->pixels, 0, this->window_width * this->window_height * this->sdl_screen->format->BytesPerPixel );
 
-               // Generate the affine transform scaling values
-               float scale_width = ( float )width / ( float )rect.w;
-               float scale_height = ( float )height / ( float )rect.h;
-
-               // Constants defined for clarity and optimisation
-               int stride = width * 3;
-               uint16_t *start = ( uint16_t * )this->sdl_screen->pixels + rect.y * scanlength + rect.x;
-
-               int y;
-
-               // Iterate through the screen using a very basic scaling algorithm
-               for ( y = 0; y < rect.h; y ++ )
+               switch( this->sdl_screen->format->BytesPerPixel )
                {
-                       // Obtain the pointer to the current screen row
-                       uint16_t *p = start;
-
-                       // Calculate the row_index
-                       int row_index = ( int )( scale_height * y );
-
-                       // Calculate the pointer for the y offset (positioned on B instead of R)
-                       uint8_t *row = image + stride * row_index;
-
-                       int x;
-
-                       // Iterate through the screen width
-                       for ( x = 0; x < rect.w; x ++ )
-                       {
-                               // Obtain the pixel pointer
-                               uint8_t *q = row + ( ( int )( scale_width * x ) * 3 );
-
-                               // Map the BGR colour from the frame to the SDL format
-                               *p ++ = SDL_MapRGB( this->sdl_screen->format, *q, *( q + 1 ), *( q + 2 ) );
-                       }
-
-                       // Move to the next row
-                       start += scanlength;
+                       case 1:
+                               display_1( this->sdl_screen, this->rect, image, width, height );
+                               break;
+                       case 2:
+                               display_2( this->sdl_screen, this->rect, image, width, height );
+                               break;
+                       case 3:
+                               display_3( this->sdl_screen, this->rect, image, width, height );
+                               break;
+                       case 4:
+                               display_4( this->sdl_screen, this->rect, image, width, height );
+                               break;
+                       default:
+                               fprintf( stderr, "Unsupported video depth %d\n", this->sdl_screen->format->BytesPerPixel );
+                               break;
                }
 
                // Flip it into sight
                SDL_Flip( this->sdl_screen );
-
-               sdl_unlock_display();
        }
 
-       return 0;
+       sdl_unlock_display();
+
+       if ( unlock != NULL ) unlock( );
+
+       return 1;
 }
 
 /** Threaded wrapper for pipe.
@@ -446,7 +528,7 @@ static void *consumer_thread( void *arg )
 
        // internal intialization
        mlt_frame frame = NULL;
-       struct timespec tm = { 0, 1000 };
+       struct timespec tm = { 0, 1000000 };
 
        if ( mlt_properties_get_int( mlt_consumer_properties( consumer ), "sdl_started" ) == 0 )
        {
@@ -461,8 +543,13 @@ static void *consumer_thread( void *arg )
        }
        else
        {
-               this->sdl_screen = SDL_GetVideoSurface( );
-               mlt_properties_set_int( mlt_consumer_properties( consumer ), "changed", 1 );
+               mlt_properties_set_int( mlt_consumer_properties( consumer ), "changed", 2 );
+               if ( SDL_GetVideoSurface( ) != NULL )
+               {
+                       this->sdl_screen = SDL_GetVideoSurface( );
+                       consumer_get_dimensions( &this->window_width, &this->window_height );
+                       mlt_properties_set_int( mlt_consumer_properties( consumer ), "changed", 0 );
+               }
        }
 
        // Loop until told not to
@@ -474,9 +561,9 @@ static void *consumer_thread( void *arg )
                // Ensure that we have a frame
                if ( frame != NULL )
                {
-                       consumer_play_video( this, frame );
+                       if ( consumer_play_video( this, frame ) == 0 )
+                               nanosleep( &tm, NULL );
                        mlt_frame_close( frame );
-                       nanosleep( &tm, NULL );
                }
        }
 
@@ -498,9 +585,6 @@ static int consumer_get_dimensions( int *width, int *height )
        // Specify the SDL Version
        SDL_VERSION( &wm.version );
 
-       // Lock the display
-       sdl_lock_display();
-
        // Get the wm structure
        if ( SDL_GetWMInfo( &wm ) == 1 )
        {
@@ -526,9 +610,6 @@ static int consumer_get_dimensions( int *width, int *height )
                }
        }
 
-       // Unlock the display
-       sdl_lock_display();
-
        return changed;
 }