]> git.sesse.net Git - vlc/blobdiff - lib/media_player.c
log: fix theoretical pointer alignment problem
[vlc] / lib / media_player.c
index 8eee79c7c1406916e81d3e87d48f7b8240a9e9f3..f234b57c6284313dd1e728ed286981334d0ab59a 100644 (file)
@@ -57,6 +57,22 @@ input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
                      vlc_value_t oldval, vlc_value_t newval,
                      void * p_userdata );
 
+static int
+input_es_changed( vlc_object_t * p_this, char const * psz_cmd,
+                  int action, vlc_value_t *p_val,
+                  void *p_userdata);
+
+static int
+input_es_selected( vlc_object_t * p_this, char const * psz_cmd,
+                   vlc_value_t oldval, vlc_value_t newval,
+                   void * p_userdata );
+
+static void
+add_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi );
+
+static void
+del_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi );
+
 static int
 snapshot_was_taken( vlc_object_t *p_this, char const *psz_cmd,
                     vlc_value_t oldval, vlc_value_t newval, void *p_data );
@@ -125,6 +141,7 @@ static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abor
                     input_scrambled_changed, p_mi );
     var_DelCallback( p_input_thread, "intf-event",
                      input_event_changed, p_mi );
+    del_es_callbacks( p_input_thread, p_mi );
 
     /* We owned this one */
     input_Stop( p_input_thread, b_input_abort );
@@ -347,6 +364,85 @@ input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
     return VLC_SUCCESS;
 }
 
+static int track_type_from_name(const char *psz_name)
+{
+   if( !strcmp( psz_name, "video-es" ) )
+       return libvlc_track_video;
+    else if( !strcmp( psz_name, "audio-es" ) )
+        return libvlc_track_audio;
+    else if( !strcmp( psz_name, "spu-es" ) )
+        return libvlc_track_text;
+    else
+        return libvlc_track_unknown;
+}
+
+static int input_es_changed( vlc_object_t *p_this,
+                             char const *psz_cmd,
+                             int action,
+                             vlc_value_t *p_val,
+                             void *p_userdata )
+{
+    VLC_UNUSED(p_this);
+    libvlc_media_player_t *mp = p_userdata;
+    libvlc_event_t event;
+
+    /* Ignore the "Disable" element */
+    if (p_val && p_val->i_int < 0)
+        return VLC_EGENERIC;
+
+    switch (action)
+    {
+    case VLC_VAR_ADDCHOICE:
+        event.type = libvlc_MediaPlayerESAdded;
+        break;
+    case VLC_VAR_DELCHOICE:
+    case VLC_VAR_CLEARCHOICES:
+        event.type = libvlc_MediaPlayerESDeleted;
+        break;
+    default:
+        return VLC_EGENERIC;
+    }
+
+    event.u.media_player_es_changed.i_type = track_type_from_name(psz_cmd);
+
+    int i_id;
+    if (action != VLC_VAR_CLEARCHOICES)
+    {
+        if (!p_val)
+            return VLC_EGENERIC;
+        i_id = p_val->i_int;
+    }
+    else
+    {
+        /* -1 means all ES tracks of this type were deleted. */
+        i_id = -1;
+    }
+    event.u.media_player_es_changed.i_id = i_id;
+
+    libvlc_event_send(mp->p_event_manager, &event);
+
+    return VLC_SUCCESS;
+}
+
+static int
+input_es_selected( vlc_object_t * p_this, char const * psz_cmd,
+                   vlc_value_t oldval, vlc_value_t newval,
+                   void * p_userdata )
+{
+    VLC_UNUSED(p_this);
+    VLC_UNUSED(oldval);
+    libvlc_media_player_t *mp = p_userdata;
+    libvlc_event_t event;
+
+    event.type = libvlc_MediaPlayerESSelected;
+    event.u.media_player_es_changed.i_type = track_type_from_name(psz_cmd);
+    event.u.media_player_es_changed.i_id = newval.i_int;
+
+    libvlc_event_send(mp->p_event_manager, &event);
+
+    return VLC_SUCCESS;
+}
+
 /**************************************************************************
  * Snapshot Taken Event.
  *
@@ -460,7 +556,7 @@ libvlc_media_player_new( libvlc_instance_t *instance )
 
     var_Create (mp, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
     var_Create (mp, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
-    var_Create (mp, "hue", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "hue", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
     var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
     var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
 
@@ -469,6 +565,7 @@ libvlc_media_player_new( libvlc_instance_t *instance )
     var_Create (mp, "mute", VLC_VAR_BOOL);
     var_Create (mp, "volume", VLC_VAR_FLOAT);
     var_Create (mp, "corks", VLC_VAR_INTEGER);
+    var_Create (mp, "audio-filter", VLC_VAR_STRING);
     var_Create (mp, "amem-data", VLC_VAR_ADDRESS);
     var_Create (mp, "amem-setup", VLC_VAR_ADDRESS);
     var_Create (mp, "amem-cleanup", VLC_VAR_ADDRESS);
@@ -537,6 +634,9 @@ libvlc_media_player_new( libvlc_instance_t *instance )
 
     register_event(mp, Vout);
     register_event(mp, ScrambledChanged);
+    register_event(mp, ESAdded);
+    register_event(mp, ESDeleted);
+    register_event(mp, ESSelected);
 
     /* Snapshot initialization */
     register_event(mp, SnapshotTaken);
