media_player.c 60.7 KB
Newer Older
Clément Stenac's avatar
Clément Stenac committed
1
/*****************************************************************************
2
 * media_player.c: Libvlc API Media Instance management functions
Clément Stenac's avatar
Clément Stenac committed
3
 *****************************************************************************
4
 * Copyright (C) 2005-2015 VLC authors and VideoLAN
Clément Stenac's avatar
Clément Stenac committed
5
 *
6
 * Authors: Clément Stenac <zorglub@videolan.org>
Clément Stenac's avatar
Clément Stenac committed
7
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
8 9 10
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
Clément Stenac's avatar
Clément Stenac committed
11 12 13 14
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
15 16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
Clément Stenac's avatar
Clément Stenac committed
17
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
18 19 20
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Clément Stenac's avatar
Clément Stenac committed
21 22
 *****************************************************************************/

Geoffroy Couprie's avatar
Geoffroy Couprie committed
23 24 25 26
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

27
#include <assert.h>
28

Clément Stenac's avatar
Clément Stenac committed
29
#include <vlc/libvlc.h>
30 31 32
#include <vlc/libvlc_media.h>
#include <vlc/libvlc_events.h>

Clément Stenac's avatar
Clément Stenac committed
33 34
#include <vlc_demux.h>
#include <vlc_input.h>
35
#include <vlc_vout.h>
Mark Lee's avatar
Mark Lee committed
36
#include <vlc_aout.h>
37
#include <vlc_keys.h>
38 39 40 41

#include "libvlc_internal.h"
#include "media_internal.h" // libvlc_media_set_state()
#include "media_player_internal.h"
Clément Stenac's avatar
Clément Stenac committed
42

43
static int
44 45 46 47 48 49 50 51
input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
                        vlc_value_t oldval, vlc_value_t newval,
                        void * p_userdata );
static int
input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
                        vlc_value_t oldval, vlc_value_t newval,
                        void * p_userdata );
static int
52 53 54 55
input_scrambled_changed( vlc_object_t * p_this, char const * psz_cmd,
                        vlc_value_t oldval, vlc_value_t newval,
                        void * p_userdata );
static int
Laurent Aimar's avatar
Laurent Aimar committed
56
input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
57 58 59
                     vlc_value_t oldval, vlc_value_t newval,
                     void * p_userdata );

60 61 62 63 64 65 66 67 68 69
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 );

70 71 72 73
static int
corks_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
              vlc_value_t cur, void *opaque);

74 75 76 77
static int
mute_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
             vlc_value_t cur, void *opaque);

78 79 80 81
static int
volume_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
               vlc_value_t cur, void *opaque);

82 83 84 85 86 87
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 );

88 89 90
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 );
91

92
static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi );
93

94 95 96 97
/*
 * Shortcuts
 */

98 99 100 101 102 103 104 105 106
/*
 * The input lock protects the input and input resource pointer.
 * It MUST NOT be used from callbacks.
 *
 * The object lock protects the reset, namely the media and the player state.
 * It can, and usually needs to be taken from callbacks.
 * The object lock can be acquired under the input lock... and consequently
 * the opposite order is STRICTLY PROHIBITED.
 */
107 108 109 110 111 112 113 114 115 116
static inline void lock(libvlc_media_player_t *mp)
{
    vlc_mutex_lock(&mp->object_lock);
}

static inline void unlock(libvlc_media_player_t *mp)
{
    vlc_mutex_unlock(&mp->object_lock);
}

117 118 119 120 121 122 123 124 125 126
static inline void lock_input(libvlc_media_player_t *mp)
{
    vlc_mutex_lock(&mp->input.lock);
}

static inline void unlock_input(libvlc_media_player_t *mp)
{
    vlc_mutex_unlock(&mp->input.lock);
}

127
/*
JP Dinger's avatar
JP Dinger committed
128
 * Release the associated input thread.
129 130
 *
 * Object lock is NOT held.
131
 * Input lock is held or instance is being destroyed.
132
 */
