diff -Nru mlt-0.7.6+git20111222/debian/changelog mlt-0.7.6+git20120204/debian/changelog --- mlt-0.7.6+git20111222/debian/changelog 2011-12-22 17:26:03.000000000 +0000 +++ mlt-0.7.6+git20120204/debian/changelog 2012-02-05 12:33:38.000000000 +0000 @@ -1,3 +1,17 @@ +mlt (0.7.6+git20120204-2) unstable; urgency=high + + * Add patch 01-various-upstream-fixes-20120205 which includes various + upstream fixes like fixing a FTBFS with libav on architectures without MMX. + Closes: #658376 + + -- Patrick Matthäi Sun, 05 Feb 2012 13:33:07 +0100 + +mlt (0.7.6+git20120204-1) unstable; urgency=low + + * New upstream git snapshot. + + -- Patrick Matthäi Sat, 04 Feb 2012 14:18:33 +0100 + mlt (0.7.6+git20111222-1) unstable; urgency=low * New upstream git snapshot. diff -Nru mlt-0.7.6+git20111222/debian/patches/01-various-upstream-fixes-20120205.diff mlt-0.7.6+git20120204/debian/patches/01-various-upstream-fixes-20120205.diff --- mlt-0.7.6+git20111222/debian/patches/01-various-upstream-fixes-20120205.diff 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.6+git20120204/debian/patches/01-various-upstream-fixes-20120205.diff 2012-02-05 12:33:38.000000000 +0000 @@ -0,0 +1,135 @@ +# Fix compilation on architectures without MMX and libav 0.8. +# Closes: #658376 +# Hopefuly it will also fix a bug with libav 0.8 where your video gets inverted colors. +# Closes: #657871 + +diff -Naur mlt-0.7.6+git20120204.orig/src/modules/avformat/consumer_avformat.c mlt-0.7.6+git20120204/src/modules/avformat/consumer_avformat.c +--- mlt-0.7.6+git20120204.orig/src/modules/avformat/consumer_avformat.c 2012-02-04 14:14:54.000000000 +0100 ++++ mlt-0.7.6+git20120204/src/modules/avformat/consumer_avformat.c 2012-02-05 13:22:39.879438830 +0100 +@@ -394,7 +394,7 @@ + for ( i = 0; i < count; i++ ) + { + const char *opt_name = mlt_properties_get_name( properties, i ); +-#if LIBAVUTIL_VERSION_INT > ((51<<16)+(7<<8)+0) ++#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(10<<8)+0) + const AVOption *opt = av_opt_find( obj, opt_name, NULL, flags, flags ); + #else + const AVOption *opt = av_find_opt( obj, opt_name, NULL, flags, flags ); +@@ -404,7 +404,7 @@ + if ( !opt && ( + ( opt_name[0] == 'v' && ( flags & AV_OPT_FLAG_VIDEO_PARAM ) ) || + ( opt_name[0] == 'a' && ( flags & AV_OPT_FLAG_AUDIO_PARAM ) ) ) ) +-#if LIBAVUTIL_VERSION_INT > ((51<<16)+(7<<8)+0) ++#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(10<<8)+0) + opt = av_opt_find( obj, ++opt_name, NULL, flags, flags ); + #else + opt = av_find_opt( obj, ++opt_name, NULL, flags, flags ); +@@ -1501,15 +1501,16 @@ + fifo = sample_fifo_init( frequency, channels ); + mlt_properties_set_data( properties, "sample_fifo", fifo, 0, ( mlt_destructor )sample_fifo_close, NULL ); + } +- +- // Silence if not normal forward speed +- if ( mlt_properties_get_double( frame_properties, "_speed" ) != 1.0 ) +- memset( pcm, 0, samples * channels * sample_bytes ); +- +- // Append the samples +- sample_fifo_append( fifo, pcm, samples * channels * sample_bytes ); +- total_time += ( samples * 1000000 ) / frequency; +- ++ if ( pcm ) ++ { ++ // Silence if not normal forward speed ++ if ( mlt_properties_get_double( frame_properties, "_speed" ) != 1.0 ) ++ memset( pcm, 0, samples * channels * sample_bytes ); ++ ++ // Append the samples ++ sample_fifo_append( fifo, pcm, samples * channels * sample_bytes ); ++ total_time += ( samples * 1000000 ) / frequency; ++ } + if ( !video_st ) + mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); + } +@@ -1700,7 +1701,7 @@ + + // Do the colour space conversion + #ifdef SWSCALE +- int flags = SWS_BILINEAR; ++ int flags = SWS_BICUBIC; + #ifdef USE_MMX + flags |= SWS_CPU_CAPS_MMX; + #endif +diff -Naur mlt-0.7.6+git20120204.orig/src/modules/avformat/filter_avcolour_space.c mlt-0.7.6+git20120204/src/modules/avformat/filter_avcolour_space.c +--- mlt-0.7.6+git20120204.orig/src/modules/avformat/filter_avcolour_space.c 2011-12-13 19:28:26.000000000 +0100 ++++ mlt-0.7.6+git20120204/src/modules/avformat/filter_avcolour_space.c 2012-02-05 13:22:39.879438830 +0100 +@@ -117,7 +117,7 @@ + AVPicture input; + AVPicture output; + #ifdef SWSCALE +- int flags = SWS_BILINEAR | SWS_ACCURATE_RND; ++ int flags = SWS_BICUBIC | SWS_ACCURATE_RND; + + if ( out_fmt == PIX_FMT_YUYV422 ) + flags |= SWS_FULL_CHR_H_INP; +diff -Naur mlt-0.7.6+git20120204.orig/src/modules/avformat/filter_avdeinterlace.c mlt-0.7.6+git20120204/src/modules/avformat/filter_avdeinterlace.c +--- mlt-0.7.6+git20120204.orig/src/modules/avformat/filter_avdeinterlace.c 2011-03-15 18:55:45.000000000 +0100 ++++ mlt-0.7.6+git20120204/src/modules/avformat/filter_avdeinterlace.c 2012-02-05 13:22:39.879438830 +0100 +@@ -31,7 +31,7 @@ + #include "mmx.h" + #else + #define MAX_NEG_CROP 1024 +-extern uint8_t ff_cropTbl[256 + 2 * MAX_NEG_CROP]; ++static uint8_t ff_cropTbl[256 + 2 * MAX_NEG_CROP] = {0,}; + #endif + + #ifdef USE_MMX +@@ -346,6 +346,17 @@ + + mlt_filter filter_avdeinterlace_init( void *arg ) + { ++#ifndef USE_MMX ++ if ( ff_cropTbl[MAX_NEG_CROP + 1] == 0 ) ++ { ++ int i; ++ for(i=0;i<256;i++) ff_cropTbl[i + MAX_NEG_CROP] = i; ++ for(i=0;iprocess = deinterlace_process; +diff -Naur mlt-0.7.6+git20120204.orig/src/modules/avformat/producer_avformat.c mlt-0.7.6+git20120204/src/modules/avformat/producer_avformat.c +--- mlt-0.7.6+git20120204.orig/src/modules/avformat/producer_avformat.c 2012-02-04 14:14:54.000000000 +0100 ++++ mlt-0.7.6+git20120204/src/modules/avformat/producer_avformat.c 2012-02-05 13:22:39.883438678 +0100 +@@ -1247,7 +1247,7 @@ + { + #ifdef SWSCALE + int full_range = -1; +- int flags = SWS_BILINEAR | SWS_ACCURATE_RND; ++ int flags = SWS_BICUBIC | SWS_ACCURATE_RND; + + #ifdef USE_MMX + flags |= SWS_CPU_CAPS_MMX; +@@ -1799,7 +1799,7 @@ + for ( i = 0; i < count; i++ ) + { + const char *opt_name = mlt_properties_get_name( properties, i ); +-#if LIBAVUTIL_VERSION_INT > ((51<<16)+(7<<8)+0) ++#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(10<<8)+0) + const AVOption *opt = av_opt_find( obj, opt_name, NULL, flags, flags ); + #else + const AVOption *opt = av_find_opt( obj, opt_name, NULL, flags, flags ); +diff -Naur mlt-0.7.6+git20120204.orig/src/modules/core/producer_consumer.c mlt-0.7.6+git20120204/src/modules/core/producer_consumer.c +--- mlt-0.7.6+git20120204.orig/src/modules/core/producer_consumer.c 2012-02-04 14:14:54.000000000 +0100 ++++ mlt-0.7.6+git20120204/src/modules/core/producer_consumer.c 2012-02-05 13:22:39.883438678 +0100 +@@ -141,6 +141,7 @@ + + // Since we control the seeking, prevent it from seeking on its own + mlt_producer_set_speed( cx->producer, 0 ); ++ cx->audio_position = -1; + + // We will encapsulate a consumer + cx->consumer = mlt_consumer_new( cx->profile ); diff -Nru mlt-0.7.6+git20111222/debian/patches/series mlt-0.7.6+git20120204/debian/patches/series --- mlt-0.7.6+git20111222/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.6+git20120204/debian/patches/series 2012-02-05 12:33:38.000000000 +0000 @@ -0,0 +1 @@ +01-various-upstream-fixes-20120205.diff diff -Nru mlt-0.7.6+git20111222/docs/mlt-xml.txt mlt-0.7.6+git20120204/docs/mlt-xml.txt --- mlt-0.7.6+git20111222/docs/mlt-xml.txt 2011-05-26 16:34:35.000000000 +0000 +++ mlt-0.7.6+git20120204/docs/mlt-xml.txt 2012-02-04 13:14:54.000000000 +0000 @@ -202,6 +202,7 @@ + @@ -256,6 +257,7 @@ + diff -Nru mlt-0.7.6+git20111222/mlt-framework.pc mlt-0.7.6+git20120204/mlt-framework.pc --- mlt-0.7.6+git20111222/mlt-framework.pc 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.6+git20120204/mlt-framework.pc 2011-05-29 12:48:57.000000000 +0000 @@ -0,0 +1,16 @@ +prefix=/usr/local +exec_prefix=/usr/local +libdir=/usr/local/lib +includedir=/usr/local/include +datadir=/usr/local/share +mandir=/usr/local/share/man +version=0.7.3 +cflags=-I/usr/local/include -I/usr/local/include/mlt -D_REENTRANT +libs=-L/usr/local/lib -lmlt + +Name: mlt-framework +Description: MLT multimedia framework +Version: ${version} +Requires: +Libs: -L${libdir} ${libs} +Cflags: ${cflags} diff -Nru mlt-0.7.6+git20111222/mlt++.pc mlt-0.7.6+git20120204/mlt++.pc --- mlt-0.7.6+git20111222/mlt++.pc 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.6+git20120204/mlt++.pc 2011-05-29 12:48:57.000000000 +0000 @@ -0,0 +1,16 @@ +prefix=/usr/local +exec_prefix=/usr/local +libdir=/usr/local/lib +includedir=/usr/local/include +datadir=/usr/local/share +mandir=/usr/local/share/man +version=0.7.3 +cflags=-I/usr/local/include -I/usr/local/include/mlt++ -D_REENTRANT +libs=-L/usr/local/lib -lmlt++ + +Name: mlt++ +Description: C++ API for MLT multimedia framework +Version: ${version} +Requires: mlt-framework +Libs: -L${libdir} ${libs} +Cflags: ${cflags} diff -Nru mlt-0.7.6+git20111222/packages.dat mlt-0.7.6+git20120204/packages.dat --- mlt-0.7.6+git20111222/packages.dat 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.6+git20120204/packages.dat 2011-05-29 12:48:57.000000000 +0000 @@ -0,0 +1,2 @@ +framework -I/usr/local/include -I/usr/local/include/mlt -D_REENTRANT -L/usr/local/lib -lmlt +mlt++ -I/usr/local/include -I/usr/local/include/mlt++ -D_REENTRANT -L/usr/local/lib -lmlt++ diff -Nru mlt-0.7.6+git20111222/src/framework/mlt_producer.h mlt-0.7.6+git20120204/src/framework/mlt_producer.h --- mlt-0.7.6+git20111222/src/framework/mlt_producer.h 2011-05-26 16:34:35.000000000 +0000 +++ mlt-0.7.6+git20120204/src/framework/mlt_producer.h 2012-02-04 13:14:54.000000000 +0000 @@ -36,7 +36,7 @@ * service network - that could be through synthesis or reading a stream. * * \extends mlt_service - * \event \em producer-changed + * \event \em producer-changed either service-changed was fired or the timing of the producer changed * \properties \em mlt_type the name of the service subclass, e.g. mlt_producer * \properties \em mlt_service the name of a producer subclass * \properties \em _position the current position of the play head, relative to the in point diff -Nru mlt-0.7.6+git20111222/src/framework/mlt_service.c mlt-0.7.6+git20120204/src/framework/mlt_service.c --- mlt-0.7.6+git20111222/src/framework/mlt_service.c 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/framework/mlt_service.c 2012-02-04 13:14:54.000000000 +0000 @@ -265,7 +265,7 @@ /** Disconnect a service from its consumer. * - * \public \memberof mlt_service_s + * \private \memberof mlt_service_s * \param self a service */ @@ -521,6 +521,19 @@ mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "service-changed", NULL ); } +/** The property-changed event handler. + * + * \private \memberof mlt_service_s + * \param owner ignored + * \param self the service on which the "property-changed" event is fired + * \param name the name of the property that changed + */ + +static void mlt_service_filter_property_changed( mlt_service owner, mlt_service self, char *name ) +{ + mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "property-changed", name, NULL ); +} + /** Attach a filter. * * \public \memberof mlt_service_s @@ -559,7 +572,7 @@ mlt_events_fire( properties, "service-changed", NULL ); mlt_events_fire( props, "service-changed", NULL ); mlt_events_listen( props, self, "service-changed", ( mlt_listener )mlt_service_filter_changed ); - mlt_events_listen( props, self, "property-changed", ( mlt_listener )mlt_service_filter_changed ); + mlt_events_listen( props, self, "property-changed", ( mlt_listener )mlt_service_filter_property_changed ); } else { diff -Nru mlt-0.7.6+git20111222/src/framework/mlt_service.h mlt-0.7.6+git20120204/src/framework/mlt_service.h --- mlt-0.7.6+git20111222/src/framework/mlt_service.h 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/framework/mlt_service.h 2012-02-04 13:14:54.000000000 +0000 @@ -39,7 +39,7 @@ * connections a "service network," which is similar to what DirectShow calls * a filter graph or what gstreamer calls an element pipeline. * - * \event \em service-changed + * \event \em service-changed a filter was attached or detached or a transition was connected or disconnected * \event \em property-changed * \properties \em mlt_type identifies the subclass * \properties \em _mlt_service_hidden a flag that indicates whether to hide the mlt_service diff -Nru mlt-0.7.6+git20111222/src/framework/mlt_types.h mlt-0.7.6+git20120204/src/framework/mlt_types.h --- mlt-0.7.6+git20111222/src/framework/mlt_types.h 2011-12-20 18:07:08.000000000 +0000 +++ mlt-0.7.6+git20120204/src/framework/mlt_types.h 2012-02-04 13:14:54.000000000 +0000 @@ -2,7 +2,7 @@ * \file mlt_types.h * \brief Provides forward definitions of all public types * - * Copyright (C) 2003-2009 Ushodaya Enterprises Limited + * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * \author Charles Yates * * This library is free software; you can redistribute it and/or @@ -57,8 +57,8 @@ mlt_audio_s16 = 1, /**< signed 16-bit interleaved PCM */ mlt_audio_s32, /**< signed 32-bit non-interleaved PCM */ mlt_audio_float, /**< 32-bit non-interleaved floating point */ - mlt_audio_s32le, /**< signed 32-bit interleaved PCM, may only used by producers */ - mlt_audio_f32le /**< 32-bit interleaved floating point, may only be used by producers */ + mlt_audio_s32le, /**< signed 32-bit interleaved PCM */ + mlt_audio_f32le /**< 32-bit interleaved floating point */ } mlt_audio_format; diff -Nru mlt-0.7.6+git20111222/src/mlt++/config.mak mlt-0.7.6+git20120204/src/mlt++/config.mak --- mlt-0.7.6+git20111222/src/mlt++/config.mak 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.6+git20120204/src/mlt++/config.mak 2011-05-29 12:48:57.000000000 +0000 @@ -0,0 +1,4 @@ +soversion=3 +LIBSUF=.so +CXXFLAGS+=-Wall -W -Wwrite-strings -Wcast-qual -Wpointer-arith -Wcast-align -Wredundant-decls -fPIC -DPIC +LIBFLAGS=-shared diff -Nru mlt-0.7.6+git20111222/src/modules/avformat/consumer_avformat.c mlt-0.7.6+git20120204/src/modules/avformat/consumer_avformat.c --- mlt-0.7.6+git20111222/src/modules/avformat/consumer_avformat.c 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/avformat/consumer_avformat.c 2012-02-04 13:14:54.000000000 +0000 @@ -1,7 +1,8 @@ /* * consumer_avformat.c -- an encoder based on avformat - * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Charles Yates + * Author: Dan Dennedy * Much code borrowed from ffmpeg.c: Copyright (c) 2000-2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -44,6 +45,16 @@ #if LIBAVUTIL_VERSION_INT >= ((50<<16)+(8<<8)+0) #include #endif +#include + +#if LIBAVUTIL_VERSION_INT >= ((50<<16)+(38<<8)+0) +# include +#else +# define AV_SAMPLE_FMT_NONE SAMPLE_FMT_NONE +# define AV_SAMPLE_FMT_S16 SAMPLE_FMT_S16 +# define AV_SAMPLE_FMT_S32 SAMPLE_FMT_S32 +# define AV_SAMPLE_FMT_FLT SAMPLE_FMT_FLT +#endif #if LIBAVUTIL_VERSION_INT < (50<<16) #define PIX_FMT_RGB32 PIX_FMT_RGBA32 @@ -64,16 +75,13 @@ #define AUDIO_BUFFER_SIZE (1024 * 42) #define VIDEO_BUFFER_SIZE (2048 * 1024) -void avformat_lock( ); -void avformat_unlock( ); - // // This structure should be extended and made globally available in mlt // typedef struct { - int16_t *buffer; + uint8_t *buffer; int size; int used; double time; @@ -90,42 +98,16 @@ return fifo; } -// sample_fifo_clear and check are temporarily aborted (not working as intended) - -void sample_fifo_clear( sample_fifo fifo, double time ) -{ - int words = ( float )( time - fifo->time ) * fifo->frequency * fifo->channels; - if ( ( int )( ( float )time * 100 ) < ( int )( ( float )fifo->time * 100 ) && fifo->used > words && words > 0 ) - { - memmove( fifo->buffer, &fifo->buffer[ words ], ( fifo->used - words ) * sizeof( int16_t ) ); - fifo->used -= words; - fifo->time = time; - } - else if ( ( int )( ( float )time * 100 ) != ( int )( ( float )fifo->time * 100 ) ) - { - fifo->used = 0; - fifo->time = time; - } -} - -void sample_fifo_check( sample_fifo fifo, double time ) -{ - if ( fifo->used == 0 ) - { - if ( ( int )( ( float )time * 100 ) < ( int )( ( float )fifo->time * 100 ) ) - fifo->time = time; - } -} - -void sample_fifo_append( sample_fifo fifo, int16_t *samples, int count ) +// count is the number of samples multiplied by the number of bytes per sample +void sample_fifo_append( sample_fifo fifo, uint8_t *samples, int count ) { if ( ( fifo->size - fifo->used ) < count ) { fifo->size += count * 5; - fifo->buffer = realloc( fifo->buffer, fifo->size * sizeof( int16_t ) ); + fifo->buffer = realloc( fifo->buffer, fifo->size ); } - memcpy( &fifo->buffer[ fifo->used ], samples, count * sizeof( int16_t ) ); + memcpy( &fifo->buffer[ fifo->used ], samples, count ); fifo->used += count; } @@ -134,14 +116,14 @@ return fifo->used; } -int sample_fifo_fetch( sample_fifo fifo, int16_t *samples, int count ) +int sample_fifo_fetch( sample_fifo fifo, uint8_t *samples, int count ) { if ( count > fifo->used ) count = fifo->used; - memcpy( samples, fifo->buffer, count * sizeof( int16_t ) ); + memcpy( samples, fifo->buffer, count ); fifo->used -= count; - memmove( fifo->buffer, &fifo->buffer[ count ], fifo->used * sizeof( int16_t ) ); + memmove( fifo->buffer, &fifo->buffer[ count ], fifo->used ); fifo->time += ( double )count / fifo->channels / fifo->frequency; @@ -196,6 +178,9 @@ mlt_properties_set_double( properties, "muxdelay", 0.7 ); mlt_properties_set_double( properties, "muxpreload", 0.5 ); + // Some AVOption defaults we like + mlt_properties_set( properties, "strict", "experimental" ); + // Ensure termination at end of the stream mlt_properties_set_int( properties, "terminate_on_pause", 1 ); @@ -402,21 +387,33 @@ { int i; int count = mlt_properties_count( properties ); +#if LIBAVUTIL_VERSION_INT < ((51<<16)+(12<<8)+0) int alloc = 1; +#endif for ( i = 0; i < count; i++ ) { const char *opt_name = mlt_properties_get_name( properties, i ); +#if LIBAVUTIL_VERSION_INT > ((51<<16)+(7<<8)+0) + const AVOption *opt = av_opt_find( obj, opt_name, NULL, flags, flags ); +#else const AVOption *opt = av_find_opt( obj, opt_name, NULL, flags, flags ); +#endif // If option not found, see if it was prefixed with a or v (-vb) if ( !opt && ( ( opt_name[0] == 'v' && ( flags & AV_OPT_FLAG_VIDEO_PARAM ) ) || ( opt_name[0] == 'a' && ( flags & AV_OPT_FLAG_AUDIO_PARAM ) ) ) ) +#if LIBAVUTIL_VERSION_INT > ((51<<16)+(7<<8)+0) + opt = av_opt_find( obj, ++opt_name, NULL, flags, flags ); +#else opt = av_find_opt( obj, ++opt_name, NULL, flags, flags ); +#endif // Apply option if found if ( opt ) -#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(7<<8)+0) +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(12<<8)+0) + av_opt_set( obj, opt_name, mlt_properties_get_value( properties, i), 0 ); +#elif LIBAVCODEC_VERSION_INT >= ((52<<16)+(7<<8)+0) av_set_string3( obj, opt_name, mlt_properties_get_value( properties, i), alloc, NULL ); #elif LIBAVCODEC_VERSION_INT >= ((51<<16)+(59<<8)+0) av_set_string2( obj, opt_name, mlt_properties_get_value( properties, i), alloc ); @@ -426,6 +423,73 @@ } } +static int get_mlt_audio_format( int av_sample_fmt ) +{ + switch ( av_sample_fmt ) + { + case AV_SAMPLE_FMT_S32: + return mlt_audio_s32le; + case AV_SAMPLE_FMT_FLT: + return mlt_audio_f32le; +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) + case AV_SAMPLE_FMT_S32P: + return mlt_audio_s32; + case AV_SAMPLE_FMT_FLTP: + return mlt_audio_float; +#endif + default: + return mlt_audio_s16; + } +} + +static int pick_sample_fmt( mlt_properties properties, AVCodec *codec ) +{ + int sample_fmt = AV_SAMPLE_FMT_S16; + const char *format = mlt_properties_get( properties, "mlt_audio_format" ); + const int *p = codec->sample_fmts; + + // get default av_sample_fmt from mlt_audio_format + if ( format ) + { + if ( !strcmp( format, "s32le" ) ) + sample_fmt = AV_SAMPLE_FMT_S32; + else if ( !strcmp( format, "f32le" ) ) + sample_fmt = AV_SAMPLE_FMT_FLT; +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) + else if ( !strcmp( format, "s32" ) ) + sample_fmt = AV_SAMPLE_FMT_S32P; + else if ( !strcmp( format, "float" ) ) + sample_fmt = AV_SAMPLE_FMT_FLTP; +#endif + } + // check if codec supports our mlt_audio_format + for ( ; *p != -1; p++ ) + { + if ( *p == sample_fmt ) + return sample_fmt; + } + // no match - pick first one we support + for ( p = codec->sample_fmts; *p != -1; p++ ) + { + switch (*p) + { + case AV_SAMPLE_FMT_S16: + case AV_SAMPLE_FMT_S32: + case AV_SAMPLE_FMT_FLT: +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0) + case AV_SAMPLE_FMT_S32P: + case AV_SAMPLE_FMT_FLTP: +#endif + return *p; + default: + break; + } + } + mlt_log_error( properties, "audio codec sample_fmt not compatible" ); + + return AV_SAMPLE_FMT_NONE; +} + /** Add an audio output stream */ @@ -435,7 +499,11 @@ mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Create a new stream +#if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(10<<8)+0) + AVStream *st = avformat_new_stream( oc, codec ); +#else AVStream *st = av_new_stream( oc, oc->nb_streams ); +#endif // If created, then initialise from properties if ( st != NULL ) @@ -451,7 +519,7 @@ c->codec_id = codec->id; c->codec_type = CODEC_TYPE_AUDIO; - c->sample_fmt = SAMPLE_FMT_S16; + c->sample_fmt = pick_sample_fmt( properties, codec ); #if 0 // disabled until some audio codecs are multi-threaded // Setup multi-threading @@ -490,7 +558,10 @@ if ( audio_qscale > QSCALE_NONE ) { c->flags |= CODEC_FLAG_QSCALE; - c->global_quality = st->quality = FF_QP2LAMBDA * audio_qscale; + c->global_quality = FF_QP2LAMBDA * audio_qscale; +#if LIBAVFORMAT_VERSION_MAJOR < 53 + st->quality = c->global_quality; +#endif } // Set parameters controlled by MLT @@ -500,7 +571,11 @@ if ( mlt_properties_get( properties, "alang" ) != NULL ) #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(43<<8)+0) +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) + av_dict_set( &oc->metadata, "language", mlt_properties_get( properties, "alang" ), 0 ); +#else av_metadata_set2( &oc->metadata, "language", mlt_properties_get( properties, "alang" ), 0 ); +#endif #else strncpy( st->language, mlt_properties_get( properties, "alang" ), sizeof( st->language ) ); @@ -529,7 +604,7 @@ else codec = avcodec_find_encoder( c->codec_id ); -#if LIBAVCODEC_VERSION_MAJOR >= 53 +#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(122<<8)+0) // Process properties as AVOptions on the AVCodec if ( codec && codec->priv_class ) { @@ -550,10 +625,12 @@ } #endif - avformat_lock(); - // Continue if codec found and we can open it - if ( codec != NULL && avcodec_open( c, codec ) >= 0 ) +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) + if ( codec && avcodec_open2( c, codec, NULL ) >= 0 ) +#else + if ( codec && avcodec_open( c, codec ) >= 0 ) +#endif { // ugly hack for PCM codecs (will be removed ASAP with new PCM // support to compute the input frame size in samples @@ -587,8 +664,6 @@ { mlt_log_warning( NULL, "%s: Unable to encode audio - disabling audio output.\n", __FILE__ ); } - - avformat_unlock(); return audio_input_frame_size; } @@ -596,11 +671,7 @@ static void close_audio( AVFormatContext *oc, AVStream *st ) { if ( st && st->codec ) - { - avformat_lock(); avcodec_close( st->codec ); - avformat_unlock(); - } } /** Add a video output stream @@ -612,7 +683,11 @@ mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Create a new stream +#if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(10<<8)+0) + AVStream *st = avformat_new_stream( oc, codec ); +#else AVStream *st = av_new_stream( oc, oc->nb_streams ); +#endif if ( st != NULL ) { @@ -756,7 +831,10 @@ if ( mlt_properties_get_double( properties, "qscale" ) > 0 ) { c->flags |= CODEC_FLAG_QSCALE; - st->quality = FF_QP2LAMBDA * mlt_properties_get_double( properties, "qscale" ); + c->global_quality = FF_QP2LAMBDA * mlt_properties_get_double( properties, "qscale" ); +#if LIBAVFORMAT_VERSION_MAJOR < 53 + st->quality = c->global_quality; +#endif } // Allow the user to override the video fourcc @@ -914,7 +992,7 @@ else codec = avcodec_find_encoder( video_enc->codec_id ); -#if LIBAVCODEC_VERSION_MAJOR >= 53 +#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(122<<8)+0) // Process properties as AVOptions on the AVCodec if ( codec && codec->priv_class ) { @@ -947,10 +1025,11 @@ video_enc->pix_fmt = codec->pix_fmts[ 0 ]; } - // Open the codec safely - avformat_lock(); - int result = codec != NULL && avcodec_open( video_enc, codec ) >= 0; - avformat_unlock(); +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) + int result = codec && avcodec_open2( video_enc, codec, NULL ) >= 0; +#else + int result = codec && avcodec_open( video_enc, codec ) >= 0; +#endif return result; } @@ -959,10 +1038,8 @@ { if ( st && st->codec ) { - avformat_lock(); av_freep( &st->codec->stats_in ); avcodec_close(st->codec); - avformat_unlock(); } } @@ -1017,11 +1094,10 @@ int img_height = height; // Get default audio properties - mlt_audio_format aud_fmt = mlt_audio_s16; int channels = mlt_properties_get_int( properties, "channels" ); int total_channels = channels; int frequency = mlt_properties_get_int( properties, "frequency" ); - int16_t *pcm = NULL; + void *pcm = NULL; int samples = 0; // AVFormat audio buffer and frame size @@ -1051,8 +1127,8 @@ mlt_image_format img_fmt = mlt_image_yuv422; // For receiving audio samples back from the fifo - int16_t *audio_buf_1 = av_malloc( AUDIO_ENCODE_BUFFER_SIZE ); - int16_t *audio_buf_2 = NULL; + uint8_t *audio_buf_1 = av_malloc( AUDIO_ENCODE_BUFFER_SIZE ); + uint8_t *audio_buf_2 = NULL; int count = 0; // Allocate the context @@ -1190,7 +1266,11 @@ markup[0] = '\0'; if ( !strstr( key, ".stream." ) ) #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(43<<8)+0) +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) + av_dict_set( &oc->metadata, key, mlt_properties_get_value( properties, i ), 0 ); +#else av_metadata_set2( &oc->metadata, key, mlt_properties_get_value( properties, i ), 0 ); +#endif #else av_metadata_set( &oc->metadata, key, mlt_properties_get_value( properties, i ) ); #endif @@ -1231,13 +1311,16 @@ frame = mlt_consumer_rt_frame( consumer ); // Set the timecode from the MLT metadata if available. - const char *timecode = mlt_properties_get( MLT_FRAME_PROPERTIES(frame), "meta.attr.vitc.markup" ); - if ( timecode && strcmp( timecode, "" ) ) - { - mlt_properties_set( properties, "timecode", timecode ); - if ( strchr( timecode, ';' ) ) - mlt_properties_set_int( properties, "drop_frame_timecode", 1 ); - } + if ( frame ) + { + const char *timecode = mlt_properties_get( MLT_FRAME_PROPERTIES(frame), "meta.attr.vitc.markup" ); + if ( timecode && strcmp( timecode, "" ) ) + { + mlt_properties_set( properties, "timecode", timecode ); + if ( strchr( timecode, ';' ) ) + mlt_properties_set_int( properties, "drop_frame_timecode", 1 ); + } + } // Add audio and video streams if ( video_codec_id != CODEC_ID_NONE ) @@ -1268,10 +1351,24 @@ } mlt_properties_set_int( properties, "channels", total_channels ); + // Audio format is determined when adding the audio stream + mlt_audio_format aud_fmt = mlt_audio_none; + if ( audio_st[0] ) + aud_fmt = get_mlt_audio_format( audio_st[0]->codec->sample_fmt ); + int sample_bytes = mlt_audio_format_size( aud_fmt, 1, 1 ); + sample_bytes = sample_bytes ? sample_bytes : 1; // prevent divide by zero + // Set the parameters (even though we have none...) - if ( av_set_parameters(oc, NULL) >= 0 ) +#if LIBAVFORMAT_VERSION_INT < ((53<<16)+(2<<8)+0) + if ( av_set_parameters(oc, NULL) >= 0 ) +#endif { +#if LIBAVFORMAT_VERSION_MAJOR >= 53 + if ( mlt_properties_get( properties, "muxpreload" ) && ! mlt_properties_get( properties, "preload" ) ) + mlt_properties_set_double( properties, "preload", mlt_properties_get_double( properties, "muxpreload" ) ); +#else oc->preload = ( int )( mlt_properties_get_double( properties, "muxpreload" ) * AV_TIME_BASE ); +#endif oc->max_delay= ( int )( mlt_properties_get_double( properties, "muxdelay" ) * AV_TIME_BASE ); // Process properties as AVOptions @@ -1280,14 +1377,14 @@ { mlt_properties p = mlt_properties_load( fpre ); apply_properties( oc, p, AV_OPT_FLAG_ENCODING_PARAM ); -#if LIBAVFORMAT_VERSION_MAJOR >= 53 +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(110<<8)+0) if ( oc->oformat && oc->oformat->priv_class && oc->priv_data ) apply_properties( oc->priv_data, p, AV_OPT_FLAG_ENCODING_PARAM ); #endif mlt_properties_close( p ); } apply_properties( oc, properties, AV_OPT_FLAG_ENCODING_PARAM ); -#if LIBAVFORMAT_VERSION_MAJOR >= 53 +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(110<<8)+0) if ( oc->oformat && oc->oformat->priv_class && oc->priv_data ) apply_properties( oc->priv_data, properties, AV_OPT_FLAG_ENCODING_PARAM ); #endif @@ -1344,13 +1441,19 @@ // Write the stream header. if ( mlt_properties_get_int( properties, "running" ) ) +#if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(2<<8)+0) + avformat_write_header( oc, NULL ); +#else av_write_header( oc ); +#endif } +#if LIBAVFORMAT_VERSION_INT < ((53<<16)+(2<<8)+0) else { mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Invalid output format parameters\n" ); mlt_properties_set_int( properties, "running", 0 ); } +#endif // Allocate picture if ( video_st ) @@ -1387,7 +1490,7 @@ { samples = mlt_sample_calculator( fps, frequency, count ++ ); channels = total_channels; - mlt_frame_get_audio( frame, (void**) &pcm, &aud_fmt, &frequency, &channels, &samples ); + mlt_frame_get_audio( frame, &pcm, &aud_fmt, &frequency, &channels, &samples ); // Save the audio channel remap properties for later mlt_properties_pass( frame_meta_properties, frame_properties, "meta.map.audio." ); @@ -1401,10 +1504,10 @@ // Silence if not normal forward speed if ( mlt_properties_get_double( frame_properties, "_speed" ) != 1.0 ) - memset( pcm, 0, samples * channels * 2 ); + memset( pcm, 0, samples * channels * sample_bytes ); // Append the samples - sample_fifo_append( fifo, pcm, samples * channels ); + sample_fifo_append( fifo, pcm, samples * channels * sample_bytes ); total_time += ( samples * 1000000 ) / frequency; if ( !video_st ) @@ -1426,15 +1529,15 @@ if ( !video_st || ( video_st && audio_st[0] && audio_pts < video_pts ) ) { // Write audio - if ( ( video_st && terminated ) || ( channels * audio_input_frame_size ) < sample_fifo_used( fifo ) ) + if ( ( video_st && terminated ) || ( channels * audio_input_frame_size ) < sample_fifo_used( fifo ) / sample_bytes ) { int j = 0; // channel offset into interleaved source buffer - int n = FFMIN( FFMIN( channels * audio_input_frame_size, sample_fifo_used( fifo ) ), AUDIO_ENCODE_BUFFER_SIZE ); + int n = FFMIN( FFMIN( channels * audio_input_frame_size, sample_fifo_used( fifo ) / sample_bytes ), AUDIO_ENCODE_BUFFER_SIZE ); // Get the audio samples if ( n > 0 ) { - sample_fifo_fetch( fifo, audio_buf_1, n ); + sample_fifo_fetch( fifo, audio_buf_1, n * sample_bytes ); } else if ( audio_codec_id == CODEC_ID_VORBIS && terminated ) { @@ -1461,7 +1564,7 @@ // Optimized for single track and no channel remap if ( !audio_st[1] && !mlt_properties_count( frame_meta_properties ) ) { - pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, audio_buf_1 ); + pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, (short*) audio_buf_1 ); } else { @@ -1510,14 +1613,14 @@ // Interleave the audio buffer with the # channels for this stream/mapping. for ( k = 0; k < map_channels; k++, j++, source_offset++, dest_offset++ ) { - int16_t *src = audio_buf_1 + source_offset; - int16_t *dest = audio_buf_2 + dest_offset; + void *src = audio_buf_1 + source_offset * sample_bytes; + void *dest = audio_buf_2 + dest_offset * sample_bytes; int s = samples + 1; while ( --s ) { - *dest = *src; - dest += current_channels; - src += channels; + memcpy( dest, src, sample_bytes ); + dest += current_channels * sample_bytes; + src += channels * sample_bytes; } } } @@ -1528,7 +1631,7 @@ dest_offset += current_channels; } } - pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, audio_buf_2 ); + pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, (short*) audio_buf_2 ); } // Write the compressed frame in the media file @@ -1660,7 +1763,7 @@ else { // Set the quality - output->quality = video_st->quality; + output->quality = c->global_quality; // Set frame interlace hints output->interlaced_frame = !mlt_properties_get_int( frame_properties, "progressive" ); @@ -1726,7 +1829,7 @@ long passed = time_difference( &ante ); if ( fifo != NULL ) { - long pending = ( ( ( long )sample_fifo_used( fifo ) * 1000 ) / frequency ) * 1000; + long pending = ( ( ( long )sample_fifo_used( fifo ) / sample_bytes * 1000 ) / frequency ) * 1000; passed -= pending; } if ( passed < total_time ) @@ -1751,10 +1854,10 @@ pkt.size = 0; if ( /*( c->capabilities & CODEC_CAP_SMALL_LAST_FRAME ) &&*/ - ( channels * audio_input_frame_size < sample_fifo_used( fifo ) ) ) + ( channels * audio_input_frame_size < sample_fifo_used( fifo ) / sample_bytes ) ) { - sample_fifo_fetch( fifo, audio_buf_1, channels * audio_input_frame_size ); - pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, audio_buf_1 ); + sample_fifo_fetch( fifo, audio_buf_1, channels * audio_input_frame_size * sample_bytes ); + pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, (short*) audio_buf_1 ); } if ( pkt.size <= 0 ) pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, NULL ); diff -Nru mlt-0.7.6+git20111222/src/modules/avformat/factory.c mlt-0.7.6+git20120204/src/modules/avformat/factory.c --- mlt-0.7.6+git20111222/src/modules/avformat/factory.c 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/avformat/factory.c 2012-02-04 13:14:54.000000000 +0000 @@ -1,6 +1,6 @@ /* * factory.c -- the factory method interfaces - * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Charles Yates * * This library is free software; you can redistribute it and/or @@ -46,48 +46,29 @@ // A static flag used to determine if avformat has been initialised static int avformat_initialised = 0; -// A locking mutex -static pthread_mutex_t avformat_mutex; - -#if 0 -// These 3 functions should override the alloc functions in libavformat -// but some formats or codecs seem to crash when used (wmv in particular) - -void *av_malloc( unsigned int size ) -{ - return mlt_pool_alloc( size ); -} - -void *av_realloc( void *ptr, unsigned int size ) -{ - return mlt_pool_realloc( ptr, size ); -} - -void av_free( void *ptr ) -{ - return mlt_pool_release( ptr ); -} -#endif - -void avformat_destroy( void *ignore ) +static int avformat_lockmgr(void **mutex, enum AVLockOp op) { - // Clean up - // av_free_static( ); -XXX this is deprecated - - // Destroy the mutex - pthread_mutex_destroy( &avformat_mutex ); -} + pthread_mutex_t** pmutex = (pthread_mutex_t**) mutex; -void avformat_lock( ) -{ - // Lock the mutex now - pthread_mutex_lock( &avformat_mutex ); -} + switch (op) + { + case AV_LOCK_CREATE: + *pmutex = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(*pmutex, NULL); + break; + case AV_LOCK_OBTAIN: + pthread_mutex_lock(*pmutex); + break; + case AV_LOCK_RELEASE: + pthread_mutex_unlock(*pmutex); + break; + case AV_LOCK_DESTROY: + pthread_mutex_destroy(*pmutex); + free(*pmutex); + break; + } -void avformat_unlock( ) -{ - // Unlock the mutex now - pthread_mutex_unlock( &avformat_mutex ); + return 0; } static void avformat_init( ) @@ -96,12 +77,14 @@ if ( avformat_initialised == 0 ) { avformat_initialised = 1; - pthread_mutex_init( &avformat_mutex, NULL ); + av_lockmgr_register( &avformat_lockmgr ); av_register_all( ); #ifdef AVDEVICE avdevice_register_all(); #endif - mlt_factory_register_for_clean_up( NULL, avformat_destroy ); +#if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(13<<8)) + avformat_network_init(); +#endif av_log_set_level( mlt_log_get_level() ); } } @@ -140,7 +123,11 @@ const AVOption *opt = NULL; // For each AVOption on the AVClass object +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(12<<8)+0) + while ( ( opt = av_opt_next( object, opt ) ) ) +#else while ( ( opt = av_next_option( object, opt ) ) ) +#endif { // If matches flags and not a binary option (not supported by Mlt) if ( !( opt->flags & req_flags ) || ( opt->type == FF_OPT_TYPE_BINARY ) ) @@ -310,7 +297,11 @@ // Annotate the yaml properties with AVOptions. mlt_properties params = (mlt_properties) mlt_properties_get_data( result, "parameters", NULL ); AVFormatContext *avformat = avformat_alloc_context(); +#if LIBAVCODEC_VERSION_INT > ((53<<16)+(8<<8)+0) + AVCodecContext *avcodec = avcodec_alloc_context3( NULL ); +#else AVCodecContext *avcodec = avcodec_alloc_context(); +#endif int flags = ( type == consumer_type )? AV_OPT_FLAG_ENCODING_PARAM : AV_OPT_FLAG_DECODING_PARAM; add_parameters( params, avformat, flags, NULL, NULL ); diff -Nru mlt-0.7.6+git20111222/src/modules/avformat/filter_avresample.c mlt-0.7.6+git20120204/src/modules/avformat/filter_avresample.c --- mlt-0.7.6+git20111222/src/modules/avformat/filter_avresample.c 2011-05-26 16:34:35.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/avformat/filter_avresample.c 2012-02-04 13:14:54.000000000 +0000 @@ -28,6 +28,11 @@ // ffmpeg Header files #include +#if LIBAVUTIL_VERSION_INT >= ((50<<16)+(38<<8)+0) +# include +#else +# define AV_SAMPLE_FMT_S16 SAMPLE_FMT_S16 +#endif /** Get the audio. */ @@ -79,7 +84,7 @@ // Create the resampler #if (LIBAVCODEC_VERSION_INT >= ((52<<16)+(15<<8)+0)) resample = av_audio_resample_init( *channels, *channels, output_rate, *frequency, - SAMPLE_FMT_S16, SAMPLE_FMT_S16, 16, 10, 0, 0.8 ); + AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16, 16, 10, 0, 0.8 ); #else resample = audio_resample_init( *channels, *channels, output_rate, *frequency ); #endif diff -Nru mlt-0.7.6+git20111222/src/modules/avformat/producer_avformat.c mlt-0.7.6+git20120204/src/modules/avformat/producer_avformat.c --- mlt-0.7.6+git20111222/src/modules/avformat/producer_avformat.c 2011-12-20 18:07:08.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/avformat/producer_avformat.c 2012-02-04 13:14:54.000000000 +0000 @@ -1,6 +1,6 @@ /* * producer_avformat.c -- avformat producer - * Copyright (C) 2003-2009 Ushodaya Enterprises Limited + * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Charles Yates * Author: Dan Dennedy * Much code borrowed from ffmpeg.c: Copyright (c) 2000-2003 Fabrice Bellard @@ -34,17 +34,27 @@ #ifdef SWSCALE # include #endif -#if LIBAVCODEC_VERSION_MAJOR >= 53 -#include -#elif (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) + +#if LIBAVUTIL_VERSION_INT >= ((50<<16)+(38<<8)+0) +# include +#else +# define AV_SAMPLE_FMT_S16 SAMPLE_FMT_S16 +# define AV_SAMPLE_FMT_S32 SAMPLE_FMT_S32 +# define AV_SAMPLE_FMT_FLT SAMPLE_FMT_FLT +# if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) const char *avcodec_get_sample_fmt_name(int sample_fmt); +# endif #endif + #ifdef VDPAU # include #endif #if (LIBAVUTIL_VERSION_INT > ((50<<16)+(7<<8)+0)) # include #endif +#if (LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0)) +# include +#endif // System header files #include @@ -72,9 +82,6 @@ #define MAX_AUDIO_STREAMS (10) #define MAX_VDPAU_SURFACES (10) -void avformat_lock( ); -void avformat_unlock( ); - struct producer_avformat_s { mlt_producer parent; @@ -114,6 +121,7 @@ mlt_deque apackets; mlt_deque vpackets; pthread_mutex_t packets_mutex; + pthread_mutex_t open_mutex; #ifdef VDPAU struct { @@ -196,14 +204,19 @@ else if ( self->seekable ) { // Close the file to release resources for large playlists - reopen later as needed - avformat_lock(); +#if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(17<<8)+0) + if ( self->audio_format ) + avformat_close_input( &self->audio_format ); + if ( self->video_format ) + avformat_close_input( &self->video_format ); +#else if ( self->audio_format ) av_close_input_file( self->audio_format ); - self->audio_format = NULL; if ( self->video_format ) av_close_input_file( self->video_format ); +#endif + self->audio_format = NULL; self->video_format = NULL; - avformat_unlock(); } } if ( producer ) @@ -266,7 +279,11 @@ { int i; char key[200]; +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) + AVDictionaryEntry *tag = NULL; +#else AVMetadataTag *tag = NULL; +#endif AVFormatContext *context = self->video_format; mlt_properties meta_media = MLT_PRODUCER_PROPERTIES( self->parent ); @@ -315,7 +332,11 @@ mlt_properties_set_double( meta_media, key, (double) codec_context->time_base.den / ( codec_context->time_base.num == 0 ? 1 : codec_context->time_base.num ) ); snprintf( key, sizeof(key), "meta.media.%d.codec.pix_fmt", i ); +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(3<<8)+0) + mlt_properties_set( meta_media, key, av_get_pix_fmt_name( codec_context->pix_fmt ) ); +#else mlt_properties_set( meta_media, key, avcodec_get_pix_fmt_name( codec_context->pix_fmt ) ); +#endif snprintf( key, sizeof(key), "meta.media.%d.codec.sample_aspect_ratio", i ); mlt_properties_set_double( meta_media, key, av_q2d( codec_context->sample_aspect_ratio ) ); #if LIBAVCODEC_VERSION_INT > ((52<<16)+(28<<8)+0) @@ -344,7 +365,7 @@ if ( self->audio_index < 0 ) self->audio_index = i; mlt_properties_set( meta_media, key, "audio" ); -#if LIBAVCODEC_VERSION_MAJOR >= 53 +#if LIBAVUTIL_VERSION_INT >= ((50<<16)+(38<<8)+0) snprintf( key, sizeof(key), "meta.media.%d.codec.sample_fmt", i ); mlt_properties_set( meta_media, key, av_get_sample_fmt_name( codec_context->sample_fmt ) ); #elif (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) @@ -378,7 +399,11 @@ // Read Metadata #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) + while ( ( tag = av_dict_get( stream->metadata, "", tag, AV_DICT_IGNORE_SUFFIX ) ) ) +#else while ( ( tag = av_metadata_get( stream->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX ) ) ) +#endif { if ( tag->value && strcmp( tag->value, "" ) && strcmp( tag->value, "und" ) ) { @@ -389,7 +414,11 @@ #endif } #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) + while ( ( tag = av_dict_get( context->metadata, "", tag, AV_DICT_IGNORE_SUFFIX ) ) ) +#else while ( ( tag = av_metadata_get( context->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX ) ) ) +#endif { if ( tag->value && strcmp( tag->value, "" ) && strcmp( tag->value, "und" ) ) { @@ -544,11 +573,15 @@ return aspect_ratio; } +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) +static char* parse_url( mlt_profile profile, const char* URL, AVInputFormat **format, AVDictionary **params ) +#else static char* parse_url( mlt_profile profile, const char* URL, AVInputFormat **format, AVFormatParameters *params ) +#endif { if ( !URL ) return NULL; - const char *result = URL; + char *result = NULL; char *protocol = strdup( URL ); char *url = strchr( protocol, ':' ); @@ -571,6 +604,11 @@ if ( *format ) { +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) + // support for legacy width and height parameters + char *width = NULL; + char *height = NULL; +#else // These are required by video4linux2 (defaults) params->width = profile->width; params->height = profile->height; @@ -578,6 +616,7 @@ params->time_base = (AVRational){ profile->frame_rate_den, profile->frame_rate_num }; params->channels = 2; params->sample_rate = 48000; +#endif // Parse out params url = strchr( url, '?' ); @@ -596,6 +635,20 @@ char *t = strchr( value, '&' ); if ( t ) t[0] = 0; +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) + // translate old parameters to new av_dict names + if ( !strcmp( name, "frame_rate" ) ) + av_dict_set( params, "framerate", value, 0 ); + else if ( !strcmp( name, "pix_fmt" ) ) + av_dict_set( params, "pixel_format", value, 0 ); + else if ( !strcmp( name, "width" ) ) + width = strdup( value ); + else if ( !strcmp( name, "height" ) ) + height = strdup( value ); + else + // generic demux/device option support + av_dict_set( params, name, value, 0 ); +#else if ( !strcmp( name, "frame_rate" ) ) params->time_base.den = atoi( value ); else if ( !strcmp( name, "frame_rate_base" ) ) @@ -616,13 +669,32 @@ params->height = atoi( value ); else if ( !strcmp( name, "standard" ) ) params->standard = strdup( value ); +#endif } free( name ); url = strchr( url, '&' ); } +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) + // continued support for legacy width and height parameters + if ( width && height ) + { + char *s = malloc( strlen( width ) + strlen( height ) + 2 ); + strcpy( s, width ); + strcat( s, "x"); + strcat( s, height ); + av_dict_set( params, "video_size", s, 0 ); + free( s ); + } + if ( width ) free( width ); + if ( height ) free ( height ); +#endif } + result = strdup( result ); + } + else + { + result = strdup( URL ); } - result = strdup( result ); free( protocol ); return result; } @@ -683,9 +755,15 @@ self->seekable = av_seek_frame( format, -1, format->start_time, AVSEEK_FLAG_BACKWARD ) >= 0; mlt_properties_set_int( properties, "seekable", self->seekable ); self->dummy_context = format; +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) + self->video_format = NULL; + avformat_open_input( &self->video_format, filename, NULL, NULL ); + avformat_find_stream_info( self->video_format, NULL ); +#else av_open_input_file( &self->video_format, filename, NULL, 0, NULL ); + av_find_stream_info( self->video_format ); +#endif format = self->video_format; - av_find_stream_info( format ); } // Fetch the width, height and aspect ratio @@ -744,6 +822,7 @@ pthread_mutex_init( &self->audio_mutex, NULL ); pthread_mutex_init( &self->video_mutex, NULL ); pthread_mutex_init( &self->packets_mutex, NULL ); + pthread_mutex_init( &self->open_mutex, NULL ); pthread_mutex_lock( &self->audio_mutex ); pthread_mutex_lock( &self->video_mutex ); } @@ -751,35 +830,54 @@ // Parse URL AVInputFormat *format = NULL; +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) + AVDictionary *params = NULL; +#else AVFormatParameters params; memset( ¶ms, 0, sizeof(params) ); +#endif char *filename = parse_url( profile, URL, &format, ¶ms ); // Now attempt to open the file or device with filename +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) + error = avformat_open_input( &self->video_format, filename, format, ¶ms ) < 0; + if ( error ) + // If the URL is a network stream URL, then we probably need to open with full URL + error = avformat_open_input( &self->video_format, URL, format, ¶ms ) < 0; +#else error = av_open_input_file( &self->video_format, filename, format, 0, ¶ms ) < 0; if ( error ) // If the URL is a network stream URL, then we probably need to open with full URL error = av_open_input_file( &self->video_format, URL, format, 0, ¶ms ) < 0; +#endif // Set MLT properties onto video AVFormatContext if ( !error && self->video_format ) { apply_properties( self->video_format, properties, AV_OPT_FLAG_DECODING_PARAM ); -#if LIBAVFORMAT_VERSION_MAJOR >= 53 +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(110<<8)+0) if ( self->video_format->iformat && self->video_format->iformat->priv_class && self->video_format->priv_data ) apply_properties( self->video_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM ); #endif } +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) + av_dict_free( ¶ms ); +#else // Cleanup AVFormatParameters if ( params.standard ) free( (void*) params.standard ); +#endif // If successful, then try to get additional info if ( !error && self->video_format ) { // Get the stream info +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) + error = avformat_find_stream_info( self->video_format, NULL ) < 0; +#else error = av_find_stream_info( self->video_format ) < 0; +#endif // Continue if no error if ( !error && self->video_format ) @@ -802,13 +900,21 @@ if ( self->seekable ) { // And open again for our audio context - av_open_input_file( &self->audio_format, filename, NULL, 0, NULL ); +#if LIBAVFORMAT_VERSION_INT > ((53<<16)+(6<<8)+0) + avformat_open_input( &self->audio_format, filename, NULL, NULL ); apply_properties( self->audio_format, properties, AV_OPT_FLAG_DECODING_PARAM ); -#if LIBAVFORMAT_VERSION_MAJOR >= 53 if ( self->audio_format->iformat && self->audio_format->iformat->priv_class && self->audio_format->priv_data ) apply_properties( self->audio_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM ); + avformat_find_stream_info( self->audio_format, NULL ); +#else + av_open_input_file( &self->audio_format, filename, NULL, 0, NULL ); + apply_properties( self->audio_format, properties, AV_OPT_FLAG_DECODING_PARAM ); +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(110<<8)+0) + if ( self->audio_format->iformat && self->audio_format->iformat->priv_class && self->audio_format->priv_data ) + apply_properties( self->audio_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM ); #endif av_find_stream_info( self->audio_format ); +#endif } else { @@ -841,10 +947,14 @@ if ( self->dummy_context ) { - avformat_lock(); + pthread_mutex_lock( &self->open_mutex ); +#if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(17<<8)+0) + avformat_close_input( &self->dummy_context ); +#else av_close_input_file( self->dummy_context ); - avformat_unlock(); +#endif self->dummy_context = NULL; + pthread_mutex_unlock( &self->open_mutex ); } // Unlock the service @@ -863,18 +973,25 @@ mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); pthread_mutex_lock( &self->audio_mutex ); + pthread_mutex_lock( &self->open_mutex ); - avformat_lock(); if ( self->video_codec ) avcodec_close( self->video_codec ); self->video_codec = NULL; +#if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(17<<8)+0) + if ( self->dummy_context ) + avformat_close_input( &self->dummy_context ); + if ( self->video_format ) + avformat_close_input( &self->video_format ); +#else if ( self->dummy_context ) av_close_input_file( self->dummy_context ); - self->dummy_context = NULL; if ( self->video_format ) av_close_input_file( self->video_format ); +#endif + self->dummy_context = NULL; self->video_format = NULL; - avformat_unlock(); + pthread_mutex_unlock( &self->open_mutex ); int audio_index = self->audio_index; int video_index = self->video_index; @@ -1035,8 +1152,12 @@ AVCodec *codec = avcodec_find_decoder( codec_context->codec_id ); // If we don't have a codec and we can't initialise it, we can't do much more... - avformat_lock( ); + pthread_mutex_lock( &self->open_mutex ); +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) + if ( codec && avcodec_open2( codec_context, codec, NULL ) >= 0 ) +#else if ( codec && avcodec_open( codec_context, codec ) >= 0 ) +#endif { self->audio_streams++; self->audio_max_stream = i; @@ -1047,7 +1168,7 @@ self->max_frequency = codec_context->sample_rate; avcodec_close( codec_context ); } - avformat_unlock( ); + pthread_mutex_unlock( &self->open_mutex ); } } mlt_log_verbose( NULL, "[producer avformat] audio: total_streams %d max_stream %d total_channels %d max_channels %d\n", @@ -1678,11 +1799,17 @@ for ( i = 0; i < count; i++ ) { const char *opt_name = mlt_properties_get_name( properties, i ); +#if LIBAVUTIL_VERSION_INT > ((51<<16)+(7<<8)+0) + const AVOption *opt = av_opt_find( obj, opt_name, NULL, flags, flags ); +#else const AVOption *opt = av_find_opt( obj, opt_name, NULL, flags, flags ); +#endif if ( opt_name && mlt_properties_get( properties, opt_name ) ) { if ( opt ) -#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(7<<8)+0) +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(12<<8)+0) + av_opt_set( obj, opt_name, mlt_properties_get( properties, opt_name), 0 ); +#elif LIBAVCODEC_VERSION_INT >= ((52<<16)+(7<<8)+0) av_set_string3( obj, opt_name, mlt_properties_get( properties, opt_name), 0, NULL ); #elif LIBAVCODEC_VERSION_INT >= ((51<<16)+(59<<8)+0) av_set_string2( obj, opt_name, mlt_properties_get( properties, opt_name), 0 ); @@ -1734,8 +1861,12 @@ codec_context->thread_count = thread_count; // If we don't have a codec and we can't initialise it, we can't do much more... - avformat_lock( ); + pthread_mutex_lock( &self->open_mutex ); +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) + if ( codec && avcodec_open2( codec_context, codec, NULL ) >= 0 ) +#else if ( codec && avcodec_open( codec_context, codec ) >= 0 ) +#endif { // Now store the codec with its destructor self->video_codec = codec_context; @@ -1744,14 +1875,14 @@ { // Remember that we can't use this later self->video_index = -1; - avformat_unlock( ); + pthread_mutex_unlock( &self->open_mutex ); return 0; } - avformat_unlock( ); + pthread_mutex_unlock( &self->open_mutex ); // Process properties as AVOptions apply_properties( codec_context, properties, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); -#if LIBAVCODEC_VERSION_MAJOR >= 53 +#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(122<<8)+0) if ( codec->priv_class && codec_context->priv_data ) apply_properties( codec_context->priv_data, properties, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); #endif @@ -1898,11 +2029,11 @@ { // Reset the video properties if the index changed self->video_index = index; - avformat_lock(); + pthread_mutex_lock( &self->open_mutex ); if ( self->video_codec ) avcodec_close( self->video_codec ); self->video_codec = NULL; - avformat_unlock(); + pthread_mutex_unlock( &self->open_mutex ); } // Get the frame properties @@ -1986,7 +2117,9 @@ static int sample_bytes( AVCodecContext *context ) { -#if LIBAVCODEC_VERSION_MAJOR >= 53 +#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(8<<8)+0) + return av_get_bytes_per_sample( context->sample_fmt ); +#elif LIBAVCODEC_VERSION_MAJOR >= 53 return av_get_bits_per_sample_fmt( context->sample_fmt ) / 8; #else return av_get_bits_per_sample_format( context->sample_fmt ) / 8; @@ -2170,7 +2303,7 @@ self->audio_resample[ index ] = av_audio_resample_init( self->audio_index == INT_MAX ? codec_context->channels : *channels, codec_context->channels, *frequency, codec_context->sample_rate, - SAMPLE_FMT_S16, codec_context->sample_fmt, 16, 10, 0, 0.8 ); + AV_SAMPLE_FMT_S16, codec_context->sample_fmt, 16, 10, 0, 0.8 ); #else self->audio_resample[ index ] = audio_resample_init( self->audio_index == INT_MAX ? codec_context->channels : *channels, @@ -2273,8 +2406,8 @@ index = self->audio_index; *channels = self->audio_codec[ index ]->channels; *frequency = self->audio_codec[ index ]->sample_rate; - *format = self->audio_codec[ index ]->sample_fmt == SAMPLE_FMT_S32 ? mlt_audio_s32le - : self->audio_codec[ index ]->sample_fmt == SAMPLE_FMT_FLT ? mlt_audio_f32le + *format = self->audio_codec[ index ]->sample_fmt == AV_SAMPLE_FMT_S32 ? mlt_audio_s32le + : self->audio_codec[ index ]->sample_fmt == AV_SAMPLE_FMT_FLT ? mlt_audio_f32le : mlt_audio_s16; sizeof_sample = sample_bytes( self->audio_codec[ index ] ); } @@ -2284,8 +2417,8 @@ for ( index = 0; index < index_max; index++ ) if ( self->audio_codec[ index ] && !self->audio_resample[ index ] ) { - *format = self->audio_codec[ index ]->sample_fmt == SAMPLE_FMT_S32 ? mlt_audio_s32le - : self->audio_codec[ index ]->sample_fmt == SAMPLE_FMT_FLT ? mlt_audio_f32le + *format = self->audio_codec[ index ]->sample_fmt == AV_SAMPLE_FMT_S32 ? mlt_audio_s32le + : self->audio_codec[ index ]->sample_fmt == AV_SAMPLE_FMT_FLT ? mlt_audio_f32le : mlt_audio_s16; sizeof_sample = sample_bytes( self->audio_codec[ index ] ); break; @@ -2378,8 +2511,12 @@ AVCodec *codec = avcodec_find_decoder( codec_context->codec_id ); // If we don't have a codec and we can't initialise it, we can't do much more... - avformat_lock( ); + pthread_mutex_lock( &self->open_mutex ); +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) + if ( codec && avcodec_open2( codec_context, codec, NULL ) >= 0 ) +#else if ( codec && avcodec_open( codec_context, codec ) >= 0 ) +#endif { // Now store the codec with its destructor if ( self->audio_codec[ index ] ) @@ -2391,11 +2528,11 @@ // Remember that we can't use self later self->audio_index = -1; } - avformat_unlock( ); + pthread_mutex_unlock( &self->open_mutex ); // Process properties as AVOptions apply_properties( codec_context, properties, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); -#if LIBAVCODEC_VERSION_MAJOR >= 53 +#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(122<<8)+0) if ( codec && codec->priv_class && codec_context->priv_data ) apply_properties( codec_context->priv_data, properties, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); #endif @@ -2454,11 +2591,11 @@ // Update the audio properties if the index changed if ( context && index > -1 && index != self->audio_index ) { - avformat_lock(); + pthread_mutex_lock( &self->open_mutex ); if ( self->audio_codec[ self->audio_index ] ) avcodec_close( self->audio_codec[ self->audio_index ] ); self->audio_codec[ self->audio_index ] = NULL; - avformat_unlock(); + pthread_mutex_unlock( &self->open_mutex ); } if ( self->audio_index != -1 ) self->audio_index = index; @@ -2551,7 +2688,7 @@ // Cleanup av contexts av_free( self->av_frame ); - avformat_lock(); + pthread_mutex_lock( &self->open_mutex ); int i; for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) { @@ -2567,13 +2704,22 @@ avcodec_close( self->video_codec ); self->video_codec = NULL; // Close the file +#if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(17<<8)+0) + if ( self->dummy_context ) + avformat_close_input( &self->dummy_context ); + if ( self->seekable && self->audio_format ) + avformat_close_input( &self->audio_format ); + if ( self->video_format ) + avformat_close_input( &self->video_format ); +#else if ( self->dummy_context ) av_close_input_file( self->dummy_context ); if ( self->seekable && self->audio_format ) av_close_input_file( self->audio_format ); if ( self->video_format ) av_close_input_file( self->video_format ); - avformat_unlock(); +#endif + pthread_mutex_unlock( &self->open_mutex ); #ifdef VDPAU vdpau_producer_close( self ); #endif @@ -2584,6 +2730,7 @@ pthread_mutex_destroy( &self->audio_mutex ); pthread_mutex_destroy( &self->video_mutex ); pthread_mutex_destroy( &self->packets_mutex ); + pthread_mutex_destroy( &self->open_mutex ); // Cleanup the packet queues AVPacket *pkt; diff -Nru mlt-0.7.6+git20111222/src/modules/core/filter_audiochannels.c mlt-0.7.6+git20120204/src/modules/core/filter_audiochannels.c --- mlt-0.7.6+git20111222/src/modules/core/filter_audiochannels.c 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/core/filter_audiochannels.c 2012-02-04 13:14:54.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_audiochannels.c -- convert from one audio format to another - * Copyright (C) 2009 Ushodaya Enterprises Limited + * Copyright (C) 2009-2012 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library is free software; you can redistribute it and/or @@ -46,14 +46,27 @@ { for ( j = 0; j < *channels; j++ ) { - new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + k ]; + new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + k ]; + k = ( k + 1 ) % channels_avail; + } + } + } + else if ( *format == mlt_audio_s32le || *format == mlt_audio_f32le ) + { + int32_t *p = (int32_t*) new_buffer; + int i, j, k = 0; + for ( i = 0; i < *samples; i++ ) + { + for ( j = 0; j < *channels; j++ ) + { + p[ ( i * *channels ) + j ] = ((int32_t*)(*buffer))[ ( i * channels_avail ) + k ]; k = ( k + 1 ) % channels_avail; } } } else { - // non-interleaved + // non-interleaved - s32 or float int size_avail = mlt_audio_format_size( *format, *samples, channels_avail ); int32_t *p = (int32_t*) new_buffer; int i = *channels / channels_avail; diff -Nru mlt-0.7.6+git20111222/src/modules/core/filter_audioconvert.c mlt-0.7.6+git20120204/src/modules/core/filter_audioconvert.c --- mlt-0.7.6+git20111222/src/modules/core/filter_audioconvert.c 2011-05-26 16:34:35.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/core/filter_audioconvert.c 2012-02-04 13:14:54.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_audioconvert.c -- convert from one audio format to another - * Copyright (C) 2009 Ushodaya Enterprises Limited + * Copyright (C) 2009-2012 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library is free software; you can redistribute it and/or @@ -81,6 +81,34 @@ error = 0; break; } + case mlt_audio_s32le: + { + int32_t *buffer = mlt_pool_alloc( size ); + int32_t *p = buffer; + int16_t *q = (int16_t*) *audio; + int i = samples * channels + 1; + while ( --i ) + *p++ = (int32_t) *q++ << 16; + *audio = buffer; + error = 0; + break; + } + case mlt_audio_f32le: + { + float *buffer = mlt_pool_alloc( size ); + float *p = buffer; + int16_t *q = (int16_t*) *audio; + int i = samples * channels + 1; + while ( --i ) + { + float f = (float)( *q++ ) / 32768.0; + f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; + *p++ = f; + } + *audio = buffer; + error = 0; + break; + } default: break; } @@ -113,6 +141,36 @@ error = 0; break; } + case mlt_audio_s32le: + { + int32_t *buffer = mlt_pool_alloc( size ); + int32_t *p = buffer; + int32_t *q = (int32_t*) *audio; + int s, c; + for ( s = 0; s < samples; s++ ) + for ( c = 0; c < channels; c++ ) + *p++ = *( q + c * samples + s ); + *audio = buffer; + error = 0; + break; + } + case mlt_audio_f32le: + { + float *buffer = mlt_pool_alloc( size ); + float *p = buffer; + int32_t *q = (int32_t*) *audio; + int s, c; + for ( s = 0; s < samples; s++ ) + for ( c = 0; c < channels; c++ ) + { + float f = (float)( *( q + c * samples + s ) ) / 2147483648.0; + f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; + *p++ = f; + } + *audio = buffer; + error = 0; + break; + } default: break; } @@ -153,6 +211,36 @@ error = 0; break; } + case mlt_audio_s32le: + { + int32_t *buffer = mlt_pool_alloc( size ); + int32_t *p = buffer; + float *q = (float*) *audio; + int s, c; + for ( s = 0; s < samples; s++ ) + for ( c = 0; c < channels; c++ ) + { + float f = *( q + c * samples + s ); + f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; + *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; + } + *audio = buffer; + error = 0; + break; + } + case mlt_audio_f32le: + { + float *buffer = mlt_pool_alloc( size ); + float *p = buffer; + float *q = (float*) *audio; + int s, c; + for ( s = 0; s < samples; s++ ) + for ( c = 0; c < channels; c++ ) + *p++ = *( q + c * samples + s ); + *audio = buffer; + error = 0; + break; + } default: break; } @@ -210,6 +298,18 @@ error = 0; break; } + case mlt_audio_f32le: + { + float *buffer = mlt_pool_alloc( size ); + float *p = buffer; + int32_t *q = (int32_t*) *audio; + int i = samples * channels + 1; + while ( --i ) + *p++ = (float)( *q++ ) / 2147483648.0; + *audio = buffer; + error = 0; + break; + } default: break; } @@ -273,6 +373,22 @@ error = 0; break; } + case mlt_audio_s32le: + { + int32_t *buffer = mlt_pool_alloc( size ); + int32_t *p = buffer; + float *q = (float*) *audio; + int i = samples * channels + 1; + while ( --i ) + { + float f = *q++; + f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; + *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; + } + *audio = buffer; + error = 0; + break; + } default: break; } diff -Nru mlt-0.7.6+git20111222/src/modules/core/filter_channelcopy.c mlt-0.7.6+git20120204/src/modules/core/filter_channelcopy.c --- mlt-0.7.6+git20111222/src/modules/core/filter_channelcopy.c 2011-05-26 16:34:35.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/core/filter_channelcopy.c 2012-02-04 13:14:54.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_channelcopy.c -- copy one audio channel to another - * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library is free software; you can redistribute it and/or @@ -86,6 +86,26 @@ } break; } + case mlt_audio_s32le: + case mlt_audio_f32le: + { + int32_t *f = (int32_t*) *buffer + from; + int32_t *t = (int32_t*) *buffer + to; + int32_t x; + int i; + + if ( swap ) + for ( i = 0; i < *samples; i++, f += *channels, t += *channels ) + { + x = *t; + *t = *f; + *f = x; + } + else + for ( i = 0; i < *samples; i++, f += *channels, t += *channels ) + *t = *f; + break; + } case mlt_audio_float: { float *f = (float*) *buffer + from * *samples; diff -Nru mlt-0.7.6+git20111222/src/modules/core/filter_mono.c mlt-0.7.6+git20120204/src/modules/core/filter_mono.c --- mlt-0.7.6+git20111222/src/modules/core/filter_mono.c 2011-05-26 16:34:35.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/core/filter_mono.c 2012-02-04 13:14:54.000000000 +0000 @@ -1,6 +1,6 @@ /* * filter_mono.c -- mix all channels to a mono signal across n channels - * Copyright (C) 2003-2009 Ushodaya Enterprises Limited + * Copyright (C) 2003-2012 Ushodaya Enterprises Limited * Author: Dan Dennedy * * This library is free software; you can redistribute it and/or @@ -58,6 +58,34 @@ *buffer = new_buffer; break; } + case mlt_audio_s32le: + { + int32_t *new_buffer = mlt_pool_alloc( size ); + for ( i = 0; i < *samples; i++ ) + { + int32_t mixdown = 0; + for ( j = 0; j < *channels; j++ ) + mixdown += ((int32_t*) *buffer)[ ( i * *channels ) + j ] / *channels; + for ( j = 0; j < channels_out; j++ ) + new_buffer[ ( i * channels_out ) + j ] = mixdown; + } + *buffer = new_buffer; + break; + } + case mlt_audio_f32le: + { + float *new_buffer = mlt_pool_alloc( size ); + for ( i = 0; i < *samples; i++ ) + { + float mixdown = 0; + for ( j = 0; j < *channels; j++ ) + mixdown += ((float*) *buffer)[ ( i * *channels ) + j ] / *channels; + for ( j = 0; j < channels_out; j++ ) + new_buffer[ ( i * channels_out ) + j ] = mixdown; + } + *buffer = new_buffer; + break; + } case mlt_audio_s32: { int32_t *new_buffer = mlt_pool_alloc( size ); diff -Nru mlt-0.7.6+git20111222/src/modules/core/producer_melt.c mlt-0.7.6+git20120204/src/modules/core/producer_melt.c --- mlt-0.7.6+git20111222/src/modules/core/producer_melt.c 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/core/producer_melt.c 2012-02-04 13:14:54.000000000 +0000 @@ -439,7 +439,8 @@ backtrack = 1; } - while ( argv[ i ] != NULL && strchr( argv[ i ], '=' ) ) + while ( argv[ i ] != NULL && strchr( argv[ i ], '=' ) && + ( !strchr( argv[ i ], ':' ) || strchr( argv[ i ], ':' ) > strchr( argv[ i ], '=' ) ) ) { i ++; backtrack = 1; diff -Nru mlt-0.7.6+git20111222/src/modules/gtk2/producer_pango.c mlt-0.7.6+git20120204/src/modules/gtk2/producer_pango.c --- mlt-0.7.6+git20111222/src/modules/gtk2/producer_pango.c 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/gtk2/producer_pango.c 2012-02-04 13:14:54.000000000 +0000 @@ -536,6 +536,9 @@ { producer_pango this = producer->child; + // Fetch the producers properties + mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES( producer ); + // Generate a frame *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) ); @@ -556,7 +559,11 @@ // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", 1 ); - mlt_properties_set_double( properties, "aspect_ratio", 1 ); + double force_ratio = mlt_properties_get_double( producer_properties, "force_aspect_ratio" ); + if ( force_ratio > 0.0 ) + mlt_properties_set_double( properties, "aspect_ratio", force_ratio ); + else + mlt_properties_set_double( properties, "aspect_ratio", 1.0); // Stack the get image callback mlt_frame_push_service( *frame, this ); diff -Nru mlt-0.7.6+git20111222/src/modules/gtk2/producer_pango.yml mlt-0.7.6+git20120204/src/modules/gtk2/producer_pango.yml --- mlt-0.7.6+git20111222/src/modules/gtk2/producer_pango.yml 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/gtk2/producer_pango.yml 2012-02-04 13:14:54.000000000 +0000 @@ -214,3 +214,9 @@ type: integer description: The last requested scaled image height. readonly: yes + + - identifier: force_aspect_ratio + title: Sample aspect ratio + type: float + description: Optionally override a (mis)detected aspect ratio + mutable: yes diff -Nru mlt-0.7.6+git20111222/src/modules/gtk2/producer_pixbuf.yml mlt-0.7.6+git20120204/src/modules/gtk2/producer_pixbuf.yml --- mlt-0.7.6+git20111222/src/modules/gtk2/producer_pixbuf.yml 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/gtk2/producer_pixbuf.yml 2012-02-04 13:14:54.000000000 +0000 @@ -98,3 +98,9 @@ minimum: 0 maximum: 1 widget: checkbox + + - identifier: force_aspect_ratio + title: Sample aspect ratio + type: float + description: Optionally override a (mis)detected aspect ratio + mutable: yes diff -Nru mlt-0.7.6+git20111222/src/modules/jackrack/Makefile mlt-0.7.6+git20120204/src/modules/jackrack/Makefile --- mlt-0.7.6+git20111222/src/modules/jackrack/Makefile 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/jackrack/Makefile 2012-02-04 13:14:54.000000000 +0000 @@ -1,6 +1,6 @@ CFLAGS += -I../.. -LDFLAGS += -L../../framework -lmlt -lpthread -lm +LDFLAGS += -L../../framework -lmlt -lpthread include ../../../config.mak include config.mak @@ -32,6 +32,7 @@ LDFLAGS += $(LIBDL) LDFLAGS += `pkg-config --libs libxml-2.0` LDFLAGS += `pkg-config --libs glib-2.0` +LDFLAGS += -lm YML_FILES = *.yml BLACKLIST = blacklist.txt diff -Nru mlt-0.7.6+git20111222/src/modules/kdenlive/filter_freeze.c mlt-0.7.6+git20120204/src/modules/kdenlive/filter_freeze.c --- mlt-0.7.6+git20111222/src/modules/kdenlive/filter_freeze.c 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/kdenlive/filter_freeze.c 2012-02-04 13:14:54.000000000 +0000 @@ -56,6 +56,12 @@ { // freeze_frame has not been fetched yet or is not useful, so fetch it and cache it. mlt_producer producer = mlt_frame_get_original_producer(frame); + + // If requested freeze frame is out of the cutted producer, get parent + if ( pos < mlt_producer_get_in( producer ) || pos > mlt_producer_get_out( producer ) ) + { + producer = mlt_producer_cut_parent( producer ); + } mlt_producer_seek( producer, pos ); // Get the frame diff -Nru mlt-0.7.6+git20111222/src/modules/make.inc mlt-0.7.6+git20120204/src/modules/make.inc --- mlt-0.7.6+git20111222/src/modules/make.inc 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/make.inc 2011-05-29 12:48:57.000000000 +0000 @@ -0,0 +1 @@ +SUBDIRS = core frei0r melt kdenlive normalize sdl motion_est rotoscoping vorbis dgraft gtk2 dv swfdec plus decklink avformat feeds resample lumas vmfx xml qimage sox effectv oldfilm linsys jackrack kino xine diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/filter_videostab2.c mlt-0.7.6+git20120204/src/modules/videostab/filter_videostab2.c --- mlt-0.7.6+git20111222/src/modules/videostab/filter_videostab2.c 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/filter_videostab2.c 2012-02-04 13:14:54.000000000 +0000 @@ -32,11 +32,16 @@ #include "stabilize.h" #include "transform_image.h" +typedef struct { + StabData* stab; + TransformData* trans; + int initialized; + void* parent; +} videostab2_data; -static void serialize_vectors( StabData* self, mlt_position length ) +static void serialize_vectors( videostab2_data* self, mlt_position length ) { mlt_geometry g = mlt_geometry_init(); - if ( g ) { struct mlt_geometry_item_s item; @@ -46,7 +51,7 @@ item.key = item.f[0] = item.f[1] = 1; item.f[2] = item.f[3] = item.f[4] = 1; - tlist* transform_data =self->transs; + tlist* transform_data =self->stab->transs; for ( i = 0; i < length; i++ ) { // Set the geometry item @@ -71,8 +76,8 @@ mlt_geometry_close( g ); } } - -Transform* deserialize_vectors( char *vectors, mlt_position length ) +// scale zoom implements the factor that the vetcors must be scaled since the vector is calulated for real with, now we need it for (scaled)width +Transform* deserialize_vectors( char *vectors, mlt_position length ,float scale_zoom ) { mlt_geometry g = mlt_geometry_init(); Transform* tx=NULL; @@ -81,21 +86,20 @@ { struct mlt_geometry_item_s item; int i; - tx=malloc(sizeof(Transform)*length); - memset(tx,sizeof(Transform)*length,0); + tx=calloc(1,sizeof(Transform)*length); // Copy the geometry items to a vc array for interp() for ( i = 0; i < length; i++ ) { mlt_geometry_fetch( g, &item, i ); Transform t; - t.x=item.x; - t.y=item.y; + t.x=scale_zoom*item.x; + t.y=scale_zoom*item.y; t.alpha=item.w; - t.zoom=item.h; + t.zoom=scale_zoom*item.h; t.extra=0; tx[i]=t; } - + } else { @@ -110,97 +114,102 @@ 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_frame_pop_service( frame ); - //*format = mlt_image_rgb24; - *format = mlt_image_yuv420p; + char *vectors = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "vectors" ); + *format = mlt_image_yuv422; + if (vectors) + *format= mlt_image_rgb24; mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "consumer_deinterlace", 1 ); int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if ( !error && *image ) { - StabData* self = filter->child; + videostab2_data* data = filter->child; + if ( data==NULL ) { // big error, abort + return 1; + } mlt_position length = mlt_filter_get_length2( filter, frame ); int h = *height; int w = *width; // Service locks are for concurrency control mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); - if ( !self->initialized ) - { - // Initialize our context - self->initialized = 1; - self->width=w; - self->height=h; - self->framesize=w*h* 3/2;//( mlt_image_format_size ( *format, w,h , 0) ; // 3/2 =1 too small - self->shakiness = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "shakiness" ); - self->accuracy = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "accuracy" ); - self->stepsize = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "stepsize" ); - self->algo = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "algo" ); - self->show = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "show" ); - self->contrast_threshold = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter) , "mincontrast" ); - stabilize_configure(self); - } - char *vectors = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "vectors" ); - if ( !vectors ) - { - // Analyse - mlt_position pos = mlt_filter_get_position( filter, frame ); - stabilize_filter_video ( self, *image, *format ); - - // On last frame - if ( pos == length - 1 ) + if ( !vectors) { + if ( !data->initialized ) { - serialize_vectors( self, length ); + // Initialize our context + data->initialized = 1; + data->stab->width=w; + data->stab->height=h; + if (*format==mlt_image_yuv420p) data->stab->framesize=w*h* 3/2;//( mlt_image_format_size ( *format, w,h , 0) ; // 3/2 =1 too small + if (*format==mlt_image_yuv422) data->stab->framesize=w*h; + data->stab->shakiness = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "shakiness" ); + data->stab->accuracy = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "accuracy" ); + data->stab->stepsize = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "stepsize" ); + data->stab->algo = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "algo" ); + data->stab->show = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter) , "show" ); + data->stab->contrast_threshold = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter) , "mincontrast" ); + stabilize_configure(data->stab); } + // Analyse + mlt_position pos = mlt_filter_get_position( filter, frame ); + stabilize_filter_video ( data->stab , *image, *format ); + + // On last frame + if ( pos == length - 1 ) + { + serialize_vectors( data , length ); + } } - if ( vectors ) + else { - // Apply - TransformData* tf=mlt_properties_get_data( MLT_FILTER_PROPERTIES(filter), "_transformdata", NULL); - char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "rescale.interp" ); - - if (!tf){ - tf=mlt_pool_alloc(sizeof(TransformData)); - mlt_properties_set_data( MLT_FILTER_PROPERTIES(filter), "_transformdata", tf, 0, ( mlt_destructor )mlt_pool_release, NULL ); - } - if ( self->initialized != 2 ) + if ( data->initialized!=1 ) { - // Load analysis results from property - self->initialized = 2; + char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "rescale.interp" ); - int interp = 2; - if ( strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 ) - interp = 0; - else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 ) - interp = 1; - else if ( strcmp( interps, "bilinear" ) == 0 ) - interp = 2; - else if ( strcmp( interps, "bicubic" ) == 0 ) - interp = 3; - else if ( strcmp( interps, "bicublin" ) == 0 ) - interp = 4; - - tf->interpoltype = interp; - tf->smoothing = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "smoothing" ); - tf->maxshift = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "maxshift" ); - tf->maxangle = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "maxangle" ); - tf->crop = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "crop" ); - tf->invert = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "invert" ); - tf->relative = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "relative" ); - tf->zoom = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "zoom" ); - tf->optzoom = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "optzoom" ); - tf->sharpen = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter), "sharpen" ); + if ( data->initialized != 2 ) + { + // Load analysis results from property + data->initialized = 2; + + int interp = 2; + float scale_zoom=1.0; + if (*width!=mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "real_width" )) + scale_zoom=(float)*width/(float)mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "real_width" ); + if ( strcmp( interps, "nearest" ) == 0 || strcmp( interps, "neighbor" ) == 0 ) + interp = 0; + else if ( strcmp( interps, "tiles" ) == 0 || strcmp( interps, "fast_bilinear" ) == 0 ) + interp = 1; + else if ( strcmp( interps, "bilinear" ) == 0 ) + interp = 2; + else if ( strcmp( interps, "bicubic" ) == 0 ) + interp = 3; + else if ( strcmp( interps, "bicublin" ) == 0 ) + interp = 4; + + data->trans->interpoltype = interp; + data->trans->smoothing = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "smoothing" ); + data->trans->maxshift = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "maxshift" ); + data->trans->maxangle = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "maxangle" ); + data->trans->crop = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "crop" ); + data->trans->invert = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "invert" ); + data->trans->relative = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "relative" ); + data->trans->zoom = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "zoom" ); + data->trans->optzoom = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "optzoom" ); + data->trans->sharpen = mlt_properties_get_double( MLT_FILTER_PROPERTIES(filter), "sharpen" ); - transform_configure(tf,w,h,*format ,*image, deserialize_vectors( vectors, length ),length); - - } - if ( self->initialized == 2 ) - { - // Stabilize - float pos = mlt_filter_get_position( filter, frame ); - tf->current_trans=pos; - transform_filter_video(tf, *image, *format ); - } + transform_configure(data->trans,w,h,*format ,*image, deserialize_vectors( vectors, length , scale_zoom ),length); + + } + if ( data->initialized == 2 ) + { + // Stabilize + float pos = mlt_filter_get_position( filter, frame ); + data->trans->current_trans=pos; + transform_filter_video(data->trans, *image, *format ); + + } + } } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } @@ -216,41 +225,50 @@ static void filter_close( mlt_filter parent ) { - StabData* self = parent->child; - stabilize_stop(self); - free( self ); + videostab2_data* data = parent->child; + if (data){ + if (data->stab) stabilize_stop(data->stab); + if (data->trans){ + if (data->trans->src) free(data->trans->src); + free (data->trans); + } + free( data ); + } parent->close = NULL; parent->child = NULL; } mlt_filter filter_videostab2_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { - StabData* self = calloc( 1, sizeof(StabData) ); - if ( self ) + videostab2_data* data= calloc( 1, sizeof(videostab2_data)); + data->stab = calloc( 1, sizeof(StabData) ); + data->trans = calloc( 1, sizeof (TransformData) ) ; + if ( data ) { mlt_filter parent = mlt_filter_new(); - parent->child = self; + + parent->child = data; parent->close = filter_close; parent->process = filter_process; - self->parent = parent; + data->parent = parent; //properties for stabilize - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "shakiness", "4" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "accuracy", "4" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "stepsize", "6" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "algo", "1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "mincontrast", "0.3" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "show", "0" ); - + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "shakiness", "4" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "accuracy", "4" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "stepsize", "6" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "algo", "1" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "mincontrast", "0.3" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "show", "0" ); + //properties for transform - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "smoothing", "10" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "maxshift", "-1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "maxangle", "-1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "crop", "0" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "invert", "0" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "relative", "1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "zoom", "0" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "optzoom", "1" ); - mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "sharpen", "0.8" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "smoothing", "10" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "maxshift", "-1" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "maxangle", "-1" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "crop", "0" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "invert", "0" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "relative", "1" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "zoom", "0" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "optzoom", "1" ); + mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "sharpen", "0.8" ); return parent; } return NULL; diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/filter_videostab.c mlt-0.7.6+git20120204/src/modules/videostab/filter_videostab.c --- mlt-0.7.6+git20111222/src/modules/videostab/filter_videostab.c 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/filter_videostab.c 2012-02-04 13:14:54.000000000 +0000 @@ -32,12 +32,13 @@ #include "stab/vector.h" #include "stab/utils.h" #include "stab/estimate.h" -#include "stab/resample.h" +#include "stab/resample.h" typedef struct { mlt_filter parent; int initialized; + int* lanc_kernels; es_ctx *es; vc *pos_i; vc *pos_h; @@ -146,9 +147,7 @@ hipass( self->pos_i, self->pos_h, length, fps ); serialize_vectors( self, length ); } - } - if ( vectors ) - { + } else { // Apply if ( self->initialized != 2 ) { @@ -164,8 +163,8 @@ int i; for (i = 0; i < h; i ++) - self->pos_y[i] = interp( self->pos_h, length, pos + (i - h / 2.0) * shutter_angle / (h * 360.0) ); - rs_resample( self->rs, *image, self->pos_y ); + self->pos_y[i] = interp( self->lanc_kernels,self->pos_h, length, pos + (i - h / 2.0) * shutter_angle / (h * 360.0) ); + rs_resample( self->lanc_kernels,self->rs, *image, self->pos_y ); } } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); @@ -188,7 +187,7 @@ if ( self->pos_h ) free( self->pos_h ); if ( self->pos_y ) free( self->pos_y ); if ( self->rs ) rs_free( self->rs ); - free_lanc_kernels(); + if ( self->lanc_kernels) free_lanc_kernels(self->lanc_kernels); free( self ); parent->close = NULL; parent->child = NULL; @@ -205,7 +204,7 @@ parent->process = filter_process; self->parent = parent; mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "shutterangle", "0" ); // 0 - 180 , default 0 - prepare_lanc_kernels(); + self->lanc_kernels=prepare_lanc_kernels(); return parent; } return NULL; diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/Makefile mlt-0.7.6+git20120204/src/modules/videostab/Makefile --- mlt-0.7.6+git20111222/src/modules/videostab/Makefile 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/Makefile 2012-02-04 13:14:54.000000000 +0000 @@ -1,8 +1,12 @@ -CFLAGS += -I../.. +include ../../../config.mak + +CFLAGS += -I../.. +ifdef SSE2_FLAGS +CFLAGS += -msse2 +endif -LDFLAGS += -L../../framework -lmlt -lm +LDFLAGS += -L../../framework -lmlt -lm -include ../../../config.mak TARGET = ../libmltvideostab$(LIBSUF) diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/stab/resample.c mlt-0.7.6+git20120204/src/modules/videostab/stab/resample.c --- mlt-0.7.6+git20111222/src/modules/videostab/stab/resample.c 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/stab/resample.c 2012-02-04 13:14:54.000000000 +0000 @@ -26,14 +26,14 @@ rs_ctx *rs = (rs_ctx *)malloc(sizeof(rs_ctx)); rs->tf = (unsigned char *)malloc(nc * nr * 3 * sizeof(unsigned char)); - + rs->nc = nc; rs->nr = nr; return rs; } -void rs_resample(rs_ctx *rs, unsigned char *f, vc *p) { +void rs_resample(int* lanc_kernels,rs_ctx *rs, unsigned char *f, vc *p) { int i, x, y, c; @@ -42,24 +42,24 @@ int yp = y * rs->nc; int xd = floor(p[y].x); - int *lk = select_lanc_kernel(p[y].x); + int *lk = select_lanc_kernel(lanc_kernels,p[y].x); for (x = 0; x < rs->nc; x ++) { int pd = (yp + x) * 3; int a[3]; - + for (c = 0; c < 3; c ++) a[c] = 0; for (i = -3; i < 5; i ++) { - + int ps = (yp + clamp(x + xd + i, 0, rs->nc - 1)) * 3; for (c = 0; c < 3; c ++) a[c] += f[ps + c] * lk[i + 3]; } - + for (c = 0; c < 3; c ++) rs->tf[pd + c] = clamp(a[c] / 1024, 0, 255); } @@ -70,18 +70,18 @@ int yp = y * rs->nc; int yd = floor(p[y].y); - int *lk = select_lanc_kernel(p[y].y); + int *lk = select_lanc_kernel(lanc_kernels,p[y].y); for (x = 0; x < rs->nc; x ++) { int pd = (yp + x) * 3; int a[3]; - + for (c = 0; c < 3; c ++) a[c] = 0; - + for (i = -3; i < 5; i ++) { - + int ps = (clamp(y + yd + i, 0, rs->nr - 1) * rs->nc + x) * 3; for (c = 0; c < 3; c ++) diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/stab/resample.h mlt-0.7.6+git20120204/src/modules/videostab/stab/resample.h --- mlt-0.7.6+git20111222/src/modules/videostab/stab/resample.h 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/stab/resample.h 2012-02-04 13:14:54.000000000 +0000 @@ -12,7 +12,7 @@ rs_ctx *rs_init(int, int); -void rs_resample(rs_ctx *, unsigned char *, vc *); +void rs_resample(int*,rs_ctx *, unsigned char *, vc *); void rs_free(rs_ctx *); diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/stab/utils.c mlt-0.7.6+git20120204/src/modules/videostab/stab/utils.c --- mlt-0.7.6+git20111222/src/modules/videostab/stab/utils.c 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/stab/utils.c 2012-02-04 13:14:54.000000000 +0000 @@ -21,8 +21,6 @@ #include "utils.h" -int *lanc_kernels = NULL; - float lanc(float x, float r) { float t = x * M_PI; @@ -32,7 +30,7 @@ if (x <= -r || x >= r) return 0.0; - + return r * sin(t) * sin(t / r) / (t * t); } @@ -67,7 +65,7 @@ cw += ck[i] = hann(i, d - 1); for (i = 0; i < l; i ++) { - + vc a = vc_zero(); for (j = i - r; j <= i + r; j ++) { @@ -79,7 +77,7 @@ vo[i] = vc_div(a, cw); } - + free(ck); } @@ -93,37 +91,38 @@ vo[i] = vc_sub(vi[i], vo[i]); } -void prepare_lanc_kernels() { +int* prepare_lanc_kernels() { int i, j; - lanc_kernels = (int *)malloc(256 * 8 * sizeof(int)); + int* lanc_kernels = (int *)malloc(256 * 8 * sizeof(int)); for (i = 0; i < 256; i ++) for (j = -3; j < 5; j ++) lanc_kernels[i * 8 + j + 3] = lanc(j - i / 256.0, 4) * 1024.0; + return lanc_kernels; } -int *select_lanc_kernel(float x) { +int *select_lanc_kernel(int* lanc_kernels,float x) { return lanc_kernels + (int)((x - floor(x)) * 256.0) * 8; } -void free_lanc_kernels() { +void free_lanc_kernels(int *lanc_kernels) { free(lanc_kernels); } -vc interp(vc *vi, int l, float x) { +vc interp(int* lanc_kernels, vc *vi, int l, float x) { vc a = vc_zero(); int xd = floor(x); - int *lk = select_lanc_kernel(x); + int *lk = select_lanc_kernel(lanc_kernels,x); int i; for (i = -3; i < 5; i ++) { - + int ic = clamp(xd + i, 0, l - 1); vc_mul_acc(&a, vi[ic], lk[i + 3]); diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/stab/utils.h mlt-0.7.6+git20120204/src/modules/videostab/stab/utils.h --- mlt-0.7.6+git20111222/src/modules/videostab/stab/utils.h 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/stab/utils.h 2012-02-04 13:14:54.000000000 +0000 @@ -15,7 +15,6 @@ #define FALSE 0 #endif -int *lanc_kernels; float lanc(float, float); float hann(float, float); @@ -25,11 +24,11 @@ void lopass(vc *, vc *, int, int); void hipass(vc *, vc *, int, int); -void prepare_lanc_kernels(); -int *select_lanc_kernel(float); -void free_lanc_kernels(); +int* prepare_lanc_kernels(); +int *select_lanc_kernel(int*,float); +void free_lanc_kernels(int*); -vc interp(vc *, int, float); +vc interp(int*,vc *, int, float); #endif diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/stabilize.c mlt-0.7.6+git20120204/src/modules/videostab/stabilize.c --- mlt-0.7.6+git20111222/src/modules/videostab/stabilize.c 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/stabilize.c 2012-02-04 13:14:54.000000000 +0000 @@ -2,28 +2,29 @@ * filter_stabilize.c * * Copyright (C) Georg Martius - June 2007 - * georg dot martius at web dot de + * georg dot martius at web dot de + * mlt adaption by Marco Gittler marco at gitma dot de 2011 * * This file is part of transcode, a video stream processing tool - * + * * transcode 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, or (at your option) * any later version. - * + * * transcode 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* Typical call: - * transcode -V -J stabilize=shakiness=5:show=1,preview + * transcode -V -J stabilize=shakiness=5:show=1,preview * -i inp.mpeg -y null,null -o dummy * all parameters are optional */ @@ -48,12 +49,14 @@ TC_MODULE_FLAG_RECONFIGURABLE | TC_MODULE_FLAG_DELAY #define MAX(a,b) ((a < b) ? (b) : (a)) #define MIN(a,b) ((a < b) ? (a) : (b)) -#include "stabilize.h" +#include "stabilize.h" #include #include #include #include - +#ifdef USE_SSE2 +#include +#endif void addTrans(StabData* sd, Transform sl) { @@ -66,7 +69,7 @@ /** initialise measurement fields on the frame. - The size of the fields and the maxshift is used to + The size of the fields and the maxshift is used to calculate an optimal distribution in the frame. */ int initFields(StabData* sd) @@ -77,7 +80,7 @@ // make sure that the remaining rows have the same length sd->field_num = rows*cols; sd->field_rows = rows; - mlt_log_warning (NULL,"field setup: rows: %i cols: %i Total: %i fields", + mlt_log_debug (NULL,"field setup: rows: %i cols: %i Total: %i fields", rows, cols, sd->field_num); if (!(sd->fields = malloc(sizeof(Field) * sd->field_num))) { @@ -109,13 +112,13 @@ \param d_x shift in x direction \param d_y shift in y direction */ -double compareImg(unsigned char* I1, unsigned char* I2, +double compareImg(unsigned char* I1, unsigned char* I2, int width, int height, int bytesPerPixel, int d_x, int d_y) { int i, j; unsigned char* p1 = NULL; unsigned char* p2 = NULL; - long int sum = 0; + long int sum = 0; int effectWidth = width - abs(d_x); int effectHeight = height - abs(d_y); @@ -131,77 +134,100 @@ for (i = 0; i < effectHeight; i++) { p1 = I1; p2 = I2; - if (d_y > 0 ){ + if (d_y > 0 ){ p1 += (i + d_y) * width * bytesPerPixel; p2 += i * width * bytesPerPixel; } else { p1 += i * width * bytesPerPixel; p2 += (i - d_y) * width * bytesPerPixel; } - if (d_x > 0) { + if (d_x > 0) { p1 += d_x * bytesPerPixel; } else { - p2 -= d_x * bytesPerPixel; + p2 -= d_x * bytesPerPixel; } - // TODO: use some mmx or sse stuff here - for (j = 0; j < effectWidth * bytesPerPixel; j++) { - /* debugging code continued */ +#ifdef USE_SSE2 + __m128i A,B,C,D,E; + for (j = 0; j < effectWidth * bytesPerPixel - 16; j++) { +#else + for (j = 0; j < effectWidth * bytesPerPixel; j++) { +#endif /* fwrite(p1,1,1,pic1);fwrite(p1,1,1,pic1);fwrite(p1,1,1,pic1); - fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2); + fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2); */ +#ifdef USE_SSE2 + A= _mm_loadu_si128((__m128i*)p1); //load unaligned data + B= _mm_loadu_si128((__m128i*)p2); + C= _mm_sad_epu8(A, B);//diff per 8 bit pixel stored in 2 64 byte values + D = _mm_srli_si128(C, 8); // shift first 64 byte value to align at the same as C + E = _mm_add_epi32(C, D); // add the 2 values (sum of all diffs) + sum+= _mm_cvtsi128_si32(E); //convert _m128i to int + + p1+=16; + p2+=16; + j+=15; +#else sum += abs((int)*p1 - (int)*p2); p1++; - p2++; + p2++; +#endif } } /* fclose(pic1); - fclose(pic2); + fclose(pic2); */ return sum/((double) effectWidth * effectHeight * bytesPerPixel); } /** - compares a small part of two given images + compares a small part of two given images and returns the average absolute difference. - Field center, size and shift have to be choosen, + Field center, size and shift have to be choosen, so that no clipping is required - - \param field Field specifies position(center) and size of subimage + + \param field Field specifies position(center) and size of subimage \param d_x shift in x direction - \param d_y shift in y direction + \param d_y shift in y direction */ -double compareSubImg(unsigned char* const I1, unsigned char* const I2, - const Field* field, +double compareSubImg(unsigned char* const I1, unsigned char* const I2, + const Field* field, int width, int height, int bytesPerPixel, int d_x, int d_y) { int k, j; unsigned char* p1 = NULL; unsigned char* p2 = NULL; int s2 = field->size / 2; - double sum = 0; + double sum=0.0; p1=I1 + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel; + p2=I2 + ((field->x - s2 + d_x) + (field->y - s2 + d_y)*width)*bytesPerPixel; // TODO: use some mmx or sse stuff here +#ifdef USE_SSE2 + __m128i A,B,C,D,E; +#endif for (j = 0; j < field->size; j++){ - - for (k = 0; k < field->size * bytesPerPixel; k++) { -#if HAVE_MMX -#error "wo" +#ifdef USE_SSE2 + for (k = 0; k < (field->size * bytesPerPixel) - 16 ; k++) { + A= _mm_loadu_si128((__m128i*)p1); //load unaligned data + B= _mm_loadu_si128((__m128i*)p2); + C= _mm_sad_epu8(A, B);//abd diff stored in 2 64 byte values + D = _mm_srli_si128(C, 8); // shift value 8 byte right + E = _mm_add_epi32(C, D); // add the 2 values (sum of all diffs) + sum+= _mm_cvtsi128_si32(E); //convert _m128i to int + + p1+=16; + p2+=16; + k+=15; #else + for (k = 0; k < (field->size * bytesPerPixel); k++) { sum += abs((int)*p1 - (int)*p2); - /*asm { - push edx - - pop edx - emms - }*/ -#endif p1++; - p2++; + p2++; +#endif } - p1 += (width - field->size) * bytesPerPixel; - p2 += (width - field->size) * bytesPerPixel; + p1 += ((width - field->size) * bytesPerPixel); + p2 += ((width - field->size) * bytesPerPixel); } return sum/((double) field->size *field->size* bytesPerPixel); } @@ -211,37 +237,75 @@ return contrastSubImg(sd->curr,field,sd->width,sd->height,1); } -/** - \see contrastSubImg three times called with bytesPerPixel=3 - for all channels +/** + \see contrastSubImg three times called with bytesPerPixel=3 + for all channels */ double contrastSubImgRGB(StabData* sd, const Field* field){ unsigned char* const I = sd->curr; - return ( contrastSubImg(I, field,sd->width,sd->height,3) + return ( contrastSubImg(I, field,sd->width,sd->height,3) + contrastSubImg(I+1,field,sd->width,sd->height,3) + contrastSubImg(I+2,field,sd->width,sd->height,3))/3; } /** calculates Michelson-contrast in the given small part of the given image - - \param I pointer to framebuffer - \param field Field specifies position(center) and size of subimage + + \param I pointer to framebuffer + \param field Field specifies position(center) and size of subimage \param width width of frame \param height height of frame \param bytesPerPixel calc contrast for only for first channel */ -double contrastSubImg(unsigned char* const I, const Field* field, +double contrastSubImg(unsigned char* const I, const Field* field, int width, int height, int bytesPerPixel) { +#if USE_SSE2 + int k, j; + int s2 = field->size / 2; + __m128i mini = _mm_set_epi64(_mm_set1_pi8(255), _mm_set1_pi8(255)); + __m128i maxi = _mm_set_epi64(_mm_set1_pi8(0) , _mm_set1_pi8(0)); + unsigned char* p = I + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel; + __m128i A; + for (j = 0; j < field->size; j++){ + for (k = 0; k < (field->size * bytesPerPixel)-16 ; k++) { + A= _mm_loadu_si128((__m128i*)p); //load unaligned data + + maxi = _mm_max_epu8(A,maxi); + mini = _mm_min_epu8(A,mini); + p+=16; + k+=15; + } + p += (width - field->size) * bytesPerPixel; + } + int max=0; + union { + __m128i m; + uint8_t t[16]; + } m; + m.m=maxi; + for (j=0;j<16;j++) { + if (m.t[j] >max) + max=m.t[j]; + } + int min=255; + m.m=mini; + for (j=0;j<16;j++) { + if (m.t[j] size / 2; unsigned char mini = 255; unsigned char maxi = 0; - p = I + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel; // TODO: use some mmx or sse stuff here + for (j = 0; j < field->size; j++){ for (k = 0; k < field->size * bytesPerPixel; k++) { mini = (mini < *p) ? mini : *p; @@ -251,6 +315,7 @@ p += (width - field->size) * bytesPerPixel; } return (maxi-mini)/(maxi+mini+0.1); // +0.1 to avoid division by 0 +#endif } /** tries to register current frame onto previous frame. @@ -262,23 +327,23 @@ { int x = 0, y = 0; int i, j; - double minerror = 1e20; + double minerror = 1e20; for (i = -sd->maxshift; i <= sd->maxshift; i++) { for (j = -sd->maxshift; j <= sd->maxshift; j++) { - double error = compareImg(sd->curr, sd->prev, + double error = compareImg(sd->curr, sd->prev, sd->width, sd->height, 3, i, j); if (error < minerror) { minerror = error; x = i; y = j; - } + } } - } + } return new_transform(x, y, 0, 0, 0); } -/** tries to register current frame onto previous frame. +/** tries to register current frame onto previous frame. (only the luminance is used) This is the most simple algorithm: shift images to all possible positions and calc summed error @@ -298,17 +363,17 @@ #endif // we only use the luminance part of the image - Y_c = sd->curr; + Y_c = sd->curr; // Cb_c = sd->curr + sd->width*sd->height; //Cr_c = sd->curr + 5*sd->width*sd->height/4; - Y_p = sd->prev; + Y_p = sd->prev; //Cb_p = sd->prev + sd->width*sd->height; //Cr_p = sd->prev + 5*sd->width*sd->height/4; - double minerror = 1e20; + double minerror = 1e20; for (i = -sd->maxshift; i <= sd->maxshift; i++) { for (j = -sd->maxshift; j <= sd->maxshift; j++) { - double error = compareImg(Y_c, Y_p, + double error = compareImg(Y_c, Y_p, sd->width, sd->height, 1, i, j); #ifdef STABVERBOSE fprintf(f, "%i %i %f\n", i, j, error); @@ -317,9 +382,9 @@ minerror = error; x = i; y = j; - } + } } - } + } #ifdef STABVERBOSE fclose(f); tc_log_msg(MOD_NAME, "Minerror: %f\n", minerror); @@ -329,23 +394,23 @@ -/* calculates rotation angle for the given transform and +/* calculates rotation angle for the given transform and * field with respect to the given center-point */ -double calcAngle(StabData* sd, Field* field, Transform* t, +double calcAngle(StabData* sd, Field* field, Transform* t, int center_x, int center_y) { - // we better ignore fields that are to close to the rotation center + // we better ignore fields that are to close to the rotation center if (abs(field->x - center_x) + abs(field->y - center_y) < sd->maxshift) { return 0; } else { - // double r = sqrt(field->x*field->x + field->y*field->y); + // double r = sqrt(field->x*field->x + field->y*field->y); double a1 = atan2(field->y - center_y, field->x - center_x); - double a2 = atan2(field->y - center_y + t->y, + double a2 = atan2(field->y - center_y + t->y, field->x - center_x + t->x); double diff = a2 - a1; - return (diff>M_PI) ? diff - 2*M_PI - : ( (diff<-M_PI) ? diff + 2*M_PI : diff); + return (diff>M_PI) ? diff - 2*M_PI + : ( (diff<-M_PI) ? diff + 2*M_PI : diff); } } @@ -367,28 +432,28 @@ /* return t; */ /* } */ #ifdef STABVERBOSE - // printf("%i %i %f\n", sd->t, fieldnum, contr); + // printf("%i %i %f\n", sd->t, fieldnum, contr); FILE *f = NULL; char buffer[32]; snprintf(buffer, sizeof(buffer), "f%04i_%02i.dat", sd->t, fieldnum); f = fopen(buffer, "w"); fprintf(f, "# splot \"%s\"\n", buffer); -#endif +#endif - double minerror = 1e10; + double minerror = 1e10; double error = 1e10; for (i = -sd->maxshift; i <= sd->maxshift; i += sd->stepsize) { for (j = -sd->maxshift; j <= sd->maxshift; j += sd->stepsize) { - error = compareSubImg(Y_c, Y_p, field, + error = compareSubImg(Y_c, Y_p, field, sd->width, sd->height, 1, i, j); #ifdef STABVERBOSE fprintf(f, "%i %i %f\n", i, j, error); -#endif +#endif if (error < minerror) { minerror = error; t.x = i; t.y = j; - } + } } } @@ -396,42 +461,42 @@ int r = sd->stepsize - 1; for (i = t.x - r; i <= t.x + r; i += 1) { for (j = -t.y - r; j <= t.y + r; j += 1) { - if (i == t.x && j == t.y) + if (i == t.x && j == t.y) continue; //no need to check this since already done - error = compareSubImg(Y_c, Y_p, field, + error = compareSubImg(Y_c, Y_p, field, sd->width, sd->height, 1, i, j); #ifdef STABVERBOSE fprintf(f, "%i %i %f\n", i, j, error); -#endif +#endif if (error < minerror){ minerror = error; t.x = i; t.y = j; - } + } } } } -#ifdef STABVERBOSE - fclose(f); - mlt_log_warning ( "Minerror: %f\n", minerror); +#ifdef STABVERBOSE + fclose(f); + mlt_log_debug ( "Minerror: %f\n", minerror); #endif if (!sd->allowmax && fabs(t.x) == sd->maxshift) { -#ifdef STABVERBOSE - mlt_log_warning ( "maximal x shift "); +#ifdef STABVERBOSE + mlt_log_debug ( "maximal x shift "); #endif t.x = 0; } if (!sd->allowmax && fabs(t.y) == sd->maxshift) { -#ifdef STABVERBOSE - mlt_log_warning ("maximal y shift "); +#ifdef STABVERBOSE + mlt_log_debug ("maximal y shift "); #endif t.y = 0; } return t; } -/* calculates the optimal transformation for one field in RGB +/* calculates the optimal transformation for one field in RGB * slower than the YUV version because it uses all three color channels */ Transform calcFieldTransRGB(StabData* sd, const Field* field, int fieldnum) @@ -439,28 +504,28 @@ Transform t = null_transform(); unsigned char *I_c = sd->curr, *I_p = sd->prev; int i, j; - - double minerror = 1e20; + + double minerror = 1e20; for (i = -sd->maxshift; i <= sd->maxshift; i += 2) { - for (j=-sd->maxshift; j <= sd->maxshift; j += 2) { - double error = compareSubImg(I_c, I_p, field, + for (j=-sd->maxshift; j <= sd->maxshift; j += 2) { + double error = compareSubImg(I_c, I_p, field, sd->width, sd->height, 3, i, j); if (error < minerror) { minerror = error; t.x = i; t.y = j; - } + } } } for (i = t.x - 1; i <= t.x + 1; i += 2) { for (j = -t.y - 1; j <= t.y + 1; j += 2) { - double error = compareSubImg(I_c, I_p, field, + double error = compareSubImg(I_c, I_p, field, sd->width, sd->height, 3, i, j); if (error < minerror) { minerror = error; t.x = i; t.y = j; - } + } } } if (!sd->allowmax && fabs(t.x) == sd->maxshift) { @@ -472,8 +537,8 @@ return t; } -/* compares contrast_idx structures respect to the contrast - (for sort function) +/* compares contrast_idx structures respect to the contrast + (for sort function) */ int cmp_contrast_idx(const void *ci1, const void* ci2) { @@ -491,7 +556,7 @@ int i,j; tlist* goodflds = tlist_new(0); contrast_idx *ci = malloc(sizeof(contrast_idx) * sd->field_num); - + // we split all fields into row+1 segments and take from each segment // the best fields int numsegms = (sd->field_rows+1); @@ -500,12 +565,12 @@ contrast_idx *ci_segms = malloc(sizeof(contrast_idx) * sd->field_num); int remaining = 0; // calculate contrast for each field - for (i = 0; i < sd->field_num; i++) { + for (i = 0; i < sd->field_num; i++) { ci[i].contrast = contrastfunc(sd, &sd->fields[i]); ci[i].index=i; if(ci[i].contrast < sd->contrast_threshold) ci[i].contrast = 0; // else printf("%i %lf\n", ci[i].index, ci[i].contrast); - } + } memcpy(ci_segms, ci, sizeof(contrast_idx) * sd->field_num); // get best fields from each segment @@ -516,33 +581,33 @@ //printf("Segment: %i: %i-%i\n", i, startindex, endindex); // sort within segment - qsort(ci_segms+startindex, endindex-startindex, - sizeof(contrast_idx), cmp_contrast_idx); + qsort(ci_segms+startindex, endindex-startindex, + sizeof(contrast_idx), cmp_contrast_idx); // take maxfields/numsegms for(j=0; jmaxfields/numsegms; j++){ if(startindex+j >= endindex) continue; - // printf("%i %lf\n", ci_segms[startindex+j].index, + // printf("%i %lf\n", ci_segms[startindex+j].index, // ci_segms[startindex+j].contrast); - if(ci_segms[startindex+j].contrast > 0){ + if(ci_segms[startindex+j].contrast > 0){ tlist_append(goodflds, &ci[ci_segms[startindex+j].index],sizeof(contrast_idx)); // don't consider them in the later selection process - ci_segms[startindex+j].contrast=0; - } + ci_segms[startindex+j].contrast=0; + } } } // check whether enough fields are selected // printf("Phase2: %i\n", tc_list_size(goodflds)); - remaining = sd->maxfields - tlist_size(goodflds); + remaining = sd->maxfields - tlist_size(goodflds); if(remaining > 0){ // take the remaining from the leftovers - qsort(ci_segms, sd->field_num, + qsort(ci_segms, sd->field_num, sizeof(contrast_idx), cmp_contrast_idx); for(j=0; j < remaining; j++){ if(ci_segms[j].contrast > 0){ - tlist_append(goodflds, &ci_segms[j], sizeof(contrast_idx)); - } + tlist_append(goodflds, &ci_segms[j], sizeof(contrast_idx)); + } } - } + } // printf("Ende: %i\n", tc_list_size(goodflds)); free(ci); free(ci_segms); @@ -551,11 +616,11 @@ -/* tries to register current frame onto previous frame. +/* tries to register current frame onto previous frame. * Algorithm: * check all fields for vertical and horizontal transformation * use minimal difference of all possible positions - * discards fields with low contrast + * discards fields with low contrast * select maxfields field according to their contrast * calculate shift as cleaned mean of all remaining fields * calculate rotation angle of each field in respect to center of fields @@ -578,17 +643,17 @@ f = fopen(buffer, "w"); fprintf(f, "# plot \"%s\" w l, \"\" every 2:1:0\n", buffer); #endif - + tlist* goodflds = selectfields(sd, contrastfunc); - // use all "good" fields and calculate optimal match to previous frame + // use all "good" fields and calculate optimal match to previous frame contrast_idx* f; while((f = (contrast_idx*)tlist_pop(goodflds,0) ) != 0){ int i = f->index; t = fieldfunc(sd, &sd->fields[i], i); // e.g. calcFieldTransYUV #ifdef STABVERBOSE - fprintf(f, "%i %i\n%f %f %i\n \n\n", sd->fields[i].x, sd->fields[i].y, + fprintf(f, "%i %i\n%f %f %i\n \n\n", sd->fields[i].x, sd->fields[i].y, sd->fields[i].x + t.x, sd->fields[i].y + t.y, t.extra); #endif if (t.extra != -1){ // ignore if extra == -1 (unused at the moment) @@ -600,37 +665,37 @@ tlist_fini(goodflds); t = null_transform(); - num_trans = index; // amount of transforms we actually have + num_trans = index; // amount of transforms we actually have if (num_trans < 1) { printf( "too low contrast! No field remains.\n \ (no translations are detected in frame %i)", sd->t); return t; } - + int center_x = 0; int center_y = 0; // calc center point of all remaining fields for (i = 0; i < num_trans; i++) { center_x += fs[i]->x; - center_y += fs[i]->y; - } + center_y += fs[i]->y; + } center_x /= num_trans; - center_y /= num_trans; - + center_y /= num_trans; + if (sd->show){ // draw fields and transforms into frame. - // this has to be done one after another to handle possible overlap + // this has to be done one after another to handle possible overlap if (sd->show > 1) { for (i = 0; i < num_trans; i++) - drawFieldScanArea(sd, fs[i], &ts[i]); + drawFieldScanArea(sd, fs[i], &ts[i]); } for (i = 0; i < num_trans; i++) - drawField(sd, fs[i], &ts[i]); + drawField(sd, fs[i], &ts[i]); for (i = 0; i < num_trans; i++) - drawFieldTrans(sd, fs[i], &ts[i]); - } + drawFieldTrans(sd, fs[i], &ts[i]); + } /* median over all transforms t= median_xy_transform(ts, sd->field_num);*/ - // cleaned mean + // cleaned mean t = cleanmean_xy_transform(ts, num_trans); // substract avg @@ -640,8 +705,8 @@ // figure out angle if (sd->field_num < 6) { // the angle calculation is inaccurate for 5 and less fields - t.alpha = 0; - } else { + t.alpha = 0; + } else { for (i = 0; i < num_trans; i++) { angles[i] = calcAngle(sd, fs[i], &ts[i], center_x, center_y); } @@ -649,7 +714,7 @@ t.alpha = -cleanmean(angles, num_trans, &min, &max); if(max-min>sd->maxanglevariation){ t.alpha=0; - printf( "too large variation in angle(%f)\n", + printf( "too large variation in angle(%f)\n", max-min); } } @@ -658,8 +723,8 @@ double p_x = (center_x - sd->width/2); double p_y = (center_y - sd->height/2); t.x += (cos(t.alpha)-1)*p_x - sin(t.alpha)*p_y; - t.y += sin(t.alpha)*p_x + (cos(t.alpha)-1)*p_y; - + t.y += sin(t.alpha)*p_x + (cos(t.alpha)-1)*p_y; + #ifdef STABVERBOSE fclose(f); #endif @@ -673,8 +738,8 @@ mlt_log_warning (NULL, "format not usable\n"); return; } - drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, - field->size+2*sd->maxshift, field->size+2*sd->maxshift, 80); + drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, + field->size+2*sd->maxshift, field->size+2*sd->maxshift, 80); } /** draws the field */ @@ -684,7 +749,7 @@ mlt_log_warning (NULL, "format not usable\n"); return; } - drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, + drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, field->size, field->size, t->extra == -1 ? 100 : 40); } @@ -695,20 +760,20 @@ mlt_log_warning (NULL, "format not usable\n"); return; } - drawBox(sd->curr, sd->width, sd->height, 1, + drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y, 5, 5, 128); // draw center - drawBox(sd->curr, sd->width, sd->height, 1, + drawBox(sd->curr, sd->width, sd->height, 1, field->x + t->x, field->y + t->y, 8, 8, 250); // draw translation } /** * draws a box at the given position x,y (center) in the given color - (the same for all channels) + (the same for all channels) */ -void drawBox(unsigned char* I, int width, int height, int bytesPerPixel, +void drawBox(unsigned char* I, int width, int height, int bytesPerPixel, int x, int y, int sizex, int sizey, unsigned char color){ - - unsigned char* p = NULL; + + unsigned char* p = NULL; int j,k; p = I + ((x - sizex/2) + (y - sizey/2)*width)*bytesPerPixel; for (j = 0; j < sizey; j++){ @@ -724,21 +789,7 @@ FILE *f; int counter; }; -#if 0 -static int stabilize_dump_trans(tlist*item, void *userdata) -{ - struct iterdata *ID = userdata; - if (item->data) { - Transform* t = (Transform*) item->data; - fprintf(ID->f, "%i %6.4lf %6.4lf %8.5lf %6.4lf %i\n", - ID->counter, t->x, t->y, t->alpha, t->zoom, t->extra); - ID->counter++; - } - return 0; /* never give up */ -} - -#endif /*************************************************************************/ /* Module interface routines and data. */ @@ -752,17 +803,10 @@ int stabilize_init(StabData* instance) { - instance = malloc(sizeof(StabData)); // allocation with zero values - memset(instance,sizeof(StabData),0); + instance = calloc(1,sizeof(StabData)); // allocation with zero values if (!instance) { return -1; } - - //stab->vob=pixelfmt; - /**** Initialise private data structure */ - - //self->userdata = sd; - return 0; } @@ -776,85 +820,61 @@ /*TCModuleExtraData *xdata[]*/) { StabData *sd = instance; - /* sd->framesize = sd->vob->im_v_width * MAX_PLANES * + /* sd->framesize = sd->vob->im_v_width * MAX_PLANES * sizeof(char) * 2 * sd->vob->im_v_height * 2; */ /*TODO sd->framesize = sd->vob->im_v_size; */ - sd->prev = calloc(1,sd->framesize); - if (!sd->prev) { + sd->prev = calloc(1,sd->framesize); + sd->grayimage = calloc(1,sd->width*sd->height); + + if (!sd->prev || !sd->grayimage) { printf( "malloc failed"); return -1; } sd->currcopy = 0; - - /*sd->width = sd->vob->ex_v_width; - sd->height = sd->vob->ex_v_height; -*/ sd->hasSeenOneFrame = 0; sd->transs = 0; - - // Options - // done in filter : sd->stepsize = 6; sd->allowmax = 0; - // done in filter :sd->algo = 1; -// sd->field_num = 64; - // done in filter : sd->accuracy = 4; - // done in filter : sd->shakiness = 4; sd->field_size = MIN(sd->width, sd->height)/12; - // done in filter : sd->show = 0; - // done in filter : sd->contrast_threshold = 0.3; sd->maxanglevariation = 1; - - /*if (options != NULL) { - // for some reason this plugin is called in the old fashion - // (not with inspect). Anyway we support both ways of getting help. - if(optstr_lookup(options, "help")) { - printf(stabilize_help); - return -2; - } - - optstr_get(options, "shakiness", "%d", &sd->shakiness); - optstr_get(options, "accuracy", "%d", &sd->accuracy); - optstr_get(options, "stepsize", "%d", &sd->stepsize); - optstr_get(options, "algo", "%d", &sd->algo); - optstr_get(options, "mincontrast","%lf",&sd->contrast_threshold); - optstr_get(options, "show", "%d", &sd->show); - }*/ + sd->shakiness = MIN(10,MAX(1,sd->shakiness)); sd->accuracy = MAX(sd->shakiness,MIN(15,MAX(1,sd->accuracy))); if (1) { - mlt_log_warning (NULL, "Image Stabilization Settings:\n"); - mlt_log_warning (NULL, " shakiness = %d\n", sd->shakiness); - mlt_log_warning (NULL, " accuracy = %d\n", sd->accuracy); - mlt_log_warning (NULL, " stepsize = %d\n", sd->stepsize); - mlt_log_warning (NULL, " algo = %d\n", sd->algo); - mlt_log_warning (NULL, " mincontrast = %f\n", sd->contrast_threshold); - mlt_log_warning (NULL, " show = %d\n", sd->show); + mlt_log_debug (NULL, "Image Stabilization Settings:\n"); + mlt_log_debug (NULL, " shakiness = %d\n", sd->shakiness); + mlt_log_debug (NULL, " accuracy = %d\n", sd->accuracy); + mlt_log_debug (NULL, " stepsize = %d\n", sd->stepsize); + mlt_log_debug (NULL, " algo = %d\n", sd->algo); + mlt_log_debug (NULL, " mincontrast = %f\n", sd->contrast_threshold); + mlt_log_debug (NULL, " show = %d\n", sd->show); } +#ifndef USE_SSE2 + mlt_log_info(NULL,"No SSE2 support enabled, this will slow down a lot\n"); +#endif // shift and size: shakiness 1: height/40; 10: height/4 sd->maxshift = MIN(sd->width, sd->height)*sd->shakiness/40; sd->field_size = MIN(sd->width, sd->height)*sd->shakiness/40; - - mlt_log_warning ( NULL, "Fieldsize: %i, Maximal translation: %i pixel\n", + + mlt_log_debug ( NULL, "Fieldsize: %i, Maximal translation: %i pixel\n", sd->field_size, sd->maxshift); - if (sd->algo==1) { + if (sd->algo==1) { // initialize measurement fields. field_num is set here. if (!initFields(sd)) { return -1; } sd->maxfields = (sd->accuracy) * sd->field_num / 15; - mlt_log_warning ( NULL, "Number of used measurement fields: %i out of %i\n", + mlt_log_debug ( NULL, "Number of used measurement fields: %i out of %i\n", sd->maxfields, sd->field_num); } if (sd->show){ - sd->currcopy = malloc(sd->framesize); - memset ( sd->currcopy, sd->framesize, 0 ); + sd->currcopy = calloc(1,sd->framesize); } /* load unsharp filter to smooth the frames. This allows larger stepsize.*/ char unsharp_param[128]; int masksize = MIN(13,sd->stepsize*1.8); // only works up to 13. - sprintf(unsharp_param,"luma=-1:luma_matrix=%ix%i:pre=1", + sprintf(unsharp_param,"luma=-1:luma_matrix=%ix%i:pre=1", masksize, masksize); return 0; } @@ -865,16 +885,27 @@ * See tcmodule-data.h for function details. */ -int stabilize_filter_video(StabData* instance, +int stabilize_filter_video(StabData* instance, unsigned char *frame,mlt_image_format pixelformat) { StabData *sd = instance; - sd->pixelformat=pixelformat; - - if(sd->show) // save the buffer to restore at the end for prev - memcpy(sd->currcopy, frame, sd->framesize); + sd->pixelformat=pixelformat; + int l=sd->width*sd->height; + unsigned char* tmpgray=sd->grayimage; + if (pixelformat == mlt_image_yuv422){ + while(l--){ + *tmpgray++=*frame++; + frame++; + }; + } + + if(sd->show) { // save the buffer to restore at the end for prev + if (pixelformat == mlt_image_yuv420p){ + memcpy(sd->currcopy, sd->grayimage, sd->framesize); + } + } if (sd->hasSeenOneFrame) { - sd->curr = frame; + sd->curr = sd->grayimage; if (pixelformat == mlt_image_rgb24) { if (sd->algo == 0) addTrans(sd, calcShiftRGBSimple(sd)); @@ -887,6 +918,12 @@ else if (sd->algo == 1) addTrans(sd, calcTransFields(sd, calcFieldTransYUV, contrastSubImgYUV)); + } else if (pixelformat == mlt_image_yuv422 ) { + if (sd->algo == 0) + addTrans(sd, calcShiftYUVSimple(sd)); + else if (sd->algo == 1) + addTrans(sd, calcTransFields(sd, calcFieldTransYUV, + contrastSubImgYUV)); } else { mlt_log_warning (NULL,"unsupported Codec: %i\n", pixelformat); @@ -896,9 +933,9 @@ sd->hasSeenOneFrame = 1; addTrans(sd, null_transform()); } - + if(!sd->show) { // copy current frame to prev for next frame comparison - memcpy(sd->prev, frame, sd->framesize); + memcpy(sd->prev, sd->grayimage, sd->framesize); } else { // use the copy because we changed the original frame memcpy(sd->prev, sd->currcopy, sd->framesize); } @@ -914,38 +951,15 @@ int stabilize_stop(StabData* instance) { StabData *sd = instance; - - // print transs - /*struct iterdata ID; - ID.counter = 0; - ID.f = sd->f; - // write parameters as comments to file - fprintf(sd->f, "# accuracy = %d\n", sd->accuracy); - fprintf(sd->f, "# shakiness = %d\n", sd->shakiness); - fprintf(sd->f, "# stepsize = %d\n", sd->stepsize); - fprintf(sd->f, "# algo = %d\n", sd->algo); - fprintf(sd->f, "# mincontrast = %f\n", sd->contrast_threshold); - // write header line - fprintf(sd->f, "# Transforms\n#C FrameNr x y alpha zoom extra\n"); - // and all transforms - tc_list_foreach(sd->transs, stabilize_dump_trans, &ID); -*/ - /* FOR DEBUG ONLY - - tlist* transf=sd->transs; - int num=0; - while (transf ){ - Transform* t=transf->data; - if (t) - printf("%d %f %f %f %f %d\n",num++,t->x,t->y,t->alpha,t->zoom,t->extra); - transf=transf->next; - } - */ - //tc_list_del(sd->transs, 1 ); if (sd->prev) { free(sd->prev); sd->prev = NULL; } + if (sd->grayimage){ + free(sd->grayimage); + sd->grayimage=NULL; + + } return 0; } diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/stabilize.h mlt-0.7.6+git20120204/src/modules/videostab/stabilize.h --- mlt-0.7.6+git20111222/src/modules/videostab/stabilize.h 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/stabilize.h 2012-02-04 13:14:54.000000000 +0000 @@ -79,6 +79,7 @@ unsigned char* curr; // current frame buffer (only pointer) unsigned char* currcopy; // copy of the current frame needed for drawing unsigned char* prev; // frame buffer for last frame (copied) + unsigned char* grayimage; // frame buffer for last frame (copied) short hasSeenOneFrame; // true if we have a valid previous frame int width, height; @@ -86,7 +87,6 @@ /* list of transforms*/ //TCList* transs; - void* parent; tlist* transs; Field* fields; @@ -115,7 +115,6 @@ int t; char conf_str[1024]; - int initialized; } StabData; /* type for a function that calculates the transformation of a certain field diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/transform_image.c mlt-0.7.6+git20120204/src/modules/videostab/transform_image.c --- mlt-0.7.6+git20111222/src/modules/videostab/transform_image.c 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/transform_image.c 2012-02-04 13:14:54.000000000 +0000 @@ -2,23 +2,23 @@ * filter_transform.c * * Copyright (C) Georg Martius - June 2007 - * georg dot martius at web dot de + * georg dot martius at web dot de * * This file is part of transcode, a video stream processing tool - * + * * transcode 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, or (at your option) * any later version. - * + * * transcode 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * Typical call: * transcode -J transform -i inp.mpeg -y xdiv,tcaud inp_stab.avi @@ -41,118 +41,118 @@ static const char* interpoltypes[5] = {"No (0)", "Linear (1)", "Bi-Linear (2)", "Quadratic (3)", "Bi-Cubic (4)"}; -void (*interpolate)(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char def) = 0; +void (*interpolate)(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, + unsigned char def,unsigned char N, unsigned char channel) = 0; /** interpolateBiLinBorder: bi-linear interpolation function that also works at the border. This is used by many other interpolation methods at and outsize the border, see interpolate */ -void interpolateBiLinBorder(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char def) +void interpolateBiLinBorder(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, + unsigned char def,unsigned char N, unsigned char channel) { int x_f = myfloor(x); int x_c = x_f+1; int y_f = myfloor(y); int y_c = y_f+1; - short v1 = PIXEL(img, x_c, y_c, width, height, def); - short v2 = PIXEL(img, x_c, y_f, width, height, def); - short v3 = PIXEL(img, x_f, y_c, width, height, def); - short v4 = PIXEL(img, x_f, y_f, width, height, def); - float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + + short v1 = PIXELN(img, x_c, y_c, width, height, N, channel, def); + short v2 = PIXELN(img, x_c, y_f, width, height, N, channel, def); + short v3 = PIXELN(img, x_f, y_c, width, height, N, channel, def); + short v4 = PIXELN(img, x_f, y_f, width, height, N, channel, def); + float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + (v2*(x - x_f) + v4*(x_c - x))*(y_c - y); *rv = (unsigned char)s; } /* taken from http://en.wikipedia.org/wiki/Bicubic_interpolation for alpha=-0.5 - in matrix notation: + in matrix notation: a0-a3 are the neigthboring points where the target point is between a1 and a2 t is the point of interpolation (position between a1 and a2) value between 0 and 1 | 0, 2, 0, 0 | |a0| |-1, 0, 1, 0 | |a1| (1,t,t^2,t^3) | 2,-5, 4,-1 | |a2| - |-1, 3,-3, 1 | |a3| + |-1, 3,-3, 1 | |a3| */ -static short bicub_kernel(float t, short a0, short a1, short a2, short a3){ +static short bicub_kernel(float t, short a0, short a1, short a2, short a3){ return (2*a1 + t*((-a0+a2) + t*((2*a0-5*a1+4*a2-a3) + t*(-a0+3*a1-3*a2+a3) )) ) / 2; } /** interpolateBiCub: bi-cubic interpolation function using 4x4 pixel, see interpolate */ -void interpolateBiCub(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, unsigned char def) +void interpolateBiCub(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) { // do a simple linear interpolation at the border - if (x < 1 || x > width-2 || y < 1 || y > height - 2) { - interpolateBiLinBorder(rv, x,y,img,width,height,def); + if (x < 1 || x > width-2 || y < 1 || y > height - 2) { + interpolateBiLinBorder(rv, x,y,img,width,height,def,N,channel); } else { int x_f = myfloor(x); int y_f = myfloor(y); float tx = x-x_f; short v1 = bicub_kernel(tx, - PIX(img, x_f-1, y_f-1, width, height), - PIX(img, x_f, y_f-1, width, height), - PIX(img, x_f+1, y_f-1, width, height), - PIX(img, x_f+2, y_f-1, width, height)); + PIXN(img, x_f-1, y_f-1, width, height, N, channel), + PIXN(img, x_f, y_f-1, width, height, N, channel), + PIXN(img, x_f+1, y_f-1, width, height, N, channel), + PIXN(img, x_f+2, y_f-1, width, height, N, channel)); short v2 = bicub_kernel(tx, - PIX(img, x_f-1, y_f, width, height), - PIX(img, x_f, y_f, width, height), - PIX(img, x_f+1, y_f, width, height), - PIX(img, x_f+2, y_f, width, height)); + PIXN(img, x_f-1, y_f, width, height, N, channel), + PIXN(img, x_f, y_f, width, height, N, channel), + PIXN(img, x_f+1, y_f, width, height, N, channel), + PIXN(img, x_f+2, y_f, width, height, N, channel)); short v3 = bicub_kernel(tx, - PIX(img, x_f-1, y_f+1, width, height), - PIX(img, x_f, y_f+1, width, height), - PIX(img, x_f+1, y_f+1, width, height), - PIX(img, x_f+2, y_f+1, width, height)); + PIXN(img, x_f-1, y_f+1, width, height, N, channel), + PIXN(img, x_f, y_f+1, width, height, N, channel), + PIXN(img, x_f+1, y_f+1, width, height, N, channel), + PIXN(img, x_f+2, y_f+1, width, height, N, channel)); short v4 = bicub_kernel(tx, - PIX(img, x_f-1, y_f+2, width, height), - PIX(img, x_f, y_f+2, width, height), - PIX(img, x_f+1, y_f+2, width, height), - PIX(img, x_f+2, y_f+2, width, height)); + PIXN(img, x_f-1, y_f+2, width, height, N, channel), + PIXN(img, x_f, y_f+2, width, height, N, channel), + PIXN(img, x_f+1, y_f+2, width, height, N, channel), + PIXN(img, x_f+2, y_f+2, width, height, N, channel)); *rv = (unsigned char)bicub_kernel(y-y_f, v1, v2, v3, v4); } } /** interpolateSqr: bi-quatratic interpolation function, see interpolate */ -void interpolateSqr(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, unsigned char def) +void interpolateSqr(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) { - if (x < 0 || x > width-1 || y < 0 || y > height - 1) { - interpolateBiLinBorder(rv, x, y, img, width, height, def); + if (x < 0 || x > width-1 || y < 0 || y > height - 1) { + interpolateBiLinBorder(rv, x, y, img, width, height, def,N,channel); } else { int x_f = myfloor(x); int x_c = x_f+1; int y_f = myfloor(y); int y_c = y_f+1; - short v1 = PIX(img, x_c, y_c, width, height); - short v2 = PIX(img, x_c, y_f, width, height); - short v3 = PIX(img, x_f, y_c, width, height); - short v4 = PIX(img, x_f, y_f, width, height); + short v1 = PIXN(img, x_c, y_c, width, height, N, channel); + short v2 = PIXN(img, x_c, y_f, width, height, N, channel); + short v3 = PIXN(img, x_f, y_c, width, height, N, channel); + short v4 = PIXN(img, x_f, y_f, width, height, N, channel); float f1 = 1 - sqrt((x_c - x) * (y_c - y)); float f2 = 1 - sqrt((x_c - x) * (y - y_f)); float f3 = 1 - sqrt((x - x_f) * (y_c - y)); float f4 = 1 - sqrt((x - x_f) * (y - y_f)); float s = (v1*f1 + v2*f2 + v3*f3+ v4*f4)/(f1 + f2 + f3 + f4); - *rv = (unsigned char)s; + *rv = (unsigned char)s; } } /** interpolateBiLin: bi-linear interpolation function, see interpolate */ -void interpolateBiLin(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char def) +void interpolateBiLin(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, + unsigned char def,unsigned char N, unsigned char channel) { - if (x < 0 || x > width-1 || y < 0 || y > height - 1) { - interpolateBiLinBorder(rv, x, y, img, width, height, def); + if (x < 0 || x > width-1 || y < 0 || y > height - 1) { + interpolateBiLinBorder(rv, x, y, img, width, height, def,N,channel); } else { int x_f = myfloor(x); int x_c = x_f+1; int y_f = myfloor(y); int y_c = y_f+1; - short v1 = PIX(img, x_c, y_c, width, height); - short v2 = PIX(img, x_c, y_f, width, height); - short v3 = PIX(img, x_f, y_c, width, height); - short v4 = PIX(img, x_f, y_f, width, height); - float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + + short v1 = PIXN(img, x_c, y_c, width, height, N, channel); + short v2 = PIXN(img, x_c, y_f, width, height, N, channel); + short v3 = PIXN(img, x_f, y_c, width, height, N, channel); + short v4 = PIXN(img, x_f, y_f, width, height, N, channel); + float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + (v2*(x - x_f) + v4*(x_c - x))*(y_c - y); *rv = (unsigned char)s; } @@ -160,35 +160,35 @@ /** interpolateLin: linear (only x) interpolation function, see interpolate */ -void interpolateLin(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, - unsigned char def) +void interpolateLin(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, + unsigned char def,unsigned char N, unsigned char channel) { int x_f = myfloor(x); int x_c = x_f+1; int y_n = myround(y); - float v1 = PIXEL(img, x_c, y_n, width, height, def); - float v2 = PIXEL(img, x_f, y_n, width, height, def); + float v1 = PIXELN(img, x_c, y_n, width, height, N, channel,def); + float v2 = PIXELN(img, x_f, y_n, width, height, N, channel,def); float s = v1*(x - x_f) + v2*(x_c - x); *rv = (unsigned char)s; } /** interpolateZero: nearest neighbor interpolation function, see interpolate */ -void interpolateZero(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, unsigned char def) +void interpolateZero(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel) { int x_n = myround(x); int y_n = myround(y); - *rv = (unsigned char) PIXEL(img, x_n, y_n, width, height, def); + *rv = (unsigned char) PIXELN(img, x_n, y_n, width, height, N,channel,def); } -/** - * interpolateN: Bi-linear interpolation function for N channel image. +/** + * interpolateN: Bi-linear interpolation function for N channel image. * * Parameters: * rv: destination pixel (call by reference) - * x,y: the source coordinates in the image img. Note this + * x,y: the source coordinates in the image img. Note this * are real-value coordinates, that's why we interpolate * img: source image * width,height: dimension of image @@ -197,13 +197,13 @@ * def: default value if coordinates are out of range * Return value: None */ -void interpolateN(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, +void interpolateN(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, unsigned char N, unsigned char channel, unsigned char def) { if (x < - 1 || x > width || y < -1 || y > height) { - *rv = def; + *rv = def; } else { int x_f = myfloor(x); int x_c = x_f+1; @@ -212,19 +212,19 @@ short v1 = PIXELN(img, x_c, y_c, width, height, N, channel, def); short v2 = PIXELN(img, x_c, y_f, width, height, N, channel, def); short v3 = PIXELN(img, x_f, y_c, width, height, N, channel, def); - short v4 = PIXELN(img, x_f, y_f, width, height, N, channel, def); - float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + + short v4 = PIXELN(img, x_f, y_f, width, height, N, channel, def); + float s = (v1*(x - x_f)+v3*(x_c - x))*(y - y_f) + (v2*(x - x_f) + v4*(x_c - x))*(y_c - y); - *rv = (unsigned char)s; + *rv = (unsigned char)s; } } -/** +/** * transformRGB: applies current transformation to frame * Parameters: * td: private data structure of this filter - * Return value: + * Return value: * 0 for failture, 1 for success * Preconditions: * The frame must be in RGB format @@ -235,50 +235,53 @@ int x = 0, y = 0, z = 0; unsigned char *D_1, *D_2; t = td->trans[td->current_trans]; - - D_1 = td->src; - D_2 = td->dest; + + D_1 = td->src; + D_2 = td->dest; + float zm = 1.0-t.zoom/100; + float zcos_a = zm*cos(-t.alpha); // scaled cos + float zsin_a = zm*sin(-t.alpha); // scaled sin float c_s_x = td->width_src/2.0; float c_s_y = td->height_src/2.0; float c_d_x = td->width_dest/2.0; - float c_d_y = td->height_dest/2.0; + float c_d_y = td->height_dest/2.0; /* for each pixel in the destination image we calc the source - * coordinate and make an interpolation: - * p_d = c_d + M(p_s - c_s) + t - * where p are the points, c the center coordinate, - * _s source and _d destination, + * coordinate and make an interpolation: + * p_d = c_d + M(p_s - c_s) + t + * where p are the points, c the center coordinate, + * _s source and _d destination, * t the translation, and M the rotation matrix * p_s = M^{-1}(p_d - c_d - t) + c_s */ /* All 3 channels */ - if (fabs(t.alpha) > td->rotation_threshhold) { + if (fabs(t.alpha) > td->rotation_threshhold || t.zoom != 0) { for (x = 0; x < td->width_dest; x++) { for (y = 0; y < td->height_dest; y++) { float x_d1 = (x - c_d_x); float y_d1 = (y - c_d_y); - float x_s = cos(-t.alpha) * x_d1 - + sin(-t.alpha) * y_d1 + c_s_x -t.x; - float y_s = -sin(-t.alpha) * x_d1 - + cos(-t.alpha) * y_d1 + c_s_y -t.y; - for (z = 0; z < 3; z++) { // iterate over colors + float x_s = zcos_a * x_d1 + + zsin_a * y_d1 + c_s_x -t.x; + float y_s = -zsin_a * x_d1 + + zcos_a * y_d1 + c_s_y -t.y; + for (z = 0; z < 3; z++) { // iterate over colors unsigned char* dest = &D_2[(x + y * td->width_dest)*3+z]; - interpolateN(dest, x_s, y_s, D_1, - td->width_src, td->height_src, - 3, z, td->crop ? 16 : *dest); + interpolate(dest, myfloor(x_s), myfloor(y_s), D_1, + td->width_src, td->height_src, + td->crop ? 16 : *dest,3,z); } } } - }else { - /* no rotation, just translation - *(also no interpolation, since no size change (so far) + }else { + /* no rotation, just translation + *(also no interpolation, since no size change (so far) */ int round_tx = myround(t.x); int round_ty = myround(t.y); for (x = 0; x < td->width_dest; x++) { for (y = 0; y < td->height_dest; y++) { for (z = 0; z < 3; z++) { // iterate over colors - short p = PIXELN(D_1, x - round_tx, y - round_ty, + short p = PIXELN(D_1, x - round_tx, y - round_ty, td->width_src, td->height_src, 3, z, -1); if (p == -1) { if (td->crop == 1) @@ -293,12 +296,12 @@ return 1; } -/** +/** * transformYUV: applies current transformation to frame * * Parameters: * td: private data structure of this filter - * Return value: + * Return value: * 0 for failture, 1 for success * Preconditions: * The frame must be in YUV format @@ -309,9 +312,9 @@ int x = 0, y = 0; unsigned char *Y_1, *Y_2, *Cb_1, *Cb_2, *Cr_1, *Cr_2; t = td->trans[td->current_trans]; - - Y_1 = td->src; - Y_2 = td->dest; + + Y_1 = td->src; + Y_2 = td->dest; Cb_1 = td->src + td->width_src * td->height_src; Cb_2 = td->dest + td->width_dest * td->height_dest; Cr_1 = td->src + 5*td->width_src * td->height_src/4; @@ -319,17 +322,17 @@ float c_s_x = td->width_src/2.0; float c_s_y = td->height_src/2.0; float c_d_x = td->width_dest/2.0; - float c_d_y = td->height_dest/2.0; - + float c_d_y = td->height_dest/2.0; + float z = 1.0-t.zoom/100; float zcos_a = z*cos(-t.alpha); // scaled cos float zsin_a = z*sin(-t.alpha); // scaled sin /* for each pixel in the destination image we calc the source - * coordinate and make an interpolation: - * p_d = c_d + M(p_s - c_s) + t - * where p are the points, c the center coordinate, - * _s source and _d destination, + * coordinate and make an interpolation: + * p_d = c_d + M(p_s - c_s) + t + * where p are the points, c the center coordinate, + * _s source and _d destination, * t the translation, and M the rotation and scaling matrix * p_s = M^{-1}(p_d - c_d - t) + c_s */ @@ -339,25 +342,25 @@ for (y = 0; y < td->height_dest; y++) { float x_d1 = (x - c_d_x); float y_d1 = (y - c_d_y); - float x_s = zcos_a * x_d1 + float x_s = zcos_a * x_d1 + zsin_a * y_d1 + c_s_x -t.x; - float y_s = -zsin_a * x_d1 + float y_s = -zsin_a * x_d1 + zcos_a * y_d1 + c_s_y -t.y; unsigned char* dest = &Y_2[x + y * td->width_dest]; - interpolate(dest, x_s, y_s, Y_1, - td->width_src, td->height_src, - td->crop ? 16 : *dest); + interpolate(dest, x_s, y_s, Y_1, + td->width_src, td->height_src, + td->crop ? 16 : *dest,1,0); } } - }else { - /* no rotation, no zooming, just translation - *(also no interpolation, since no size change) + }else { + /* no rotation, no zooming, just translation + *(also no interpolation, since no size change) */ int round_tx = myround(t.x); int round_ty = myround(t.y); for (x = 0; x < td->width_dest; x++) { for (y = 0; y < td->height_dest; y++) { - short p = PIXEL(Y_1, x - round_tx, y - round_ty, + short p = PIXEL(Y_1, x - round_tx, y - round_ty, td->width_src, td->height_src, -1); if (p == -1) { if (td->crop == 1) @@ -379,29 +382,29 @@ for (y = 0; y < hd2; y++) { float x_d1 = x - (c_d_x)/2; float y_d1 = y - (c_d_y)/2; - float x_s = zcos_a * x_d1 + float x_s = zcos_a * x_d1 + zsin_a * y_d1 + (c_s_x -t.x)/2; - float y_s = -zsin_a * x_d1 + float y_s = -zsin_a * x_d1 + zcos_a * y_d1 + (c_s_y -t.y)/2; unsigned char* dest = &Cr_2[x + y * wd2]; - interpolate(dest, x_s, y_s, Cr_1, ws2, hs2, - td->crop ? 128 : *dest); + interpolate(dest, x_s, y_s, Cr_1, ws2, hs2, + td->crop ? 128 : *dest,1,0); dest = &Cb_2[x + y * wd2]; - interpolate(dest, x_s, y_s, Cb_1, ws2, hs2, - td->crop ? 128 : *dest); + interpolate(dest, x_s, y_s, Cb_1, ws2, hs2, + td->crop ? 128 : *dest,1,0); } } - } else { // no rotation, no zoom, no interpolation, just translation + } else { // no rotation, no zoom, no interpolation, just translation int round_tx2 = myround(t.x/2.0); - int round_ty2 = myround(t.y/2.0); + int round_ty2 = myround(t.y/2.0); for (x = 0; x < wd2; x++) { for (y = 0; y < hd2; y++) { - short cr = PIXEL(Cr_1, x - round_tx2, y - round_ty2, + short cr = PIXEL(Cr_1, x - round_tx2, y - round_ty2, wd2, hd2, -1); - short cb = PIXEL(Cb_1, x - round_tx2, y - round_ty2, + short cb = PIXEL(Cb_1, x - round_tx2, y - round_ty2, wd2, hd2, -1); if (cr == -1) { - if (td->crop==1) { + if (td->crop==1) { Cr_2[x + y * wd2] = 128; Cb_2[x + y * wd2] = 128; } @@ -419,7 +422,7 @@ /** * preprocess_transforms: does smoothing, relative to absolute conversion, * and cropping of too large transforms. - * This is actually the core algorithm for canceling the jiggle in the + * This is actually the core algorithm for canceling the jiggle in the * movie. We perform a low-pass filter in terms of transformation size. * This enables still camera movement, but in a smooth fasion. * @@ -440,7 +443,7 @@ if (td->trans_len < 1) return 0; if (0) { - mlt_log_warning(NULL,"Preprocess transforms:"); + mlt_log_debug(NULL,"Preprocess transforms:"); } if (td->smoothing>0) { /* smoothing */ @@ -454,35 +457,35 @@ */ int s = td->smoothing * 2 + 1; Transform null = null_transform(); - /* avg is the average over [-smoothing, smoothing] transforms + /* avg is the average over [-smoothing, smoothing] transforms around the current point */ Transform avg; - /* avg2 is a sliding average over the filtered signal! (only to past) + /* avg2 is a sliding average over the filtered signal! (only to past) * with smoothing * 10 horizont to kill offsets */ Transform avg2 = null_transform(); double tau = 1.0/(3 * s); /* initialise sliding sum with hypothetic sum centered around * -1st element. We have two choices: - * a) assume the camera is not moving at the beginning + * a) assume the camera is not moving at the beginning * b) assume that the camera moves and we use the first transforms */ - Transform s_sum = null; + Transform s_sum = null; for (i = 0; i < td->smoothing; i++){ s_sum = add_transforms(&s_sum, i < td->trans_len ? &ts2[i]:&null); } mult_transform(&s_sum, 2); // choice b (comment out for choice a) for (i = 0; i < td->trans_len; i++) { - Transform* old = ((i - td->smoothing - 1) < 0) + Transform* old = ((i - td->smoothing - 1) < 0) ? &null : &ts2[(i - td->smoothing - 1)]; - Transform* new = ((i + td->smoothing) >= td->trans_len) + Transform* new = ((i + td->smoothing) >= td->trans_len) ? &null : &ts2[(i + td->smoothing)]; s_sum = sub_transforms(&s_sum, old); s_sum = add_transforms(&s_sum, new); avg = mult_transform(&s_sum, 1.0/s); - /* lowpass filter: + /* lowpass filter: * meaning high frequency must be transformed away */ ts[i] = sub_transforms(&ts2[i], &avg); @@ -492,35 +495,35 @@ ts[i] = sub_transforms(&ts[i], &avg2); if (0 /*verbose*/ ) { - mlt_log_warning(NULL,"s_sum: %5lf %5lf %5lf, ts: %5lf, %5lf, %5lf\n", - s_sum.x, s_sum.y, s_sum.alpha, + mlt_log_warning(NULL,"s_sum: %5lf %5lf %5lf, ts: %5lf, %5lf, %5lf\n", + s_sum.x, s_sum.y, s_sum.alpha, ts[i].x, ts[i].y, ts[i].alpha); - mlt_log_warning(NULL, - " avg: %5lf, %5lf, %5lf avg2: %5lf, %5lf, %5lf", - avg.x, avg.y, avg.alpha, - avg2.x, avg2.y, avg2.alpha); + mlt_log_warning(NULL, + " avg: %5lf, %5lf, %5lf avg2: %5lf, %5lf, %5lf", + avg.x, avg.y, avg.alpha, + avg2.x, avg2.y, avg2.alpha); } } free(ts2); } - - + + /* invert? */ if (td->invert) { for (i = 0; i < td->trans_len; i++) { - ts[i] = mult_transform(&ts[i], -1); + ts[i] = mult_transform(&ts[i], -1); } } - + /* relative to absolute */ if (td->relative) { Transform t = ts[0]; for (i = 1; i < td->trans_len; i++) { if (0/*verbose*/ ) { - mlt_log_warning(NULL, "shift: %5lf %5lf %lf \n", + mlt_log_warning(NULL, "shift: %5lf %5lf %lf \n", t.x, t.y, t.alpha *180/M_PI); } - ts[i] = add_transforms(&ts[i], &t); + ts[i] = add_transforms(&ts[i], &t); t = ts[i]; } } @@ -534,25 +537,25 @@ for (i = 0; i < td->trans_len; i++) ts[i].alpha = TC_CLAMP(ts[i].alpha, -td->maxangle, td->maxangle); - /* Calc optimal zoom + /* Calc optimal zoom * cheap algo is to only consider transformations - * uses cleaned max and min + * uses cleaned max and min */ - if (td->optzoom != 0 && td->trans_len > 1){ + if (td->optzoom != 0 && td->trans_len > 1){ Transform min_t, max_t; - cleanmaxmin_xy_transform(ts, td->trans_len, 10, &min_t, &max_t); + cleanmaxmin_xy_transform(ts, td->trans_len, 10, &min_t, &max_t); // the zoom value only for x double zx = 2*TC_MAX(max_t.x,fabs(min_t.x))/td->width_src; // the zoom value only for y double zy = 2*TC_MAX(max_t.y,fabs(min_t.y))/td->height_src; td->zoom += 100* TC_MAX(zx,zy); // use maximum - mlt_log_warning(NULL,"Final zoom: %lf\n", td->zoom); + mlt_log_debug(NULL,"Final zoom: %lf\n", td->zoom); } - + /* apply global zoom */ if (td->zoom != 0){ for (i = 0; i < td->trans_len; i++) - ts[i].zoom += td->zoom; + ts[i].zoom += td->zoom; } return 1; @@ -571,7 +574,7 @@ TransformData* td = NULL; TC_MODULE_SELF_CHECK(self, "init"); TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features); - + td = tc_zalloc(sizeof(TransformData)); if (td == NULL) { tc_log_error(MOD_NAME, "init: out of memory!"); @@ -590,83 +593,83 @@ * transform_configure: Configure this instance of the module. See * tcmodule-data.h for function details. */ -int transform_configure(TransformData *self,int width,int height, mlt_image_format pixelformat, unsigned char* image ,Transform* tx,int trans_len) +int transform_configure(TransformData *self,int width,int height, mlt_image_format pixelformat, unsigned char* image ,Transform* tx,int trans_len) { TransformData *td = self; /**** Initialise private data structure */ /* td->framesize = td->vob->im_v_width * - * MAX_PLANES * sizeof(char) * 2 * td->vob->im_v_height * 2; + * MAX_PLANES * sizeof(char) * 2 * td->vob->im_v_height * 2; */ // rgb24 = w*h*3 , yuv420p = w* h* 3/2 - td->framesize_src = width*height*(pixelformat==mlt_image_rgb24 ? 3 : (3.0/2.0)); + td->framesize_src = width*height*(pixelformat==mlt_image_rgb24 ? 3 : (3.0/2.0)); td->src = malloc(td->framesize_src); /* FIXME */ if (td->src == NULL) { mlt_log_error(NULL,"tc_malloc failed\n"); return -1; } - + td->width_src = width; td->height_src = height; - + /* Todo: in case we can scale the images, calc new size later */ td->width_dest = width; td->height_dest = height; td->framesize_dest = td->framesize_src; td->dest = 0; - + td->trans = tx; td->trans_len = trans_len; td->current_trans = 0; - td->warned_transform_end = 0; + td->warned_transform_end = 0; /* Options */ // set from filter td->maxshift = -1; // set from filter td->maxangle = -1; - + // set from filter td->crop = 0; // set from filter td->relative = 1; // set from filter td->invert = 0; // set from filter td->smoothing = 10; - + td->rotation_threshhold = 0.25/(180/M_PI); // set from filter td->zoom = 0; // set from filter td->optzoom = 1; // set from filter td->interpoltype = 2; // bi-linear // set from filter td->sharpen = 0.8; - + td->interpoltype = TC_MIN(td->interpoltype,4); if (1) { - mlt_log_warning(NULL, "Image Transformation/Stabilization Settings:\n"); - mlt_log_warning(NULL, " smoothing = %d\n", td->smoothing); - mlt_log_warning(NULL, " maxshift = %d\n", td->maxshift); - mlt_log_warning(NULL, " maxangle = %f\n", td->maxangle); - mlt_log_warning(NULL, " crop = %s\n", + mlt_log_debug(NULL, "Image Transformation/Stabilization Settings:\n"); + mlt_log_debug(NULL, " smoothing = %d\n", td->smoothing); + mlt_log_debug(NULL, " maxshift = %d\n", td->maxshift); + mlt_log_debug(NULL, " maxangle = %f\n", td->maxangle); + mlt_log_debug(NULL, " crop = %s\n", td->crop ? "Black" : "Keep"); - mlt_log_warning(NULL, " relative = %s\n", + mlt_log_debug(NULL, " relative = %s\n", td->relative ? "True": "False"); - mlt_log_warning(NULL, " invert = %s\n", + mlt_log_debug(NULL, " invert = %s\n", td->invert ? "True" : "False"); - mlt_log_warning(NULL, " zoom = %f\n", td->zoom); - mlt_log_warning(NULL, " optzoom = %s\n", + mlt_log_debug(NULL, " zoom = %f\n", td->zoom); + mlt_log_debug(NULL, " optzoom = %s\n", td->optzoom ? "On" : "Off"); - mlt_log_warning(NULL, " interpol = %s\n", + mlt_log_debug(NULL, " interpol = %s\n", interpoltypes[td->interpoltype]); - mlt_log_warning(NULL, " sharpen = %f\n", td->sharpen); + mlt_log_debug(NULL, " sharpen = %f\n", td->sharpen); } - + if (td->maxshift > td->width_dest/2 ) td->maxshift = td->width_dest/2; if (td->maxshift > td->height_dest/2) td->maxshift = td->height_dest/2; - + if (!preprocess_transforms(td)) { mlt_log_error(NULL,"error while preprocessing transforms!"); - return -1; - } + return -1; + } switch(td->interpoltype){ case 0: interpolate = &interpolateZero; break; @@ -676,7 +679,7 @@ case 4: interpolate = &interpolateBiCub; break; default: interpolate = &interpolateBiLin; } - + return 0; } @@ -685,21 +688,21 @@ * transform_filter_video: performs the transformation of frames * See tcmodule-data.h for function details. */ -int transform_filter_video(TransformData *self, - unsigned char *frame,mlt_image_format pixelformat) +int transform_filter_video(TransformData *self, + unsigned char *frame,mlt_image_format pixelformat) { TransformData *td = self; - + td->dest = frame; memcpy(td->src, frame, td->framesize_src); - if (td->current_trans >= td->trans_len) { + if (td->current_trans >= td->trans_len) { td->current_trans = td->trans_len-1; if(!td->warned_transform_end) mlt_log_warning(NULL,"not enough transforms found, use last transformation!\n"); - td->warned_transform_end = 1; + td->warned_transform_end = 1; } - + if (pixelformat == mlt_image_rgb24 ) { transformRGB(td); } else if (pixelformat == mlt_image_yuv420p) { diff -Nru mlt-0.7.6+git20111222/src/modules/videostab/transform_image.h mlt-0.7.6+git20120204/src/modules/videostab/transform_image.h --- mlt-0.7.6+git20111222/src/modules/videostab/transform_image.h 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/videostab/transform_image.h 2012-02-04 13:14:54.000000000 +0000 @@ -2,23 +2,23 @@ * filter_transform.c * * Copyright (C) Georg Martius - June 2007 - * georg dot martius at web dot de + * georg dot martius at web dot de * * This file is part of transcode, a video stream processing tool - * + * * transcode 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, or (at your option) * any later version. - * + * * transcode 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * Typical call: * transcode -J transform -i inp.mpeg -y xdiv,tcaud inp_stab.avi @@ -34,11 +34,12 @@ #define DEFAULT_TRANS_FILE_NAME "transforms.dat" #define PIXEL(img, x, y, w, h, def) ((x) < 0 || (y) < 0) ? def \ - : (((x) >=w || (y) >= h) ? def : img[(x) + (y) * w]) -#define PIX(img, x, y, w, h) (img[(x) + (y) * w]) + : (((x) >=w || (y) >= h) ? def : img[(x) + (y) * w]) +#define PIX(img, x, y, w, h) (img[(x) + (y) * w]) +#define PIXN(img, x, y, w, h,N,channel) (img[((x) + (y) * w)*N+channel]) // gives Pixel in N-channel image. channel in {0..N-1} #define PIXELN(img, x, y, w, h, N,channel , def) ((x) < 0 || (y) < 0) ? def \ - : (((x) >=w || (y) >= h) ? def : img[((x) + (y) * w)*N + channel]) + : (((x) >=w || (y) >= h) ? def : img[((x) + (y) * w)*N + channel]) typedef struct { int framesize_src; // size of frame buffer in bytes (src) @@ -53,23 +54,23 @@ int current_trans; // index to current transformation int trans_len; // length of trans array short warned_transform_end; // whether we warned that there is no transform left - + /* Options */ int maxshift; // maximum number of pixels we will shift double maxangle; // maximum angle in rad - /* whether to consider transforms as relative (to previous frame) - * or absolute transforms + /* whether to consider transforms as relative (to previous frame) + * or absolute transforms */ - int relative; - /* number of frames (forward and backward) + int relative; + /* number of frames (forward and backward) * to use for smoothing transforms */ - int smoothing; + int smoothing; int crop; // 1: black bg, 0: keep border from last frame(s) int invert; // 1: invert transforms, 0: nothing /* constants */ /* threshhold below which no rotation is performed */ - double rotation_threshhold; + double rotation_threshhold; double zoom; // percentage to zoom: 0->no zooming 10:zoom in 10% int optzoom; // 1: determine optimal zoom, 0: nothing int interpoltype; // type of interpolation: 0->Zero,1->Lin,2->BiLin,3->Sqr @@ -79,20 +80,20 @@ } TransformData; /* forward declarations, please look below for documentation*/ -void interpolateBiLinBorder(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def); -void interpolateBiCub(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, unsigned char def); -void interpolateSqr(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def); -void interpolateBiLin(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def); -void interpolateLin(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def); -void interpolateZero(unsigned char *rv, float x, float y, - unsigned char* img, int w, int h, unsigned char def); -void interpolateN(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, +void interpolateBiLinBorder(unsigned char *rv, float x, float y, + unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); +void interpolateBiCub(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, unsigned char def,unsigned char N, unsigned char channel); +void interpolateSqr(unsigned char *rv, float x, float y, + unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); +void interpolateBiLin(unsigned char *rv, float x, float y, + unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); +void interpolateLin(unsigned char *rv, float x, float y, + unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); +void interpolateZero(unsigned char *rv, float x, float y, + unsigned char* img, int w, int h, unsigned char def,unsigned char N, unsigned char channel); +void interpolateN(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, unsigned char N, unsigned char channel, unsigned char def); int transformRGB(TransformData* td); int transformYUV(TransformData* td); @@ -100,25 +101,25 @@ int preprocess_transforms(TransformData* td); -/** +/** * interpolate: general interpolation function pointer for one channel image data * * Parameters: * rv: destination pixel (call by reference) - * x,y: the source coordinates in the image img. Note this + * x,y: the source coordinates in the image img. Note this * are real-value coordinates, that's why we interpolate * img: source image * width,height: dimension of image * def: default value if coordinates are out of range * Return value: None */ -/*void (*interpolate)(unsigned char *rv, float x, float y, - unsigned char* img, int width, int height, +/*void (*interpolate)(unsigned char *rv, float x, float y, + unsigned char* img, int width, int height, unsigned char def) = 0; */ /** interpolateBiLinBorder: bi-linear interpolation function that also works at the border. This is used by many other interpolation methods at and outsize the border, see interpolate */ int transform_configure(TransformData *self,int width,int height, mlt_image_format pixelformat, unsigned char* image,Transform* tx,int trans_len) ; -int transform_filter_video(TransformData *self, +int transform_filter_video(TransformData *self, unsigned char *frame,mlt_image_format pixelformat); diff -Nru mlt-0.7.6+git20111222/src/modules/xml/consumer_xml.c mlt-0.7.6+git20120204/src/modules/xml/consumer_xml.c --- mlt-0.7.6+git20111222/src/modules/xml/consumer_xml.c 2011-10-08 12:23:44.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/xml/consumer_xml.c 2012-02-04 13:14:54.000000000 +0000 @@ -26,6 +26,7 @@ #include #include #include +#include #define ID_SIZE 128 @@ -59,7 +60,37 @@ static void *consumer_thread( void *arg ); static void serialise_service( serialise_context context, mlt_service service, xmlNode *node ); -typedef enum +static char* filter_restricted( const char *in ) +{ + if ( !in ) return NULL; + size_t n = strlen( in ); + char *out = calloc( 1, n + 1 ); + char *p = out; + mbstate_t mbs; + memset( &mbs, 0, sizeof(mbs) ); + while ( *in ) + { + wchar_t w; + size_t c = mbrtowc( &w, in, n, &mbs ); + if ( c <= 0 ) break; + n -= c; + in += c; + if ( w == 0x9 || w == 0xA || w == 0xD || + ( w >= 0x20 && w <= 0xD7FF ) || + ( w >= 0xE000 && w <= 0xFFFD ) || + ( w >= 0x10000 && w <= 0x10FFFF ) ) + { + mbstate_t ps; + memset( &ps, 0, sizeof(ps) ); + c = wcrtomb( p, w, &ps ); + if ( c > 0 ) + p += c; + } + } + return out; +} + +typedef enum { xml_existing, xml_producer, @@ -91,7 +122,7 @@ // Attempt to reuse existing id id = mlt_properties_get( MLT_SERVICE_PROPERTIES( service ), "id" ); - // If no id, or the id is used in the map (for another service), then + // If no id, or the id is used in the map (for another service), then // create a new one. if ( id == NULL || mlt_properties_get_data( map, id, NULL ) != NULL ) { @@ -182,7 +213,7 @@ { int i; xmlNode *p; - + // Enumerate the properties for ( i = 0; i < mlt_properties_count( properties ); i++ ) { @@ -200,12 +231,18 @@ strcmp( name, "width" ) && strcmp( name, "height" ) ) { - char *value = mlt_properties_get_value( properties, i ); - int rootlen = strlen( context->root ); - if ( rootlen && !strncmp( value, context->root, rootlen ) && value[ rootlen ] == '/' ) - value += rootlen + 1; - p = xmlNewTextChild( node, NULL, _x("property"), _x(value) ); - xmlNewProp( p, _x("name"), _x(name) ); + char *value = filter_restricted( mlt_properties_get_value( properties, i ) ); + if ( value ) + { + int rootlen = strlen( context->root ); + // convert absolute path to relative + if ( rootlen && !strncmp( value, context->root, rootlen ) && value[ rootlen ] == '/' ) + p = xmlNewTextChild( node, NULL, _x("property"), _x(value + rootlen + 1 ) ); + else + p = xmlNewTextChild( node, NULL, _x("property"), _x(value) ); + xmlNewProp( p, _x("name"), _x(name) ); + free( value ); + } } } } @@ -214,21 +251,24 @@ { int i; xmlNode *p; - + // Enumerate the properties for ( i = 0; store != NULL && i < mlt_properties_count( properties ); i++ ) { char *name = mlt_properties_get_name( properties, i ); if ( !strncmp( name, store, strlen( store ) ) ) { - char *value = mlt_properties_get_value( properties, i ); - if ( value != NULL ) + char *value = filter_restricted( mlt_properties_get_value( properties, i ) ); + if ( value ) { int rootlen = strlen( context->root ); + // convert absolute path to relative if ( rootlen && !strncmp( value, context->root, rootlen ) && value[ rootlen ] == '/' ) - value += rootlen + 1; - p = xmlNewTextChild( node, NULL, _x("property"), _x(value) ); + p = xmlNewTextChild( node, NULL, _x("property"), _x(value + rootlen + 1) ); + else + p = xmlNewTextChild( node, NULL, _x("property"), _x(value) ); xmlNewProp( p, _x("name"), _x(name) ); + free( value ); } } } @@ -239,7 +279,7 @@ int i; xmlNode *p; mlt_filter filter = NULL; - + // Enumerate the filters for ( i = 0; ( filter = mlt_producer_filter( MLT_PRODUCER( service ), i ) ) != NULL; i ++ ) { @@ -275,7 +315,7 @@ { xmlNode *child = node; mlt_service parent = MLT_SERVICE( mlt_producer_cut_parent( MLT_PRODUCER( service ) ) ); - + if ( context->pass == 0 ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( parent ); @@ -313,7 +353,7 @@ static void serialise_multitrack( serialise_context context, mlt_service service, xmlNode *node ) { int i; - + if ( context->pass == 0 ) { // Iterate over the tracks to collect the producers @@ -351,7 +391,7 @@ serialise_store_properties( context, MLT_PRODUCER_PROPERTIES( producer ), track, "meta." ); serialise_service_filters( context, MLT_PRODUCER_SERVICE( producer ), track ); } - + hide = mlt_properties_get_int( context->hide_map, id ); if ( hide ) xmlNewProp( track, _x("hide"), _x( hide == 1 ? "video" : ( hide == 2 ? "audio" : "both" ) ) ); @@ -366,7 +406,7 @@ xmlNode *child = node; mlt_playlist_clip_info info; mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); - + if ( context->pass == 0 ) { // Get a new id - if already allocated, do nothing @@ -391,7 +431,7 @@ } } } - + child = xmlNewChild( node, NULL, _x("playlist"), NULL ); // Set the id @@ -406,7 +446,7 @@ // Add producer to the map mlt_properties_set_int( context->hide_map, id, mlt_properties_get_int( properties, "hide" ) ); - + // Iterate over the playlist entries for ( i = 0; i < mlt_playlist_count( MLT_PLAYLIST( service ) ); i++ ) { @@ -461,7 +501,7 @@ { xmlNode *child = node; mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); - + if ( context->pass == 0 ) { // Recurse on connected producer @@ -500,7 +540,7 @@ { xmlNode *child = node; mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); - + // Recurse on connected producer serialise_service( context, mlt_service_producer( service ), node ); @@ -529,7 +569,7 @@ { xmlNode *child = node; mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); - + // Recurse on connected producer serialise_service( context, MLT_SERVICE( MLT_TRANSITION( service )->producer ), node ); @@ -541,7 +581,7 @@ return; child = xmlNewChild( node, NULL, _x("transition"), NULL ); - + // Set the id xmlNewProp( child, _x("id"), _x(id) ); if ( mlt_properties_get( properties, "title" ) ) @@ -561,7 +601,7 @@ { mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); char *mlt_type = mlt_properties_get( properties, "mlt_type" ); - + // Tell about the producer if ( strcmp( mlt_type, "producer" ) == 0 ) { @@ -587,20 +627,20 @@ else if ( strcmp( mlt_type, "mlt_producer" ) == 0 ) { char *resource = mlt_properties_get( properties, "resource" ); - + // Recurse on multitrack's tracks if ( resource && strcmp( resource, "" ) == 0 ) { serialise_multitrack( context, service, node ); break; } - + // Recurse on playlist's clips else if ( resource && strcmp( resource, "" ) == 0 ) { serialise_playlist( context, service, node ); } - + // Recurse on tractor's producer else if ( resource && strcmp( resource, "" ) == 0 ) { @@ -618,21 +658,21 @@ serialise_producer( context, service, node ); } } - + // Tell about a filter else if ( strcmp( mlt_type, "filter" ) == 0 ) { serialise_filter( context, service, node ); break; } - + // Tell about a transition else if ( strcmp( mlt_type, "transition" ) == 0 ) { serialise_transition( context, service, node ); break; } - + // Get the next connected service service = mlt_service_producer( service ); } @@ -706,7 +746,7 @@ // Construct the context maps context->id_map = mlt_properties_new(); context->hide_map = mlt_properties_new(); - + // Ensure producer is a framework producer mlt_properties_set( MLT_SERVICE_PROPERTIES( service ), "mlt_type", "mlt_producer" ); @@ -724,7 +764,7 @@ mlt_properties_close( context->hide_map ); free( context->root ); free( context ); - + return doc; } diff -Nru mlt-0.7.6+git20111222/src/modules/xml/producer_xml.c mlt-0.7.6+git20120204/src/modules/xml/producer_xml.c --- mlt-0.7.6+git20111222/src/modules/xml/producer_xml.c 2011-12-20 18:07:09.000000000 +0000 +++ mlt-0.7.6+git20120204/src/modules/xml/producer_xml.c 2012-02-04 13:14:54.000000000 +0000 @@ -22,6 +22,7 @@ // when the returned producer is closed). #include +#include #include #include #include @@ -1469,6 +1470,28 @@ return e; } +static void on_error( void * ctx, const char * msg, ...) +{ + struct _xmlError* err_ptr = xmlCtxtGetLastError(ctx); + + switch( err_ptr->level ) + { + case XML_ERR_WARNING: + mlt_log_warning( NULL, "XML parse warning: %s\trow: %d\tcol: %d\n", + err_ptr->message, err_ptr->line, err_ptr->int2); + break; + case XML_ERR_ERROR: + mlt_log_error( NULL, "XML parse error: %s\trow: %d\tcol: %d\n", + err_ptr->message, err_ptr->line, err_ptr->int2); + break; + default: + case XML_ERR_FATAL: + mlt_log_fatal( NULL, "XML parse fatal: %s\trow: %d\tcol: %d\n", + err_ptr->message, err_ptr->line, err_ptr->int2); + break; + } +} + /** Convert a hexadecimal character to its value. */ static int tohex( char p ) @@ -1607,8 +1630,11 @@ // We need to track the number of registered filters mlt_properties_set_int( context->destructors, "registered", 0 ); - // Setup SAX callbacks + // Setup SAX callbacks for first pass sax->startElement = on_start_element; + sax->warning = on_error; + sax->error = on_error; + sax->fatalError = on_error; // Setup libxml2 SAX parsing xmlInitParser(); @@ -1636,6 +1662,7 @@ xmlcontext->sax = sax; xmlcontext->_private = ( void* )context; xmlParseDocument( xmlcontext ); + well_formed = xmlcontext->wellFormed; // Cleanup after parsing xmlcontext->sax = NULL; @@ -1644,6 +1671,19 @@ context->stack_node_size = 0; context->stack_service_size = 0; + // Bad xml - clean up and return NULL + if ( !well_formed ) + { + mlt_properties_close( context->producer_map ); + mlt_properties_close( context->destructors ); + mlt_properties_close( context->params ); + xmlFreeDoc( context->entity_doc ); + free( context ); + free( sax ); + free( filename ); + return NULL; + } + // Setup the second pass context->pass ++; if ( info == 0 ) @@ -1664,7 +1704,7 @@ return NULL; } - // Setup SAX callbacks + // Setup SAX callbacks for second pass sax->endElement = on_end_element; sax->characters = on_characters; sax->cdataBlock = on_characters;