media.c 43.4 KB
Newer Older
1
/*****************************************************************************
2
 * media.c: Libvlc API media descripor management
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2007 VLC authors and VideoLAN
5 6 7 8
 * $Id$
 *
 * Authors: Pierre d'Herbemont <pdherbemont@videolan.org>
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
9 10 11
 * 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
12 13 14 15
 * (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
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
19 20 21
 * 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.
22 23
 *****************************************************************************/

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

28
#include <assert.h>
29
#include <errno.h>
30

31
#include <vlc/libvlc.h>
32 33 34 35 36
#include <vlc/libvlc_media.h>
#include <vlc/libvlc_media_list.h> // For the subitems, here for convenience
#include <vlc/libvlc_events.h>

#include <vlc_common.h>
37 38
#include <vlc_input.h>
#include <vlc_meta.h>
39
#include <vlc_playlist.h> /* For the preparser */
40
#include <vlc_url.h>
41

42
#include "../src/libvlc.h"
43 44 45

#include "libvlc_internal.h"
#include "media_internal.h"
46
#include "media_list_internal.h"
47

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
static const vlc_meta_type_t libvlc_to_vlc_meta[] =
{
    [libvlc_meta_Title]        = vlc_meta_Title,
    [libvlc_meta_Artist]       = vlc_meta_Artist,
    [libvlc_meta_Genre]        = vlc_meta_Genre,
    [libvlc_meta_Copyright]    = vlc_meta_Copyright,
    [libvlc_meta_Album]        = vlc_meta_Album,
    [libvlc_meta_TrackNumber]  = vlc_meta_TrackNumber,
    [libvlc_meta_Description]  = vlc_meta_Description,
    [libvlc_meta_Rating]       = vlc_meta_Rating,
    [libvlc_meta_Date]         = vlc_meta_Date,
    [libvlc_meta_Setting]      = vlc_meta_Setting,
    [libvlc_meta_URL]          = vlc_meta_URL,
    [libvlc_meta_Language]     = vlc_meta_Language,
    [libvlc_meta_NowPlaying]   = vlc_meta_NowPlaying,
    [libvlc_meta_Publisher]    = vlc_meta_Publisher,
    [libvlc_meta_EncodedBy]    = vlc_meta_EncodedBy,
    [libvlc_meta_ArtworkURL]   = vlc_meta_ArtworkURL,
66 67 68 69 70 71
    [libvlc_meta_TrackID]      = vlc_meta_TrackID,
    [libvlc_meta_TrackTotal]   = vlc_meta_TrackTotal,
    [libvlc_meta_Director]     = vlc_meta_Director,
    [libvlc_meta_Season]       = vlc_meta_Season,
    [libvlc_meta_Episode]      = vlc_meta_Episode,
    [libvlc_meta_ShowName]     = vlc_meta_ShowName,
72
    [libvlc_meta_Actors]       = vlc_meta_Actors,
73
    [libvlc_meta_AlbumArtist]  = vlc_meta_AlbumArtist,
74 75
    [libvlc_meta_DiscNumber]   = vlc_meta_DiscNumber,
    [libvlc_meta_DiscTotal]    = vlc_meta_DiscTotal
76 77
};

78
static const libvlc_meta_t vlc_to_libvlc_meta[] =
79 80 81 82 83 84 85 86 87 88 89 90 91 92
{
    [vlc_meta_Title]        = libvlc_meta_Title,
    [vlc_meta_Artist]       = libvlc_meta_Artist,
    [vlc_meta_Genre]        = libvlc_meta_Genre,
    [vlc_meta_Copyright]    = libvlc_meta_Copyright,
    [vlc_meta_Album]        = libvlc_meta_Album,
    [vlc_meta_TrackNumber]  = libvlc_meta_TrackNumber,
    [vlc_meta_Description]  = libvlc_meta_Description,
    [vlc_meta_Rating]       = libvlc_meta_Rating,
    [vlc_meta_Date]         = libvlc_meta_Date,
    [vlc_meta_Setting]      = libvlc_meta_Setting,
    [vlc_meta_URL]          = libvlc_meta_URL,
    [vlc_meta_Language]     = libvlc_meta_Language,
    [vlc_meta_NowPlaying]   = libvlc_meta_NowPlaying,
93
    [vlc_meta_ESNowPlaying] = libvlc_meta_NowPlaying,
94 95 96
    [vlc_meta_Publisher]    = libvlc_meta_Publisher,
    [vlc_meta_EncodedBy]    = libvlc_meta_EncodedBy,
    [vlc_meta_ArtworkURL]   = libvlc_meta_ArtworkURL,
97 98 99 100 101 102
    [vlc_meta_TrackID]      = libvlc_meta_TrackID,
    [vlc_meta_TrackTotal]   = libvlc_meta_TrackTotal,
    [vlc_meta_Director]     = libvlc_meta_Director,
    [vlc_meta_Season]       = libvlc_meta_Season,
    [vlc_meta_Episode]      = libvlc_meta_Episode,
    [vlc_meta_ShowName]     = libvlc_meta_ShowName,
103
    [vlc_meta_Actors]       = libvlc_meta_Actors,
104
    [vlc_meta_AlbumArtist]  = libvlc_meta_AlbumArtist,
105 106
    [vlc_meta_DiscNumber]   = libvlc_meta_DiscNumber,
    [vlc_meta_DiscTotal]    = libvlc_meta_DiscTotal
107 108
};

109 110 111 112 113 114 115 116 117 118 119
static_assert(
    ORIENT_TOP_LEFT     == (int) libvlc_video_orient_top_left &&
    ORIENT_TOP_RIGHT    == (int) libvlc_video_orient_top_right &&
    ORIENT_BOTTOM_LEFT  == (int) libvlc_video_orient_bottom_left &&
    ORIENT_BOTTOM_RIGHT == (int) libvlc_video_orient_bottom_right &&
    ORIENT_LEFT_TOP     == (int) libvlc_video_orient_left_top &&
    ORIENT_LEFT_BOTTOM  == (int) libvlc_video_orient_left_bottom &&
    ORIENT_RIGHT_TOP    == (int) libvlc_video_orient_right_top &&
    ORIENT_RIGHT_BOTTOM == (int) libvlc_video_orient_right_bottom,
    "Mismatch between libvlc_video_orient_t and video_orientation_t" );

