From 0cf7dff156fe3c541eb5d668e317cc73b008c7b0 Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Thu, 1 Jan 2004 15:37:05 +0000 Subject: [PATCH] ntsc fixes and service doco for discussion git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@33 d19143bc-622f-0410-bfdd-b5b2a6649095 --- docs/services.txt | 99 +++++++++++++++++ mlt/docs/services.txt | 99 +++++++++++++++++ mlt/src/framework/mlt_factory.c | 14 +++ mlt/src/framework/mlt_factory.h | 1 + mlt/src/framework/mlt_multitrack.c | 1 + mlt/src/framework/mlt_producer.c | 4 + mlt/src/modules/ffmpeg/audio.sh | 14 +++ mlt/src/modules/ffmpeg/filter_ffmpeg_dub.c | 27 ++++-- mlt/src/modules/ffmpeg/producer_ffmpeg.c | 158 +++++++++++++++++++++------- mlt/src/modules/ffmpeg/producer_ffmpeg.h | 5 +- mlt/src/modules/ffmpeg/video.sh | 14 +++ src/framework/mlt_factory.c | 14 +++ src/framework/mlt_factory.h | 1 + src/framework/mlt_multitrack.c | 1 + src/framework/mlt_producer.c | 4 + src/modules/ffmpeg/audio.sh | 14 +++ src/modules/ffmpeg/filter_ffmpeg_dub.c | 27 ++++-- src/modules/ffmpeg/producer_ffmpeg.c | 158 +++++++++++++++++++++------- src/modules/ffmpeg/producer_ffmpeg.h | 5 +- src/modules/ffmpeg/video.sh | 14 +++ 20 files changed, 576 insertions(+), 98 deletions(-) create mode 100644 docs/services.txt create mode 100644 mlt/docs/services.txt create mode 100755 mlt/src/modules/ffmpeg/audio.sh create mode 100755 mlt/src/modules/ffmpeg/video.sh create mode 100755 src/modules/ffmpeg/audio.sh create mode 100755 src/modules/ffmpeg/video.sh diff --git a/docs/services.txt b/docs/services.txt new file mode 100644 index 0000000..3588610 --- /dev/null +++ b/docs/services.txt @@ -0,0 +1,99 @@ +Producers +--------- + + ffmpeg + + Description: + + Test case pipe based producer for video and audio. + + Constructor argument: + + 'file' - produce a/v from file + v4l - produce a/v from video4linux and dsp device + + Initialisation Properties + + string video_type - "file" or "v4l" + string video_file - file or v4l device + string video_size - WxH of video to produce (default: "") + int video_loop - loop video until audio exhausted (default: 0) + string audio_type - "file" or "dsp" + string audio_file - file or dsp device + int audio_rate - audio frequency (default: 48000) + int audio_channels - audio channels (default: 2) + int audio_track - audio track to use (default: 0) + int audio_loop - loop audio until video exhausted (default: 0) + timecode in - in point + timecode out - out point + double fps - output frames per second (default: 25) + + Read Only Properties + + end_of_clip - holds 1 when input is exhausted + + Dependencies + + ffmpeg executable. + + Known Bugs + + in/out point setting is broken. + + Implementation does not allow fast random access. + + libdv + + Description: + + libdv based decoder for video and audio. + + Constructor argument: + + 'file' - produce a/v from file + + Initialisation Properties + + string file - file location + timecode in - in point + timecode out - out point + + Read Only Properties + + double fps - output frames per second + + Dependencies + + libdv. + + Known Bugs + + 'file' is not populated on properties? + + mcdv + mcmpeg + pango + pixbuf + ppm + + +Filters +------- + + deinterlace + ffmpeg_dub + gamma + greyscale + resize + +Transitions +----------- + + composite + +Consumers +--------- + + bluefish + sdl + diff --git a/mlt/docs/services.txt b/mlt/docs/services.txt new file mode 100644 index 0000000..3588610 --- /dev/null +++ b/mlt/docs/services.txt @@ -0,0 +1,99 @@ +Producers +--------- + + ffmpeg + + Description: + + Test case pipe based producer for video and audio. + + Constructor argument: + + 'file' - produce a/v from file + v4l - produce a/v from video4linux and dsp device + + Initialisation Properties + + string video_type - "file" or "v4l" + string video_file - file or v4l device + string video_size - WxH of video to produce (default: "") + int video_loop - loop video until audio exhausted (default: 0) + string audio_type - "file" or "dsp" + string audio_file - file or dsp device + int audio_rate - audio frequency (default: 48000) + int audio_channels - audio channels (default: 2) + int audio_track - audio track to use (default: 0) + int audio_loop - loop audio until video exhausted (default: 0) + timecode in - in point + timecode out - out point + double fps - output frames per second (default: 25) + + Read Only Properties + + end_of_clip - holds 1 when input is exhausted + + Dependencies + + ffmpeg executable. + + Known Bugs + + in/out point setting is broken. + + Implementation does not allow fast random access. + + libdv + + Description: + + libdv based decoder for video and audio. + + Constructor argument: + + 'file' - produce a/v from file + + Initialisation Properties + + string file - file location + timecode in - in point + timecode out - out point + + Read Only Properties + + double fps - output frames per second + + Dependencies + + libdv. + + Known Bugs + + 'file' is not populated on properties? + + mcdv + mcmpeg + pango + pixbuf + ppm + + +Filters +------- + + deinterlace + ffmpeg_dub + gamma + greyscale + resize + +Transitions +----------- + + composite + +Consumers +--------- + + bluefish + sdl + diff --git a/mlt/src/framework/mlt_factory.c b/mlt/src/framework/mlt_factory.c index 5d7187b..9795770 100644 --- a/mlt/src/framework/mlt_factory.c +++ b/mlt/src/framework/mlt_factory.c @@ -24,10 +24,12 @@ #include "mlt_properties.h" #include +#include /** Singleton repositories */ +static char *mlt_prefix = NULL; static mlt_properties object_list = NULL; static mlt_repository producers = NULL; static mlt_repository filters = NULL; @@ -43,6 +45,9 @@ int mlt_factory_init( char *prefix ) if ( prefix == NULL ) prefix = PREFIX_DATA; + // Store the prefix for later retrieval + mlt_prefix = strdup( prefix ); + // Create the object list. object_list = calloc( sizeof( struct mlt_properties_s ), 1 ); mlt_properties_init( object_list, NULL ); @@ -56,6 +61,14 @@ int mlt_factory_init( char *prefix ) return 0; } +/** Fetch the prefix used in this instance. +*/ + +const char *mlt_factory_prefix( ) +{ + return mlt_prefix; +} + /** Fetch a producer from the repository. */ @@ -98,6 +111,7 @@ void mlt_factory_close( ) mlt_repository_close( transitions ); mlt_repository_close( consumers ); mlt_properties_close( object_list ); + free( mlt_prefix ); free( object_list ); } diff --git a/mlt/src/framework/mlt_factory.h b/mlt/src/framework/mlt_factory.h index c9e7766..d0b9160 100644 --- a/mlt/src/framework/mlt_factory.h +++ b/mlt/src/framework/mlt_factory.h @@ -24,6 +24,7 @@ #include "mlt_types.h" extern int mlt_factory_init( char *prefix ); +extern const char *mlt_factory_prefix( ); extern mlt_producer mlt_factory_producer( char *name, void *input ); extern mlt_filter mlt_factory_filter( char *name, void *input ); extern mlt_transition mlt_factory_transition( char *name, void *input ); diff --git a/mlt/src/framework/mlt_multitrack.c b/mlt/src/framework/mlt_multitrack.c index 2e44f5b..96169b0 100644 --- a/mlt/src/framework/mlt_multitrack.c +++ b/mlt/src/framework/mlt_multitrack.c @@ -141,6 +141,7 @@ void mlt_multitrack_refresh( mlt_multitrack this ) mlt_properties_set_timecode( properties, "length", length ); mlt_properties_set_timecode( properties, "out", length ); mlt_properties_set_timecode( properties, "playtime", length - mlt_properties_get_timecode( properties, "in" ) ); + mlt_properties_set_double( properties, "fps", fps ); } /** Connect a producer to a given track. diff --git a/mlt/src/framework/mlt_producer.c b/mlt/src/framework/mlt_producer.c index 7dc6c6e..991c698 100644 --- a/mlt/src/framework/mlt_producer.c +++ b/mlt/src/framework/mlt_producer.c @@ -279,6 +279,10 @@ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int ind mlt_producer_prepare_next( this ); } + // Copy the fps of the producer onto the frame + mlt_properties properties = mlt_frame_properties( *frame ); + mlt_properties_set_double( properties, "fps", mlt_producer_get_fps( this ) ); + return 0; } diff --git a/mlt/src/modules/ffmpeg/audio.sh b/mlt/src/modules/ffmpeg/audio.sh new file mode 100755 index 0000000..3c7475a --- /dev/null +++ b/mlt/src/modules/ffmpeg/audio.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +audio_type="$1" +audio_file="$2" +audio_position=$3 +audio_frequency=$4 +audio_channels=$5 +audio_track=$5 + +if [ "$audio_type" == "dsp" ] +then ffmpeg -ad "$audio_file" -f s16le -ar $audio_frequency -ac $audio_channels - +else ffmpeg -i "$audio_file" -ss $audio_position -f s16le -ar $audio_frequency -ac $audio_channels - +fi + diff --git a/mlt/src/modules/ffmpeg/filter_ffmpeg_dub.c b/mlt/src/modules/ffmpeg/filter_ffmpeg_dub.c index 3ba9932..652354b 100644 --- a/mlt/src/modules/ffmpeg/filter_ffmpeg_dub.c +++ b/mlt/src/modules/ffmpeg/filter_ffmpeg_dub.c @@ -38,10 +38,10 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format mlt_properties producer_properties = mlt_producer_properties( producer ); // Get the original get_audio - int ( *get_audio )( mlt_frame, int16_t **, mlt_audio_format *, int *, int *, int * ) = mlt_properties_get_data( frame_properties, "get_audio", NULL ); + frame->get_audio = mlt_properties_get_data( frame_properties, "get_audio", NULL ); // Call the original get_audio - get_audio( frame, buffer, format, frequency, channels, samples ); + mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Now if our producer is still producing, override the audio if ( !mlt_properties_get_int( producer_properties, "end_of_clip" ) ) @@ -52,6 +52,9 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format // We need a frame from the producer mlt_frame producer_frame; + // Set the FPS + mlt_properties_set_double( producer_properties, "fps", mlt_properties_get_double( frame_properties, "fps" ) ); + // Seek to the position mlt_producer_seek_frame( producer, ( int64_t )position ); @@ -88,14 +91,22 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) // Obtain the frame properties mlt_properties frame_properties = mlt_frame_properties( frame ); - // Backup the original get_audio (it's still needed) - mlt_properties_set_data( frame_properties, "get_audio", frame->get_audio, 0, NULL, NULL ); + // Get the producer properties + mlt_properties producer_properties = mlt_producer_properties( producer ); - // Pass the producer on the frame - mlt_properties_set_data( frame_properties, "producer", producer, 0, NULL, NULL ); + // Only do this if we have not reached end of clip and ffmpeg_dub has not already been done + if ( !mlt_properties_get_int( producer_properties, "end_of_clip" ) && + mlt_properties_get_data( frame_properties, "get_audio", NULL ) == NULL ) + { + // Backup the original get_audio (it's still needed) + mlt_properties_set_data( frame_properties, "get_audio", frame->get_audio, 0, NULL, NULL ); + + // Pass the producer on the frame + mlt_properties_set_data( frame_properties, "producer", producer, 0, NULL, NULL ); - // Override the get_audio method - frame->get_audio = filter_get_audio; + // Override the get_audio method + frame->get_audio = filter_get_audio; + } return frame; } diff --git a/mlt/src/modules/ffmpeg/producer_ffmpeg.c b/mlt/src/modules/ffmpeg/producer_ffmpeg.c index 45c702b..95763df 100644 --- a/mlt/src/modules/ffmpeg/producer_ffmpeg.c +++ b/mlt/src/modules/ffmpeg/producer_ffmpeg.c @@ -19,7 +19,11 @@ */ #include "producer_ffmpeg.h" + #include +#include + +#include #include #include @@ -62,19 +66,28 @@ mlt_producer producer_ffmpeg_init( char *file ) // Set the properties mlt_properties_set( properties, "mlt_type", "producer_ffmpeg" ); - mlt_properties_set_int( properties, "known_length", 0 ); - mlt_properties_set( properties, "video_type", file ); + if ( file != NULL && !strcmp( file, "v4l" ) ) { + mlt_properties_set( properties, "video_type", "v4l" ); mlt_properties_set( properties, "video_file", "/dev/video0" ); + mlt_properties_set( properties, "video_size", "640x480" ); + mlt_properties_set( properties, "audio_type", "dsp" ); mlt_properties_set( properties, "audio_file", "/dev/dsp" ); } else { + mlt_properties_set( properties, "video_type", "file" ); mlt_properties_set( properties, "video_file", file ); + mlt_properties_set( properties, "video_size", "" ); + mlt_properties_set( properties, "audio_type", "file" ); mlt_properties_set( properties, "audio_file", file ); } + mlt_properties_set_int( properties, "audio_rate", 48000 ); + mlt_properties_set_int( properties, "audio_channels", 2 ); + mlt_properties_set_int( properties, "audio_track", 0 ); + this->buffer = malloc( 1024 * 1024 * 2 ); return producer; @@ -108,33 +121,38 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma FILE *producer_ffmpeg_run_video( producer_ffmpeg this ) { - // Get the producer - mlt_producer producer = &this->parent; + if ( this->video == NULL ) + { + // Get the producer + mlt_producer producer = &this->parent; - // Get the properties of the producer - mlt_properties properties = mlt_producer_properties( producer ); + // Get the properties of the producer + mlt_properties properties = mlt_producer_properties( producer ); - char *video_type = mlt_properties_get( properties, "video_type" ); - char *video_file = mlt_properties_get( properties, "video_file" ); - int video_loop = mlt_properties_get_int( properties, "video_loop" ); + // Get the video loop property + int video_loop = mlt_properties_get_int( properties, "video_loop" ); - if ( this->video == NULL ) - { if ( !this->open || video_loop ) { + const char *mlt_prefix = mlt_factory_prefix( ); + char *video_type = mlt_properties_get( properties, "video_type" ); + char *video_file = mlt_properties_get( properties, "video_file" ); + float video_rate = mlt_properties_get_double( properties, "fps" ); + char *video_size = mlt_properties_get( properties, "video_size" ); char command[ 1024 ] = ""; - float fps = mlt_producer_get_fps( &this->parent ); float position = mlt_producer_position( &this->parent ); if ( video_loop ) position = 0; - if ( video_type != NULL && !strcmp( video_type, "v4l" ) ) - sprintf( command, "ffmpeg -r %f -s 640x480 -vd \"%s\" -f imagepipe -f yuv4mpegpipe - 2>/dev/null", fps, video_file ); - else if ( video_file != NULL && strcmp( video_file, "" ) ) - sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -f yuv4mpegpipe - 2>/dev/null", video_file, position, fps ); + sprintf( command, "%s/ffmpeg/video.sh \"%s\" \"%s\" \"%s\" %f %f 2>/dev/null", + mlt_prefix, + video_type, + video_file, + video_size, + video_rate, + position ); - if ( strcmp( command, "" ) ) - this->video = popen( command, "r" ); + this->video = popen( command, "r" ); } } return this->video; @@ -148,26 +166,33 @@ FILE *producer_ffmpeg_run_audio( producer_ffmpeg this ) // Get the properties of the producer mlt_properties properties = mlt_producer_properties( producer ); - char *video_type = mlt_properties_get( properties, "video_type" ); - char *audio_file = mlt_properties_get( properties, "audio_file" ); - int audio_loop = mlt_properties_get_int( properties, "audio_loop" ); - if ( this->audio == NULL ) { + int audio_loop = mlt_properties_get_int( properties, "audio_loop" ); + if ( !this->open || audio_loop ) { + const char *mlt_prefix = mlt_factory_prefix( ); + char *audio_type = mlt_properties_get( properties, "audio_type" ); + char *audio_file = mlt_properties_get( properties, "audio_file" ); + int frequency = mlt_properties_get_int( properties, "audio_rate" ); + int channels = mlt_properties_get_int( properties, "audio_channels" ); + int track = mlt_properties_get_int( properties, "audio_track" ); char command[ 1024 ] = ""; float position = mlt_producer_position( &this->parent ); if ( audio_loop ) position = 0; - if ( video_type != NULL && !strcmp( video_type, "v4l" ) ) - sprintf( command, "ffmpeg -ad \"%s\" -f s16le -ar 48000 -ac 2 - 2>/dev/null", audio_file ); - else if ( audio_file != NULL ) - sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 - 2>/dev/null", audio_file, position ); + sprintf( command, "%s/ffmpeg/audio.sh \"%s\" \"%s\" %f %d %d %d 2>/dev/null", + mlt_prefix, + audio_type, + audio_file, + position, + frequency, + channels, + track ); - if ( strcmp( command, "" ) ) - this->audio = popen( command, "r" ); + this->audio = popen( command, "r" ); } } return this->audio; @@ -213,6 +238,57 @@ static void producer_ffmpeg_position( producer_ffmpeg this, uint64_t requested, this->open = 1; } +static int sample_calculator( float fps, int frequency, int64_t position ) +{ + int samples = 0; + + if ( fps == 25 ) + { + samples = frequency / 25; + } + else if ( fps >= 29.97 && fps < 29.98 ) + { + samples = frequency / 30; + + switch ( frequency ) + { + case 48000: + if ( position % 5 != 0 ) + samples += 2; + break; + case 44100: + if ( position % 300 == 0 ) + samples = 1471; + else if ( position % 30 == 0 ) + samples = 1470; + else if ( position % 2 == 0 ) + samples = 1472; + else + samples = 1471; + break; + case 32000: + if ( position % 30 == 0 ) + samples = 1068; + else if ( position % 29 == 0 ) + samples = 1067; + else if ( position % 4 == 2 ) + samples = 1067; + else + samples = 1068; + break; + default: + samples = 0; + } + } + else + { + if ( fps != 0 ) + samples = frequency / fps; + } + + return samples; +} + 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 @@ -221,14 +297,15 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma producer_ffmpeg producer = mlt_properties_get_data( properties, "producer_ffmpeg", NULL ); mlt_properties producer_properties = mlt_producer_properties( &producer->parent ); + int64_t target = mlt_properties_get_double( properties, "target" ); int skip = mlt_properties_get_int( properties, "skip" ); - *frequency = 48000; - *channels = 2; - *samples = 1920; + float fps = mlt_properties_get_double( producer_properties, "fps" ); + *frequency = mlt_properties_get_int( producer_properties, "audio_rate" ); + *channels = mlt_properties_get_int( producer_properties, "audio_channels" ); - // Size - int size = *samples * *channels * 2; + // Maximum Size (?) + int size = ( *frequency / 25 ) * *channels * 2; // Allocate an image *buffer = malloc( size ); @@ -238,7 +315,8 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma { do { - if ( fread( *buffer, size, 1, producer->audio ) != 1 ) + *samples = sample_calculator( fps, *frequency, target - skip ); + if ( fread( *buffer, *samples * *channels * 2, 1, producer->audio ) != 1 ) { pclose( producer->audio ); producer->audio = NULL; @@ -249,6 +327,7 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma } else { + *samples = sample_calculator( fps, *frequency, target ); memset( *buffer, 0, size ); } @@ -303,11 +382,15 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Are we at the position expected? producer_ffmpeg_position( this, mlt_producer_frame( producer ), &skip ); + // Get properties objects + mlt_properties producer_properties = mlt_producer_properties( &this->parent ); + // Get the frames properties mlt_properties properties = mlt_frame_properties( *frame ); FILE *video = this->video; + mlt_properties_set_double( properties, "target", mlt_producer_frame( producer ) ); mlt_properties_set_int( properties, "skip", skip ); // Read the video @@ -345,8 +428,10 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Clean up if ( this->video != NULL ) { + int video_loop = mlt_properties_get_int( producer_properties, "video_loop" ); + // Inform caller that end of clip is reached - this->end_of_video = 1; + this->end_of_video = !video_loop; pclose( this->video ); this->video = NULL; } @@ -362,9 +447,6 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Hmm - register audio callback ( *frame )->get_audio = producer_get_audio; - // Get properties objects - mlt_properties producer_properties = mlt_producer_properties( &this->parent ); - // Get the additional properties double aspect_ratio = mlt_properties_get_double( producer_properties, "aspect_ratio" ); double speed = mlt_properties_get_double( producer_properties, "speed" ); diff --git a/mlt/src/modules/ffmpeg/producer_ffmpeg.h b/mlt/src/modules/ffmpeg/producer_ffmpeg.h index a80470b..b283850 100644 --- a/mlt/src/modules/ffmpeg/producer_ffmpeg.h +++ b/mlt/src/modules/ffmpeg/producer_ffmpeg.h @@ -18,11 +18,10 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _PRODUCER_Y4M_H_ -#define _PRODUCER_Y4M_H_ +#ifndef _PRODUCER_FFMPEG_H_ +#define _PRODUCER_FFMPEG_H_ #include -#include extern mlt_producer producer_ffmpeg_init( char *file ); diff --git a/mlt/src/modules/ffmpeg/video.sh b/mlt/src/modules/ffmpeg/video.sh new file mode 100755 index 0000000..481718c --- /dev/null +++ b/mlt/src/modules/ffmpeg/video.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +video_type="$1" +video_file="$2" +video_size="$3" +video_fps=$4 +video_position=$5 + +[ "$video_size" != "" ] && video_size="-s "$video_size + +if [ "$video_type" == "v4l" ] +then ffmpeg -vd "$video_file" -r $video_fps $video_size -f imagepipe -f yuv4mpegpipe - +else ffmpeg -i "$video_file" -ss $video_position -f imagepipe -r $video_fps $video_size -f yuv4mpegpipe - +fi diff --git a/src/framework/mlt_factory.c b/src/framework/mlt_factory.c index 5d7187b..9795770 100644 --- a/src/framework/mlt_factory.c +++ b/src/framework/mlt_factory.c @@ -24,10 +24,12 @@ #include "mlt_properties.h" #include +#include /** Singleton repositories */ +static char *mlt_prefix = NULL; static mlt_properties object_list = NULL; static mlt_repository producers = NULL; static mlt_repository filters = NULL; @@ -43,6 +45,9 @@ int mlt_factory_init( char *prefix ) if ( prefix == NULL ) prefix = PREFIX_DATA; + // Store the prefix for later retrieval + mlt_prefix = strdup( prefix ); + // Create the object list. object_list = calloc( sizeof( struct mlt_properties_s ), 1 ); mlt_properties_init( object_list, NULL ); @@ -56,6 +61,14 @@ int mlt_factory_init( char *prefix ) return 0; } +/** Fetch the prefix used in this instance. +*/ + +const char *mlt_factory_prefix( ) +{ + return mlt_prefix; +} + /** Fetch a producer from the repository. */ @@ -98,6 +111,7 @@ void mlt_factory_close( ) mlt_repository_close( transitions ); mlt_repository_close( consumers ); mlt_properties_close( object_list ); + free( mlt_prefix ); free( object_list ); } diff --git a/src/framework/mlt_factory.h b/src/framework/mlt_factory.h index c9e7766..d0b9160 100644 --- a/src/framework/mlt_factory.h +++ b/src/framework/mlt_factory.h @@ -24,6 +24,7 @@ #include "mlt_types.h" extern int mlt_factory_init( char *prefix ); +extern const char *mlt_factory_prefix( ); extern mlt_producer mlt_factory_producer( char *name, void *input ); extern mlt_filter mlt_factory_filter( char *name, void *input ); extern mlt_transition mlt_factory_transition( char *name, void *input ); diff --git a/src/framework/mlt_multitrack.c b/src/framework/mlt_multitrack.c index 2e44f5b..96169b0 100644 --- a/src/framework/mlt_multitrack.c +++ b/src/framework/mlt_multitrack.c @@ -141,6 +141,7 @@ void mlt_multitrack_refresh( mlt_multitrack this ) mlt_properties_set_timecode( properties, "length", length ); mlt_properties_set_timecode( properties, "out", length ); mlt_properties_set_timecode( properties, "playtime", length - mlt_properties_get_timecode( properties, "in" ) ); + mlt_properties_set_double( properties, "fps", fps ); } /** Connect a producer to a given track. diff --git a/src/framework/mlt_producer.c b/src/framework/mlt_producer.c index 7dc6c6e..991c698 100644 --- a/src/framework/mlt_producer.c +++ b/src/framework/mlt_producer.c @@ -279,6 +279,10 @@ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int ind mlt_producer_prepare_next( this ); } + // Copy the fps of the producer onto the frame + mlt_properties properties = mlt_frame_properties( *frame ); + mlt_properties_set_double( properties, "fps", mlt_producer_get_fps( this ) ); + return 0; } diff --git a/src/modules/ffmpeg/audio.sh b/src/modules/ffmpeg/audio.sh new file mode 100755 index 0000000..3c7475a --- /dev/null +++ b/src/modules/ffmpeg/audio.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +audio_type="$1" +audio_file="$2" +audio_position=$3 +audio_frequency=$4 +audio_channels=$5 +audio_track=$5 + +if [ "$audio_type" == "dsp" ] +then ffmpeg -ad "$audio_file" -f s16le -ar $audio_frequency -ac $audio_channels - +else ffmpeg -i "$audio_file" -ss $audio_position -f s16le -ar $audio_frequency -ac $audio_channels - +fi + diff --git a/src/modules/ffmpeg/filter_ffmpeg_dub.c b/src/modules/ffmpeg/filter_ffmpeg_dub.c index 3ba9932..652354b 100644 --- a/src/modules/ffmpeg/filter_ffmpeg_dub.c +++ b/src/modules/ffmpeg/filter_ffmpeg_dub.c @@ -38,10 +38,10 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format mlt_properties producer_properties = mlt_producer_properties( producer ); // Get the original get_audio - int ( *get_audio )( mlt_frame, int16_t **, mlt_audio_format *, int *, int *, int * ) = mlt_properties_get_data( frame_properties, "get_audio", NULL ); + frame->get_audio = mlt_properties_get_data( frame_properties, "get_audio", NULL ); // Call the original get_audio - get_audio( frame, buffer, format, frequency, channels, samples ); + mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Now if our producer is still producing, override the audio if ( !mlt_properties_get_int( producer_properties, "end_of_clip" ) ) @@ -52,6 +52,9 @@ static int filter_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format // We need a frame from the producer mlt_frame producer_frame; + // Set the FPS + mlt_properties_set_double( producer_properties, "fps", mlt_properties_get_double( frame_properties, "fps" ) ); + // Seek to the position mlt_producer_seek_frame( producer, ( int64_t )position ); @@ -88,14 +91,22 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) // Obtain the frame properties mlt_properties frame_properties = mlt_frame_properties( frame ); - // Backup the original get_audio (it's still needed) - mlt_properties_set_data( frame_properties, "get_audio", frame->get_audio, 0, NULL, NULL ); + // Get the producer properties + mlt_properties producer_properties = mlt_producer_properties( producer ); - // Pass the producer on the frame - mlt_properties_set_data( frame_properties, "producer", producer, 0, NULL, NULL ); + // Only do this if we have not reached end of clip and ffmpeg_dub has not already been done + if ( !mlt_properties_get_int( producer_properties, "end_of_clip" ) && + mlt_properties_get_data( frame_properties, "get_audio", NULL ) == NULL ) + { + // Backup the original get_audio (it's still needed) + mlt_properties_set_data( frame_properties, "get_audio", frame->get_audio, 0, NULL, NULL ); + + // Pass the producer on the frame + mlt_properties_set_data( frame_properties, "producer", producer, 0, NULL, NULL ); - // Override the get_audio method - frame->get_audio = filter_get_audio; + // Override the get_audio method + frame->get_audio = filter_get_audio; + } return frame; } diff --git a/src/modules/ffmpeg/producer_ffmpeg.c b/src/modules/ffmpeg/producer_ffmpeg.c index 45c702b..95763df 100644 --- a/src/modules/ffmpeg/producer_ffmpeg.c +++ b/src/modules/ffmpeg/producer_ffmpeg.c @@ -19,7 +19,11 @@ */ #include "producer_ffmpeg.h" + #include +#include + +#include #include #include @@ -62,19 +66,28 @@ mlt_producer producer_ffmpeg_init( char *file ) // Set the properties mlt_properties_set( properties, "mlt_type", "producer_ffmpeg" ); - mlt_properties_set_int( properties, "known_length", 0 ); - mlt_properties_set( properties, "video_type", file ); + if ( file != NULL && !strcmp( file, "v4l" ) ) { + mlt_properties_set( properties, "video_type", "v4l" ); mlt_properties_set( properties, "video_file", "/dev/video0" ); + mlt_properties_set( properties, "video_size", "640x480" ); + mlt_properties_set( properties, "audio_type", "dsp" ); mlt_properties_set( properties, "audio_file", "/dev/dsp" ); } else { + mlt_properties_set( properties, "video_type", "file" ); mlt_properties_set( properties, "video_file", file ); + mlt_properties_set( properties, "video_size", "" ); + mlt_properties_set( properties, "audio_type", "file" ); mlt_properties_set( properties, "audio_file", file ); } + mlt_properties_set_int( properties, "audio_rate", 48000 ); + mlt_properties_set_int( properties, "audio_channels", 2 ); + mlt_properties_set_int( properties, "audio_track", 0 ); + this->buffer = malloc( 1024 * 1024 * 2 ); return producer; @@ -108,33 +121,38 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma FILE *producer_ffmpeg_run_video( producer_ffmpeg this ) { - // Get the producer - mlt_producer producer = &this->parent; + if ( this->video == NULL ) + { + // Get the producer + mlt_producer producer = &this->parent; - // Get the properties of the producer - mlt_properties properties = mlt_producer_properties( producer ); + // Get the properties of the producer + mlt_properties properties = mlt_producer_properties( producer ); - char *video_type = mlt_properties_get( properties, "video_type" ); - char *video_file = mlt_properties_get( properties, "video_file" ); - int video_loop = mlt_properties_get_int( properties, "video_loop" ); + // Get the video loop property + int video_loop = mlt_properties_get_int( properties, "video_loop" ); - if ( this->video == NULL ) - { if ( !this->open || video_loop ) { + const char *mlt_prefix = mlt_factory_prefix( ); + char *video_type = mlt_properties_get( properties, "video_type" ); + char *video_file = mlt_properties_get( properties, "video_file" ); + float video_rate = mlt_properties_get_double( properties, "fps" ); + char *video_size = mlt_properties_get( properties, "video_size" ); char command[ 1024 ] = ""; - float fps = mlt_producer_get_fps( &this->parent ); float position = mlt_producer_position( &this->parent ); if ( video_loop ) position = 0; - if ( video_type != NULL && !strcmp( video_type, "v4l" ) ) - sprintf( command, "ffmpeg -r %f -s 640x480 -vd \"%s\" -f imagepipe -f yuv4mpegpipe - 2>/dev/null", fps, video_file ); - else if ( video_file != NULL && strcmp( video_file, "" ) ) - sprintf( command, "ffmpeg -i \"%s\" -ss %f -f imagepipe -r %f -f yuv4mpegpipe - 2>/dev/null", video_file, position, fps ); + sprintf( command, "%s/ffmpeg/video.sh \"%s\" \"%s\" \"%s\" %f %f 2>/dev/null", + mlt_prefix, + video_type, + video_file, + video_size, + video_rate, + position ); - if ( strcmp( command, "" ) ) - this->video = popen( command, "r" ); + this->video = popen( command, "r" ); } } return this->video; @@ -148,26 +166,33 @@ FILE *producer_ffmpeg_run_audio( producer_ffmpeg this ) // Get the properties of the producer mlt_properties properties = mlt_producer_properties( producer ); - char *video_type = mlt_properties_get( properties, "video_type" ); - char *audio_file = mlt_properties_get( properties, "audio_file" ); - int audio_loop = mlt_properties_get_int( properties, "audio_loop" ); - if ( this->audio == NULL ) { + int audio_loop = mlt_properties_get_int( properties, "audio_loop" ); + if ( !this->open || audio_loop ) { + const char *mlt_prefix = mlt_factory_prefix( ); + char *audio_type = mlt_properties_get( properties, "audio_type" ); + char *audio_file = mlt_properties_get( properties, "audio_file" ); + int frequency = mlt_properties_get_int( properties, "audio_rate" ); + int channels = mlt_properties_get_int( properties, "audio_channels" ); + int track = mlt_properties_get_int( properties, "audio_track" ); char command[ 1024 ] = ""; float position = mlt_producer_position( &this->parent ); if ( audio_loop ) position = 0; - if ( video_type != NULL && !strcmp( video_type, "v4l" ) ) - sprintf( command, "ffmpeg -ad \"%s\" -f s16le -ar 48000 -ac 2 - 2>/dev/null", audio_file ); - else if ( audio_file != NULL ) - sprintf( command, "ffmpeg -i \"%s\" -ss %f -f s16le -ar 48000 -ac 2 - 2>/dev/null", audio_file, position ); + sprintf( command, "%s/ffmpeg/audio.sh \"%s\" \"%s\" %f %d %d %d 2>/dev/null", + mlt_prefix, + audio_type, + audio_file, + position, + frequency, + channels, + track ); - if ( strcmp( command, "" ) ) - this->audio = popen( command, "r" ); + this->audio = popen( command, "r" ); } } return this->audio; @@ -213,6 +238,57 @@ static void producer_ffmpeg_position( producer_ffmpeg this, uint64_t requested, this->open = 1; } +static int sample_calculator( float fps, int frequency, int64_t position ) +{ + int samples = 0; + + if ( fps == 25 ) + { + samples = frequency / 25; + } + else if ( fps >= 29.97 && fps < 29.98 ) + { + samples = frequency / 30; + + switch ( frequency ) + { + case 48000: + if ( position % 5 != 0 ) + samples += 2; + break; + case 44100: + if ( position % 300 == 0 ) + samples = 1471; + else if ( position % 30 == 0 ) + samples = 1470; + else if ( position % 2 == 0 ) + samples = 1472; + else + samples = 1471; + break; + case 32000: + if ( position % 30 == 0 ) + samples = 1068; + else if ( position % 29 == 0 ) + samples = 1067; + else if ( position % 4 == 2 ) + samples = 1067; + else + samples = 1068; + break; + default: + samples = 0; + } + } + else + { + if ( fps != 0 ) + samples = frequency / fps; + } + + return samples; +} + 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 @@ -221,14 +297,15 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma producer_ffmpeg producer = mlt_properties_get_data( properties, "producer_ffmpeg", NULL ); mlt_properties producer_properties = mlt_producer_properties( &producer->parent ); + int64_t target = mlt_properties_get_double( properties, "target" ); int skip = mlt_properties_get_int( properties, "skip" ); - *frequency = 48000; - *channels = 2; - *samples = 1920; + float fps = mlt_properties_get_double( producer_properties, "fps" ); + *frequency = mlt_properties_get_int( producer_properties, "audio_rate" ); + *channels = mlt_properties_get_int( producer_properties, "audio_channels" ); - // Size - int size = *samples * *channels * 2; + // Maximum Size (?) + int size = ( *frequency / 25 ) * *channels * 2; // Allocate an image *buffer = malloc( size ); @@ -238,7 +315,8 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma { do { - if ( fread( *buffer, size, 1, producer->audio ) != 1 ) + *samples = sample_calculator( fps, *frequency, target - skip ); + if ( fread( *buffer, *samples * *channels * 2, 1, producer->audio ) != 1 ) { pclose( producer->audio ); producer->audio = NULL; @@ -249,6 +327,7 @@ static int producer_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_forma } else { + *samples = sample_calculator( fps, *frequency, target ); memset( *buffer, 0, size ); } @@ -303,11 +382,15 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Are we at the position expected? producer_ffmpeg_position( this, mlt_producer_frame( producer ), &skip ); + // Get properties objects + mlt_properties producer_properties = mlt_producer_properties( &this->parent ); + // Get the frames properties mlt_properties properties = mlt_frame_properties( *frame ); FILE *video = this->video; + mlt_properties_set_double( properties, "target", mlt_producer_frame( producer ) ); mlt_properties_set_int( properties, "skip", skip ); // Read the video @@ -345,8 +428,10 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Clean up if ( this->video != NULL ) { + int video_loop = mlt_properties_get_int( producer_properties, "video_loop" ); + // Inform caller that end of clip is reached - this->end_of_video = 1; + this->end_of_video = !video_loop; pclose( this->video ); this->video = NULL; } @@ -362,9 +447,6 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // Hmm - register audio callback ( *frame )->get_audio = producer_get_audio; - // Get properties objects - mlt_properties producer_properties = mlt_producer_properties( &this->parent ); - // Get the additional properties double aspect_ratio = mlt_properties_get_double( producer_properties, "aspect_ratio" ); double speed = mlt_properties_get_double( producer_properties, "speed" ); diff --git a/src/modules/ffmpeg/producer_ffmpeg.h b/src/modules/ffmpeg/producer_ffmpeg.h index a80470b..b283850 100644 --- a/src/modules/ffmpeg/producer_ffmpeg.h +++ b/src/modules/ffmpeg/producer_ffmpeg.h @@ -18,11 +18,10 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _PRODUCER_Y4M_H_ -#define _PRODUCER_Y4M_H_ +#ifndef _PRODUCER_FFMPEG_H_ +#define _PRODUCER_FFMPEG_H_ #include -#include extern mlt_producer producer_ffmpeg_init( char *file ); diff --git a/src/modules/ffmpeg/video.sh b/src/modules/ffmpeg/video.sh new file mode 100755 index 0000000..481718c --- /dev/null +++ b/src/modules/ffmpeg/video.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +video_type="$1" +video_file="$2" +video_size="$3" +video_fps=$4 +video_position=$5 + +[ "$video_size" != "" ] && video_size="-s "$video_size + +if [ "$video_type" == "v4l" ] +then ffmpeg -vd "$video_file" -r $video_fps $video_size -f imagepipe -f yuv4mpegpipe - +else ffmpeg -i "$video_file" -ss $video_position -f imagepipe -r $video_fps $video_size -f yuv4mpegpipe - +fi -- 1.7.4.4