]> git.sesse.net Git - vlc/blobdiff - src/control/media_player.c
Simplify libvlc_media_player_is_playing(). Should really be inline.
[vlc] / src / control / media_player.c
index 31589b3172710542fc8e1d67d5d75d2d92d53973..4b63d1baf78643b2a5d50ec293a58bfa68b98a95 100644 (file)
@@ -65,11 +65,11 @@ static inline libvlc_state_t vlc_to_libvlc_state( int vlc_state )
 }
 
 /*
- * Release the associated input thread
+ * Release the associated input thread.
  *
  * Object lock is NOT held.
  */
-static void release_input_thread( libvlc_media_player_t *p_mi )
+static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abort )
 {
     input_thread_t * p_input_thread;
 
@@ -78,19 +78,23 @@ static void release_input_thread( libvlc_media_player_t *p_mi )
 
     p_input_thread = p_mi->p_input_thread;
 
-    /* No one is tracking this input_thread appart us. Destroy it */
+    /* No one is tracking this input_thread apart from us. Destroy it. */
     if( p_mi->b_own_its_input_thread )
     {
-        var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
-        var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
-        var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
+        var_DelCallback( p_input_thread, "can-seek",
+                         input_seekable_changed, p_mi );
+        var_DelCallback( p_input_thread, "can-pause",
+                         input_pausable_changed, p_mi );
+        var_DelCallback( p_input_thread, "intf-event",
+                         input_event_changed, p_mi );
 
         /* We owned this one */
-        input_StopThread( p_input_thread );
+        input_StopThread( p_input_thread, b_input_abort );
         vlc_thread_join( p_input_thread );
 
         var_Destroy( p_input_thread, "drawable-hwnd" );
         var_Destroy( p_input_thread, "drawable-xid" );
+        var_Destroy( p_input_thread, "drawable-agl" );
     }
 
     vlc_object_release( p_input_thread );
@@ -102,7 +106,7 @@ static void release_input_thread( libvlc_media_player_t *p_mi )
  * Retrieve the input thread. Be sure to release the object
  * once you are done with it. (libvlc Internal)
  *
- * Object lock is held.
+ * Function will lock the object.
  */
 input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi,
                                          libvlc_exception_t *p_e )
@@ -212,7 +216,7 @@ input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
                 return VLC_SUCCESS;
         }
 
-        libvlc_media_set_state( p_mi->p_md, libvlc_state, NULL);
+        libvlc_media_set_state( p_mi->p_md, libvlc_state, NULL );
         libvlc_event_send( p_mi->p_event_manager, &event );
     }
     else if( newval.i_int == INPUT_EVENT_TIMES )
@@ -222,12 +226,14 @@ input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
 
         /* */
         event.type = libvlc_MediaPlayerPositionChanged;
-        event.u.media_player_position_changed.new_position = var_GetFloat( p_input, "position" );;
+        event.u.media_player_position_changed.new_position =
+                                          var_GetFloat( p_input, "position" );
         libvlc_event_send( p_mi->p_event_manager, &event );
 
         /* */
         event.type = libvlc_MediaPlayerTimeChanged;
-        event.u.media_player_time_changed.new_time = var_GetTime( p_input, "time" );
+        event.u.media_player_time_changed.new_time =
+                                               var_GetTime( p_input, "time" );
         libvlc_event_send( p_mi->p_event_manager, &event );
     }
 
@@ -237,7 +243,18 @@ input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
 
 
 /**************************************************************************
- * Create a Media Instance object
+ * Create a Media Instance object.
+ *
+ * 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)
+ *
+ * Object locking strategy:
+ * - No lock held while in constructor.
+ * - When accessing any member variable this lock is held. (XXX who locks?)
+ * - When attempting to destroy the object the lock is also held.
  **************************************************************************/
 libvlc_media_player_t *
 libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
@@ -258,21 +275,13 @@ libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
         return NULL;
     }
     p_mi->p_md = NULL;