120 121 122 123 124 125
static_assert(
    PROJECTION_MODE_RECTANGULAR             == (int) libvlc_video_projection_rectangular &&
    PROJECTION_MODE_EQUIRECTANGULAR         == (int) libvlc_video_projection_equirectangular &&
    PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD == (int) libvlc_video_projection_cubemap_layout_standard,
    "Mismatch between libvlc_video_projection_t and video_projection_mode_t" );

126 127
static libvlc_media_list_t *media_get_subitems( libvlc_media_t * p_md,
                                                bool b_create )
128 129 130 131
{
    libvlc_media_list_t *p_subitems = NULL;

    vlc_mutex_lock( &p_md->subitems_lock );
132
    if( p_md->p_subitems == NULL && b_create )
133 134 135
    {
        p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance );
        if( p_md->p_subitems != NULL )
136 137
        {
            p_md->p_subitems->b_read_only = true;
138
            p_md->p_subitems->p_internal_md = p_md;
139
        }
140 141 142 143 144 145
    }
    p_subitems = p_md->p_subitems;
    vlc_mutex_unlock( &p_md->subitems_lock );
    return p_subitems;
}

146 147
static libvlc_media_t *input_item_add_subitem( libvlc_media_t *p_md,
                                               input_item_t *item )
148
{
149
    libvlc_media_t * p_md_child;
150
    libvlc_media_list_t *p_subitems;
151 152
    libvlc_event_t event;

153 154
    p_md_child = libvlc_media_new_from_input_item( p_md->p_libvlc_instance,
                                                   item );
155

156
    /* Add this to our media list */
157
    p_subitems = media_get_subitems( p_md, true );
158
    if( p_subitems != NULL )
159 160
    {
        libvlc_media_list_lock( p_subitems );
161
        libvlc_media_list_internal_add_media( p_subitems, p_md_child );
162 163
        libvlc_media_list_unlock( p_subitems );
    }
164

165
    /* Construct the event */
166
    event.type = libvlc_MediaSubItemAdded;
167
    event.u.media_subitem_added.new_child = p_md_child;
168 169

    /* Send the event */
170
    libvlc_event_send( &p_md->event_manager, &event );
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
    return p_md_child;
}

static void input_item_add_subnode( libvlc_media_t *md,
                                    input_item_node_t *node )
{
    for( int i = 0; i < node->i_children; i++ )
    {
        input_item_node_t *child = node->pp_children[i];
        libvlc_media_t *md_child = input_item_add_subitem( md, child->p_item );

        if( md_child != NULL )
        {
            input_item_add_subnode( md_child, child );
            libvlc_media_release( md_child );
        }
    }
188 189
}

190 191 192 193 194 195 196 197
/**************************************************************************
 * input_item_subitemtree_added (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_subitemtree_added( const vlc_event_t * p_event,
                                          void * user_data )
{
    libvlc_media_t * p_md = user_data;
    libvlc_event_t event;
198 199 200 201 202 203 204
    input_item_node_t *node = p_event->u.input_item_subitem_tree_added.p_root;

    /* FIXME FIXME FIXME
     * Recursive function calls seem much simpler for this. But playlists are
     * untrusted and can be arbitrarily deep (e.g. with XSPF). So recursion can
     * potentially lead to plain old stack overflow. */
    input_item_add_subnode( p_md, node );
205 206 207 208 209 210

    /* Construct the event */
    event.type = libvlc_MediaSubItemTreeAdded;
    event.u.media_subitemtree_added.item = p_md;

    /* Send the event */
211
    libvlc_event_send( &p_md->event_manager, &event );
212 213
}

214 215 216 217 218 219
/**************************************************************************
 * input_item_meta_changed (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_meta_changed( const vlc_event_t *p_event,
                                     void * user_data )
{
220
    libvlc_media_t * p_md = user_data;
221 222 223
    libvlc_event_t event;

    /* Construct the event */
224
    event.type = libvlc_MediaMetaChanged;
225
    event.u.media_meta_changed.meta_type =
226 227 228
        vlc_to_libvlc_meta[p_event->u.input_item_meta_changed.meta_type];

    /* Send the event */
229
    libvlc_event_send( &p_md->event_manager, &event );
230 231
}

232 233 234 235 236 237
/**************************************************************************
 * input_item_duration_changed (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_duration_changed( const vlc_event_t *p_event,
                                         void * user_data )
{
238
    libvlc_media_t * p_md = user_data;
239 240 241
    libvlc_event_t event;

    /* Construct the event */
242
    event.type = libvlc_MediaDurationChanged;
243 244
    event.u.media_duration_changed.new_duration =
        from_mtime(p_event->u.input_item_duration_changed.new_duration);
245 246

    /* Send the event */
247
    libvlc_event_send( &p_md->event_manager, &event );
248 249
}

250 251
static void send_parsed_changed( libvlc_media_t *p_md,
                                 libvlc_media_parsed_status_t new_status )
