media_player.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:43k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * media_player.c: Libvlc API Media Instance management functions
  3.  *****************************************************************************
  4.  * Copyright (C) 2005-2009 the VideoLAN team
  5.  * $Id: f69f621ceba3d14024633b152d32039aede79102 $
  6.  *
  7.  * Authors: Clément Stenac <zorglub@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. #ifdef HAVE_CONFIG_H
  24. # include <config.h>
  25. #endif
  26. #include <assert.h>
  27. #include <vlc/libvlc.h>
  28. #include <vlc/libvlc_media.h>
  29. #include <vlc/libvlc_events.h>
  30. #include <vlc_demux.h>
  31. #include <vlc_input.h>
  32. #include <vlc_vout.h>
  33. #include "libvlc.h"
  34. #include "libvlc_internal.h"
  35. #include "media_internal.h" // libvlc_media_set_state()
  36. #include "media_player_internal.h"
  37. static int
  38. input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
  39.                         vlc_value_t oldval, vlc_value_t newval,
  40.                         void * p_userdata );
  41. static int
  42. input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
  43.                         vlc_value_t oldval, vlc_value_t newval,
  44.                         void * p_userdata );
  45. static int
  46. input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
  47.                      vlc_value_t oldval, vlc_value_t newval,
  48.                      void * p_userdata );
  49. static int SnapshotTakenCallback( vlc_object_t *p_this, char const *psz_cmd,
  50.                        vlc_value_t oldval, vlc_value_t newval, void *p_data );
  51. static const libvlc_state_t vlc_to_libvlc_state_array[] =
  52. {
  53.     [INIT_S]        = libvlc_NothingSpecial,
  54.     [OPENING_S]     = libvlc_Opening,
  55.     [PLAYING_S]     = libvlc_Playing,
  56.     [PAUSE_S]       = libvlc_Paused,
  57.     [END_S]         = libvlc_Ended,
  58.     [ERROR_S]       = libvlc_Error,
  59. };
  60. static inline libvlc_state_t vlc_to_libvlc_state( int vlc_state )
  61. {
  62.     if( vlc_state < 0 || vlc_state > 6 )
  63.         return libvlc_Ended;
  64.     return vlc_to_libvlc_state_array[vlc_state];
  65. }
  66. static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi );
  67. /*
  68.  * Release the associated input thread.
  69.  *
  70.  * Object lock is NOT held.
  71.  */
  72. static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abort )
  73. {
  74.     input_thread_t * p_input_thread;
  75.     if( !p_mi || !p_mi->p_input_thread )
  76.         return;
  77.     p_input_thread = p_mi->p_input_thread;
  78.     /* No one is tracking this input_thread apart from us. Destroy it. */
  79.     if( p_mi->b_own_its_input_thread )
  80.     {
  81.         var_DelCallback( p_input_thread, "can-seek",
  82.                          input_seekable_changed, p_mi );
  83.         var_DelCallback( p_input_thread, "can-pause",
  84.                          input_pausable_changed, p_mi );
  85.         var_DelCallback( p_input_thread, "intf-event",
  86.                          input_event_changed, p_mi );
  87.         /* We owned this one */
  88.         input_Stop( p_input_thread, b_input_abort );
  89.         vlc_thread_join( p_input_thread );
  90.         var_Destroy( p_input_thread, "drawable-hwnd" );
  91.         var_Destroy( p_input_thread, "drawable-xid" );
  92.         var_Destroy( p_input_thread, "drawable-agl" );
  93.     }
  94.     vlc_object_release( p_input_thread );
  95.     p_mi->p_input_thread = NULL;
  96. }
  97. /*
  98.  * Retrieve the input thread. Be sure to release the object
  99.  * once you are done with it. (libvlc Internal)
  100.  *
  101.  * Function will lock the object.
  102.  */
  103. input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi,
  104.                                          libvlc_exception_t *p_e )
  105. {
  106.     input_thread_t *p_input_thread;
  107.     if( !p_mi ) RAISENULL( "Media Instance is NULL" );
  108.     vlc_mutex_lock( &p_mi->object_lock );
  109.     if( !p_mi->p_input_thread )
  110.     {
  111.         vlc_mutex_unlock( &p_mi->object_lock );
  112.         RAISENULL( "Input is NULL" );
  113.     }
  114.     p_input_thread = p_mi->p_input_thread;
  115.     vlc_object_hold( p_input_thread );
  116.     vlc_mutex_unlock( &p_mi->object_lock );
  117.     return p_input_thread;
  118. }
  119. static int
  120. input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
  121.                         vlc_value_t oldval, vlc_value_t newval,
  122.                         void * p_userdata )
  123. {
  124.     VLC_UNUSED(oldval);
  125.     VLC_UNUSED(p_this);
  126.     VLC_UNUSED(psz_cmd);
  127.     libvlc_media_player_t * p_mi = p_userdata;
  128.     libvlc_event_t event;
  129.     libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
  130.     event.type = libvlc_MediaPlayerSeekableChanged;
  131.     event.u.media_player_seekable_changed.new_seekable = newval.b_bool;
  132.     libvlc_event_send( p_mi->p_event_manager, &event );
  133.     return VLC_SUCCESS;
  134. }
  135. static int
  136. input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
  137.                         vlc_value_t oldval, vlc_value_t newval,
  138.                         void * p_userdata )
  139. {
  140.     VLC_UNUSED(oldval);
  141.     VLC_UNUSED(p_this);
  142.     VLC_UNUSED(psz_cmd);
  143.     libvlc_media_player_t * p_mi = p_userdata;
  144.     libvlc_event_t event;
  145.     libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
  146.     event.type = libvlc_MediaPlayerPausableChanged;
  147.     event.u.media_player_pausable_changed.new_pausable = newval.b_bool;
  148.     libvlc_event_send( p_mi->p_event_manager, &event );
  149.     return VLC_SUCCESS;
  150. }
  151. static int
  152. input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
  153.                      vlc_value_t oldval, vlc_value_t newval,
  154.                      void * p_userdata )
  155. {
  156.     VLC_UNUSED(oldval);
  157.     input_thread_t * p_input = (input_thread_t *)p_this;
  158.     libvlc_media_player_t * p_mi = p_userdata;
  159.     libvlc_event_t event;
  160.     assert( !strcmp( psz_cmd, "intf-event" ) );
  161.     if( newval.i_int == INPUT_EVENT_STATE )
  162.     {
  163.         libvlc_state_t libvlc_state;
  164.         switch ( var_GetInteger( p_input, "state" ) )
  165.         {
  166.             case INIT_S:
  167.                 libvlc_state = libvlc_NothingSpecial;
  168.                 event.type = libvlc_MediaPlayerNothingSpecial;
  169.                 break;
  170.             case OPENING_S:
  171.                 libvlc_state = libvlc_Opening;
  172.                 event.type = libvlc_MediaPlayerOpening;
  173.                 break;
  174.             case PLAYING_S:
  175.                 libvlc_state = libvlc_Playing;
  176.                 event.type = libvlc_MediaPlayerPlaying;
  177.                 break;
  178.             case PAUSE_S:
  179.                 libvlc_state = libvlc_Paused;
  180.                 event.type = libvlc_MediaPlayerPaused;
  181.                 break;
  182.             case END_S:
  183.                 libvlc_state = libvlc_Ended;
  184.                 event.type = libvlc_MediaPlayerEndReached;
  185.                 break;
  186.             case ERROR_S:
  187.                 libvlc_state = libvlc_Error;
  188.                 event.type = libvlc_MediaPlayerEncounteredError;
  189.                 break;
  190.             default:
  191.                 return VLC_SUCCESS;
  192.         }
  193.         libvlc_media_set_state( p_mi->p_md, libvlc_state, NULL );
  194.         libvlc_event_send( p_mi->p_event_manager, &event );
  195.     }
  196.     else if( newval.i_int == INPUT_EVENT_TIMES )
  197.     {
  198.         if( var_GetInteger( p_input, "state" ) != PLAYING_S )
  199.             return VLC_SUCCESS; /* Don't send the position while stopped */
  200.         /* */
  201.         event.type = libvlc_MediaPlayerPositionChanged;
  202.         event.u.media_player_position_changed.new_position =
  203.                                           var_GetFloat( p_input, "position" );
  204.         libvlc_event_send( p_mi->p_event_manager, &event );
  205.         /* */
  206.         event.type = libvlc_MediaPlayerTimeChanged;
  207.         event.u.media_player_time_changed.new_time =
  208.                                                var_GetTime( p_input, "time" );
  209.         libvlc_event_send( p_mi->p_event_manager, &event );
  210.     }
  211.     return VLC_SUCCESS;
  212. }
  213. /**************************************************************************
  214.  * Create a Media Instance object.
  215.  *
  216.  * Refcount strategy:
  217.  * - All items created by _new start with a refcount set to 1.
  218.  * - Accessor _release decrease the refcount by 1, if after that
  219.  *   operation the refcount is 0, the object is destroyed.
  220.  * - Accessor _retain increase the refcount by 1 (XXX: to implement)
  221.  *
  222.  * Object locking strategy:
  223.  * - No lock held while in constructor.
  224.  * - When accessing any member variable this lock is held. (XXX who locks?)
  225.  * - When attempting to destroy the object the lock is also held.
  226.  **************************************************************************/
  227. libvlc_media_player_t *
  228. libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
  229.                            libvlc_exception_t * p_e )
  230. {
  231.     libvlc_media_player_t * p_mi;
  232.     if( !p_libvlc_instance )
  233.     {
  234.         libvlc_exception_raise( p_e, "invalid libvlc instance" );
  235.         return NULL;
  236.     }
  237.     p_mi = malloc( sizeof(libvlc_media_player_t) );
  238.     if( !p_mi )
  239.     {
  240.         libvlc_exception_raise( p_e, "Not enough memory" );
  241.         return NULL;
  242.     }
  243.     p_mi->p_md = NULL;
  244.     p_mi->drawable.agl = 0;
  245.     p_mi->drawable.xid = 0;
  246.     p_mi->drawable.hwnd = NULL;
  247.     p_mi->drawable.nsobject = NULL;
  248.     p_mi->p_libvlc_instance = p_libvlc_instance;
  249.     p_mi->p_input_thread = NULL;
  250.     p_mi->i_refcount = 1;
  251.     p_mi->b_own_its_input_thread = true;
  252.     vlc_mutex_init( &p_mi->object_lock );
  253.     p_mi->p_event_manager = libvlc_event_manager_new( p_mi,
  254.             p_libvlc_instance, p_e );
  255.     if( libvlc_exception_raised( p_e ) )
  256.     {
  257.         vlc_mutex_destroy( &p_mi->object_lock );
  258.         free( p_mi );
  259.         return NULL;
  260.     }
  261.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  262.             libvlc_MediaPlayerNothingSpecial, p_e );
  263.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  264.             libvlc_MediaPlayerOpening, p_e );
  265.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  266.             libvlc_MediaPlayerBuffering, p_e );
  267.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  268.             libvlc_MediaPlayerPlaying, p_e );
  269.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  270.             libvlc_MediaPlayerPaused, p_e );
  271.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  272.             libvlc_MediaPlayerStopped, p_e );
  273.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  274.             libvlc_MediaPlayerForward, p_e );
  275.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  276.             libvlc_MediaPlayerBackward, p_e );
  277.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  278.             libvlc_MediaPlayerEndReached, p_e );
  279.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  280.             libvlc_MediaPlayerEncounteredError, p_e );
  281.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  282.             libvlc_MediaPlayerPositionChanged, p_e );
  283.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  284.             libvlc_MediaPlayerTimeChanged, p_e );
  285.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  286.             libvlc_MediaPlayerTitleChanged, p_e );
  287.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  288.             libvlc_MediaPlayerSeekableChanged, p_e );
  289.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  290.             libvlc_MediaPlayerPausableChanged, p_e );
  291.     /* Snapshot initialization */
  292.     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
  293.            libvlc_MediaPlayerSnapshotTaken, p_e );
  294.     /* Attach a var callback to the global object to provide the glue between
  295.         vout_thread that generates the event and media_player that re-emits it
  296.         with its own event manager
  297.     */
  298.     var_Create( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken",
  299.                 VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
  300.     var_AddCallback( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken",
  301.                      SnapshotTakenCallback, p_mi );
  302.     return p_mi;
  303. }
  304. /**************************************************************************
  305.  * Create a Media Instance object with a media descriptor.
  306.  **************************************************************************/
  307. libvlc_media_player_t *
  308. libvlc_media_player_new_from_media(
  309.                                     libvlc_media_t * p_md,
  310.                                     libvlc_exception_t *p_e )
  311. {
  312.     libvlc_media_player_t * p_mi;
  313.     p_mi = libvlc_media_player_new( p_md->p_libvlc_instance, p_e );
  314.     if( !p_mi )
  315.         return NULL;
  316.     libvlc_media_retain( p_md );
  317.     p_mi->p_md = p_md;
  318.     return p_mi;
  319. }
  320. /**************************************************************************
  321.  * Create a new media instance object from an input_thread (Libvlc Internal).
  322.  **************************************************************************/
  323. libvlc_media_player_t * libvlc_media_player_new_from_input_thread(
  324.                                    struct libvlc_instance_t *p_libvlc_instance,
  325.                                    input_thread_t *p_input,
  326.                                    libvlc_exception_t *p_e )
  327. {
  328.     libvlc_media_player_t * p_mi;
  329.     if( !p_input )
  330.     {
  331.         libvlc_exception_raise( p_e, "invalid input thread" );
  332.         return NULL;
  333.     }
  334.     p_mi = libvlc_media_player_new( p_libvlc_instance, p_e );
  335.     if( !p_mi )
  336.         return NULL;
  337.     p_mi->p_md = libvlc_media_new_from_input_item(
  338.                     p_libvlc_instance,
  339.                     input_GetItem( p_input ), p_e );
  340.     if( !p_mi->p_md )
  341.     {
  342.         libvlc_media_player_destroy( p_mi );
  343.         return NULL;
  344.     }
  345.     /* will be released in media_player_release() */
  346.     vlc_object_hold( p_input );
  347.     p_mi->p_input_thread = p_input;
  348.     p_mi->b_own_its_input_thread = false;
  349.     return p_mi;
  350. }
  351. /**************************************************************************
  352.  * Destroy a Media Instance object (libvlc internal)
  353.  *
  354.  * Warning: No lock held here, but hey, this is internal. Caller must lock.
  355.  **************************************************************************/
  356. static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
  357. {
  358.     input_thread_t *p_input_thread;
  359.     libvlc_exception_t p_e;
  360.     if( !p_mi )
  361.         return;
  362.     libvlc_exception_init( &p_e );
  363. /* Detach Callback from the main libvlc object */
  364.     var_DelCallback( p_mi->p_libvlc_instance->p_libvlc_int,
  365.                      "vout-snapshottaken", SnapshotTakenCallback, p_mi );
  366.     p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
  367.     if( libvlc_exception_raised( &p_e ) )
  368.     {
  369.         libvlc_event_manager_release( p_mi->p_event_manager );
  370.         libvlc_exception_clear( &p_e );
  371.         free( p_mi );
  372.         return; /* no need to worry about no input thread */
  373.     }
  374.     vlc_mutex_destroy( &p_mi->object_lock );
  375.     vlc_object_release( p_input_thread );
  376.     libvlc_media_release( p_mi->p_md );
  377.     free( p_mi );
  378. }
  379. /**************************************************************************
  380.  * Release a Media Instance object.
  381.  *
  382.  * Function does the locking.
  383.  **************************************************************************/
  384. void libvlc_media_player_release( libvlc_media_player_t *p_mi )
  385. {
  386.     if( !p_mi )
  387.         return;
  388.     vlc_mutex_lock( &p_mi->object_lock );
  389.     p_mi->i_refcount--;
  390.     if( p_mi->i_refcount > 0 )
  391.     {
  392.         vlc_mutex_unlock( &p_mi->object_lock );
  393.         return;
  394.     }
  395.     vlc_mutex_unlock( &p_mi->object_lock );
  396.     /* Detach Callback from the main libvlc object */
  397.     var_DelCallback( p_mi->p_libvlc_instance->p_libvlc_int,
  398.                      "vout-snapshottaken", SnapshotTakenCallback, p_mi );
  399.     vlc_mutex_destroy( &p_mi->object_lock );
  400.     release_input_thread( p_mi, true );
  401.     libvlc_event_manager_release( p_mi->p_event_manager );
  402.     libvlc_media_release( p_mi->p_md );
  403.     free( p_mi );
  404. }
  405. /**************************************************************************
  406.  * Retain a Media Instance object.
  407.  *
  408.  * Caller must hold the lock.
  409.  **************************************************************************/
  410. void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
  411. {
  412.     assert( p_mi );
  413.     vlc_mutex_lock( &p_mi->object_lock );
  414.     p_mi->i_refcount++;
  415.     vlc_mutex_unlock( &p_mi->object_lock );
  416. }
  417. /**************************************************************************
  418.  * Set the Media descriptor associated with the instance.
  419.  *
  420.  * Enter without lock -- function will lock the object.
  421.  **************************************************************************/
  422. void libvlc_media_player_set_media(
  423.                             libvlc_media_player_t *p_mi,
  424.                             libvlc_media_t *p_md,
  425.                             libvlc_exception_t *p_e )
  426. {
  427.     VLC_UNUSED(p_e);
  428.     if( !p_mi )
  429.         return;
  430.     vlc_mutex_lock( &p_mi->object_lock );
  431.     /* FIXME I am not sure if it is a user request or on die(eof/error)
  432.      * request here */
  433.     release_input_thread( p_mi,
  434.                           p_mi->p_input_thread &&
  435.                           !p_mi->p_input_thread->b_eof &&
  436.                           !p_mi->p_input_thread->b_error );
  437.     if( p_mi->p_md )
  438.         libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, p_e );
  439.     libvlc_media_release( p_mi->p_md );
  440.     if( !p_md )
  441.     {
  442.         p_mi->p_md = NULL;
  443.         vlc_mutex_unlock( &p_mi->object_lock );
  444.         return; /* It is ok to pass a NULL md */
  445.     }
  446.     libvlc_media_retain( p_md );
  447.     p_mi->p_md = p_md;
  448.     /* The policy here is to ignore that we were created using a different
  449.      * libvlc_instance, because we don't really care */
  450.     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
  451.     vlc_mutex_unlock( &p_mi->object_lock );
  452. }
  453. /**************************************************************************
  454.  * Get the Media descriptor associated with the instance.
  455.  **************************************************************************/
  456. libvlc_media_t *
  457. libvlc_media_player_get_media(
  458.                             libvlc_media_player_t *p_mi,
  459.                             libvlc_exception_t *p_e )
  460. {
  461.     libvlc_media_t *p_m;
  462.     VLC_UNUSED(p_e);
  463.     vlc_mutex_lock( &p_mi->object_lock );
  464.     p_m = p_mi->p_md;
  465.     if( p_m )
  466.         libvlc_media_retain( p_mi->p_md );
  467.     vlc_mutex_unlock( &p_mi->object_lock );
  468.     return p_mi->p_md;
  469. }
  470. /**************************************************************************
  471.  * Get the event Manager.
  472.  **************************************************************************/
  473. libvlc_event_manager_t *
  474. libvlc_media_player_event_manager(
  475.                             libvlc_media_player_t *p_mi,
  476.                             libvlc_exception_t *p_e )
  477. {
  478.     VLC_UNUSED(p_e);
  479.     return p_mi->p_event_manager;
  480. }
  481. /**************************************************************************
  482.  * Trigger a snapshot Taken Event.
  483.  *************************************************************************/
  484. static int SnapshotTakenCallback( vlc_object_t *p_this, char const *psz_cmd,
  485.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  486. {
  487.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
  488.     VLC_UNUSED(p_this) ;
  489.     libvlc_media_player_t* p_mi = (libvlc_media_player_t*) p_data ;
  490.     libvlc_event_t event ;
  491.     event.type = libvlc_MediaPlayerSnapshotTaken ;
  492.     event.u.media_player_snapshot_taken.psz_filename = newval.psz_string ;
  493.     /* Snapshot psz data is a vlc_variable owned by libvlc object .
  494.          Its memmory management is taken care by the obj*/
  495.     msg_Dbg( p_this, "about to emit libvlc_snapshot_taken.make psz_str=0x%p"
  496.              " (%s)", event.u.media_player_snapshot_taken.psz_filename,
  497.              event.u.media_player_snapshot_taken.psz_filename );
  498.     libvlc_event_send( p_mi->p_event_manager, &event );
  499.     return VLC_SUCCESS;
  500. }
  501. /**************************************************************************
  502.  * Tell media player to start playing.
  503.  **************************************************************************/
  504. void libvlc_media_player_play( libvlc_media_player_t *p_mi,
  505.                                  libvlc_exception_t *p_e )
  506. {
  507.     input_thread_t * p_input_thread;
  508.     if( (p_input_thread = libvlc_get_input_thread( p_mi, p_e )) )
  509.     {
  510.         /* A thread already exists, send it a play message */
  511.         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
  512.         vlc_object_release( p_input_thread );
  513.         return;
  514.     }
  515.     /* Ignore previous exception */
  516.     libvlc_exception_clear( p_e );
  517.     vlc_mutex_lock( &p_mi->object_lock );
  518.     if( !p_mi->p_md )
  519.     {
  520.         libvlc_exception_raise( p_e, "no associated media descriptor" );
  521.         vlc_mutex_unlock( &p_mi->object_lock );
  522.         return;
  523.     }
  524.     p_mi->p_input_thread = input_Create( p_mi->p_libvlc_instance->p_libvlc_int,
  525.                                          p_mi->p_md->p_input_item, NULL, NULL );
  526.     if( !p_mi->p_input_thread )
  527.     {
  528.         vlc_mutex_unlock( &p_mi->object_lock );
  529.         return;
  530.     }
  531.     p_input_thread = p_mi->p_input_thread;
  532.     var_Create( p_input_thread, "drawable-agl", VLC_VAR_INTEGER );
  533.     if( p_mi->drawable.agl )
  534.         var_SetInteger( p_input_thread, "drawable-agl", p_mi->drawable.agl );
  535.     var_Create( p_input_thread, "drawable-xid", VLC_VAR_INTEGER );
  536.     if( p_mi->drawable.xid )
  537.         var_SetInteger( p_input_thread, "drawable-xid", p_mi->drawable.xid );
  538.     var_Create( p_input_thread, "drawable-hwnd", VLC_VAR_ADDRESS );
  539.     if( p_mi->drawable.hwnd != NULL )
  540.     {
  541.         vlc_value_t val = { .p_address = p_mi->drawable.hwnd };
  542.         var_Set( p_input_thread, "drawable-hwnd", val );
  543.     }
  544. var_Create( p_input_thread, "drawable-nsobject", VLC_VAR_ADDRESS );
  545.     if( p_mi->drawable.nsobject != NULL )
  546.     {
  547.         vlc_value_t val = { .p_address = p_mi->drawable.nsobject };
  548.         var_Set( p_input_thread, "drawable-nsobject", val );
  549.     }
  550.     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
  551.     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
  552.     var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
  553.     if( input_Start( p_input_thread ) )
  554.     {
  555.         vlc_object_release( p_input_thread );
  556.         p_mi->p_input_thread = NULL;
  557.     }
  558.     vlc_mutex_unlock( &p_mi->object_lock );
  559. }
  560. /**************************************************************************
  561.  * Pause.
  562.  **************************************************************************/
  563. void libvlc_media_player_pause( libvlc_media_player_t *p_mi,
  564.                                   libvlc_exception_t *p_e )
  565. {
  566.     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
  567.     if( !p_input_thread )
  568.         return;
  569.     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
  570.     if( state == libvlc_Playing || state == libvlc_Buffering )
  571.     {
  572.         if( libvlc_media_player_can_pause( p_mi, p_e ) )
  573.             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
  574.         else
  575.             libvlc_media_player_stop( p_mi, p_e );
  576.     }
  577.     else
  578.         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
  579.     vlc_object_release( p_input_thread );
  580. }
  581. /**************************************************************************
  582.  * Tells whether the media player is currently playing.
  583.  *
  584.  * Enter with lock held.
  585.  **************************************************************************/
  586. int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi,
  587.                                      libvlc_exception_t *p_e )
  588. {
  589.     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
  590.     return (libvlc_Playing == state) || (libvlc_Buffering == state);
  591. }
  592. /**************************************************************************
  593.  * Stop playing.
  594.  **************************************************************************/
  595. void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
  596.                                  libvlc_exception_t *p_e )
  597. {
  598.     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
  599.     if( state == libvlc_Playing ||
  600.         state == libvlc_Paused ||
  601.         state == libvlc_Buffering )
  602.     {
  603.         /* Send a stop notification event only if we are in playing,
  604.          * buffering or paused states */
  605.         libvlc_media_set_state( p_mi->p_md, libvlc_Ended, p_e );
  606.         /* Construct and send the event */
  607.         libvlc_event_t event;
  608.         event.type = libvlc_MediaPlayerStopped;
  609.         libvlc_event_send( p_mi->p_event_manager, &event );
  610.     }
  611.     if( p_mi->b_own_its_input_thread )
  612.     {
  613.         vlc_mutex_lock( &p_mi->object_lock );
  614.         release_input_thread( p_mi, true ); /* This will stop the input thread */
  615.         vlc_mutex_unlock( &p_mi->object_lock );
  616.     }
  617.     else
  618.     {
  619.         input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
  620.         if( !p_input_thread )
  621.             return;
  622.         input_Stop( p_input_thread, true );
  623.         vlc_object_release( p_input_thread );
  624.         p_mi->p_input_thread = NULL;
  625.     }
  626. }
  627. /**************************************************************************
  628.  * set_nsobject
  629.  **************************************************************************/
  630. void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
  631.  void * drawable,
  632.  libvlc_exception_t *p_e )
  633. {
  634.     (void) p_e;
  635.     p_mi->drawable.nsobject = drawable;
  636. }
  637. /**************************************************************************
  638.  * get_nsobject
  639.  **************************************************************************/
  640. void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
  641. {
  642.     return p_mi->drawable.nsobject;
  643. }
  644. /**************************************************************************
  645.  * set_agl
  646.  **************************************************************************/
  647. void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
  648.                                       uint32_t drawable,
  649.                                       libvlc_exception_t *p_e )
  650. {
  651.     (void) p_e;
  652.     p_mi->drawable.agl = drawable;
  653. }
  654. /**************************************************************************
  655.  * get_agl
  656.  **************************************************************************/
  657. uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
  658. {
  659.     return p_mi->drawable.agl;
  660. }
  661. /**************************************************************************
  662.  * set_xwindow
  663.  **************************************************************************/
  664. void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
  665.                                       uint32_t drawable,
  666.                                       libvlc_exception_t *p_e )
  667. {
  668.     (void) p_e;
  669.     p_mi->drawable.xid = drawable;
  670. }
  671. /**************************************************************************
  672.  * get_xwindow
  673.  **************************************************************************/
  674. uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
  675. {
  676.     return p_mi->drawable.xid;
  677. }
  678. /**************************************************************************
  679.  * set_hwnd
  680.  **************************************************************************/
  681. void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
  682.                                    void *drawable,
  683.                                    libvlc_exception_t *p_e )
  684. {
  685.     (void) p_e;
  686.     p_mi->drawable.hwnd = drawable;
  687. }
  688. /**************************************************************************
  689.  * get_hwnd
  690.  **************************************************************************/
  691. void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
  692. {
  693.     return p_mi->drawable.hwnd;
  694. }
  695. /**************************************************************************
  696.  * Set Drawable
  697.  **************************************************************************/
  698. void libvlc_media_player_set_drawable( libvlc_media_player_t *p_mi,
  699.                                        libvlc_drawable_t drawable,
  700.                                        libvlc_exception_t *p_e )
  701. {
  702. #ifdef WIN32
  703.     if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
  704.         p_mi->drawable.hwnd = (HWND)drawable;
  705.     else
  706.         libvlc_exception_raise(p_e, "Operation not supported");
  707. #elif defined(__APPLE__)
  708.     p_mi->drawable.agl = drawable;
  709.     (void) p_e;
  710. #else
  711.     p_mi->drawable.xid = drawable;
  712.     (void) p_e;
  713. #endif
  714. }
  715. /**************************************************************************
  716.  * Get Drawable
  717.  **************************************************************************/
  718. libvlc_drawable_t
  719. libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi,
  720.                                    libvlc_exception_t *p_e )
  721. {
  722.     VLC_UNUSED(p_e);
  723. #ifdef WIN32
  724.     if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
  725.         return (libvlc_drawable_t)p_mi->drawable.hwnd;
  726.     else
  727.         return 0;
  728. #elif defined(__APPLE__)
  729.     return p_mi->drawable.agl;
  730. #else
  731.     return p_mi->drawable.xid;
  732. #endif
  733. }
  734. /**************************************************************************
  735.  * Getters for stream information
  736.  **************************************************************************/
  737. libvlc_time_t libvlc_media_player_get_length(
  738.                              libvlc_media_player_t *p_mi,
  739.                              libvlc_exception_t *p_e )
  740. {
  741.     input_thread_t *p_input_thread;
  742.     vlc_value_t val;
  743.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
  744.     if( !p_input_thread )
  745.         return -1;
  746.     var_Get( p_input_thread, "length", &val );
  747.     vlc_object_release( p_input_thread );
  748.     return (val.i_time+500LL)/1000LL;
  749. }
  750. libvlc_time_t libvlc_media_player_get_time(
  751.                                    libvlc_media_player_t *p_mi,
  752.                                    libvlc_exception_t *p_e )
  753. {
  754.     input_thread_t *p_input_thread;
  755.     vlc_value_t val;
  756.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  757.     if( !p_input_thread )
  758.         return -1;
  759.     var_Get( p_input_thread , "time", &val );
  760.     vlc_object_release( p_input_thread );
  761.     return (val.i_time+500LL)/1000LL;
  762. }
  763. void libvlc_media_player_set_time(
  764.                                  libvlc_media_player_t *p_mi,
  765.                                  libvlc_time_t time,
  766.                                  libvlc_exception_t *p_e )
  767. {
  768.     input_thread_t *p_input_thread;
  769.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  770.     if( !p_input_thread )
  771.         return;
  772.     var_SetTime( p_input_thread, "time", time*1000LL );
  773.     vlc_object_release( p_input_thread );
  774. }
  775. void libvlc_media_player_set_position(
  776.                                 libvlc_media_player_t *p_mi,
  777.                                 float position,
  778.                                 libvlc_exception_t *p_e )
  779. {
  780.     input_thread_t *p_input_thread;
  781.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
  782.     if( !p_input_thread )
  783.         return;
  784.     var_SetFloat( p_input_thread, "position", position );
  785.     vlc_object_release( p_input_thread );
  786. }
  787. float libvlc_media_player_get_position(
  788.                                  libvlc_media_player_t *p_mi,
  789.                                  libvlc_exception_t *p_e )
  790. {
  791.     input_thread_t *p_input_thread;
  792.     vlc_value_t val;
  793.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  794.     if( !p_input_thread )
  795.         return -1.0;
  796.     var_Get( p_input_thread, "position", &val );
  797.     vlc_object_release( p_input_thread );
  798.     return val.f_float;
  799. }
  800. void libvlc_media_player_set_chapter(
  801.                                  libvlc_media_player_t *p_mi,
  802.                                  int chapter,
  803.                                  libvlc_exception_t *p_e )
  804. {
  805.     input_thread_t *p_input_thread;
  806.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
  807.     if( !p_input_thread )
  808.         return;
  809.     var_SetInteger( p_input_thread, "chapter", chapter );
  810.     vlc_object_release( p_input_thread );
  811. }
  812. int libvlc_media_player_get_chapter(
  813.                                  libvlc_media_player_t *p_mi,
  814.                                  libvlc_exception_t *p_e )
  815. {
  816.     input_thread_t *p_input_thread;
  817.     vlc_value_t val;
  818.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  819.     if( !p_input_thread )
  820.         return -1;
  821.     var_Get( p_input_thread, "chapter", &val );
  822.     vlc_object_release( p_input_thread );
  823.     return val.i_int;
  824. }
  825. int libvlc_media_player_get_chapter_count(
  826.                                  libvlc_media_player_t *p_mi,
  827.                                  libvlc_exception_t *p_e )
  828. {
  829.     input_thread_t *p_input_thread;
  830.     vlc_value_t val;
  831.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  832.     if( !p_input_thread )
  833.         return -1;
  834.     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
  835.     vlc_object_release( p_input_thread );
  836.     return val.i_int;
  837. }
  838. int libvlc_media_player_get_chapter_count_for_title(
  839.                                  libvlc_media_player_t *p_mi,
  840.                                  int i_title,
  841.                                  libvlc_exception_t *p_e )
  842. {
  843.     input_thread_t *p_input_thread;
  844.     vlc_value_t val;
  845.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  846.     if( !p_input_thread )
  847.         return -1;
  848.     char *psz_name;
  849.     if( asprintf( &psz_name,  "title %2i", i_title ) == -1 )
  850.     {
  851.         vlc_object_release( p_input_thread );
  852.         return -1;
  853.     }
  854.     var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
  855.     vlc_object_release( p_input_thread );
  856.     free( psz_name );
  857.     return val.i_int;
  858. }
  859. void libvlc_media_player_set_title(
  860.                                  libvlc_media_player_t *p_mi,
  861.                                  int i_title,
  862.                                  libvlc_exception_t *p_e )
  863. {
  864.     input_thread_t *p_input_thread;
  865.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
  866.     if( !p_input_thread )
  867.         return;
  868.     var_SetInteger( p_input_thread, "title", i_title );
  869.     vlc_object_release( p_input_thread );
  870.     //send event
  871.     libvlc_event_t event;
  872.     event.type = libvlc_MediaPlayerTitleChanged;
  873.     event.u.media_player_title_changed.new_title = i_title;
  874.     libvlc_event_send( p_mi->p_event_manager, &event );
  875. }
  876. int libvlc_media_player_get_title(
  877.                                  libvlc_media_player_t *p_mi,
  878.                                  libvlc_exception_t *p_e )
  879. {
  880.     input_thread_t *p_input_thread;
  881.     vlc_value_t val;
  882.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  883.     if( !p_input_thread )
  884.         return -1;
  885.     var_Get( p_input_thread, "title", &val );
  886.     vlc_object_release( p_input_thread );
  887.     return val.i_int;
  888. }
  889. int libvlc_media_player_get_title_count(
  890.                                  libvlc_media_player_t *p_mi,
  891.                                  libvlc_exception_t *p_e )
  892. {
  893.     input_thread_t *p_input_thread;
  894.     vlc_value_t val;
  895.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  896.     if( !p_input_thread )
  897.         return -1;
  898.     var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
  899.     vlc_object_release( p_input_thread );
  900.     return val.i_int;
  901. }
  902. void libvlc_media_player_next_chapter(
  903.                                  libvlc_media_player_t *p_mi,
  904.                                  libvlc_exception_t *p_e )
  905. {
  906.     input_thread_t *p_input_thread;
  907.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
  908.     if( !p_input_thread )
  909.         return;
  910.     int i_type = var_Type( p_input_thread, "next-chapter" );
  911.     var_SetBool( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
  912.                             "next-chapter":"next-title", true );
  913.     vlc_object_release( p_input_thread );
  914. }
  915. void libvlc_media_player_previous_chapter(
  916.                                  libvlc_media_player_t *p_mi,
  917.                                  libvlc_exception_t *p_e )
  918. {
  919.     input_thread_t *p_input_thread;
  920.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
  921.     if( !p_input_thread )
  922.         return;
  923.     int i_type = var_Type( p_input_thread, "next-chapter" );
  924.     var_SetBool( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
  925.                             "prev-chapter":"prev-title", true );
  926.     vlc_object_release( p_input_thread );
  927. }
  928. float libvlc_media_player_get_fps(
  929.                                  libvlc_media_player_t *p_mi,
  930.                                  libvlc_exception_t *p_e)
  931. {
  932.     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  933.     double f_fps = 0.0;
  934.     if( p_input_thread )
  935.     {
  936.         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
  937.             f_fps = 0.0;
  938.         vlc_object_release( p_input_thread );
  939.     }
  940.     return f_fps;
  941. }
  942. int libvlc_media_player_will_play( libvlc_media_player_t *p_mi,
  943.                                      libvlc_exception_t *p_e)
  944. {
  945.     input_thread_t *p_input_thread =
  946.                             libvlc_get_input_thread ( p_mi, p_e);
  947.     if ( !p_input_thread )
  948.         return false;
  949.     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
  950.     {
  951.         vlc_object_release( p_input_thread );
  952.         return true;
  953.     }
  954.     vlc_object_release( p_input_thread );
  955.     return false;
  956. }
  957. void libvlc_media_player_set_rate(
  958.                                  libvlc_media_player_t *p_mi,
  959.                                  float rate,
  960.                                  libvlc_exception_t *p_e )
  961. {
  962.     input_thread_t *p_input_thread;
  963.     bool b_can_rewind;
  964.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  965.     if( !p_input_thread )
  966.         return;
  967.     b_can_rewind = var_GetBool( p_input_thread, "can-rewind" );
  968.     if( (rate < 0.0) && !b_can_rewind )
  969.     {
  970.         vlc_object_release( p_input_thread );
  971.         libvlc_exception_raise( p_e, "Rate value is invalid" );
  972.         return;
  973.     }
  974.     var_SetInteger( p_input_thread, "rate", 1000.0f/rate );
  975.     vlc_object_release( p_input_thread );
  976. }
  977. float libvlc_media_player_get_rate(
  978.                                  libvlc_media_player_t *p_mi,
  979.                                  libvlc_exception_t *p_e )
  980. {
  981.     input_thread_t *p_input_thread;
  982.     vlc_value_t val;
  983.     bool b_can_rewind;
  984.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  985.     if( !p_input_thread )
  986.         return 0.0;  /* rate < 0 indicates rewind */
  987.     var_Get( p_input_thread, "rate", &val );
  988.     b_can_rewind = var_GetBool( p_input_thread, "can-rewind" );
  989.     if( (val.i_int < 0) && !b_can_rewind )
  990.     {
  991.         vlc_object_release( p_input_thread );
  992.         libvlc_exception_raise( p_e, "invalid rate" );
  993.         return 0.0;
  994.     }
  995.     vlc_object_release( p_input_thread );
  996.     return (float)1000.0f/val.i_int;
  997. }
  998. libvlc_state_t libvlc_media_player_get_state(
  999.                                  libvlc_media_player_t *p_mi,
  1000.                                  libvlc_exception_t *p_e )
  1001. {
  1002.     input_thread_t *p_input_thread;
  1003.     libvlc_state_t state = libvlc_Ended;
  1004.     vlc_value_t val;
  1005.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  1006.     if( !p_input_thread )
  1007.     {
  1008.         /* We do return the right value, no need to throw an exception */
  1009.         if( libvlc_exception_raised( p_e ) )
  1010.             libvlc_exception_clear( p_e );
  1011.         return state;
  1012.     }
  1013.     var_Get( p_input_thread, "state", &val );
  1014.     state = vlc_to_libvlc_state(val.i_int);
  1015.     if( state == libvlc_Playing )
  1016.     {
  1017.         float caching;
  1018.         caching = var_GetFloat( p_input_thread, "cache" );
  1019.         if( caching > 0.0 && caching < 1.0 )
  1020.             state = libvlc_Buffering;
  1021.     }
  1022.     vlc_object_release( p_input_thread );
  1023.     return state;
  1024. }
  1025. int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi,
  1026.                                        libvlc_exception_t *p_e )
  1027. {
  1028.     input_thread_t *p_input_thread;
  1029.     vlc_value_t val;
  1030.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  1031.     if ( !p_input_thread )
  1032.     {
  1033.         /* We do return the right value, no need to throw an exception */
  1034.         if( libvlc_exception_raised( p_e ) )
  1035.             libvlc_exception_clear( p_e );
  1036.         return false;
  1037.     }
  1038.     var_Get( p_input_thread, "can-seek", &val );
  1039.     vlc_object_release( p_input_thread );
  1040.     return val.b_bool;
  1041. }
  1042. /* internal function, used by audio, video */
  1043. libvlc_track_description_t *
  1044.         libvlc_get_track_description( libvlc_media_player_t *p_mi,
  1045.                                       const char *psz_variable,
  1046.                                       libvlc_exception_t *p_e )
  1047. {
  1048.     input_thread_t *p_input = libvlc_get_input_thread( p_mi, p_e );
  1049.     if( !p_input )
  1050.         return NULL;
  1051.     vlc_value_t val_list, text_list;
  1052.     var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list);
  1053.     if( val_list.p_list->i_count <= 0 ) /* no tracks */
  1054.     {
  1055.         var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list);
  1056.         vlc_object_release( p_input );
  1057.         return NULL;
  1058.     }
  1059.     libvlc_track_description_t *p_track_description, *p_actual, *p_previous;
  1060.     p_track_description = ( libvlc_track_description_t * )
  1061.         malloc( sizeof( libvlc_track_description_t ) );
  1062.     if ( !p_track_description )
  1063.     {
  1064.         var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
  1065.                     &val_list, &text_list);
  1066.         vlc_object_release( p_input );
  1067.         libvlc_exception_raise( p_e, "no enough memory" );
  1068.         return NULL;
  1069.     }
  1070.     p_actual = p_track_description;
  1071.     p_previous = NULL;
  1072.     for( int i = 0; i < val_list.p_list->i_count; i++ )
  1073.     {
  1074.         if( !p_actual )
  1075.         {
  1076.             p_actual = ( libvlc_track_description_t * )
  1077.                 malloc( sizeof( libvlc_track_description_t ) );
  1078.             if ( !p_actual )
  1079.             {
  1080.                 libvlc_track_description_release( p_track_description );
  1081.                 var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
  1082.                             &val_list, &text_list);
  1083.                 vlc_object_release( p_input );
  1084.                 libvlc_exception_raise( p_e, "no enough memory" );
  1085.                 return NULL;
  1086.             }
  1087.         }
  1088.         p_actual->i_id = val_list.p_list->p_values[i].i_int;
  1089.         p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
  1090.         p_actual->p_next = NULL;
  1091.         if( p_previous )
  1092.             p_previous->p_next = p_actual;
  1093.         p_previous = p_actual;
  1094.         p_actual =  NULL;
  1095.     }
  1096.     var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list);
  1097.     vlc_object_release( p_input );
  1098.     return p_track_description;
  1099. }
  1100. void libvlc_track_description_release( libvlc_track_description_t *p_td )
  1101. {
  1102.     libvlc_track_description_t *p_actual, *p_before;
  1103.     p_actual = p_td;
  1104.     while ( p_actual )
  1105.     {
  1106.         free( p_actual->psz_name );
  1107.         p_before = p_actual;
  1108.         p_actual = p_before->p_next;
  1109.         free( p_before );
  1110.     }
  1111. }
  1112. int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi,
  1113.                                      libvlc_exception_t *p_e )
  1114. {
  1115.     input_thread_t *p_input_thread;
  1116.     vlc_value_t val;
  1117.     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
  1118.     if ( !p_input_thread )
  1119.     {
  1120.         /* We do return the right value, no need to throw an exception */
  1121.         if( libvlc_exception_raised( p_e ) )
  1122.             libvlc_exception_clear( p_e );
  1123.         return false;
  1124.     }
  1125.     var_Get( p_input_thread, "can-pause", &val );
  1126.     vlc_object_release( p_input_thread );
  1127.     return val.b_bool;
  1128. }