133
static void release_input_thread( libvlc_media_player_t *p_mi )
134
{
135
    assert( p_mi );
136

137
    input_thread_t *p_input_thread = p_mi->input.p_thread;
138
    if( !p_input_thread )
139
        return;
140
    p_mi->input.p_thread = NULL;
141

142 143 144 145
    var_DelCallback( p_input_thread, "can-seek",
                     input_seekable_changed, p_mi );
    var_DelCallback( p_input_thread, "can-pause",
                    input_pausable_changed, p_mi );
146 147
    var_DelCallback( p_input_thread, "program-scrambled",
                    input_scrambled_changed, p_mi );
148 149
    var_DelCallback( p_input_thread, "intf-event",
                     input_event_changed, p_mi );
150
    del_es_callbacks( p_input_thread, p_mi );
151 152

    /* We owned this one */
153
    input_Stop( p_input_thread );
154
    input_Close( p_input_thread );
155 156
}

157 158
/*
 * Retrieve the input thread. Be sure to release the object
159
 * once you are done with it. (libvlc Internal)
160
 */
161
input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi )
Clément Stenac's avatar
Clément Stenac committed
162 163 164
{
    input_thread_t *p_input_thread;

165
    assert( p_mi );
166

167 168
    lock_input(p_mi);
    p_input_thread = p_mi->input.p_thread;
169 170
    if( p_input_thread )
        vlc_object_hold( p_input_thread );
171 172
    else
        libvlc_printerr( "No active input" );
173
    unlock_input(p_mi);
174

175 176 177
    return p_input_thread;
}

178 179 180 181 182
/*
 * Set the internal state of the media_player. (media player Internal)
 *
 * Function will lock the media_player.
 */
183 184 185 186 187
static void set_state( libvlc_media_player_t *p_mi, libvlc_state_t state,
    bool b_locked )
{
    if(!b_locked)
        lock(p_mi);
188
    p_mi->state = state;
189

190 191 192
    libvlc_media_t *media = p_mi->p_md;
    if (media)
        libvlc_media_retain(media);
193

194 195
    if(!b_locked)
        unlock(p_mi);
196

197 198
    if (media)
    {
199 200 201
        // Also set the state of the corresponding media
        // This is strictly for convenience.
        libvlc_media_set_state(media, state);
202 203

        libvlc_media_release(media);
204 205 206
    }
}

207
static int
208
input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
209 210 211 212
                        vlc_value_t oldval, vlc_value_t newval,
                        void * p_userdata )
{
    VLC_UNUSED(oldval);
213 214
    VLC_UNUSED(p_this);
    VLC_UNUSED(psz_cmd);
215
    libvlc_media_player_t * p_mi = p_userdata;
216 217
    libvlc_event_t event;

218
    event.type = libvlc_MediaPlayerSeekableChanged;
219
    event.u.media_player_seekable_changed.new_seekable = newval.b_bool;
220 221 222 223 224 225 226 227 228 229 230

    libvlc_event_send( p_mi->p_event_manager, &event );
    return VLC_SUCCESS;
}

static int
input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
                        vlc_value_t oldval, vlc_value_t newval,
                        void * p_userdata )
{
    VLC_UNUSED(oldval);
231 232
    VLC_UNUSED(p_this);
    VLC_UNUSED(psz_cmd);
233
    libvlc_media_player_t * p_mi = p_userdata;
234 235
    libvlc_event_t event;

236
    event.type = libvlc_MediaPlayerPausableChanged;
237
    event.u.media_player_pausable_changed.new_pausable = newval.b_bool;
238 239 240 241 242

    libvlc_event_send( p_mi->p_event_manager, &event );
    return VLC_SUCCESS;
}

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
static int
input_scrambled_changed( vlc_object_t * p_this, char const * psz_cmd,
                        vlc_value_t oldval, vlc_value_t newval,
                        void * p_userdata )
{
    VLC_UNUSED(oldval);
    VLC_UNUSED(p_this);
    VLC_UNUSED(psz_cmd);
    libvlc_media_player_t * p_mi = p_userdata;
    libvlc_event_t event;

    event.type = libvlc_MediaPlayerScrambledChanged;
    event.u.media_player_scrambled_changed.new_scrambled = newval.b_bool;

    libvlc_event_send( p_mi->p_event_manager, &event );
    return VLC_SUCCESS;
}

