* 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.<type>.<name>[<index>]),
and then the convert filter uses these to set Movit parameters on the right
Effects.
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();
}
} // 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 );
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 );
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 );
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 );
#include <glew.h>
#include <mlt++/MltFilter.h>
#include <mlt++/MltDeque.h>
+#include <map>
+#include <string>
#define MAXLISTCOUNT 1024
typedef struct glsl_list_s *glsl_list;
class EffectChain;
class MltInput;
+struct GlslChain
+{
+ EffectChain *effect_chain;
+
+ // All services owned by the effect chain and their associated Movit effect.
+ std::map<mlt_service, Effect*> 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:
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 );
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;
#include <string.h>
#include <stdlib.h>
#include <assert.h>
+#include <string>
#include "filter_glsl_manager.h"
#include <movit/effect_chain.h>
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!
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;
}
#include "filter_glsl_manager.h"
#include <movit/padding_effect.h>
+#include "optional_effect.h"
static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
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<PaddingEffect> );
+ 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;
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;
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;
{
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;
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;
#include "filter_glsl_manager.h"
#include <movit/mirror_effect.h>
+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;
}
#include <assert.h>
#include "filter_glsl_manager.h"
-#include <movit/mix_effect.h>
+#include <movit/multiply_effect.h>
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;
#include "filter_glsl_manager.h"
#include <movit/resample_effect.h>
+#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 );
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<ResampleEffect> );
+ // 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;
#include "filter_glsl_manager.h"
#include <movit/init.h>
#include <movit/padding_effect.h>
+#include "optional_effect.h"
static float alignment_parse( char* align )
{
}
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<PaddingEffect> );
+ *image = (uint8_t *) MLT_FILTER_SERVICE( filter );
+ return error;
}
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 PaddingEffect );
mlt_frame_push_service( frame, filter );
mlt_frame_push_get_image( frame, get_image );
return frame;
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;
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;
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;
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;
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);
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:
--- /dev/null
+#ifndef OPTIONAL_EFFECT_H
+#define OPTIONAL_EFFECT_H
+
+#include <movit/effect.h>
+#include <movit/effect_chain.h>
+#include <assert.h>
+
+// 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 T>
+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
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 );
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;
#include <movit/effect_chain.h>
#include <movit/util.h>
#include <movit/overlay_effect.h>
-#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;