252 253 254
{
    libvlc_event_t event;

255 256
    vlc_mutex_lock( &p_md->parsed_lock );
    if( p_md->parsed_status == new_status )
257
    {
258
        vlc_mutex_unlock( &p_md->parsed_lock );
259 260
        return;
    }
261

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
    /* Legacy: notify libvlc_media_parse */
    if( !p_md->is_parsed )
    {
        p_md->is_parsed = true;
        vlc_cond_broadcast( &p_md->parsed_cond );
    }

    p_md->parsed_status = new_status;
    if( p_md->parsed_status == libvlc_media_parsed_status_skipped )
        p_md->has_asked_preparse = false;

    vlc_mutex_unlock( &p_md->parsed_lock );

    if( new_status == libvlc_media_parsed_status_done )
    {
        libvlc_media_list_t *p_subitems = media_get_subitems( p_md, false );
        if( p_subitems != NULL )
        {
            /* notify the media list */
            libvlc_media_list_lock( p_subitems );
            libvlc_media_list_internal_end_reached( p_subitems );
            libvlc_media_list_unlock( p_subitems );
        }
    }
286

287
    /* Construct the event */
288
    event.type = libvlc_MediaParsedChanged;
289
    event.u.media_parsed_changed.new_status = new_status;
290 291

    /* Send the event */
292
    libvlc_event_send( &p_md->event_manager, &event );
293 294
}

295 296 297 298 299 300 301
/**************************************************************************
 * input_item_preparse_ended (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_preparse_ended( const vlc_event_t * p_event,
                                       void * user_data )
{
    libvlc_media_t * p_md = user_data;
302
    libvlc_media_parsed_status_t new_status;
303

304
    switch( p_event->u.input_item_preparse_ended.new_status )
305 306
    {
        case ITEM_PREPARSE_SKIPPED:
307
            new_status = libvlc_media_parsed_status_skipped;
308 309
            break;
        case ITEM_PREPARSE_FAILED:
310
            new_status = libvlc_media_parsed_status_failed;
311
            break;
312 313 314
        case ITEM_PREPARSE_TIMEOUT:
            new_status = libvlc_media_parsed_status_timeout;
            break;
315
        case ITEM_PREPARSE_DONE:
316
            new_status = libvlc_media_parsed_status_done;
317
            break;
318 319
        default:
            return;
320
    }
321
    send_parsed_changed( p_md, new_status );
322 323
}

324 325 326
/**************************************************************************
 * Install event handler (Private)
 **************************************************************************/
327
static void install_input_item_observer( libvlc_media_t *p_md )
328 329 330 331 332
{
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemMetaChanged,
                      input_item_meta_changed,
                      p_md );
333 334 335 336
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemDurationChanged,
                      input_item_duration_changed,
                      p_md );
337 338 339 340
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemTreeAdded,
                      input_item_subitemtree_added,
                      p_md );
341 342 343 344
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemPreparseEnded,
                      input_item_preparse_ended,
                      p_md );
345 346 347 348 349
}

/**************************************************************************
 * Uninstall event handler (Private)
 **************************************************************************/
350
static void uninstall_input_item_observer( libvlc_media_t *p_md )
351 352 353 354 355
{
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemMetaChanged,
                      input_item_meta_changed,
                      p_md );
356 357 358 359
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemDurationChanged,
                      input_item_duration_changed,
                      p_md );
360 361 362 363
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemTreeAdded,
                      input_item_subitemtree_added,
                      p_md );
364 365 366 367
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemPreparseEnded,
                      input_item_preparse_ended,
                      p_md );
368
}
369 370

/**************************************************************************
371 372 373
 * Create a new media descriptor object from an input_item
 * (libvlc internal)
 * That's the generic constructor
374
 **************************************************************************/
375
libvlc_media_t * libvlc_media_new_from_input_item(
376
                                   libvlc_instance_t *p_instance,
377
                                   input_item_t *p_input_item )
378
{
379
    libvlc_media_t * p_md;
380 381

    if (!p_input_item)
382
    {
383
        libvlc_printerr( "No input item given" );
384 385
        return NULL;
    }
386

387
    p_md = calloc( 1, sizeof(libvlc_media_t) );
388 389
    if( !p_md )
    {
390
        libvlc_printerr( "Not enough memory" );
391 392 393
        return NULL;
    }

394 395
    p_md->p_libvlc_instance = p_instance;
    p_md->p_input_item      = p_input_item;
396
    p_md->i_refcount        = 1;
397

398 399
    vlc_cond_init(&p_md->parsed_cond);
    vlc_mutex_init(&p_md->parsed_lock);
400
    vlc_mutex_init(&p_md->subitems_lock);
401

402
    p_md->state = libvlc_NothingSpecial;
403

404 405 406 407
    /* A media descriptor can be a playlist. When you open a playlist
     * It can give a bunch of item to read. */
    p_md->p_subitems        = NULL;

408
    libvlc_event_manager_init( &p_md->event_manager, p_md );
409

410
    input_item_Hold( p_md->p_input_item );
411

412 413
    install_input_item_observer( p_md );

414
    libvlc_retain( p_instance );
415
    return p_md;
416 417
}

418
/**************************************************************************
419
 * Create a new media descriptor object
420
 **************************************************************************/
421 422
libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance,
                                           const char * psz_mrl )
423
{
424
    input_item_t * p_input_item;
425
    libvlc_media_t * p_md;
426

427
    p_input_item = input_item_New( psz_mrl, NULL );
428

429
    if (!p_input_item)
430
    {
431
        libvlc_printerr( "Not enough memory" );
432 433
        return NULL;
    }
434

435
    p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
436

437
    /* The p_input_item is retained in libvlc_media_new_from_input_item */
438
    input_item_Release( p_input_item );
439

440
    return p_md;
441 442
}

443 444 445
libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance,
                                       const char *path )
{
446
    char *mrl = vlc_path2uri( path, NULL );
447 448
    if( unlikely(mrl == NULL) )
    {
449
        libvlc_printerr( "%s", vlc_strerror_c(errno) );
450 451 452 453 454 455 456 457
        return NULL;
    }

    libvlc_media_t *m = libvlc_media_new_location( p_instance, mrl );
    free( mrl );
    return m;
}

458 459 460 461 462 463 464 465
libvlc_media_t *libvlc_media_new_fd( libvlc_instance_t *p_instance, int fd )
{
    char mrl[16];
    snprintf( mrl, sizeof(mrl), "fd://%d", fd );

    return libvlc_media_new_location( p_instance, mrl );
}