261
static int
Laurent Aimar's avatar
Laurent Aimar committed
262
input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
263 264 265
                     vlc_value_t oldval, vlc_value_t newval,
                     void * p_userdata )
{
266
    VLC_UNUSED(oldval); VLC_UNUSED(psz_cmd);
Laurent Aimar's avatar
Laurent Aimar committed
267
    input_thread_t * p_input = (input_thread_t *)p_this;
268
    libvlc_media_player_t * p_mi = p_userdata;
Laurent Aimar's avatar
Laurent Aimar committed
269
    libvlc_event_t event;
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
270

271
    assert( !strcmp( psz_cmd, "intf-event" ) );
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
272

273 274
    if( newval.i_int == INPUT_EVENT_STATE )
    {
275
        libvlc_state_t libvlc_state;
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306

        switch ( var_GetInteger( p_input, "state" ) )
        {
            case INIT_S:
                libvlc_state = libvlc_NothingSpecial;
                event.type = libvlc_MediaPlayerNothingSpecial;
                break;
            case OPENING_S:
                libvlc_state = libvlc_Opening;
                event.type = libvlc_MediaPlayerOpening;
                break;
            case PLAYING_S:
                libvlc_state = libvlc_Playing;
                event.type = libvlc_MediaPlayerPlaying;
                break;
            case PAUSE_S:
                libvlc_state = libvlc_Paused;
                event.type = libvlc_MediaPlayerPaused;
                break;
            case END_S:
                libvlc_state = libvlc_Ended;
                event.type = libvlc_MediaPlayerEndReached;
                break;
            case ERROR_S:
                libvlc_state = libvlc_Error;
                event.type = libvlc_MediaPlayerEncounteredError;
                break;

            default:
                return VLC_SUCCESS;
        }
307

308
        set_state( p_mi, libvlc_state, false );
309 310
        libvlc_event_send( p_mi->p_event_manager, &event );
    }
311
    else if( newval.i_int == INPUT_EVENT_DEAD )
312
    {
313
        libvlc_state_t libvlc_state = libvlc_Ended;
314 315
        event.type = libvlc_MediaPlayerStopped;

316
        set_state( p_mi, libvlc_state, false );
317 318
        libvlc_event_send( p_mi->p_event_manager, &event );
    }
319
    else if( newval.i_int == INPUT_EVENT_POSITION )
320 321 322 323 324 325
    {
        if( var_GetInteger( p_input, "state" ) != PLAYING_S )
            return VLC_SUCCESS; /* Don't send the position while stopped */

        /* */
        event.type = libvlc_MediaPlayerPositionChanged;
JP Dinger's avatar
JP Dinger committed
326 327
        event.u.media_player_position_changed.new_position =
                                          var_GetFloat( p_input, "position" );
328 329 330 331
        libvlc_event_send( p_mi->p_event_manager, &event );

        /* */
        event.type = libvlc_MediaPlayerTimeChanged;
JP Dinger's avatar
JP Dinger committed
332
        event.u.media_player_time_changed.new_time =
333
           from_mtime(var_GetInteger( p_input, "time" ));
334 335
        libvlc_event_send( p_mi->p_event_manager, &event );
    }
336 337 338 339
    else if( newval.i_int == INPUT_EVENT_LENGTH )
    {
        event.type = libvlc_MediaPlayerLengthChanged;
        event.u.media_player_length_changed.new_length =
340
           from_mtime(var_GetInteger( p_input, "length" ));
341 342
        libvlc_event_send( p_mi->p_event_manager, &event );
    }
343 344 345 346 347 348 349
    else if( newval.i_int == INPUT_EVENT_CACHE )
    {
        event.type = libvlc_MediaPlayerBuffering;
        event.u.media_player_buffering.new_cache = (int)(100 *
            var_GetFloat( p_input, "cache" ));
        libvlc_event_send( p_mi->p_event_manager, &event );
    }
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
    else if( newval.i_int == INPUT_EVENT_VOUT )
    {
        vout_thread_t **pp_vout;
        size_t i_vout;
        if( input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) )
        {
            i_vout  = 0;
        }
        else
        {
            for( size_t i = 0; i < i_vout; i++ )
                vlc_object_release( pp_vout[i] );
            free( pp_vout );
        }

        event.type = libvlc_MediaPlayerVout;
        event.u.media_player_vout.new_count = i_vout;
        libvlc_event_send( p_mi->p_event_manager, &event );
    }
