]> git.sesse.net Git - mlt/blobdiff - src/modules/core/transition_composite.c
Add service locks for parallelism.
[mlt] / src / modules / core / transition_composite.c
index 3930ecd83b871f6b87603200f906bdb413b72a7b..14e00575519a52f53c2bdc6c9c8ba34bae5088b1 100644 (file)
@@ -27,7 +27,7 @@
 #include <string.h>
 #include <math.h>
 
-typedef void ( *composite_line_fn )( uint8_t *dest, uint8_t *src, int width_src, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int softness );
+typedef void ( *composite_line_fn )( uint8_t *dest, uint8_t *src, int width_src, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int softness, uint32_t step );
 
 /** Geometry struct.
 */
@@ -201,7 +201,7 @@ static inline double delta_calculate( mlt_transition this, mlt_frame frame, mlt_
        return length * ( y - x ) / 2.0;
 }
 
-static int get_value( mlt_properties properties, char *preferred, char *fallback )
+static int get_value( mlt_properties properties, const char *preferred, const char *fallback )
 {
        int value = mlt_properties_get_int( properties, preferred );
        if ( value == 0 )
@@ -368,9 +368,9 @@ static void luma_read_yuv422( uint8_t *image, uint16_t **map, int width, int hei
                *p++ = ( image[ i ] - 16 ) * 299; // 299 = 65535 / 219
 }
 
-static inline int calculate_mix( uint16_t *luma, int j, int soft, int weight, int alpha )
+static inline int calculate_mix( uint16_t *luma, int j, int softness, int weight, int alpha, uint32_t step )
 {
-       return ( ( ( luma == NULL ) ? weight : smoothstep( luma[ j ], luma[ j ] + soft, weight + soft ) ) * alpha ) >> 8;
+       return ( ( luma ? smoothstep( luma[ j ], luma[ j ] + softness, step ) : weight ) * alpha ) >> 8;
 }
 
 static inline uint8_t sample_mix( uint8_t dest, uint8_t src, int mix )
@@ -381,14 +381,14 @@ static inline uint8_t sample_mix( uint8_t dest, uint8_t src, int mix )
 /** Composite a source line over a destination line
 */
 
-static void composite_line_yuv( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft )
+static void composite_line_yuv( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step )
 {
        register int j;
        register int mix;
 
        for ( j = 0; j < width; j ++ )
        {
-               mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ );
+               mix = calculate_mix( luma, j, soft, weight, *alpha_b ++, step );
                *dest = sample_mix( *dest, *src++, mix );
                dest++;
                *dest = sample_mix( *dest, *src++, mix );
@@ -398,14 +398,14 @@ static void composite_line_yuv( uint8_t *dest, uint8_t *src, int width, uint8_t
        }
 }
 
-static void composite_line_yuv_or( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft )
+static void composite_line_yuv_or( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step )
 {
        register int j;
        register int mix;
 
        for ( j = 0; j < width; j ++ )
        {
-               mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ | *alpha_a );
+               mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ | *alpha_a, step );
                *dest = sample_mix( *dest, *src++, mix );
                dest++;
                *dest = sample_mix( *dest, *src++, mix );
@@ -414,14 +414,14 @@ static void composite_line_yuv_or( uint8_t *dest, uint8_t *src, int width, uint8
        }
 }
 
-static void composite_line_yuv_and( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft )
+static void composite_line_yuv_and( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step  )
 {
        register int j;
        register int mix;
 
        for ( j = 0; j < width; j ++ )
        {
-               mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ & *alpha_a );
+               mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ & *alpha_a, step );
                *dest = sample_mix( *dest, *src++, mix );
                dest++;
                *dest = sample_mix( *dest, *src++, mix );
@@ -430,14 +430,14 @@ static void composite_line_yuv_and( uint8_t *dest, uint8_t *src, int width, uint
        }
 }
 