@@ -691,12 +791,13 @@ libvlc_media_player_get_media( libvlc_media_player_t *p_mi )
 {
     libvlc_media_t *p_m;
 
-    lock(p_mi);
+    lock( p_mi );
     p_m = p_mi->p_md;
     if( p_m )
-        libvlc_media_retain( p_mi->p_md );
-    unlock(p_mi);
-    return p_mi->p_md;
+        libvlc_media_retain( p_m );
+    unlock( p_mi );
+
+    return p_m;
 }
 
 /**************************************************************************
@@ -708,6 +809,26 @@ libvlc_media_player_event_manager( libvlc_media_player_t *p_mi )
     return p_mi->p_event_manager;
 }
 
+static void add_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi )
+{
+    var_AddListCallback( p_input_thread, "video-es", input_es_changed, p_mi );
+    var_AddListCallback( p_input_thread, "audio-es", input_es_changed, p_mi );
+    var_AddListCallback( p_input_thread, "spu-es", input_es_changed, p_mi );
+    var_AddCallback( p_input_thread, "video-es", input_es_selected, p_mi );
+    var_AddCallback( p_input_thread, "audio-es", input_es_selected, p_mi );
+    var_AddCallback( p_input_thread, "spu-es", input_es_selected, p_mi );
+}
+
+static void del_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi )
+{
+    var_DelListCallback( p_input_thread, "video-es", input_es_changed, p_mi );
+    var_DelListCallback( p_input_thread, "audio-es", input_es_changed, p_mi );
+    var_DelListCallback( p_input_thread, "spu-es", input_es_changed, p_mi );
+    var_DelCallback( p_input_thread, "video-es", input_es_selected, p_mi );
+    var_DelCallback( p_input_thread, "audio-es", input_es_selected, p_mi );
+    var_DelCallback( p_input_thread, "spu-es", input_es_selected, p_mi );
+}
+
 /**************************************************************************
  * Tell media player to start playing.
  **************************************************************************/
@@ -749,10 +870,12 @@ int libvlc_media_player_play( libvlc_media_player_t *p_mi )
     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
     var_AddCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
     var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
+    add_es_callbacks( p_input_thread, p_mi );
 
     if( input_Start( p_input_thread ) )
     {
         unlock_input(p_mi);
+        del_es_callbacks( p_input_thread, p_mi );
         var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
         var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
         var_DelCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
@@ -780,7 +903,7 @@ void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused )
             if( libvlc_media_player_can_pause( p_mi ) )
                 input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
             else
-                libvlc_media_player_stop( p_mi );
+                input_Stop( p_input_thread, true );
         }
     }
     else
@@ -1133,10 +1256,10 @@ int libvlc_media_player_get_chapter_count( libvlc_media_player_t *p_mi )
     if( !p_input_thread )
         return -1;
 
-    var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
+    int i_ret = var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
     vlc_object_release( p_input_thread );
 
-    return val.i_int;
+    return i_ret == VLC_SUCCESS ? val.i_int : -1;
 }
 
 int libvlc_media_player_get_chapter_count_for_title(
@@ -1156,11 +1279,11 @@ int libvlc_media_player_get_chapter_count_for_title(
         vlc_object_release( p_input_thread );
         return -1;
     }
-    var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
+    int i_ret = var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
     vlc_object_release( p_input_thread );
     free( psz_name );
 
-    return val.i_int;
+    return i_ret == VLC_SUCCESS ? val.i_int : -1;
 }
 
 void libvlc_media_player_set_title( libvlc_media_player_t *p_mi,
@@ -1206,10 +1329,10 @@ int libvlc_media_player_get_title_count( libvlc_media_player_t *p_mi )
     if( !p_input_thread )
         return -1;
 
-    var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
+    int i_ret = var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
     vlc_object_release( p_input_thread );
 
-    return val.i_int;
+    return i_ret == VLC_SUCCESS ? val.i_int : -1;
 }
 
 void libvlc_media_player_next_chapter( libvlc_media_player_t *p_mi )