369 370 371 372 373 374
    else if ( newval.i_int == INPUT_EVENT_TITLE )
    {
        event.type = libvlc_MediaPlayerTitleChanged;
        event.u.media_player_title_changed.new_title = var_GetInteger( p_input, "title" );
        libvlc_event_send( p_mi->p_event_manager, &event );
    }
375 376 377 378 379 380
    else if ( newval.i_int == INPUT_EVENT_CHAPTER )
    {
        event.type = libvlc_MediaPlayerChapterChanged;
        event.u.media_player_chapter_changed.new_chapter = var_GetInteger( p_input, "chapter" );
        libvlc_event_send( p_mi->p_event_manager, &event );
    }
Laurent Aimar's avatar
Laurent Aimar committed
381

382 383 384
    return VLC_SUCCESS;
}

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
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;
}

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
/**************************************************************************
 * Snapshot Taken Event.
 *
 * FIXME: This snapshot API interface makes no sense in media_player.
 *************************************************************************/
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 )
{
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_this);

    libvlc_media_player_t *mp = p_data;
    libvlc_event_t event;
    event.type = libvlc_MediaPlayerSnapshotTaken;
    event.u.media_player_snapshot_taken.psz_filename = newval.psz_string;
    libvlc_event_send(mp->p_event_manager, &event);

    return VLC_SUCCESS;
}

483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
static int corks_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
                         vlc_value_t cur, void *opaque)
{
    libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;

    if (!old.i_int != !cur.i_int)
    {
        libvlc_event_t event;

        event.type = cur.i_int ? libvlc_MediaPlayerCorked
                               : libvlc_MediaPlayerUncorked;
        libvlc_event_send(mp->p_event_manager, &event);
    }
    VLC_UNUSED(name); VLC_UNUSED(opaque);
    return VLC_SUCCESS;
}

500 501 502 503 504 505 506 507 508 509 510 511 512
static int audio_device_changed(vlc_object_t *obj, const char *name,
                                vlc_value_t old, vlc_value_t cur, void *opaque)
{
    libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
    libvlc_event_t event;

    event.type = libvlc_MediaPlayerAudioDevice;
    event.u.media_player_audio_device.device = cur.psz_string;
    libvlc_event_send(mp->p_event_manager, &event);
    VLC_UNUSED(name); VLC_UNUSED(old); VLC_UNUSED(opaque);
    return VLC_SUCCESS;
}

513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
static int mute_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
                        vlc_value_t cur, void *opaque)
{
    libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;

    if (old.b_bool != cur.b_bool)
    {
        libvlc_event_t event;

        event.type = cur.b_bool ? libvlc_MediaPlayerMuted
                                : libvlc_MediaPlayerUnmuted;
        libvlc_event_send(mp->p_event_manager, &event);
    }
    VLC_UNUSED(name); VLC_UNUSED(opaque);
    return VLC_SUCCESS;
}

