extern mlt_filter filter_affine_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
extern mlt_filter filter_charcoal_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
extern mlt_filter filter_dynamictext_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_filter filter_lift_gamma_gain_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
extern mlt_filter filter_loudness_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
extern mlt_filter filter_invert_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
extern mlt_filter filter_rgblut_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
MLT_REGISTER( filter_type, "charcoal", filter_charcoal_init );
MLT_REGISTER( filter_type, "dynamictext", filter_dynamictext_init );
MLT_REGISTER( filter_type, "invert", filter_invert_init );
+ MLT_REGISTER( filter_type, "lift_gamma_gain", filter_lift_gamma_gain_init );
MLT_REGISTER( filter_type, "loudness", filter_loudness_init );
MLT_REGISTER( filter_type, "rgblut", filter_rgblut_init );
MLT_REGISTER( filter_type, "sepia", filter_sepia_init );
MLT_REGISTER_METADATA( filter_type, "charcoal", metadata, "filter_charcoal.yml" );
MLT_REGISTER_METADATA( filter_type, "dynamictext", metadata, "filter_dynamictext.yml" );
MLT_REGISTER_METADATA( filter_type, "invert", metadata, "filter_invert.yml" );
+ MLT_REGISTER_METADATA( filter_type, "lift_gamma_gain", metadata, "filter_lift_gamma_gain.yml" );
MLT_REGISTER_METADATA( filter_type, "loudness", metadata, "filter_loudness.yml" );
MLT_REGISTER_METADATA( filter_type, "rgblut", metadata, "filter_rgblut.yml" );
MLT_REGISTER_METADATA( filter_type, "sepia", metadata, "filter_sepia.yml" );
--- /dev/null
+/*
+ * filter_lift_gamma_gain.cpp
+ * Copyright (C) 2014 Brian Matherly <pez4brian@yahoo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <framework/mlt.h>
+#include <stdlib.h>
+#include <math.h>
+
+typedef struct
+{
+ uint8_t rlut[256];
+ uint8_t glut[256];
+ uint8_t blut[256];
+ double rlift, glift, blift;
+ double rgamma, ggamma, bgamma;
+ double rgain, ggain, bgain;
+} private_data;
+
+static void refresh_lut( mlt_filter filter, mlt_frame frame )
+{
+ private_data* private = (private_data*)filter->child;
+ 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 );
+ double rlift = mlt_properties_anim_get_double( properties, "lift_r", position, length );
+ double glift = mlt_properties_anim_get_double( properties, "lift_g", position, length );
+ double blift = mlt_properties_anim_get_double( properties, "lift_b", position, length );
+ double rgamma = mlt_properties_anim_get_double( properties, "gamma_r", position, length );
+ double ggamma = mlt_properties_anim_get_double( properties, "gamma_g", position, length );
+ double bgamma = mlt_properties_anim_get_double( properties, "gamma_b", position, length );
+ double rgain = mlt_properties_anim_get_double( properties, "gain_r", position, length );
+ double ggain = mlt_properties_anim_get_double( properties, "gain_g", position, length );
+ double bgain = mlt_properties_anim_get_double( properties, "gain_b", position, length );
+
+ // Only regenerate the LUT if something changed.
+ if( private->rlift != rlift || private->glift != glift || private->blift != blift ||
+ private->rgamma != rgamma || private->ggamma != ggamma || private->bgamma != bgamma ||
+ private->rgain != rgain || private->ggain != ggain || private->bgain != bgain )
+ {
+ int i = 0;
+ for( i = 0; i < 256; i++ )
+ {
+ // Convert to gamma 2.2
+ double gamma22 = pow( (double)i / 255.0, 1.0f / 2.2f );
+ double r = gamma22;
+ double g = gamma22;
+ double b = gamma22;
+
+ // Apply lift
+ r += rlift * ( 1 - r );
+ g += glift * ( 1 - g );
+ b += blift * ( 1 - b );
+
+ // Apply gamma
+ r = pow( r, 2.2f / rgamma );
+ g = pow( g, 2.2f / ggamma );
+ b = pow( b, 2.2f / bgamma );
+
+ // Apply gain
+ r *= pow( rgain, 1.0f / rgamma );
+ g *= pow( ggain, 1.0f / ggamma );
+ b *= pow( bgain, 1.0f / bgamma );
+
+ // Update LUT
+ private->rlut[ i ] = (int)(r * 255.0);
+ private->glut[ i ] = (int)(g * 255.0);
+ private->blut[ i ] = (int)(b * 255.0);
+ }
+
+ // Store the values that created the LUT so that
+ // changes can be detected.
+ private->rlift = rlift;
+ private->glift = glift;
+ private->blift = blift;
+ private->rgamma = rgamma;
+ private->ggamma = ggamma;
+ private->bgamma = bgamma;
+ private->rgain = rgain;
+ private->ggain = ggain;
+ private->bgain = bgain;
+ }
+}
+
+static void apply_lut( mlt_filter filter, uint8_t* image, mlt_image_format format, int width, int height )
+{
+ private_data* private = (private_data*)filter->child;
+ int total = width * height + 1;
+ uint8_t* sample = image;
+
+ switch( format )
+ {
+ case mlt_image_rgb24:
+ while( --total )
+ {
+ *sample = private->rlut[ *sample ];
+ sample++;
+ *sample = private->glut[ *sample ];
+ sample++;
+ *sample = private->blut[ *sample ];
+ sample++;
+ }
+ break;
+ case mlt_image_rgb24a:
+ while( --total )
+ {
+ *sample = private->rlut[ *sample ];
+ sample++;
+ *sample = private->glut[ *sample ];
+ sample++;
+ *sample = private->blut[ *sample ];
+ sample++;
+ sample++; // Skip alpha
+ }
+ break;
+ default:
+ mlt_log_error( MLT_FILTER_SERVICE( filter ), "Invalid image format: %s\n", mlt_image_format_name( format ) );
+ break;
+ }
+}
+
+static int filter_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 );
+ int error = 0;
+
+ mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
+
+ // Regenerate the LUT if necessary
+ refresh_lut( filter, frame );
+
+ // Make sure the format is acceptable
+ if( *format != mlt_image_rgb24 && *format != mlt_image_rgb24a )
+ {
+ *format = mlt_image_rgb24;
+ }
+
+ // Get the image
+ writable = 1;
+ error = mlt_frame_get_image( frame, image, format, width, height, writable );
+
+ // Apply the LUT
+ if( !error )
+ {
+ apply_lut( filter, *image, *format, *width, *height );
+ }
+
+ mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
+
+ return error;
+}
+
+static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
+{
+ mlt_frame_push_service( frame, filter );
+ mlt_frame_push_get_image( frame, filter_get_image );
+ return frame;
+}
+
+static void filter_close( mlt_filter filter )
+{
+ private_data* private = (private_data*)filter->child;
+
+ if ( private )
+ {
+ free( private );
+ }
+ filter->child = NULL;
+ filter->close = NULL;
+ filter->parent.close = NULL;
+ mlt_service_close( &filter->parent );
+}
+
+mlt_filter filter_lift_gamma_gain_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+ mlt_filter filter = mlt_filter_new();
+ private_data* private = (private_data*)calloc( 1, sizeof(private_data) );
+ int i = 0;
+
+ if ( filter && private )
+ {
+ mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+
+ // Initialize private data
+ for( i = 0; i < 256; i++ )
+ {
+ private->rlut[i] = i;
+ private->glut[i] = i;
+ private->blut[i] = i;
+ }
+ private->rlift = private->glift = private->blift = 0.0;
+ private->rgamma = private->ggamma = private->bgamma = 1.0;
+ private->rgain = private->ggain = private->bgain = 1.0;
+
+ // Initialize filter properties
+ mlt_properties_set_double( properties, "lift_r", private->rlift );
+ mlt_properties_set_double( properties, "lift_g", private->glift );
+ mlt_properties_set_double( properties, "lift_b", private->blift );
+ mlt_properties_set_double( properties, "gamma_r", private->rgamma );
+ mlt_properties_set_double( properties, "gamma_g", private->ggamma );
+ mlt_properties_set_double( properties, "gamma_b", private->bgamma );
+ mlt_properties_set_double( properties, "gain_r", private->rgain );
+ mlt_properties_set_double( properties, "gain_g", private->ggain );
+ mlt_properties_set_double( properties, "gain_b", private->bgain );
+
+ filter->close = filter_close;
+ filter->process = filter_process;
+ filter->child = private;
+ }
+ else
+ {
+ mlt_log_error( MLT_FILTER_SERVICE(filter), "Filter lift_gamma_gain init failed\n" );
+
+ if( filter )
+ {
+ mlt_filter_close( filter );
+ filter = NULL;
+ }
+
+ if( private )
+ {
+ free( private );
+ }
+ }
+
+ return filter;
+}