From e119b618924284bb2bcc7c2199ab06066ed76c8e Mon Sep 17 00:00:00 2001 From: lilo_booter Date: Tue, 27 Jan 2004 15:36:31 +0000 Subject: [PATCH] vorbis producer added, clean up on clip handling in multitrack git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@97 d19143bc-622f-0410-bfdd-b5b2a6649095 --- README | 1 + docs/services.txt | 28 ++ src/framework/mlt_multitrack.c | 84 ++++-- src/miracle/miracle_unit.c | 10 +- src/modules/Makefile | 2 +- src/modules/avformat/producer_avformat.c | 6 +- src/modules/inigo/producer_inigo.c | 8 + src/modules/vorbis/Makefile | 29 ++ src/modules/vorbis/configure | 11 + src/modules/vorbis/factory.c | 46 +++ src/modules/vorbis/producer_vorbis.c | 339 +++++++++++++++++++++++ src/modules/vorbis/producer_vorbis.h | 28 ++ 12 files changed, 565 insertions(+), 27 deletions(-) create mode 100644 src/modules/vorbis/Makefile create mode 100755 src/modules/vorbis/configure create mode 100644 src/modules/vorbis/factory.c create mode 100644 src/modules/vorbis/producer_vorbis.c create mode 100644 src/modules/vorbis/producer_vorbis.h diff --git a/README b/README index 8e163130..4fc7dad7 100644 --- a/README +++ b/README @@ -19,6 +19,7 @@ Directories + dv - libdv dependent services + ffmpeg - ffmpeg dependent services + avformat - libavformat dependent services + + vorbis - vorbis dependenent services + sdl - SDL dependent services + resample - libresample dependent services + gtk2 - pango and pixbuf dependent services diff --git a/docs/services.txt b/docs/services.txt index 390d05d6..8cbed80f 100644 --- a/docs/services.txt +++ b/docs/services.txt @@ -313,6 +313,34 @@ Producers Since it uses pipes, it is not compatible with bluefish. + vorbis + + Description + + OGG Vorbis file reader. + + Constructor Argument + + 'file' - file to use (only .ogg supported at the moment) + + Initialisation Properties + + int in - in point + int out - out point + + Read Only Properties + + double fps - this is fixed at 25 for PAL currently + + Dependencies + + libvorbisfile + + Known Bugs + + Fixed frame size (PAL audio chunks). + Doesn't cover ogg files with multiple, differing sections. + Filters ------- diff --git a/src/framework/mlt_multitrack.c b/src/framework/mlt_multitrack.c index 2faaf69a..ef7a1bed 100644 --- a/src/framework/mlt_multitrack.c +++ b/src/framework/mlt_multitrack.c @@ -210,6 +210,21 @@ mlt_producer mlt_multitrack_track( mlt_multitrack this, int track ) return producer; } +static int position_compare( const void *p1, const void *p2 ) +{ + return *( int64_t * )p1 - *( int64_t * )p2; +} + +static int add_unique( mlt_position *array, int size, mlt_position position ) +{ + int i = 0; + for ( i = 0; i < size; i ++ ) + if ( array[ i ] == position ) + break; + if ( i == size ) + array[ size ++ ] = position; + return size; +} /** Determine the clip point. @@ -233,11 +248,12 @@ mlt_producer mlt_multitrack_track( mlt_multitrack this, int track ) mlt_position mlt_multitrack_clip( mlt_multitrack this, mlt_whence whence, int index ) { - int first = 1; mlt_position position = 0; int i = 0; + int j = 0; + int64_t *map = malloc( 1000 * sizeof( mlt_position ) ); + int count = 0; - // Loop through each of the tracks for ( i = 0; i < this->count; i ++ ) { // Get the producer for this track @@ -252,35 +268,59 @@ mlt_position mlt_multitrack_clip( mlt_multitrack this, mlt_whence whence, int in // Determine if it's a playlist mlt_playlist playlist = mlt_properties_get_data( properties, "playlist", NULL ); - // We only consider playlists + // Special case consideration of playlists if ( playlist != NULL ) { - // Locate the smallest position - if ( first ) - { - // First position found - position = mlt_playlist_clip( playlist, whence, index ); - - // We're no longer first - first = 0; - } - else - { - // Obtain the clip position in this playlist - //mlt_position position2 = mlt_playlist_clip( playlist, whence, index ); - - // If this position is prior to the first, then use it - //if ( position2 < position ) - //position = position2; - } + for ( j = 0; j < mlt_playlist_count( playlist ); j ++ ) + count = add_unique( map, count, mlt_playlist_clip( playlist, mlt_whence_relative_start, j ) ); + count = add_unique( map, count, mlt_producer_get_out( producer ) + 1 ); } else { - fprintf( stderr, "track %d isn't a playlist\n", index ); + count = add_unique( map, count, 0 ); + count = add_unique( map, count, mlt_producer_get_out( producer ) + 1 ); } } } + // Now sort the map + qsort( map, count, sizeof( int64_t ), position_compare ); + + // Now locate the requested index + switch( whence ) + { + case mlt_whence_relative_start: + if ( index < count ) + position = map[ index ]; + else + position = map[ count - 1 ]; + break; + + case mlt_whence_relative_current: + position = mlt_producer_position( mlt_multitrack_producer( this ) ); + for ( i = 0; i < count - 2; i ++ ) + if ( position >= map[ i ] && position < map[ i + 1 ] ) + break; + index += i; + if ( index >= 0 && index < count ) + position = map[ index ]; + else if ( index < 0 ) + position = map[ 0 ]; + else + position = map[ count - 1 ]; + break; + + case mlt_whence_relative_end: + if ( index < count ) + position = map[ count - index - 1 ]; + else + position = map[ 0 ]; + break; + } + + // Free the map + free( map ); + return position; } diff --git a/src/miracle/miracle_unit.c b/src/miracle/miracle_unit.c index 2f739179..b194e7c2 100644 --- a/src/miracle/miracle_unit.c +++ b/src/miracle/miracle_unit.c @@ -146,6 +146,8 @@ static mlt_producer create_producer( miracle_unit unit, char *file ) char *args[ 2 ] = { file, NULL }; result = mlt_factory_producer( "inigo", args ); } + else if ( strstr( file, ".westley" ) ) + result = mlt_factory_producer( "westley", file ); else if ( strstr( file, ".mpg" ) ) result = mlt_factory_producer( "mcmpeg", file ); else if ( strstr( file, ".mpeg" ) ) @@ -166,7 +168,9 @@ static mlt_producer create_producer( miracle_unit unit, char *file ) result = mlt_factory_producer( "pixbuf", file ); else if ( strstr( file, ".txt" ) ) result = mlt_factory_producer( "pango", file ); - + else if ( strstr( file, ".ogg" ) ) + result = mlt_factory_producer( "vorbis", file ); + // 2nd Line fallbacks if ( result == NULL && strstr( file, ".dv" ) ) result = mlt_factory_producer( "libdv", file ); @@ -177,6 +181,10 @@ static mlt_producer create_producer( miracle_unit unit, char *file ) if ( result == NULL ) result = mlt_factory_producer( "avformat", file ); + // 4th line fallbacks + if ( result == NULL ) + result = mlt_factory_producer( "ffmpeg", file ); + // Now store the result mlt_properties_set_data( properties, file, result, 0, ( mlt_destructor )mlt_producer_close, NULL ); } diff --git a/src/modules/Makefile b/src/modules/Makefile index 8a14a7fb..4691b5e6 100644 --- a/src/modules/Makefile +++ b/src/modules/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = core gtk2 dv sdl mainconcept bluefish ffmpeg resample inigo avformat westley +SUBDIRS = core gtk2 dv sdl mainconcept bluefish ffmpeg resample inigo avformat vorbis westley all clean depend install: list='$(SUBDIRS)'; \ diff --git a/src/modules/avformat/producer_avformat.c b/src/modules/avformat/producer_avformat.c index 943b8476..d19c1659 100644 --- a/src/modules/avformat/producer_avformat.c +++ b/src/modules/avformat/producer_avformat.c @@ -92,7 +92,7 @@ mlt_producer producer_avformat_init( char *file ) /** Find the default streams. */ -void find_default_streams( AVFormatContext *context, int *audio_index, int *video_index ) +static void find_default_streams( AVFormatContext *context, int *audio_index, int *video_index ) { int i; @@ -122,7 +122,7 @@ void find_default_streams( AVFormatContext *context, int *audio_index, int *vide /** Producer file destructor. */ -void producer_file_close( void *context ) +static void producer_file_close( void *context ) { if ( context != NULL ) { @@ -140,7 +140,7 @@ void producer_file_close( void *context ) /** Producer file destructor. */ -void producer_codec_close( void *codec ) +static void producer_codec_close( void *codec ) { if ( codec != NULL ) { diff --git a/src/modules/inigo/producer_inigo.c b/src/modules/inigo/producer_inigo.c index ed20ea3b..313e8d59 100644 --- a/src/modules/inigo/producer_inigo.c +++ b/src/modules/inigo/producer_inigo.c @@ -48,7 +48,9 @@ static mlt_producer parse_inigo( char *file ) if ( result != NULL ) { mlt_properties properties = mlt_producer_properties( result ); + fprintf( stderr, "resource = %s\n", mlt_properties_get( properties, "resource" ) ); mlt_properties_set( properties, "resource", file ); + fprintf( stderr, "resource = %s\n", mlt_properties_get( properties, "resource" ) ); } while( count -- ) @@ -85,6 +87,8 @@ static mlt_producer create_producer( char *file ) result = mlt_factory_producer( "pango", file ); else if ( strstr( file, ".westley" ) ) result = mlt_factory_producer( "westley", file ); + else if ( strstr( file, ".ogg" ) ) + result = mlt_factory_producer( "vorbis", file ); // 2nd Line fallbacks if ( result == NULL && strstr( file, ".dv" ) ) @@ -96,6 +100,10 @@ static mlt_producer create_producer( char *file ) if ( result == NULL ) result = mlt_factory_producer( "avformat", file ); + // 4th line fallbacks + if ( result == NULL ) + result = mlt_factory_producer( "ffmpeg", file ); + return result; } diff --git a/src/modules/vorbis/Makefile b/src/modules/vorbis/Makefile new file mode 100644 index 00000000..ac457c01 --- /dev/null +++ b/src/modules/vorbis/Makefile @@ -0,0 +1,29 @@ + +TARGET = ../libmltvorbis.so + +OBJS = factory.o \ + producer_vorbis.o + +CFLAGS = -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 + +LDFLAGS = -lvorbisfile + +SRCS := $(OBJS:.o=.c) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) -shared -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/modules/vorbis/configure b/src/modules/vorbis/configure new file mode 100755 index 00000000..77f31557 --- /dev/null +++ b/src/modules/vorbis/configure @@ -0,0 +1,11 @@ +#!/bin/bash + +if [ "$help" != "1" ] +then + +cat << EOF >> ../producers.dat +vorbis libmltvorbis.so +EOF + +fi + diff --git a/src/modules/vorbis/factory.c b/src/modules/vorbis/factory.c new file mode 100644 index 00000000..2ca93091 --- /dev/null +++ b/src/modules/vorbis/factory.c @@ -0,0 +1,46 @@ +/* + * factory.c -- the factory method interfaces + * Copyright (C) 2003-2004 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. + */ + +#include + +#include "producer_vorbis.h" + +void *mlt_create_producer( char *id, void *arg ) +{ + if ( !strcmp( id, "vorbis" ) ) + return producer_vorbis_init( arg ); + return NULL; +} + +void *mlt_create_filter( char *id, void *arg ) +{ + return NULL; +} + +void *mlt_create_transition( char *id, void *arg ) +{ + return NULL; +} + +void *mlt_create_consumer( char *id, void *arg ) +{ + return NULL; +} + diff --git a/src/modules/vorbis/producer_vorbis.c b/src/modules/vorbis/producer_vorbis.c new file mode 100644 index 00000000..9d3b849c --- /dev/null +++ b/src/modules/vorbis/producer_vorbis.c @@ -0,0 +1,339 @@ +/* + * producer_vorbis.c -- vorbis producer + * Copyright (C) 2003-2004 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. + */ + +// Local header files +#include "producer_vorbis.h" + +// MLT Header files +#include + +// vorbis Header files +#include +#include + +// System header files +#include +#include + +// Forward references. +static int producer_open( mlt_producer this, char *file ); +static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ); + +/** Constructor for libvorbis. +*/ + +mlt_producer producer_vorbis_init( char *file ) +{ + mlt_producer this = NULL; + + // Check that we have a non-NULL argument + if ( file != NULL ) + { + // Construct the producer + this = calloc( 1, sizeof( struct mlt_producer_s ) ); + + // Initialise it + if ( mlt_producer_init( this, NULL ) == 0 ) + { + // Get the properties + mlt_properties properties = mlt_producer_properties( this ); + + // Set the resource property (required for all producers) + mlt_properties_set( properties, "resource", file ); + + // Register our get_frame implementation + this->get_frame = producer_get_frame; + + // Open the file + if ( producer_open( this, file ) != 0 ) + { + // Clean up + mlt_producer_close( this ); + this = NULL; + } + } + } + + return this; +} + +/** Destuctor for ogg files. +*/ + +static void producer_file_close( void *file ) +{ + if ( file != NULL ) + { + // Close the ogg vorbis structure + ov_clear( file ); + + // Free the memory + free( file ); + } +} + +/** Open the file. +*/ + +static int producer_open( mlt_producer this, char *file ) +{ + // FILE pointer for file + FILE *input = fopen( file, "r" ); + + // Error code to return + int error = input == NULL; + + // Continue if file is open + if ( error == 0 ) + { + // OggVorbis file structure + OggVorbis_File *ov = calloc( 1, sizeof( OggVorbis_File ) ); + + // Attempt to open the stream + error = ov == NULL || ov_open( input, ov, NULL, 0 ) != 0; + + // Assign to producer properties if successful + if ( error == 0 ) + { + // Get the properties + mlt_properties properties = mlt_producer_properties( this ); + + // Assign the ov structure + mlt_properties_set_data( properties, "ogg_vorbis_file", ov, 0, producer_file_close, NULL ); + + if ( ov_seekable( ov ) ) + { + // Get the length of the file + double length = ov_time_total( ov, -1 ); + + // We will treat everything with the producer fps + double fps = mlt_properties_get_double( properties, "fps" ); + + // Set out and length of file + mlt_properties_set_position( properties, "out", ( length * fps ) - 1 ); + mlt_properties_set_position( properties, "length", ( length * fps ) ); + } + } + else + { + // Clean up + free( ov ); + + // Must close input file when open fails + fclose( input ); + } + } + + return error; +} + +/** Convert a frame position to a time code. +*/ + +static double producer_time_of_frame( mlt_producer this, mlt_position position ) +{ + // Get the properties + mlt_properties properties = mlt_producer_properties( this ); + + // Obtain the fps + double fps = mlt_properties_get_double( properties, "fps" ); + + // Do the calc + return ( double )position / fps; +} + +/** Get the audio from a frame. +*/ + +static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +{ + // Get the properties from the frame + mlt_properties frame_properties = mlt_frame_properties( frame ); + + // Obtain the frame number of this frame + mlt_position position = mlt_properties_get_position( frame_properties, "vorbis_position" ); + + // Get the producer + mlt_producer this = mlt_properties_get_data( frame_properties, "vorbis_producer", NULL ); + + // Get the producer properties + mlt_properties properties = mlt_producer_properties( this ); + + // Get the ogg vorbis file + OggVorbis_File *ov = mlt_properties_get_data( properties, "ogg_vorbis_file", NULL ); + + // Obtain the expected frame numer + mlt_position expected = mlt_properties_get_position( properties, "audio_expected" ); + + // Get the fps for this producer + double fps = mlt_properties_get_double( properties, "fps" ); + + // Get the vorbis info + vorbis_info *vi = ov_info( ov, -1 ); + + // Obtain the audio buffer + int16_t *audio_buffer = mlt_properties_get_data( properties, "audio_buffer", NULL ); + + // Get amount of audio used + int audio_used = mlt_properties_get_int( properties, "audio_used" ); + + // Number of frames to ignore (for ffwd) + int ignore = 0; + + // Flag for paused (silence) + int paused = 0; + + // Check for audio buffer and create if necessary + if ( audio_buffer == NULL ) + { + // Allocate the audio buffer + audio_buffer = malloc( 131072 * sizeof( int16_t ) ); + + // And store it on properties for reuse + mlt_properties_set_data( properties, "audio_buffer", audio_buffer, 0, free, NULL ); + } + + // Seek if necessary + if ( position != expected ) + { + if ( position + 1 == expected ) + { + // We're paused - silence required + paused = 1; + } + else if ( position > expected && ( position - expected ) < 250 ) + { + // Fast forward - seeking is inefficient for small distances - just ignore following frames + ignore = position - expected; + } + else + { + // Seek to the required position + ov_time_seek( ov, producer_time_of_frame( this, position ) ); + expected = position; + audio_used = 0; + } + } + + // Return info in frame + *frequency = vi->rate; + *channels = vi->channels; + + // Get the audio if required + if ( !paused ) + { + // Bitstream section + int current_section; + + // Get the number of samples for the current frame + *samples = mlt_sample_calculator( fps, *frequency, expected ++ ); + + while( *samples > audio_used ) + { + // Read the samples + int bytes = ov_read( ov, ( char * )( &audio_buffer[ audio_used * 2 ] ), 4096, 0, 2, 1, ¤t_section ); + + // Break if error or eof + if ( bytes <= 0 ) + break; + + // Increment number of samples used + audio_used += bytes / ( sizeof( int16_t ) * *channels ); + + // Handle ignore + while ( ignore && audio_used >= *samples ) + { + ignore --; + audio_used -= *samples; + memmove( audio_buffer, &audio_buffer[ *samples * *channels ], audio_used * sizeof( int16_t ) ); + *samples = mlt_sample_calculator( fps, *frequency, expected ++ ); + } + } + + // Now handle the audio if we have enough + if ( audio_used >= *samples ) + { + *buffer = malloc( *samples * *channels * sizeof( int16_t ) ); + memcpy( *buffer, audio_buffer, *samples * *channels * sizeof( int16_t ) ); + audio_used -= *samples; + memmove( audio_buffer, &audio_buffer[ *samples * *channels ], audio_used * *channels * sizeof( int16_t ) ); + mlt_properties_set_data( frame_properties, "audio", *buffer, 0, free, NULL ); + } + else + { + frame->get_audio = NULL; + mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); + audio_used = 0; + } + + // Store the number of audio samples still available + mlt_properties_set_int( properties, "audio_used", audio_used ); + } + else + { + // Get silence and don't touch the context + frame->get_audio = NULL; + *samples = mlt_sample_calculator( fps, *frequency, position ); + mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); + } + + // Regardless of speed, we expect to get the next frame (cos we ain't too bright) + mlt_properties_set_position( properties, "audio_expected", position + 1 ); + + return 0; +} + +/** Set up audio handling. +*/ + +static void producer_set_up_audio( mlt_producer this, mlt_frame frame ) +{ + // Get the properties + mlt_properties properties = mlt_frame_properties( frame ); + + // Set the audio method + frame->get_audio = producer_get_audio; + + // Set the producer on the frame + mlt_properties_set_data( properties, "vorbis_producer", this, 0, NULL, NULL ); +} + +/** Our get frame implementation. +*/ + +static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ) +{ + // Create an empty frame + *frame = mlt_frame_init( ); + + // Update timecode on the frame we're creating + mlt_frame_set_position( *frame, mlt_producer_position( this ) ); + + // Set the position of this producer + mlt_properties_set_position( mlt_frame_properties( *frame ), "vorbis_position", mlt_producer_get_in( this ) + mlt_producer_position( this ) ); + + // Set up the audio + producer_set_up_audio( this, *frame ); + + // Calculate the next timecode + mlt_producer_prepare_next( this ); + + return 0; +} diff --git a/src/modules/vorbis/producer_vorbis.h b/src/modules/vorbis/producer_vorbis.h new file mode 100644 index 00000000..6aaf404f --- /dev/null +++ b/src/modules/vorbis/producer_vorbis.h @@ -0,0 +1,28 @@ +/* + * producer_vorbis.h -- vorbis producer + * Copyright (C) 2003-2004 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 _PRODUCER_VORBIS_H_ +#define _PRODUCER_VORBIS_H_ + +#include + +extern mlt_producer producer_vorbis_init( char *file ); + +#endif -- 2.39.2