X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fframework%2Fmlt_consumer.c;h=93afe447d6a13c81ea9b00cb98c29d4799aa6d76;hb=3902731cb8a9622204d584c4962c74e2a5a35428;hp=8ed90c7256dce4effaa2c1bdbbc9982c07d3af19;hpb=e5fd66367b6f976e3bcb0ada98408afcb40cb2ce;p=melted diff --git a/src/framework/mlt_consumer.c b/src/framework/mlt_consumer.c index 8ed90c7..93afe44 100644 --- a/src/framework/mlt_consumer.c +++ b/src/framework/mlt_consumer.c @@ -1,8 +1,9 @@ /** * \file mlt_consumer.c * \brief abstraction for all consumer services + * \see mlt_consumer_s * - * Copyright (C) 2003-2008 Ushodaya Enterprises Limited + * Copyright (C) 2003-2009 Ushodaya Enterprises Limited * \author Charles Yates * * This library is free software; you can redistribute it and/or @@ -25,12 +26,16 @@ #include "mlt_producer.h" #include "mlt_frame.h" #include "mlt_profile.h" +#include "mlt_log.h" #include #include #include #include +/** Define this if you want an automatic deinterlace (if necessary) when the + * consumer's producer is not running at normal speed. + */ #undef DEINTERLACE_ON_NOT_NORMAL_SPEED static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ); @@ -38,6 +43,16 @@ static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner static void mlt_consumer_property_changed( mlt_service owner, mlt_consumer this, char *name ); static void apply_profile_properties( mlt_consumer this, mlt_profile profile, mlt_properties properties ); +/** Initialize a consumer service. + * + * \public \memberof mlt_consumer_s + * \param this the consumer to initialize + * \param child a pointer to the object for the subclass + * \param profile the \p mlt_profile_s to use (optional but recommended, + * uses the environment variable MLT if this is NULL) + * \return true if there was an error + */ + int mlt_consumer_init( mlt_consumer this, void *child, mlt_profile profile ) { int error = 0; @@ -95,6 +110,14 @@ int mlt_consumer_init( mlt_consumer this, void *child, mlt_profile profile ) return error; } +/** Convert the profile into properties on the consumer. + * + * \private \memberof mlt_consumer_s + * \param this a consumer + * \param profile a profile + * \param properties a properties list (typically, the consumer's) + */ + static void apply_profile_properties( mlt_consumer this, mlt_profile profile, mlt_properties properties ) { mlt_event_block( this->event_listener ); @@ -113,6 +136,14 @@ static void apply_profile_properties( mlt_consumer this, mlt_profile profile, ml mlt_event_unblock( this->event_listener ); } +/** The property-changed event listener + * + * \private \memberof mlt_consumer_s + * \param owner the service a service (ignored) + * \param this the consumer + * \param name the name of the property that changed + */ + static void mlt_consumer_property_changed( mlt_service owner, mlt_consumer this, char *name ) { if ( !strcmp( name, "profile" ) ) @@ -224,12 +255,34 @@ static void mlt_consumer_property_changed( mlt_service owner, mlt_consumer this, } } +/** The transmitter for the consumer-frame-show event + * + * Invokes the listener. + * + * \private \memberof mlt_consumer_s + * \param listener a function pointer that will be invoked + * \param owner a properties list that will be passed to \p listener + * \param this a service that will be passed to \p listener + * \param args an array of pointers - the first entry is passed as a string to \p listener + */ + static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) { if ( listener != NULL ) listener( owner, this, ( mlt_frame )args[ 0 ] ); } +/** The transmitter for the consumer-frame-render event + * + * Invokes the listener. + * + * \private \memberof mlt_consumer_s + * \param listener a function pointer that will be invoked + * \param owner a properties list that will be passed to \p listener + * \param this a service that will be passed to \p listener + * \param args an array of pointers - the first entry is passed as a string to \p listener + */ + static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) { if ( listener != NULL ) @@ -237,7 +290,11 @@ static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties own } /** Create a new consumer. -*/ + * + * \public \memberof mlt_consumer_s + * \param profile a profile (optional, but recommended) + * \return a new consumer + */ mlt_consumer mlt_consumer_new( mlt_profile profile ) { @@ -253,7 +310,12 @@ mlt_consumer mlt_consumer_new( mlt_profile profile ) } /** Get the parent service object. -*/ + * + * \public \memberof mlt_consumer_s + * \param this a consumer + * \return the parent service class + * \see MLT_CONSUMER_SERVICE + */ mlt_service mlt_consumer_service( mlt_consumer this ) { @@ -261,7 +323,12 @@ mlt_service mlt_consumer_service( mlt_consumer this ) } /** Get the consumer properties. -*/ + * + * \public \memberof mlt_consumer_s + * \param this a consumer + * \return the consumer's properties list + * \see MLT_CONSUMER_PROPERTIES + */ mlt_properties mlt_consumer_properties( mlt_consumer this ) { @@ -269,7 +336,15 @@ mlt_properties mlt_consumer_properties( mlt_consumer this ) } /** Connect the consumer to the producer. -*/ + * + * \public \memberof mlt_consumer_s + * \param this a consumer + * \param producer a producer + * \return > 0 warning, == 0 success, < 0 serious error, + * 1 = this service does not accept input, + * 2 = the producer is invalid, + * 3 = the producer is already registered with this consumer + */ int mlt_consumer_connect( mlt_consumer this, mlt_service producer ) { @@ -277,7 +352,11 @@ int mlt_consumer_connect( mlt_consumer this, mlt_service producer ) } /** Start the consumer. -*/ + * + * \public \memberof mlt_consumer_s + * \param this a consumer + * \return true if there was an error + */ int mlt_consumer_start( mlt_consumer this ) { @@ -330,7 +409,8 @@ int mlt_consumer_start( mlt_consumer this ) // Check and run an ante command if ( mlt_properties_get( properties, "ante" ) ) - system( mlt_properties_get( properties, "ante" ) ); + if ( system( mlt_properties_get( properties, "ante" ) ) == -1 ) + mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "ante" ) ); // Set the real_time preference this->real_time = mlt_properties_get_int( properties, "real_time" ); @@ -342,9 +422,15 @@ int mlt_consumer_start( mlt_consumer this ) return 0; } -/** An alternative method to feed frames into the consumer - only valid if - the consumer itself is not connected. -*/ +/** An alternative method to feed frames into the consumer. + * + * Only valid if the consumer itself is not connected. + * + * \public \memberof mlt_consumer_s + * \param this a consumer + * \param frame a frame + * \return true (ignore this for now) + */ int mlt_consumer_put_frame( mlt_consumer this, mlt_frame frame ) { @@ -381,7 +467,11 @@ int mlt_consumer_put_frame( mlt_consumer this, mlt_frame frame ) } /** Protected method for consumer to get frames from connected service -*/ + * + * \public \memberof mlt_consumer_s + * \param this a consumer + * \return a frame + */ mlt_frame mlt_consumer_get_frame( mlt_consumer this ) { @@ -448,6 +538,13 @@ mlt_frame mlt_consumer_get_frame( mlt_consumer this ) return frame; } +/** Compute the time difference between now and a time value. + * + * \private \memberof mlt_consumer_s + * \param time1 a time value to be compared against now + * \return the difference in microseconds + */ + static inline long time_difference( struct timeval *time1 ) { struct timeval time2; @@ -457,6 +554,13 @@ static inline long time_difference( struct timeval *time1 ) return time1->tv_sec * 1000000 + time1->tv_usec - time2.tv_sec * 1000000 - time2.tv_usec; } +/** The thread procedure for asynchronously pulling frames through the service + * network connected to a consumer. + * + * \private \memberof mlt_consumer_s + * \param arg a consumer + */ + static void *consumer_read_ahead_thread( void *arg ) { // The argument is the consumer @@ -643,6 +747,12 @@ static void *consumer_read_ahead_thread( void *arg ) return NULL; } +/** Start the read/render thread. + * + * \private \memberof mlt_consumer_s + * \param this a consumer + */ + static void consumer_read_ahead_start( mlt_consumer this ) { // We're running now @@ -678,6 +788,12 @@ static void consumer_read_ahead_start( mlt_consumer this ) } } +/** Stop the read/render thread. + * + * \private \memberof mlt_consumer_s + * \param this a consumer + */ + static void consumer_read_ahead_stop( mlt_consumer this ) { // Make sure we're running @@ -714,6 +830,12 @@ static void consumer_read_ahead_stop( mlt_consumer this ) } } +/** Flush the read/render thread's buffer. + * + * \public \memberof mlt_consumer_s + * \param this a consumer + */ + void mlt_consumer_purge( mlt_consumer this ) { if ( this->ahead ) @@ -726,6 +848,17 @@ void mlt_consumer_purge( mlt_consumer this ) } } +/** Get the next frame from the producer connected to a consumer. + * + * Typically, one uses this instead of \p mlt_consumer_get_frame to make + * the asynchronous/real-time behavior configurable at runtime. + * You should close the frame returned from this when you are done with it. + * + * \public \memberof mlt_consumer_s + * \param this a consumer + * \return a frame + */ + mlt_frame mlt_consumer_rt_frame( mlt_consumer this ) { // Frame to return @@ -771,7 +904,10 @@ mlt_frame mlt_consumer_rt_frame( mlt_consumer this ) } /** Callback for the implementation to indicate a stopped condition. -*/ + * + * \public \memberof mlt_consumer_s + * \param this a consumer + */ void mlt_consumer_stopped( mlt_consumer this ) { @@ -781,28 +917,31 @@ void mlt_consumer_stopped( mlt_consumer this ) } /** Stop the consumer. -*/ + * + * \public \memberof mlt_consumer_s + * \param this a consumer + * \return true if there was an error + */ int mlt_consumer_stop( mlt_consumer this ) { // Get the properies mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - char *debug = mlt_properties_get( MLT_CONSUMER_PROPERTIES( this ), "debug" ); // Just in case... - if ( debug ) fprintf( stderr, "%s: stopping put waiting\n", debug ); + mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_DEBUG, "stopping put waiting\n" ); pthread_mutex_lock( &this->put_mutex ); this->put_active = 0; pthread_cond_broadcast( &this->put_cond ); pthread_mutex_unlock( &this->put_mutex ); // Stop the consumer - if ( debug ) fprintf( stderr, "%s: stopping consumer\n", debug ); + mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_DEBUG, "stopping consumer\n" ); if ( this->stop != NULL ) this->stop( this ); // Check if the user has requested real time or not and stop if necessary - if ( debug ) fprintf( stderr, "%s: stopping read_ahead\n", debug ); + mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_DEBUG, "stopping read_ahead\n" ); if ( mlt_properties_get_int( properties, "real_time" ) ) consumer_read_ahead_stop( this ); @@ -811,15 +950,20 @@ int mlt_consumer_stop( mlt_consumer this ) // Check and run a post command if ( mlt_properties_get( properties, "post" ) ) - system( mlt_properties_get( properties, "post" ) ); + if (system( mlt_properties_get( properties, "post" ) ) == -1 ) + mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "post" ) ); - if ( debug ) fprintf( stderr, "%s: stopped\n", debug ); + mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_DEBUG, "stopped\n" ); return 0; } /** Determine if the consumer is stopped. -*/ + * + * \public \memberof mlt_consumer_s + * \param this a consumer + * \return true if the consumer is stopped + */ int mlt_consumer_is_stopped( mlt_consumer this ) { @@ -830,8 +974,11 @@ int mlt_consumer_is_stopped( mlt_consumer this ) return 0; } -/** Close the consumer. -*/ +/** Close and destroy the consumer. + * + * \public \memberof mlt_consumer_s + * \param this a consumer + */ void mlt_consumer_close( mlt_consumer this ) {