@@ -1342,7 +1465,9 @@ libvlc_track_description_t *
         return NULL;
 
     vlc_value_t val_list, text_list;
-    var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list);
+    int i_ret = var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list );
+    if( i_ret != VLC_SUCCESS )
+        return NULL;
 
     /* no tracks */
     if( val_list.p_list->i_count <= 0 )
@@ -1444,12 +1569,30 @@ void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
     }
 }
 
+/**
+ * Private lookup table to get subpicture alignment flag values corresponding
+ * to a libvlc_position_t enumerated value.
+ */
+static const unsigned char position_subpicture_alignment[] = {
+    [libvlc_position_center]       = 0,
+    [libvlc_position_left]         = SUBPICTURE_ALIGN_LEFT,
+    [libvlc_position_right]        = SUBPICTURE_ALIGN_RIGHT,
+    [libvlc_position_top]          = SUBPICTURE_ALIGN_TOP,
+    [libvlc_position_top_left]     = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT,
+    [libvlc_position_top_right]    = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_RIGHT,
+    [libvlc_position_bottom]       = SUBPICTURE_ALIGN_BOTTOM,
+    [libvlc_position_bottom_left]  = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_LEFT,
+    [libvlc_position_bottom_right] = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_RIGHT
+};
+
 void libvlc_media_player_set_video_title_display( libvlc_media_player_t *p_mi, libvlc_position_t position, unsigned timeout )
 {
+    assert( position >= libvlc_position_disable && position <= libvlc_position_bottom_right );
+
     if ( position != libvlc_position_disable )
     {
         var_SetBool( p_mi, "video-title-show", true );
-        var_SetInteger( p_mi, "video-title-position", position );
+        var_SetInteger( p_mi, "video-title-position", position_subpicture_alignment[position] );
         var_SetInteger( p_mi, "video-title-timeout", timeout );
     }
     else
@@ -1471,49 +1614,35 @@ void libvlc_media_player_set_video_title_display( libvlc_media_player_t *p_mi, l
 
 int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equalizer_t *p_equalizer )
 {
-    float f_preamp;
-    char *psz_bands;
+    char bands[EQZ_BANDS_MAX * EQZ_BAND_VALUE_SIZE + 1];
 
-    if ( p_equalizer )
+    if( p_equalizer != NULL )
     {
-        f_preamp = p_equalizer->f_preamp;
-
-        psz_bands = malloc( EQZ_BANDS_MAX * EQZ_BAND_VALUE_SIZE + 1 );
-        if ( unlikely( psz_bands == NULL ) )
-            return -1;
-
-        char *p = psz_bands;
-        int c;
-        for ( int i = 0; i < EQZ_BANDS_MAX; i++ )
+        for( unsigned i = 0, c = 0; i < EQZ_BANDS_MAX; i++ )
         {
-            c = snprintf( p, EQZ_BAND_VALUE_SIZE + 1, " %.07f", p_equalizer->f_amp[i] );
-            if ( unlikely( c >= EQZ_BAND_VALUE_SIZE + 1 ) )
-            {
-                free( psz_bands );
+            c += snprintf( bands + c, sizeof(bands) - c, " %.07f",
+                          p_equalizer->f_amp[i] );
+            if( unlikely(c >= sizeof(bands)) )
                 return -1;
-            }
-
-            p += c;
         }
-    }
-    else
-    {
-        f_preamp = 0.f;
-        psz_bands = NULL;
-    }
 
-    var_SetFloat( p_mi, "equalizer-preamp", f_preamp );
-    var_SetString( p_mi, "equalizer-bands", psz_bands );
+        var_SetFloat( p_mi, "equalizer-preamp", p_equalizer->f_preamp );
+        var_SetString( p_mi, "equalizer-bands", bands );
+    }
+    var_SetString( p_mi, "audio-filter", p_equalizer ? "equalizer" : "" );
 
     audio_output_t *p_aout = input_resource_HoldAout( p_mi->input.p_resource );
-    if ( p_aout )
+    if( p_aout != NULL )
     {
-        var_SetFloat( p_aout, "equalizer-preamp", f_preamp );
-        var_SetString( p_aout, "equalizer-bands", psz_bands );
+        if( p_equalizer != NULL )
+        {
+            var_SetFloat( p_aout, "equalizer-preamp", p_equalizer->f_preamp );
+            var_SetString( p_aout, "equalizer-bands", bands );
+        }
 
+        var_SetString( p_aout, "audio-filter", p_equalizer ? "equalizer" : "" );
         vlc_object_release( p_aout );
     }
 
-    free( psz_bands );
     return 0;
 }