From 1458c3ed23a0eb7b2dceebfb35618a2ffc498abc Mon Sep 17 00:00:00 2001 From: Eoin O'Neill Date: Thu, 5 May 2022 15:53:53 -0700 Subject: [PATCH 01/16] Initial krita repository setup... --- src/modules/krita/CMakeLists.txt | 15 +++ src/modules/krita/factory.c | 39 +++++++ src/modules/krita/filter_framerange.c | 140 ++++++++++++++++++++++++ src/modules/krita/filter_framerange.yml | 26 +++++ 4 files changed, 220 insertions(+) create mode 100644 src/modules/krita/CMakeLists.txt create mode 100644 src/modules/krita/factory.c create mode 100755 src/modules/krita/filter_framerange.c create mode 100644 src/modules/krita/filter_framerange.yml diff --git a/src/modules/krita/CMakeLists.txt b/src/modules/krita/CMakeLists.txt new file mode 100644 index 000000000..1814702a9 --- /dev/null +++ b/src/modules/krita/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(mltkrita MODULE +) + +target_compile_options(mltkrita PRIVATE ${MLT_COMPILE_OPTIONS}) + +target_link_libraries(mltkrita PRIVATE mlt m) + +set_target_properties(mltkrita PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}") + +install(TARGETS mltkrita LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) + +install(FILES + DESTINATION ${MLT_INSTALL_DATA_DIR}/krita +) + diff --git a/src/modules/krita/factory.c b/src/modules/krita/factory.c new file mode 100644 index 000000000..9f0068178 --- /dev/null +++ b/src/modules/krita/factory.c @@ -0,0 +1,39 @@ +/* + * factory.c -- the factory method interfaces + * Copyright (C) 2021 Eoin O'Neill + * Copyright (C) 2021 Emmet O'Neill + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +//extern mlt_filter filter_framerange_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_producer producer_framebuffer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); + +static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) +{ + char file[ PATH_MAX ]; + snprintf( file, PATH_MAX, "%s/kdenlive/%s", mlt_environment( "MLT_DATA" ), (char*) data ); + return mlt_properties_parse_yaml( file ); +} + +MLT_REPOSITORY +{ + //MLT_REGISTER( mlt_service_filter_type, "framerange", filter_framerange_init ); + //MLT_REGISTER_METADATA( mlt_service_filter_type, "framerange", metadata, "filter_framerange.yml" ); +} diff --git a/src/modules/krita/filter_framerange.c b/src/modules/krita/filter_framerange.c new file mode 100755 index 000000000..1c2853ec7 --- /dev/null +++ b/src/modules/krita/filter_framerange.c @@ -0,0 +1,140 @@ +/* + * filter_freeze.c -- simple frame freezing filter + * Copyright (C) 2007 Jean-Baptiste Mardelle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +{ + mlt_filter self = mlt_frame_pop_service( frame ); + mlt_properties properties = MLT_FILTER_PROPERTIES( self ); + + int frame_start = mlt_properties_get_int( properties, "frame_start" ); + int frame_end = mlt_properties_get_int( properties, "frame_end" ); + mlt_position pos = mlt_producer_get_in( mlt_frame_get_original_producer( frame ) ); + mlt_position currentpos = mlt_filter_get_position( self, frame ); + int real_frame_index = (currentpos % (frame_end - frame_start) + frame_start); + + mlt_service_lock( MLT_FILTER_SERVICE( self ) ); + + //Get producer + mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); + mlt_producer_seek( producer, pos ); + + //Get and set frame data + mlt_frame real_frame = NULL;; + mlt_service_get_frame( mlt_producer_service(producer), &real_frame, 0 ); + mlt_properties_set_position( properties, "_frame", real_frame_index ); + + // Get real image from producer + uint8_t *buffer = NULL; + int error = mlt_frame_get_image( real_frame, &buffer, format, width, height, 1 ); + mlt_service_unlock( MLT_FILTER_SERVICE( self ) ); + + // Copy its data to current frame + int size = mlt_image_format_size( *format, *width, *height, NULL ); + uint8_t *image_copy = mlt_pool_alloc( size ); + memcpy( image_copy, buffer, size ); + *image = image_copy; + mlt_frame_set_image( frame, *image, size, mlt_pool_release ); + + uint8_t *alpha_buffer = mlt_frame_get_alpha( real_frame ); + if ( alpha_buffer ) + { + int alphasize = *width * *height; + uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); + memcpy( alpha_copy, alpha_buffer, alphasize ); + mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); + } + + return error; +} + +static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +{ + mlt_filter self = mlt_frame_pop_service( frame ); + mlt_properties properties = MLT_FILTER_PROPERTIES( self ); + + int frame_start = mlt_properties_get_int( properties, "frame_start" ); + int frame_end = mlt_properties_get_int( properties, "frame_end" ); + mlt_position pos = mlt_producer_get_in( mlt_frame_get_original_producer( frame ) ); + mlt_position currentpos = mlt_filter_get_position( self, frame ); + int real_frame_index = (currentpos % (frame_end - frame_start) + frame_start); + + mlt_service_lock( MLT_FILTER_SERVICE( self ) ); + + //Get producer + mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); + mlt_producer_seek( producer, pos ); + + //Get and set frame data + mlt_frame real_frame = NULL;; + mlt_service_get_frame( mlt_producer_service(producer), &real_frame, 0 ); + mlt_properties_set_position( properties, "_frame", real_frame_index ); + + // Get real audio from producer + return mlt_frame_get_audio( real_frame, buffer, format, frequency, channels, samples ); +} + +/** Filter processing. +*/ + +static mlt_frame filter_process( mlt_filter self, mlt_frame frame ) +{ + + // Push the filter on to the stack + mlt_frame_push_service( frame, self); + + // Push the frame filter + mlt_frame_push_get_image( frame, filter_get_image ); + + mlt_frame_push_audio( frame, filter_get_audio ); + + + return frame; +} + +/** Constructor for the filter. +*/ + +mlt_filter filter_framerange_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + mlt_filter filter = mlt_filter_new( ); + if ( filter != NULL ) + { + filter->process = filter_process; + // Set the frame which will be chosen for freeze + mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "frame_start", "0" ); + + // If freeze_after = 1, only frames after the "frame" value will be frozen + mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "frame_end", "100" ); + + } + return filter; +} + + + diff --git a/src/modules/krita/filter_framerange.yml b/src/modules/krita/filter_framerange.yml new file mode 100644 index 000000000..de1080460 --- /dev/null +++ b/src/modules/krita/filter_framerange.yml @@ -0,0 +1,26 @@ +schema_version: 0.3 +type: filter +identifier: freeze +title: Freeze frame +version: 1 +copyright: Eoin O'Neill, Emmet O'Neill +creator: Eoin O'Neill, Emmet O'Neill +license: LGPLv2.1 +language: en +tags: + - Video + - Audio +parameters: + - identifier: frame_start + title: Start Frame + type: integer + description: First frame of the acceptable playback range. + default: 0 + mutable: true + + - identifier: frame_end + title: End Frame + type: integer + description: Last frame of the acceptable playback range. + default: 100 + mutable: true From b4a8bea4e625d75902a47db44ccb8a568e6ff6a8 Mon Sep 17 00:00:00 2001 From: Eoin O'Neill Date: Thu, 19 May 2022 13:21:41 -0700 Subject: [PATCH 02/16] More krita work. --- CMakeLists.txt | 2 + src/modules/CMakeLists.txt | 4 + src/modules/krita/CMakeLists.txt | 3 + src/modules/krita/factory.c | 14 +- src/modules/krita/filter_framerange.c | 179 ++++++++++++++++++++++++-- src/modules/krita/producer_ranged.c | 162 +++++++++++++++++++++++ src/modules/krita/producer_ranged.yml | 26 ++++ 7 files changed, 371 insertions(+), 19 deletions(-) create mode 100755 src/modules/krita/producer_ranged.c create mode 100644 src/modules/krita/producer_ranged.yml diff --git a/CMakeLists.txt b/CMakeLists.txt index 45c4c597a..0d7fd44dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ option(MOD_GLAXNIMATE "Enable Glaxnimate module (Qt5)" OFF) option(MOD_GLAXNIMATE_QT6 "Enable Glaxnimate module (Qt6)" OFF) option(MOD_JACKRACK "Enable JACK Rack module" ON) option(MOD_KDENLIVE "Enable Kdenlive module" ON) +option(MOD_KRITA "Enable Krita module" ON) option(MOD_NDI "Enable NDI module" OFF) option(MOD_NORMALIZE "Enable Normalize module (GPL)" ON) option(MOD_OLDFILM "Enable Oldfilm module" ON) @@ -590,6 +591,7 @@ add_feature_info("Module: Glaxnimate (Qt5)" MOD_GLAXNIMATE "") add_feature_info("Module: Glaxnimate (Qt6)" MOD_GLAXNIMATE_QT6 "") add_feature_info("Module: JACKRack" MOD_JACKRACK "") add_feature_info("Module: Kdenlive" MOD_KDENLIVE "") +add_feature_info("Module: Krita" MOD_KRITA "") add_feature_info("Module: NDI" MOD_NDI "") add_feature_info("Module: Normalize" MOD_NORMALIZE "") add_feature_info("Module: Oldfilm" MOD_OLDFILM "") diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt index 0c8dcdb14..bf4e573e8 100644 --- a/src/modules/CMakeLists.txt +++ b/src/modules/CMakeLists.txt @@ -28,6 +28,10 @@ if(MOD_KDENLIVE) add_subdirectory(kdenlive) endif() +if(MOD_KRITA) + add_subdirectory(krita) +endif() + if(MOD_NDI) add_subdirectory(ndi) endif() diff --git a/src/modules/krita/CMakeLists.txt b/src/modules/krita/CMakeLists.txt index 1814702a9..e335e40fa 100644 --- a/src/modules/krita/CMakeLists.txt +++ b/src/modules/krita/CMakeLists.txt @@ -1,4 +1,6 @@ add_library(mltkrita MODULE + factory.c + producer_ranged.c ) target_compile_options(mltkrita PRIVATE ${MLT_COMPILE_OPTIONS}) @@ -10,6 +12,7 @@ set_target_properties(mltkrita PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE install(TARGETS mltkrita LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES + producer_ranged.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/krita ) diff --git a/src/modules/krita/factory.c b/src/modules/krita/factory.c index 9f0068178..d449d8e40 100644 --- a/src/modules/krita/factory.c +++ b/src/modules/krita/factory.c @@ -1,7 +1,7 @@ /* * factory.c -- the factory method interfaces - * Copyright (C) 2021 Eoin O'Neill - * Copyright (C) 2021 Emmet O'Neill + * Copyright (C) 2022 Eoin O'Neill + * Copyright (C) 2022 Emmet O'Neill * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,18 +22,18 @@ #include #include -//extern mlt_filter filter_framerange_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); -extern mlt_producer producer_framebuffer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_producer producer_ranged_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); + static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; - snprintf( file, PATH_MAX, "%s/kdenlive/%s", mlt_environment( "MLT_DATA" ), (char*) data ); + snprintf( file, PATH_MAX, "%s/krita/%s", mlt_environment( "MLT_DATA" ), (char*) data ); return mlt_properties_parse_yaml( file ); } MLT_REPOSITORY { - //MLT_REGISTER( mlt_service_filter_type, "framerange", filter_framerange_init ); - //MLT_REGISTER_METADATA( mlt_service_filter_type, "framerange", metadata, "filter_framerange.yml" ); + MLT_REGISTER( mlt_service_producer_type, "ranged", producer_ranged_init ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "ranged", metadata, "producer_ranged.yml" ); } diff --git a/src/modules/krita/filter_framerange.c b/src/modules/krita/filter_framerange.c index 1c2853ec7..381642afc 100755 --- a/src/modules/krita/filter_framerange.c +++ b/src/modules/krita/filter_framerange.c @@ -1,6 +1,7 @@ /* * filter_freeze.c -- simple frame freezing filter - * Copyright (C) 2007 Jean-Baptiste Mardelle + * Copyright (C) 2022 Eoin O'Neill + * Copyright (C) 2022 Emmet O'Neill * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -80,23 +81,21 @@ static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *f int frame_start = mlt_properties_get_int( properties, "frame_start" ); int frame_end = mlt_properties_get_int( properties, "frame_end" ); - mlt_position pos = mlt_producer_get_in( mlt_frame_get_original_producer( frame ) ); mlt_position currentpos = mlt_filter_get_position( self, frame ); int real_frame_index = (currentpos % (frame_end - frame_start) + frame_start); + mlt_service_lock( MLT_FILTER_SERVICE( self ) ); //Get producer mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); - mlt_producer_seek( producer, pos ); - - //Get and set frame data - mlt_frame real_frame = NULL;; - mlt_service_get_frame( mlt_producer_service(producer), &real_frame, 0 ); - mlt_properties_set_position( properties, "_frame", real_frame_index ); + mlt_frame_set_position( frame, real_frame_index ); + mlt_frame real_frame = NULL; + mlt_service_get_frame( MLT_SERVICE(producer), &real_frame, real_frame_index); + mlt_frame_get_audio(real_frame, buffer, format, frequency, channels, samples); + mlt_service_unlock( MLT_FILTER_SERVICE(self) ); - // Get real audio from producer - return mlt_frame_get_audio( real_frame, buffer, format, frequency, channels, samples ); + return 0; } /** Filter processing. @@ -106,13 +105,23 @@ static mlt_frame filter_process( mlt_filter self, mlt_frame frame ) { // Push the filter on to the stack - mlt_frame_push_service( frame, self); + //mlt_frame_push_service( frame, self); // Push the frame filter - mlt_frame_push_get_image( frame, filter_get_image ); + //mlt_frame_push_get_image( frame, filter_get_image ); + mlt_frame_push_service( frame, self ); mlt_frame_push_audio( frame, filter_get_audio ); +// mlt_properties properties = MLT_FILTER_PROPERTIES( self ); +// +// int frame_start = mlt_properties_get_int( properties, "frame_start" ); +// int frame_end = mlt_properties_get_int( properties, "frame_end" ); +// +// mlt_position position = mlt_frame_get_position( frame ); +// mlt_position real_frame_index = (position % (frame_end - frame_start) + frame_start); +// mlt_frame_set_position( frame, real_frame_index ); + return frame; } @@ -138,3 +147,149 @@ mlt_filter filter_framerange_init( mlt_profile profile, mlt_service_type type, c +mlt_producer producer_timewarp_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + // Create a new producer object + mlt_producer producer = mlt_producer_new( profile ); + private_data* pdata = (private_data*)calloc( 1, sizeof(private_data) ); + + if ( arg && producer && pdata ) + { + double frame_rate_num_scaled; + mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); + + // Initialize the producer + mlt_properties_set( producer_properties, "resource", arg ); + producer->child = pdata; + producer->get_frame = producer_get_frame; + producer->close = (mlt_destructor)producer_close; + + // Get the resource to be passed to the clip producer + char* resource = strchr( arg, ':' ); + if ( resource == NULL ) + resource = arg; // Apparently speed was not specified. + else + resource++; // move past the delimiter. + + // Initialize private data + pdata->first_frame = 1; + pdata->speed = atof( arg ); + if( pdata->speed == 0.0 ) + { + pdata->speed = 1.0; + } + pdata->clip_profile = NULL; + pdata->clip_parameters = NULL; + pdata->clip_producer = NULL; + pdata->pitch_filter = NULL; + + // Create a false profile to be used by the clip producer. + pdata->clip_profile = mlt_profile_clone( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ); + // Frame rate must be recalculated for the clip profile to change the time base. + if( pdata->clip_profile->frame_rate_num < 1000 ) + { + // Scale the frame rate fraction so we keep more accuracy when + // the speed is factored in. + pdata->clip_profile->frame_rate_num *= 1000; + pdata->clip_profile->frame_rate_den *= 1000; + } + frame_rate_num_scaled = (double)pdata->clip_profile->frame_rate_num / fabs(pdata->speed); + if (frame_rate_num_scaled > INT_MAX) // Check for overflow in case speed < 1.0 + { + //scale by denominator to avoid overflow. + pdata->clip_profile->frame_rate_den = (double)pdata->clip_profile->frame_rate_den * fabs(pdata->speed); + } + else + { + //scale by numerator + pdata->clip_profile->frame_rate_num = frame_rate_num_scaled; + } + + // Create a producer for the clip using the false profile. + pdata->clip_producer = mlt_factory_producer( pdata->clip_profile, "abnormal", resource ); + + if( pdata->clip_producer ) + { + mlt_properties clip_properties = MLT_PRODUCER_PROPERTIES( pdata->clip_producer ); + int n = 0; + int i = 0; + + // Set the speed to 0 since we will control the seeking + mlt_producer_set_speed( pdata->clip_producer, 0 ); + + // Create a list of all parameters used by the clip producer so that + // they can be passed between the clip producer and this producer. + pdata->clip_parameters = mlt_properties_new(); + mlt_repository repository = mlt_factory_repository(); + mlt_properties clip_metadata = mlt_repository_metadata( repository, mlt_service_producer_type, mlt_properties_get( clip_properties, "mlt_service" ) ); + if ( clip_metadata ) + { + mlt_properties params = (mlt_properties) mlt_properties_get_data( clip_metadata, "parameters", NULL ); + if ( params ) + { + n = mlt_properties_count( params ); + for ( i = 0; i < n; i++ ) + { + mlt_properties param = (mlt_properties) mlt_properties_get_data( params, mlt_properties_get_name( params, i ), NULL ); + char* identifier = mlt_properties_get( param, "identifier" ); + if ( identifier ) + { + // Set the value to 1 to indicate the parameter exists. + mlt_properties_set_int( pdata->clip_parameters, identifier, 1 ); + } + } + // Explicitly exclude the "resource" parameter since it needs to be different. + mlt_properties_set_int( pdata->clip_parameters, "resource", 0 ); + } + } + + // Pass parameters and properties from the clip producer to this producer. + // Some properties may have been set during initialization. + n = mlt_properties_count( clip_properties ); + for ( i = 0; i < n; i++ ) + { + char* name = mlt_properties_get_name( clip_properties, i ); + if ( mlt_properties_get_int( pdata->clip_parameters, name ) || + !strcmp( name, "length" ) || + !strcmp( name, "in" ) || + !strcmp( name, "out" ) || + !strncmp( name, "meta.", 5 ) ) + { + mlt_properties_pass_property( producer_properties, clip_properties, name ); + } + } + + // Initialize warp producer properties + mlt_properties_set_double( producer_properties, "warp_speed", pdata->speed ); + mlt_properties_set( producer_properties, "warp_resource", mlt_properties_get( clip_properties, "resource" ) ); + + // Monitor property changes from both producers so that the clip + // parameters can be passed back and forth. + mlt_events_listen( clip_properties, producer, "property-changed", ( mlt_listener )clip_property_changed ); + mlt_events_listen( producer_properties, producer, "property-changed", ( mlt_listener )timewarp_property_changed ); + } + } + + if ( !producer || !pdata || !pdata->clip_producer ) + { + if ( pdata ) + { + mlt_producer_close( pdata->clip_producer ); + mlt_profile_close( pdata->clip_profile ); + mlt_properties_close( pdata->clip_parameters ); + free( pdata ); + } + + if ( producer ) + { + producer->child = NULL; + producer->close = NULL; + mlt_producer_close( producer ); + free( producer ); + producer = NULL; + } + } + + return producer; +} + diff --git a/src/modules/krita/producer_ranged.c b/src/modules/krita/producer_ranged.c new file mode 100755 index 000000000..ae844e8a4 --- /dev/null +++ b/src/modules/krita/producer_ranged.c @@ -0,0 +1,162 @@ +/* + * filter_freeze.c -- simple frame freezing filter + * Copyright (C) 2022 Eoin O'Neill + * Copyright (C) 2022 Emmet O'Neill + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + + +typedef struct +{ + int frame_start; + int frame_end; + mlt_producer producer_internal; +} private_data; + + +static int restrict_range( int input, int min, int max ) { + const int span = max - min; + return (MAX(input - min, 0) % (span + 1)) + min; +} + +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) +{ + private_data* pdata = (private_data*)producer->child; + + const int position = mlt_producer_position(pdata->producer_internal); + mlt_properties_set_position(MLT_PRODUCER_PROPERTIES(pdata->producer_internal), "_position", restrict_range(position, pdata->frame_start, pdata->frame_end)); + int r = mlt_service_get_frame((mlt_service)pdata->producer_internal, frame, index); + + return r; +} + +static int producer_seek( mlt_producer producer, mlt_position position) +{ + private_data* pdata = (private_data*)producer->child; + + int r = mlt_producer_seek(pdata->producer_internal, position); + + return r; +} + +static void producer_property_changed( mlt_service owner, mlt_producer self, mlt_event_data event_data) +{ + const char *name = mlt_event_data_to_string(event_data); + if (!name) return; + + if (strcmp(name, "start_frame") || strcmp( name, "end_frame" )){ + private_data* pdata = (private_data*)self->child; + mlt_properties props = MLT_PRODUCER_PROPERTIES(self); + pdata->frame_start = mlt_properties_get_int(props, "start_frame"); + pdata->frame_end = mlt_properties_get_int(props, "end_frame"); + } + + if (strcmp(name, "_profile")) { + private_data* pdata = (private_data*)self->child; + mlt_service_set_profile((mlt_service)pdata->producer_internal, mlt_service_profile((mlt_service)self)); + } +} + + +static void producer_close( mlt_producer producer ) +{ + private_data* pdata = (private_data*)producer->child; + + if ( pdata ) + { + mlt_producer_close( pdata->producer_internal ); + free( pdata ); + } +} + + +/** Constructor for the producer. +*/ +mlt_producer producer_ranged_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + // Create a new producer object + mlt_producer producer = mlt_producer_new( profile ); + private_data* pdata = (private_data*)calloc( 1, sizeof(private_data) ); + + if ( arg && producer && pdata ) + { + mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); + + // Initialize the producer + mlt_properties_set( producer_properties, "resource", arg ); + producer->child = pdata; + producer->get_frame = producer_get_frame; + producer->seek = producer_seek; + producer->close = (mlt_destructor)producer_close; + + // Get the resource to be passed to the clip producer + char* resource = arg; + + // Default frame start / end props. + pdata->frame_start = 0; + pdata->frame_end = 240; + + // Initialize property values for start / end frames. + mlt_properties_set_int(producer_properties, "start_frame", pdata->frame_start); + mlt_properties_set_int(producer_properties, "end_frame", pdata->frame_end); + + // Create a producer for the clip using the false profile. + pdata->producer_internal = mlt_factory_producer( profile, "abnormal", resource); + + if (pdata->producer_internal) { + mlt_producer_set_speed(pdata->producer_internal, 1.0); + } + + mlt_events_listen( producer_properties, producer, "property-changed", ( mlt_listener )producer_property_changed ); + } + + if ( !producer || !pdata || !pdata->producer_internal ) + { + if ( pdata ) + { + mlt_producer_close( pdata->producer_internal ); + free( pdata ); + } + + if ( producer ) + { + producer->child = NULL; + producer->close = NULL; + mlt_producer_close( producer ); + free( producer ); + producer = NULL; + } + } + + return producer; +} + + diff --git a/src/modules/krita/producer_ranged.yml b/src/modules/krita/producer_ranged.yml new file mode 100644 index 000000000..7058f2a13 --- /dev/null +++ b/src/modules/krita/producer_ranged.yml @@ -0,0 +1,26 @@ +schema_version: 0.3 +type: producer +identifier: ranged +title: Ranged +version: 1 +copyright: Eoin O'Neill, Emmet O'Neill +creator: Eoin O'Neill, Emmet O'Neill +license: LGPLv2.1 +language: en +tags: + - Video + - Audio +parameters: + - identifier: frame_start + title: Start Frame + type: integer + description: First frame of the acceptable playback range. + default: 0 + mutable: true + + - identifier: frame_end + title: End Frame + type: integer + description: Last frame of the acceptable playback range. + default: 100 + mutable: true From 69d38f03ddfda88a572fe0c069f707dd7ac0b41d Mon Sep 17 00:00:00 2001 From: Eoin O'Neill Date: Wed, 22 Jun 2022 18:25:54 -0700 Subject: [PATCH 03/16] Added more options to enable or disable frame range limits. --- src/modules/krita/producer_ranged.c | 30 +++++++++++++++++++++++---- src/modules/krita/producer_ranged.yml | 7 +++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/modules/krita/producer_ranged.c b/src/modules/krita/producer_ranged.c index ae844e8a4..6a6c5a523 100755 --- a/src/modules/krita/producer_ranged.c +++ b/src/modules/krita/producer_ranged.c @@ -38,6 +38,7 @@ typedef struct { int frame_start; int frame_end; + int limit_enabled; mlt_producer producer_internal; } private_data; @@ -47,12 +48,24 @@ static int restrict_range( int input, int min, int max ) { return (MAX(input - min, 0) % (span + 1)) + min; } + +int is_valid_range( const private_data* pdata ) { + return pdata->frame_start > -1 && pdata->frame_end > -1 && pdata->frame_end > pdata->frame_start; +} + +int is_limit_enabled( const private_data* pdata) { + return pdata->limit_enabled != 0; +} + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { private_data* pdata = (private_data*)producer->child; const int position = mlt_producer_position(pdata->producer_internal); - mlt_properties_set_position(MLT_PRODUCER_PROPERTIES(pdata->producer_internal), "_position", restrict_range(position, pdata->frame_start, pdata->frame_end)); + if (is_valid_range(pdata) && is_limit_enabled(pdata)) { + mlt_properties_set_position(MLT_PRODUCER_PROPERTIES(pdata->producer_internal), "_position", restrict_range(position, pdata->frame_start, pdata->frame_end)); + } + int r = mlt_service_get_frame((mlt_service)pdata->producer_internal, frame, index); return r; @@ -72,13 +85,20 @@ static void producer_property_changed( mlt_service owner, mlt_producer self, mlt const char *name = mlt_event_data_to_string(event_data); if (!name) return; - if (strcmp(name, "start_frame") || strcmp( name, "end_frame" )){ + if (strcmp(name, "start_frame") || strcmp( name, "end_frame" )){ private_data* pdata = (private_data*)self->child; mlt_properties props = MLT_PRODUCER_PROPERTIES(self); pdata->frame_start = mlt_properties_get_int(props, "start_frame"); pdata->frame_end = mlt_properties_get_int(props, "end_frame"); } + // TODO: Find out why this strcmp doesn't work... + //if (strcmp(name, "limit_enabled")) { + private_data* pdata = (private_data*)self->child; + mlt_properties props = MLT_PRODUCER_PROPERTIES(self); + pdata->limit_enabled = mlt_properties_get_int(props, "limit_enabled"); + //} + if (strcmp(name, "_profile")) { private_data* pdata = (private_data*)self->child; mlt_service_set_profile((mlt_service)pdata->producer_internal, mlt_service_profile((mlt_service)self)); @@ -121,12 +141,14 @@ mlt_producer producer_ranged_init( mlt_profile profile, mlt_service_type type, c char* resource = arg; // Default frame start / end props. - pdata->frame_start = 0; - pdata->frame_end = 240; + pdata->frame_start = -1; + pdata->frame_end = -1; + pdata->limit_enabled = 1; // Initialize property values for start / end frames. mlt_properties_set_int(producer_properties, "start_frame", pdata->frame_start); mlt_properties_set_int(producer_properties, "end_frame", pdata->frame_end); + mlt_properties_set_int(producer_properties, "limit_enabled", pdata->limit_enabled); // Create a producer for the clip using the false profile. pdata->producer_internal = mlt_factory_producer( profile, "abnormal", resource); diff --git a/src/modules/krita/producer_ranged.yml b/src/modules/krita/producer_ranged.yml index 7058f2a13..fff52988b 100644 --- a/src/modules/krita/producer_ranged.yml +++ b/src/modules/krita/producer_ranged.yml @@ -24,3 +24,10 @@ parameters: description: Last frame of the acceptable playback range. default: 100 mutable: true + + - identifier: limit_enabled + title: Limit Enabled + type: integer + description: Whether the frame limiting feature should be enabled. + default: 0 + mutable: true From bc2fd9da70602902a17f99a4b8bc1b28ee703803 Mon Sep 17 00:00:00 2001 From: Eoin O'Neill Date: Wed, 21 Sep 2022 19:34:37 -0700 Subject: [PATCH 04/16] Add support for variable play speeds. --- src/modules/krita/producer_ranged.c | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/modules/krita/producer_ranged.c b/src/modules/krita/producer_ranged.c index 6a6c5a523..32393034c 100755 --- a/src/modules/krita/producer_ranged.c +++ b/src/modules/krita/producer_ranged.c @@ -39,6 +39,7 @@ typedef struct int frame_start; int frame_end; int limit_enabled; + double speed; mlt_producer producer_internal; } private_data; @@ -57,6 +58,28 @@ int is_limit_enabled( const private_data* pdata) { return pdata->limit_enabled != 0; } +static int producer_get_audio( mlt_frame frame, void** buffer, mlt_audio_format* format, int* frequency, int* channels, int* samples ) +{ + mlt_producer producer = mlt_frame_pop_audio( frame ); + private_data* pdata = (private_data*)producer->child; + struct mlt_audio_s audio; + mlt_audio_set_values( &audio, *buffer, *frequency, *format, *samples, *channels ); + + int error = mlt_frame_get_audio( frame, &audio.data, &audio.format, &audio.frequency, &audio.channels, &audio.samples ); + + // Scale the frequency to account for the speed change. + audio.frequency = (double)audio.frequency * fabs(pdata->speed); + + if( pdata->speed < 0.0 ) + { + mlt_audio_reverse( &audio ); + } + + mlt_audio_get_values( &audio, buffer, frequency, format, samples, channels ); + + return error; +} + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { private_data* pdata = (private_data*)producer->child; @@ -68,6 +91,12 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i int r = mlt_service_get_frame((mlt_service)pdata->producer_internal, frame, index); + if ( !mlt_frame_is_test_audio( *frame ) ) + { + mlt_frame_push_audio( *frame, producer ); + mlt_frame_push_audio( *frame, producer_get_audio ); + } + return r; } @@ -99,6 +128,11 @@ static void producer_property_changed( mlt_service owner, mlt_producer self, mlt pdata->limit_enabled = mlt_properties_get_int(props, "limit_enabled"); //} + if (strcmp(name, "speed")) { + mlt_properties props = MLT_PRODUCER_PROPERTIES(self); + pdata->speed = mlt_properties_get_double(props, "speed"); + } + if (strcmp(name, "_profile")) { private_data* pdata = (private_data*)self->child; mlt_service_set_profile((mlt_service)pdata->producer_internal, mlt_service_profile((mlt_service)self)); @@ -144,11 +178,13 @@ mlt_producer producer_ranged_init( mlt_profile profile, mlt_service_type type, c pdata->frame_start = -1; pdata->frame_end = -1; pdata->limit_enabled = 1; + pdata->speed = 1.0; // Initialize property values for start / end frames. mlt_properties_set_int(producer_properties, "start_frame", pdata->frame_start); mlt_properties_set_int(producer_properties, "end_frame", pdata->frame_end); mlt_properties_set_int(producer_properties, "limit_enabled", pdata->limit_enabled); + mlt_properties_set_double(producer_properties, "speed", pdata->speed); // Create a producer for the clip using the false profile. pdata->producer_internal = mlt_factory_producer( profile, "abnormal", resource); From 36792290604b86e5624427abb2fd64008af1bc9c Mon Sep 17 00:00:00 2001 From: Eoin O'Neill Date: Wed, 21 Sep 2022 19:36:00 -0700 Subject: [PATCH 05/16] Remove remnants of old experimentation. --- src/modules/krita/filter_framerange.c | 295 ------------------------ src/modules/krita/filter_framerange.yml | 26 --- 2 files changed, 321 deletions(-) delete mode 100755 src/modules/krita/filter_framerange.c delete mode 100644 src/modules/krita/filter_framerange.yml diff --git a/src/modules/krita/filter_framerange.c b/src/modules/krita/filter_framerange.c deleted file mode 100755 index 381642afc..000000000 --- a/src/modules/krita/filter_framerange.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * filter_freeze.c -- simple frame freezing filter - * Copyright (C) 2022 Eoin O'Neill - * Copyright (C) 2022 Emmet O'Neill - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) -{ - mlt_filter self = mlt_frame_pop_service( frame ); - mlt_properties properties = MLT_FILTER_PROPERTIES( self ); - - int frame_start = mlt_properties_get_int( properties, "frame_start" ); - int frame_end = mlt_properties_get_int( properties, "frame_end" ); - mlt_position pos = mlt_producer_get_in( mlt_frame_get_original_producer( frame ) ); - mlt_position currentpos = mlt_filter_get_position( self, frame ); - int real_frame_index = (currentpos % (frame_end - frame_start) + frame_start); - - mlt_service_lock( MLT_FILTER_SERVICE( self ) ); - - //Get producer - mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); - mlt_producer_seek( producer, pos ); - - //Get and set frame data - mlt_frame real_frame = NULL;; - mlt_service_get_frame( mlt_producer_service(producer), &real_frame, 0 ); - mlt_properties_set_position( properties, "_frame", real_frame_index ); - - // Get real image from producer - uint8_t *buffer = NULL; - int error = mlt_frame_get_image( real_frame, &buffer, format, width, height, 1 ); - mlt_service_unlock( MLT_FILTER_SERVICE( self ) ); - - // Copy its data to current frame - int size = mlt_image_format_size( *format, *width, *height, NULL ); - uint8_t *image_copy = mlt_pool_alloc( size ); - memcpy( image_copy, buffer, size ); - *image = image_copy; - mlt_frame_set_image( frame, *image, size, mlt_pool_release ); - - uint8_t *alpha_buffer = mlt_frame_get_alpha( real_frame ); - if ( alpha_buffer ) - { - int alphasize = *width * *height; - uint8_t *alpha_copy = mlt_pool_alloc( alphasize ); - memcpy( alpha_copy, alpha_buffer, alphasize ); - mlt_frame_set_alpha( frame, alpha_copy, alphasize, mlt_pool_release ); - } - - return error; -} - -static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) -{ - mlt_filter self = mlt_frame_pop_service( frame ); - mlt_properties properties = MLT_FILTER_PROPERTIES( self ); - - int frame_start = mlt_properties_get_int( properties, "frame_start" ); - int frame_end = mlt_properties_get_int( properties, "frame_end" ); - mlt_position currentpos = mlt_filter_get_position( self, frame ); - int real_frame_index = (currentpos % (frame_end - frame_start) + frame_start); - - - mlt_service_lock( MLT_FILTER_SERVICE( self ) ); - - //Get producer - mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); - mlt_frame_set_position( frame, real_frame_index ); - mlt_frame real_frame = NULL; - mlt_service_get_frame( MLT_SERVICE(producer), &real_frame, real_frame_index); - mlt_frame_get_audio(real_frame, buffer, format, frequency, channels, samples); - mlt_service_unlock( MLT_FILTER_SERVICE(self) ); - - return 0; -} - -/** Filter processing. -*/ - -static mlt_frame filter_process( mlt_filter self, mlt_frame frame ) -{ - - // Push the filter on to the stack - //mlt_frame_push_service( frame, self); - - // Push the frame filter - //mlt_frame_push_get_image( frame, filter_get_image ); - - mlt_frame_push_service( frame, self ); - mlt_frame_push_audio( frame, filter_get_audio ); - -// mlt_properties properties = MLT_FILTER_PROPERTIES( self ); -// -// int frame_start = mlt_properties_get_int( properties, "frame_start" ); -// int frame_end = mlt_properties_get_int( properties, "frame_end" ); -// -// mlt_position position = mlt_frame_get_position( frame ); -// mlt_position real_frame_index = (position % (frame_end - frame_start) + frame_start); -// mlt_frame_set_position( frame, real_frame_index ); - - - return frame; -} - -/** Constructor for the filter. -*/ - -mlt_filter filter_framerange_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - mlt_filter filter = mlt_filter_new( ); - if ( filter != NULL ) - { - filter->process = filter_process; - // Set the frame which will be chosen for freeze - mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "frame_start", "0" ); - - // If freeze_after = 1, only frames after the "frame" value will be frozen - mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "frame_end", "100" ); - - } - return filter; -} - - - -mlt_producer producer_timewarp_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) -{ - // Create a new producer object - mlt_producer producer = mlt_producer_new( profile ); - private_data* pdata = (private_data*)calloc( 1, sizeof(private_data) ); - - if ( arg && producer && pdata ) - { - double frame_rate_num_scaled; - mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); - - // Initialize the producer - mlt_properties_set( producer_properties, "resource", arg ); - producer->child = pdata; - producer->get_frame = producer_get_frame; - producer->close = (mlt_destructor)producer_close; - - // Get the resource to be passed to the clip producer - char* resource = strchr( arg, ':' ); - if ( resource == NULL ) - resource = arg; // Apparently speed was not specified. - else - resource++; // move past the delimiter. - - // Initialize private data - pdata->first_frame = 1; - pdata->speed = atof( arg ); - if( pdata->speed == 0.0 ) - { - pdata->speed = 1.0; - } - pdata->clip_profile = NULL; - pdata->clip_parameters = NULL; - pdata->clip_producer = NULL; - pdata->pitch_filter = NULL; - - // Create a false profile to be used by the clip producer. - pdata->clip_profile = mlt_profile_clone( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ); - // Frame rate must be recalculated for the clip profile to change the time base. - if( pdata->clip_profile->frame_rate_num < 1000 ) - { - // Scale the frame rate fraction so we keep more accuracy when - // the speed is factored in. - pdata->clip_profile->frame_rate_num *= 1000; - pdata->clip_profile->frame_rate_den *= 1000; - } - frame_rate_num_scaled = (double)pdata->clip_profile->frame_rate_num / fabs(pdata->speed); - if (frame_rate_num_scaled > INT_MAX) // Check for overflow in case speed < 1.0 - { - //scale by denominator to avoid overflow. - pdata->clip_profile->frame_rate_den = (double)pdata->clip_profile->frame_rate_den * fabs(pdata->speed); - } - else - { - //scale by numerator - pdata->clip_profile->frame_rate_num = frame_rate_num_scaled; - } - - // Create a producer for the clip using the false profile. - pdata->clip_producer = mlt_factory_producer( pdata->clip_profile, "abnormal", resource ); - - if( pdata->clip_producer ) - { - mlt_properties clip_properties = MLT_PRODUCER_PROPERTIES( pdata->clip_producer ); - int n = 0; - int i = 0; - - // Set the speed to 0 since we will control the seeking - mlt_producer_set_speed( pdata->clip_producer, 0 ); - - // Create a list of all parameters used by the clip producer so that - // they can be passed between the clip producer and this producer. - pdata->clip_parameters = mlt_properties_new(); - mlt_repository repository = mlt_factory_repository(); - mlt_properties clip_metadata = mlt_repository_metadata( repository, mlt_service_producer_type, mlt_properties_get( clip_properties, "mlt_service" ) ); - if ( clip_metadata ) - { - mlt_properties params = (mlt_properties) mlt_properties_get_data( clip_metadata, "parameters", NULL ); - if ( params ) - { - n = mlt_properties_count( params ); - for ( i = 0; i < n; i++ ) - { - mlt_properties param = (mlt_properties) mlt_properties_get_data( params, mlt_properties_get_name( params, i ), NULL ); - char* identifier = mlt_properties_get( param, "identifier" ); - if ( identifier ) - { - // Set the value to 1 to indicate the parameter exists. - mlt_properties_set_int( pdata->clip_parameters, identifier, 1 ); - } - } - // Explicitly exclude the "resource" parameter since it needs to be different. - mlt_properties_set_int( pdata->clip_parameters, "resource", 0 ); - } - } - - // Pass parameters and properties from the clip producer to this producer. - // Some properties may have been set during initialization. - n = mlt_properties_count( clip_properties ); - for ( i = 0; i < n; i++ ) - { - char* name = mlt_properties_get_name( clip_properties, i ); - if ( mlt_properties_get_int( pdata->clip_parameters, name ) || - !strcmp( name, "length" ) || - !strcmp( name, "in" ) || - !strcmp( name, "out" ) || - !strncmp( name, "meta.", 5 ) ) - { - mlt_properties_pass_property( producer_properties, clip_properties, name ); - } - } - - // Initialize warp producer properties - mlt_properties_set_double( producer_properties, "warp_speed", pdata->speed ); - mlt_properties_set( producer_properties, "warp_resource", mlt_properties_get( clip_properties, "resource" ) ); - - // Monitor property changes from both producers so that the clip - // parameters can be passed back and forth. - mlt_events_listen( clip_properties, producer, "property-changed", ( mlt_listener )clip_property_changed ); - mlt_events_listen( producer_properties, producer, "property-changed", ( mlt_listener )timewarp_property_changed ); - } - } - - if ( !producer || !pdata || !pdata->clip_producer ) - { - if ( pdata ) - { - mlt_producer_close( pdata->clip_producer ); - mlt_profile_close( pdata->clip_profile ); - mlt_properties_close( pdata->clip_parameters ); - free( pdata ); - } - - if ( producer ) - { - producer->child = NULL; - producer->close = NULL; - mlt_producer_close( producer ); - free( producer ); - producer = NULL; - } - } - - return producer; -} - diff --git a/src/modules/krita/filter_framerange.yml b/src/modules/krita/filter_framerange.yml deleted file mode 100644 index de1080460..000000000 --- a/src/modules/krita/filter_framerange.yml +++ /dev/null @@ -1,26 +0,0 @@ -schema_version: 0.3 -type: filter -identifier: freeze -title: Freeze frame -version: 1 -copyright: Eoin O'Neill, Emmet O'Neill -creator: Eoin O'Neill, Emmet O'Neill -license: LGPLv2.1 -language: en -tags: - - Video - - Audio -parameters: - - identifier: frame_start - title: Start Frame - type: integer - description: First frame of the acceptable playback range. - default: 0 - mutable: true - - - identifier: frame_end - title: End Frame - type: integer - description: Last frame of the acceptable playback range. - default: 100 - mutable: true From a027ac20ac9e639df9deb0ab2556289e3c06c142 Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov Date: Thu, 6 Apr 2023 15:55:27 +0200 Subject: [PATCH 06/16] Fix compilation on Windows with Clang 15 --- src/framework/CMakeLists.txt | 8 ++------ src/framework/mlt_property.h | 2 ++ src/mlt++/CMakeLists.txt | 8 ++------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index e17e43c00..c61cd3b8e 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -96,12 +96,8 @@ set_target_properties(mlt PROPERTIES if(WIN32) if(MINGW) - install(FILES "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libmlt-${MLT_VERSION_MAJOR}.dll" - DESTINATION ${CMAKE_INSTALL_LIBDIR} - RENAME libmlt.dll - ) - target_link_options(mlt PRIVATE -Wl,--output-def,libmlt.def) - install(FILES "${CMAKE_BINARY_DIR}/libmlt.def" DESTINATION ${CMAKE_INSTALL_LIBDIR}) + target_link_options(mlt PRIVATE -Wl,--output-def,${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libmlt-${MLT_VERSION_MAJOR}.def) + install(FILES "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libmlt-${MLT_VERSION_MAJOR}.def" DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() target_sources(mlt PRIVATE ../win32/win32.c ../win32/strptime.c) target_link_libraries(mlt PRIVATE Iconv::Iconv) diff --git a/src/framework/mlt_property.h b/src/framework/mlt_property.h index 4b51af415..e347d4b68 100644 --- a/src/framework/mlt_property.h +++ b/src/framework/mlt_property.h @@ -39,6 +39,8 @@ typedef locale_t mlt_locale_t; #elif defined(__OpenBSD__) /* XXX matches __nop_locale glue in libc++ */ typedef void *mlt_locale_t; +#elif (defined _WIN32 && defined _LIBCPP_VERSION) +struct mlt_locale_t; #else typedef char *mlt_locale_t; #endif diff --git a/src/mlt++/CMakeLists.txt b/src/mlt++/CMakeLists.txt index 26c055796..7028c41dd 100644 --- a/src/mlt++/CMakeLists.txt +++ b/src/mlt++/CMakeLists.txt @@ -85,12 +85,8 @@ set_target_properties(mlt++ PROPERTIES if(WIN32) if(MINGW) - install(FILES "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libmlt++-${MLT_VERSION_MAJOR}.dll" - DESTINATION ${CMAKE_INSTALL_LIBDIR} - RENAME libmlt++.dll - ) - target_link_options(mlt++ PRIVATE -Wl,--output-def,libmlt++.def) - install(FILES "${CMAKE_BINARY_DIR}/libmlt++.def" DESTINATION ${CMAKE_INSTALL_LIBDIR}) + target_link_options(mlt++ PRIVATE -Wl,--output-def,${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libmlt++-${MLT_VERSION_MAJOR}.def) + install(FILES "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libmlt++-${MLT_VERSION_MAJOR}.def" DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() target_compile_definitions(mlt++ PRIVATE MLTPP_EXPORTS) endif() From 5761ef39cb647a6c0ad804c0e01c3b2db20959f7 Mon Sep 17 00:00:00 2001 From: Emmet O'Neill Date: Wed, 3 May 2023 21:56:52 -0700 Subject: [PATCH 07/16] Renamed 'producer_ranged' to 'producer_krita'. --- src/modules/krita/CMakeLists.txt | 4 ++-- src/modules/krita/factory.c | 6 +++--- src/modules/krita/producer_ranged.c | 2 +- src/modules/krita/producer_ranged.yml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/krita/CMakeLists.txt b/src/modules/krita/CMakeLists.txt index e335e40fa..3e85cb67f 100644 --- a/src/modules/krita/CMakeLists.txt +++ b/src/modules/krita/CMakeLists.txt @@ -1,6 +1,6 @@ add_library(mltkrita MODULE factory.c - producer_ranged.c + producer_krita.c ) target_compile_options(mltkrita PRIVATE ${MLT_COMPILE_OPTIONS}) @@ -12,7 +12,7 @@ set_target_properties(mltkrita PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE install(TARGETS mltkrita LIBRARY DESTINATION ${MLT_INSTALL_MODULE_DIR}) install(FILES - producer_ranged.yml + producer_krita.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/krita ) diff --git a/src/modules/krita/factory.c b/src/modules/krita/factory.c index d449d8e40..1fef3e67b 100644 --- a/src/modules/krita/factory.c +++ b/src/modules/krita/factory.c @@ -22,7 +22,7 @@ #include #include -extern mlt_producer producer_ranged_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_producer producer_krita_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) @@ -34,6 +34,6 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat MLT_REPOSITORY { - MLT_REGISTER( mlt_service_producer_type, "ranged", producer_ranged_init ); - MLT_REGISTER_METADATA( mlt_service_producer_type, "ranged", metadata, "producer_ranged.yml" ); + MLT_REGISTER( mlt_service_producer_type, "krita", producer_krita_init ); + MLT_REGISTER_METADATA( mlt_service_producer_type, "krita", metadata, "producer_krita.yml" ); } diff --git a/src/modules/krita/producer_ranged.c b/src/modules/krita/producer_ranged.c index 32393034c..071f75ca7 100755 --- a/src/modules/krita/producer_ranged.c +++ b/src/modules/krita/producer_ranged.c @@ -154,7 +154,7 @@ static void producer_close( mlt_producer producer ) /** Constructor for the producer. */ -mlt_producer producer_ranged_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +mlt_producer producer_krita_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create a new producer object mlt_producer producer = mlt_producer_new( profile ); diff --git a/src/modules/krita/producer_ranged.yml b/src/modules/krita/producer_ranged.yml index fff52988b..ef6e79ff4 100644 --- a/src/modules/krita/producer_ranged.yml +++ b/src/modules/krita/producer_ranged.yml @@ -1,7 +1,7 @@ schema_version: 0.3 type: producer -identifier: ranged -title: Ranged +identifier: krita +title: Krita version: 1 copyright: Eoin O'Neill, Emmet O'Neill creator: Eoin O'Neill, Emmet O'Neill From 27de4d052e61d635b7a0efc363d4c2d787e205f8 Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov Date: Tue, 9 May 2023 14:28:01 +0200 Subject: [PATCH 08/16] Fix rename of the files producer_ranged -> producer_krita --- src/modules/krita/{producer_ranged.c => producer_krita.c} | 0 src/modules/krita/{producer_ranged.yml => producer_krita.yml} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/modules/krita/{producer_ranged.c => producer_krita.c} (100%) mode change 100755 => 100644 rename src/modules/krita/{producer_ranged.yml => producer_krita.yml} (100%) diff --git a/src/modules/krita/producer_ranged.c b/src/modules/krita/producer_krita.c old mode 100755 new mode 100644 similarity index 100% rename from src/modules/krita/producer_ranged.c rename to src/modules/krita/producer_krita.c diff --git a/src/modules/krita/producer_ranged.yml b/src/modules/krita/producer_krita.yml similarity index 100% rename from src/modules/krita/producer_ranged.yml rename to src/modules/krita/producer_krita.yml From 175c9f2672b298187436a705b638ba15c71e7278 Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov Date: Fri, 30 Jun 2023 13:19:54 +0300 Subject: [PATCH 09/16] Fix a memory leak in the MLT's producer_krita The virtual destructors should be chained in a rather peculiar way in MLT to avoid leaks. --- src/modules/krita/producer_krita.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/krita/producer_krita.c b/src/modules/krita/producer_krita.c index 071f75ca7..92c470aed 100644 --- a/src/modules/krita/producer_krita.c +++ b/src/modules/krita/producer_krita.c @@ -149,6 +149,10 @@ static void producer_close( mlt_producer producer ) mlt_producer_close( pdata->producer_internal ); free( pdata ); } + + producer->close = NULL; + mlt_producer_close( producer ); + free( producer ); } From 5be23204a9dd579012b46e5285815382b27018d5 Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov Date: Fri, 30 Jun 2023 13:51:39 +0300 Subject: [PATCH 10/16] Fix two memory leaks in MLT library --- src/framework/mlt_repository.c | 14 ++++++++------ src/mlt++/MltPushConsumer.cpp | 4 +++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/framework/mlt_repository.c b/src/framework/mlt_repository.c index caedf2139..e81716fe4 100644 --- a/src/framework/mlt_repository.c +++ b/src/framework/mlt_repository.c @@ -336,12 +336,14 @@ void *mlt_repository_create(mlt_repository self, void mlt_repository_close(mlt_repository self) { - mlt_properties_close(self->consumers); - mlt_properties_close(self->filters); - mlt_properties_close(self->producers); - mlt_properties_close(self->transitions); - mlt_properties_close(&self->parent); - free(self); + mlt_properties_close( self->consumers ); + mlt_properties_close( self->filters ); + mlt_properties_close( self->links ); + mlt_properties_close( self->producers ); + mlt_properties_close( self->transitions ); + mlt_properties_close( &self->parent ); + + free( self ); } /** Get the list of registered consumers. diff --git a/src/mlt++/MltPushConsumer.cpp b/src/mlt++/MltPushConsumer.cpp index 464877c2d..4ce70fffa 100644 --- a/src/mlt++/MltPushConsumer.cpp +++ b/src/mlt++/MltPushConsumer.cpp @@ -67,7 +67,9 @@ PushConsumer::PushConsumer(Profile &profile, const char *id, const char *service } } -PushConsumer::~PushConsumer() {} +PushConsumer::~PushConsumer() { + delete m_private; +} void PushConsumer::set_render(int width, int height, double aspect_ratio) { From 238f40a8f4281614b8adcd71341fe8a522e91003 Mon Sep 17 00:00:00 2001 From: Emmet O'Neill Date: Wed, 29 Nov 2023 16:15:29 -0800 Subject: [PATCH 11/16] Ran clang-format on appropriate files. --- src/framework/mlt_repository.c | 1 - src/modules/krita/factory.c | 22 +- src/modules/krita/producer_krita.c | 315 +++++++++++++++-------------- 3 files changed, 175 insertions(+), 163 deletions(-) diff --git a/src/framework/mlt_repository.c b/src/framework/mlt_repository.c index e81716fe4..2b7276417 100644 --- a/src/framework/mlt_repository.c +++ b/src/framework/mlt_repository.c @@ -342,7 +342,6 @@ void mlt_repository_close(mlt_repository self) mlt_properties_close( self->producers ); mlt_properties_close( self->transitions ); mlt_properties_close( &self->parent ); - free( self ); } diff --git a/src/modules/krita/factory.c b/src/modules/krita/factory.c index 1fef3e67b..ed80c5fbd 100644 --- a/src/modules/krita/factory.c +++ b/src/modules/krita/factory.c @@ -18,22 +18,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include #include +#include +#include -extern mlt_producer producer_krita_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); - +extern mlt_producer producer_krita_init(mlt_profile profile, + mlt_service_type type, + const char *id, + char *arg); -static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) +static mlt_properties metadata(mlt_service_type type, const char *id, void *data) { - char file[ PATH_MAX ]; - snprintf( file, PATH_MAX, "%s/krita/%s", mlt_environment( "MLT_DATA" ), (char*) data ); - return mlt_properties_parse_yaml( file ); + char file[PATH_MAX]; + snprintf(file, PATH_MAX, "%s/krita/%s", mlt_environment("MLT_DATA"), (char *) data); + return mlt_properties_parse_yaml(file); } MLT_REPOSITORY { - MLT_REGISTER( mlt_service_producer_type, "krita", producer_krita_init ); - MLT_REGISTER_METADATA( mlt_service_producer_type, "krita", metadata, "producer_krita.yml" ); + MLT_REGISTER(mlt_service_producer_type, "krita", producer_krita_init); + MLT_REGISTER_METADATA(mlt_service_producer_type, "krita", metadata, "producer_krita.yml"); } diff --git a/src/modules/krita/producer_krita.c b/src/modules/krita/producer_krita.c index 92c470aed..cde682f50 100644 --- a/src/modules/krita/producer_krita.c +++ b/src/modules/krita/producer_krita.c @@ -19,206 +19,217 @@ */ #include +#include #include +#include #include #include #include -#include -#include +#include #include #include -#include -#include #include - - +#include typedef struct { - int frame_start; - int frame_end; - int limit_enabled; - double speed; - mlt_producer producer_internal; + int frame_start; + int frame_end; + int limit_enabled; + double speed; + mlt_producer producer_internal; } private_data; - -static int restrict_range( int input, int min, int max ) { - const int span = max - min; - return (MAX(input - min, 0) % (span + 1)) + min; +static int restrict_range(int input, int min, int max) +{ + const int span = max - min; + return (MAX(input - min, 0) % (span + 1)) + min; } - -int is_valid_range( const private_data* pdata ) { - return pdata->frame_start > -1 && pdata->frame_end > -1 && pdata->frame_end > pdata->frame_start; +int is_valid_range(const private_data *pdata) +{ + return pdata->frame_start > -1 && pdata->frame_end > -1 + && pdata->frame_end > pdata->frame_start; } -int is_limit_enabled( const private_data* pdata) { - return pdata->limit_enabled != 0; +int is_limit_enabled(const private_data *pdata) +{ + return pdata->limit_enabled != 0; } -static int producer_get_audio( mlt_frame frame, void** buffer, mlt_audio_format* format, int* frequency, int* channels, int* samples ) +static int producer_get_audio(mlt_frame frame, + void **buffer, + mlt_audio_format *format, + int *frequency, + int *channels, + int *samples) { - mlt_producer producer = mlt_frame_pop_audio( frame ); - private_data* pdata = (private_data*)producer->child; - struct mlt_audio_s audio; - mlt_audio_set_values( &audio, *buffer, *frequency, *format, *samples, *channels ); + mlt_producer producer = mlt_frame_pop_audio(frame); + private_data *pdata = (private_data *) producer->child; + struct mlt_audio_s audio; + mlt_audio_set_values(&audio, *buffer, *frequency, *format, *samples, *channels); - int error = mlt_frame_get_audio( frame, &audio.data, &audio.format, &audio.frequency, &audio.channels, &audio.samples ); + int error = mlt_frame_get_audio(frame, + &audio.data, + &audio.format, + &audio.frequency, + &audio.channels, + &audio.samples); - // Scale the frequency to account for the speed change. - audio.frequency = (double)audio.frequency * fabs(pdata->speed); + // Scale the frequency to account for the speed change. + audio.frequency = (double) audio.frequency * fabs(pdata->speed); - if( pdata->speed < 0.0 ) - { - mlt_audio_reverse( &audio ); - } + if (pdata->speed < 0.0) { + mlt_audio_reverse(&audio); + } - mlt_audio_get_values( &audio, buffer, frequency, format, samples, channels ); + mlt_audio_get_values(&audio, buffer, frequency, format, samples, channels); - return error; + return error; } -static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) +static int producer_get_frame(mlt_producer producer, mlt_frame_ptr frame, int index) { - private_data* pdata = (private_data*)producer->child; + private_data *pdata = (private_data *) producer->child; - const int position = mlt_producer_position(pdata->producer_internal); - if (is_valid_range(pdata) && is_limit_enabled(pdata)) { - mlt_properties_set_position(MLT_PRODUCER_PROPERTIES(pdata->producer_internal), "_position", restrict_range(position, pdata->frame_start, pdata->frame_end)); - } + const int position = mlt_producer_position(pdata->producer_internal); + if (is_valid_range(pdata) && is_limit_enabled(pdata)) { + mlt_properties_set_position(MLT_PRODUCER_PROPERTIES(pdata->producer_internal), + "_position", + restrict_range(position, pdata->frame_start, pdata->frame_end)); + } - int r = mlt_service_get_frame((mlt_service)pdata->producer_internal, frame, index); + int r = mlt_service_get_frame((mlt_service) pdata->producer_internal, frame, index); - if ( !mlt_frame_is_test_audio( *frame ) ) - { - mlt_frame_push_audio( *frame, producer ); - mlt_frame_push_audio( *frame, producer_get_audio ); - } + if (!mlt_frame_is_test_audio(*frame)) { + mlt_frame_push_audio(*frame, producer); + mlt_frame_push_audio(*frame, producer_get_audio); + } - return r; + return r; } -static int producer_seek( mlt_producer producer, mlt_position position) +static int producer_seek(mlt_producer producer, mlt_position position) { - private_data* pdata = (private_data*)producer->child; + private_data *pdata = (private_data *) producer->child; - int r = mlt_producer_seek(pdata->producer_internal, position); + int r = mlt_producer_seek(pdata->producer_internal, position); - return r; + return r; } -static void producer_property_changed( mlt_service owner, mlt_producer self, mlt_event_data event_data) +static void producer_property_changed(mlt_service owner, + mlt_producer self, + mlt_event_data event_data) { - const char *name = mlt_event_data_to_string(event_data); - if (!name) return; - - if (strcmp(name, "start_frame") || strcmp( name, "end_frame" )){ - private_data* pdata = (private_data*)self->child; - mlt_properties props = MLT_PRODUCER_PROPERTIES(self); - pdata->frame_start = mlt_properties_get_int(props, "start_frame"); - pdata->frame_end = mlt_properties_get_int(props, "end_frame"); - } - - // TODO: Find out why this strcmp doesn't work... - //if (strcmp(name, "limit_enabled")) { - private_data* pdata = (private_data*)self->child; - mlt_properties props = MLT_PRODUCER_PROPERTIES(self); - pdata->limit_enabled = mlt_properties_get_int(props, "limit_enabled"); - //} - - if (strcmp(name, "speed")) { - mlt_properties props = MLT_PRODUCER_PROPERTIES(self); - pdata->speed = mlt_properties_get_double(props, "speed"); - } - - if (strcmp(name, "_profile")) { - private_data* pdata = (private_data*)self->child; - mlt_service_set_profile((mlt_service)pdata->producer_internal, mlt_service_profile((mlt_service)self)); - } + const char *name = mlt_event_data_to_string(event_data); + if (!name) + return; + + if (strcmp(name, "start_frame") || strcmp(name, "end_frame")) { + private_data *pdata = (private_data *) self->child; + mlt_properties props = MLT_PRODUCER_PROPERTIES(self); + pdata->frame_start = mlt_properties_get_int(props, "start_frame"); + pdata->frame_end = mlt_properties_get_int(props, "end_frame"); + } + + // TODO: Find out why this strcmp doesn't work... + //if (strcmp(name, "limit_enabled")) { + private_data *pdata = (private_data *) self->child; + mlt_properties props = MLT_PRODUCER_PROPERTIES(self); + pdata->limit_enabled = mlt_properties_get_int(props, "limit_enabled"); + //} + + if (strcmp(name, "speed")) { + mlt_properties props = MLT_PRODUCER_PROPERTIES(self); + pdata->speed = mlt_properties_get_double(props, "speed"); + } + + if (strcmp(name, "_profile")) { + private_data *pdata = (private_data *) self->child; + mlt_service_set_profile((mlt_service) pdata->producer_internal, + mlt_service_profile((mlt_service) self)); + } } - -static void producer_close( mlt_producer producer ) +static void producer_close(mlt_producer producer) { - private_data* pdata = (private_data*)producer->child; + private_data *pdata = (private_data *) producer->child; - if ( pdata ) - { - mlt_producer_close( pdata->producer_internal ); - free( pdata ); - } + if (pdata) { + mlt_producer_close(pdata->producer_internal); + free(pdata); + } - producer->close = NULL; - mlt_producer_close( producer ); - free( producer ); + producer->close = NULL; + mlt_producer_close(producer); + free(producer); } - /** Constructor for the producer. */ -mlt_producer producer_krita_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +mlt_producer producer_krita_init(mlt_profile profile, + mlt_service_type type, + const char *id, + char *arg) { - // Create a new producer object - mlt_producer producer = mlt_producer_new( profile ); - private_data* pdata = (private_data*)calloc( 1, sizeof(private_data) ); - - if ( arg && producer && pdata ) - { - mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); - - // Initialize the producer - mlt_properties_set( producer_properties, "resource", arg ); - producer->child = pdata; - producer->get_frame = producer_get_frame; - producer->seek = producer_seek; - producer->close = (mlt_destructor)producer_close; - - // Get the resource to be passed to the clip producer - char* resource = arg; - - // Default frame start / end props. - pdata->frame_start = -1; - pdata->frame_end = -1; - pdata->limit_enabled = 1; - pdata->speed = 1.0; - - // Initialize property values for start / end frames. - mlt_properties_set_int(producer_properties, "start_frame", pdata->frame_start); - mlt_properties_set_int(producer_properties, "end_frame", pdata->frame_end); - mlt_properties_set_int(producer_properties, "limit_enabled", pdata->limit_enabled); - mlt_properties_set_double(producer_properties, "speed", pdata->speed); - - // Create a producer for the clip using the false profile. - pdata->producer_internal = mlt_factory_producer( profile, "abnormal", resource); - - if (pdata->producer_internal) { - mlt_producer_set_speed(pdata->producer_internal, 1.0); - } - - mlt_events_listen( producer_properties, producer, "property-changed", ( mlt_listener )producer_property_changed ); - } - - if ( !producer || !pdata || !pdata->producer_internal ) - { - if ( pdata ) - { - mlt_producer_close( pdata->producer_internal ); - free( pdata ); - } - - if ( producer ) - { - producer->child = NULL; - producer->close = NULL; - mlt_producer_close( producer ); - free( producer ); - producer = NULL; - } - } - - return producer; + // Create a new producer object + mlt_producer producer = mlt_producer_new(profile); + private_data *pdata = (private_data *) calloc(1, sizeof(private_data)); + + if (arg && producer && pdata) { + mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES(producer); + + // Initialize the producer + mlt_properties_set(producer_properties, "resource", arg); + producer->child = pdata; + producer->get_frame = producer_get_frame; + producer->seek = producer_seek; + producer->close = (mlt_destructor) producer_close; + + // Get the resource to be passed to the clip producer + char *resource = arg; + + // Default frame start / end props. + pdata->frame_start = -1; + pdata->frame_end = -1; + pdata->limit_enabled = 1; + pdata->speed = 1.0; + + // Initialize property values for start / end frames. + mlt_properties_set_int(producer_properties, "start_frame", pdata->frame_start); + mlt_properties_set_int(producer_properties, "end_frame", pdata->frame_end); + mlt_properties_set_int(producer_properties, "limit_enabled", pdata->limit_enabled); + mlt_properties_set_double(producer_properties, "speed", pdata->speed); + + // Create a producer for the clip using the false profile. + pdata->producer_internal = mlt_factory_producer(profile, "abnormal", resource); + + if (pdata->producer_internal) { + mlt_producer_set_speed(pdata->producer_internal, 1.0); + } + + mlt_events_listen(producer_properties, + producer, + "property-changed", + (mlt_listener) producer_property_changed); + } + + if (!producer || !pdata || !pdata->producer_internal) { + if (pdata) { + mlt_producer_close(pdata->producer_internal); + free(pdata); + } + + if (producer) { + producer->child = NULL; + producer->close = NULL; + mlt_producer_close(producer); + free(producer); + producer = NULL; + } + } + + return producer; } - - From cb16673644f9feff497e8e185562081f31427a54 Mon Sep 17 00:00:00 2001 From: Emmet O'Neill Date: Wed, 29 Nov 2023 16:16:48 -0800 Subject: [PATCH 12/16] Fixup incorrect info in producer_krita.c file header. --- src/modules/krita/producer_krita.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/krita/producer_krita.c b/src/modules/krita/producer_krita.c index cde682f50..4effe0712 100644 --- a/src/modules/krita/producer_krita.c +++ b/src/modules/krita/producer_krita.c @@ -1,5 +1,5 @@ /* - * filter_freeze.c -- simple frame freezing filter + * producer_krita.c -- Produces variable-speed audio within a restricted range of frames. Used internally by Krita to drive audio-synced animation playback. * Copyright (C) 2022 Eoin O'Neill * Copyright (C) 2022 Emmet O'Neill * From 1ece39e19afe58adc641250be340a506ebe4ebae Mon Sep 17 00:00:00 2001 From: Emmet O'Neill Date: Thu, 30 Nov 2023 15:25:15 -0800 Subject: [PATCH 13/16] Improved producer_krita.yml manifest information. --- src/modules/krita/producer_krita.yml | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/modules/krita/producer_krita.yml b/src/modules/krita/producer_krita.yml index ef6e79ff4..2d8dc4213 100644 --- a/src/modules/krita/producer_krita.yml +++ b/src/modules/krita/producer_krita.yml @@ -7,27 +7,47 @@ copyright: Eoin O'Neill, Emmet O'Neill creator: Eoin O'Neill, Emmet O'Neill license: LGPLv2.1 language: en +description: Produces variable-speed audio within a restricted range of frames. Used internally by Krita to drive audio-synced animation playback. tags: - Video - Audio parameters: + - identifier: resource + title: Audio File Resource + type: string + argument: yes + description: | + The producer resource, which can be a file name or any producer service name. + The resource will be passed to the loader to create the encapsulated + producer. + readonly: no + required: yes + mutable: no + - identifier: frame_start title: Start Frame type: integer - description: First frame of the acceptable playback range. + description: First frame of the restricted playback range. default: 0 mutable: true - identifier: frame_end title: End Frame type: integer - description: Last frame of the acceptable playback range. - default: 100 + description: Last frame of the restricted playback range. + default: 120 mutable: true - identifier: limit_enabled title: Limit Enabled type: integer - description: Whether the frame limiting feature should be enabled. + description: Whether the frame range should be restricted to the specified start/end limits. default: 0 mutable: true + + - identifier: speed + title: Playback Speed + type: double + description: Normalized playback speed. + default: 1.0 + mutable: true From bc24505366df2b28211415688426b3694d25b07b Mon Sep 17 00:00:00 2001 From: Emmet O'Neill Date: Thu, 30 Nov 2023 15:26:45 -0800 Subject: [PATCH 14/16] Fixed bad strcmps and cleaned up property_changed func. --- src/modules/krita/producer_krita.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/modules/krita/producer_krita.c b/src/modules/krita/producer_krita.c index 4effe0712..1262b94be 100644 --- a/src/modules/krita/producer_krita.c +++ b/src/modules/krita/producer_krita.c @@ -127,27 +127,23 @@ static void producer_property_changed(mlt_service owner, if (!name) return; - if (strcmp(name, "start_frame") || strcmp(name, "end_frame")) { - private_data *pdata = (private_data *) self->child; - mlt_properties props = MLT_PRODUCER_PROPERTIES(self); + private_data *pdata = (private_data *) self->child; + mlt_properties props = MLT_PRODUCER_PROPERTIES(self); + + if (!strcmp(name, "start_frame") || !strcmp(name, "end_frame")) { pdata->frame_start = mlt_properties_get_int(props, "start_frame"); pdata->frame_end = mlt_properties_get_int(props, "end_frame"); } - // TODO: Find out why this strcmp doesn't work... - //if (strcmp(name, "limit_enabled")) { - private_data *pdata = (private_data *) self->child; - mlt_properties props = MLT_PRODUCER_PROPERTIES(self); - pdata->limit_enabled = mlt_properties_get_int(props, "limit_enabled"); - //} + if (!strcmp(name, "limit_enabled")) { + pdata->limit_enabled = mlt_properties_get_int(props, "limit_enabled"); + } - if (strcmp(name, "speed")) { - mlt_properties props = MLT_PRODUCER_PROPERTIES(self); + if (!strcmp(name, "speed")) { pdata->speed = mlt_properties_get_double(props, "speed"); } - if (strcmp(name, "_profile")) { - private_data *pdata = (private_data *) self->child; + if (!strcmp(name, "_profile")) { mlt_service_set_profile((mlt_service) pdata->producer_internal, mlt_service_profile((mlt_service) self)); } From 4bbdcfab6bdfc4e52fc1959912a1266820118cca Mon Sep 17 00:00:00 2001 From: Emmet O'Neill Date: Mon, 4 Dec 2023 12:55:55 -0800 Subject: [PATCH 15/16] Cleanup: Stripped out a bunch of unneeded stuff. Got some good feedback from mlt crew. Otherwise just cleaned up some messy old plugin code. --- src/modules/krita/producer_krita.c | 102 +++++++++-------------------- 1 file changed, 30 insertions(+), 72 deletions(-) diff --git a/src/modules/krita/producer_krita.c b/src/modules/krita/producer_krita.c index 1262b94be..9a0469918 100644 --- a/src/modules/krita/producer_krita.c +++ b/src/modules/krita/producer_krita.c @@ -34,28 +34,23 @@ typedef struct { - int frame_start; - int frame_end; - int limit_enabled; - double speed; mlt_producer producer_internal; } private_data; -static int restrict_range(int input, int min, int max) +/** Restricts frame index to within range by modulus wrapping (not clamping). +*/ +static int restrict_range(int index, int min, int max) { const int span = max - min; - return (MAX(input - min, 0) % (span + 1)) + min; + return (MAX(index - min, 0) % (span + 1)) + min; } -int is_valid_range(const private_data *pdata) +static int is_valid_range(const int frame_start, const int frame_end) { - return pdata->frame_start > -1 && pdata->frame_end > -1 - && pdata->frame_end > pdata->frame_start; -} + const bool NON_NEGATIVE = frame_start >= 0 && frame_end >= 0; + const bool NON_INVERTED = frame_end > frame_start; -int is_limit_enabled(const private_data *pdata) -{ - return pdata->limit_enabled != 0; + return NON_NEGATIVE && NON_INVERTED; } static int producer_get_audio(mlt_frame frame, @@ -66,8 +61,9 @@ static int producer_get_audio(mlt_frame frame, int *samples) { mlt_producer producer = mlt_frame_pop_audio(frame); - private_data *pdata = (private_data *) producer->child; + struct mlt_audio_s audio; + mlt_audio_set_values(&audio, *buffer, *frequency, *format, *samples, *channels); int error = mlt_frame_get_audio(frame, @@ -77,10 +73,13 @@ static int producer_get_audio(mlt_frame frame, &audio.channels, &audio.samples); - // Scale the frequency to account for the speed change. - audio.frequency = (double) audio.frequency * fabs(pdata->speed); + mlt_properties props = MLT_PRODUCER_PROPERTIES(producer); - if (pdata->speed < 0.0) { + // Scale the frequency to account for the dynamic speed (normalized). + const double SPEED = mlt_properties_get_double(props, "speed"); + + audio.frequency = (double) audio.frequency * fabs(SPEED); + if (SPEED < 0.0) { mlt_audio_reverse(&audio); } @@ -91,62 +90,37 @@ static int producer_get_audio(mlt_frame frame, static int producer_get_frame(mlt_producer producer, mlt_frame_ptr frame, int index) { + mlt_properties props = MLT_PRODUCER_PROPERTIES(producer); + const int FRAME_START = mlt_properties_get_int(props, "start_frame"); + const int FRAME_END = mlt_properties_get_int(props, "end_frame"); + const bool IS_RANGE_LIMITED = mlt_properties_get_int(props, "limit_enabled"); + private_data *pdata = (private_data *) producer->child; + const int POSITION = mlt_producer_position(pdata->producer_internal); - const int position = mlt_producer_position(pdata->producer_internal); - if (is_valid_range(pdata) && is_limit_enabled(pdata)) { + if (IS_RANGE_LIMITED && is_valid_range(FRAME_START, FRAME_END)) { mlt_properties_set_position(MLT_PRODUCER_PROPERTIES(pdata->producer_internal), "_position", - restrict_range(position, pdata->frame_start, pdata->frame_end)); + restrict_range(POSITION, FRAME_START, FRAME_END)); } - int r = mlt_service_get_frame((mlt_service) pdata->producer_internal, frame, index); + int retval = mlt_service_get_frame((mlt_service) pdata->producer_internal, frame, index); if (!mlt_frame_is_test_audio(*frame)) { mlt_frame_push_audio(*frame, producer); mlt_frame_push_audio(*frame, producer_get_audio); } - return r; + return retval; } static int producer_seek(mlt_producer producer, mlt_position position) { private_data *pdata = (private_data *) producer->child; - int r = mlt_producer_seek(pdata->producer_internal, position); + int retval = mlt_producer_seek(pdata->producer_internal, position); - return r; -} - -static void producer_property_changed(mlt_service owner, - mlt_producer self, - mlt_event_data event_data) -{ - const char *name = mlt_event_data_to_string(event_data); - if (!name) - return; - - private_data *pdata = (private_data *) self->child; - mlt_properties props = MLT_PRODUCER_PROPERTIES(self); - - if (!strcmp(name, "start_frame") || !strcmp(name, "end_frame")) { - pdata->frame_start = mlt_properties_get_int(props, "start_frame"); - pdata->frame_end = mlt_properties_get_int(props, "end_frame"); - } - - if (!strcmp(name, "limit_enabled")) { - pdata->limit_enabled = mlt_properties_get_int(props, "limit_enabled"); - } - - if (!strcmp(name, "speed")) { - pdata->speed = mlt_properties_get_double(props, "speed"); - } - - if (!strcmp(name, "_profile")) { - mlt_service_set_profile((mlt_service) pdata->producer_internal, - mlt_service_profile((mlt_service) self)); - } + return retval; } static void producer_close(mlt_producer producer) @@ -187,32 +161,16 @@ mlt_producer producer_krita_init(mlt_profile profile, // Get the resource to be passed to the clip producer char *resource = arg; - // Default frame start / end props. - pdata->frame_start = -1; - pdata->frame_end = -1; - pdata->limit_enabled = 1; - pdata->speed = 1.0; - - // Initialize property values for start / end frames. - mlt_properties_set_int(producer_properties, "start_frame", pdata->frame_start); - mlt_properties_set_int(producer_properties, "end_frame", pdata->frame_end); - mlt_properties_set_int(producer_properties, "limit_enabled", pdata->limit_enabled); - mlt_properties_set_double(producer_properties, "speed", pdata->speed); - // Create a producer for the clip using the false profile. pdata->producer_internal = mlt_factory_producer(profile, "abnormal", resource); if (pdata->producer_internal) { mlt_producer_set_speed(pdata->producer_internal, 1.0); } - - mlt_events_listen(producer_properties, - producer, - "property-changed", - (mlt_listener) producer_property_changed); } - if (!producer || !pdata || !pdata->producer_internal) { + const bool INVALID_CONTEXT = !producer || !pdata || !pdata->producer_internal; + if (INVALID_CONTEXT) { // Clean up early... if (pdata) { mlt_producer_close(pdata->producer_internal); free(pdata); From e3b0de9c5f57fc9fbad38a57c6b44e96a6b78e86 Mon Sep 17 00:00:00 2001 From: Emmet O'Neill Date: Tue, 5 Dec 2023 21:05:35 -0800 Subject: [PATCH 16/16] Removed incorrect information from comment. --- src/modules/krita/producer_krita.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/krita/producer_krita.c b/src/modules/krita/producer_krita.c index 9a0469918..4bfbef15b 100644 --- a/src/modules/krita/producer_krita.c +++ b/src/modules/krita/producer_krita.c @@ -161,7 +161,7 @@ mlt_producer producer_krita_init(mlt_profile profile, // Get the resource to be passed to the clip producer char *resource = arg; - // Create a producer for the clip using the false profile. + // Create internal producer pdata->producer_internal = mlt_factory_producer(profile, "abnormal", resource); if (pdata->producer_internal) {