double max_gain - a floating point or decibel value of the maximum gain that
can be applied during normalisation.
- an unspecified value uses the default 20dB
+
+ string end - a gain value just like the gain property above.
+ This causes the gain to be interpolated from 'gain' to 'end'
+ over the duration.
+
+ int window - the size of the normalising smoothing buffer in video frame units.
+ - the smoothing buffer prevents erratic gain changes.
+ - the default value is 75 video frames.
+
+ gain can be applied as a factor to the normalise amplitude!
Dependencies
string interpolation - see constructor argument above
+ If a property "consumer_aspect_ratio" exists on the frame, then
+ rescaler normalises the producer's aspect ratio and maximises the
+ size of the frame, but may not produce the consumer's requested
+ dimension. Therefore, this option works best in conjunction with the
+ resize filter. This behavior can be disabled by another service by
+ either removing the property, setting it to zero, or setting
+ frame property "distort" to 1.
+
Dependencies
libgdk_pixbuf-2.0, libglib-2.0, libgobject-2.0, libgmodule-2.0
Constructor Argument
- mix - see below
+ start - see below
Initalisation Properties
Mutable Properties
- double mix - the mix level to apply to the second frame.
- - any negative value causes an automatic crossfade.
+ double start - the mix level to apply to the second frame.
+ - any negative value causes an automatic crossfade from 0 to 1.
+ double end - the ending value of the mix level. mix level will be interpolated
+ from start to end over the in-out range.
+ int reverse - set to 1 to reverse the direction of the mix.
Read Only Properties
return input;
}
-int mlt_frame_mix_audio( mlt_frame this, mlt_frame that, float weight, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+int mlt_frame_mix_audio( mlt_frame this, mlt_frame that, float weight_start, float weight_end, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
{
int ret = 0;
int16_t *p_src, *p_dest;
*buffer = p_dest;
*frequency = frequency_dest;
+ // Compute a smooth ramp over start to end
+ float weight = weight_start;
+ float weight_step = ( weight_end - weight_start ) / *samples;
+
// Mixdown
for ( i = 0; i < *samples; i++ )
{
s = (double) src[ i * channels_src + j ];
dest[ i * channels_dest + j ] = s * weight + d * ( 1.0 - weight );
}
+ weight += weight_step;
}
// We have to copy --sigh
extern uint8_t *mlt_frame_resize_yuv422( mlt_frame this, int owidth, int oheight );
extern uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight );
extern void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input, int iwidth, int iheight );
-extern int mlt_frame_mix_audio( mlt_frame this, mlt_frame that, float weight, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
+extern int mlt_frame_mix_audio( mlt_frame this, mlt_frame that, float weight_start, float weight_end, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples );
extern int mlt_sample_calculator( float fps, int frequency, int64_t position );
#endif
filter_volume.o \
transition_composite.o \
transition_luma.o \
- transition_mix.o
+ transition_mix.o \
+ filter_brightness.o
CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread
resize libmltcore.so
volume libmltcore.so
obscure libmltcore.so
+brightness libmltcore.so
EOF
cat << EOF >> ../transitions.dat
#include "transition_composite.h"
#include "transition_luma.h"
#include "transition_mix.h"
+#include "filter_brightness.h"
void *mlt_create_producer( char *id, void *arg )
{
return filter_resize_init( arg );
if ( !strcmp( id, "volume" ) )
return filter_volume_init( arg );
+ if ( !strcmp( id, "brightness" ) )
+ return filter_brightness_init( arg );
return NULL;
}
--- /dev/null
+/*
+ * filter_brightness.c -- gamma filter
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "filter_brightness.h"
+
+#include <framework/mlt_frame.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+/** Do it :-).
+*/
+
+static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+ mlt_frame_get_image( this, image, format, width, height, 1 );
+ uint8_t *p = *image;
+ uint8_t *q = *image + *width * *height * 2;
+
+ // Get the brightness level
+ double level = mlt_properties_get_double( mlt_frame_properties( this ), "brightness.level" );
+
+ while ( p != q )
+ {
+ float x = (float) *p * level;
+ *p = x < 16 ? 16 : x > 235 ? 235 : x;
+ p += 2;
+ }
+
+ return 0;
+}
+
+/** Filter processing.
+*/
+
+static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
+{
+ double level = fabs( mlt_properties_get_double( mlt_filter_properties( this ), "start" ) );
+
+ // If there is an end adjust gain to the range
+ if ( mlt_properties_get( mlt_filter_properties( this ), "end" ) != NULL )
+ {
+ // Determine the time position of this frame in the transition duration
+ mlt_position in = mlt_filter_get_in( this );
+ mlt_position out = mlt_filter_get_out( this );
+ mlt_position time = mlt_frame_get_position( frame );
+ double position = ( double )( time - in ) / ( double )( out - in + 1 );
+ double end = fabs( mlt_properties_get_double( mlt_filter_properties( this ), "end" ) );
+ level += ( end - level ) * position;
+ }
+ mlt_frame_push_get_image( frame, filter_get_image );
+ mlt_properties_set_double( mlt_frame_properties( frame ), "brightness.level", level );
+ return frame;
+}
+
+/** Constructor for the filter.
+*/
+
+mlt_filter filter_brightness_init( char *arg )
+{
+ mlt_filter this = calloc( sizeof( struct mlt_filter_s ), 1 );
+ if ( this != NULL )
+ {
+ mlt_filter_init( this, NULL );
+ this->process = filter_process;
+ if ( arg != NULL )
+ mlt_properties_set_double( mlt_filter_properties( this ), "start", atof( arg ) );
+ }
+ return this;
+}
+
--- /dev/null
+/*
+ * filter_brightness.h -- gamma filter
+ * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Author: Charles Yates <charles.yates@pandora.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _FILTER_BRIGHTNESS_H_
+#define _FILTER_BRIGHTNESS_H_
+
+#include <framework/mlt_filter.h>
+
+extern mlt_filter filter_brightness_init( char *arg );
+
+#endif
{
// Get the properties of the a frame
mlt_properties properties = mlt_frame_properties( frame );
- double gain = mlt_properties_get_double( properties, "gain" );
+ double gain = mlt_properties_get_double( properties, "volume.gain" );
double max_gain = mlt_properties_get_double( properties, "volume.max_gain" );
double limiter_level = 0.5; /* -6 dBFS */
int normalise = mlt_properties_get_int( properties, "volume.normalise" );
double amplitude = mlt_properties_get_double( properties, "volume.amplitude" );
- int i;
+ int i, j;
double sample;
int16_t peak;
+ // Get the filter from the frame
+ mlt_filter this = mlt_properties_get_data( properties, "filter_volume", NULL );
+
+ // Get the properties from the filter
+ mlt_properties filter_props = mlt_filter_properties( this );
+
if ( mlt_properties_get( properties, "volume.limiter" ) != NULL )
limiter_level = mlt_properties_get_double( properties, "volume.limiter" );
if ( normalise )
{
- int window = mlt_properties_get_int( properties, "volume.window" );
- double *smooth_buffer = mlt_properties_get_data( properties, "volume.smooth_buffer", NULL );
- int *smooth_index = mlt_properties_get_data( properties, "volume.smooth_index", NULL );
+ int window = mlt_properties_get_int( filter_props, "window" );
+ double *smooth_buffer = mlt_properties_get_data( filter_props, "smooth_buffer", NULL );
+ int *smooth_index = mlt_properties_get_data( filter_props, "smooth_index", NULL );
if ( window > 0 && smooth_buffer != NULL )
{
}
else
{
- gain = amplitude / signal_max_power( *buffer, *channels, *samples, &peak );
+ gain *= amplitude / signal_max_power( *buffer, *channels, *samples, &peak );
}
}
if ( max_gain > 0 && gain > max_gain )
gain = max_gain;
+ // Initialise filter's previous gain value to prevent an inadvertant jump from 0
+ if ( mlt_properties_get( filter_props, "previous_gain" ) == NULL )
+ mlt_properties_set_double( filter_props, "previous_gain", gain );
+
+ // Start the gain out at the previous
+ double previous_gain = mlt_properties_get_double( filter_props, "previous_gain" );
+
+ // Determine ramp increment
+ double gain_step = ( gain - previous_gain ) / *samples;
+// fprintf( stderr, "filter_volume: previous gain %f current gain %f step %f\n", previous_gain, gain, gain_step );
+
+ // Save the current gain for the next iteration
+ mlt_properties_set_double( filter_props, "previous_gain", gain );
+
+ // Ramp from the previous gain to the current
+ gain = previous_gain;
+
+ int16_t *p = *buffer;
+
// Apply the gain
- for ( i = 0; i < ( *channels * *samples ); i++ )
+ for ( i = 0; i < *samples; i++ )
{
- sample = (*buffer)[i] * gain;
- (*buffer)[i] = ROUND( sample );
-
- if ( gain > 1.0 )
+ for ( j = 0; j < *channels; j++ )
{
- /* use limiter function instead of clipping */
- if ( normalise )
- (*buffer)[i] = ROUND( samplemax * limiter( sample / (double) samplemax, limiter_level ) );
+ sample = *p * gain;
+ *p = ROUND( sample );
+
+ if ( gain > 1.0 )
+ {
+ /* use limiter function instead of clipping */
+ if ( normalise )
+ *p = ROUND( samplemax * limiter( sample / (double) samplemax, limiter_level ) );
- /* perform clipping */
- else if ( sample > samplemax )
- (*buffer)[i] = samplemax;
- else if ( sample < samplemin )
- (*buffer)[i] = samplemin;
+ /* perform clipping */
+ else if ( sample > samplemax )
+ *p = samplemax;
+ else if ( sample < samplemin )
+ *p = samplemin;
+ }
+ p++;
}
+ gain += gain_step;
}
return 0;
mlt_properties properties = mlt_frame_properties( frame );
mlt_properties filter_props = mlt_filter_properties( this );
- // Propogate the gain property
+ // Parse the gain property
if ( mlt_properties_get( properties, "gain" ) == NULL )
{
double gain = 1.0; // no adjustment
/* check if "dB" is given after number */
if ( strncaseeq( p, "db", 2 ) )
gain = DBFSTOAMP( gain );
+
+ // If there is an end adjust gain to the range
+ if ( mlt_properties_get( filter_props, "end" ) != NULL )
+ {
+ // Determine the time position of this frame in the transition duration
+ mlt_position in = mlt_filter_get_in( this );
+ mlt_position out = mlt_filter_get_out( this );
+ mlt_position time = mlt_frame_get_position( frame );
+ double position = ( double )( time - in ) / ( double )( out - in + 1 );
+
+ double end = -1;
+ char *p = mlt_properties_get( filter_props, "end" );
+ if ( strcmp( p, "" ) != 0 )
+ end = fabs( strtod( p, &p) );
+
+ while ( isspace( *p ) )
+ p++;
+
+ /* check if "dB" is given after number */
+ if ( strncaseeq( p, "db", 2 ) )
+ end = DBFSTOAMP( gain );
+
+ if ( end != -1 )
+ gain += ( end - gain ) * position;
+ }
}
}
- mlt_properties_set_double( properties, "gain", gain );
+ mlt_properties_set_double( properties, "volume.gain", gain );
}
- // Propogate the maximum gain property
+ // Parse the maximum gain property
if ( mlt_properties_get( filter_props, "max_gain" ) != NULL )
{
char *p = mlt_properties_get( filter_props, "max_gain" );
mlt_properties_set_double( properties, "volume.max_gain", gain );
}
- // Parse and propogate the limiter property
+ // Parse the limiter property
if ( mlt_properties_get( filter_props, "limiter" ) != NULL )
{
char *p = mlt_properties_get( filter_props, "limiter" );
mlt_properties_set_double( properties, "volume.limiter", level );
}
- // Parse and propogate the normalise property
+ // Parse the normalise property
if ( mlt_properties_get( filter_props, "normalise" ) != NULL )
{
char *p = mlt_properties_get( filter_props, "normalise" );
if ( amplitude > 1.0 )
amplitude = 1.0;
}
+
+ // If there is an end adjust gain to the range
+ if ( mlt_properties_get( filter_props, "end" ) != NULL )
+ {
+ // Determine the time position of this frame in the transition duration
+ mlt_position in = mlt_filter_get_in( this );
+ mlt_position out = mlt_filter_get_out( this );
+ mlt_position time = mlt_frame_get_position( frame );
+ double position = ( double )( time - in ) / ( double )( out - in + 1 );
+ amplitude *= position;
+ }
mlt_properties_set_int( properties, "volume.normalise", 1 );
mlt_properties_set_double( properties, "volume.amplitude", amplitude );
}
+ // Parse the window property and allocate smoothing buffer if needed
int window = mlt_properties_get_int( filter_props, "window" );
if ( mlt_properties_get( filter_props, "smooth_buffer" ) == NULL && window > 1 )
{
mlt_properties_set_data( filter_props, "smooth_index", smooth_index, 0, free, NULL );
}
- // Propogate the smoothing buffer properties
- mlt_properties_set_int( properties, "volume.window", window );
- mlt_properties_set_data( properties, "volume.smooth_buffer",
- mlt_properties_get_data( filter_props, "smooth_buffer", NULL ), 0, NULL, NULL );
- mlt_properties_set_data( properties, "volume.smooth_index",
- mlt_properties_get_data( filter_props, "smooth_index", NULL ), 0, NULL, NULL );
+ // Put a filter reference onto the frame
+ mlt_properties_set_data( properties, "filter_volume", this, 0, NULL, NULL );
// Backup the original get_audio (it's still needed)
mlt_properties_set_data( properties, "volume.get_audio", frame->get_audio, 0, NULL, NULL );
// Restore the original get_audio
frame->get_audio = mlt_properties_get_data( a_props, "mix.get_audio", NULL );
- double mix = 0.5;
+ double mix_start = 0.5, mix_end = 0.5;
+ if ( mlt_properties_get( b_props, "audio.previous_mix" ) != NULL )
+ mix_start = mlt_properties_get_double( b_props, "audio.previous_mix" );
if ( mlt_properties_get( b_props, "audio.mix" ) != NULL )
- mix = mlt_properties_get_double( b_props, "audio.mix" );
+ mix_end = mlt_properties_get_double( b_props, "audio.mix" );
if ( mlt_properties_get_int( b_props, "audio.reverse" ) )
- mix = 1 - mix;
+ {
+ mix_start = 1 - mix_start;
+ mix_end = 1 - mix_end;
+ }
+ //fprintf( stderr, "transition_mix: previous %f current %f\n", mix_start, mix_end );
- mlt_frame_mix_audio( frame, b_frame, mix, buffer, format, frequency, channels, samples );
+ mlt_frame_mix_audio( frame, b_frame, mix_start, mix_end, buffer, format, frequency, channels, samples );
// Push the b_frame back on for get_image
mlt_frame_push_frame( frame, b_frame );
mlt_properties b_props = mlt_frame_properties( b_frame );
// Only if mix is specified, otherwise a producer may set the mix
- if ( mlt_properties_get( properties, "mix" ) != NULL )
+ if ( mlt_properties_get( properties, "start" ) != NULL )
{
- // A negative means crossfade
- if ( mlt_properties_get_double( properties, "mix" ) < 0 )
+ // Determine the time position of this frame in the transition duration
+ mlt_position in = mlt_transition_get_in( this );
+ mlt_position out = mlt_transition_get_out( this );
+ mlt_position time = mlt_frame_get_position( b_frame );
+ double mix = ( double )( time - in ) / ( double )( out - in + 1 );
+
+ // If there is an end mix level adjust mix to the range
+ if ( mlt_properties_get( properties, "end" ) != NULL )
+ {
+ double start = mlt_properties_get_double( properties, "start" );
+ double end = mlt_properties_get_double( properties, "end" );
+ mix = start + ( end - start ) * mix;
+ }
+ // A negative means total crossfade (uses position)
+ else if ( mlt_properties_get_double( properties, "start" ) >= 0 )
{
- // Determine the time position of this frame in the transition duration
- mlt_position in = mlt_transition_get_in( this );
- mlt_position out = mlt_transition_get_out( this );
- mlt_position time = mlt_frame_get_position( b_frame );
- double mix = ( double )( time - in ) / ( double )( out - in + 1 );
- mlt_properties_set_double( b_props, "audio.mix", mix );
+ // Otherwise, start/constructor is a constant mix level
+ mix = mlt_properties_get_double( properties, "start" );
}
- else
- mlt_properties_set_double( b_props, "audio.mix", mlt_properties_get_double( properties, "mix" ) );
+
+ // Finally, set the mix property on the frame
+ mlt_properties_set_double( b_props, "audio.mix", mix );
+
+ // Initialise transition previous mix value to prevent an inadvertant jump from 0
+ if ( mlt_properties_get( properties, "previous_mix" ) == NULL )
+ mlt_properties_set_double( properties, "previous_mix", mlt_properties_get_double( b_props, "audio.mix" ) );
+
+ // Tell b frame what the previous mix level was
+ mlt_properties_set_double( b_props, "audio.previous_mix", mlt_properties_get_double( properties, "previous_mix" ) );
+
+ // Save the current mix level for the next iteration
+ mlt_properties_set_double( properties, "previous_mix", mlt_properties_get_double( b_props, "audio.mix" ) );
+
mlt_properties_set_double( b_props, "audio.reverse", mlt_properties_get_double( properties, "reverse" ) );
}
{
this->process = transition_process;
if ( arg != NULL )
- mlt_properties_set_double( mlt_transition_properties( this ), "mix", atof( arg ) );
+ mlt_properties_set_double( mlt_transition_properties( this ), "start", atof( arg ) );
}
return this;
}
int owidth = *width;
int oheight = *height;
uint8_t *input = NULL;
-
char *interps = mlt_properties_get( properties, "rescale.interp" );
int interp = PIXOPS_INTERP_BILINEAR;
+ double i_aspect_ratio = mlt_frame_get_aspect_ratio( this );
+ double o_aspect_ratio = mlt_properties_get_double( properties, "consumer_aspect_ratio" );
+
if ( strcmp( interps, "nearest" ) == 0 )
interp = PIXOPS_INTERP_NEAREST;
else if ( strcmp( interps, "tiles" ) == 0 )
mlt_frame_get_image( this, &input, format, &iwidth, &iheight, 0 );
-#if 0
- // Determine maximum size within the aspect ratio:
- double i_aspect_ratio = mlt_frame_get_aspect_ratio( this );
- // TODO: this needs to be provided q
- #define o_aspect_ratio ( double )( 4.0 / 3.0 )
-
- if ( ( owidth * i_aspect_ratio * o_aspect_ratio ) > owidth )
- oheight *= o_aspect_ratio / i_aspect_ratio;
- else
- owidth *= i_aspect_ratio * o_aspect_ratio;
+ if ( o_aspect_ratio != 0 && o_aspect_ratio != i_aspect_ratio && mlt_properties_get_int( properties, "distort" ) == 0 )
+ {
+ // Determine maximum size within the aspect ratio:
- fprintf( stderr, "rescale: from %dx%d (%f) to %dx%d\n", iwidth, iheight, i_aspect_ratio, owidth, oheight );
-#endif
+ if ( ( owidth * i_aspect_ratio * o_aspect_ratio ) > owidth )
+ oheight *= o_aspect_ratio / i_aspect_ratio;
+ else
+ owidth *= i_aspect_ratio * o_aspect_ratio;
+ //fprintf( stderr, "rescale: from %dx%d (aspect %f) to %dx%d (aspect %f)\n", iwidth, iheight, i_aspect_ratio, owidth, oheight, o_aspect_ratio );
+ }
// If width and height are correct, don't do anything
if ( strcmp( interps, "none" ) && input != NULL && ( iwidth != owidth || iheight != oheight ) )