+    p_mi->drawable.agl = 0;
     p_mi->drawable.xid = 0;
     p_mi->drawable.hwnd = NULL;
     p_mi->p_libvlc_instance = p_libvlc_instance;
     p_mi->p_input_thread = NULL;
-    /* 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;
     p_mi->b_own_its_input_thread = true;
-    /* 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->object_lock );
     p_mi->p_event_manager = libvlc_event_manager_new( p_mi,
             p_libvlc_instance, p_e );
@@ -321,14 +330,16 @@ libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
         vout_thread that generates the event and media_player that re-emits it
         with its own event manager
     */
-    var_Create( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
-    var_AddCallback( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken", SnapshotTakenCallback, p_mi );
+    var_Create( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken",
+                VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
+    var_AddCallback( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken",
+                     SnapshotTakenCallback, p_mi );
 
     return p_mi;
 }
 
 /**************************************************************************
- * Create a Media Instance object with a media descriptor
+ * Create a Media Instance object with a media descriptor.
  **************************************************************************/
 libvlc_media_player_t *
 libvlc_media_player_new_from_media(
@@ -348,7 +359,7 @@ libvlc_media_player_new_from_media(
 }
 
 /**************************************************************************
- * Create a new media instance object from an input_thread (Libvlc Internal)
+ * Create a new media instance object from an input_thread (Libvlc Internal).
  **************************************************************************/
 libvlc_media_player_t * libvlc_media_player_new_from_input_thread(
                                    struct libvlc_instance_t *p_libvlc_instance,
@@ -390,7 +401,7 @@ libvlc_media_player_t * libvlc_media_player_new_from_input_thread(
 /**************************************************************************
  * Destroy a Media Instance object (libvlc internal)
  *
- * Warning: No lock held here, but hey, this is internal.
+ * Warning: No lock held here, but hey, this is internal. Caller must lock.
  **************************************************************************/
 void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
 {
@@ -403,7 +414,8 @@ void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
         return;
 
        /* Detach Callback from the main libvlc object */
-    var_DelCallback( p_mi->p_libvlc_instance->p_libvlc_int, "vout-snapshottaken", SnapshotTakenCallback, p_mi );
+    var_DelCallback( p_mi->p_libvlc_instance->p_libvlc_int,
+                     "vout-snapshottaken", SnapshotTakenCallback, p_mi );
 
     p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
 
@@ -424,7 +436,9 @@ void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
 }
 
 /**************************************************************************
- * Release a Media Instance object
+ * Release a Media Instance object.
+ *
+ * Function does the locking.
  **************************************************************************/
 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
 {
@@ -443,7 +457,7 @@ void libvlc_media_player_release( libvlc_media_player_t *p_mi )
     vlc_mutex_unlock( &p_mi->object_lock );
     vlc_mutex_destroy( &p_mi->object_lock );
 
-    release_input_thread( p_mi );
+    release_input_thread( p_mi, true );
 
     libvlc_event_manager_release( p_mi->p_event_manager );
 
@@ -453,7 +467,9 @@ void libvlc_media_player_release( libvlc_media_player_t *p_mi )
 }
 
 /**************************************************************************
- * Retain a Media Instance object
+ * Retain a Media Instance object.
+ *
+ * Caller must hold the lock.
  **************************************************************************/
 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
 {
@@ -464,7 +480,9 @@ void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
 }
 
 /**************************************************************************
- * Set the Media descriptor associated with the instance
+ * Set the Media descriptor associated with the instance.
+ *
+ * Enter without lock -- function will lock the object.
  **************************************************************************/
 void libvlc_media_player_set_media(
                             libvlc_media_player_t *p_mi,
@@ -478,7 +496,12 @@ void libvlc_media_player_set_media(
 
     vlc_mutex_lock( &p_mi->object_lock );
 
-    release_input_thread( p_mi );
+    /* FIXME I am not sure if it is a user request or on die(eof/error)
+     * request here */
+    release_input_thread( p_mi,
+                          p_mi->p_input_thread &&
+                          !p_mi->p_input_thread->b_eof &&
+                          !p_mi->p_input_thread->b_error );
 
     if( p_mi->p_md )
         libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, p_e );
@@ -503,7 +526,7 @@ void libvlc_media_player_set_media(
 }
 
 /**************************************************************************
- * Get the Media descriptor associated with the instance
+ * Get the Media descriptor associated with the instance.
  **************************************************************************/
 libvlc_media_t *
 libvlc_media_player_get_media(
@@ -520,7 +543,7 @@ libvlc_media_player_get_media(
 }
 
 /**************************************************************************
- * Get the event Manager
+ * Get the event Manager.
  **************************************************************************/
 libvlc_event_manager_t *
 libvlc_media_player_event_manager(
@@ -533,7 +556,7 @@ libvlc_media_player_event_manager(
 }
 
 /**************************************************************************
- * Trigger a snapshot Taken Event
+ * Trigger a snapshot Taken Event.
  *************************************************************************/
 static int SnapshotTakenCallback( vlc_object_t *p_this, char const *psz_cmd,
                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
@@ -547,15 +570,16 @@ static int SnapshotTakenCallback( vlc_object_t *p_this, char const *psz_cmd,
     event.u.media_player_snapshot_taken.psz_filename = newval.psz_string ;
     /* Snapshot psz data is a vlc_variable owned by libvlc object .
          Its memmory management is taken care by the obj*/
-    msg_Dbg( p_this, "about to emit libvlc_snapshot_taken.make psz_str=0x%p (%s)",
-          event.u.media_player_snapshot_taken.psz_filename ,event.u.media_player_snapshot_taken.psz_filename );
+    msg_Dbg( p_this, "about to emit libvlc_snapshot_taken.make psz_str=0x%p"
+             " (%s)", event.u.media_player_snapshot_taken.psz_filename,
+             event.u.media_player_snapshot_taken.psz_filename );
     libvlc_event_send( p_mi->p_event_manager, &event );
 
     return VLC_SUCCESS;
 }
 
 /**************************************************************************
- * Play
+ * Tell media player to start playing.
  **************************************************************************/
 void libvlc_media_player_play( libvlc_media_player_t *p_mi,
                                  libvlc_exception_t *p_e )
@@ -582,9 +606,8 @@ void libvlc_media_player_play( libvlc_media_player_t *p_mi,
         return;
     }
 
-    p_mi->p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
-                      p_mi->p_md->p_input_item );
-
+    p_mi->p_input_thread = input_CreateThread(
+            p_mi->p_libvlc_instance->p_libvlc_int, p_mi->p_md->p_input_item );
 
     if( !p_mi->p_input_thread )
     {
@@ -594,6 +617,10 @@ void libvlc_media_player_play( libvlc_media_player_t *p_mi,
 
     p_input_thread = p_mi->p_input_thread;
 
+    var_Create( p_input_thread, "drawable-agl", VLC_VAR_INTEGER );
+    if( p_mi->drawable.agl )
+        var_SetInteger( p_input_thread, "drawable-agl", p_mi->drawable.agl );
+
     var_Create( p_input_thread, "drawable-xid", VLC_VAR_INTEGER );
     if( p_mi->drawable.xid )
         var_SetInteger( p_input_thread, "drawable-xid", p_mi->drawable.xid );
@@ -613,7 +640,7 @@ void libvlc_media_player_play( libvlc_media_player_t *p_mi,
 }
 
 /**************************************************************************
- * Pause
+ * Pause.
  **************************************************************************/
 void libvlc_media_player_pause( libvlc_media_player_t *p_mi,
                                   libvlc_exception_t *p_e )
@@ -639,30 +666,20 @@ void libvlc_media_player_pause( libvlc_media_player_t *p_mi,
 }
 
 /**************************************************************************
- * is_playing
+ * Tells whether the media player is currently playing.
+ *
+ * Enter with lock held.
  **************************************************************************/
 int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi,
                                      libvlc_exception_t *p_e )
 {
-    input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
-
-    if( !p_input_thread )
-        return 0;
-
     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
-
-    vlc_object_release( p_input_thread );
-    
-    if( state == libvlc_Playing )
-    {
-        return 1;
-    }
-    return 0;
+    return libvlc_Playing == state;
 }
 
 
 /**************************************************************************
- * Stop
+ * Stop playing.
  **************************************************************************/
 void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
                                  libvlc_exception_t *p_e )
@@ -671,7 +688,8 @@ void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
 
     if( state == libvlc_Playing || state == libvlc_Paused )
     {
-        /* Send a stop notification event only of we are in playing or paused states */
+        /* Send a stop notification event only if we are in playing or
+         * paused states */
         libvlc_media_set_state( p_mi->p_md, libvlc_Ended, p_e );
 
         /* Construct and send the event */
@@ -683,7 +701,7 @@ void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
     if( p_mi->b_own_its_input_thread )
     {
         vlc_mutex_lock( &p_mi->object_lock );
-        release_input_thread( p_mi ); /* This will stop the input thread */
+        release_input_thread( p_mi, true ); /* This will stop the input thread */
         vlc_mutex_unlock( &p_mi->object_lock );
     }
     else
@@ -693,19 +711,53 @@ void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
         if( !p_input_thread )
             return;
 
-        input_StopThread( p_input_thread );
+        input_StopThread( p_input_thread, true );
         vlc_object_release( p_input_thread );
+        p_mi->p_input_thread = NULL;
     }
 }
 
-void libvlc_media_player_set_xid( libvlc_media_player_t *p_mi,
-                                  uint32_t drawable,
-                                  libvlc_exception_t *p_e )
+/**************************************************************************
+ * set_agl
+ **************************************************************************/
+void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
+                                      uint32_t drawable,
+                                      libvlc_exception_t *p_e )
+{
+    (void) p_e;
+    p_mi->drawable.agl = drawable;
+}
+
+/**************************************************************************
+ * get_agl
+ **************************************************************************/
+uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
+{
+    return p_mi->drawable.agl;
+}
+
+/**************************************************************************
+ * set_xwindow
+ **************************************************************************/
+void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
+                                      uint32_t drawable,
+                                      libvlc_exception_t *p_e )
 {
     (void) p_e;
     p_mi->drawable.xid = drawable;
 }
 
+/**************************************************************************
+ * get_xwindow
+ **************************************************************************/
+uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
+{
+    return p_mi->drawable.xid;
+}
+
+/**************************************************************************
+ * set_hwnd
+ **************************************************************************/
 void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
                                    void *drawable,
                                    libvlc_exception_t *p_e )
@@ -714,6 +766,14 @@ void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
     p_mi->drawable.hwnd = drawable;
 }
 
+/**************************************************************************
+ * get_hwnd
+ **************************************************************************/
+void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
+{
+    return p_mi->drawable.hwnd;
+}
+
 /**************************************************************************
  * Set Drawable
  **************************************************************************/
@@ -721,39 +781,37 @@ void libvlc_media_player_set_drawable( libvlc_media_player_t *p_mi,
                                        libvlc_drawable_t drawable,
                                        libvlc_exception_t *p_e )
 {
-    input_thread_t *p_input_thread;
-    vout_thread_t *p_vout = NULL;
-
+#ifdef WIN32
+    if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
+        p_mi->drawable.hwnd = (HWND)drawable;
+    else
+        libvlc_exception_raise(p_e, "Operation not supported");
+#elif defined(__APPLE__)
+    p_mi->drawable.agl = drawable;
+#else
     p_mi->drawable.xid = drawable;
-
-    /* Allow on the fly drawable changing. This is tricky has this may
-     * not be supported by every vout. We though can't disable it
-     * because of some creepy drawable type that are not flexible enough
-     * (Win32 HWND for instance) */
-    p_input_thread = libvlc_get_input_thread( p_mi, p_e );
-    if( !p_input_thread ) {
-        /* No input, nothing more to do, we are fine */
-        libvlc_exception_clear( p_e );
-        return;
-    }
-
-    p_vout = vlc_object_find( p_input_thread, VLC_OBJECT_VOUT, FIND_CHILD );
-    if( p_vout )
-    {
-        vout_Control( p_vout , VOUT_REPARENT, drawable);
-        vlc_object_release( p_vout );
-    }
-    vlc_object_release( p_input_thread );
+#endif
 }
 
 /**************************************************************************
  * Get Drawable
  **************************************************************************/
 libvlc_drawable_t
-libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi, libvlc_exception_t *p_e )
+libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi,
+                                   libvlc_exception_t *p_e )
 {
     VLC_UNUSED(p_e);
+
+#ifdef WIN32
+    if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
+        return (libvlc_drawable_t)p_mi->drawable.hwnd;
+    else
+        return 0;
+#elif defined(__APPLE__)
+    return p_mi->drawable.agl;
+#else
     return p_mi->drawable.xid;
+#endif
 }
 
 /**************************************************************************
@@ -1056,15 +1114,12 @@ void libvlc_media_player_set_rate(
     vlc_value_t val;
     bool b_can_rewind;
 
-    if( rate != 0 )
-        RAISEVOID( "Rate value is invalid" );
-
-    p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
+    p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
     if( !p_input_thread )
         return;
 
     b_can_rewind = var_GetBool( p_input_thread, "can-rewind" );
-    if( (rate < 0) && !b_can_rewind )
+    if( (rate < 0.0) && !b_can_rewind )
     {
         vlc_object_release( p_input_thread );
         libvlc_exception_raise( p_e, "Rate value is invalid" );
@@ -1105,21 +1160,30 @@ libvlc_state_t libvlc_media_player_get_state(
                                  libvlc_exception_t *p_e )
 {
     input_thread_t *p_input_thread;
+    libvlc_state_t state = libvlc_Ended;
     vlc_value_t val;
 
     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
-    if ( !p_input_thread )
+    if( !p_input_thread )
     {
         /* We do return the right value, no need to throw an exception */
         if( libvlc_exception_raised( p_e ) )
             libvlc_exception_clear( p_e );
-        return libvlc_Ended;
+        return state;
     }
 
     var_Get( p_input_thread, "state", &val );
