X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fcontrol%2Fmedia_instance.c;h=6f10e14f8d5aeb5ceb00ac8f9aa446aa9d2682ea;hb=6ee1e193fd896ab9a4729fde14f009d9ce629815;hp=9ec00b12abf7641b632bd46f30b97cf298ff2cff;hpb=be6efa200669abe4afc82ab9d4ef618ae7af1c11;p=vlc diff --git a/src/control/media_instance.c b/src/control/media_instance.c index 9ec00b12ab..6f10e14f8d 100644 --- a/src/control/media_instance.c +++ b/src/control/media_instance.c @@ -21,48 +21,220 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ -#include "libvlc_internal.h" #include #include #include #include "input/input_internal.h" +#include "libvlc_internal.h" + +/* + * Release the associated input thread + * + * Object lock is NOT held. + */ +static void release_input_thread( libvlc_media_instance_t *p_mi ) +{ + input_thread_t *p_input_thread; + vlc_bool_t should_destroy; + + if( !p_mi || p_mi->i_input_id == -1 ) + return; + + p_input_thread = (input_thread_t*)vlc_object_get( + p_mi->p_libvlc_instance->p_libvlc_int, + p_mi->i_input_id ); + + p_mi->i_input_id = -1; + + if( !p_input_thread ) + return; + + /* release for previous vlc_object_get */ + vlc_object_release( p_input_thread ); + + should_destroy = p_input_thread->i_refcount == 1; + + /* release for initial p_input_thread yield (see _new()) */ + vlc_object_release( p_input_thread ); + + /* No one is tracking this input_thread appart us. Destroy it */ + if( should_destroy ) + { + /* We owned this one */ + input_StopThread( p_input_thread ); + var_Destroy( p_input_thread, "drawable" ); + input_DestroyThread( p_input_thread ); + } + else + { + /* XXX: hack the playlist doesn't retain the input thread, + * so we did it for the playlist (see _new_from_input_thread), + * revert that here. */ + vlc_object_release( p_input_thread ); + } +} /* * Retrieve the input thread. Be sure to release the object * once you are done with it. (libvlc Internal) + * + * Object lock is held. */ input_thread_t *libvlc_get_input_thread( libvlc_media_instance_t *p_mi, - libvlc_exception_t *p_e ) + libvlc_exception_t *p_e ) { input_thread_t *p_input_thread; + vlc_mutex_lock( &p_mi->object_lock ); + if( !p_mi || p_mi->i_input_id == -1 ) + { + vlc_mutex_unlock( &p_mi->object_lock ); RAISENULL( "Input is NULL" ); + } p_input_thread = (input_thread_t*)vlc_object_get( p_mi->p_libvlc_instance->p_libvlc_int, p_mi->i_input_id ); if( !p_input_thread ) + { + vlc_mutex_unlock( &p_mi->object_lock ); RAISENULL( "Input does not exist" ); + } + vlc_mutex_unlock( &p_mi->object_lock ); return p_input_thread; } +/* + * input_state_changed (Private) (input var "state" Callback) + */ +static int +input_state_changed( vlc_object_t * p_this, char const * psz_cmd, + vlc_value_t oldval, vlc_value_t newval, + void * p_userdata ) +{ + libvlc_media_instance_t * p_mi = p_userdata; + libvlc_event_t event; + + if( newval.i_int == oldval.i_int ) + return VLC_SUCCESS; /* No change since last time, don't propagate */ + + switch ( newval.i_int ) + { + case END_S: + event.type = libvlc_MediaInstanceReachedEnd; + break; + case PAUSE_S: + event.type = libvlc_MediaInstancePaused; + break; + case PLAYING_S: + event.type = libvlc_MediaInstancePlayed; + break; + default: + return VLC_SUCCESS; + } + + libvlc_event_send( p_mi->p_event_manager, &event ); + return VLC_SUCCESS; +} + +/* + * input_position_changed (Private) (input var "intf-change" Callback) + */ +static int +input_position_changed( vlc_object_t * p_this, char const * psz_cmd, + vlc_value_t oldval, vlc_value_t newval, + void * p_userdata ) +{ + libvlc_media_instance_t * p_mi = p_userdata; + vlc_value_t val; + + if (!strcmp(psz_cmd, "intf" /* "-change" no need to go further */)) + { + input_thread_t * p_input = (input_thread_t *)p_this; + var_Get( p_input, "position", &val ); + + if ((val.i_time % I64C(500000)) != 0) + return VLC_SUCCESS; /* No need to have a better precision */ + var_Get( p_input, "state", &val ); + + if( val.i_int != PLAYING_S ) + return VLC_SUCCESS; /* Don't send the position while stopped */ + } + else + val.i_time = newval.i_time; + + libvlc_event_t event; + event.type = libvlc_MediaInstancePositionChanged; + event.u.media_instance_position_changed.new_position = val.i_time; + + libvlc_event_send( p_mi->p_event_manager, &event ); + return VLC_SUCCESS; +} + /************************************************************************** * Create a Media Instance object **************************************************************************/ libvlc_media_instance_t * -libvlc_media_instance_new( libvlc_media_descriptor_t *p_md ) +libvlc_media_instance_new( libvlc_instance_t * p_libvlc_instance, + libvlc_exception_t * p_e ) { libvlc_media_instance_t * p_mi; - if( !p_md ) + if( !p_libvlc_instance ) + { + libvlc_exception_raise( p_e, "invalid libvlc instance" ); return NULL; + } p_mi = malloc( sizeof(libvlc_media_instance_t) ); - p_mi->p_md = libvlc_media_descriptor_duplicate( p_md ); - p_mi->p_libvlc_instance = p_mi->p_md->p_libvlc_instance; + p_mi->p_md = NULL; + p_mi->drawable = 0; + p_mi->p_libvlc_instance = p_libvlc_instance; p_mi->i_input_id = -1; + /* refcount strategy: + * - All items created by _new start with a refcount set to 1 + * - Accessor _release decrease the refcount by 1, if after that + * operation the refcount is 0, the object is destroyed. + * - Accessor _retain increase the refcount by 1 (XXX: to implement) */ + p_mi->i_refcount = 1; + /* object_lock strategy: + * - No lock held in constructor + * - Lock when accessing all variable this lock is held + * - Lock when attempting to destroy the object the lock is also held */ + vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int, + &p_mi->object_lock ); + p_mi->p_event_manager = libvlc_event_manager_new( p_mi, + p_libvlc_instance, p_e ); + if( libvlc_exception_raised( p_e ) ) + { + free( p_mi ); + return NULL; + } + + libvlc_event_manager_register_event_type( p_mi->p_event_manager, + libvlc_MediaInstanceReachedEnd, p_e ); + + return p_mi; +} + +/************************************************************************** + * Create a Media Instance object with a media descriptor + **************************************************************************/ +libvlc_media_instance_t * +libvlc_media_instance_new_from_media_descriptor( + libvlc_media_descriptor_t * p_md, + libvlc_exception_t *p_e ) +{ + libvlc_media_instance_t * p_mi; + p_mi = libvlc_media_instance_new( p_md->p_libvlc_instance, p_e ); + + if( !p_mi ) + return NULL; + + libvlc_media_descriptor_retain( p_md ); + p_mi->p_md = p_md; return p_mi; } @@ -72,32 +244,54 @@ libvlc_media_instance_new( libvlc_media_descriptor_t *p_md ) **************************************************************************/ libvlc_media_instance_t * libvlc_media_instance_new_from_input_thread( struct libvlc_instance_t *p_libvlc_instance, - input_thread_t *p_input ) + input_thread_t *p_input, + libvlc_exception_t *p_e ) { libvlc_media_instance_t * p_mi; - p_mi = malloc( sizeof(libvlc_media_instance_t) ); + if( !p_input ) + { + libvlc_exception_raise( p_e, "invalid input thread" ); + return NULL; + } + + p_mi = libvlc_media_instance_new( p_libvlc_instance, p_e ); + + if( !p_mi ) + return NULL; + p_mi->p_md = libvlc_media_descriptor_new_from_input_item( p_libvlc_instance, - p_input->p->input.p_item ); - p_mi->p_libvlc_instance = p_libvlc_instance; - p_mi->i_input_id = p_input->i_object_id; + p_input->p->input.p_item, p_e ); + + if( !p_mi->p_md ) + { + libvlc_media_instance_destroy( p_mi ); + return NULL; + } + p_mi->i_input_id = p_input->i_object_id; + /* will be released in media_instance_release() */ - vlc_object_retain( p_input ); + vlc_object_yield( p_input ); + + /* XXX: Hack as the playlist doesn't yield the input thread we retain + * the input for the playlist. (see corresponding hack in _release) */ + vlc_object_yield( p_input ); return p_mi; } /************************************************************************** - * Destroy a Media Instance object + * Destroy a Media Instance object (libvlc internal) + * + * Warning: No lock held here, but hey, this is internal. **************************************************************************/ void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi ) { input_thread_t *p_input_thread; libvlc_exception_t p_e; - /* XXX: locking */ libvlc_exception_init( &p_e ); if( !p_mi ) @@ -106,11 +300,16 @@ void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi ) p_input_thread = libvlc_get_input_thread( p_mi, &p_e ); if( libvlc_exception_raised( &p_e ) ) + { + libvlc_event_manager_release( p_mi->p_event_manager ); + free( p_mi ); return; /* no need to worry about no input thread */ - + } + vlc_mutex_destroy( &p_mi->object_lock ); + input_DestroyThread( p_input_thread ); - libvlc_media_descriptor_destroy( p_mi->p_md ); + libvlc_media_descriptor_release( p_mi->p_md ); free( p_mi ); } @@ -120,34 +319,104 @@ void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi ) **************************************************************************/ void libvlc_media_instance_release( libvlc_media_instance_t *p_mi ) { - input_thread_t *p_input_thread; - libvlc_exception_t p_e; + if( !p_mi ) + return; - /* XXX: locking */ - libvlc_exception_init( &p_e ); + vlc_mutex_lock( &p_mi->object_lock ); + + p_mi->i_refcount--; + + if( p_mi->i_refcount > 0 ) + { + vlc_mutex_unlock( &p_mi->object_lock ); + return; + } + vlc_mutex_unlock( &p_mi->object_lock ); + vlc_mutex_destroy( &p_mi->object_lock ); + libvlc_event_manager_release( p_mi->p_event_manager ); + + release_input_thread( p_mi ); + + libvlc_media_descriptor_release( p_mi->p_md ); + + free( p_mi ); +} + +/************************************************************************** + * Retain a Media Instance object + **************************************************************************/ +void libvlc_media_instance_retain( libvlc_media_instance_t *p_mi ) +{ if( !p_mi ) return; - p_input_thread = libvlc_get_input_thread( p_mi, &p_e ); + p_mi->i_refcount++; +} +/************************************************************************** + * Set the Media descriptor associated with the instance + **************************************************************************/ +void libvlc_media_instance_set_media_descriptor( + libvlc_media_instance_t *p_mi, + libvlc_media_descriptor_t *p_md, + libvlc_exception_t *p_e ) +{ + (void)p_e; - if( !libvlc_exception_raised( &p_e ) ) - { - /* release for previous libvlc_get_input_thread */ - vlc_object_release( p_input_thread ); + if( !p_mi ) + return; - /* release for initial p_input_thread yield (see _new()) */ - vlc_object_release( p_input_thread ); + vlc_mutex_lock( &p_mi->object_lock ); + + release_input_thread( p_mi ); + + libvlc_media_descriptor_release( p_mi->p_md ); - /* No one is tracking this input_thread appart us. Destroy it */ - if( p_input_thread->i_refcount <= 0 ) - input_DestroyThread( p_input_thread ); - /* btw, we still have an XXX locking here */ + if( !p_md ) + { + p_mi->p_md = NULL; + vlc_mutex_unlock( &p_mi->object_lock ); + return; /* It is ok to pass a NULL md */ } - libvlc_media_descriptor_destroy( p_mi->p_md ); + libvlc_media_descriptor_retain( p_md ); + p_mi->p_md = p_md; + + /* The policy here is to ignore that we were created using a different + * libvlc_instance, because we don't really care */ + p_mi->p_libvlc_instance = p_md->p_libvlc_instance; - free( p_mi ); + vlc_mutex_unlock( &p_mi->object_lock ); +} + +/************************************************************************** + * Get the Media descriptor associated with the instance + **************************************************************************/ +libvlc_media_descriptor_t * +libvlc_media_instance_get_media_descriptor( + libvlc_media_instance_t *p_mi, + libvlc_exception_t *p_e ) +{ + (void)p_e; + + if( !p_mi->p_md ) + return NULL; + + libvlc_media_descriptor_retain( p_mi->p_md ); + return p_mi->p_md; +} + +/************************************************************************** + * Get the event Manager + **************************************************************************/ +libvlc_event_manager_t * +libvlc_media_instance_event_manager( + libvlc_media_instance_t *p_mi, + libvlc_exception_t *p_e ) +{ + (void)p_e; + + return p_mi->p_event_manager; } /************************************************************************** @@ -158,28 +427,47 @@ void libvlc_media_instance_play( libvlc_media_instance_t *p_mi, { input_thread_t * p_input_thread; - if( p_mi->i_input_id != -1) + if( (p_input_thread = libvlc_get_input_thread( p_mi, p_e )) ) { + /* A thread alread exists, send it a play message */ vlc_value_t val; val.i_int = PLAYING_S; - /* A thread alread exists, send it a play message */ - p_input_thread = libvlc_get_input_thread( p_mi, p_e ); - - if( libvlc_exception_raised( p_e ) ) - return; - input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, PLAYING_S ); vlc_object_release( p_input_thread ); return; } + /* Ignore previous exception */ + libvlc_exception_clear( p_e ); + + vlc_mutex_lock( &p_mi->object_lock ); + + if( !p_mi->p_md ) + { + libvlc_exception_raise( p_e, "no associated media descriptor" ); + vlc_mutex_unlock( &p_mi->object_lock ); + return; + } + p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int, p_mi->p_md->p_input_item ); p_mi->i_input_id = p_input_thread->i_object_id; + if( p_mi->drawable ) + { + vlc_value_t val; + val.i_int = p_mi->drawable; + var_Create( p_input_thread, "drawable", VLC_VAR_DOINHERIT ); + var_Set( p_input_thread, "drawable", val ); + } + var_AddCallback( p_input_thread, "state", input_state_changed, p_mi ); + var_AddCallback( p_input_thread, "intf-change", input_position_changed, p_mi ); + /* will be released in media_instance_release() */ vlc_object_yield( p_input_thread ); + + vlc_mutex_unlock( &p_mi->object_lock ); } /************************************************************************** @@ -194,13 +482,32 @@ void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi, p_input_thread = libvlc_get_input_thread( p_mi, p_e ); - if( libvlc_exception_raised( p_e ) ) + if( !p_input_thread ) return; input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, val ); vlc_object_release( p_input_thread ); } +/************************************************************************** + * Stop + **************************************************************************/ +void libvlc_media_instance_stop( libvlc_media_instance_t *p_mi, + libvlc_exception_t *p_e ) +{ + //libvlc_exception_raise( p_e, "Not implemented" ); +} + +/************************************************************************** + * Set Drawable + **************************************************************************/ +void libvlc_media_instance_set_drawable( libvlc_media_instance_t *p_mi, + libvlc_drawable_t drawable, + libvlc_exception_t *p_e ) +{ + p_mi->drawable = drawable; +} + /************************************************************************** * Getters for stream information **************************************************************************/ @@ -257,7 +564,7 @@ void libvlc_media_instance_set_time( void libvlc_media_instance_set_position( libvlc_media_instance_t *p_mi, float position, - libvlc_exception_t *p_e ) + libvlc_exception_t *p_e ) { input_thread_t *p_input_thread; vlc_value_t val; @@ -290,7 +597,7 @@ float libvlc_media_instance_get_position( float libvlc_media_instance_get_fps( libvlc_media_instance_t *p_mi, - libvlc_exception_t *p_e) + libvlc_exception_t *p_e) { double f_fps = 0.0; input_thread_t *p_input_thread; @@ -315,14 +622,14 @@ float libvlc_media_instance_get_fps( vlc_bool_t libvlc_media_instance_will_play( libvlc_media_instance_t *p_mi, - libvlc_exception_t *p_e) + libvlc_exception_t *p_e) { input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e); if ( !p_input_thread ) return VLC_FALSE; - if ( !p_input_thread->b_die && !p_input_thread->b_dead ) + if ( !p_input_thread->b_die && !p_input_thread->b_dead ) { vlc_object_release( p_input_thread ); return VLC_TRUE; @@ -334,7 +641,7 @@ vlc_bool_t libvlc_media_instance_will_play( void libvlc_media_instance_set_rate( libvlc_media_instance_t *p_mi, float rate, - libvlc_exception_t *p_e ) + libvlc_exception_t *p_e ) { input_thread_t *p_input_thread; vlc_value_t val; @@ -385,4 +692,3 @@ int libvlc_media_instance_get_state( return val.i_int; } -