From 8a3795b090723264c973d274eedc28da480e76fd Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Wed, 18 Feb 2004 10:49:32 +0000 Subject: [PATCH] Optimisations (part 0), pixel v percentage, reworked aspect ratio calcs, ante/post properties for dv consumers, avformat rework, westley root git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@149 d19143bc-622f-0410-bfdd-b5b2a6649095 --- src/albino/Makefile | 2 +- src/framework/Makefile | 2 +- src/framework/mlt_consumer.c | 34 ++++-- src/framework/mlt_filter.c | 7 +- src/framework/mlt_filter.h | 1 + src/framework/mlt_frame.c | 111 ++++++++++++-------- src/framework/mlt_properties.c | 7 ++ src/humperdink/Makefile | 2 +- src/inigo/Makefile | 2 +- src/miracle/Makefile | 2 +- src/miracle/miracle_local.c | 24 ++++- src/miracle/miracle_unit.c | 3 + src/miracle/miracle_unit_commands.c | 3 - src/modules/avformat/Makefile | 2 +- src/modules/avformat/producer_avformat.c | 91 ++++++++++++---- src/modules/core/Makefile | 2 +- src/modules/core/filter_obscure.c | 72 ++++++++++--- src/modules/core/filter_resize.c | 53 +++++++++- src/modules/core/transition_composite.c | 169 +++++++++++++++++++----------- src/modules/dv/Makefile | 2 +- src/modules/fezzik/Makefile | 2 +- src/modules/ffmpeg/Makefile | 2 +- src/modules/gtk2/filter_rescale.c | 30 ++---- src/modules/gtk2/producer_pango.c | 57 ++++++++--- src/modules/gtk2/producer_pixbuf.c | 91 +++++++++++----- src/modules/inigo/Makefile | 2 +- src/modules/resample/Makefile | 2 +- src/modules/sdl/Makefile | 2 +- src/modules/sdl/consumer_sdl.c | 3 + src/modules/vorbis/Makefile | 2 +- src/modules/westley/Makefile | 2 +- src/modules/westley/producer_westley.c | 37 ++++++-- src/tests/Makefile | 2 +- src/valerie/Makefile | 2 +- 34 files changed, 577 insertions(+), 250 deletions(-) diff --git a/src/albino/Makefile b/src/albino/Makefile index 051c5fe..7507b8a 100644 --- a/src/albino/Makefile +++ b/src/albino/Makefile @@ -2,7 +2,7 @@ TARGET = albino OBJS = albino.o -CFLAGS = -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic +CFLAGS = -O3 -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic LDFLAGS = -L ../valerie -L ../miracle -L ../framework -lmiracle -lmlt -lvalerie diff --git a/src/framework/Makefile b/src/framework/Makefile index 562698e..da4ff1a 100644 --- a/src/framework/Makefile +++ b/src/framework/Makefile @@ -19,7 +19,7 @@ OBJS = mlt_frame.o \ SRCS := $(OBJS:.o=.c) -CFLAGS = -g -Wall -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS = -g -O3 -Wall -D_FILE_OFFSET_BITS=64 -pthread LDFLAGS = -lm -ldl -lpthread diff --git a/src/framework/mlt_consumer.c b/src/framework/mlt_consumer.c index 92a95fe..44fc184 100644 --- a/src/framework/mlt_consumer.c +++ b/src/framework/mlt_consumer.c @@ -107,15 +107,25 @@ int mlt_consumer_start( mlt_consumer this ) // Deal with it now. if ( test_card != NULL ) { - // Create a test card producer - // TODO: do we want to use fezzik here? - mlt_producer producer = mlt_factory_producer( "fezzik", test_card ); - - // Do we have a producer - if ( producer != NULL ) + if ( mlt_properties_get_data( properties, "test_card_producer", NULL ) == NULL ) { - // Set the test card on the consumer - mlt_properties_set_data( properties, "test_card_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); + // Create a test card producer + // TODO: do we want to use fezzik here? + mlt_producer producer = mlt_factory_producer( "fezzik", test_card ); + + // Do we have a producer + if ( producer != NULL ) + { + // Test card should loop I guess... + mlt_properties_set( mlt_producer_properties( producer ), "eof", "loop" ); + + // Set the test card on the consumer + mlt_properties_set_data( properties, "test_card_producer", producer, 0, ( mlt_destructor )mlt_producer_close, NULL ); + } + + // Check and run an ante command + if ( mlt_properties_get( properties, "ante" ) ) + system( mlt_properties_get( properties, "ante" ) ); } } @@ -173,11 +183,15 @@ int mlt_consumer_stop( mlt_consumer this ) // Stop the consumer if ( this->stop != NULL ) - return this->stop( this ); + this->stop( this ); // Kill the test card mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); + // Check and run a post command + if ( mlt_properties_get( properties, "post" ) ) + system( mlt_properties_get( properties, "post" ) ); + return 0; } @@ -186,7 +200,7 @@ int mlt_consumer_stop( mlt_consumer this ) int mlt_consumer_is_stopped( mlt_consumer this ) { - // Stop the consumer + // Check if the consumer is stopped if ( this->is_stopped != NULL ) return this->is_stopped( this ); diff --git a/src/framework/mlt_filter.c b/src/framework/mlt_filter.c index 95dfc5a..90dea22 100644 --- a/src/framework/mlt_filter.c +++ b/src/framework/mlt_filter.c @@ -63,6 +63,9 @@ mlt_service mlt_filter_service( mlt_filter this ) return &this->parent; } +/** Get the properties associated to this filter. +*/ + mlt_properties mlt_filter_properties( mlt_filter this ) { return mlt_service_properties( mlt_filter_service( this ) ); @@ -129,7 +132,7 @@ mlt_position mlt_filter_get_out( mlt_filter this ) /** Process the frame. */ -static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) +mlt_frame mlt_filter_process( mlt_filter this, mlt_frame frame ) { if ( this->process == NULL ) return frame; @@ -157,7 +160,7 @@ static int filter_get_frame( mlt_service service, mlt_frame_ptr frame, int index { mlt_position position = mlt_frame_get_position( *frame ); if ( position >= in && ( out == 0 || position < out ) ) - *frame = filter_process( this, *frame ); + *frame = mlt_filter_process( this, *frame ); return 0; } else diff --git a/src/framework/mlt_filter.h b/src/framework/mlt_filter.h index edaf6f6..d107b33 100644 --- a/src/framework/mlt_filter.h +++ b/src/framework/mlt_filter.h @@ -50,6 +50,7 @@ struct mlt_filter_s extern int mlt_filter_init( mlt_filter this, void *child ); extern mlt_service mlt_filter_service( mlt_filter this ); extern mlt_properties mlt_filter_properties( mlt_filter this ); +extern mlt_frame mlt_filter_process( mlt_filter this, mlt_frame that ); extern int mlt_filter_connect( mlt_filter this, mlt_service producer, int index ); extern void mlt_filter_set_in_and_out( mlt_filter this, mlt_position in, mlt_position out ); extern int mlt_filter_get_track( mlt_filter this ); diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c index cbc8074..5a2eaad 100644 --- a/src/framework/mlt_frame.c +++ b/src/framework/mlt_frame.c @@ -35,6 +35,9 @@ mlt_frame mlt_frame_init( ) if ( this != NULL ) { + // Get the normalisation + char *normalisation = getenv( "MLT_NORMALISATION" ); + // Initialise the properties mlt_properties properties = &this->parent; mlt_properties_init( properties, this ); @@ -42,11 +45,27 @@ mlt_frame mlt_frame_init( ) // Set default properties on the frame mlt_properties_set_position( properties, "_position", 0.0 ); mlt_properties_set_data( properties, "image", NULL, 0, NULL, NULL ); - mlt_properties_set_int( properties, "width", 720 ); - mlt_properties_set_int( properties, "height", 576 ); + + if ( normalisation == NULL || strcmp( normalisation, "NTSC" ) ) + { + mlt_properties_set_int( properties, "width", 720 ); + mlt_properties_set_int( properties, "height", 576 ); + mlt_properties_set_int( properties, "normalised_width", 720 ); + mlt_properties_set_int( properties, "normalised_height", 576 ); + } + else + { + mlt_properties_set_int( properties, "width", 720 ); + mlt_properties_set_int( properties, "height", 480 ); + mlt_properties_set_int( properties, "normalised_width", 720 ); + mlt_properties_set_int( properties, "normalised_height", 480 ); + } + mlt_properties_set_double( properties, "aspect_ratio", 4.0 / 3.0 ); mlt_properties_set_data( properties, "audio", NULL, 0, NULL, NULL ); mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL ); + + } return this; } @@ -174,10 +193,13 @@ int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *for mlt_service_get_frame( mlt_producer_service( producer ), &test_frame, 0 ); if ( test_frame != NULL ) { + mlt_properties test_properties = mlt_frame_properties( test_frame ); + mlt_properties_set_double( test_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "consumer_aspect_ratio" ) ); + mlt_properties_set_double( test_properties, "consumer_scale", mlt_properties_get_double( properties, "consumer_scale" ) ); + mlt_properties_set( test_properties, "rescale.interp", "nearest" ); mlt_frame_get_image( test_frame, buffer, format, width, height, writable ); - mlt_properties_inherit( mlt_frame_properties( this ), mlt_frame_properties( test_frame ) ); + mlt_properties_inherit( properties, test_properties ); mlt_properties_set_data( properties, "test_card_frame", test_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); - mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); @@ -410,29 +432,6 @@ int mlt_convert_yuv420p_to_yuv422( uint8_t *yuv420p, int width, int height, int return ret; } -void *memfill( void *dst, void *src, int l, int elements ) -{ - int i = 0; - if ( l == 2 ) - { - uint8_t *p = dst; - uint8_t *src1 = src; - uint8_t *src2 = src + 1; - for ( i = 0; i < elements; i ++ ) - { - *p ++ = *src1; - *p ++ = *src2; - } - dst = p; - } - else - { - for ( i = 0; i < elements; i ++ ) - dst = memcpy( dst, src, l ) + l; - } - return dst; -} - void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input, int iwidth, int iheight ) { // Calculate strides @@ -465,38 +464,62 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input uint8_t *in_middle = input + istride * ( iheight / 2 ) + ( iwidth / 2 ) * 2; int in_line = - in_y_range * istride - in_x_range * 2; - uint8_t black[ 2 ] = { 16, 128 }; + uint8_t black[ 2 ] = { 0, 128 }; + int elements; + + // Fill whole section with black + y = out_y_range - ( iheight / 2 ); + int blank_elements = ostride * y / 2; + elements = blank_elements; + while ( elements -- ) + { + *out_line ++ = black[ 0 ]; + *out_line ++ = black[ 1 ]; + } + + int active_width = 2 * iwidth; + int inactive_width = out_x_range - in_x_range; // Loop for the entirety of our output height. - for ( y = - out_y_range; y < out_y_range ; y ++ ) + while ( iheight -- ) { // Start at the beginning of the line out_ptr = out_line; - if ( abs( y ) < iheight / 2 ) + // Fill the outer part with black + elements = inactive_width; + while ( elements -- ) { - // Fill the outer part with black - 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, 2 * iwidth ); - out_ptr += 2 * iwidth; + *out_ptr ++ = black[ 0 ]; + *out_ptr ++ = black[ 1 ]; + } - // Fill the outer part with black - 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, active_width ); + out_ptr += active_width; - // Move to next input line - in_line += istride; - } - else + // Fill the outer part with black + elements = inactive_width; + while ( elements -- ) { - // Fill whole line with black - out_ptr = memfill( out_ptr, black, 2, owidth ); + *out_ptr ++ = black[ 0 ]; + *out_ptr ++ = black[ 1 ]; } + // Move to next input line + in_line += istride; + // Move to next output line out_line += ostride; } + + // Fill whole section with black + elements = blank_elements; + while ( elements -- ) + { + *out_line ++ = black[ 0 ]; + *out_line ++ = black[ 1 ]; + } } /** A resizing function for yuv422 frames - this does not rescale, but simply diff --git a/src/framework/mlt_properties.c b/src/framework/mlt_properties.c index e1e6453..dbce362 100644 --- a/src/framework/mlt_properties.c +++ b/src/framework/mlt_properties.c @@ -252,6 +252,13 @@ int mlt_properties_parse( mlt_properties this, char *namevalue ) strcpy( value, "" ); } + if ( strlen( value ) > 1 && value[ 0 ] == '\"' ) + { + strcpy( value, value + 1 ); + if ( value[ strlen( value ) - 1 ] == '\"' ) + value[ strlen( value ) - 1 ] = '\0'; + } + error = mlt_properties_set( this, name, value ); free( name ); diff --git a/src/humperdink/Makefile b/src/humperdink/Makefile index 53f2f96..86fc404 100644 --- a/src/humperdink/Makefile +++ b/src/humperdink/Makefile @@ -4,7 +4,7 @@ OBJS = client.o \ io.o \ remote.o -CFLAGS = -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic +CFLAGS = -O3 -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic LDFLAGS = -L ../valerie -lvalerie diff --git a/src/inigo/Makefile b/src/inigo/Makefile index 78e7cfa..b9e0b5d 100644 --- a/src/inigo/Makefile +++ b/src/inigo/Makefile @@ -3,7 +3,7 @@ TARGET = inigo OBJS = inigo.o \ io.o -CFLAGS = -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic +CFLAGS = -O3 -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic LDFLAGS = -L ../framework -lmlt diff --git a/src/miracle/Makefile b/src/miracle/Makefile index 3bda183..bae78c2 100644 --- a/src/miracle/Makefile +++ b/src/miracle/Makefile @@ -12,7 +12,7 @@ LIB_OBJS = miracle_log.o \ OBJS = $(APP_OBJS) $(LIB_OBJS) -CFLAGS = -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic +CFLAGS = -O3 -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic LDFLAGS = -L ../valerie -lvalerie -L ../framework -lmlt diff --git a/src/miracle/miracle_local.c b/src/miracle/miracle_local.c index 71b7b77..9929e12 100644 --- a/src/miracle/miracle_local.c +++ b/src/miracle/miracle_local.c @@ -127,7 +127,8 @@ typedef enum ATYPE_NONE, ATYPE_FLOAT, ATYPE_STRING, - ATYPE_INT + ATYPE_INT, + ATYPE_PAIR } arguments_types; @@ -165,7 +166,7 @@ static command_t vocabulary[] = {"UADD", miracle_add_unit, 0, ATYPE_STRING, "Create a new DV unit (virtual VTR) to transmit to receiver specified in GUID argument."}, {"ULS", miracle_list_units, 0, ATYPE_NONE, "Lists the units that have already been added to the server."}, {"CLS", miracle_list_clips, 0, ATYPE_STRING, "Lists the clips at directory name argument."}, - {"SET", miracle_set_global_property, 0, ATYPE_STRING, "Set a server configuration property."}, + {"SET", miracle_set_global_property, 0, ATYPE_PAIR, "Set a server configuration property."}, {"GET", miracle_get_global_property, 0, ATYPE_STRING, "Get a server configuration property."}, {"RUN", miracle_run, 0, ATYPE_STRING, "Run a batch file." }, {"LIST", miracle_list, 1, ATYPE_NONE, "List the playlist associated to a unit."}, @@ -185,7 +186,7 @@ static command_t vocabulary[] = {"SIN", miracle_set_in_point, 1, ATYPE_INT, "Set the IN point of the loaded clip to frame number argument. -1 = reset in point to 0"}, {"SOUT", miracle_set_out_point, 1, ATYPE_INT, "Set the OUT point of the loaded clip to frame number argument. -1 = reset out point to maximum."}, {"USTA", miracle_get_unit_status, 1, ATYPE_NONE, "Report information about the unit."}, - {"USET", miracle_set_unit_property, 1, ATYPE_STRING, "Set a unit configuration property."}, + {"USET", miracle_set_unit_property, 1, ATYPE_PAIR, "Set a unit configuration property."}, {"UGET", miracle_get_unit_property, 1, ATYPE_STRING, "Get a unit configuration property."}, {"XFER", miracle_transfer, 1, ATYPE_STRING, "Transfer the unit's clip to another unit specified as argument."}, {"SHUTDOWN", miracle_shutdown, 0, ATYPE_NONE, "Shutdown the server."}, @@ -359,7 +360,7 @@ int miracle_command_parse_unit( command_argument cmd, int argument ) /** Parse a normal argument. */ -void *miracle_command_parse_argument( command_argument cmd, int argument, arguments_types type ) +void *miracle_command_parse_argument( command_argument cmd, int argument, arguments_types type, char *command ) { void *ret = NULL; char *value = valerie_tokeniser_get_string( cmd->tokeniser, argument ); @@ -381,6 +382,19 @@ void *miracle_command_parse_argument( command_argument cmd, int argument, argume ret = strdup( value ); break; + case ATYPE_PAIR: + if ( strchr( command, '=' ) ) + { + char *ptr = strchr( command, '=' ); + while ( *( ptr - 1 ) != ' ' ) + ptr --; + ret = strdup( ptr ); + ptr = ret; + while( ptr[ strlen( ptr ) - 1 ] == ' ' ) + ptr[ strlen( ptr ) - 1 ] = '\0'; + } + break; + case ATYPE_INT: ret = malloc( sizeof( int ) ); if ( ret != NULL ) @@ -453,7 +467,7 @@ static valerie_response miracle_local_execute( miracle_local local, char *comman if ( miracle_command_get_error( &cmd ) == RESPONSE_SUCCESS ) { - cmd.argument = miracle_command_parse_argument( &cmd, position, vocabulary[ index ].type ); + cmd.argument = miracle_command_parse_argument( &cmd, position, vocabulary[ index ].type, command ); if ( cmd.argument == NULL && vocabulary[ index ].type != ATYPE_NONE ) miracle_command_set_error( &cmd, RESPONSE_MISSING_ARG ); position ++; diff --git a/src/miracle/miracle_unit.c b/src/miracle/miracle_unit.c index e7d6a2a..4fbfdbc 100644 --- a/src/miracle/miracle_unit.c +++ b/src/miracle/miracle_unit.c @@ -392,6 +392,9 @@ void miracle_unit_play( miracle_unit_t *unit, int speed ) void miracle_unit_terminate( miracle_unit unit ) { mlt_consumer consumer = mlt_properties_get_data( unit->properties, "consumer", NULL ); + mlt_playlist playlist = mlt_properties_get_data( unit->properties, "playlist", NULL ); + mlt_producer producer = mlt_playlist_producer( playlist ); + mlt_producer_set_speed( producer, 0 ); mlt_consumer_stop( consumer ); miracle_unit_status_communicate( unit ); } diff --git a/src/miracle/miracle_unit_commands.c b/src/miracle/miracle_unit_commands.c index 4e6fb17..66f84bb 100644 --- a/src/miracle/miracle_unit_commands.c +++ b/src/miracle/miracle_unit_commands.c @@ -249,10 +249,7 @@ int miracle_stop( command_argument cmd_arg ) if ( unit == NULL ) return RESPONSE_INVALID_UNIT; else - { - miracle_unit_play( unit, 0 ); miracle_unit_terminate( unit ); - } return RESPONSE_SUCCESS; } diff --git a/src/modules/avformat/Makefile b/src/modules/avformat/Makefile index 8a67046..e702047 100644 --- a/src/modules/avformat/Makefile +++ b/src/modules/avformat/Makefile @@ -4,7 +4,7 @@ TARGET = ../libmltavformat.so OBJS = factory.o \ producer_avformat.o -CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 +CFLAGS = -O3 -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 LDFLAGS = -lavformat -lavcodec diff --git a/src/modules/avformat/producer_avformat.c b/src/modules/avformat/producer_avformat.c index 6333c55..1f637d4 100644 --- a/src/modules/avformat/producer_avformat.c +++ b/src/modules/avformat/producer_avformat.c @@ -31,6 +31,7 @@ #include #include #include +#include // Forward references. static int producer_open( mlt_producer this, char *file ); @@ -319,6 +320,9 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form // Current time calcs double current_time = 0; + // We may want to use the source fps if available + double source_fps = mlt_properties_get_double( properties, "source_fps" ); + // Set the result arguments that we know here (only *buffer is now required) *format = mlt_image_yuv422; *width = codec_context->width; @@ -370,7 +374,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form // Duplicate the last image if necessary if ( mlt_properties_get_data( properties, "current_image", NULL ) != NULL && - ( paused || mlt_properties_get_double( properties, "current_time" ) > real_timecode ) ) + ( paused || mlt_properties_get_double( properties, "current_time" ) >= real_timecode ) ) { // Get current image and size int size = 0; @@ -401,27 +405,30 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form // We only deal with video from the selected video_index if ( ret >= 0 && pkt.stream_index == index && pkt.size > 0 ) { + current_time = ( double )pkt.pts / 1000000.0; + // Decode the image // Wouldn't it be great if I could use this... //if ( (float)pkt.pts / 1000000.0 >= real_timecode ) ret = avcodec_decode_video( codec_context, &frame, &got_picture, pkt.data, pkt.size ); - // Handle ignore - if ( (float)pkt.pts / 1000000.0 < real_timecode ) - { - ignore = 0; - got_picture = 0; - } - else if ( (float)pkt.pts / 1000000.0 >= real_timecode ) + if ( got_picture ) { - ignore = 0; - } - else if ( got_picture && ignore -- ) - { - got_picture = 0; + // Handle ignore + if ( current_time < real_timecode ) + { + ignore = 0; + got_picture = 0; + } + else if ( current_time >= real_timecode ) + { + ignore = 0; + } + else if ( got_picture && ignore -- ) + { + got_picture = 0; + } } - - current_time = ( double )pkt.pts / 1000000.0; } // We're finished with this packet regardless @@ -449,7 +456,17 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form memcpy( image, output->data[ 0 ], size ); memcpy( *buffer, output->data[ 0 ], size ); mlt_properties_set_data( frame_properties, "image", *buffer, size, free, NULL ); - mlt_properties_set_double( properties, "current_time", current_time ); + + if ( current_time == 0 && source_fps != 0 ) + { + double fps = mlt_properties_get_double( properties, "fps" ); + current_time = ceil( source_fps * ( double )position / fps ) * ( 1 / source_fps ); + mlt_properties_set_double( properties, "current_time", current_time ); + } + else + { + mlt_properties_set_double( properties, "current_time", current_time ); + } } } @@ -503,9 +520,9 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame ) if ( codec != NULL && avcodec_open( codec_context, codec ) >= 0 ) { double aspect_ratio = 0; + double source_fps = 0; // Set aspect ratio - fprintf( stderr, "AVFORMAT: sample aspect %d\n", codec_context->sample_aspect_ratio.num ); if ( codec_context->sample_aspect_ratio.num == 0) aspect_ratio = 0; else @@ -515,6 +532,14 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame ) aspect_ratio = ( double )codec_context->width / ( double )codec_context->height; mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio ); + fprintf( stderr, "AVFORMAT: sample aspect %f\n", aspect_ratio ); + + // Determine the fps + source_fps = ( double )codec_context->frame_rate / codec_context->frame_rate_base; + + // We'll use fps if it's available + if ( source_fps > 0 && source_fps < 30 ) + mlt_properties_set_double( properties, "source_fps", source_fps ); // Now store the codec with its destructor mlt_properties_set_data( properties, "video_codec", codec_context, 0, producer_codec_close, NULL ); @@ -601,6 +626,7 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Flag for paused (silence) int paused = 0; + int locked = 0; // Lock the mutex now pthread_mutex_lock( &avformat_mutex ); @@ -645,6 +671,8 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // Clear the usage in the audio buffer audio_used = 0; + + locked = 1; } } @@ -673,17 +701,17 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form uint8_t *ptr = pkt.data; int data_size; - if ( ptr == NULL || len == 0 ) - break; - // We only deal with video from the selected video_index - while ( ret >= 0 && pkt.stream_index == index && len > 0 ) + while ( ptr != NULL && ret >= 0 && pkt.stream_index == index && len > 0 ) { // Decode the audio ret = avcodec_decode_audio( codec_context, temp, &data_size, ptr, len ); if ( ret < 0 ) + { + ret = 0; break; + } len -= ret; ptr += ret; @@ -706,7 +734,24 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form // If we're behind, ignore this packet float current_pts = (float)pkt.pts / 1000000.0; double discrepancy = mlt_properties_get_double( properties, "discrepancy" ); - if ( discrepancy * current_pts < real_timecode ) + if ( current_pts != 0 && real_timecode != 0 ) + { + if ( discrepancy != 1 ) + discrepancy = ( discrepancy + ( real_timecode / current_pts ) ) / 2; + else + discrepancy = real_timecode / current_pts; + if ( discrepancy > 0.9 && discrepancy < 1.1 ) + discrepancy = 1.0; + else + discrepancy = floor( discrepancy + 0.5 ); + + if ( discrepancy == 0 ) + discrepancy = 1.0; + + mlt_properties_set_double( properties, "discrepancy", discrepancy ); + } + + if ( discrepancy * current_pts <= ( real_timecode - 0.02 ) ) ignore = 1; } @@ -715,7 +760,6 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form } // Now handle the audio if we have enough - if ( audio_used >= *samples ) { *buffer = malloc( *samples * *channels * sizeof( int16_t ) ); @@ -793,6 +837,7 @@ static void producer_set_up_audio( mlt_producer this, mlt_frame frame ) { // Now store the codec with its destructor mlt_properties_set_data( properties, "audio_codec", codec_context, 0, producer_codec_close, NULL ); + } else { diff --git a/src/modules/core/Makefile b/src/modules/core/Makefile index a93ab76..d1d05d7 100644 --- a/src/modules/core/Makefile +++ b/src/modules/core/Makefile @@ -14,7 +14,7 @@ OBJS = factory.o \ transition_mix.o \ filter_brightness.o -CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS = -O3 -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread SRCS := $(OBJS:.o=.c) diff --git a/src/modules/core/filter_obscure.c b/src/modules/core/filter_obscure.c index 75a9652..e6e7c71 100644 --- a/src/modules/core/filter_obscure.c +++ b/src/modules/core/filter_obscure.c @@ -31,6 +31,8 @@ struct geometry_s { + int nw; + int nh; float x; float y; float w; @@ -39,11 +41,39 @@ struct geometry_s int mask_h; }; +/** Parse a value from a geometry string. +*/ + +static float parse_value( char **ptr, int normalisation, char delim, float defaults ) +{ + float value = defaults; + + if ( *ptr != NULL && **ptr != '\0' ) + { + char *end = NULL; + value = strtod( *ptr, &end ); + if ( end != NULL ) + { + if ( *end == '%' ) + value = ( value / 100.0 ) * normalisation; + while ( *end == delim || *end == '%' ) + end ++; + } + *ptr = end; + } + + return value; +} + /** Parse a geometry property string. */ -static void geometry_parse( struct geometry_s *geometry, struct geometry_s *defaults, char *property ) +static void geometry_parse( struct geometry_s *geometry, struct geometry_s *defaults, char *property, int nw, int nh ) { + // Assign normalised width and height + geometry->nw = nw; + geometry->nh = nh; + // Assign from defaults if available if ( defaults != NULL ) { @@ -62,7 +92,15 @@ static void geometry_parse( struct geometry_s *geometry, struct geometry_s *defa // Parse the geomtry string if ( property != NULL ) - sscanf( property, "%f,%f:%fx%f:%dx%d", &geometry->x, &geometry->y, &geometry->w, &geometry->h, &geometry->mask_w, &geometry->mask_h ); + { + char *ptr = property; + geometry->x = parse_value( &ptr, nw, ',', geometry->x ); + geometry->y = parse_value( &ptr, nh, ':', geometry->y ); + geometry->w = parse_value( &ptr, nw, 'x', geometry->w ); + geometry->h = parse_value( &ptr, nh, ':', geometry->h ); + geometry->mask_w = parse_value( &ptr, nw, 'x', geometry->mask_w ); + geometry->mask_h = parse_value( &ptr, nh, ' ', geometry->mask_h ); + } } /** A Timism but not as clean ;-). @@ -80,13 +118,13 @@ static float lerp( float value, float lower, float upper ) /** Calculate real geometry. */ -static void geometry_calculate( struct geometry_s *output, struct geometry_s *in, struct geometry_s *out, float position ) +static void geometry_calculate( struct geometry_s *output, struct geometry_s *in, struct geometry_s *out, float position, int ow, int oh ) { // Calculate this frames geometry - output->x = lerp( in->x + ( out->x - in->x ) * position, 0, 100 ); - output->y = lerp( in->y + ( out->y - in->y ) * position, 0, 100 ); - output->w = lerp( in->w + ( out->w - in->w ) * position, 0, 100 - output->x ); - output->h = lerp( in->h + ( out->h - in->h ) * position, 0, 100 - output->y ); + output->x = lerp( ( in->x + ( out->x - in->x ) * position ) / ( float )out->nw * ow, 0, ow ); + output->y = lerp( ( in->y + ( out->y - in->y ) * position ) / ( float )out->nh * oh, 0, oh ); + output->w = lerp( ( in->w + ( out->w - in->w ) * position ) / ( float )out->nw * ow, 0, ow - output->x ); + output->h = lerp( ( in->h + ( out->h - in->h ) * position ) / ( float )out->nh * oh, 0, oh - output->y ); output->mask_w = in->mask_w + ( out->mask_w - in->mask_w ) * position; output->mask_h = in->mask_h + ( out->mask_h - in->mask_h ) * position; } @@ -149,10 +187,10 @@ void obscure_average( uint8_t *start, int width, int height, int stride ) static void obscure_render( uint8_t *image, int width, int height, struct geometry_s result ) { - int area_x = ( result.x / 100 ) * width; - int area_y = ( result.y / 100 ) * height; - int area_w = ( result.w / 100 ) * width; - int area_h = ( result.h / 100 ) * height; + int area_x = result.x; + int area_y = result.y; + int area_w = result.w; + int area_h = result.h; int mw = result.mask_w; int mh = result.mask_h; @@ -195,6 +233,10 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format // Get the filter properties mlt_properties properties = mlt_filter_properties( this ); + // Obtain the normalised width and height from the frame + int normalised_width = mlt_properties_get_int( frame_properties, "normalised_width" ); + int normalised_height = mlt_properties_get_int( frame_properties, "normalised_height" ); + // Structures for geometry struct geometry_s result; struct geometry_s start; @@ -204,11 +246,11 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format float position = position_calculate( this, frame ); // Now parse the geometries - geometry_parse( &start, NULL, mlt_properties_get( properties, "start" ) ); - geometry_parse( &end, &start, mlt_properties_get( properties, "end" ) ); + geometry_parse( &start, NULL, mlt_properties_get( properties, "start" ), normalised_width, normalised_height ); + geometry_parse( &end, &start, mlt_properties_get( properties, "end" ), normalised_width, normalised_height ); // Do the calculation - geometry_calculate( &result, &start, &end, position ); + geometry_calculate( &result, &start, &end, position, *width, *height ); // Now actually render it obscure_render( *image, *width, *height, result ); @@ -257,7 +299,7 @@ mlt_filter filter_obscure_init( void *arg ) mlt_properties properties = mlt_filter_properties( this ); mlt_filter_init( this, NULL ); this->process = filter_process; - mlt_properties_set( properties, "start", arg != NULL ? arg : "0,0:100x100" ); + mlt_properties_set( properties, "start", arg != NULL ? arg : "0%,0%:100%x100%" ); mlt_properties_set( properties, "end", "" ); return this; } diff --git a/src/modules/core/filter_resize.c b/src/modules/core/filter_resize.c index be1e23f..72ab49d 100644 --- a/src/modules/core/filter_resize.c +++ b/src/modules/core/filter_resize.c @@ -26,22 +26,65 @@ #include #include +static int get_value( mlt_properties properties, char *preferred, char *fallback ) +{ + int value = mlt_properties_get_int( properties, preferred ); + if ( value == 0 ) + value = mlt_properties_get_int( properties, fallback ); + return value; +} + /** Do it :-). */ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { + // Get the properties from the frame mlt_properties properties = mlt_frame_properties( this ); + + // Assign requested width/height from our subordinate int owidth = *width; int oheight = *height; + + if ( mlt_properties_get( properties, "distort" ) == NULL ) + { + // Now do additional calcs based on real_width/height etc + int normalised_width = mlt_properties_get_int( properties, "normalised_width" ); + int normalised_height = mlt_properties_get_int( properties, "normalised_height" ); + int real_width = get_value( properties, "real_width", "width" ); + int real_height = get_value( properties, "real_height", "height" ); + double input_ar = mlt_frame_get_aspect_ratio( this ); + double output_ar = mlt_properties_get_double( properties, "consumer_aspect_ratio" ); + int scaled_width = ( input_ar > output_ar ? input_ar / output_ar : output_ar / input_ar ) * real_width; + int scaled_height = ( input_ar > output_ar ? input_ar / output_ar : output_ar / input_ar ) * real_height; + + // Now ensure that our images fit in the normalised frame + if ( scaled_width > normalised_width ) + { + scaled_height = scaled_height * normalised_width / scaled_width; + scaled_width = normalised_width; + } + if ( scaled_height > normalised_height ) + { + scaled_width = scaled_width * normalised_height / scaled_height; + scaled_height = normalised_height; + } + + if ( input_ar == output_ar && scaled_height == normalised_height ) + scaled_width = normalised_width; + // Now calculate the actual image size that we want + owidth = scaled_width * owidth / normalised_width; + oheight = scaled_height * oheight / normalised_height; + } + + // Now pass on the calculations down the line + mlt_properties_set_int( properties, "resize_width", *width ); + mlt_properties_set_int( properties, "resize_height", *height ); + + // Now get the image mlt_frame_get_image( this, image, format, &owidth, &oheight, writable ); - if ( *width == 0 ) - *width = 720; - if ( *height == 0 ) - *height = 576; - // Correct field order if needed if ( mlt_properties_get_int( properties, "top_field_first" ) == 1 ) { diff --git a/src/modules/core/transition_composite.c b/src/modules/core/transition_composite.c index 0e1c0d7..2cec6a6 100644 --- a/src/modules/core/transition_composite.c +++ b/src/modules/core/transition_composite.c @@ -29,6 +29,8 @@ struct geometry_s { + int nw; + int nh; float x; float y; float w; @@ -36,11 +38,41 @@ struct geometry_s float mix; }; -/** Parse a geometry property string. +/** Parse a value from a geometry string. */ -static void geometry_parse( struct geometry_s *geometry, struct geometry_s *defaults, char *property ) +static float parse_value( char **ptr, int normalisation, char delim, float defaults ) { + float value = defaults; + + if ( *ptr != NULL && **ptr != '\0' ) + { + char *end = NULL; + value = strtod( *ptr, &end ); + if ( end != NULL ) + { + if ( *end == '%' ) + value = ( value / 100.0 ) * normalisation; + while ( *end == delim || *end == '%' ) + end ++; + } + *ptr = end; + } + + return value; +} + +/** Parse a geometry property string with the syntax X,Y:WxH:MIX. Any value can be + expressed as a percentage by appending a % after the value, otherwise values are + assumed to be relative to the normalised dimensions of the consumer. +*/ + +static void geometry_parse( struct geometry_s *geometry, struct geometry_s *defaults, char *property, int nw, int nh ) +{ + // Assign normalised width and height + geometry->nw = nw; + geometry->nh = nh; + // Assign from defaults if available if ( defaults != NULL ) { @@ -57,7 +89,14 @@ static void geometry_parse( struct geometry_s *geometry, struct geometry_s *defa // Parse the geomtry string if ( property != NULL ) - sscanf( property, "%f,%f:%fx%f:%f", &geometry->x, &geometry->y, &geometry->w, &geometry->h, &geometry->mix ); + { + char *ptr = property; + geometry->x = parse_value( &ptr, nw, ',', geometry->x ); + geometry->y = parse_value( &ptr, nh, ':', geometry->y ); + geometry->w = parse_value( &ptr, nw, 'x', geometry->w ); + geometry->h = parse_value( &ptr, nh, ':', geometry->h ); + geometry->mix = parse_value( &ptr, 100, ' ', geometry->mix ); + } } /** Calculate real geometry. @@ -66,6 +105,8 @@ static void geometry_parse( struct geometry_s *geometry, struct geometry_s *defa static void geometry_calculate( struct geometry_s *output, struct geometry_s *in, struct geometry_s *out, float position ) { // Calculate this frames geometry + output->nw = in->nw; + output->nh = in->nh; output->x = in->x + ( out->x - in->x ) * position; output->y = in->y + ( out->y - in->y ) * position; output->w = in->w + ( out->w - in->w ) * position; @@ -89,6 +130,14 @@ static float position_calculate( mlt_transition this, mlt_frame frame ) return ( float )( position - in ) / ( float )( out - in + 1 ); } +static int get_value( mlt_properties properties, char *preferred, char *fallback ) +{ + int value = mlt_properties_get_int( properties, preferred ); + if ( value == 0 ) + value = mlt_properties_get_int( properties, fallback ); + return value; +} + /** Composite function. */ @@ -102,74 +151,71 @@ static int composite_yuv( uint8_t *p_dest, mlt_image_format format_dest, int wid int x_src = 0, y_src = 0; mlt_image_format format_src = format_dest; - int x = ( int )( ( float )width_dest * geometry.x / 100 ); - int y = ( int )( ( float )height_dest * geometry.y / 100 ); float weight = geometry.mix / 100; // Compute the dimensioning rectangle - int width_src = ( int )( ( float )width_dest * geometry.w / 100 ); - int height_src = ( int )( ( float )height_dest * geometry.h / 100 ); - mlt_properties b_props = mlt_frame_properties( that ); mlt_transition this = mlt_properties_get_data( b_props, "transition_composite", NULL ); mlt_properties properties = mlt_transition_properties( this ); - if ( mlt_properties_get( properties, "distort" ) == NULL && - mlt_properties_get( mlt_frame_properties( that ), "real_width" ) != NULL ) + if ( mlt_properties_get( properties, "distort" ) == NULL ) { - int width_b = mlt_properties_get_double( b_props, "real_width" ); - int height_b = mlt_properties_get_double( b_props, "real_height" ); - - // Maximise the dimensioning rectangle to the aspect of the b_frame - if ( mlt_properties_get_double( b_props, "aspect_ratio" ) * height_src > width_src ) - height_src = ( double )width_src / mlt_properties_get_double( b_props, "aspect_ratio" ) + 0.5; - else - width_src = mlt_properties_get_double( b_props, "aspect_ratio" ) * height_src + 0.5; - - // See if we need to normalise pixel aspect ratio - // We can use consumer_aspect_ratio because the a_frame will take on this aspect - double aspect = mlt_properties_get_double( b_props, "consumer_aspect_ratio" ); - if ( aspect != 0 ) + // Now do additional calcs based on real_width/height etc + //int normalised_width = mlt_properties_get_int( b_props, "normalised_width" ); + //int normalised_height = mlt_properties_get_int( b_props, "normalised_height" ); + int normalised_width = geometry.w; + int normalised_height = geometry.h; + int real_width = get_value( b_props, "real_width", "width" ); + int real_height = get_value( b_props, "real_height", "height" ); + double input_ar = mlt_frame_get_aspect_ratio( that ); + double output_ar = mlt_properties_get_double( b_props, "consumer_aspect_ratio" ); + int scaled_width = ( input_ar > output_ar ? input_ar / output_ar : output_ar / input_ar ) * real_width; + int scaled_height = ( input_ar > output_ar ? input_ar / output_ar : output_ar / input_ar ) * real_height; + + // Now ensure that our images fit in the normalised frame + if ( scaled_width > normalised_width ) { - // Derive the consumer pixel aspect - double oaspect = aspect / ( double )width_dest * height_dest; - - // Get the b frame pixel aspect - usually 1 - double iaspect = mlt_properties_get_double( b_props, "aspect_ratio" ) / width_b * height_b; - - // Normalise pixel aspect - if ( iaspect != 0 && iaspect != oaspect ) - { - width_b = iaspect / oaspect * ( double )width_b + 0.5; - width_src = iaspect / oaspect * ( double )width_src + 0.5; - } - - // Tell rescale not to normalise display aspect - mlt_frame_set_aspect_ratio( that, aspect ); + scaled_height = scaled_height * normalised_width / scaled_width; + scaled_width = normalised_width; } - - // Adjust overall scale for consumer - double consumer_scale = mlt_properties_get_double( b_props, "consumer_scale" ); - if ( consumer_scale > 0 ) + if ( scaled_height > normalised_height ) { - width_b = consumer_scale * width_b + 0.5; - height_b = consumer_scale * height_b + 0.5; + scaled_width = scaled_width * normalised_height / scaled_height; + scaled_height = normalised_height; } -// fprintf( stderr, "bounding rect %dx%d for overlay %dx%d\n", width_src, height_src, width_b, height_b ); - // Constrain the overlay to the dimensioning rectangle - if ( width_b < width_src && height_b < height_src ) + // Special case + if ( scaled_height == normalised_height ) + scaled_width = normalised_width; + + // Now we need to align to the geometry + if ( scaled_width <= geometry.w && scaled_height <= geometry.h ) { - width_src = width_b; - height_src = height_b; + // TODO: Should take into account requested alignment here... + // Assume centred alignment for now + + geometry.x = geometry.x + ( geometry.w - scaled_width ) / 2; + geometry.y = geometry.y + ( geometry.h - scaled_height ) / 2; + geometry.w = scaled_width; + geometry.h = scaled_height; + mlt_properties_set( b_props, "distort", "true" ); + } + else + { + mlt_properties_set( b_props, "distort", "true" ); } } - else if ( mlt_properties_get( b_props, "real_width" ) != NULL ) + else { - // Tell rescale not to normalise display aspect - mlt_properties_set_double( b_props, "consumer_aspect_ratio", 0 ); + // We want to ensure that we bypass resize now... + mlt_properties_set( b_props, "distort", "true" ); } + int x = ( geometry.x * width_dest ) / geometry.nw; + int y = ( geometry.y * height_dest ) / geometry.nh; + int width_src = ( geometry.w * width_dest ) / geometry.nw; + int height_src = ( geometry.h * height_dest ) / geometry.nh; + x -= x % 2; // optimization points - no work to do @@ -273,6 +319,9 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f if ( b_frame != NULL ) { + // Get the properties of the a frame + mlt_properties a_props = mlt_frame_properties( a_frame ); + // Get the properties of the b frame mlt_properties b_props = mlt_frame_properties( b_frame ); @@ -290,19 +339,21 @@ static int transition_get_image( mlt_frame a_frame, uint8_t **image, mlt_image_f // Calculate the position float position = position_calculate( this, a_frame ); + // Obtain the normalised width and height from the a_frame + int normalised_width = mlt_properties_get_int( a_props, "normalised_width" ); + int normalised_height = mlt_properties_get_int( a_props, "normalised_height" ); + // Now parse the geometries - geometry_parse( &start, NULL, mlt_properties_get( properties, "start" ) ); - geometry_parse( &end, &start, mlt_properties_get( properties, "end" ) ); + geometry_parse( &start, NULL, mlt_properties_get( properties, "start" ), normalised_width, normalised_height ); + geometry_parse( &end, &start, mlt_properties_get( properties, "end" ), normalised_width, normalised_height ); // Do the calculation geometry_calculate( &result, &start, &end, position ); // Since we are the consumer of the b_frame, we must pass along these // consumer properties from the a_frame - mlt_properties_set_double( b_props, "consumer_aspect_ratio", - mlt_properties_get_double( mlt_frame_properties( a_frame ), "consumer_aspect_ratio" ) ); - mlt_properties_set_double( b_props, "consumer_scale", - mlt_properties_get_double( mlt_frame_properties( a_frame ), "consumer_scale" ) ); + mlt_properties_set_double( b_props, "consumer_aspect_ratio", mlt_properties_get_double( a_props, "consumer_aspect_ratio" ) ); + mlt_properties_set_double( b_props, "consumer_scale", mlt_properties_get_double( a_props, "consumer_scale" ) ); // Composite the b_frame on the a_frame composite_yuv( *image, *format, *width, *height, b_frame, result ); @@ -333,7 +384,7 @@ mlt_transition transition_composite_init( char *arg ) if ( this != NULL && mlt_transition_init( this, NULL ) == 0 ) { this->process = composite_process; - mlt_properties_set( mlt_transition_properties( this ), "start", arg != NULL ? arg : "85,5:10x10" ); + mlt_properties_set( mlt_transition_properties( this ), "start", arg != NULL ? arg : "85%,5%:10%x10%" ); mlt_properties_set( mlt_transition_properties( this ), "end", "" ); } return this; diff --git a/src/modules/dv/Makefile b/src/modules/dv/Makefile index f3aac3c..4c0150a 100644 --- a/src/modules/dv/Makefile +++ b/src/modules/dv/Makefile @@ -5,7 +5,7 @@ OBJS = factory.o \ producer_libdv.o \ consumer_libdv.o -CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS = -O3 -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread LDFLAGS=-ldv -lpthread diff --git a/src/modules/fezzik/Makefile b/src/modules/fezzik/Makefile index 7b5a2a7..b2c9368 100644 --- a/src/modules/fezzik/Makefile +++ b/src/modules/fezzik/Makefile @@ -4,7 +4,7 @@ TARGET = ../libmltfezzik.so OBJS = factory.o \ producer_fezzik.o -CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS = -O3 -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread SRCS := $(OBJS:.o=.c) diff --git a/src/modules/ffmpeg/Makefile b/src/modules/ffmpeg/Makefile index 52c407b..ce5e260 100644 --- a/src/modules/ffmpeg/Makefile +++ b/src/modules/ffmpeg/Makefile @@ -6,7 +6,7 @@ OBJS = factory.o \ filter_ffmpeg_dub.o \ consumer_ffmpeg.o -CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS = -O3 -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread SRCS := $(OBJS:.o=.c) diff --git a/src/modules/gtk2/filter_rescale.c b/src/modules/gtk2/filter_rescale.c index 39185be..85bb8cd 100644 --- a/src/modules/gtk2/filter_rescale.c +++ b/src/modules/gtk2/filter_rescale.c @@ -47,8 +47,6 @@ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format * uint8_t *input = NULL; char *interps = mlt_properties_get( properties, "rescale.interp" ); int interp = PIXOPS_INTERP_BILINEAR; - double i_aspect_ratio = mlt_frame_get_aspect_ratio( this ); - double o_aspect_ratio = mlt_properties_get_double( properties, "consumer_aspect_ratio" ); if ( strcmp( interps, "nearest" ) == 0 ) interp = PIXOPS_INTERP_NEAREST; @@ -57,25 +55,19 @@ static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format * else if ( strcmp( interps, "hyper" ) == 0 ) interp = PIXOPS_INTERP_HYPER; - mlt_frame_get_image( this, &input, format, &iwidth, &iheight, writable ); - - if ( o_aspect_ratio != 0 && o_aspect_ratio != i_aspect_ratio && mlt_properties_get( properties, "distort" ) == NULL ) + // If real_width/height exist, we want that as minimum information + if ( mlt_properties_get_int( properties, "real_width" ) ) { - int temp_width = i_aspect_ratio / o_aspect_ratio * owidth + 0.5; - - // Determine maximum size within the aspect ratio: - if ( temp_width > owidth ) - if ( i_aspect_ratio > o_aspect_ratio ) - oheight = o_aspect_ratio / i_aspect_ratio * oheight + 0.5; - else - oheight = i_aspect_ratio / o_aspect_ratio * oheight + 0.5; - else - owidth = temp_width; - - // Tell frame we have conformed the aspect to the consumer - mlt_frame_set_aspect_ratio( this, o_aspect_ratio ); + iwidth = mlt_properties_get_int( properties, "real_width" ); + iheight = mlt_properties_get_int( properties, "real_height" ); } - //fprintf( stderr, "rescale: from %dx%d (aspect %f) to %dx%d (aspect %f)\n", iwidth, iheight, i_aspect_ratio, owidth, oheight, o_aspect_ratio ); + + // Let the producer know what we are actually requested to obtain + mlt_properties_set_int( properties, "rescale_width", *width ); + mlt_properties_set_int( properties, "rescale_height", *height ); + + // Get the image as requested + mlt_frame_get_image( this, &input, format, &iwidth, &iheight, writable ); if ( input != NULL ) { diff --git a/src/modules/gtk2/producer_pango.c b/src/modules/gtk2/producer_pango.c index a626a9d..11f9285 100644 --- a/src/modules/gtk2/producer_pango.c +++ b/src/modules/gtk2/producer_pango.c @@ -32,6 +32,7 @@ struct producer_pango_s int width; int height; uint8_t *image; + uint8_t *alpha; char *fgcolor; char *bgcolor; int align; @@ -252,6 +253,11 @@ static void refresh_image( mlt_frame frame, int width, int height ) rgba_color fgcolor = parse_color( this->fgcolor ); rgba_color bgcolor = parse_color( this->bgcolor ); + free( this->image ); + free( this->alpha ); + this->image = NULL; + this->alpha = NULL; + // Render the title pixbuf = pango_get_pixbuf( markup, text, font, fgcolor, bgcolor, pad, align ); @@ -272,6 +278,11 @@ static void refresh_image( mlt_frame frame, int width, int height ) } else if ( this->image == NULL || width != this->width || height != this->height ) { + free( this->image ); + free( this->alpha ); + this->image = NULL; + this->alpha = NULL; + pixbuf = mlt_properties_get_data( producer_props, "pixbuf", NULL ); mlt_properties_set_int( producer_props, "bpp", gdk_pixbuf_get_has_alpha( pixbuf ) ? 4 : 3 ); } @@ -281,30 +292,33 @@ static void refresh_image( mlt_frame frame, int width, int height ) // If we have a pixbuf and a valid width if ( pixbuf && width > 0 ) { - int i; - // Note - the original pixbuf is already safe and ready for destruction - pixbuf = gdk_pixbuf_scale_simple( pixbuf, width, height, GDK_INTERP_HYPER ); + pixbuf = gdk_pixbuf_scale_simple( pixbuf, width, height, GDK_INTERP_NEAREST ); // Store width and height - this->width = gdk_pixbuf_get_width( pixbuf ); - this->height = gdk_pixbuf_get_height( pixbuf ); + this->width = width; + this->height = height; // Allocate/define image // IRRIGATE ME - uint8_t *image = malloc( this->width * ( this->height + 1 )* bpp ); + uint8_t *image = malloc( width * ( height + 1 ) * bpp ); + uint8_t *alpha = NULL; + + // Allocate the alpha mask + alpha = malloc( this->width * this->height ); - for ( i = 0; i < height; i++ ) - memcpy( image + i * width * bpp, - gdk_pixbuf_get_pixels( pixbuf ) + i * gdk_pixbuf_get_rowstride( pixbuf ), - gdk_pixbuf_get_width( pixbuf ) * bpp ); + // Convert the image + mlt_convert_rgb24a_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ), + this->width, this->height, + gdk_pixbuf_get_rowstride( pixbuf ), + image, alpha ); // Finished with pixbuf now g_object_unref( pixbuf ); // reference the image in the producer - free( this->image ); this->image = image; + this->alpha = alpha; } // Set width/height @@ -315,6 +329,7 @@ static void refresh_image( mlt_frame frame, int width, int height ) // pass the image data without destructor mlt_properties_set_data( properties, "image", this->image, this->width * ( this->height + 1 ) * bpp, NULL, NULL ); + mlt_properties_set_data( properties, "alpha", this->alpha, this->width * this->height, NULL, NULL ); } static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) @@ -322,12 +337,15 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form // Obtain properties of frame mlt_properties properties = mlt_frame_properties( frame ); + *width = mlt_properties_get_int( properties, "rescale_width" ); + *height = mlt_properties_get_int( properties, "rescale_height" ); + // Refresh the image refresh_image( frame, *width, *height ); // Determine format - mlt_producer this = mlt_properties_get_data( properties, "producer_pango", NULL ); - *format = ( mlt_properties_get_int( mlt_producer_properties( this ), "bpp" ) == 4 ) ? mlt_image_rgb24a : mlt_image_rgb24; + //mlt_producer this = mlt_properties_get_data( properties, "producer_pango", NULL ); + //*format = ( mlt_properties_get_int( mlt_producer_properties( this ), "bpp" ) == 4 ) ? mlt_image_rgb24a : mlt_image_rgb24; // May need to know the size of the image to clone it int size = 0; @@ -360,6 +378,15 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form return 0; } +static uint8_t *producer_get_alpha_mask( mlt_frame this ) +{ + // Obtain properties of frame + mlt_properties properties = mlt_frame_properties( this ); + + // Return the alpha mask + return mlt_properties_get_data( properties, "alpha", NULL ); +} + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_pango this = producer->child; @@ -380,6 +407,9 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( properties, "real_width" ) / mlt_properties_get_double( properties, "real_height" ) ); + // Set alpha call back + ( *frame )->get_alpha_mask = producer_get_alpha_mask; + // Stack the get image callback mlt_frame_push_get_image( *frame, producer_get_image ); @@ -396,6 +426,7 @@ static void producer_close( mlt_producer parent ) { producer_pango this = parent->child; free( this->image ); + free( this->alpha ); free( this->fgcolor ); free( this->bgcolor ); free( this->markup ); diff --git a/src/modules/gtk2/producer_pixbuf.c b/src/modules/gtk2/producer_pixbuf.c index cc47424..3cdd5ed 100644 --- a/src/modules/gtk2/producer_pixbuf.c +++ b/src/modules/gtk2/producer_pixbuf.c @@ -34,12 +34,6 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); static void producer_close( mlt_producer parent ); -typedef enum -{ - SIGNAL_FORMAT_PAL, - SIGNAL_FORMAT_NTSC -} mlt_signal_format; - static int filter_files( const struct dirent *de ) { if ( de->d_name[ 0 ] != '.' ) @@ -48,7 +42,6 @@ static int filter_files( const struct dirent *de ) return 0; } - mlt_producer producer_pixbuf_init( char *filename ) { producer_pixbuf this = calloc( sizeof( struct producer_pixbuf_s ), 1 ); @@ -56,12 +49,13 @@ mlt_producer producer_pixbuf_init( char *filename ) { mlt_producer producer = &this->parent; - producer->get_frame = producer_get_frame; - producer->close = producer_close; - // Get the properties interface mlt_properties properties = mlt_producer_properties( &this->parent ); + // Callback registration + producer->get_frame = producer_get_frame; + producer->close = producer_close; + // Set the default properties mlt_properties_set( properties, "resource", filename ); mlt_properties_set_int( properties, "ttl", 25 ); @@ -89,7 +83,7 @@ mlt_producer producer_pixbuf_init( char *filename ) gap ++; } } - mlt_properties_set_position( properties, "out", this->count * 25 ); + mlt_properties_set_position( properties, "out", this->count * 250 ); } else if ( strstr( filename, "/.all." ) != NULL ) { @@ -123,7 +117,7 @@ mlt_producer producer_pixbuf_init( char *filename ) { this->filenames = realloc( this->filenames, sizeof( char * ) * ( this->count + 1 ) ); this->filenames[ this->count ++ ] = strdup( filename ); - mlt_properties_set_position( properties, "out", 25 ); + mlt_properties_set_position( properties, "out", 250 ); } // Initialise gobject types @@ -163,16 +157,25 @@ static void refresh_image( mlt_frame frame, int width, int height ) mlt_frame_set_position( frame, mlt_producer_position( producer ) ); // optimization for subsequent iterations on single picture - if ( this->image != NULL && image_idx == this->image_idx ) + if ( width != 0 && this->image != NULL && image_idx == this->image_idx ) { if ( width != this->width || height != this->height ) { pixbuf = mlt_properties_get_data( producer_props, "pixbuf", NULL ); mlt_properties_set_int( producer_props, "bpp", gdk_pixbuf_get_has_alpha( pixbuf ) ? 4 : 3 ); + free( this->image ); + free( this->alpha ); + this->image = NULL; + this->alpha = NULL; } } - else + else if ( this->image == NULL || image_idx != this->image_idx ) { + free( this->image ); + free( this->alpha ); + this->image = NULL; + this->alpha = NULL; + this->image_idx = image_idx; pixbuf = gdk_pixbuf_new_from_file( this->filenames[ image_idx ], &error ); @@ -197,31 +200,47 @@ static void refresh_image( mlt_frame frame, int width, int height ) // If we have a pixbuf if ( pixbuf && width > 0 ) { - int i; - //fprintf( stderr, "SCALING PIXBUF from %dx%d to %dx%d\n", gdk_pixbuf_get_width( pixbuf ), gdk_pixbuf_get_height( pixbuf ), width, height ); // Note - the original pixbuf is already safe and ready for destruction - pixbuf = gdk_pixbuf_scale_simple( pixbuf, width, height, GDK_INTERP_HYPER ); + pixbuf = gdk_pixbuf_scale_simple( pixbuf, width, height, GDK_INTERP_NEAREST ); // Store width and height - this->width = gdk_pixbuf_get_width( pixbuf ); - this->height = gdk_pixbuf_get_height( pixbuf ); + this->width = width; + this->height = height; + //fprintf( stderr, "SCALING PIXBUF from %dx%d to %dx%d %dx%d\n", gdk_pixbuf_get_width( pixbuf ), gdk_pixbuf_get_height( pixbuf ), width, height, this->width, this->height ); // Allocate/define image // IRRIGATE ME uint8_t *image = malloc( width * ( height + 1 ) * bpp ); + uint8_t *alpha = NULL; - for ( i = 0; i < height; i++ ) - memcpy( image + i * width * bpp, - gdk_pixbuf_get_pixels( pixbuf ) + i * gdk_pixbuf_get_rowstride( pixbuf ), - gdk_pixbuf_get_width( pixbuf ) * bpp ); + // Extract YUV422 and alpha + if ( gdk_pixbuf_get_has_alpha( pixbuf ) ) + { + // Allocate the alpha mask + alpha = malloc( this->width * this->height ); + + // Convert the image + mlt_convert_rgb24a_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ), + this->width, this->height, + gdk_pixbuf_get_rowstride( pixbuf ), + image, alpha ); + } + else + { + // No alpha to extract + mlt_convert_rgb24_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ), + this->width, this->height, + gdk_pixbuf_get_rowstride( pixbuf ), + image ); + } // Finished with pixbuf now g_object_unref( pixbuf ); - // Pass image on properties with or without destructor - free( this->image ); + // Assign images to producer this->image = image; + this->alpha = alpha; } // Set width/height of frame @@ -231,7 +250,8 @@ static void refresh_image( mlt_frame frame, int width, int height ) mlt_properties_set_int( properties, "real_height", mlt_properties_get_int( producer_props, "real_height" ) ); // pass the image data without destructor - mlt_properties_set_data( properties, "image", this->image, this->width * ( this->height + 1 ) * bpp, NULL, NULL ); + mlt_properties_set_data( properties, "image", this->image, this->width * ( this->height + 1 ) * 2, NULL, NULL ); + mlt_properties_set_data( properties, "alpha", this->alpha, this->width * this->height, NULL, NULL ); } static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) @@ -239,12 +259,15 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form // Obtain properties of frame mlt_properties properties = mlt_frame_properties( frame ); + *width = mlt_properties_get_int( properties, "rescale_width" ); + *height = mlt_properties_get_int( properties, "rescale_height" ); + // Refresh the image refresh_image( frame, *width, *height ); // Determine format - mlt_producer this = mlt_properties_get_data( properties, "producer_pixbuf", NULL ); - *format = ( mlt_properties_get_int( mlt_producer_properties( this ), "bpp" ) == 4 ) ? mlt_image_rgb24a : mlt_image_rgb24; + //mlt_producer this = mlt_properties_get_data( properties, "producer_pixbuf", NULL ); + //*format = ( mlt_properties_get_int( mlt_producer_properties( this ), "bpp" ) == 4 ) ? mlt_image_rgb24a : mlt_image_rgb24; // May need to know the size of the image to clone it int size = 0; @@ -279,6 +302,15 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form return 0; } +static uint8_t *producer_get_alpha_mask( mlt_frame this ) +{ + // Obtain properties of frame + mlt_properties properties = mlt_frame_properties( this ); + + // Return the alpha mask + return mlt_properties_get_data( properties, "alpha", NULL ); +} + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { // Get the real structure for this producer @@ -300,6 +332,9 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i mlt_properties_set_int( properties, "progressive", 1 ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( properties, "real_width" ) / mlt_properties_get_double( properties, "real_height" ) ); + // Set alpha call back + ( *frame )->get_alpha_mask = producer_get_alpha_mask; + // Push the get_image method mlt_frame_push_get_image( *frame, producer_get_image ); diff --git a/src/modules/inigo/Makefile b/src/modules/inigo/Makefile index 527e49c..bed91de 100644 --- a/src/modules/inigo/Makefile +++ b/src/modules/inigo/Makefile @@ -4,7 +4,7 @@ TARGET = ../libmltinigo.so OBJS = factory.o \ producer_inigo.o -CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS = -O3 -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread SRCS := $(OBJS:.o=.c) diff --git a/src/modules/resample/Makefile b/src/modules/resample/Makefile index b8b7542..e70434c 100644 --- a/src/modules/resample/Makefile +++ b/src/modules/resample/Makefile @@ -4,7 +4,7 @@ TARGET = ../libmltresample.so OBJS = factory.o \ filter_resample.o -CFLAGS = -I../../ -Wall -g +CFLAGS = -O3 -I../../ -Wall -g LDFLAGS= -lsamplerate diff --git a/src/modules/sdl/Makefile b/src/modules/sdl/Makefile index b527594..9512936 100644 --- a/src/modules/sdl/Makefile +++ b/src/modules/sdl/Makefile @@ -4,7 +4,7 @@ TARGET = ../libmltsdl.so OBJS = factory.o \ consumer_sdl.o -CFLAGS = -I../../ `sdl-config --cflags` -Wall -g -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS = -O3 -I../../ `sdl-config --cflags` -Wall -g -D_FILE_OFFSET_BITS=64 -pthread LDFLAGS= `sdl-config --libs` diff --git a/src/modules/sdl/consumer_sdl.c b/src/modules/sdl/consumer_sdl.c index 3e5d28e..715833c 100644 --- a/src/modules/sdl/consumer_sdl.c +++ b/src/modules/sdl/consumer_sdl.c @@ -515,6 +515,9 @@ static void *consumer_thread( void *arg ) SDL_FreeYUVOverlay( this->sdl_overlay ); SDL_Quit( ); + while( -- this->count >= 0 ) + mlt_frame_close( this->queue[ this->count ] ); + this->sdl_screen = NULL; this->sdl_overlay = NULL; this->audio_avail = 0; diff --git a/src/modules/vorbis/Makefile b/src/modules/vorbis/Makefile index fd8f129..8b89411 100644 --- a/src/modules/vorbis/Makefile +++ b/src/modules/vorbis/Makefile @@ -4,7 +4,7 @@ TARGET = ../libmltvorbis.so OBJS = factory.o \ producer_vorbis.o -CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 +CFLAGS = -O3 -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 LDFLAGS = -lvorbisfile -lvorbis diff --git a/src/modules/westley/Makefile b/src/modules/westley/Makefile index 576a6ea..871c9ac 100644 --- a/src/modules/westley/Makefile +++ b/src/modules/westley/Makefile @@ -5,7 +5,7 @@ OBJS = factory.o \ consumer_westley.o \ producer_westley.o -CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread `xml2-config --cflags` +CFLAGS = -O3 -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread `xml2-config --cflags` LDFLAGS = `xml2-config --libs` diff --git a/src/modules/westley/producer_westley.c b/src/modules/westley/producer_westley.c index 9ac5fa3..808d5ad 100644 --- a/src/modules/westley/producer_westley.c +++ b/src/modules/westley/producer_westley.c @@ -373,7 +373,22 @@ static void on_end_producer( deserialise_context context, const xmlChar *name ) // Instatiate the producer if ( mlt_properties_get( properties, "resource" ) != NULL ) - service = MLT_SERVICE( mlt_factory_producer( "fezzik", mlt_properties_get( properties, "resource" ) ) ); + { + char *root = mlt_properties_get( context->producer_map, "_root" ); + char *resource = mlt_properties_get( properties, "resource" ); + char *full_resource = malloc( strlen( root ) + strlen( resource ) + 1 ); + if ( resource[ 0 ] != '/' ) + { + strcpy( full_resource, root ); + strcat( full_resource, resource ); + } + else + { + strcpy( full_resource, resource ); + } + service = MLT_SERVICE( mlt_factory_producer( "fezzik", full_resource ) ); + free( full_resource ); + } if ( service == NULL && mlt_properties_get( properties, "mlt_service" ) != NULL ) { service = MLT_SERVICE( mlt_factory_producer( mlt_properties_get( properties, "mlt_service" ), @@ -582,7 +597,6 @@ static void on_characters( void *ctx, const xmlChar *ch, int len ) mlt_producer producer_westley_init( char *filename ) { - static int init = 0; xmlSAXHandler *sax = calloc( 1, sizeof( xmlSAXHandler ) ); struct deserialise_context_s *context = calloc( 1, sizeof( struct deserialise_context_s ) ); mlt_properties properties = NULL; @@ -590,17 +604,26 @@ mlt_producer producer_westley_init( char *filename ) context->producer_map = mlt_properties_new(); context->destructors = mlt_properties_new(); + // We need to track the number of registered filters mlt_properties_set_int( context->destructors, "registered", 0 ); + + // We need the directory prefix which was used for the westley + mlt_properties_set( context->producer_map, "_root", "" ); + if ( strchr( filename, '/' ) ) + { + char *root = NULL; + mlt_properties_set( context->producer_map, "_root", filename ); + root = mlt_properties_get( context->producer_map, "_root" ); + *( strrchr( root, '/' ) + 1 ) = '\0'; + } + sax->startElement = on_start_element; sax->endElement = on_end_element; sax->characters = on_characters; - if ( !init ) - { - xmlInitParser(); - //init = 1; - } + // I REALLY DON'T GET THIS - HOW THE HELL CAN YOU REFERENCE A WESTLEY IN A WESTLEY??? + xmlInitParser(); xmlSAXUserParseFile( sax, context, filename ); diff --git a/src/tests/Makefile b/src/tests/Makefile index 3c7dd78..263d72e 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1,6 +1,6 @@ TARGET = dan charlie pango pixbuf dissolve luma -CFLAGS = -I .. -Wall -rdynamic -pthread +CFLAGS = -O3 -I .. -Wall -rdynamic -pthread LDFLAGS = -L ../framework -lmlt diff --git a/src/valerie/Makefile b/src/valerie/Makefile index 6afae18..6fa6d0a 100644 --- a/src/valerie/Makefile +++ b/src/valerie/Makefile @@ -13,7 +13,7 @@ OBJS = valerie.o \ SRCS := $(OBJS:.o=.c) -CFLAGS=-Wall -g -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS=-O3 -Wall -g -D_FILE_OFFSET_BITS=64 -pthread LDFLAGS=-ldv -lpthread -- 1.7.4.4