From 6005571e839b74e9019f8f43b4ef4ff76f793780 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 1 Jan 2014 18:14:18 +0100 Subject: [PATCH] Change how the Movit chain is built. * Build the chain in GlslManager. This allows us to get rid of effects that don't actually do anything (like all the normalizers in the common case); in Movit, they tend to burn a lot of memory bandwidth. We solve this by a new OptionalEffect template, that can rewrite itself out of the graph if it sees it is a no-op. We need to recreate the chain from scratch if this status should change (e.g. the input resolution changed from one frame to the next, and we thus suddenly need resizing after all), so we keep a "fingerprint" string that contains all the unique IDs of the services in use, as well as their disabled status, and compare against this frame. Building the chain in one piece also opens up for transitions to be more efficient; they are now built as part of one big Movit chain, instead of bouncing to an 8-bit sRGB buffer and back. * Change the mlt_glsl type. Now, the mlt_glsl image type has a defined value, which is the mlt_service pointer. Each filter is responsible for storing this input service. This, together with the mlt_frame, enables us to actually build the Movit chain based on the MLT relations, instead of just relying in the order in which they are called and assuming everything has a single input. As a special case, the value (mlt_service) -1 (which should never be a valid pointer) means that we read the information from an input rather than an effect. In this case, we take a copy of the pixel data we get in (since it will soon be garbage collected), store it in an MltInput and then store that MltInput for later use. This could probably be further simplified in the future to get completely rid of MltInput and just use the regular FlatInput/YCbCrInput instead. This also requires us to change so that the chain is built and finalized at the _end_ of the conversion steps (where it's logically needed), instead of at the beginning as before. The beginning (conversion from * -> mlt_glsl) now only stores the input as described below. * Change Effect and EffectChain storage. This changes the storage of Movit stuff as follows: - The EffectChain (along with some associated information to be able to more easily locate the services and Effect pointers; together, called a GlslChain) is now stored on the output service, not on the input producer. This allows us to have multiple EffectChains floating around. - The Effect pointers no longer live permanently on the MLT graph, since each MLT service can have more than one Effect. Instead, they live temporarily on the frame (because the frame is not shared between threads, giving us a poor man's version of thread-local storage), until they reach the point where we decide if we need to rebuild the EffectChain or not. At this point, they are either made part of the chain (and owned by it), or disposed as unneeded. - The MltInput also lives on the frame. (If we have multiple inputs, we also have multiple frames.) As mentioned above, its use is signaled by an mlt_service of -1. * Change how Movit parameter setting works. Services no longer set parameters directly on the Movit filters, since they cannot know before the graph construction time whether the correct destination is the newly created Effect, or a similar one in the EffectChain. Instead, they set special properties (movit.parms..[]), and then the convert filter uses these to set Movit parameters on the right Effects. --- src/modules/opengl/filter_glsl_manager.cpp | 134 +++--- src/modules/opengl/filter_glsl_manager.h | 44 +- src/modules/opengl/filter_movit_blur.cpp | 26 +- src/modules/opengl/filter_movit_convert.cpp | 444 ++++++++++++++---- src/modules/opengl/filter_movit_crop.cpp | 34 +- .../filter_movit_deconvolution_sharpen.cpp | 38 +- src/modules/opengl/filter_movit_diffusion.cpp | 26 +- src/modules/opengl/filter_movit_glow.cpp | 30 +- .../opengl/filter_movit_lift_gamma_gain.cpp | 50 +- src/modules/opengl/filter_movit_mirror.cpp | 18 +- src/modules/opengl/filter_movit_opacity.cpp | 33 +- src/modules/opengl/filter_movit_resample.cpp | 40 +- src/modules/opengl/filter_movit_resize.cpp | 25 +- .../opengl/filter_movit_saturation.cpp | 22 +- src/modules/opengl/filter_movit_vignette.cpp | 26 +- .../opengl/filter_movit_white_balance.cpp | 40 +- src/modules/opengl/mlt_movit_input.cpp | 13 +- src/modules/opengl/mlt_movit_input.h | 6 +- src/modules/opengl/optional_effect.h | 29 ++ src/modules/opengl/transition_movit_mix.cpp | 94 +--- .../opengl/transition_movit_overlay.cpp | 77 +-- 21 files changed, 703 insertions(+), 546 deletions(-) create mode 100644 src/modules/opengl/optional_effect.h diff --git a/src/modules/opengl/filter_glsl_manager.cpp b/src/modules/opengl/filter_glsl_manager.cpp index 9cb0855c..d941f8e9 100644 --- a/src/modules/opengl/filter_glsl_manager.cpp +++ b/src/modules/opengl/filter_glsl_manager.cpp @@ -290,9 +290,6 @@ void GlslManager::onServiceChanged( mlt_properties owner, mlt_service aservice ) Mlt::Service service( aservice ); service.lock(); service.set( "movit chain", NULL, 0 ); - service.set( "movit input", NULL, 0 ); - // Destroy the effect list. - GlslManager::get_instance()->set( service.get( "_unique_id" ), NULL, 0 ); service.unlock(); } @@ -316,102 +313,95 @@ mlt_filter filter_glsl_manager_init( mlt_profile profile, mlt_service_type type, } // extern "C" -Mlt::Properties GlslManager::effect_list( Mlt::Service& service ) +static void deleteChain( GlslChain* chain ) { - char *unique_id = service.get( "_unique_id" ); - mlt_properties properties = (mlt_properties) get_data( unique_id ); - if ( !properties ) { - properties = mlt_properties_new(); - set( unique_id, properties, 0, (mlt_destructor) mlt_properties_close ); - } - Mlt::Properties p( properties ); - return p; + delete chain->effect_chain; + delete chain; +} + +void* GlslManager::get_frame_specific_data( mlt_service service, mlt_frame frame, const char *key, int *length ) +{ + const char *unique_id = mlt_properties_get( MLT_SERVICE_PROPERTIES(service), "_unique_id" ); + char buf[256]; + snprintf( buf, sizeof(buf), "%s_%s", key, unique_id ); + return mlt_properties_get_data( MLT_FRAME_PROPERTIES(frame), buf, length ); } -static void deleteChain( EffectChain* chain ) +int GlslManager::set_frame_specific_data( mlt_service service, mlt_frame frame, const char *key, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise ) { - delete chain; + const char *unique_id = mlt_properties_get( MLT_SERVICE_PROPERTIES(service), "_unique_id" ); + char buf[256]; + snprintf( buf, sizeof(buf), "%s_%s", key, unique_id ); + return mlt_properties_set_data( MLT_FRAME_PROPERTIES(frame), buf, value, length, destroy, serialise ); } -bool GlslManager::init_chain( mlt_service aservice ) +void GlslManager::set_chain( mlt_service service, GlslChain* chain ) { - bool error = true; - Mlt::Service service( aservice ); - EffectChain* chain = (EffectChain*) service.get_data( "movit chain" ); - if ( !chain ) { - mlt_profile profile = mlt_service_profile( aservice ); - Input* input = new MltInput( profile->width, profile->height ); - chain = new EffectChain( profile->display_aspect_num, profile->display_aspect_den ); - chain->add_input( input ); - service.set( "movit chain", chain, 0, (mlt_destructor) deleteChain ); - service.set( "movit input", input, 0 ); - service.set( "_movit finalized", 0 ); - service.listen( "service-changed", aservice, (mlt_listener) GlslManager::onServiceChanged ); - service.listen( "property-changed", aservice, (mlt_listener) GlslManager::onPropertyChanged ); - error = false; - } - return error; + mlt_properties_set_data( MLT_SERVICE_PROPERTIES(service), "_movit chain", chain, 0, (mlt_destructor) deleteChain, NULL ); } -EffectChain* GlslManager::get_chain( mlt_service service ) +GlslChain* GlslManager::get_chain( mlt_service service ) { - return (EffectChain*) mlt_properties_get_data( MLT_SERVICE_PROPERTIES(service), "movit chain", NULL ); + return (GlslChain*) mlt_properties_get_data( MLT_SERVICE_PROPERTIES(service), "_movit chain", NULL ); +} + +Effect* GlslManager::get_effect( mlt_service service, mlt_frame frame ) +{ + return (Effect*) get_frame_specific_data( service, frame, "_movit effect", NULL ); } -MltInput *GlslManager::get_input( mlt_service service ) +Effect* GlslManager::set_effect( mlt_service service, mlt_frame frame, Effect* effect ) { - return (MltInput*) mlt_properties_get_data( MLT_SERVICE_PROPERTIES(service), "movit input", NULL ); + set_frame_specific_data( service, frame, "_movit effect", effect, 0, NULL, NULL ); + return effect; } -void GlslManager::reset_finalized( mlt_service service ) +MltInput* GlslManager::get_input( mlt_producer producer, mlt_frame frame ) { - mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_movit finalized", 0 ); + return (MltInput*) get_frame_specific_data( MLT_PRODUCER_SERVICE(producer), frame, "_movit input", NULL ); } -Effect* GlslManager::get_effect( mlt_service service, mlt_frame frame ) +MltInput* GlslManager::set_input( mlt_producer producer, mlt_frame frame, MltInput* input ) { - Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); - char *unique_id = mlt_properties_get( MLT_SERVICE_PROPERTIES(service), "_unique_id" ); - return (Effect*) GlslManager::get_instance()->effect_list( producer ).get_data( unique_id ); + set_frame_specific_data( MLT_PRODUCER_SERVICE(producer), frame, "_movit input", input, 0, NULL, NULL ); + return input; } -Effect* GlslManager::add_effect( mlt_service service, mlt_frame frame, Effect* effect ) +uint8_t* GlslManager::get_input_pixel_pointer( mlt_producer producer, mlt_frame frame ) { - Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); - EffectChain* chain = (EffectChain*) producer.get_data( "movit chain" ); - chain->add_effect( effect ); - char *unique_id = mlt_properties_get( MLT_SERVICE_PROPERTIES(service), "_unique_id" ); - GlslManager::get_instance()->effect_list( producer ).set( unique_id, effect, 0 ); - return effect; + return (uint8_t*) get_frame_specific_data( MLT_PRODUCER_SERVICE(producer), frame, "_movit input pp", NULL ); } -Effect* GlslManager::add_effect( mlt_service service, mlt_frame frame, Effect* effect, Effect* input_b ) +uint8_t* GlslManager::set_input_pixel_pointer( mlt_producer producer, mlt_frame frame, uint8_t* image ) { - Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); - EffectChain* chain = (EffectChain*) producer.get_data( "movit chain" ); - chain->add_effect( effect, chain->last_added_effect(), - input_b? input_b : chain->last_added_effect() ); - char *unique_id = mlt_properties_get( MLT_SERVICE_PROPERTIES(service), "_unique_id" ); - GlslManager::get_instance()->effect_list( producer ).set( unique_id, effect, 0 ); - return effect; + set_frame_specific_data( MLT_PRODUCER_SERVICE(producer), frame, "_movit input pp", image, 0, NULL, NULL ); + return image; } -void GlslManager::render_fbo( mlt_service service, void* chain, GLuint fbo, int width, int height ) +mlt_service GlslManager::get_effect_input( mlt_service service, mlt_frame frame ) { - EffectChain* effect_chain = (EffectChain*) chain; - mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); - if ( !mlt_properties_get_int( properties, "_movit finalized" ) ) { - mlt_properties_set_int( properties, "_movit finalized", 1 ); - effect_chain->add_effect( new Mlt::VerticalFlip() ); - effect_chain->finalize(); - } - effect_chain->render_to_fbo( fbo, width, height ); + return (mlt_service) get_frame_specific_data( service, frame, "_movit effect input", NULL ); +} + +void GlslManager::set_effect_input( mlt_service service, mlt_frame frame, mlt_service input_service ) +{ + set_frame_specific_data( service, frame, "_movit effect input", input_service, 0, NULL, NULL ); +} + +void GlslManager::get_effect_secondary_input( mlt_service service, mlt_frame frame, mlt_service *input_service, mlt_frame *input_frame) +{ + *input_service = (mlt_service) get_frame_specific_data( service, frame, "_movit effect secondary input", NULL ); + *input_frame = (mlt_frame) get_frame_specific_data( service, frame, "_movit effect secondary input frame", NULL ); +} + +void GlslManager::set_effect_secondary_input( mlt_service service, mlt_frame frame, mlt_service input_service, mlt_frame input_frame ) +{ + set_frame_specific_data( service, frame, "_movit effect secondary input", input_service, 0, NULL, NULL ); + set_frame_specific_data( service, frame, "_movit effect secondary input frame", input_frame, 0, NULL, NULL ); } -int GlslManager::render_frame_texture(mlt_service service, mlt_frame frame, int width, int height, uint8_t **image) +int GlslManager::render_frame_texture(EffectChain *chain, mlt_frame frame, int width, int height, uint8_t **image) { - EffectChain* chain = get_chain( service ); - if (!chain) return 1; glsl_fbo fbo = get_fbo( width, height ); if (!fbo) return 1; glsl_texture texture = get_texture( width, height, GL_RGBA ); @@ -442,7 +432,7 @@ int GlslManager::render_frame_texture(mlt_service service, mlt_frame frame, int glClientWaitSync( prev_sync, 0, GL_TIMEOUT_IGNORED ); glDeleteSync( prev_sync ); } - render_fbo( service, chain, fbo->fbo, width, height ); + chain->render_to_fbo( fbo->fbo, width, height ); prev_sync = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); GLsync sync = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); @@ -461,10 +451,8 @@ int GlslManager::render_frame_texture(mlt_service service, mlt_frame frame, int return 0; } -int GlslManager::render_frame_rgba(mlt_service service, mlt_frame frame, int width, int height, uint8_t **image) +int GlslManager::render_frame_rgba(EffectChain *chain, mlt_frame frame, int width, int height, uint8_t **image) { - EffectChain* chain = get_chain( service ); - if (!chain) return 1; glsl_fbo fbo = get_fbo( width, height ); if (!fbo) return 1; glsl_texture texture = get_texture( width, height, GL_RGBA ); @@ -492,7 +480,7 @@ int GlslManager::render_frame_rgba(mlt_service service, mlt_frame frame, int wid glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); - render_fbo( service, chain, fbo->fbo, width, height ); + chain->render_to_fbo( fbo->fbo, width, height ); // Read FBO into PBO glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); diff --git a/src/modules/opengl/filter_glsl_manager.h b/src/modules/opengl/filter_glsl_manager.h index 4bc3836b..c850c86a 100644 --- a/src/modules/opengl/filter_glsl_manager.h +++ b/src/modules/opengl/filter_glsl_manager.h @@ -23,6 +23,8 @@ #include #include #include +#include +#include #define MAXLISTCOUNT 1024 typedef struct glsl_list_s *glsl_list; @@ -68,6 +70,19 @@ class Effect; class EffectChain; class MltInput; +struct GlslChain +{ + EffectChain *effect_chain; + + // All services owned by the effect chain and their associated Movit effect. + std::map effects; + + // For each effect in the Movit graph, a unique identifier for the service + // and whether it's disabled or not, using post-order traversal. + // We need to generate the chain if and only if this has changed. + std::string fingerprint; +}; + class GlslManager : public Mlt::Filter { public: @@ -83,21 +98,30 @@ public: glsl_pbo get_pbo(int size); void cleanupContext(); - Properties effect_list( Mlt::Service &service ); - static bool init_chain(mlt_service); - static EffectChain* get_chain(mlt_service); - static MltInput* get_input(mlt_service); - static void reset_finalized(mlt_service); + static void set_chain(mlt_service, GlslChain*); + static GlslChain* get_chain(mlt_service); + static Effect* get_effect(mlt_service, mlt_frame); - static Effect* add_effect(mlt_service, mlt_frame, Effect*); - static Effect* add_effect(mlt_service, mlt_frame, Effect*, Effect* input_b); - static void render_fbo(mlt_service, void *chain, GLuint fbo, int width, int height); - int render_frame_texture(mlt_service, mlt_frame, int width, int height, uint8_t **image); - int render_frame_rgba(mlt_service, mlt_frame, int width, int height, uint8_t **image); + static Effect* set_effect(mlt_service, mlt_frame, Effect*); + static MltInput* get_input(mlt_producer, mlt_frame); + static MltInput* set_input(mlt_producer, mlt_frame, MltInput*); + static uint8_t* get_input_pixel_pointer(mlt_producer, mlt_frame); + static uint8_t* set_input_pixel_pointer(mlt_producer, mlt_frame, uint8_t*); + + static mlt_service get_effect_input(mlt_service, mlt_frame); + static void set_effect_input(mlt_service, mlt_frame, mlt_service); + static void get_effect_secondary_input(mlt_service, mlt_frame, mlt_service*, mlt_frame*); + static void set_effect_secondary_input(mlt_service, mlt_frame, mlt_service, mlt_frame); + + int render_frame_texture(EffectChain*, mlt_frame, int width, int height, uint8_t **image); + int render_frame_rgba(EffectChain*, mlt_frame, int width, int height, uint8_t **image); static void lock_service(mlt_frame frame); static void unlock_service(mlt_frame frame); private: + static void* get_frame_specific_data( mlt_service service, mlt_frame frame, const char *key, int *length ); + static int set_frame_specific_data( mlt_service service, mlt_frame frame, const char *key, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise ); + static void onInit( mlt_properties owner, GlslManager* filter ); static void onClose( mlt_properties owner, GlslManager* filter ); static void onServiceChanged( mlt_properties owner, mlt_service service ); diff --git a/src/modules/opengl/filter_movit_blur.cpp b/src/modules/opengl/filter_movit_blur.cpp index 54ccd92f..79acaaae 100644 --- a/src/modules/opengl/filter_movit_blur.cpp +++ b/src/modules/opengl/filter_movit_blur.cpp @@ -29,28 +29,22 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - double radius = mlt_properties_anim_get_double( properties, "radius", - mlt_filter_get_position( filter, frame ), - mlt_filter_get_length2( filter, frame ) ); - bool ok = effect->set_float( "radius", radius ); - assert(ok); - } + double radius = mlt_properties_anim_get_double( properties, "radius", + mlt_filter_get_position( filter, frame ), + mlt_filter_get_length2( filter, frame ) ); + mlt_properties_set_double( properties, "movit.parms.float.radius", + radius ); GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; - return mlt_frame_get_image( frame, image, format, width, height, writable ); + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new BlurEffect ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( !effect ) { - effect = GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new BlurEffect() ); - assert(effect); - } - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_convert.cpp b/src/modules/opengl/filter_movit_convert.cpp index 2229aebc..3e61dffc 100644 --- a/src/modules/opengl/filter_movit_convert.cpp +++ b/src/modules/opengl/filter_movit_convert.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "filter_glsl_manager.h" #include @@ -103,6 +104,277 @@ static void get_format_from_properties( mlt_properties properties, ImageFormat* ycbcr_format->cb_y_position = ycbcr_format->cr_y_position = 0.5f; } +static void build_fingerprint( mlt_service service, mlt_frame frame, std::string *fingerprint ) +{ + if ( service == (mlt_service) -1 ) { + fingerprint->append( "input" ); + return; + } + + Effect* effect = GlslManager::get_effect( service, frame ); + assert( effect ); + mlt_service input_a = GlslManager::get_effect_input( service, frame ); + fingerprint->push_back( '(' ); + build_fingerprint( input_a, frame, fingerprint ); + fingerprint->push_back( ')' ); + + mlt_frame frame_b; + mlt_service input_b; + GlslManager::get_effect_secondary_input( service, frame, &input_b, &frame_b ); + if ( input_b ) { + fingerprint->push_back( '(' ); + build_fingerprint( input_b, frame_b, fingerprint ); + fingerprint->push_back( ')' ); + } + + fingerprint->push_back( '(' ); + fingerprint->append( mlt_properties_get( MLT_SERVICE_PROPERTIES( service ), "_unique_id" ) ); + bool disable = mlt_properties_get_int( MLT_SERVICE_PROPERTIES( service ), "movit.disable" ); + if ( disable ) { + fingerprint->push_back( 'd' ); + bool ok = effect->set_int( "disable", 1 ); + assert(ok); + } + fingerprint->push_back( ')' ); +} + +static Effect* build_movit_chain( mlt_service service, mlt_frame frame, GlslChain *chain ) +{ + if ( service == (mlt_service) -1 ) { + mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); + MltInput* input = GlslManager::get_input( producer, frame ); + GlslManager::set_input( producer, frame, NULL ); + chain->effect_chain->add_input( input ); + chain->effects.insert(std::make_pair( MLT_SERVICE( producer ), input ) ); + return input; + } + + Effect* effect = GlslManager::get_effect( service, frame ); + assert( effect ); + GlslManager::set_effect( service, frame, NULL ); + + mlt_service input_a = GlslManager::get_effect_input( service, frame ); + mlt_service input_b; + mlt_frame frame_b; + GlslManager::get_effect_secondary_input( service, frame, &input_b, &frame_b ); + Effect *effect_a = build_movit_chain( input_a, frame, chain ); + + if ( input_b ) { + Effect *effect_b = build_movit_chain( input_b, frame_b, chain ); + chain->effect_chain->add_effect( effect, effect_a, effect_b ); + } else { + chain->effect_chain->add_effect( effect, effect_a ); + } + + chain->effects.insert(std::make_pair( service, effect ) ); + return effect; +} + +static void dispose_movit_effects( mlt_service service, mlt_frame frame ) +{ + if ( service == (mlt_service) -1 ) { + mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); + delete GlslManager::get_input( producer, frame ); + GlslManager::set_input( producer, frame, NULL ); + return; + } + + delete GlslManager::get_effect( service, frame ); + GlslManager::set_effect( service, frame, NULL ); + + mlt_service input_a = GlslManager::get_effect_input( service, frame ); + mlt_service input_b; + mlt_frame frame_b; + GlslManager::get_effect_secondary_input( service, frame, &input_b, &frame_b ); + dispose_movit_effects( input_a, frame ); + + if ( input_b ) { + dispose_movit_effects( input_b, frame_b ); + } +} + +static void finalize_movit_chain( mlt_service leaf_service, mlt_frame frame ) +{ + GlslChain* chain = GlslManager::get_chain( leaf_service ); + + std::string new_fingerprint; + build_fingerprint( leaf_service, frame, &new_fingerprint ); + + // Build the chain if needed. + if ( !chain || new_fingerprint != chain->fingerprint ) { + printf("=== CREATING NEW CHAIN (old chain=%p, leaf=%p, fingerprint=%s) ===\n", chain, leaf_service, new_fingerprint.c_str()); + mlt_profile profile = mlt_service_profile( leaf_service ); + chain = new GlslChain; + chain->effect_chain = new EffectChain( profile->display_aspect_num, profile->display_aspect_den ); + chain->fingerprint = new_fingerprint; + + build_movit_chain( leaf_service, frame, chain ); + chain->effect_chain->add_effect( new Mlt::VerticalFlip ); + + ImageFormat output_format; + output_format.color_space = COLORSPACE_sRGB; + output_format.gamma_curve = GAMMA_sRGB; + chain->effect_chain->add_output(output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); + chain->effect_chain->set_dither_bits(8); + chain->effect_chain->finalize(); + + GlslManager::set_chain( leaf_service, chain ); + } else { + // Delete all the created Effect instances to avoid memory leaks. + dispose_movit_effects( leaf_service, frame ); + } +} + +static void set_movit_parameters( GlslChain *chain, mlt_service service, mlt_frame frame ) +{ + if ( service == (mlt_service) -1 ) { + mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); + MltInput* input = (MltInput *) chain->effects[ MLT_PRODUCER_SERVICE( producer ) ]; + input->set_pixel_data( GlslManager::get_input_pixel_pointer( producer, frame ) ); + return; + } + + Effect* effect = chain->effects[ service ]; + mlt_service input_a = GlslManager::get_effect_input( service, frame ); + set_movit_parameters( chain, input_a, frame ); + + mlt_service input_b; + mlt_frame frame_b; + GlslManager::get_effect_secondary_input( service, frame, &input_b, &frame_b ); + if ( input_b ) { + set_movit_parameters( chain, input_b, frame_b ); + } + + mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); + int count = mlt_properties_count( properties ); + for (int i = 0; i < count; ++i) { + const char *name = mlt_properties_get_name( properties, i ); + if (strncmp(name, "movit.parms.float.", strlen("movit.parms.float.")) == 0) { + bool ok = effect->set_float(name + strlen("movit.parms.float."), + mlt_properties_get_double( properties, name )); + assert(ok); + } + if (strncmp(name, "movit.parms.int.", strlen("movit.parms.int.")) == 0) { + bool ok = effect->set_int(name + strlen("movit.parms.int."), + mlt_properties_get_int( properties, name )); + assert(ok); + } + if (strncmp(name, "movit.parms.vec3.", strlen("movit.parms.vec3.")) == 0 && + strcmp(name + strlen(name) - 3, "[0]") == 0) { + float val[3]; + char *name_copy = strdup(name); + char *index_char = name_copy + strlen(name_copy) - 2; + val[0] = mlt_properties_get_double( properties, name_copy ); + *index_char = '1'; + val[1] = mlt_properties_get_double( properties, name_copy ); + *index_char = '2'; + val[2] = mlt_properties_get_double( properties, name_copy ); + index_char[-1] = '\0'; + bool ok = effect->set_vec3(name_copy + strlen("movit.parms.vec3."), val); + assert(ok); + free(name_copy); + } + if (strncmp(name, "movit.parms.vec4.", strlen("movit.parms.vec4.")) == 0 && + strcmp(name + strlen(name) - 3, "[0]") == 0) { + float val[4]; + char *name_copy = strdup(name); + char *index_char = name_copy + strlen(name_copy) - 2; + val[0] = mlt_properties_get_double( properties, name_copy ); + *index_char = '1'; + val[1] = mlt_properties_get_double( properties, name_copy ); + *index_char = '2'; + val[2] = mlt_properties_get_double( properties, name_copy ); + *index_char = '3'; + val[3] = mlt_properties_get_double( properties, name_copy ); + index_char[-1] = '\0'; + bool ok = effect->set_vec4(name_copy + strlen("movit.parms.vec4."), val); + assert(ok); + free(name_copy); + } + } +} + +static void dispose_pixel_pointers( mlt_service service, mlt_frame frame ) +{ + if ( service == (mlt_service) -1 ) { + mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); + mlt_pool_release( GlslManager::get_input_pixel_pointer( producer, frame ) ); + return; + } + + mlt_service input_a = GlslManager::get_effect_input( service, frame ); + dispose_pixel_pointers( input_a, frame ); + + mlt_service input_b; + mlt_frame frame_b; + GlslManager::get_effect_secondary_input( service, frame, &input_b, &frame_b ); + if ( input_b ) { + dispose_pixel_pointers( input_b, frame_b ); + } +} + +static int movit_render( EffectChain *chain, mlt_frame frame, mlt_image_format *format, mlt_image_format output_format, int width, int height, uint8_t **image ) +{ + GlslManager* glsl = GlslManager::get_instance(); + int error; + if ( output_format == mlt_image_glsl_texture ) { + error = glsl->render_frame_texture( chain, frame, width, height, image ); + } + else { + error = glsl->render_frame_rgba( chain, frame, width, height, image ); + if ( !error && output_format != mlt_image_rgb24a ) { + *format = mlt_image_rgb24a; + error = convert_on_cpu( frame, image, format, output_format ); + } + } + return error; +} + +// Create an MltInput for an image with the given format and dimensions. +static MltInput* create_input( mlt_properties properties, mlt_image_format format, int aspect_width, int aspect_height, int width, int height ) +{ + MltInput* input = new MltInput( aspect_width, aspect_height ); + if ( format == mlt_image_rgb24a || format == mlt_image_opengl ) { + // TODO: Get the color space if available. + input->useFlatInput( FORMAT_RGBA_POSTMULTIPLIED_ALPHA, width, height ); + } + else if ( format == mlt_image_rgb24 ) { + // TODO: Get the color space if available. + input->useFlatInput( FORMAT_RGB, width, height ); + } + else if ( format == mlt_image_yuv420p ) { + ImageFormat image_format; + YCbCrFormat ycbcr_format; + get_format_from_properties( properties, &image_format, &ycbcr_format ); + ycbcr_format.chroma_subsampling_x = ycbcr_format.chroma_subsampling_y = 2; + input->useYCbCrInput( image_format, ycbcr_format, width, height ); + } + else if ( format == mlt_image_yuv422 ) { + ImageFormat image_format; + YCbCrFormat ycbcr_format; + get_format_from_properties( properties, &image_format, &ycbcr_format ); + ycbcr_format.chroma_subsampling_x = 2; + ycbcr_format.chroma_subsampling_y = 1; + input->useYCbCrInput( image_format, ycbcr_format, width, height ); + } + return input; +} + +// Make a copy of the given image (allocated using mlt_pool_alloc) suitable +// to pass as pixel pointer to an MltInput (created using create_input +// with the same parameters), and return that pointer. +static uint8_t* make_input_copy( mlt_image_format format, uint8_t *image, int width, int height ) +{ + int img_size = mlt_image_format_size( format, width, height, NULL ); + uint8_t* img_copy = (uint8_t*) mlt_pool_alloc( img_size ); + if ( format == mlt_image_yuv422 ) { + yuv422_to_yuv422p( image, img_copy, width, height ); + } else { + memcpy( img_copy, image, img_size ); + } + return img_copy; +} + static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format ) { // Nothing to do! @@ -127,114 +399,94 @@ static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *fo int error = 0; int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); - int img_size = mlt_image_format_size( *format, width, height, NULL ); - mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); - mlt_service service = MLT_PRODUCER_SERVICE(producer); GlslManager::get_instance()->lock_service( frame ); - EffectChain* chain = GlslManager::get_chain( service ); - MltInput* input = GlslManager::get_input( service ); + + // If we're at the beginning of a series of Movit effects, store the input + // sent into the chain. + if ( output_format == mlt_image_glsl ) { + mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); + mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); + MltInput *input = create_input( properties, *format, profile->width, profile->height, width, height ); + GlslManager::set_input( producer, frame, input ); + uint8_t *img_copy = make_input_copy( *format, *image, width, height ); + GlslManager::set_input_pixel_pointer( producer, frame, img_copy ); - if ( !chain || !input ) { - GlslManager::get_instance()->unlock_service( frame ); - return 2; + *image = (uint8_t *) -1; + mlt_frame_set_image( frame, *image, 0, NULL ); } - if ( *format != mlt_image_glsl ) { - bool finalize_chain = false; - if ( output_format == mlt_image_glsl_texture ) { - // We might already have a texture from a previous conversion from mlt_image_glsl. - glsl_texture texture = (glsl_texture) mlt_properties_get_data( properties, "movit.convert.texture", NULL ); - // XXX: requires a special property set on the frame by the app for now - // because we do not have reliable way to clear the texture property - // when a downstream filter has changed image. - if ( texture && mlt_properties_get_int( properties, "movit.convert.use_texture") ) { - *image = (uint8_t*) &texture->texture; - mlt_frame_set_image( frame, *image, 0, NULL ); - mlt_properties_set_int( properties, "format", output_format ); - *format = output_format; - GlslManager::get_instance()->unlock_service( frame ); - return error; - } else { - // Use a separate chain to convert image in RAM to OpenGL texture. - // Use cached chain if available and compatible. - Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); - chain = (EffectChain*) producer.get_data( "movit.convert.chain" ); - input = (MltInput*) producer.get_data( "movit.convert.input" ); - int w = producer.get_int( "movit.convert.width" ); - int h = producer.get_int( "movit.convert.height" ); - mlt_image_format f = (mlt_image_format) producer.get_int( "movit.convert.format" ); - if ( !chain || width != w || height != h || output_format != f ) { - chain = new EffectChain( width, height ); - input = new MltInput( width, height ); - chain->add_input( input ); - chain->add_effect( new Mlt::VerticalFlip() ); - finalize_chain = true; - producer.set( "movit.convert.chain", chain, 0, (mlt_destructor) delete_chain ); - producer.set( "movit.convert.input", input, 0 ); - producer.set( "movit.convert.width", width ); - producer.set( "movit.convert.height", height ); - producer.set( "movit.convert.format", output_format ); - } - } - } - if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { - // TODO: Get the color space if available. - input->useFlatInput( chain, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, width, height ); - input->set_pixel_data( *image ); - } - else if ( *format == mlt_image_rgb24 ) { - // TODO: Get the color space if available. - input->useFlatInput( chain, FORMAT_RGB, width, height ); - input->set_pixel_data( *image ); - } - else if ( *format == mlt_image_yuv420p ) { - ImageFormat image_format; - YCbCrFormat ycbcr_format; - get_format_from_properties( properties, &image_format, &ycbcr_format ); - ycbcr_format.chroma_subsampling_x = ycbcr_format.chroma_subsampling_y = 2; - input->useYCbCrInput( chain, image_format, ycbcr_format, width, height ); - input->set_pixel_data( *image ); - } - else if ( *format == mlt_image_yuv422 ) { - ImageFormat image_format; - YCbCrFormat ycbcr_format; - get_format_from_properties( properties, &image_format, &ycbcr_format ); - ycbcr_format.chroma_subsampling_x = 2; - ycbcr_format.chroma_subsampling_y = 1; - input->useYCbCrInput( chain, image_format, ycbcr_format, width, height ); - - // convert chunky to planar - uint8_t* planar = (uint8_t*) mlt_pool_alloc( img_size ); - yuv422_to_yuv422p( *image, planar, width, height ); - input->set_pixel_data( planar ); - mlt_frame_set_image( frame, planar, img_size, mlt_pool_release ); - } - // Finalize the separate conversion chain if needed. - if ( finalize_chain ) - chain->finalize(); + // If we're at the _end_ of a series of Movit effects, render the chain. + if ( *format == mlt_image_glsl ) { + mlt_service leaf_service = (mlt_service) *image; + + // Construct the chain unless we already have a good one. + finalize_movit_chain( leaf_service, frame ); + + // Set per-frame parameters now that we know which Effect instances to set them on. + GlslChain *chain = GlslManager::get_chain( leaf_service ); + set_movit_parameters( chain, leaf_service, frame ); + + error = movit_render( chain->effect_chain, frame, format, output_format, width, height, image ); + + dispose_pixel_pointers( leaf_service, frame ); } - if ( output_format != mlt_image_glsl ) { + // If we've been asked to render some frame directly to a texture (without any + // effects in-between), we create a new mini-chain to do so. + if ( *format != mlt_image_glsl && output_format == mlt_image_glsl_texture ) { + // We might already have a texture from a previous conversion from mlt_image_glsl. + glsl_texture texture = (glsl_texture) mlt_properties_get_data( properties, "movit.convert.texture", NULL ); + // XXX: requires a special property set on the frame by the app for now + // because we do not have reliable way to clear the texture property + // when a downstream filter has changed image. + if ( texture && mlt_properties_get_int( properties, "movit.convert.use_texture") ) { + *image = (uint8_t*) &texture->texture; + mlt_frame_set_image( frame, *image, 0, NULL ); + } else { + // Use a separate chain to convert image in RAM to OpenGL texture. + // Use cached chain if available and compatible. + Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); + EffectChain *chain = (EffectChain*) producer.get_data( "movit.convert.chain" ); + MltInput *input = (MltInput*) producer.get_data( "movit.convert.input" ); + int w = producer.get_int( "movit.convert.width" ); + int h = producer.get_int( "movit.convert.height" ); + mlt_image_format f = (mlt_image_format) producer.get_int( "movit.convert.format" ); + if ( !chain || !input || width != w || height != h || *format != f ) { + chain = new EffectChain( width, height ); + input = create_input( properties, *format, width, height, width, height ); + chain->add_input( input ); + chain->add_effect( new Mlt::VerticalFlip() ); + ImageFormat movit_output_format; + movit_output_format.color_space = COLORSPACE_sRGB; + movit_output_format.gamma_curve = GAMMA_sRGB; + chain->add_output(movit_output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); + chain->set_dither_bits(8); + chain->finalize(); + producer.set( "movit.convert.chain", chain, 0, (mlt_destructor) delete_chain ); + producer.set( "movit.convert.input", input, 0, NULL ); + producer.set( "movit.convert.width", width ); + producer.set( "movit.convert.height", height ); + producer.set( "movit.convert.format", *format ); + } - if ( output_format == mlt_image_glsl_texture ) { - error = glsl->render_frame_texture( service, frame, width, height, image ); - } - else { - error = glsl->render_frame_rgba( service, frame, width, height, image ); - if ( !error && output_format != mlt_image_rgb24a ) { - *format = mlt_image_rgb24a; - error = convert_on_cpu( frame, image, format, output_format ); + if ( *format == mlt_image_yuv422 ) { + // We need to convert to planar, which make_input_copy() will do for us. + uint8_t *planar = make_input_copy( *format, *image, width, height ); + input->set_pixel_data( planar ); + error = movit_render( chain, frame, format, output_format, width, height, image ); + mlt_pool_release( planar ); + } else { + input->set_pixel_data( *image ); + error = movit_render( chain, frame, format, output_format, width, height, image ); } } - mlt_properties_set_int( properties, "format", output_format ); - *format = output_format; - } - else { - mlt_properties_set_int( properties, "format", output_format ); - *format = output_format; } + GlslManager::get_instance()->unlock_service( frame ); + mlt_properties_set_int( properties, "format", output_format ); + *format = output_format; + return error; } diff --git a/src/modules/opengl/filter_movit_crop.cpp b/src/modules/opengl/filter_movit_crop.cpp index f35fc7f2..53367350 100644 --- a/src/modules/opengl/filter_movit_crop.cpp +++ b/src/modules/opengl/filter_movit_crop.cpp @@ -23,6 +23,7 @@ #include "filter_glsl_manager.h" #include +#include "optional_effect.h" static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { @@ -76,32 +77,31 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_log_debug( MLT_FILTER_SERVICE(filter), "%dx%d -> %dx%d\n", *width, *height, owidth, oheight); + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - bool ok = effect->set_int( "width", owidth ); - ok |= effect->set_int( "height", oheight ); - ok |= effect->set_float( "left", -left ); - ok |= effect->set_float( "top", -top ); - assert(ok); - *width = owidth; - *height = oheight; - } + mlt_properties_set_int( properties, "movit.parms.int.width", owidth ); + mlt_properties_set_int( properties, "movit.parms.int.height", oheight ); + mlt_properties_set_double( properties, "movit.parms.float.left", -left ); + mlt_properties_set_double( properties, "movit.parms.float.top", -top ); + + bool disable = ( *width == owidth && *height == oheight ); + mlt_properties_set_int( properties, "movit.disable", disable ); + GlslManager::get_instance()->unlock_service( frame ); } + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + Effect* effect = GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new OptionalEffect ); + assert(effect); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + RGBATuple border_color( 0.0f, 0.0f, 0.0f, 1.0f ); + bool ok = effect->set_vec4( "border_color", (float*) &border_color ); + assert(ok); return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); - if ( !GlslManager::init_chain( MLT_PRODUCER_SERVICE(producer) ) ) { - Effect* effect = GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new PaddingEffect ); - RGBATuple border_color( 0.0f, 0.0f, 0.0f, 1.0f ); - bool ok = effect->set_vec4( "border_color", (float*) &border_color ); - assert(ok); - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_deconvolution_sharpen.cpp b/src/modules/opengl/filter_movit_deconvolution_sharpen.cpp index 8a33f494..bedb3133 100644 --- a/src/modules/opengl/filter_movit_deconvolution_sharpen.cpp +++ b/src/modules/opengl/filter_movit_deconvolution_sharpen.cpp @@ -29,33 +29,29 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); - bool ok = effect->set_int( "matrix_size", - mlt_properties_anim_get_int( properties, "matrix_size", position, length ) ); - ok |= effect->set_float( "cirlce_radius", - mlt_properties_anim_get_double( properties, "circle_radius", position, length ) ); - ok |= effect->set_float( "gaussian_radius", - mlt_properties_anim_get_double( properties, "gaussian_radius", position, length ) ); - ok |= effect->set_float( "correlation", - mlt_properties_anim_get_double( properties, "correlation", position, length ) ); - ok |= effect->set_float( "noise", - mlt_properties_anim_get_double( properties, "noise", position, length ) ); - assert(ok); - } + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + mlt_properties_set_int( properties, "movit.parms.int.matrix_size", + mlt_properties_anim_get_int( properties, "matrix_size", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.float.circle_radius", + mlt_properties_anim_get_double( properties, "circle_radius", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.float.gaussian_radius", + mlt_properties_anim_get_double( properties, "gaussian_radius", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.float.correlation", + mlt_properties_anim_get_double( properties, "correlation", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.float.noise", + mlt_properties_anim_get_double( properties, "noise", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; - return mlt_frame_get_image( frame, image, format, width, height, writable ); + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new DeconvolutionSharpenEffect ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - if ( !GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ) ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new DeconvolutionSharpenEffect() ); - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_diffusion.cpp b/src/modules/opengl/filter_movit_diffusion.cpp index e6341f34..c04c2ce4 100644 --- a/src/modules/opengl/filter_movit_diffusion.cpp +++ b/src/modules/opengl/filter_movit_diffusion.cpp @@ -29,27 +29,23 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); - bool ok = effect->set_float( "radius", - mlt_properties_anim_get_double( properties, "radius", position, length ) ); - ok |= effect->set_float( "blurred_mix_amount", - mlt_properties_anim_get_double( properties, "mix", position, length ) ); - assert(ok); - } + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + mlt_properties_set_double( properties, "movit.parms.float.radius", + mlt_properties_anim_get_double( properties, "radius", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.float.blurred_mix_amount", + mlt_properties_anim_get_double( properties, "mix", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; - return mlt_frame_get_image( frame, image, format, width, height, writable ); + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new DiffusionEffect ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - if ( !GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ) ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new DiffusionEffect() ); - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_glow.cpp b/src/modules/opengl/filter_movit_glow.cpp index 1d849c1b..ab9ea0c5 100644 --- a/src/modules/opengl/filter_movit_glow.cpp +++ b/src/modules/opengl/filter_movit_glow.cpp @@ -28,30 +28,26 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); - bool ok = effect->set_float( "radius", - mlt_properties_anim_get_double( properties, "radius", position, length ) ); - ok |= effect->set_float( "blurred_mix_amount", - mlt_properties_anim_get_double( properties, "blur_mix", position, length ) ); - ok |= effect->set_float( "highlight_cutoff", - mlt_properties_anim_get_double( properties, "highlight_cutoff", position, length ) ); - assert(ok); - } + mlt_properties_set_double( properties, "movit.parms.float.radius", + mlt_properties_anim_get_double( properties, "radius", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.float.blurred_mix_amount", + mlt_properties_anim_get_double( properties, "blur_mix", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.float.highlight_cutoff", + mlt_properties_anim_get_double( properties, "highlight_cutoff", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; - return mlt_frame_get_image( frame, image, format, width, height, writable ); + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new GlowEffect ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - if ( !GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ) ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new GlowEffect() ); - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_lift_gamma_gain.cpp b/src/modules/opengl/filter_movit_lift_gamma_gain.cpp index 015ab672..de934d03 100644 --- a/src/modules/opengl/filter_movit_lift_gamma_gain.cpp +++ b/src/modules/opengl/filter_movit_lift_gamma_gain.cpp @@ -29,37 +29,37 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); - RGBTriplet triplet( - mlt_properties_anim_get_double( properties, "lift_r", position, length ), - mlt_properties_anim_get_double( properties, "lift_g", position, length ), - mlt_properties_anim_get_double( properties, "lift_b", position, length ) - ); - bool ok = effect->set_vec3( "lift", (float*) &triplet ); - triplet.r = mlt_properties_anim_get_double( properties, "gamma_r", position, length ); - triplet.g = mlt_properties_anim_get_double( properties, "gamma_g", position, length ); - triplet.b = mlt_properties_anim_get_double( properties, "gamma_b", position, length ); - ok |= effect->set_vec3( "gamma", (float*) &triplet ); - triplet.r = mlt_properties_anim_get_double( properties, "gain_r", position, length ); - triplet.g = mlt_properties_anim_get_double( properties, "gain_g", position, length ); - triplet.b = mlt_properties_anim_get_double( properties, "gain_b", position, length ); - ok |= effect->set_vec3( "gain", (float*) &triplet ); - assert(ok); - } + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + mlt_properties_set_double( properties, "movit.parms.vec3.lift[0]", + mlt_properties_anim_get_double( properties, "lift_r", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.vec3.lift[1]", + mlt_properties_anim_get_double( properties, "lift_g", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.vec3.lift[2]", + mlt_properties_anim_get_double( properties, "lift_b", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.vec3.gamma[0]", + mlt_properties_anim_get_double( properties, "gamma_r", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.vec3.gamma[1]", + mlt_properties_anim_get_double( properties, "gamma_g", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.vec3.gamma[2]", + mlt_properties_anim_get_double( properties, "gamma_b", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.vec3.gain[0]", + mlt_properties_anim_get_double( properties, "gain_r", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.vec3.gain[1]", + mlt_properties_anim_get_double( properties, "gain_g", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.vec3.gain[2]", + mlt_properties_anim_get_double( properties, "gain_b", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; - return mlt_frame_get_image( frame, image, format, width, height, writable ); + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new LiftGammaGainEffect ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - if ( !GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ) ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new LiftGammaGainEffect ); - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_mirror.cpp b/src/modules/opengl/filter_movit_mirror.cpp index 55fa6376..12d8d271 100644 --- a/src/modules/opengl/filter_movit_mirror.cpp +++ b/src/modules/opengl/filter_movit_mirror.cpp @@ -24,13 +24,21 @@ #include "filter_glsl_manager.h" #include +static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +{ + mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); + *format = mlt_image_glsl; + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new MirrorEffect ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; +} + static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( !effect ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new MirrorEffect() ); - } + mlt_frame_push_service( frame, filter ); + mlt_frame_push_get_image( frame, get_image ); return frame; } diff --git a/src/modules/opengl/filter_movit_opacity.cpp b/src/modules/opengl/filter_movit_opacity.cpp index be80239d..5916c34e 100644 --- a/src/modules/opengl/filter_movit_opacity.cpp +++ b/src/modules/opengl/filter_movit_opacity.cpp @@ -22,38 +22,31 @@ #include #include "filter_glsl_manager.h" -#include +#include static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); - bool ok = effect->set_float( "strength_first", - mlt_properties_anim_get_double( properties, "opacity", position, length ) ); - assert(ok); - } + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + double opacity = mlt_properties_anim_get_double( properties, "opacity", position, length ); + mlt_properties_set_double( properties, "movit.parms.vec4.factor[0]", opacity ); + mlt_properties_set_double( properties, "movit.parms.vec4.factor[1]", opacity ); + mlt_properties_set_double( properties, "movit.parms.vec4.factor[2]", opacity ); + mlt_properties_set_double( properties, "movit.parms.vec4.factor[3]", opacity ); GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; - return mlt_frame_get_image( frame, image, format, width, height, writable ); + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new MultiplyEffect ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( !effect ) { - effect = GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new MixEffect, 0 ); - assert(effect); - bool ok = effect->set_float( "strength_first", 1.0f ); - ok |= effect->set_float( "strength_second", 0.0f ); - assert(ok); - } - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_resample.cpp b/src/modules/opengl/filter_movit_resample.cpp index 93e7b6ce..1b76339e 100644 --- a/src/modules/opengl/filter_movit_resample.cpp +++ b/src/modules/opengl/filter_movit_resample.cpp @@ -23,10 +23,10 @@ #include "filter_glsl_manager.h" #include +#include "optional_effect.h" static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { - int error = 0; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); @@ -60,30 +60,34 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format if ( iheight != oheight ) mlt_properties_set_int( properties, "consumer_deinterlace", 1 ); + GlslManager::get_instance()->lock_service( frame ); + mlt_properties_set_int( filter_properties, "movit.parms.int.width", owidth ); + mlt_properties_set_int( filter_properties, "movit.parms.int.height", oheight ); + + bool disable = ( iwidth == owidth && iheight == oheight ); + mlt_properties_set_int( filter_properties, "movit.disable", disable ); + + *width = owidth; + *height = oheight; + + GlslManager::get_instance()->unlock_service( frame ); + // Get the image as requested if ( *format != mlt_image_none ) *format = mlt_image_glsl; - error = mlt_frame_get_image( frame, image, format, &iwidth, &iheight, writable ); - if ( !error ) { - GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - bool ok = effect->set_int( "width", owidth ); - ok |= effect->set_int( "height", oheight ); - assert(ok); - *width = owidth; - *height = oheight; - } - GlslManager::get_instance()->unlock_service( frame ); - } - - return error; + int error = mlt_frame_get_image( frame, image, format, &iwidth, &iheight, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + Effect *effect = GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new OptionalEffect ); + // This needs to be something else than 0x0 at chain finalization time. + bool ok = effect->set_int("width", owidth); + ok |= effect->set_int("height", oheight); + assert( ok ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ) ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new ResampleEffect ); mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_resize.cpp b/src/modules/opengl/filter_movit_resize.cpp index ef87c7e9..04953d9c 100644 --- a/src/modules/opengl/filter_movit_resize.cpp +++ b/src/modules/opengl/filter_movit_resize.cpp @@ -26,6 +26,7 @@ #include "filter_glsl_manager.h" #include #include +#include "optional_effect.h" static float alignment_parse( char* align ) { @@ -156,16 +157,22 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format } if ( !error ) { + mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - bool ok = effect->set_int( "width", *width ); - ok |= effect->set_int( "height", *height ); - ok |= effect->set_float( "left", rect.x ); - ok |= effect->set_float( "top", rect.y ); - assert(ok); - } + mlt_properties_set_int( filter_properties, "movit.parms.int.width", *width ); + mlt_properties_set_int( filter_properties, "movit.parms.int.height", *height ); + mlt_properties_set_double( filter_properties, "movit.parms.float.left", rect.x ); + mlt_properties_set_double( filter_properties, "movit.parms.float.top", rect.y ); + + bool disable = ( *width == owidth && *height == oheight ); + mlt_properties_set_int( filter_properties, "movit.disable", disable ); + GlslManager::get_instance()->unlock_service( frame ); + + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new OptionalEffect ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } return error; @@ -173,8 +180,6 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ) ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new PaddingEffect ); mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_saturation.cpp b/src/modules/opengl/filter_movit_saturation.cpp index 04d1d0a0..d23a0503 100644 --- a/src/modules/opengl/filter_movit_saturation.cpp +++ b/src/modules/opengl/filter_movit_saturation.cpp @@ -29,25 +29,21 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); - bool ok = effect->set_float( "saturation", - mlt_properties_anim_get_double( properties, "saturation", position, length ) ); - assert(ok); - } + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + mlt_properties_set_double( properties, "movit.parms.float.saturation", + mlt_properties_anim_get_double( properties, "saturation", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; - return mlt_frame_get_image( frame, image, format, width, height, writable ); + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new SaturationEffect() ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - if ( !GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ) ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new SaturationEffect() ); - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_vignette.cpp b/src/modules/opengl/filter_movit_vignette.cpp index 589931b6..bdcb8a28 100644 --- a/src/modules/opengl/filter_movit_vignette.cpp +++ b/src/modules/opengl/filter_movit_vignette.cpp @@ -29,27 +29,23 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); - bool ok = effect->set_float( "radius", - mlt_properties_anim_get_double( properties, "radius", position, length ) ); - ok |= effect->set_float( "inner_radius", - mlt_properties_anim_get_double( properties, "inner_radius", position, length ) ); - assert(ok); - } + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + mlt_properties_set_double( properties, "movit.parms.float.radius", + mlt_properties_anim_get_double( properties, "radius", position, length ) ); + mlt_properties_set_double( properties, "movit.parms.float.inner_radius", + mlt_properties_anim_get_double( properties, "inner_radius", position, length ) ); GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; - return mlt_frame_get_image( frame, image, format, width, height, writable ); + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new VignetteEffect() ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - if ( !GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ) ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new VignetteEffect() ); - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/filter_movit_white_balance.cpp b/src/modules/opengl/filter_movit_white_balance.cpp index fa047761..71a325d5 100644 --- a/src/modules/opengl/filter_movit_white_balance.cpp +++ b/src/modules/opengl/filter_movit_white_balance.cpp @@ -40,32 +40,32 @@ static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); GlslManager::get_instance()->lock_service( frame ); - Effect* effect = GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ); - if ( effect ) { - mlt_position position = mlt_filter_get_position( filter, frame ); - mlt_position length = mlt_filter_get_length2( filter, frame ); - int color_int = mlt_properties_anim_get_int( properties, "neutral_color", position, length ); - RGBTriplet color( - srgb8_to_linear((color_int >> 24) & 0xff), - srgb8_to_linear((color_int >> 16) & 0xff), - srgb8_to_linear((color_int >> 8) & 0xff) - ); - bool ok = effect->set_vec3( "neutral_color", (float*) &color ); - ok |= effect->set_float( "output_color_temperature", - mlt_properties_anim_get_double( properties, "color_temperature", position, length ) ); - assert(ok); - } + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_position length = mlt_filter_get_length2( filter, frame ); + int color_int = mlt_properties_anim_get_int( properties, "neutral_color", position, length ); + RGBTriplet color( + srgb8_to_linear((color_int >> 24) & 0xff), + srgb8_to_linear((color_int >> 16) & 0xff), + srgb8_to_linear((color_int >> 8) & 0xff) + ); + mlt_properties_set_double( properties, "movit.parms.vec3.neutral_color[0]", color.r ); + mlt_properties_set_double( properties, "movit.parms.vec3.neutral_color[1]", color.g ); + mlt_properties_set_double( properties, "movit.parms.vec3.neutral_color[2]", color.b ); + double output_color_temperature = + mlt_properties_anim_get_double( properties, "color_temperature", position, length ); + mlt_properties_set_double( properties, "movit.parms.float.output_color_temperature", + output_color_temperature ); GlslManager::get_instance()->unlock_service( frame ); *format = mlt_image_glsl; - return mlt_frame_get_image( frame, image, format, width, height, writable ); + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + GlslManager::set_effect_input( MLT_FILTER_SERVICE( filter ), frame, (mlt_service) *image ); + GlslManager::set_effect( MLT_FILTER_SERVICE( filter ), frame, new WhiteBalanceEffect ); + *image = (uint8_t *) MLT_FILTER_SERVICE( filter ); + return error; } static mlt_frame process( mlt_filter filter, mlt_frame frame ) { - if ( !mlt_frame_is_test_card( frame ) ) { - if ( !GlslManager::get_effect( MLT_FILTER_SERVICE( filter ), frame ) ) - GlslManager::add_effect( MLT_FILTER_SERVICE( filter ), frame, new WhiteBalanceEffect ); - } mlt_frame_push_service( frame, filter ); mlt_frame_push_get_image( frame, get_image ); return frame; diff --git a/src/modules/opengl/mlt_movit_input.cpp b/src/modules/opengl/mlt_movit_input.cpp index f4b29022..d2755741 100644 --- a/src/modules/opengl/mlt_movit_input.cpp +++ b/src/modules/opengl/mlt_movit_input.cpp @@ -83,7 +83,7 @@ GammaCurve MltInput::get_gamma_curve() const return input->get_gamma_curve(); } -void MltInput::useFlatInput(EffectChain* chain, MovitPixelFormat pix_fmt, unsigned width, unsigned height) +void MltInput::useFlatInput(MovitPixelFormat pix_fmt, unsigned width, unsigned height) { if (!input) { m_width = width; @@ -92,28 +92,21 @@ void MltInput::useFlatInput(EffectChain* chain, MovitPixelFormat pix_fmt, unsign image_format.color_space = COLORSPACE_sRGB; image_format.gamma_curve = GAMMA_sRGB; input = new FlatInput(image_format, pix_fmt, GL_UNSIGNED_BYTE, width, height); - chain->add_output(image_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); - chain->set_dither_bits(8); } } -void MltInput::useYCbCrInput(EffectChain* chain, const ImageFormat& image_format, const YCbCrFormat& ycbcr_format, unsigned width, unsigned height) +void MltInput::useYCbCrInput(const ImageFormat& image_format, const YCbCrFormat& ycbcr_format, unsigned width, unsigned height) { if (!input) { m_width = width; m_height = height; input = new YCbCrInput(image_format, ycbcr_format, width, height); - ImageFormat output_format; - output_format.color_space = COLORSPACE_sRGB; - output_format.gamma_curve = GAMMA_sRGB; - chain->add_output(output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); - chain->set_dither_bits(8); isRGB = false; m_ycbcr_format = ycbcr_format; } } -void MltInput::useFBOInput(EffectChain *chain, GLuint texture) +void MltInput::useFBOInput(GLuint texture) { if (!input) { FBOInput* fboInput = new FBOInput(m_width, m_height); diff --git a/src/modules/opengl/mlt_movit_input.h b/src/modules/opengl/mlt_movit_input.h index 2f5de231..ce9f61ae 100644 --- a/src/modules/opengl/mlt_movit_input.h +++ b/src/modules/opengl/mlt_movit_input.h @@ -45,9 +45,9 @@ public: GammaCurve get_gamma_curve() const; // Custom methods - void useFlatInput(EffectChain* chain, MovitPixelFormat pix_fmt, unsigned width, unsigned height); - void useYCbCrInput(EffectChain* chain, const ImageFormat& image_format, const YCbCrFormat& ycbcr_format, unsigned width, unsigned height); - void useFBOInput(EffectChain* chain, GLuint texture); + void useFlatInput(MovitPixelFormat pix_fmt, unsigned width, unsigned height); + void useYCbCrInput(const ImageFormat& image_format, const YCbCrFormat& ycbcr_format, unsigned width, unsigned height); + void useFBOInput(GLuint texture); void set_pixel_data(const unsigned char* data); private: diff --git a/src/modules/opengl/optional_effect.h b/src/modules/opengl/optional_effect.h new file mode 100644 index 00000000..ec6ea27a --- /dev/null +++ b/src/modules/opengl/optional_effect.h @@ -0,0 +1,29 @@ +#ifndef OPTIONAL_EFFECT_H +#define OPTIONAL_EFFECT_H + +#include +#include +#include + +// A wrapper effect that, at rewrite time, can remove itself entirely from the loop. +// It does so if "disable" is set to a nonzero value at finalization time. +template +class OptionalEffect : public T { +public: + OptionalEffect() : disable(0) { this->register_int("disable", &disable); } + virtual std::string effect_type_id() const { return "OptionalEffect[" + T::effect_type_id() + "]"; } + virtual void rewrite_graph(EffectChain *graph, Node *self) { + if (disable) { + assert(self->incoming_links.size() == 1); + graph->replace_sender(self, self->incoming_links[0]); + self->disabled = true; + } else { + T::rewrite_graph(graph, self); + } + } + +private: + int disable; +}; + +#endif diff --git a/src/modules/opengl/transition_movit_mix.cpp b/src/modules/opengl/transition_movit_mix.cpp index 1697d12e..4adc810e 100644 --- a/src/modules/opengl/transition_movit_mix.cpp +++ b/src/modules/opengl/transition_movit_mix.cpp @@ -32,34 +32,19 @@ static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { - int error = 0; + int error; // Get the b frame from the stack mlt_frame b_frame = (mlt_frame) mlt_frame_pop_frame( a_frame ); // Get the transition object mlt_transition transition = (mlt_transition) mlt_frame_pop_service( a_frame ); + mlt_service service = MLT_TRANSITION_SERVICE( transition ); + mlt_service_lock( service ); // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); - // Get the properties of the a frame - mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); - - // Get the movit objects - mlt_service service = MLT_TRANSITION_SERVICE( transition ); - mlt_service_lock( service ); - EffectChain* chain = GlslManager::get_chain( service ); - Effect* effect = (Effect*) mlt_properties_get_data( properties, "movit effect", NULL ); - MltInput* a_input = GlslManager::get_input( service ); - MltInput* b_input = (MltInput*) mlt_properties_get_data( properties, "movit input B", NULL ); - mlt_image_format output_format = *format; - - if ( !chain || !a_input ) { - mlt_service_unlock( service ); - return 2; - } - // Get the transition parameters mlt_position position = mlt_transition_get_position( transition, a_frame ); mlt_position length = mlt_transition_get_length( transition ); @@ -69,71 +54,30 @@ static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *form mlt_transition_get_progress( transition, a_frame ); double inverse = 1.0 - mix; - // Set the movit parameters - bool ok = effect->set_float( "strength_first", reverse ? mix : inverse ); - ok |= effect->set_float( "strength_second", reverse ? inverse : mix ); - assert( ok ); - - // Get the frames' textures - GLuint* texture_id[2] = {0, 0}; - *format = mlt_image_glsl_texture; - mlt_frame_get_image( a_frame, (uint8_t**) &texture_id[0], format, width, height, 0 ); - a_input->useFBOInput( chain, *texture_id[0] ); - *format = mlt_image_glsl_texture; - mlt_frame_get_image( b_frame, (uint8_t**) &texture_id[1], format, width, height, 0 ); - b_input->useFBOInput( chain, *texture_id[1] ); - - // Set resolution to that of the a_frame - *width = mlt_properties_get_int( a_props, "width" ); - *height = mlt_properties_get_int( a_props, "height" ); - - // Setup rendering to an FBO - GlslManager* glsl = GlslManager::get_instance(); - if ( output_format == mlt_image_glsl_texture ) { - error = glsl->render_frame_texture( service, a_frame, *width, *height, image ); - *format = output_format; - } - else { - error = glsl->render_frame_rgba( service, a_frame, *width, *height, image ); - *format = mlt_image_rgb24a; - } - mlt_service_unlock( service ); + // Set the Movit parameters. + mlt_properties_set_double( properties, "movit.parms.float.strength_first", reverse ? mix : inverse ); + mlt_properties_set_double( properties, "movit.parms.float.strength_second", reverse ? inverse : mix ); + + uint8_t *a_image, *b_image; + + // Get the two images. + *format = mlt_image_glsl; + error = mlt_frame_get_image( a_frame, &a_image, format, width, height, writable ); + error = mlt_frame_get_image( b_frame, &b_image, format, width, height, writable ); + GlslManager::set_effect_input( service, a_frame, (mlt_service) a_image ); + GlslManager::set_effect_secondary_input( service, a_frame, (mlt_service) b_image, b_frame ); + GlslManager::set_effect( service, a_frame, new MixEffect() ); + *image = (uint8_t *) service; + + mlt_service_unlock( service ); return error; } static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { - mlt_service service = MLT_TRANSITION_SERVICE(transition); - - if ( !GlslManager::init_chain( service ) ) { - // Create the Movit effect chain - EffectChain* chain = GlslManager::get_chain( service ); - mlt_profile profile = mlt_service_profile( service ); - Input* b_input = new MltInput( profile->width, profile->height ); - ImageFormat output_format; - output_format.color_space = COLORSPACE_sRGB; - output_format.gamma_curve = GAMMA_sRGB; - chain->add_input( b_input ); - chain->add_output( output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED ); - chain->set_dither_bits( 8 ); - - Effect* effect = chain->add_effect( new MixEffect(), - GlslManager::get_input( service ), b_input ); - - // Save these new effects on properties for get_image - mlt_properties properties = MLT_TRANSITION_PROPERTIES(transition); - mlt_properties_set_data( properties, "movit effect", effect, 0, NULL, NULL ); - mlt_properties_set_data( properties, "movit input B", b_input, 0, NULL, NULL ); - } - - // Push the transition on to the frame mlt_frame_push_service( a_frame, transition ); - - // Push the b_frame on to the stack mlt_frame_push_frame( a_frame, b_frame ); - - // Push the transition method mlt_frame_push_get_image( a_frame, get_image ); return a_frame; diff --git a/src/modules/opengl/transition_movit_overlay.cpp b/src/modules/opengl/transition_movit_overlay.cpp index 4492ce6b..2b77c9c6 100644 --- a/src/modules/opengl/transition_movit_overlay.cpp +++ b/src/modules/opengl/transition_movit_overlay.cpp @@ -27,96 +27,39 @@ #include #include #include -#include "mlt_movit_input.h" -#include "mlt_flip_effect.h" static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { - int error = 0; + int error; // Get the b frame from the stack mlt_frame b_frame = (mlt_frame) mlt_frame_pop_frame( a_frame ); // Get the transition object mlt_transition transition = (mlt_transition) mlt_frame_pop_service( a_frame ); - - // Get the properties of the transition - mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); - - // Get the properties of the a frame - mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); - - // Get the movit objects mlt_service service = MLT_TRANSITION_SERVICE( transition ); mlt_service_lock( service ); - EffectChain* chain = GlslManager::get_chain( service ); - MltInput* a_input = GlslManager::get_input( service ); - MltInput* b_input = (MltInput*) mlt_properties_get_data( properties, "movit input B", NULL ); - mlt_image_format output_format = *format; - if ( !chain || !a_input ) { - mlt_service_unlock( service ); - return 2; - } + uint8_t *a_image, *b_image; - // Get the frames' textures - GLuint* texture_id[2] = {0, 0}; - *format = mlt_image_glsl_texture; - mlt_frame_get_image( a_frame, (uint8_t**) &texture_id[0], format, width, height, 0 ); - a_input->useFBOInput( chain, *texture_id[0] ); - *format = mlt_image_glsl_texture; - mlt_frame_get_image( b_frame, (uint8_t**) &texture_id[1], format, width, height, 0 ); - b_input->useFBOInput( chain, *texture_id[1] ); + // Get the two images. + *format = mlt_image_glsl; + error = mlt_frame_get_image( a_frame, &a_image, format, width, height, writable ); + error = mlt_frame_get_image( b_frame, &b_image, format, width, height, writable ); - // Set resolution to that of the a_frame - *width = mlt_properties_get_int( a_props, "width" ); - *height = mlt_properties_get_int( a_props, "height" ); + GlslManager::set_effect_input( service, a_frame, (mlt_service) a_image ); + GlslManager::set_effect_secondary_input( service, a_frame, (mlt_service) b_image, b_frame ); + GlslManager::set_effect( service, a_frame, new OverlayEffect ); + *image = (uint8_t *) service; - // Setup rendering to an FBO - GlslManager* glsl = GlslManager::get_instance(); - if ( output_format == mlt_image_glsl_texture ) { - error = glsl->render_frame_texture( service, a_frame, *width, *height, image ); - *format = output_format; - } - else { - error = glsl->render_frame_rgba( service, a_frame, *width, *height, image ); - *format = mlt_image_rgb24a; - } mlt_service_unlock( service ); - return error; } static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { - mlt_service service = MLT_TRANSITION_SERVICE(transition); - - if ( !GlslManager::init_chain( service ) ) { - // Create the Movit effect chain - EffectChain* chain = GlslManager::get_chain( service ); - mlt_profile profile = mlt_service_profile( service ); - Input* b_input = new MltInput( profile->width, profile->height ); - ImageFormat output_format; - output_format.color_space = COLORSPACE_sRGB; - output_format.gamma_curve = GAMMA_sRGB; - chain->add_input( b_input ); - chain->add_output( output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED ); - chain->set_dither_bits( 8 ); - - chain->add_effect( new OverlayEffect(), GlslManager::get_input( service ), b_input ); - - // Save these new input on properties for get_image - mlt_properties_set_data( MLT_TRANSITION_PROPERTIES(transition), - "movit input B", b_input, 0, NULL, NULL ); - } - - // Push the transition on to the frame mlt_frame_push_service( a_frame, transition ); - - // Push the b_frame on to the stack mlt_frame_push_frame( a_frame, b_frame ); - - // Push the transition method mlt_frame_push_get_image( a_frame, get_image ); return a_frame; -- 2.39.2