X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmodules%2Fcore%2Ffilter_rescale.c;h=2f7f933fab6517ffde052efc05be9145626e1d00;hb=64a0ea6e23df2d9cae46e98bd34893397134e75c;hp=25ca5fcff7d38ce347e7101ef7ba51f9c13bd184;hpb=b1616107824f9c1b2e83c97d9a8d3b0cc700ef5f;p=mlt diff --git a/src/modules/core/filter_rescale.c b/src/modules/core/filter_rescale.c index 25ca5fcf..2f7f933f 100644 --- a/src/modules/core/filter_rescale.c +++ b/src/modules/core/filter_rescale.c @@ -20,142 +20,137 @@ #include #include +#include +#include #include #include #include #include -typedef int ( *image_scaler )( mlt_frame this, uint8_t **image, mlt_image_format iformat, mlt_image_format oformat, int iwidth, int iheight, int owidth, int oheight ); +/** virtual function declaration for an image scaler + * + * image scaler implementations are expected to support the following in and out formats: + * yuv422 -> yuv422 + * rgb24 -> rgb24 + * rgb24a -> rgb24a + * rgb24 -> yuv422 + * rgb24a -> yuv422 + */ -static void scale_alpha( mlt_frame this, int iwidth, int iheight, int owidth, int oheight ); +typedef int ( *image_scaler )( mlt_frame frame, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ); -static int filter_scale( mlt_frame this, uint8_t **image, mlt_image_format iformat, mlt_image_format oformat, int iwidth, int iheight, int owidth, int oheight ) +static int filter_scale( mlt_frame frame, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ) { - // Get the properties - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); - - // Get the rescaling interpolsation - char *interps = mlt_properties_get( properties, "rescale.interp" ); - - // Carry out the rescaling - if ( iformat == mlt_image_yuv422 && oformat == mlt_image_yuv422 ) - { - // Scale the frame - mlt_frame_rescale_yuv422( this, owidth, oheight ); - - // Return the output - *image = mlt_properties_get_data( properties, "image", NULL ); - - // Scale the alpha channel only if exists and not correct size - int alpha_size = 0; - mlt_properties_get_data( properties, "alpha", &alpha_size ); - if ( alpha_size > 0 && alpha_size != ( owidth * oheight ) ) - scale_alpha( this, iwidth, iheight, owidth, oheight ); - } - else if ( iformat == mlt_image_rgb24 || iformat == mlt_image_rgb24a ) - { - int bpp = (iformat == mlt_image_rgb24a ? 4 : 3 ); - - // Create the yuv image - uint8_t *output = mlt_pool_alloc( iwidth * ( iheight + 1 ) * 2 ); + // Create the output image + uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * 2 ); - if ( strcmp( interps, "none" ) && ( iwidth != owidth || iheight != oheight ) ) - { - // Extract YUV422 and alpha - if ( bpp == 4 ) - { - // Allocate the alpha mask - uint8_t *alpha = mlt_pool_alloc( iwidth * ( iheight + 1 ) ); + // Calculate strides + int istride = iwidth * 2; + int ostride = owidth * 2; + iwidth = iwidth - ( iwidth % 4 ); - // Convert the image and extract alpha - mlt_convert_rgb24a_to_yuv422( *image, iwidth, iheight, iwidth * 4, output, alpha ); + // Derived coordinates + int dy, dx; - mlt_properties_set_data( properties, "alpha", alpha, iwidth * ( iheight + 1 ), ( mlt_destructor )mlt_pool_release, NULL ); + // Calculate ranges + int out_x_range = owidth / 2; + int out_y_range = oheight / 2; + int in_x_range = iwidth / 2; + int in_y_range = iheight / 2; - scale_alpha( this, iwidth, iheight, owidth, oheight ); - } - else - { - // No alpha to extract - mlt_convert_rgb24_to_yuv422( *image, iwidth, iheight, iwidth * 3, output ); - } + // Output pointers + register uint8_t *out_line = output; + register uint8_t *out_ptr; - mlt_properties_set_data( properties, "image", output, iwidth * ( iheight + 1 ) * 2, ( mlt_destructor )mlt_pool_release, NULL ); + // Calculate a middle pointer + uint8_t *in_middle = *image + istride * in_y_range + in_x_range * 2; + uint8_t *in_line; - // Scale the frame - output = mlt_frame_rescale_yuv422( this, owidth, oheight ); + // Generate the affine transform scaling values + register int scale_width = ( iwidth << 16 ) / owidth; + register int scale_height = ( iheight << 16 ) / oheight; + register int base = 0; - } - else - { - // Extract YUV422 and alpha - if ( bpp == 4 ) - { - // Allocate the alpha mask - uint8_t *alpha = mlt_pool_alloc( owidth * ( oheight + 1 ) ); + int outer = out_x_range * scale_width; + int bottom = out_y_range * scale_height; - // Convert the image and extract alpha - mlt_convert_rgb24a_to_yuv422( *image, owidth, oheight, owidth * 4, output, alpha ); + // Loop for the entirety of our output height. + for ( dy = - bottom; dy < bottom; dy += scale_height ) + { + // Start at the beginning of the line + out_ptr = out_line; - mlt_properties_set_data( properties, "alpha", alpha, owidth * ( oheight + 1 ), ( mlt_destructor )mlt_pool_release, NULL ); + // Pointer to the middle of the input line + in_line = in_middle + ( dy >> 16 ) * istride; - scale_alpha( this, iwidth, iheight, owidth, oheight ); - } - else - { - // No alpha to extract - mlt_convert_rgb24_to_yuv422( *image, owidth, oheight, owidth * 3, output ); - } + // Loop for the entirety of our output row. + for ( dx = - outer; dx < outer; dx += scale_width ) + { + base = dx >> 15; + base &= 0xfffffffe; + *out_ptr ++ = *( in_line + base ); + base &= 0xfffffffc; + *out_ptr ++ = *( in_line + base + 1 ); + dx += scale_width; + base = dx >> 15; + base &= 0xfffffffe; + *out_ptr ++ = *( in_line + base ); + base &= 0xfffffffc; + *out_ptr ++ = *( in_line + base + 3 ); } - - // Now update the frame - mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * 2, ( mlt_destructor )mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", owidth ); - mlt_properties_set_int( properties, "height", oheight ); - - *image = output; + // Move to next output line + out_line += ostride; } + + // Now update the frame + mlt_frame_set_image( frame, output, owidth * ( oheight + 1 ) * 2, mlt_pool_release ); + *image = output; return 0; } -static void scale_alpha( mlt_frame this, int iwidth, int iheight, int owidth, int oheight ) +static void scale_alpha( mlt_frame frame, int iwidth, int iheight, int owidth, int oheight ) { // Scale the alpha uint8_t *output = NULL; - uint8_t *input = mlt_frame_get_alpha_mask( this ); + uint8_t *input = mlt_frame_get_alpha_mask( frame ); if ( input != NULL ) { - uint8_t *out_line; - int x, y; - int ox = ( iwidth << 10 ) / owidth; - int oy = ( iheight << 10 ) / oheight; + uint8_t *out_line, *in_line; + register int i, j, x, y; + register int ox = ( iwidth << 16 ) / owidth; + register int oy = ( iheight << 16 ) / oheight; output = mlt_pool_alloc( owidth * oheight ); out_line = output; // Loop for the entirety of our output height. - for ( y = 0; y < oheight; y ++ ) - for ( x = 0; x < owidth; x ++ ) - *out_line ++ = *( input + ( ( 512 + ( y * oy * iwidth ) + x * ox ) >> 10 ) ); + for ( i = 0, y = (oy >> 1); i < oheight; i++, y += oy ) + { + in_line = &input[ (y >> 16) * iwidth ]; + for ( j = 0, x = (ox >> 1); j < owidth; j++, x += ox ) + *out_line ++ = in_line[ x >> 16 ]; + } // Set it back on the frame - mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "alpha", output, owidth * oheight, mlt_pool_release, NULL ); + mlt_frame_set_alpha( frame, output, owidth * oheight, mlt_pool_release ); } } /** Do it :-). */ -static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { + int error = 0; + // Get the frame properties - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); + mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the filter from the stack - mlt_filter filter = mlt_frame_pop_service( this ); + mlt_filter filter = mlt_frame_pop_service( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); @@ -166,8 +161,9 @@ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format * // Correct Width/height if necessary if ( *width == 0 || *height == 0 ) { - *width = mlt_properties_get_int( properties, "normalised_width" ); - *height = mlt_properties_get_int( properties, "normalised_height" ); + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); + *width = profile->width; + *height = profile->height; } // There can be problems with small images - avoid them (by hacking - gah) @@ -175,10 +171,11 @@ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format * { int iwidth = *width; int iheight = *height; - int owidth = *width; - int oheight = *height; + double factor = mlt_properties_get_double( filter_properties, "factor" ); + factor = factor > 0 ? factor : 1.0; + int owidth = *width * factor; + int oheight = *height * factor; char *interps = mlt_properties_get( properties, "rescale.interp" ); - int wanted_format = *format; // Default from the scaler if not specifed on the frame if ( interps == NULL ) @@ -187,15 +184,15 @@ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format * mlt_properties_set( properties, "rescale.interp", interps ); } - // If real_width/height exist, we want that as minimum information - if ( mlt_properties_get_int( properties, "real_width" ) ) + // If meta.media.width/height exist, we want that as minimum information + if ( mlt_properties_get_int( properties, "meta.media.width" ) ) { - iwidth = mlt_properties_get_int( properties, "real_width" ); - iheight = mlt_properties_get_int( properties, "real_height" ); + iwidth = mlt_properties_get_int( properties, "meta.media.width" ); + iheight = mlt_properties_get_int( properties, "meta.media.height" ); } // Let the producer know what we are actually requested to obtain - if ( *format == mlt_image_yuv422 && strcmp( interps, "none" ) ) + if ( strcmp( interps, "none" ) ) { mlt_properties_set_int( properties, "rescale_width", *width ); mlt_properties_set_int( properties, "rescale_height", *height ); @@ -212,51 +209,35 @@ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format * if ( iheight != oheight && ( strcmp( interps, "nearest" ) || ( iheight % oheight != 0 ) ) ) mlt_properties_set_int( properties, "consumer_deinterlace", 1 ); + // Convert the image to yuv422 when using the local scaler + if ( scaler_method == filter_scale ) + *format = mlt_image_yuv422; + // Get the image as requested - mlt_frame_get_image( this, image, format, &iwidth, &iheight, writable ); + mlt_frame_get_image( frame, image, format, &iwidth, &iheight, writable ); // Get rescale interpretation again, in case the producer wishes to override scaling interps = mlt_properties_get( properties, "rescale.interp" ); - if ( *image != NULL && ( *format != mlt_image_yuv422 || ( iwidth != owidth || iheight != oheight ) ) ) + if ( *image && strcmp( interps, "none" ) && ( iwidth != owidth || iheight != oheight ) ) { - // If the colour space is correct and scaling is off, do nothing - if ( *format == mlt_image_yuv422 && !strcmp( interps, "none" ) ) - { - *width = iwidth; - *height = iheight; - } - else if ( *format == mlt_image_yuv422 ) - { - // Call the local scaler - scaler_method( this, image, *format, mlt_image_yuv422, iwidth, iheight, owidth, oheight ); - *width = owidth; - *height = oheight; - } - else if ( *format == mlt_image_rgb24 && wanted_format == mlt_image_rgb24 ) - { - // Call the local scaler - scaler_method( this, image, *format, mlt_image_rgb24, iwidth, iheight, owidth, oheight ); + mlt_log_debug( MLT_FILTER_SERVICE( filter ), "%dx%d -> %dx%d (%s) %s\n", + iwidth, iheight, owidth, oheight, mlt_image_format_name( *format ), interps ); - // Return the output - *width = owidth; - *height = oheight; - } - else if ( *format == mlt_image_rgb24 || *format == mlt_image_rgb24a ) + // If valid colorspace + if ( *format == mlt_image_yuv422 || *format == mlt_image_rgb24 || + *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { - // Call the local scaler - scaler_method( this, image, *format, mlt_image_yuv422, iwidth, iheight, owidth, oheight ); - - // Return the output - *format = mlt_image_yuv422; + // Call the virtual function + scaler_method( frame, image, format, iwidth, iheight, owidth, oheight ); *width = owidth; *height = oheight; } - else - { - *width = iwidth; - *height = iheight; - } + // Scale the alpha channel only if exists and not correct size + int alpha_size = 0; + mlt_properties_get_data( properties, "alpha", &alpha_size ); + if ( alpha_size > 0 && alpha_size != ( owidth * oheight ) && alpha_size != ( owidth * ( oheight + 1 ) ) ) + scale_alpha( frame, iwidth, iheight, owidth, oheight ); } else { @@ -266,29 +247,19 @@ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format * } else { - // Store the requested width/height - int iwidth = *width; - int iheight = *height; - - // Get the image as requested - mlt_frame_get_image( this, image, format, &iwidth, &iheight, writable ); - - // Too small - for now just assign as though we got what we wanted - *width = iwidth; - *height = iheight; + error = 1; } - - return 0; + return error; } /** Filter processing. */ -static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) +static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Push the filter - mlt_frame_push_service( frame, this ); + mlt_frame_push_service( frame, filter ); // Push the get image method mlt_frame_push_service( frame, filter_get_image ); @@ -302,16 +273,16 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) mlt_filter filter_rescale_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create a new scaler - mlt_filter this = mlt_filter_new( ); + mlt_filter filter = mlt_filter_new( ); // If successful, then initialise it - if ( this != NULL ) + if ( filter != NULL ) { // Get the properties - mlt_properties properties = MLT_FILTER_PROPERTIES( this ); + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); // Set the process method - this->process = filter_process; + filter->process = filter_process; // Set the inerpolation mlt_properties_set( properties, "interpolation", arg == NULL ? "bilinear" : arg ); @@ -320,6 +291,6 @@ mlt_filter filter_rescale_init( mlt_profile profile, mlt_service_type type, cons mlt_properties_set_data( properties, "method", filter_scale, 0, NULL, NULL ); } - return this; + return filter; }