466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
libvlc_media_t *libvlc_media_new_callbacks(libvlc_instance_t *p_instance,
                                           libvlc_media_open_cb open_cb,
                                           libvlc_media_read_cb read_cb,
                                           libvlc_media_seek_cb seek_cb,
                                           libvlc_media_close_cb close_cb,
                                           void *opaque)
{
    libvlc_media_t *m = libvlc_media_new_location(p_instance, "imem://");
    if (unlikely(m == NULL))
        return NULL;

    assert(read_cb != NULL);
    input_item_AddOpaque(m->p_input_item, "imem-data", opaque);
    input_item_AddOpaque(m->p_input_item, "imem-open", open_cb);
    input_item_AddOpaque(m->p_input_item, "imem-read", read_cb);
    input_item_AddOpaque(m->p_input_item, "imem-seek", seek_cb);
    input_item_AddOpaque(m->p_input_item, "imem-close", close_cb);
    return m;
}

486 487 488
/**************************************************************************
 * Create a new media descriptor object
 **************************************************************************/
489 490
libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance,
                                           const char * psz_name )
491 492
{
    input_item_t * p_input_item;
493
    libvlc_media_t * p_md;
494
    libvlc_media_list_t * p_subitems;
495

496
    p_input_item = input_item_New( "vlc://nop", psz_name );
497 498 499

    if (!p_input_item)
    {
500
        libvlc_printerr( "Not enough memory" );
501 502 503
        return NULL;
    }

504
    p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
505
    input_item_Release( p_input_item );
506

507
    p_subitems = media_get_subitems( p_md, true );
508 509 510 511
    if( p_subitems == NULL) {
        libvlc_media_release( p_md );
        return NULL;
    }
512 513 514 515

    return p_md;
}

516 517
/**************************************************************************
 * Add an option to the media descriptor,
518 519
 * that will be used to determine how the media_player will read the
 * media. This allow to use VLC advanced reading/streaming
520 521 522 523
 * options in a per-media basis
 *
 * The options are detailled in vlc --long-help, for instance "--sout-all"
 **************************************************************************/
524 525
void libvlc_media_add_option( libvlc_media_t * p_md,
                              const char * psz_option )
526
{
527
    libvlc_media_add_option_flag( p_md, psz_option,
528
                          VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED );
529 530
}

531
/**************************************************************************
532
 * Same as libvlc_media_add_option but with configurable flags.
533
 **************************************************************************/
534
void libvlc_media_add_option_flag( libvlc_media_t * p_md,
535
                                   const char * ppsz_option,
536
                                   unsigned i_flags )
537
{
538
    input_item_AddOption( p_md->p_input_item, ppsz_option, i_flags );
539 540
}

541 542 543
/**************************************************************************
 * Delete a media descriptor object
 **************************************************************************/
544
void libvlc_media_release( libvlc_media_t *p_md )
545
{
546
    if (!p_md)
547 548
        return;

549 550 551 552
    p_md->i_refcount--;

    if( p_md->i_refcount > 0 )
        return;
553

554 555
    uninstall_input_item_observer( p_md );

556
    /* Cancel asynchronous parsing (if any) */
557
    libvlc_MetadataCancel( p_md->p_libvlc_instance->p_libvlc_int, p_md );
558

559 560
    if( p_md->p_subitems )
        libvlc_media_list_release( p_md->p_subitems );
561

562
    input_item_Release( p_md->p_input_item );
563

564 565
    vlc_cond_destroy( &p_md->parsed_cond );
    vlc_mutex_destroy( &p_md->parsed_lock );
566
    vlc_mutex_destroy( &p_md->subitems_lock );
567

568 569
    /* Construct the event */
    libvlc_event_t event;
570
    event.type = libvlc_MediaFreed;
571
    event.u.media_freed.md = p_md;
572 573

    /* Send the event */
574
    libvlc_event_send( &p_md->event_manager, &event );
575

576
    libvlc_event_manager_destroy( &p_md->event_manager );
577
    libvlc_release( p_md->p_libvlc_instance );
578 579 580 581
    free( p_md );
}

/**************************************************************************
582 583
 * Retain a media descriptor object
 **************************************************************************/
584
void libvlc_media_retain( libvlc_media_t *p_md )
585
{
586
    assert (p_md);
587 588 589 590 591
    p_md->i_refcount++;
}

/**************************************************************************
 * Duplicate a media descriptor object
592
 **************************************************************************/
593 594
libvlc_media_t *
libvlc_media_duplicate( libvlc_media_t *p_md_orig )
595
{
596
    return libvlc_media_new_from_input_item(
597
        p_md_orig->p_libvlc_instance, p_md_orig->p_input_item );
598 599
}

600
/**************************************************************************
601
 * Get mrl from a media descriptor object
602 603
 **************************************************************************/
char *
604
libvlc_media_get_mrl( libvlc_media_t * p_md )
605
{
606
    assert( p_md );
607
    return input_item_GetURI( p_md->p_input_item );
608 609
}

610
/**************************************************************************
611
 * Getter for meta information
612 613
 **************************************************************************/

614
char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta )
615
{
616
    char *psz_meta = NULL;
617

618 619 620 621 622 623 624 625 626 627 628 629 630
    if( e_meta == libvlc_meta_NowPlaying )
    {
        psz_meta = input_item_GetNowPlayingFb( p_md->p_input_item );
    }
    else
    {
        psz_meta = input_item_GetMeta( p_md->p_input_item,
                                             libvlc_to_vlc_meta[e_meta] );
        /* Should be integrated in core */
        if( psz_meta == NULL && e_meta == libvlc_meta_Title
         && p_md->p_input_item->psz_name != NULL )
            psz_meta = strdup( p_md->p_input_item->psz_name );
    }
631
    return psz_meta;
632
}
633