530 531 532 533 534 535 536 537 538 539 540 541 542
static int volume_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
                          vlc_value_t cur, void *opaque)
{
    libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
    libvlc_event_t event;

    event.type = libvlc_MediaPlayerAudioVolume;
    event.u.media_player_audio_volume.volume = cur.f_float;
    libvlc_event_send(mp->p_event_manager, &event);
    VLC_UNUSED(name); VLC_UNUSED(old); VLC_UNUSED(opaque);
    return VLC_SUCCESS;
}

543
/**************************************************************************
JP Dinger's avatar
JP Dinger committed
544 545 546 547 548 549 550 551 552 553 554 555
 * 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.
556
 **************************************************************************/
557
libvlc_media_player_t *
Rémi Denis-Courmont's avatar
good  
Rémi Denis-Courmont committed
558
libvlc_media_player_new( libvlc_instance_t *instance )
559
{
560
    libvlc_media_player_t * mp;
561

562
    assert(instance);
563

564 565
    mp = vlc_object_create (instance->p_libvlc_int, sizeof(*mp));
    if (unlikely(mp == NULL))
566
    {
567
        libvlc_printerr("Not enough memory");
568 569
        return NULL;
    }
570

571 572 573
    /* Input */
    var_Create (mp, "rate", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT);

574
    /* Video */
575
    var_Create (mp, "vout", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
576
    var_Create (mp, "window", VLC_VAR_STRING);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
577 578 579 580
    var_Create (mp, "vmem-lock", VLC_VAR_ADDRESS);
    var_Create (mp, "vmem-unlock", VLC_VAR_ADDRESS);
    var_Create (mp, "vmem-display", VLC_VAR_ADDRESS);
    var_Create (mp, "vmem-data", VLC_VAR_ADDRESS);
581 582
    var_Create (mp, "vmem-setup", VLC_VAR_ADDRESS);
    var_Create (mp, "vmem-cleanup", VLC_VAR_ADDRESS);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
583 584 585
    var_Create (mp, "vmem-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
    var_Create (mp, "vmem-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "vmem-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
586
    var_Create (mp, "vmem-pitch", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
587
    var_Create (mp, "avcodec-hw", VLC_VAR_STRING);
588
    var_Create (mp, "drawable-xid", VLC_VAR_INTEGER);
589
#if defined (_WIN32) || defined (__OS2__)
590
    var_Create (mp, "drawable-hwnd", VLC_VAR_INTEGER);
591 592 593 594
#endif
#ifdef __APPLE__
    var_Create (mp, "drawable-nsobject", VLC_VAR_ADDRESS);
#endif
595 596 597 598
#ifdef __ANDROID__
    var_Create (mp, "android-jvm", VLC_VAR_ADDRESS);
    var_Create (mp, "drawable-androidwindow", VLC_VAR_ADDRESS);
#endif
599 600 601
#ifdef HAVE_EVAS
    var_Create (mp, "drawable-evasobject", VLC_VAR_ADDRESS);
#endif
602 603 604 605

    var_Create (mp, "keyboard-events", VLC_VAR_BOOL);
    var_SetBool (mp, "keyboard-events", true);
    var_Create (mp, "mouse-events", VLC_VAR_BOOL);
606
    var_SetBool (mp, "mouse-events", true);
607

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
608
    var_Create (mp, "fullscreen", VLC_VAR_BOOL);
609 610
    var_Create (mp, "autoscale", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
    var_Create (mp, "zoom", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
611 612 613 614
    var_Create (mp, "aspect-ratio", VLC_VAR_STRING);
    var_Create (mp, "crop", VLC_VAR_STRING);
    var_Create (mp, "deinterlace", VLC_VAR_INTEGER);
    var_Create (mp, "deinterlace-mode", VLC_VAR_STRING);
615

616 617
    var_Create (mp, "vbi-page", VLC_VAR_INTEGER);
    var_SetInteger (mp, "vbi-page", 100);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
618

619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
    var_Create (mp, "marq-marquee", VLC_VAR_STRING);
    var_Create (mp, "marq-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "marq-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "marq-refresh", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "marq-size", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "marq-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "marq-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);

    var_Create (mp, "logo-file", VLC_VAR_STRING);
    var_Create (mp, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "logo-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "logo-repeat", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "logo-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);

637 638
    var_Create (mp, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
    var_Create (mp, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
639
    var_Create (mp, "hue", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
640 641 642
    var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
    var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
643
     /* Audio */
644
    var_Create (mp, "aout", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
645
    var_Create (mp, "audio-device", VLC_VAR_STRING);
646
    var_Create (mp, "mute", VLC_VAR_BOOL);
647
    var_Create (mp, "volume", VLC_VAR_FLOAT);
648
    var_Create (mp, "corks", VLC_VAR_INTEGER);
649
    var_Create (mp, "audio-filter", VLC_VAR_STRING);
650 651
    var_Create (mp, "amem-data", VLC_VAR_ADDRESS);
    var_Create (mp, "amem-setup", VLC_VAR_ADDRESS);
Sébastien Toque's avatar
Sébastien Toque committed
652
    var_Create (mp, "amem-cleanup", VLC_VAR_ADDRESS);
653
    var_Create (mp, "amem-play", VLC_VAR_ADDRESS);
654 655 656 657
    var_Create (mp, "amem-pause", VLC_VAR_ADDRESS);
    var_Create (mp, "amem-resume", VLC_VAR_ADDRESS);
    var_Create (mp, "amem-flush", VLC_VAR_ADDRESS);
    var_Create (mp, "amem-drain", VLC_VAR_ADDRESS);
658 659 660 661
    var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS);
    var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
    var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
662

663 664 665 666 667
    /* Video Title */
    var_Create (mp, "video-title-show", VLC_VAR_BOOL);
    var_Create (mp, "video-title-position", VLC_VAR_INTEGER);
    var_Create (mp, "video-title-timeout", VLC_VAR_INTEGER);

Mark Lee's avatar
Mark Lee committed
668 669
    /* Equalizer */
    var_Create (mp, "equalizer-preamp", VLC_VAR_FLOAT);
670
    var_Create (mp, "equalizer-vlcfreqs", VLC_VAR_BOOL);
Mark Lee's avatar
Mark Lee committed
671 672
    var_Create (mp, "equalizer-bands", VLC_VAR_STRING);

673
    mp->p_md = NULL;
674
    mp->state = libvlc_NothingSpecial;
675
    mp->p_libvlc_instance = instance;
676
    mp->input.p_thread = NULL;
677 678 679 680 681 682
    mp->input.p_resource = input_resource_New(VLC_OBJECT(mp));
    if (unlikely(mp->input.p_resource == NULL))
    {
        vlc_object_release(mp);
        return NULL;
    }
683 684 685 686
    audio_output_t *aout = input_resource_GetAout(mp->input.p_resource);
    if( aout != NULL )
        input_resource_PutAout(mp->input.p_resource, aout);

687
    vlc_mutex_init (&mp->input.lock);
688
    mp->i_refcount = 1;
689
    mp->p_event_manager = libvlc_event_manager_new(mp);
690
    if (unlikely(mp->p_event_manager == NULL))
691
    {
692
        input_resource_Release(mp->input.p_resource);
693
        vlc_object_release(mp);
694 695
        return NULL;
    }
696
    vlc_mutex_init(&mp->object_lock);
697

698
    var_AddCallback(mp, "corks", corks_changed, NULL);
699
    var_AddCallback(mp, "audio-device", audio_device_changed, NULL);
700
    var_AddCallback(mp, "mute", mute_changed, NULL);
701
    var_AddCallback(mp, "volume", volume_changed, NULL);
702

703 704
    /* Snapshot initialization */
    /* Attach a var callback to the global object to provide the glue between
705 706 707 708 709 710
     * vout_thread that generates the event and media_player that re-emits it
     * with its own event manager
     *
     * FIXME: It's unclear why we want to put this in public API, and why we
     * want to expose it in such a limiting and ugly way.
     */
711
    var_AddCallback(mp->p_libvlc, "snapshot-file", snapshot_was_taken, mp);
712

713
    libvlc_retain(instance);
714
    return mp;
715 716 717
}

/**************************************************************************
JP Dinger's avatar
JP Dinger committed
718
 * Create a Media Instance object with a media descriptor.
719
 **************************************************************************/
720
libvlc_media_player_t *
Rémi Denis-Courmont's avatar
good  
Rémi Denis-Courmont committed
721
libvlc_media_player_new_from_media( libvlc_media_t * p_md )
722
{
723
    libvlc_media_player_t * p_mi;
724

Rémi Denis-Courmont's avatar
good  
Rémi Denis-Courmont committed
725
    p_mi = libvlc_media_player_new( p_md->p_libvlc_instance );
726
    if( !p_mi )
727 728
        return NULL;

729
    libvlc_media_retain( p_md );
730
    p_mi->p_md = p_md;
731 732 733 734 735

    return p_mi;
}

/**************************************************************************
736
 * Destroy a Media Instance object (libvlc internal)
737
 *
JP Dinger's avatar
JP Dinger committed
738
 * Warning: No lock held here, but hey, this is internal. Caller must lock.
739
 **************************************************************************/
740
static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
741
{
742
    assert( p_mi );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
743

744
    /* Detach Callback from the main libvlc object */
745
    var_DelCallback( p_mi->p_libvlc,
746
                     "snapshot-file", snapshot_was_taken, p_mi );
747

748
    /* Detach callback from the media player / input manager object */
749
    var_DelCallback( p_mi, "volume", volume_changed, NULL );
750
    var_DelCallback( p_mi, "mute", mute_changed, NULL );
751
    var_DelCallback( p_mi, "audio-device", audio_device_changed, NULL );
752 753
    var_DelCallback( p_mi, "corks", corks_changed, NULL );

754 755
    /* No need for lock_input() because no other threads knows us anymore */
    if( p_mi->input.p_thread )
756
        release_input_thread(p_mi);
757 758
    input_resource_Terminate( p_mi->input.p_resource );
    input_resource_Release( p_mi->input.p_resource );
759
    vlc_mutex_destroy( &p_mi->input.lock );
760

761
    libvlc_event_manager_release( p_mi->p_event_manager );
762
    libvlc_media_release( p_mi->p_md );
763
    vlc_mutex_destroy( &p_mi->object_lock );
764 765

    libvlc_instance_t *instance = p_mi->p_libvlc_instance;
766
    vlc_object_release( p_mi );
767
    libvlc_release(instance);
768 769 770
}

/**************************************************************************
JP Dinger's avatar
JP Dinger committed
771 772 773
 * Release a Media Instance object.
 *
 * Function does the locking.
774
 **************************************************************************/
775
void libvlc_media_player_release( libvlc_media_player_t *p_mi )
776
{
777
    bool destroy;
778

779
    assert( p_mi );
780
    lock(p_mi);
781
    destroy = !--p_mi->i_refcount;
782
    unlock(p_mi);
783

784 785
    if( destroy )
        libvlc_media_player_destroy( p_mi );
786
}
787

788
/**************************************************************************
JP Dinger's avatar
JP Dinger committed
789 790 791
 * Retain a Media Instance object.
 *
 * Caller must hold the lock.
792
 **************************************************************************/
793
void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
794
{
795
    assert( p_mi );
796

797
    lock(p_mi);
798
    p_mi->i_refcount++;
799
    unlock(p_mi);
800
}
801

802
/**************************************************************************
JP Dinger's avatar
JP Dinger committed
803 804 805
 * Set the Media descriptor associated with the instance.
 *
 * Enter without lock -- function will lock the object.
806
 **************************************************************************/
807 808
void libvlc_media_player_set_media(
                            libvlc_media_player_t *p_mi,
809
                            libvlc_media_t *p_md )
810
{
811
    lock_input(p_mi);
812

813
    release_input_thread( p_mi );
814

815
    lock( p_mi );
816
    set_state( p_mi, libvlc_NothingSpecial, true );
817
    unlock_input( p_mi );
818

819
    libvlc_media_release( p_mi->p_md );
820

821 822 823
    if( !p_md )
    {
        p_mi->p_md = NULL;
824
        unlock(p_mi);
825 826 827
        return; /* It is ok to pass a NULL md */
    }

828
    libvlc_media_retain( p_md );
829
    p_mi->p_md = p_md;
830

831 832 833 834
    /* 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;

835
    unlock(p_mi);
836 837 838 839 840 841

    /* Send an event for the newly available media */
    libvlc_event_t event;
    event.type = libvlc_MediaPlayerMediaChanged;
    event.u.media_player_media_changed.new_media = p_md;
    libvlc_event_send( p_mi->p_event_manager, &event );
842

843 844 845
}

/**************************************************************************
JP Dinger's avatar
JP Dinger committed
846
 * Get the Media descriptor associated with the instance.
847
 **************************************************************************/
848
libvlc_media_t *
849
libvlc_media_player_get_media( libvlc_media_player_t *p_mi )
850
{
851
    libvlc_media_t *p_m;
852

853
    lock( p_mi );
854 855
    p_m = p_mi->p_md;
    if( p_m )
856 857 858 859
        libvlc_media_retain( p_m );
    unlock( p_mi );

    return p_m;
860 861
}

862
/**************************************************************************
JP Dinger's avatar
JP Dinger committed
863
 * Get the event Manager.
864 865
 **************************************************************************/
libvlc_event_manager_t *
866
libvlc_media_player_event_manager( libvlc_media_player_t *p_mi )
867 868 869 870
{
    return p_mi->p_event_manager;
}

871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
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 );
}

891
/**************************************************************************
JP Dinger's avatar
JP Dinger committed
892
 * Tell media player to start playing.
893
 **************************************************************************/
Rémi Denis-Courmont's avatar
good  
Rémi Denis-Courmont committed
894
int libvlc_media_player_play( libvlc_media_player_t *p_mi )
895
{
896
    lock_input( p_mi );
897

898 899
    input_thread_t *p_input_thread = p_mi->input.p_thread;
    if( p_input_thread )
900
    {
Sam Hocevar's avatar
Sam Hocevar committed
901
        /* A thread already exists, send it a play message */
902
        input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
903
        unlock_input( p_mi );
Rémi Denis-Courmont's avatar
good  
Rémi Denis-Courmont committed
904
        return 0;
905 906
    }

907
    /* Ignore previous exception */
908
    lock(p_mi);
909

910 911
    if( !p_mi->p_md )
    {
912
        unlock(p_mi);
913
        unlock_input( p_mi );
914
        libvlc_printerr( "No associated media descriptor" );
Rémi Denis-Courmont's avatar
good  
Rémi Denis-Courmont committed
915
        return -1;
916 917
    }

918 919 920 921
    p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL,
                                   p_mi->input.p_resource );
    unlock(p_mi);
    if( !p_input_thread )
922
    {
923
        unlock_input(p_mi);
Rémi Denis-Courmont's avatar
good  
Rémi Denis-Courmont committed
924 925
        libvlc_printerr( "Not enough memory" );
        return -1;
926
    }
927

928 929
    var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
    var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
930
    var_AddCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
Laurent Aimar's avatar
Laurent Aimar committed
931
    var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
932
    add_es_callbacks( p_input_thread, p_mi );
933

934 935
    if( input_Start( p_input_thread ) )
    {
936
        unlock_input(p_mi);
937
        del_es_callbacks( p_input_thread, p_mi );
938 939
        var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
        var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
940