-    vlc_object_release( p_input_thread );
+    state = vlc_to_libvlc_state(val.i_int);
 
-    return vlc_to_libvlc_state(val.i_int);
+    if( state == libvlc_Playing )
+    {
+        float caching;
+        caching = var_GetFloat( p_input_thread, "cache" );
+        if( caching > 0.0 && caching < 1.0 )
+            state = libvlc_Buffering;
+    }
+    vlc_object_release( p_input_thread );
+    return state;
 }
 
 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi,
@@ -1164,7 +1228,8 @@ libvlc_track_description_t *
         malloc( sizeof( libvlc_track_description_t ) );
     if ( !p_track_description )
     {
-        var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list);
+        var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
+                    &val_list, &text_list);
         vlc_object_release( p_input );
         libvlc_exception_raise( p_e, "no enough memory" );
         return NULL;
@@ -1180,7 +1245,8 @@ libvlc_track_description_t *
             if ( !p_actual )
             {
                 libvlc_track_description_release( p_track_description );
-                var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list);
+                var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
+                            &val_list, &text_list);
                 vlc_object_release( p_input );
                 libvlc_exception_raise( p_e, "no enough memory" );
                 return NULL;
@@ -1200,10 +1266,10 @@ libvlc_track_description_t *
     return p_track_description;
 }
 
-void libvlc_track_description_release( libvlc_track_description_t *p_track_description )
+void libvlc_track_description_release( libvlc_track_description_t *p_td )
 {
     libvlc_track_description_t *p_actual, *p_before;
-    p_actual = p_track_description;
+    p_actual = p_td;
 
     while ( p_actual )
     {