634 635 636 637 638 639 640 641 642 643 644 645 646
/**************************************************************************
 * Setter for meta information
 **************************************************************************/

void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const char *psz_value )
{
    assert( p_md );
    input_item_SetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta], psz_value );
}

int libvlc_media_save_meta( libvlc_media_t *p_md )
{
    assert( p_md );
647
    vlc_object_t *p_obj = VLC_OBJECT(p_md->p_libvlc_instance->p_libvlc_int);
648 649 650
    return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS;
}

651 652 653 654 655
/**************************************************************************
 * Getter for state information
 * Can be error, playing, buffering, NothingSpecial.
 **************************************************************************/

656
libvlc_state_t
657
libvlc_media_get_state( libvlc_media_t *p_md )
658
{
659
    assert( p_md );
660 661 662 663 664 665 666 667
    return p_md->state;
}

/**************************************************************************
 * Setter for state information (LibVLC Internal)
 **************************************************************************/

void
668
libvlc_media_set_state( libvlc_media_t *p_md,
669
                                   libvlc_state_t state )
670 671 672 673 674 675
{
    libvlc_event_t event;

    p_md->state = state;

    /* Construct the event */
676
    event.type = libvlc_MediaStateChanged;
677
    event.u.media_state_changed.new_state = state;
678 679

    /* Send the event */
680
    libvlc_event_send( &p_md->event_manager, &event );
681 682
}

683 684 685 686
/**************************************************************************
 * subitems
 **************************************************************************/
libvlc_media_list_t *
687
libvlc_media_subitems( libvlc_media_t * p_md )
688
{
689
    libvlc_media_list_t *p_subitems = media_get_subitems( p_md, true );
690 691 692
    if( p_subitems )
        libvlc_media_list_retain( p_subitems );
    return p_subitems;
693
}
694

695
/**************************************************************************
Rémi Duraffort's avatar
Rémi Duraffort committed
696
 * Getter for statistics information
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
 **************************************************************************/
int libvlc_media_get_stats( libvlc_media_t *p_md,
                            libvlc_media_stats_t *p_stats )
{
    if( !p_md->p_input_item )
        return false;

    input_stats_t *p_itm_stats = p_md->p_input_item->p_stats;
    vlc_mutex_lock( &p_itm_stats->lock );
    p_stats->i_read_bytes = p_itm_stats->i_read_bytes;
    p_stats->f_input_bitrate = p_itm_stats->f_input_bitrate;

    p_stats->i_demux_read_bytes = p_itm_stats->i_demux_read_bytes;
    p_stats->f_demux_bitrate = p_itm_stats->f_demux_bitrate;
    p_stats->i_demux_corrupted = p_itm_stats->i_demux_corrupted;
    p_stats->i_demux_discontinuity = p_itm_stats->i_demux_discontinuity;

    p_stats->i_decoded_video = p_itm_stats->i_decoded_video;
    p_stats->i_decoded_audio = p_itm_stats->i_decoded_audio;

    p_stats->i_displayed_pictures = p_itm_stats->i_displayed_pictures;
    p_stats->i_lost_pictures = p_itm_stats->i_lost_pictures;

    p_stats->i_played_abuffers = p_itm_stats->i_played_abuffers;
    p_stats->i_lost_abuffers = p_itm_stats->i_lost_abuffers;

    p_stats->i_sent_packets = p_itm_stats->i_sent_packets;
    p_stats->i_sent_bytes = p_itm_stats->i_sent_bytes;
    p_stats->f_send_bitrate = p_itm_stats->f_send_bitrate;
    vlc_mutex_unlock( &p_itm_stats->lock );
    return true;
}

730 731 732 733
/**************************************************************************
 * event_manager
 **************************************************************************/
libvlc_event_manager_t *
734
libvlc_media_event_manager( libvlc_media_t * p_md )
735
{
736
    assert( p_md );
737

738
    return &p_md->event_manager;
739
}
740 741

/**************************************************************************
742
 * Get duration of media object (in ms)
743
 **************************************************************************/
744
int64_t
745
libvlc_media_get_duration( libvlc_media_t * p_md )
746
{
747
    assert( p_md );
748

749
    if( !p_md->p_input_item )
750
    {
751
        libvlc_printerr( "No input item" );
752 753
        return -1;
    }
754

755 756 757
    if (!input_item_IsPreparsed( p_md->p_input_item ))
        return -1;

758
    return from_mtime(input_item_GetDuration( p_md->p_input_item ));
759 760
}

761
static int media_parse(libvlc_media_t *media, bool b_async,
762
                       libvlc_media_parse_flag_t parse_flag, int timeout)
763
{
764 765 766 767 768
    bool needed;

    vlc_mutex_lock(&media->parsed_lock);
    needed = !media->has_asked_preparse;
    media->has_asked_preparse = true;
769 770
    if (needed)
        media->is_parsed = false;
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    vlc_mutex_unlock(&media->parsed_lock);

    if (needed)
    {
        libvlc_int_t *libvlc = media->p_libvlc_instance->p_libvlc_int;
        input_item_t *item = media->p_input_item;
        input_item_meta_request_option_t art_scope = META_REQUEST_OPTION_NONE;
        input_item_meta_request_option_t parse_scope = META_REQUEST_OPTION_SCOPE_LOCAL;
        int ret;

        if (parse_flag & libvlc_media_fetch_local)
            art_scope |= META_REQUEST_OPTION_SCOPE_LOCAL;
        if (parse_flag & libvlc_media_fetch_network)
            art_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
        if (art_scope != META_REQUEST_OPTION_NONE) {
            ret = libvlc_ArtRequest(libvlc, item, art_scope);
            if (ret != VLC_SUCCESS)
                return ret;
        }
790

791 792
        if (parse_flag & libvlc_media_parse_network)
            parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
793 794
        if (parse_flag & libvlc_media_do_interact)
            parse_scope |= META_REQUEST_OPTION_DO_INTERACT;
795
        ret = libvlc_MetadataRequest(libvlc, item, parse_scope, timeout, media);
796 797 798 799 800 801 802 803 804 805 806 807 808 809
        if (ret != VLC_SUCCESS)
            return ret;
    }
    else
        return VLC_EGENERIC;

    if (!b_async)
    {
        vlc_mutex_lock(&media->parsed_lock);
        while (!media->is_parsed)
            vlc_cond_wait(&media->parsed_cond, &media->parsed_lock);
        vlc_mutex_unlock(&media->parsed_lock);
    }
    return VLC_SUCCESS;
810 811
}

