From 092636b85449e57fd33ffd4954a2de23c2a5f81c Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Sat, 27 Dec 2003 18:34:18 +0000 Subject: [PATCH] ppm ffmpeg git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@26 d19143bc-622f-0410-bfdd-b5b2a6649095 --- Makefile | 2 +- README | 32 ++-- configure | 2 +- mlt/Makefile | 2 +- mlt/README | 32 ++-- mlt/configure | 2 +- mlt/setenv | 10 ++ mlt/src/framework/mlt_frame.c | 73 ++++----- mlt/src/framework/mlt_playlist.c | 2 +- mlt/src/inigo/Makefile | 28 ++++ mlt/src/inigo/configure | 0 mlt/src/inigo/inigo.c | 226 +++++++++++++++++++++++++++ mlt/src/inigo/io.c | 208 ++++++++++++++++++++++++ mlt/src/inigo/io.h | 45 ++++++ mlt/src/modules/core/filter_resize.c | 7 +- mlt/src/modules/core/filter_resize.h | 2 +- mlt/src/modules/core/producer_ppm.c | 120 ++++++++++++-- mlt/src/modules/core/producer_ppm.h | 4 +- mlt/src/modules/sdl/consumer_sdl.c | 2 +- mlt/src/tests/charlie.c | 2 + setenv | 10 ++ src/framework/mlt_frame.c | 73 ++++----- src/framework/mlt_playlist.c | 2 +- src/inigo/Makefile | 28 ++++ src/inigo/configure | 0 src/inigo/inigo.c | 226 +++++++++++++++++++++++++++ src/inigo/io.c | 208 ++++++++++++++++++++++++ src/inigo/io.h | 45 ++++++ src/modules/core/filter_resize.c | 7 +- src/modules/core/filter_resize.h | 2 +- src/modules/core/producer_ppm.c | 120 ++++++++++++-- src/modules/core/producer_ppm.h | 4 +- src/modules/sdl/consumer_sdl.c | 2 +- src/tests/charlie.c | 2 + 34 files changed, 1392 insertions(+), 138 deletions(-) create mode 100644 mlt/setenv create mode 100644 mlt/src/inigo/Makefile create mode 100755 mlt/src/inigo/configure create mode 100644 mlt/src/inigo/inigo.c create mode 100644 mlt/src/inigo/io.c create mode 100644 mlt/src/inigo/io.h create mode 100644 setenv create mode 100644 src/inigo/Makefile create mode 100755 src/inigo/configure create mode 100644 src/inigo/inigo.c create mode 100644 src/inigo/io.c create mode 100644 src/inigo/io.h diff --git a/Makefile b/Makefile index a2754671..ef218098 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = src/framework src/valerie src/modules # src/miracle src/humperdink +SUBDIRS = src/framework src/modules src/inigo src/valerie # src/miracle src/humperdink all clean dist-clean depend install: list='$(SUBDIRS)'; \ diff --git a/README b/README index 6ed3c5f6..fc7f3c56 100644 --- a/README +++ b/README @@ -14,21 +14,24 @@ Directories + docs - Location of all text and source format documentation + src - All project source is provided here - + framework - The media framework - this code is 100% posix - and as such contain no implementations - requiring additional libraries - + modules - All components are defined here with a - subdirectory for each dependency - + bluefish - Bluefish dependent modules and test code + + framework - The media framework + + modules - All components are defined here + + core - Non-dependent MLT service + + dv - libdv services + ffmpeg - ffmpeg dependent modules and test code - + mainconcept - mainconcept dependent modules and test code - + SDL - SDL dependent modules and test code + + sdl - SDL dependent modules and test code + + bluefish - Bluefish dependent modules and test code (*) + + mainconcept - mainconcept dependent modules and test code (*) + + inigo - A media playing test application + valerie - Client API to access the server + miracle - The server implementation + + tests - Reserved for regression and unit tests Additional subdirectories may be nested below those shown and should be documented in their parent or here. + (*) Not posted to CVS due to licensing issues. + Configuration ------------- @@ -49,6 +52,9 @@ Configuration ./configure --disable-[mod] - do not compile specified module(s) ./configure --[other] - pass through to children + NB: This script must be run to register new services after a CVS checkout + or subsequent update. + Compilation ----------- @@ -73,9 +79,9 @@ Installation $prefix/bin/. This is linked against the framework shared object and posix libs but not against any of the modules. - The modules produce a shared object per module and a text file containing - a list of modules provided by this build. These are installed in - $prefix/share/mlt/. It is at the discretion of the module to install + The modules produce a shared object per module and update text files + containing a list of modules provided by this build. These are installed + in $prefix/share/mlt/. It is at the discretion of the module to install additional support files. To allow the development of external components, mlt-client-config and @@ -102,8 +108,8 @@ Development #include - This allows migration of source between external and internal - modules. The configuration and Makefile template requirements will require + This allows migration of source between external and internal modules. + The configuration and Makefile template requirements will require attention though. Summary diff --git a/configure b/configure index 40b31a49..4b39bfc3 100755 --- a/configure +++ b/configure @@ -40,7 +40,7 @@ done [ $help = 1 ] && show_help # Iterate through each of the components -for i in framework modules valerie miracle humperdink +for i in framework modules inigo valerie miracle humperdink do if [ -x src/$i/configure ] then diff --git a/mlt/Makefile b/mlt/Makefile index a2754671..ef218098 100644 --- a/mlt/Makefile +++ b/mlt/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = src/framework src/valerie src/modules # src/miracle src/humperdink +SUBDIRS = src/framework src/modules src/inigo src/valerie # src/miracle src/humperdink all clean dist-clean depend install: list='$(SUBDIRS)'; \ diff --git a/mlt/README b/mlt/README index 6ed3c5f6..fc7f3c56 100644 --- a/mlt/README +++ b/mlt/README @@ -14,21 +14,24 @@ Directories + docs - Location of all text and source format documentation + src - All project source is provided here - + framework - The media framework - this code is 100% posix - and as such contain no implementations - requiring additional libraries - + modules - All components are defined here with a - subdirectory for each dependency - + bluefish - Bluefish dependent modules and test code + + framework - The media framework + + modules - All components are defined here + + core - Non-dependent MLT service + + dv - libdv services + ffmpeg - ffmpeg dependent modules and test code - + mainconcept - mainconcept dependent modules and test code - + SDL - SDL dependent modules and test code + + sdl - SDL dependent modules and test code + + bluefish - Bluefish dependent modules and test code (*) + + mainconcept - mainconcept dependent modules and test code (*) + + inigo - A media playing test application + valerie - Client API to access the server + miracle - The server implementation + + tests - Reserved for regression and unit tests Additional subdirectories may be nested below those shown and should be documented in their parent or here. + (*) Not posted to CVS due to licensing issues. + Configuration ------------- @@ -49,6 +52,9 @@ Configuration ./configure --disable-[mod] - do not compile specified module(s) ./configure --[other] - pass through to children + NB: This script must be run to register new services after a CVS checkout + or subsequent update. + Compilation ----------- @@ -73,9 +79,9 @@ Installation $prefix/bin/. This is linked against the framework shared object and posix libs but not against any of the modules. - The modules produce a shared object per module and a text file containing - a list of modules provided by this build. These are installed in - $prefix/share/mlt/. It is at the discretion of the module to install + The modules produce a shared object per module and update text files + containing a list of modules provided by this build. These are installed + in $prefix/share/mlt/. It is at the discretion of the module to install additional support files. To allow the development of external components, mlt-client-config and @@ -102,8 +108,8 @@ Development #include - This allows migration of source between external and internal - modules. The configuration and Makefile template requirements will require + This allows migration of source between external and internal modules. + The configuration and Makefile template requirements will require attention though. Summary diff --git a/mlt/configure b/mlt/configure index 40b31a49..4b39bfc3 100755 --- a/mlt/configure +++ b/mlt/configure @@ -40,7 +40,7 @@ done [ $help = 1 ] && show_help # Iterate through each of the components -for i in framework modules valerie miracle humperdink +for i in framework modules inigo valerie miracle humperdink do if [ -x src/$i/configure ] then diff --git a/mlt/setenv b/mlt/setenv new file mode 100644 index 00000000..01363eb6 --- /dev/null +++ b/mlt/setenv @@ -0,0 +1,10 @@ +export MLT_REPOSITORY=`pwd`/src/modules + +export LD_LIBRARY_PATH=`pwd`/src/framework:\ +`pwd`/src/modules/bluefish:\ +`pwd`/../bluefish/lib:\ +`pwd`/../mpeg_sdk_demo/bin:\ +`pwd`/../dv_sdk + +export PATH=$PATH:`pwd`/src/inigo:`pwd`/src/miracle + diff --git a/mlt/src/framework/mlt_frame.c b/mlt/src/framework/mlt_frame.c index f0b93511..6b1558fc 100644 --- a/mlt/src/framework/mlt_frame.c +++ b/mlt/src/framework/mlt_frame.c @@ -432,6 +432,14 @@ int mlt_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float return ret; } +void *memfill( void *dst, void *src, int l, int elements ) +{ + int i = 0; + for ( i = 0; i < elements; i ++ ) + dst = memcpy( dst, src, l ) + l; + return dst; +} + void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input, int iwidth, int iheight ) { // Calculate strides @@ -439,22 +447,23 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input int ostride = owidth * 2; // Coordinates (0,0 is middle of output) - int y, x; + int y; // Calculate ranges int out_x_range = owidth / 2; int out_y_range = oheight / 2; - int in_x_range = iwidth / 2; - int in_y_range = iheight / 2; + int in_x_range = iwidth / 2 < out_x_range ? iwidth / 2 : out_x_range; + int in_y_range = iheight / 2 < out_y_range ? iheight / 2 : out_y_range; // Output pointers uint8_t *out_line = output; uint8_t *out_ptr; // Calculate a middle and possibly invalid pointer in the input - uint8_t *in_middle = input + istride * in_y_range + in_x_range * 2; - int in_line = - out_y_range * istride - out_x_range * 2; - int in_ptr; + uint8_t *in_middle = input + istride * ( iheight / 2 ) + ( iwidth / 2 ) * 2; + int in_line = - in_y_range * istride - in_x_range * 2; + + uint8_t black[ 2 ] = { 16, 128 }; // Loop for the entirety of our output height. for ( y = - out_y_range; y < out_y_range ; y ++ ) @@ -462,33 +471,29 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input // Start at the beginning of the line out_ptr = out_line; - // Point the start of the current input line (NB: can be out of range) - in_ptr = in_line; - - // Loop for the entirety of our output row. - for ( x = - out_x_range; x < out_x_range; x ++ ) - { - // Check if x and y are in the valid input range. - if ( abs( x ) < in_x_range && abs( y ) < in_y_range ) - { - // We're in the input range for this row. - *out_ptr ++ = *( in_middle + in_ptr ++ ); - *out_ptr ++ = *( in_middle + in_ptr ++ ); - } - else - { - // We're not in the input range for this row. - *out_ptr ++ = 16; - *out_ptr ++ = 128; - in_ptr += 2; - } - } + if ( abs( y ) < iheight / 2 ) + { + // Fill the outer part with black + out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range ); + + // We're in the input range for this row. + memcpy( out_ptr, in_middle + in_line, 4 * in_x_range ); + out_ptr += 4 * in_x_range; + + // Fill the outer part with black + out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range ); + + // Move to next input line + in_line += istride; + } + else + { + // Fill whole line with black + out_ptr = memfill( out_ptr, black, 2, owidth ); + } // Move to next output line out_line += ostride; - - // Move to next input line - in_line += istride; } } @@ -590,7 +595,7 @@ uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ) in_line = in_middle + dy * istride; // Loop for the entirety of our output row. - for ( x = - out_x_range; x < out_x_range; x += 2 ) + for ( x = - out_x_range; x < out_x_range; x += 1 ) { // Calculated the derived x dx = scale_width * x; @@ -599,9 +604,7 @@ uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ) if ( abs( dx ) < in_x_range && abs( dy ) < in_y_range ) { // We're in the input range for this row. - in_ptr = in_line + ( dx >> 1 ) * 4; - *out_ptr ++ = *in_ptr ++; - *out_ptr ++ = *in_ptr ++; + in_ptr = in_line + ( dx >> 1 ) * 4 - 2 * ( x & 1 ); *out_ptr ++ = *in_ptr ++; *out_ptr ++ = *in_ptr ++; } @@ -610,8 +613,6 @@ uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ) // We're not in the input range for this row. *out_ptr ++ = 16; *out_ptr ++ = 128; - *out_ptr ++ = 16; - *out_ptr ++ = 128; } } diff --git a/mlt/src/framework/mlt_playlist.c b/mlt/src/framework/mlt_playlist.c index b2f9bc86..e79e43ca 100644 --- a/mlt/src/framework/mlt_playlist.c +++ b/mlt/src/framework/mlt_playlist.c @@ -116,7 +116,7 @@ static int mlt_playlist_virtual_append( mlt_playlist this, mlt_producer producer // Inherit it from the producer fps = mlt_producer_get_fps( producer ); } - else + else if ( fps != mlt_properties_get_double( mlt_producer_properties( producer ), "fps" ) ) { // Generate a warning for now - the following attempt to fix may fail fprintf( stderr, "Warning: fps mismatch on playlist producer %d\n", this->count ); diff --git a/mlt/src/inigo/Makefile b/mlt/src/inigo/Makefile new file mode 100644 index 00000000..78e7cfa2 --- /dev/null +++ b/mlt/src/inigo/Makefile @@ -0,0 +1,28 @@ +TARGET = inigo + +OBJS = inigo.o \ + io.o + +CFLAGS = -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic + +LDFLAGS = -L ../framework -lmlt + +SRCS := $(OBJS:.o=.c) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) + +depend: $(SRCS) + $(CC) -MM $(CFLAGS) $^ 1>.depend + +dist-clean: clean + rm -f .depend + +clean: + rm -f $(OBJS) $(TARGET) + +ifneq ($(wildcard .depend),) +include .depend +endif diff --git a/mlt/src/inigo/configure b/mlt/src/inigo/configure new file mode 100755 index 00000000..e69de29b diff --git a/mlt/src/inigo/inigo.c b/mlt/src/inigo/inigo.c new file mode 100644 index 00000000..ec6000ea --- /dev/null +++ b/mlt/src/inigo/inigo.c @@ -0,0 +1,226 @@ +#include +#include +#include + +#include + +#include "io.h" + +mlt_producer create_producer( char *file ) +{ + mlt_producer result = NULL; + + // 1st Line preferences + if ( strstr( file, ".mpg" ) ) + result = mlt_factory_producer( "mcmpeg", file ); + else if ( strstr( file, ".mpeg" ) ) + result = mlt_factory_producer( "mcmpeg", file ); + else if ( strstr( file, ".dv" ) ) + result = mlt_factory_producer( "mcdv", file ); + else if ( strstr( file, ".dif" ) ) + result = mlt_factory_producer( "mcdv", file ); + else if ( strstr( file, ".jpg" ) ) + result = mlt_factory_producer( "pixbuf", file ); + else if ( strstr( file, ".JPG" ) ) + result = mlt_factory_producer( "pixbuf", file ); + else if ( strstr( file, ".jpeg" ) ) + result = mlt_factory_producer( "pixbuf", file ); + else if ( strstr( file, ".png" ) ) + result = mlt_factory_producer( "pixbuf", file ); + + // 2nd Line fallbacks + if ( result == NULL && strstr( file, ".dv" ) ) + result = mlt_factory_producer( "libdv", file ); + else if ( result == NULL && strstr( file, ".dif" ) ) + result = mlt_factory_producer( "libdv", file ); + + // 3rd line fallbacks + if ( result == NULL ) + result = mlt_factory_producer( "ppm", file ); + + return result; +} + +void transport_action( mlt_producer producer, char *value ) +{ + mlt_properties properties = mlt_producer_properties( producer ); + + switch( value[ 0 ] ) + { + case 'q': + mlt_properties_set_int( properties, "done", 1 ); + break; + case '0': + mlt_producer_set_speed( producer, 1 ); + mlt_producer_seek( producer, 0 ); + break; + case '1': + mlt_producer_set_speed( producer, -5 ); + break; + case '2': + mlt_producer_set_speed( producer, -2.5 ); + break; + case '3': + mlt_producer_set_speed( producer, -1 ); + break; + case '4': + mlt_producer_set_speed( producer, -0.5 ); + break; + case '5': + mlt_producer_set_speed( producer, 0 ); + break; + case '6': + mlt_producer_set_speed( producer, 0.5 ); + break; + case '7': + mlt_producer_set_speed( producer, 1 ); + break; + case '8': + mlt_producer_set_speed( producer, 2.5 ); + break; + case '9': + mlt_producer_set_speed( producer, 5 ); + break; + } +} + +mlt_consumer create_consumer( char *id, mlt_producer producer ) +{ + char *arg = strchr( id, ':' ); + if ( arg != NULL ) + *arg ++ = '\0'; + mlt_consumer consumer = mlt_factory_consumer( id, arg ); + if ( consumer != NULL ) + { + mlt_properties properties = mlt_consumer_properties( consumer ); + mlt_properties_set_data( properties, "transport_callback", transport_action, 0, NULL, NULL ); + mlt_properties_set_data( properties, "transport_producer", producer, 0, NULL, NULL ); + } + return consumer; +} + +void track_service( mlt_field field, void *service, mlt_destructor destructor ) +{ + mlt_properties properties = mlt_field_properties( field ); + int registered = mlt_properties_get_int( properties, "registered" ); + char *key = mlt_properties_get( properties, "registered" ); + mlt_properties_set_data( properties, key, service, 0, destructor, NULL ); + mlt_properties_set_int( properties, "registered", ++ registered ); +} + +mlt_filter create_filter( mlt_field field, char *id, int track ) +{ + char *arg = strchr( id, ':' ); + if ( arg != NULL ) + *arg ++ = '\0'; + mlt_filter filter = mlt_factory_filter( id, arg ); + if ( filter != NULL ) + { + mlt_field_plant_filter( field, filter, track ); + track_service( field, filter, ( mlt_destructor )mlt_filter_close ); + } + return filter; +} + +void set_properties( mlt_service service, char *namevalue ) +{ + mlt_properties properties = mlt_service_properties( service ); + mlt_properties_parse( properties, namevalue ); +} + +void transport( mlt_producer producer ) +{ + mlt_properties properties = mlt_producer_properties( producer ); + + term_init( ); + fprintf( stderr, "Press 'q' to continue\n" ); + while( mlt_properties_get_int( properties, "done" ) == 0 ) + { + int value = term_read( ); + if ( value != -1 ) + transport_action( producer, ( char * )&value ); + } +} + +int main( int argc, char **argv ) +{ + int i; + mlt_service service = NULL; + mlt_consumer consumer = NULL; + mlt_multitrack multitrack = NULL; + mlt_producer producer = NULL; + mlt_playlist playlist = NULL; + mlt_field field = NULL; + + // Construct the factory + mlt_factory_init( getenv( "MLT_REPOSITORY" ) ); + + // Set up containers + playlist = mlt_playlist_init( ); + + // Construct the field + field = mlt_field_init( ); + + // We need to track the number of registered filters + mlt_properties properties = mlt_field_properties( field ); + mlt_properties_set_int( properties, "registered", 0 ); + + // Get the multitrack from the field + multitrack = mlt_field_multitrack( field ); + + // Parse the arguments + for ( i = 1; i < argc; i ++ ) + { + if ( !strcmp( argv[ i ], "-consumer" ) ) + { + consumer = create_consumer( argv[ ++ i ], mlt_multitrack_producer( multitrack ) ); + if ( consumer != NULL ) + service = mlt_consumer_service( consumer ); + } + else if ( !strcmp( argv[ i ], "-filter" ) ) + { + mlt_filter filter = create_filter( field, argv[ ++ i ], 0 ); + if ( filter != NULL ) + service = mlt_filter_service( filter ); + } + else if ( !strstr( argv[ i ], "=" ) ) + { + if ( producer != NULL ) + mlt_playlist_append( playlist, producer ); + producer = create_producer( argv[ i ] ); + if ( producer != NULL ) + service = mlt_producer_service( producer ); + } + else + { + set_properties( service, argv[ i ] ); + } + } + + // If we have no consumer, default to sdl + if ( consumer == NULL ) + consumer = create_consumer( "sdl", mlt_multitrack_producer( multitrack ) ); + + // Connect producer to playlist + if ( producer != NULL ) + mlt_playlist_append( playlist, producer ); + + // Connect multitrack to producer + mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist ), 0 ); + + // Connect consumer to tractor + mlt_consumer_connect( consumer, mlt_field_service( field ) ); + + // Transport functionality + transport( mlt_multitrack_producer( multitrack ) ); + + // Close the services + mlt_consumer_close( consumer ); + mlt_field_close( field ); + mlt_producer_close( producer ); + + // Close the factory + mlt_factory_close( ); + + return 0; +} diff --git a/mlt/src/inigo/io.c b/mlt/src/inigo/io.c new file mode 100644 index 00000000..431003d3 --- /dev/null +++ b/mlt/src/inigo/io.c @@ -0,0 +1,208 @@ +/* + * io.c -- dv1394d client demo input/output + * Copyright (C) 2002-2003 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* System header files */ +#include +#include +#include +#include +#include +#include + +/* Application header files */ +#include "io.h" + +char *chomp( char *input ) +{ + if ( input != NULL ) + { + int length = strlen( input ); + if ( length && input[ length - 1 ] == '\n' ) + input[ length - 1 ] = '\0'; + if ( length > 1 && input[ length - 2 ] == '\r' ) + input[ length - 2 ] = '\0'; + } + return input; +} + +char *trim( char *input ) +{ + if ( input != NULL ) + { + int length = strlen( input ); + int first = 0; + while( first < length && isspace( input[ first ] ) ) + first ++; + memmove( input, input + first, length - first + 1 ); + length = length - first; + while ( length > 0 && isspace( input[ length - 1 ] ) ) + input[ -- length ] = '\0'; + } + return input; +} + +char *strip_quotes( char *input ) +{ + if ( input != NULL ) + { + char *ptr = strrchr( input, '\"' ); + if ( ptr != NULL ) + *ptr = '\0'; + if ( input[ 0 ] == '\"' ) + strcpy( input, input + 1 ); + } + return input; +} + +char *get_string( char *output, int maxlength, char *use ) +{ + char *value = NULL; + strcpy( output, use ); + if ( trim( chomp( fgets( output, maxlength, stdin ) ) ) != NULL ) + { + if ( !strcmp( output, "" ) ) + strcpy( output, use ); + value = output; + } + return value; +} + +int *get_int( int *output, int use ) +{ + int *value = NULL; + char temp[ 132 ]; + *output = use; + if ( trim( chomp( fgets( temp, 132, stdin ) ) ) != NULL ) + { + if ( strcmp( temp, "" ) ) + *output = atoi( temp ); + value = output; + } + return value; +} + +/** This stores the previous settings +*/ + +static struct termios oldtty; +static int mode = 0; + +/** This is called automatically on application exit to restore the + previous tty settings. +*/ + +void term_exit(void) +{ + if ( mode == 1 ) + { + tcsetattr( 0, TCSANOW, &oldtty ); + mode = 0; + } +} + +/** Init terminal so that we can grab keys without blocking. +*/ + +void term_init( ) +{ + struct termios tty; + + tcgetattr( 0, &tty ); + oldtty = tty; + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[ VMIN ] = 1; + tty.c_cc[ VTIME ] = 0; + + tcsetattr( 0, TCSANOW, &tty ); + + mode = 1; + + atexit( term_exit ); +} + +/** Check for a keypress without blocking infinitely. + Returns: ASCII value of keypress or -1 if no keypress detected. +*/ + +int term_read( ) +{ + int n = 1; + unsigned char ch; + struct timeval tv; + fd_set rfds; + + FD_ZERO( &rfds ); + FD_SET( 0, &rfds ); + tv.tv_sec = 0; + tv.tv_usec = 250; + n = select( 1, &rfds, NULL, NULL, &tv ); + if (n > 0) + { + n = read( 0, &ch, 1 ); + tcflush( 0, TCIFLUSH ); + if (n == 1) + return ch; + return n; + } + return -1; +} + +char get_keypress( ) +{ + char value = '\0'; + int pressed = 0; + + fflush( stdout ); + + term_init( ); + while ( ( pressed = term_read( ) ) == -1 ) ; + term_exit( ); + + value = (char)pressed; + + return value; +} + +void wait_for_any_key( char *message ) +{ + if ( message == NULL ) + printf( "Press any key to continue: " ); + else + printf( "%s", message ); + + get_keypress( ); + + printf( "\n\n" ); +} + +void beep( ) +{ + printf( "%c", 7 ); + fflush( stdout ); +} diff --git a/mlt/src/inigo/io.h b/mlt/src/inigo/io.h new file mode 100644 index 00000000..f97e69e4 --- /dev/null +++ b/mlt/src/inigo/io.h @@ -0,0 +1,45 @@ +/* + * io.h -- dv1394d client demo input/output + * Copyright (C) 2002-2003 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DEMO_IO_H_ +#define _DEMO_IO_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern char *chomp( char * ); +extern char *trim( char * ); +extern char *strip_quotes( char * ); +extern char *get_string( char *, int, char * ); +extern int *get_int( int *, int ); +extern void term_init( ); +extern int term_read( ); +extern void term_exit( ); +extern char get_keypress( ); +extern void wait_for_any_key( char * ); +extern void beep( ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mlt/src/modules/core/filter_resize.c b/mlt/src/modules/core/filter_resize.c index dab7fdfc..537ce505 100644 --- a/mlt/src/modules/core/filter_resize.c +++ b/mlt/src/modules/core/filter_resize.c @@ -58,13 +58,16 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) /** Constructor for the filter. */ -mlt_filter filter_resize_init( void *arg ) +mlt_filter filter_resize_init( char *arg ) { mlt_filter this = calloc( sizeof( struct mlt_filter_s ), 1 ); if ( mlt_filter_init( this, this ) == 0 ) { this->process = filter_process; - mlt_properties_set( mlt_filter_properties( this ), "scale", "off" ); + if ( arg != NULL ) + mlt_properties_set( mlt_filter_properties( this ), "scale", arg ); + else + mlt_properties_set( mlt_filter_properties( this ), "scale", "off" ); } return this; } diff --git a/mlt/src/modules/core/filter_resize.h b/mlt/src/modules/core/filter_resize.h index 0d175292..17c9c192 100644 --- a/mlt/src/modules/core/filter_resize.h +++ b/mlt/src/modules/core/filter_resize.h @@ -23,6 +23,6 @@ #include -extern mlt_filter filter_resize_init( void *arg ); +extern mlt_filter filter_resize_init( char *arg ); #endif diff --git a/mlt/src/modules/core/producer_ppm.c b/mlt/src/modules/core/producer_ppm.c index e1357c8f..ca194717 100644 --- a/mlt/src/modules/core/producer_ppm.c +++ b/mlt/src/modules/core/producer_ppm.c @@ -36,13 +36,9 @@ mlt_producer producer_ppm_init( void *command ) producer->get_frame = producer_get_frame; producer->close = producer_close; - if ( command == NULL ) - this->command = strdup( "image2raw -n -a -r 3 -ppm /usr/share/pixmaps/*.png" ); - else + if ( command != NULL ) this->command = strdup( command ); - this->pipe = popen( this->command, "r" ); - return producer; } free( this ); @@ -77,6 +73,84 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma return 0; } +static void producer_ppm_position( producer_ppm this, uint64_t requested ) +{ + if ( requested != this->expected ) + { + if ( this->video != NULL ) + pclose( this->video ); + this->video = NULL; + if ( this->audio != NULL ) + pclose( this->audio ); + this->audio = NULL; + } + + // This is the next frame we expect + this->expected = mlt_producer_frame( &this->parent ) + 1; +} + +FILE *producer_ppm_run_video( producer_ppm this ) +{ + if ( this->video == NULL ) + { + if ( this->command == NULL ) + { + this->video = popen( "image2raw -n -a -r 3 -ppm /usr/share/pixmaps/*.png", "r" ); + } + else + { + char command[ 1024 ]; + float fps = mlt_producer_get_fps( &this->parent ); + float position = mlt_producer_position( &this->parent ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -img ppm -", this->command, position, fps ); + this->video = popen( command, "r" ); + } + } + return this->video; +} + +FILE *producer_ppm_run_audio( producer_ppm this ) +{ + if ( this->audio == NULL ) + { + if ( this->command != NULL ) + { + char command[ 1024 ]; + float position = mlt_producer_position( &this->parent ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 -", this->command, position ); + this->audio = popen( command, "r" ); + } + } + return this->audio; +} + + +static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +{ + // Get the frames properties + mlt_properties properties = mlt_frame_properties( this ); + + FILE *pipe = mlt_properties_get_data( properties, "audio.pipe", NULL ); + + *frequency = 48000; + *channels = 2; + *samples = 1920; + + // Size + int size = *samples * *channels * 2; + + // Allocate an image + *buffer = malloc( size ); + + // Read it + fread( *buffer, size, 1, pipe ); + + // Pass the data on the frame properties + mlt_properties_set_data( properties, "audio", *buffer, size, free, NULL ); + + return 0; +} + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_ppm this = producer->child; @@ -86,17 +160,26 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Construct a test frame *frame = mlt_frame_init( ); - // Scan the header - if ( fscanf( this->pipe, "P6\n%d %d\n255\n", &width, &height ) == 2 ) - { - // Get the frames properties - mlt_properties properties = mlt_frame_properties( *frame ); + // Are we at the position expected? + producer_ppm_position( this, mlt_producer_frame( producer ) ); + + // Open the pipe + FILE *video = producer_ppm_run_video( this ); + + // Open the audio pipe + FILE *audio = producer_ppm_run_audio( this ); + + // Get the frames properties + mlt_properties properties = mlt_frame_properties( *frame ); + // Read the video + if ( video != NULL && fscanf( video, "P6\n%d %d\n255\n", &width, &height ) == 2 ) + { // Allocate an image uint8_t *image = malloc( width * height * 3 ); // Read it - fread( image, width * height * 3, 1, this->pipe ); + fread( image, width * height * 3, 1, video ); // Pass the data on the frame properties mlt_properties_set_data( properties, "image", image, width * height * 3, free, NULL ); @@ -107,6 +190,16 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i mlt_frame_push_get_image( *frame, producer_get_image ); } + // Read the audio + if ( audio != NULL ) + { + // Set the audio pipe + mlt_properties_set_data( properties, "audio.pipe", audio, 0, NULL, NULL ); + + // Hmm - register audio callback + ( *frame )->get_audio = producer_get_audio; + } + // Update timecode on the frame we're creating mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); @@ -119,7 +212,10 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i static void producer_close( mlt_producer parent ) { producer_ppm this = parent->child; - pclose( this->pipe ); + if ( this->video ) + pclose( this->video ); + if ( this->audio ) + pclose( this->audio ); free( this->command ); parent->close = NULL; mlt_producer_close( parent ); diff --git a/mlt/src/modules/core/producer_ppm.h b/mlt/src/modules/core/producer_ppm.h index 4787b8f6..69a253a2 100644 --- a/mlt/src/modules/core/producer_ppm.h +++ b/mlt/src/modules/core/producer_ppm.h @@ -30,7 +30,9 @@ struct producer_ppm_s { struct mlt_producer_s parent; char *command; - FILE *pipe; + FILE *video; + FILE *audio; + uint64_t expected; }; extern mlt_producer producer_ppm_init( void *command ); diff --git a/mlt/src/modules/sdl/consumer_sdl.c b/mlt/src/modules/sdl/consumer_sdl.c index a4d6b30a..cf02c737 100644 --- a/mlt/src/modules/sdl/consumer_sdl.c +++ b/mlt/src/modules/sdl/consumer_sdl.c @@ -234,7 +234,7 @@ static void *consumer_thread( void *arg ) request.freq = frequency; request.format = AUDIO_S16; request.channels = channels; - request.samples = 1024; + request.samples = 512; request.callback = sdl_fill_audio; request.userdata = (void *)this; if ( SDL_OpenAudio( &request, NULL ) < 0 ) diff --git a/mlt/src/tests/charlie.c b/mlt/src/tests/charlie.c index d6dc995c..bcd4dae6 100644 --- a/mlt/src/tests/charlie.c +++ b/mlt/src/tests/charlie.c @@ -156,6 +156,8 @@ int main( int argc, char **argv ) // Construct the field field = mlt_field_init( ); + + // We need to track the number of registered filters mlt_properties properties = mlt_field_properties( field ); mlt_properties_set_int( properties, "registered", 0 ); diff --git a/setenv b/setenv new file mode 100644 index 00000000..01363eb6 --- /dev/null +++ b/setenv @@ -0,0 +1,10 @@ +export MLT_REPOSITORY=`pwd`/src/modules + +export LD_LIBRARY_PATH=`pwd`/src/framework:\ +`pwd`/src/modules/bluefish:\ +`pwd`/../bluefish/lib:\ +`pwd`/../mpeg_sdk_demo/bin:\ +`pwd`/../dv_sdk + +export PATH=$PATH:`pwd`/src/inigo:`pwd`/src/miracle + diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c index f0b93511..6b1558fc 100644 --- a/src/framework/mlt_frame.c +++ b/src/framework/mlt_frame.c @@ -432,6 +432,14 @@ int mlt_frame_composite_yuv( mlt_frame this, mlt_frame that, int x, int y, float return ret; } +void *memfill( void *dst, void *src, int l, int elements ) +{ + int i = 0; + for ( i = 0; i < elements; i ++ ) + dst = memcpy( dst, src, l ) + l; + return dst; +} + void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input, int iwidth, int iheight ) { // Calculate strides @@ -439,22 +447,23 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input int ostride = owidth * 2; // Coordinates (0,0 is middle of output) - int y, x; + int y; // Calculate ranges int out_x_range = owidth / 2; int out_y_range = oheight / 2; - int in_x_range = iwidth / 2; - int in_y_range = iheight / 2; + int in_x_range = iwidth / 2 < out_x_range ? iwidth / 2 : out_x_range; + int in_y_range = iheight / 2 < out_y_range ? iheight / 2 : out_y_range; // Output pointers uint8_t *out_line = output; uint8_t *out_ptr; // Calculate a middle and possibly invalid pointer in the input - uint8_t *in_middle = input + istride * in_y_range + in_x_range * 2; - int in_line = - out_y_range * istride - out_x_range * 2; - int in_ptr; + uint8_t *in_middle = input + istride * ( iheight / 2 ) + ( iwidth / 2 ) * 2; + int in_line = - in_y_range * istride - in_x_range * 2; + + uint8_t black[ 2 ] = { 16, 128 }; // Loop for the entirety of our output height. for ( y = - out_y_range; y < out_y_range ; y ++ ) @@ -462,33 +471,29 @@ void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input // Start at the beginning of the line out_ptr = out_line; - // Point the start of the current input line (NB: can be out of range) - in_ptr = in_line; - - // Loop for the entirety of our output row. - for ( x = - out_x_range; x < out_x_range; x ++ ) - { - // Check if x and y are in the valid input range. - if ( abs( x ) < in_x_range && abs( y ) < in_y_range ) - { - // We're in the input range for this row. - *out_ptr ++ = *( in_middle + in_ptr ++ ); - *out_ptr ++ = *( in_middle + in_ptr ++ ); - } - else - { - // We're not in the input range for this row. - *out_ptr ++ = 16; - *out_ptr ++ = 128; - in_ptr += 2; - } - } + if ( abs( y ) < iheight / 2 ) + { + // Fill the outer part with black + out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range ); + + // We're in the input range for this row. + memcpy( out_ptr, in_middle + in_line, 4 * in_x_range ); + out_ptr += 4 * in_x_range; + + // Fill the outer part with black + out_ptr = memfill( out_ptr, black, 2, out_x_range - in_x_range ); + + // Move to next input line + in_line += istride; + } + else + { + // Fill whole line with black + out_ptr = memfill( out_ptr, black, 2, owidth ); + } // Move to next output line out_line += ostride; - - // Move to next input line - in_line += istride; } } @@ -590,7 +595,7 @@ uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ) in_line = in_middle + dy * istride; // Loop for the entirety of our output row. - for ( x = - out_x_range; x < out_x_range; x += 2 ) + for ( x = - out_x_range; x < out_x_range; x += 1 ) { // Calculated the derived x dx = scale_width * x; @@ -599,9 +604,7 @@ uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ) if ( abs( dx ) < in_x_range && abs( dy ) < in_y_range ) { // We're in the input range for this row. - in_ptr = in_line + ( dx >> 1 ) * 4; - *out_ptr ++ = *in_ptr ++; - *out_ptr ++ = *in_ptr ++; + in_ptr = in_line + ( dx >> 1 ) * 4 - 2 * ( x & 1 ); *out_ptr ++ = *in_ptr ++; *out_ptr ++ = *in_ptr ++; } @@ -610,8 +613,6 @@ uint8_t *mlt_frame_rescale_yuv422( mlt_frame this, int owidth, int oheight ) // We're not in the input range for this row. *out_ptr ++ = 16; *out_ptr ++ = 128; - *out_ptr ++ = 16; - *out_ptr ++ = 128; } } diff --git a/src/framework/mlt_playlist.c b/src/framework/mlt_playlist.c index b2f9bc86..e79e43ca 100644 --- a/src/framework/mlt_playlist.c +++ b/src/framework/mlt_playlist.c @@ -116,7 +116,7 @@ static int mlt_playlist_virtual_append( mlt_playlist this, mlt_producer producer // Inherit it from the producer fps = mlt_producer_get_fps( producer ); } - else + else if ( fps != mlt_properties_get_double( mlt_producer_properties( producer ), "fps" ) ) { // Generate a warning for now - the following attempt to fix may fail fprintf( stderr, "Warning: fps mismatch on playlist producer %d\n", this->count ); diff --git a/src/inigo/Makefile b/src/inigo/Makefile new file mode 100644 index 00000000..78e7cfa2 --- /dev/null +++ b/src/inigo/Makefile @@ -0,0 +1,28 @@ +TARGET = inigo + +OBJS = inigo.o \ + io.o + +CFLAGS = -I .. -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -rdynamic + +LDFLAGS = -L ../framework -lmlt + +SRCS := $(OBJS:.o=.c) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) + +depend: $(SRCS) + $(CC) -MM $(CFLAGS) $^ 1>.depend + +dist-clean: clean + rm -f .depend + +clean: + rm -f $(OBJS) $(TARGET) + +ifneq ($(wildcard .depend),) +include .depend +endif diff --git a/src/inigo/configure b/src/inigo/configure new file mode 100755 index 00000000..e69de29b diff --git a/src/inigo/inigo.c b/src/inigo/inigo.c new file mode 100644 index 00000000..ec6000ea --- /dev/null +++ b/src/inigo/inigo.c @@ -0,0 +1,226 @@ +#include +#include +#include + +#include + +#include "io.h" + +mlt_producer create_producer( char *file ) +{ + mlt_producer result = NULL; + + // 1st Line preferences + if ( strstr( file, ".mpg" ) ) + result = mlt_factory_producer( "mcmpeg", file ); + else if ( strstr( file, ".mpeg" ) ) + result = mlt_factory_producer( "mcmpeg", file ); + else if ( strstr( file, ".dv" ) ) + result = mlt_factory_producer( "mcdv", file ); + else if ( strstr( file, ".dif" ) ) + result = mlt_factory_producer( "mcdv", file ); + else if ( strstr( file, ".jpg" ) ) + result = mlt_factory_producer( "pixbuf", file ); + else if ( strstr( file, ".JPG" ) ) + result = mlt_factory_producer( "pixbuf", file ); + else if ( strstr( file, ".jpeg" ) ) + result = mlt_factory_producer( "pixbuf", file ); + else if ( strstr( file, ".png" ) ) + result = mlt_factory_producer( "pixbuf", file ); + + // 2nd Line fallbacks + if ( result == NULL && strstr( file, ".dv" ) ) + result = mlt_factory_producer( "libdv", file ); + else if ( result == NULL && strstr( file, ".dif" ) ) + result = mlt_factory_producer( "libdv", file ); + + // 3rd line fallbacks + if ( result == NULL ) + result = mlt_factory_producer( "ppm", file ); + + return result; +} + +void transport_action( mlt_producer producer, char *value ) +{ + mlt_properties properties = mlt_producer_properties( producer ); + + switch( value[ 0 ] ) + { + case 'q': + mlt_properties_set_int( properties, "done", 1 ); + break; + case '0': + mlt_producer_set_speed( producer, 1 ); + mlt_producer_seek( producer, 0 ); + break; + case '1': + mlt_producer_set_speed( producer, -5 ); + break; + case '2': + mlt_producer_set_speed( producer, -2.5 ); + break; + case '3': + mlt_producer_set_speed( producer, -1 ); + break; + case '4': + mlt_producer_set_speed( producer, -0.5 ); + break; + case '5': + mlt_producer_set_speed( producer, 0 ); + break; + case '6': + mlt_producer_set_speed( producer, 0.5 ); + break; + case '7': + mlt_producer_set_speed( producer, 1 ); + break; + case '8': + mlt_producer_set_speed( producer, 2.5 ); + break; + case '9': + mlt_producer_set_speed( producer, 5 ); + break; + } +} + +mlt_consumer create_consumer( char *id, mlt_producer producer ) +{ + char *arg = strchr( id, ':' ); + if ( arg != NULL ) + *arg ++ = '\0'; + mlt_consumer consumer = mlt_factory_consumer( id, arg ); + if ( consumer != NULL ) + { + mlt_properties properties = mlt_consumer_properties( consumer ); + mlt_properties_set_data( properties, "transport_callback", transport_action, 0, NULL, NULL ); + mlt_properties_set_data( properties, "transport_producer", producer, 0, NULL, NULL ); + } + return consumer; +} + +void track_service( mlt_field field, void *service, mlt_destructor destructor ) +{ + mlt_properties properties = mlt_field_properties( field ); + int registered = mlt_properties_get_int( properties, "registered" ); + char *key = mlt_properties_get( properties, "registered" ); + mlt_properties_set_data( properties, key, service, 0, destructor, NULL ); + mlt_properties_set_int( properties, "registered", ++ registered ); +} + +mlt_filter create_filter( mlt_field field, char *id, int track ) +{ + char *arg = strchr( id, ':' ); + if ( arg != NULL ) + *arg ++ = '\0'; + mlt_filter filter = mlt_factory_filter( id, arg ); + if ( filter != NULL ) + { + mlt_field_plant_filter( field, filter, track ); + track_service( field, filter, ( mlt_destructor )mlt_filter_close ); + } + return filter; +} + +void set_properties( mlt_service service, char *namevalue ) +{ + mlt_properties properties = mlt_service_properties( service ); + mlt_properties_parse( properties, namevalue ); +} + +void transport( mlt_producer producer ) +{ + mlt_properties properties = mlt_producer_properties( producer ); + + term_init( ); + fprintf( stderr, "Press 'q' to continue\n" ); + while( mlt_properties_get_int( properties, "done" ) == 0 ) + { + int value = term_read( ); + if ( value != -1 ) + transport_action( producer, ( char * )&value ); + } +} + +int main( int argc, char **argv ) +{ + int i; + mlt_service service = NULL; + mlt_consumer consumer = NULL; + mlt_multitrack multitrack = NULL; + mlt_producer producer = NULL; + mlt_playlist playlist = NULL; + mlt_field field = NULL; + + // Construct the factory + mlt_factory_init( getenv( "MLT_REPOSITORY" ) ); + + // Set up containers + playlist = mlt_playlist_init( ); + + // Construct the field + field = mlt_field_init( ); + + // We need to track the number of registered filters + mlt_properties properties = mlt_field_properties( field ); + mlt_properties_set_int( properties, "registered", 0 ); + + // Get the multitrack from the field + multitrack = mlt_field_multitrack( field ); + + // Parse the arguments + for ( i = 1; i < argc; i ++ ) + { + if ( !strcmp( argv[ i ], "-consumer" ) ) + { + consumer = create_consumer( argv[ ++ i ], mlt_multitrack_producer( multitrack ) ); + if ( consumer != NULL ) + service = mlt_consumer_service( consumer ); + } + else if ( !strcmp( argv[ i ], "-filter" ) ) + { + mlt_filter filter = create_filter( field, argv[ ++ i ], 0 ); + if ( filter != NULL ) + service = mlt_filter_service( filter ); + } + else if ( !strstr( argv[ i ], "=" ) ) + { + if ( producer != NULL ) + mlt_playlist_append( playlist, producer ); + producer = create_producer( argv[ i ] ); + if ( producer != NULL ) + service = mlt_producer_service( producer ); + } + else + { + set_properties( service, argv[ i ] ); + } + } + + // If we have no consumer, default to sdl + if ( consumer == NULL ) + consumer = create_consumer( "sdl", mlt_multitrack_producer( multitrack ) ); + + // Connect producer to playlist + if ( producer != NULL ) + mlt_playlist_append( playlist, producer ); + + // Connect multitrack to producer + mlt_multitrack_connect( multitrack, mlt_playlist_producer( playlist ), 0 ); + + // Connect consumer to tractor + mlt_consumer_connect( consumer, mlt_field_service( field ) ); + + // Transport functionality + transport( mlt_multitrack_producer( multitrack ) ); + + // Close the services + mlt_consumer_close( consumer ); + mlt_field_close( field ); + mlt_producer_close( producer ); + + // Close the factory + mlt_factory_close( ); + + return 0; +} diff --git a/src/inigo/io.c b/src/inigo/io.c new file mode 100644 index 00000000..431003d3 --- /dev/null +++ b/src/inigo/io.c @@ -0,0 +1,208 @@ +/* + * io.c -- dv1394d client demo input/output + * Copyright (C) 2002-2003 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* System header files */ +#include +#include +#include +#include +#include +#include + +/* Application header files */ +#include "io.h" + +char *chomp( char *input ) +{ + if ( input != NULL ) + { + int length = strlen( input ); + if ( length && input[ length - 1 ] == '\n' ) + input[ length - 1 ] = '\0'; + if ( length > 1 && input[ length - 2 ] == '\r' ) + input[ length - 2 ] = '\0'; + } + return input; +} + +char *trim( char *input ) +{ + if ( input != NULL ) + { + int length = strlen( input ); + int first = 0; + while( first < length && isspace( input[ first ] ) ) + first ++; + memmove( input, input + first, length - first + 1 ); + length = length - first; + while ( length > 0 && isspace( input[ length - 1 ] ) ) + input[ -- length ] = '\0'; + } + return input; +} + +char *strip_quotes( char *input ) +{ + if ( input != NULL ) + { + char *ptr = strrchr( input, '\"' ); + if ( ptr != NULL ) + *ptr = '\0'; + if ( input[ 0 ] == '\"' ) + strcpy( input, input + 1 ); + } + return input; +} + +char *get_string( char *output, int maxlength, char *use ) +{ + char *value = NULL; + strcpy( output, use ); + if ( trim( chomp( fgets( output, maxlength, stdin ) ) ) != NULL ) + { + if ( !strcmp( output, "" ) ) + strcpy( output, use ); + value = output; + } + return value; +} + +int *get_int( int *output, int use ) +{ + int *value = NULL; + char temp[ 132 ]; + *output = use; + if ( trim( chomp( fgets( temp, 132, stdin ) ) ) != NULL ) + { + if ( strcmp( temp, "" ) ) + *output = atoi( temp ); + value = output; + } + return value; +} + +/** This stores the previous settings +*/ + +static struct termios oldtty; +static int mode = 0; + +/** This is called automatically on application exit to restore the + previous tty settings. +*/ + +void term_exit(void) +{ + if ( mode == 1 ) + { + tcsetattr( 0, TCSANOW, &oldtty ); + mode = 0; + } +} + +/** Init terminal so that we can grab keys without blocking. +*/ + +void term_init( ) +{ + struct termios tty; + + tcgetattr( 0, &tty ); + oldtty = tty; + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[ VMIN ] = 1; + tty.c_cc[ VTIME ] = 0; + + tcsetattr( 0, TCSANOW, &tty ); + + mode = 1; + + atexit( term_exit ); +} + +/** Check for a keypress without blocking infinitely. + Returns: ASCII value of keypress or -1 if no keypress detected. +*/ + +int term_read( ) +{ + int n = 1; + unsigned char ch; + struct timeval tv; + fd_set rfds; + + FD_ZERO( &rfds ); + FD_SET( 0, &rfds ); + tv.tv_sec = 0; + tv.tv_usec = 250; + n = select( 1, &rfds, NULL, NULL, &tv ); + if (n > 0) + { + n = read( 0, &ch, 1 ); + tcflush( 0, TCIFLUSH ); + if (n == 1) + return ch; + return n; + } + return -1; +} + +char get_keypress( ) +{ + char value = '\0'; + int pressed = 0; + + fflush( stdout ); + + term_init( ); + while ( ( pressed = term_read( ) ) == -1 ) ; + term_exit( ); + + value = (char)pressed; + + return value; +} + +void wait_for_any_key( char *message ) +{ + if ( message == NULL ) + printf( "Press any key to continue: " ); + else + printf( "%s", message ); + + get_keypress( ); + + printf( "\n\n" ); +} + +void beep( ) +{ + printf( "%c", 7 ); + fflush( stdout ); +} diff --git a/src/inigo/io.h b/src/inigo/io.h new file mode 100644 index 00000000..f97e69e4 --- /dev/null +++ b/src/inigo/io.h @@ -0,0 +1,45 @@ +/* + * io.h -- dv1394d client demo input/output + * Copyright (C) 2002-2003 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DEMO_IO_H_ +#define _DEMO_IO_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern char *chomp( char * ); +extern char *trim( char * ); +extern char *strip_quotes( char * ); +extern char *get_string( char *, int, char * ); +extern int *get_int( int *, int ); +extern void term_init( ); +extern int term_read( ); +extern void term_exit( ); +extern char get_keypress( ); +extern void wait_for_any_key( char * ); +extern void beep( ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/modules/core/filter_resize.c b/src/modules/core/filter_resize.c index dab7fdfc..537ce505 100644 --- a/src/modules/core/filter_resize.c +++ b/src/modules/core/filter_resize.c @@ -58,13 +58,16 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) /** Constructor for the filter. */ -mlt_filter filter_resize_init( void *arg ) +mlt_filter filter_resize_init( char *arg ) { mlt_filter this = calloc( sizeof( struct mlt_filter_s ), 1 ); if ( mlt_filter_init( this, this ) == 0 ) { this->process = filter_process; - mlt_properties_set( mlt_filter_properties( this ), "scale", "off" ); + if ( arg != NULL ) + mlt_properties_set( mlt_filter_properties( this ), "scale", arg ); + else + mlt_properties_set( mlt_filter_properties( this ), "scale", "off" ); } return this; } diff --git a/src/modules/core/filter_resize.h b/src/modules/core/filter_resize.h index 0d175292..17c9c192 100644 --- a/src/modules/core/filter_resize.h +++ b/src/modules/core/filter_resize.h @@ -23,6 +23,6 @@ #include -extern mlt_filter filter_resize_init( void *arg ); +extern mlt_filter filter_resize_init( char *arg ); #endif diff --git a/src/modules/core/producer_ppm.c b/src/modules/core/producer_ppm.c index e1357c8f..ca194717 100644 --- a/src/modules/core/producer_ppm.c +++ b/src/modules/core/producer_ppm.c @@ -36,13 +36,9 @@ mlt_producer producer_ppm_init( void *command ) producer->get_frame = producer_get_frame; producer->close = producer_close; - if ( command == NULL ) - this->command = strdup( "image2raw -n -a -r 3 -ppm /usr/share/pixmaps/*.png" ); - else + if ( command != NULL ) this->command = strdup( command ); - this->pipe = popen( this->command, "r" ); - return producer; } free( this ); @@ -77,6 +73,84 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma return 0; } +static void producer_ppm_position( producer_ppm this, uint64_t requested ) +{ + if ( requested != this->expected ) + { + if ( this->video != NULL ) + pclose( this->video ); + this->video = NULL; + if ( this->audio != NULL ) + pclose( this->audio ); + this->audio = NULL; + } + + // This is the next frame we expect + this->expected = mlt_producer_frame( &this->parent ) + 1; +} + +FILE *producer_ppm_run_video( producer_ppm this ) +{ + if ( this->video == NULL ) + { + if ( this->command == NULL ) + { + this->video = popen( "image2raw -n -a -r 3 -ppm /usr/share/pixmaps/*.png", "r" ); + } + else + { + char command[ 1024 ]; + float fps = mlt_producer_get_fps( &this->parent ); + float position = mlt_producer_position( &this->parent ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -img ppm -", this->command, position, fps ); + this->video = popen( command, "r" ); + } + } + return this->video; +} + +FILE *producer_ppm_run_audio( producer_ppm this ) +{ + if ( this->audio == NULL ) + { + if ( this->command != NULL ) + { + char command[ 1024 ]; + float position = mlt_producer_position( &this->parent ); + sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 -", this->command, position ); + this->audio = popen( command, "r" ); + } + } + return this->audio; +} + + +static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +{ + // Get the frames properties + mlt_properties properties = mlt_frame_properties( this ); + + FILE *pipe = mlt_properties_get_data( properties, "audio.pipe", NULL ); + + *frequency = 48000; + *channels = 2; + *samples = 1920; + + // Size + int size = *samples * *channels * 2; + + // Allocate an image + *buffer = malloc( size ); + + // Read it + fread( *buffer, size, 1, pipe ); + + // Pass the data on the frame properties + mlt_properties_set_data( properties, "audio", *buffer, size, free, NULL ); + + return 0; +} + static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) { producer_ppm this = producer->child; @@ -86,17 +160,26 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Construct a test frame *frame = mlt_frame_init( ); - // Scan the header - if ( fscanf( this->pipe, "P6\n%d %d\n255\n", &width, &height ) == 2 ) - { - // Get the frames properties - mlt_properties properties = mlt_frame_properties( *frame ); + // Are we at the position expected? + producer_ppm_position( this, mlt_producer_frame( producer ) ); + + // Open the pipe + FILE *video = producer_ppm_run_video( this ); + + // Open the audio pipe + FILE *audio = producer_ppm_run_audio( this ); + + // Get the frames properties + mlt_properties properties = mlt_frame_properties( *frame ); + // Read the video + if ( video != NULL && fscanf( video, "P6\n%d %d\n255\n", &width, &height ) == 2 ) + { // Allocate an image uint8_t *image = malloc( width * height * 3 ); // Read it - fread( image, width * height * 3, 1, this->pipe ); + fread( image, width * height * 3, 1, video ); // Pass the data on the frame properties mlt_properties_set_data( properties, "image", image, width * height * 3, free, NULL ); @@ -107,6 +190,16 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i mlt_frame_push_get_image( *frame, producer_get_image ); } + // Read the audio + if ( audio != NULL ) + { + // Set the audio pipe + mlt_properties_set_data( properties, "audio.pipe", audio, 0, NULL, NULL ); + + // Hmm - register audio callback + ( *frame )->get_audio = producer_get_audio; + } + // Update timecode on the frame we're creating mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); @@ -119,7 +212,10 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i static void producer_close( mlt_producer parent ) { producer_ppm this = parent->child; - pclose( this->pipe ); + if ( this->video ) + pclose( this->video ); + if ( this->audio ) + pclose( this->audio ); free( this->command ); parent->close = NULL; mlt_producer_close( parent ); diff --git a/src/modules/core/producer_ppm.h b/src/modules/core/producer_ppm.h index 4787b8f6..69a253a2 100644 --- a/src/modules/core/producer_ppm.h +++ b/src/modules/core/producer_ppm.h @@ -30,7 +30,9 @@ struct producer_ppm_s { struct mlt_producer_s parent; char *command; - FILE *pipe; + FILE *video; + FILE *audio; + uint64_t expected; }; extern mlt_producer producer_ppm_init( void *command ); diff --git a/src/modules/sdl/consumer_sdl.c b/src/modules/sdl/consumer_sdl.c index a4d6b30a..cf02c737 100644 --- a/src/modules/sdl/consumer_sdl.c +++ b/src/modules/sdl/consumer_sdl.c @@ -234,7 +234,7 @@ static void *consumer_thread( void *arg ) request.freq = frequency; request.format = AUDIO_S16; request.channels = channels; - request.samples = 1024; + request.samples = 512; request.callback = sdl_fill_audio; request.userdata = (void *)this; if ( SDL_OpenAudio( &request, NULL ) < 0 ) diff --git a/src/tests/charlie.c b/src/tests/charlie.c index d6dc995c..bcd4dae6 100644 --- a/src/tests/charlie.c +++ b/src/tests/charlie.c @@ -156,6 +156,8 @@ int main( int argc, char **argv ) // Construct the field field = mlt_field_init( ); + + // We need to track the number of registered filters mlt_properties properties = mlt_field_properties( field ); mlt_properties_set_int( properties, "registered", 0 ); -- 2.39.2