-static void composite_line_yuv_xor( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft )
+static void composite_line_yuv_xor( uint8_t *dest, uint8_t *src, int width, uint8_t *alpha_b, uint8_t *alpha_a, int weight, uint16_t *luma, int soft, uint32_t step )
 {
        register int j;
        register int mix;
 
        for ( j = 0; j < width; j ++ )
        {
-               mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ ^ *alpha_a );
+               mix = calculate_mix( luma, j, soft, weight, *alpha_b ++ ^ *alpha_a, step );
                *dest = sample_mix( *dest, *src++, mix );
                dest++;
                *dest = sample_mix( *dest, *src++, mix );
@@ -449,18 +449,20 @@ static void composite_line_yuv_xor( uint8_t *dest, uint8_t *src, int width, uint
 /** Composite function.
 */
 
-static int composite_yuv( uint8_t *p_dest, int width_dest, int height_dest, uint8_t *p_src, int width_src, int height_src, uint8_t *alpha_b, uint8_t *alpha_a, struct geometry_s geometry, int field, uint16_t *p_luma, int32_t softness, composite_line_fn line_fn )
+static int composite_yuv( uint8_t *p_dest, int width_dest, int height_dest, uint8_t *p_src, int width_src, int height_src, uint8_t *alpha_b, uint8_t *alpha_a, struct geometry_s geometry, int field, uint16_t *p_luma, double softness, composite_line_fn line_fn )
 {
        int ret = 0;
        int i;
        int x_src = -geometry.x_src, y_src = -geometry.y_src;
        int uneven_x_src = ( x_src % 2 );
-       int32_t weight = ( ( 1 << 16 ) - 1 ) * ( geometry.item.mix / 100 );
        int step = ( field > -1 ) ? 2 : 1;
        int bpp = 2;
        int stride_src = geometry.sw * bpp;
        int stride_dest = width_dest * bpp;
-       
+       int i_softness = ( 1 << 16 ) * softness;
+       int weight = ( ( 1 << 16 ) - 1 ) * geometry.item.mix / 100;
+       uint32_t luma_step = ( ( 1 << 16 ) - 1 ) * geometry.item.mix / 100 * ( 1.0 + softness );
+
        // Adjust to consumer scale
        int x = rint( geometry.item.x * width_dest / geometry.nw );
        int y = rint( geometry.item.y * height_dest / geometry.nh );
@@ -566,7 +568,7 @@ static int composite_yuv( uint8_t *p_dest, int width_dest, int height_dest, uint
        // now do the compositing only to cropped extents
        for ( i = 0; i < height_src; i += step )
        {
-               line_fn( p_dest, p_src, width_src, alpha_b, alpha_a, weight, p_luma, softness );
+               line_fn( p_dest, p_src, width_src, alpha_b, alpha_a, weight, p_luma, i_softness, luma_step );
 
                p_src += stride_src;
                p_dest += stride_dest;
@@ -624,7 +626,7 @@ static uint16_t* get_luma( mlt_transition this, mlt_properties properties, int w
                luma_height = height;
        }
 
-       if ( resource != NULL && strchr( resource, '%' ) )
+       if ( resource && resource[0] && strchr( resource, '%' ) )
        {
                // TODO: Clean up quick and dirty compressed/existence check
                FILE *test;
@@ -637,7 +639,28 @@ static uint16_t* get_luma( mlt_transition this, mlt_properties properties, int w
                resource = temp;
        }
 
-       if ( resource != NULL && ( luma_bitmap == NULL || luma_width != width || luma_height != height ) )
+       if ( resource && resource[0] )
+       {
+               char *old_luma = mlt_properties_get( properties, "_luma" );
+               int old_invert = mlt_properties_get_int( properties, "_luma_invert" );
+
+               if ( invert != old_invert || ( old_luma && old_luma[0] && strcmp( resource, old_luma ) ) )
+               {
+                       mlt_properties_set_data( properties, "_luma.orig_bitmap", NULL, 0, NULL, NULL );
+                       luma_bitmap = NULL;
+               }
+       }
+       else {
+               char *old_luma = mlt_properties_get( properties, "_luma" );
+               if ( old_luma && old_luma[0] )
+               {
+                       mlt_properties_set_data( properties, "_luma.orig_bitmap", NULL, 0, NULL, NULL );
+                       luma_bitmap = NULL;
+                       mlt_properties_set( properties, "_luma", NULL);
+               }
+       }
+
+       if ( resource && resource[0] && ( luma_bitmap == NULL || luma_width != width || luma_height != height ) )
        {
                uint16_t *orig_bitmap = mlt_properties_get_data( properties, "_luma.orig_bitmap", NULL );
                luma_width = mlt_properties_get_int( properties, "_luma.orig_width" );
@@ -725,6 +748,8 @@ static uint16_t* get_luma( mlt_transition this, mlt_properties properties, int w
                mlt_properties_set_int( properties, "_luma.width", width );
                mlt_properties_set_int( properties, "_luma.height", height );
                mlt_properties_set_data( properties, "_luma.bitmap", luma_bitmap, width * height * 2, mlt_pool_release, NULL );
+               mlt_properties_set( properties, "_luma", resource );
+               mlt_properties_set_int( properties, "_luma_invert", invert );
        }
        return luma_bitmap;
 }
@@ -834,6 +859,11 @@ static int get_b_frame_image( mlt_transition this, mlt_frame b_frame, uint8_t **
 
        ret = mlt_frame_get_image( b_frame, image, &format, width, height, 1 );
 
+       // composite_yuv uses geometry->sw to determine source stride, which
+       // should equal the image width if not using crop property.
+       if ( !mlt_properties_get( properties, "crop" ) )
+               geometry->sw = *width;
+
        // Set the frame back
        mlt_properties_set_int( b_props, "resize_alpha", resize_alpha );
 
@@ -1115,7 +1145,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f
                uint8_t *alpha_b = NULL;
 
                // Composites always need scaling... defaulting to lowest
-               char *rescale = mlt_properties_get( a_props, "rescale.interp" );
+               const char *rescale = mlt_properties_get( a_props, "rescale.interp" );
                if ( rescale == NULL || !strcmp( rescale, "none" ) )
                        rescale = "nearest";
                mlt_properties_set( a_props, "rescale.interp", rescale );
@@ -1123,8 +1153,9 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f
 
                // Do the calculation
                // NB: Locks needed here since the properties are being modified
+               int invert = mlt_properties_get_int( properties, "invert" );
                mlt_service_lock( MLT_TRANSITION_SERVICE( this ) );
-               composite_calculate( this, &result, a_frame, position );
+               composite_calculate( this, &result, invert ? b_frame : a_frame, position );
                mlt_service_unlock( MLT_TRANSITION_SERVICE( this ) );
 
                // Since we are the consumer of the b_frame, we must pass along these
@@ -1152,7 +1183,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f
                }
 
                // Get the image from the a frame
-               mlt_frame_get_image( a_frame, image, format, width, height, 1 );
+               mlt_frame_get_image( a_frame, invert ? &image_b : image, format, width, height, 1 );
                alpha_a = mlt_frame_get_alpha_mask( a_frame );
 
                // Optimisation - no compositing required
@@ -1182,7 +1213,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f
                        height_b = mlt_properties_get_int( a_props, "dest_height" );
                }
 
-               if ( *image != image_b && ( image_b != NULL || get_b_frame_image( this, b_frame, &image_b, &width_b, &height_b, &result ) == 0 ) )
+               if ( *image != image_b && ( ( invert ? 0 : image_b ) || get_b_frame_image( this, b_frame, invert ? image : &image_b, &width_b, &height_b, &result ) == 0 ) )
                {
                        uint8_t *dest = *image;
                        uint8_t *src = image_b;
@@ -1191,8 +1222,10 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f
                                        mlt_properties_get_int( properties, "progressive" );
                        int field;
                        
-                       int32_t luma_softness = mlt_properties_get_double( properties, "softness" ) * ( 1 << 16 );
+                       double luma_softness = mlt_properties_get_double( properties, "softness" );
+                       mlt_service_lock( MLT_TRANSITION_SERVICE( this ) );
                        uint16_t *luma_bitmap = get_luma( this, properties, width_b, height_b );
+                       mlt_service_unlock( MLT_TRANSITION_SERVICE( this ) );
                        char *operator = mlt_properties_get( properties, "operator" );
 
                        alpha_b = alpha_b == NULL ? mlt_frame_get_alpha_mask( b_frame ) : alpha_b;
@@ -1225,7 +1258,7 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f
                                // Do the calculation if we need to
                                // NB: Locks needed here since the properties are being modified
                                mlt_service_lock( MLT_TRANSITION_SERVICE( this ) );
-                               composite_calculate( this, &result, a_frame, field_position );
+                               composite_calculate( this, &result, invert ? b_frame : a_frame, field_position );
                                mlt_service_unlock( MLT_TRANSITION_SERVICE( this ) );
 
                                if ( mlt_properties_get_int( properties, "titles" ) )
@@ -1253,7 +1286,10 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f
                                }
 
                                // Composite the b_frame on the a_frame
-                               composite_yuv( dest, *width, *height, src, width_b, height_b, alpha_b, alpha_a, result, progressive ? -1 : field, luma_bitmap, luma_softness, line_fn );
+                               if ( invert )
+                                       composite_yuv( dest, width_b, height_b, src, *width, *height, alpha_a, alpha_b, result, progressive ? -1 : field, luma_bitmap, luma_softness, line_fn );
+                               else
+                                       composite_yuv( dest, *width, *height, src, width_b, height_b, alpha_b, alpha_a, result, progressive ? -1 : field, luma_bitmap, luma_softness, line_fn );
                        }
                }
        }
@@ -1307,11 +1343,14 @@ mlt_transition transition_composite_init( mlt_profile profile, mlt_service_type
                mlt_properties_set( properties, "start", arg != NULL ? arg : "0,0:100%x100%" );
                
                // Default factory
-               mlt_properties_set( properties, "factory", "fezzik" );
+               mlt_properties_set( properties, "factory", mlt_environment( "MLT_PRODUCER" ) );
 
                // Use alignment (and hence alpha of b frame)
                mlt_properties_set_int( properties, "aligned", 1 );
 
+               // Default to progressive rendering
+               mlt_properties_set_int( properties, "progressive", 1 );
+               
                // Inform apps and framework that this is a video only transition
                mlt_properties_set_int( properties, "_transition_type", 1 );
        }