812
/**************************************************************************
813
 * Parse the media and wait.
814 815 816 817
 **************************************************************************/
void
libvlc_media_parse(libvlc_media_t *media)
{
818
    media_parse( media, false, libvlc_media_fetch_local, -1 );
819 820 821
}

/**************************************************************************
822
 * Parse the media but do not wait.
823 824 825 826
 **************************************************************************/
void
libvlc_media_parse_async(libvlc_media_t *media)
{
827
    media_parse( media, true, libvlc_media_fetch_local, -1 );
828
}
829

830 831 832 833 834
/**************************************************************************
 * Parse the media asynchronously with options.
 **************************************************************************/
int
libvlc_media_parse_with_options( libvlc_media_t *media,
835 836
                                 libvlc_media_parse_flag_t parse_flag,
                                 int timeout )
837
{
838
    return media_parse( media, true, parse_flag, timeout ) == VLC_SUCCESS ? 0 : -1;
839 840
}

841 842 843 844 845 846
void
libvlc_media_parse_stop( libvlc_media_t *media )
{
    libvlc_MetadataCancel( media->p_libvlc_instance->p_libvlc_int, media );
}

847
/**************************************************************************
848
 * Get parsed status for media object.
849
 **************************************************************************/
850
int
851
libvlc_media_is_parsed(libvlc_media_t *media)
852
{
853
    bool parsed;
854

855 856 857 858
    vlc_mutex_lock(&media->parsed_lock);
    parsed = media->is_parsed;
    vlc_mutex_unlock(&media->parsed_lock);
    return parsed;
859 860
}

861 862 863 864 865 866 867 868 869 870 871
libvlc_media_parsed_status_t
libvlc_media_get_parsed_status(libvlc_media_t *media)
{
    libvlc_media_parsed_status_t status;

    vlc_mutex_lock(&media->parsed_lock);
    status = media->parsed_status;
    vlc_mutex_unlock(&media->parsed_lock);
    return status;
}

872
/**************************************************************************
Pierre's avatar
Pierre committed
873 874
 * Sets media descriptor's user_data. user_data is specialized data
 * accessed by the host application, VLC.framework uses it as a pointer to
875
 * an native object that references a libvlc_media_t pointer
876
 **************************************************************************/
Pierre's avatar
Pierre committed
877
void
878
libvlc_media_set_user_data( libvlc_media_t * p_md, void * p_new_user_data )
879
{
880 881
    assert( p_md );
    p_md->p_user_data = p_new_user_data;
882 883 884
}

/**************************************************************************
Pierre's avatar
Pierre committed
885 886
 * Get media descriptor's user_data. user_data is specialized data
 * accessed by the host application, VLC.framework uses it as a pointer to
887
 * an native object that references a libvlc_media_t pointer
888 889
 **************************************************************************/
void *
890
libvlc_media_get_user_data( libvlc_media_t * p_md )
891
{
892 893
    assert( p_md );
    return p_md->p_user_data;
894
}
895 896 897 898 899

/**************************************************************************
 * Get media descriptor's elementary streams description
 **************************************************************************/
int
900
libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** pp_es )
901 902 903 904 905 906 907
{
    assert( p_md );

    input_item_t *p_input_item = p_md->p_input_item;
    vlc_mutex_lock( &p_input_item->lock );

    const int i_es = p_input_item->i_es;
908
    *pp_es = (i_es > 0) ? malloc( i_es * sizeof(libvlc_media_track_info_t) ) : NULL;
909

910
    if( !*pp_es ) /* no ES, or OOM */
911 912 913 914 915 916 917 918
    {
        vlc_mutex_unlock( &p_input_item->lock );
        return 0;
    }

    /* Fill array */
    for( int i = 0; i < i_es; i++ )
    {
919
        libvlc_media_track_info_t *p_mes = *pp_es+i;
920 921 922
        const es_format_t *p_es = p_input_item->es[i];

        p_mes->i_codec = p_es->i_codec;
923
        p_mes->i_id = p_es->i_id;
924 925 926 927 928 929 930 931

        p_mes->i_profile = p_es->i_profile;
        p_mes->i_level = p_es->i_level;

        switch(p_es->i_cat)
        {
        case UNKNOWN_ES:
        default:
932
            p_mes->i_type = libvlc_track_unknown;
933 934
            break;
        case VIDEO_ES:
935
            p_mes->i_type = libvlc_track_video;
936 937
            p_mes->u.video.i_height = p_es->video.i_visible_height;
            p_mes->u.video.i_width = p_es->video.i_visible_width;
938 939
            break;
        case AUDIO_ES:
940
            p_mes->i_type = libvlc_track_audio;
941 942
            p_mes->u.audio.i_channels = p_es->audio.i_channels;
            p_mes->u.audio.i_rate = p_es->audio.i_rate;
943 944
            break;
        case SPU_ES:
945
            p_mes->i_type = libvlc_track_text;
946 947 948 949 950 951 952
            break;
        }
    }

    vlc_mutex_unlock( &p_input_item->lock );
    return i_es;
}
953

954
unsigned
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t *** pp_es )
{
    assert( p_md );

    input_item_t *p_input_item = p_md->p_input_item;
    vlc_mutex_lock( &p_input_item->lock );

    const int i_es = p_input_item->i_es;
    *pp_es = (i_es > 0) ? calloc( i_es, sizeof(**pp_es) ) : NULL;

    if( !*pp_es ) /* no ES, or OOM */
    {
        vlc_mutex_unlock( &p_input_item->lock );
        return 0;
    }

    /* Fill array */
    for( int i = 0; i < i_es; i++ )
    {
        libvlc_media_track_t *p_mes = calloc( 1, sizeof(*p_mes) );
        if ( p_mes )
        {
            p_mes->audio = malloc( __MAX(__MAX(sizeof(*p_mes->audio),
                                               sizeof(*p_mes->video)),
                                               sizeof(*p_mes->subtitle)) );
        }
        if ( !p_mes || !p_mes->audio )
        {
            libvlc_media_tracks_release( *pp_es, i_es );
            *pp_es = NULL;
985
            free( p_mes );
986
            vlc_mutex_unlock( &p_input_item->lock );
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
            return 0;
        }
        (*pp_es)[i] = p_mes;

        const es_format_t *p_es = p_input_item->es[i];

        p_mes->i_codec = p_es->i_codec;
        p_mes->i_original_fourcc = p_es->i_original_fourcc;
        p_mes->i_id = p_es->i_id;

        p_mes->i_profile = p_es->i_profile;
        p_mes->i_level = p_es->i_level;

        p_mes->i_bitrate = p_es->i_bitrate;
        p_mes->psz_language = p_es->psz_language != NULL ? strdup(p_es->psz_language) : NULL;
        p_mes->psz_description = p_es->psz_description != NULL ? strdup(p_es->psz_description) : NULL;

        switch(p_es->i_cat)
        {
        case UNKNOWN_ES:
        default:
            p_mes->i_type = libvlc_track_unknown;
            break;
        case VIDEO_ES:
            p_mes->i_type = libvlc_track_video;
1012 1013
            p_mes->video->i_height = p_es->video.i_visible_height;
            p_mes->video->i_width = p_es->video.i_visible_width;
1014 1015 1016 1017
            p_mes->video->i_sar_num = p_es->video.i_sar_num;
            p_mes->video->i_sar_den = p_es->video.i_sar_den;
            p_mes->video->i_frame_rate_num = p_es->video.i_frame_rate;
            p_mes->video->i_frame_rate_den = p_es->video.i_frame_rate_base;
1018 1019 1020 1021 1022

            assert( p_es->video.orientation >= ORIENT_TOP_LEFT &&
                    p_es->video.orientation <= ORIENT_RIGHT_BOTTOM );
            p_mes->video->i_orientation = (int) p_es->video.orientation;

1023 1024 1025 1026 1027
            assert( ( p_es->video.projection_mode >= PROJECTION_MODE_RECTANGULAR &&
                    p_es->video.projection_mode <= PROJECTION_MODE_EQUIRECTANGULAR ) ||
                    ( p_es->video.projection_mode == PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD ) );
            p_mes->video->i_projection = (int) p_es->video.projection_mode;

1028 1029 1030 1031
            p_mes->video->pose.f_yaw = p_es->video.pose.yaw;
            p_mes->video->pose.f_pitch = p_es->video.pose.pitch;
            p_mes->video->pose.f_roll = p_es->video.pose.roll;
            p_mes->video->pose.f_field_of_view = p_es->video.pose.fov;
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
            break;
        case AUDIO_ES:
            p_mes->i_type = libvlc_track_audio;
            p_mes->audio->i_channels = p_es->audio.i_channels;
            p_mes->audio->i_rate = p_es->audio.i_rate;
            break;
        case SPU_ES:
            p_mes->i_type = libvlc_track_text;
            p_mes->subtitle->psz_encoding = p_es->subs.psz_encoding != NULL ?
                                            strdup(p_es->subs.psz_encoding) : NULL;
            break;
        }
    }

    vlc_mutex_unlock( &p_input_item->lock );
    return i_es;
}

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
/**************************************************************************
 * Get codec description from media elementary stream
 **************************************************************************/
const char *
libvlc_media_get_codec_description( libvlc_track_type_t i_type,
                                    uint32_t i_codec )
{
    switch( i_type )
    {
        case libvlc_track_audio:
            return vlc_fourcc_GetDescription( AUDIO_ES, i_codec );
        case libvlc_track_video:
            return vlc_fourcc_GetDescription( VIDEO_ES, i_codec );
        case libvlc_track_text:
            return vlc_fourcc_GetDescription( SPU_ES, i_codec );
        case libvlc_track_unknown:
        default:
            return vlc_fourcc_GetDescription( UNKNOWN_ES, i_codec );
    }
}
1070 1071 1072 1073

/**************************************************************************
 * Release media descriptor's elementary streams description array
 **************************************************************************/
1074
void libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count )
1075
{
1076
    for( unsigned i = 0; i < i_count; ++i )
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
    {
        if ( !p_tracks[i] )
            continue;
        free( p_tracks[i]->psz_language );
        free( p_tracks[i]->psz_description );
        switch( p_tracks[i]->i_type )
        {
        case libvlc_track_audio:
            break;
        case libvlc_track_video:
            break;
        case libvlc_track_text:
            free( p_tracks[i]->subtitle->psz_encoding );
            break;
        case libvlc_track_unknown:
        default:
            break;
        }
        free( p_tracks[i]->audio );
        free( p_tracks[i] );
    }
    free( p_tracks );
}
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131

/**************************************************************************
 * Get the media type of the media descriptor object
 **************************************************************************/
libvlc_media_type_t libvlc_media_get_type( libvlc_media_t *p_md )
{
    assert( p_md );

    int i_type;
    input_item_t *p_input_item = p_md->p_input_item;

    vlc_mutex_lock( &p_input_item->lock );
    i_type = p_md->p_input_item->i_type;
    vlc_mutex_unlock( &p_input_item->lock );

    switch( i_type )
    {
    case ITEM_TYPE_FILE:
        return libvlc_media_type_file;
    case ITEM_TYPE_NODE:
    case ITEM_TYPE_DIRECTORY:
        return libvlc_media_type_directory;
    case ITEM_TYPE_DISC:
        return libvlc_media_type_disc;
    case ITEM_TYPE_STREAM:
        return libvlc_media_type_stream;
    case ITEM_TYPE_PLAYLIST:
        return libvlc_media_type_playlist;
    default:
        return libvlc_media_type_unknown;
    }
}
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148

int libvlc_media_slaves_add( libvlc_media_t *p_md,
                             libvlc_media_slave_type_t i_type,
                             unsigned int i_priority,
                             const char *psz_uri )
{
    assert( p_md && psz_uri );
    input_item_t *p_input_item = p_md->p_input_item;

    enum slave_type i_input_slave_type;
    switch( i_type )
    {
    case libvlc_media_slave_type_subtitle:
        i_input_slave_type = SLAVE_TYPE_SPU;
        break;
    case libvlc_media_slave_type_audio:
        i_input_slave_type = SLAVE_TYPE_AUDIO;
1149
        break;
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
    default:
        vlc_assert_unreachable();
        return -1;
    }

    enum slave_priority i_input_slave_priority;
    switch( i_priority )
    {
    case 0:
        i_input_slave_priority = SLAVE_PRIORITY_MATCH_NONE;
        break;
    case 1:
        i_input_slave_priority = SLAVE_PRIORITY_MATCH_RIGHT;
        break;
    case 2:
        i_input_slave_priority = SLAVE_PRIORITY_MATCH_LEFT;
        break;
    case 3:
        i_input_slave_priority = SLAVE_PRIORITY_MATCH_ALL;
        break;
    default:
    case 4:
        i_input_slave_priority = SLAVE_PRIORITY_USER;
        break;
    }

    input_item_slave_t *p_slave = input_item_slave_New( psz_uri,
                                                      i_input_slave_type,
                                                      i_input_slave_priority );
    if( p_slave == NULL )
        return -1;
    return input_item_AddSlave( p_input_item, p_slave ) == VLC_SUCCESS ? 0 : -1;
}

void libvlc_media_slaves_clear( libvlc_media_t *p_md )
{
    assert( p_md );
    input_item_t *p_input_item = p_md->p_input_item;

    vlc_mutex_lock( &p_input_item->lock );
    for( int i = 0; i < p_input_item->i_slaves; i++ )
        input_item_slave_Delete( p_input_item->pp_slaves[i] );
    TAB_CLEAN( p_input_item->i_slaves, p_input_item->pp_slaves );
    vlc_mutex_unlock( &p_input_item->lock );
}

unsigned int libvlc_media_slaves_get( libvlc_media_t *p_md,
                                      libvlc_media_slave_t ***ppp_slaves )
{
    assert( p_md && ppp_slaves );
    input_item_t *p_input_item = p_md->p_input_item;
1201
    *ppp_slaves = NULL;
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215

    vlc_mutex_lock( &p_input_item->lock );

    int i_count = p_input_item->i_slaves;
    if( i_count <= 0 )
        return vlc_mutex_unlock( &p_input_item->lock ), 0;

    libvlc_media_slave_t **pp_slaves = calloc( i_count, sizeof(*pp_slaves) );
    if( pp_slaves == NULL )
        return vlc_mutex_unlock( &p_input_item->lock ), 0;

    for( int i = 0; i < i_count; ++i )
    {
        input_item_slave_t *p_item_slave = p_input_item->pp_slaves[i];
1216
        assert( p_item_slave->i_priority >= SLAVE_PRIORITY_MATCH_NONE );
1217

1218
        /* also allocate psz_uri buffer at the end of the struct */
1219 1220 1221 1222 1223 1224 1225 1226
        libvlc_media_slave_t *p_slave = malloc( sizeof(*p_slave) +
                                                strlen( p_item_slave->psz_uri )
                                                + 1 );
        if( p_slave == NULL )
        {
            libvlc_media_slaves_release(pp_slaves, i);
            return vlc_mutex_unlock( &p_input_item->lock ), 0;
        }
1227
        p_slave->psz_uri = (char *) ((uint8_t *)p_slave) + sizeof(*p_slave);
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
        strcpy( p_slave->psz_uri, p_item_slave->psz_uri );

        switch( p_item_slave->i_type )
        {
        case SLAVE_TYPE_SPU:
            p_slave->i_type = libvlc_media_slave_type_subtitle;
            break;
        case SLAVE_TYPE_AUDIO:
            p_slave->i_type = libvlc_media_slave_type_audio;
            break;
        default:
            vlc_assert_unreachable();
        }

        switch( p_item_slave->i_priority )
        {
        case SLAVE_PRIORITY_MATCH_NONE:
            p_slave->i_priority = 0;
            break;
        case SLAVE_PRIORITY_MATCH_RIGHT:
            p_slave->i_priority = 1;
            break;
        case SLAVE_PRIORITY_MATCH_LEFT:
            p_slave->i_priority = 2;
            break;
        case SLAVE_PRIORITY_MATCH_ALL:
            p_slave->i_priority = 3;
            break;
        case SLAVE_PRIORITY_USER:
            p_slave->i_priority = 4;
            break;
        default:
            vlc_assert_unreachable();
        }
        pp_slaves[i] = p_slave;
    }
    vlc_mutex_unlock( &p_input_item->lock );

    *ppp_slaves = pp_slaves;
    return i_count;
}

void libvlc_media_slaves_release( libvlc_media_slave_t **pp_slaves,
                                  unsigned int i_count )
{
1273 1274 1275 1276 1277 1278
    if( i_count > 0 )
    {
        assert( pp_slaves );
        for( unsigned int i = 0; i < i_count; ++i )
            free( pp_slaves[i] );
    }
1279
    free( pp_slaves );
1280
}