media.c 43.4 KB
Newer Older
1
/*****************************************************************************
2
 * media.c: Libvlc API media descripor management
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
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
LGPL  
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
LGPL  
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
LGPL  
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 148 149
/**************************************************************************
 * input_item_subitem_added (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_subitem_added( const vlc_event_t *p_event,
150
                                       void * user_data )
151
{
152 153
    libvlc_media_t * p_md = user_data;
    libvlc_media_t * p_md_child;
154
    libvlc_media_list_t *p_subitems;
155 156
    libvlc_event_t event;

157
    p_md_child = libvlc_media_new_from_input_item(
158
                p_md->p_libvlc_instance,
159
                p_event->u.input_item_subitem_added.p_new_child );
160

161
    /* Add this to our media list */
162
    p_subitems = media_get_subitems( p_md, true );
163
    if( p_subitems != NULL )
164 165
    {
        libvlc_media_list_lock( p_subitems );
166
        libvlc_media_list_internal_add_media( p_subitems, p_md_child );
167 168
        libvlc_media_list_unlock( p_subitems );
    }
169

170
    /* Construct the event */
171
    event.type = libvlc_MediaSubItemAdded;
172
    event.u.media_subitem_added.new_child = p_md_child;
173 174 175

    /* Send the event */
    libvlc_event_send( p_md->p_event_manager, &event );
176
    libvlc_media_release( p_md_child );
177 178
}

179 180 181 182 183 184
/**************************************************************************
 * input_item_subitemtree_added (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_subitemtree_added( const vlc_event_t * p_event,
                                          void * user_data )
{
185
    VLC_UNUSED( p_event );
186 187 188 189 190 191 192 193 194 195 196
    libvlc_media_t * p_md = user_data;
    libvlc_event_t event;

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

    /* Send the event */
    libvlc_event_send( p_md->p_event_manager, &event );
}

197 198 199 200 201 202
/**************************************************************************
 * input_item_meta_changed (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_meta_changed( const vlc_event_t *p_event,
                                     void * user_data )
{
203
    libvlc_media_t * p_md = user_data;
204 205 206
    libvlc_event_t event;

    /* Construct the event */
207
    event.type = libvlc_MediaMetaChanged;
208
    event.u.media_meta_changed.meta_type =
209 210 211 212 213 214
        vlc_to_libvlc_meta[p_event->u.input_item_meta_changed.meta_type];

    /* Send the event */
    libvlc_event_send( p_md->p_event_manager, &event );
}

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

    /* Construct the event */
225
    event.type = libvlc_MediaDurationChanged;
226 227
    event.u.media_duration_changed.new_duration =
        from_mtime(p_event->u.input_item_duration_changed.new_duration);
228 229 230 231 232

    /* Send the event */
    libvlc_event_send( p_md->p_event_manager, &event );
}

233 234
static void send_parsed_changed( libvlc_media_t *p_md,
                                 libvlc_media_parsed_status_t new_status )
235 236 237
{
    libvlc_event_t event;

238 239
    vlc_mutex_lock( &p_md->parsed_lock );
    if( p_md->parsed_status == new_status )
240
    {
241
        vlc_mutex_unlock( &p_md->parsed_lock );
242 243
        return;
    }
244

245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    /* 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 );
        }
    }
269

270
    /* Construct the event */
271
    event.type = libvlc_MediaParsedChanged;
272
    event.u.media_parsed_changed.new_status = new_status;
273 274

    /* Send the event */
275
    libvlc_event_send( p_md->p_event_manager, &event );
276 277
}

278 279 280 281 282 283 284
/**************************************************************************
 * 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;
285
    libvlc_media_parsed_status_t new_status;
286

287
    switch( p_event->u.input_item_preparse_ended.new_status )
288 289
    {
        case ITEM_PREPARSE_SKIPPED:
290
            new_status = libvlc_media_parsed_status_skipped;
291 292
            break;
        case ITEM_PREPARSE_FAILED:
293
            new_status = libvlc_media_parsed_status_failed;
294
            break;
295 296 297
        case ITEM_PREPARSE_TIMEOUT:
            new_status = libvlc_media_parsed_status_timeout;
            break;
298
        case ITEM_PREPARSE_DONE:
299
            new_status = libvlc_media_parsed_status_done;
300
            break;
301 302
        default:
            return;
303
    }
304
    send_parsed_changed( p_md, new_status );
305 306
}

307 308 309
/**************************************************************************
 * Install event handler (Private)
 **************************************************************************/
310
static void install_input_item_observer( libvlc_media_t *p_md )
311
{
312 313 314 315
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemAdded,
                      input_item_subitem_added,
                      p_md );
316 317 318 319
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemMetaChanged,
                      input_item_meta_changed,
                      p_md );
320 321 322 323
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemDurationChanged,
                      input_item_duration_changed,
                      p_md );
324 325 326 327
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemTreeAdded,
                      input_item_subitemtree_added,
                      p_md );
328 329 330 331
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemPreparseEnded,
                      input_item_preparse_ended,
                      p_md );
332 333 334 335 336
}

/**************************************************************************
 * Uninstall event handler (Private)
 **************************************************************************/
337
static void uninstall_input_item_observer( libvlc_media_t *p_md )
338
{
339 340 341 342
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemAdded,
                      input_item_subitem_added,
                      p_md );
343 344 345 346
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemMetaChanged,
                      input_item_meta_changed,
                      p_md );
347 348 349 350
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemDurationChanged,
                      input_item_duration_changed,
                      p_md );
351 352 353 354
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemTreeAdded,
                      input_item_subitemtree_added,
                      p_md );
355 356 357 358
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemPreparseEnded,
                      input_item_preparse_ended,
                      p_md );
359
}
360 361

/**************************************************************************
362 363 364
 * Create a new media descriptor object from an input_item
 * (libvlc internal)
 * That's the generic constructor
365
 **************************************************************************/
366
libvlc_media_t * libvlc_media_new_from_input_item(
367
                                   libvlc_instance_t *p_instance,
368
                                   input_item_t *p_input_item )
369
{
370
    libvlc_media_t * p_md;
371 372

    if (!p_input_item)
373
    {
374
        libvlc_printerr( "No input item given" );
375 376
        return NULL;
    }
377

Rémi Duraffort's avatar
Rémi Duraffort committed
378
    p_md = calloc( 1, sizeof(libvlc_media_t) );
379 380
    if( !p_md )
    {
381
        libvlc_printerr( "Not enough memory" );
382 383 384
        return NULL;
    }

385 386
    p_md->p_libvlc_instance = p_instance;
    p_md->p_input_item      = p_input_item;
387
    p_md->i_refcount        = 1;
388

389 390
    vlc_cond_init(&p_md->parsed_cond);
    vlc_mutex_init(&p_md->parsed_lock);
391
    vlc_mutex_init(&p_md->subitems_lock);
392

393
    p_md->state = libvlc_NothingSpecial;
394

395 396 397 398
    /* 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;

399
    p_md->p_event_manager = libvlc_event_manager_new( p_md );
400 401 402 403 404
    if( unlikely(p_md->p_event_manager == NULL) )
    {
        free(p_md);
        return NULL;
    }
405

406
    vlc_gc_incref( p_md->p_input_item );
407

408 409
    install_input_item_observer( p_md );

410
    libvlc_retain( p_instance );
411
    return p_md;
412 413
}

414
/**************************************************************************
415
 * Create a new media descriptor object
416
 **************************************************************************/
417 418
libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance,
                                           const char * psz_mrl )
419
{
420
    input_item_t * p_input_item;
421
    libvlc_media_t * p_md;
422

423
    p_input_item = input_item_New( psz_mrl, NULL );
424

425
    if (!p_input_item)
426
    {
427
        libvlc_printerr( "Not enough memory" );
428 429
        return NULL;
    }
430

431
    p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
432

433
    /* The p_input_item is retained in libvlc_media_new_from_input_item */
434
    vlc_gc_decref( p_input_item );
435

436
    return p_md;
437 438
}

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

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

454 455 456 457 458 459 460 461
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 );
}

462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
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;
}

482 483 484
/**************************************************************************
 * Create a new media descriptor object
 **************************************************************************/
485 486
libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance,
                                           const char * psz_name )
487 488
{
    input_item_t * p_input_item;
489
    libvlc_media_t * p_md;
490
    libvlc_media_list_t * p_subitems;
491

492
    p_input_item = input_item_New( "vlc://nop", psz_name );
493 494 495

    if (!p_input_item)
    {
496
        libvlc_printerr( "Not enough memory" );
497 498 499
        return NULL;
    }

500
    p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
501
    input_item_Release( p_input_item );
502

503
    p_subitems = media_get_subitems( p_md, true );
504 505 506 507
    if( p_subitems == NULL) {
        libvlc_media_release( p_md );
        return NULL;
    }
508 509 510 511

    return p_md;
}

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

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

537 538 539
/**************************************************************************
 * Delete a media descriptor object
 **************************************************************************/
540
void libvlc_media_release( libvlc_media_t *p_md )
541
{
542
    if (!p_md)
543 544
        return;

545 546 547 548
    p_md->i_refcount--;

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

550 551
    uninstall_input_item_observer( p_md );

552
    /* Cancel asynchronous parsing (if any) */
553
    libvlc_MetadataCancel( p_md->p_libvlc_instance->p_libvlc_int, p_md );
554

555 556
    if( p_md->p_subitems )
        libvlc_media_list_release( p_md->p_subitems );
557

558 559
    vlc_gc_decref( p_md->p_input_item );

560 561
    vlc_cond_destroy( &p_md->parsed_cond );
    vlc_mutex_destroy( &p_md->parsed_lock );
562
    vlc_mutex_destroy( &p_md->subitems_lock );
563

564 565
    /* Construct the event */
    libvlc_event_t event;
566
    event.type = libvlc_MediaFreed;
567
    event.u.media_freed.md = p_md;
568 569 570 571

    /* Send the event */
    libvlc_event_send( p_md->p_event_manager, &event );

572
    libvlc_event_manager_release( p_md->p_event_manager );
573
    libvlc_release( p_md->p_libvlc_instance );
574 575 576 577
    free( p_md );
}

/**************************************************************************
578 579
 * Retain a media descriptor object
 **************************************************************************/
580
void libvlc_media_retain( libvlc_media_t *p_md )
581
{
582
    assert (p_md);
583 584 585 586 587
    p_md->i_refcount++;
}

/**************************************************************************
 * Duplicate a media descriptor object
588
 **************************************************************************/
589 590
libvlc_media_t *
libvlc_media_duplicate( libvlc_media_t *p_md_orig )
591
{
592
    return libvlc_media_new_from_input_item(
593
        p_md_orig->p_libvlc_instance, p_md_orig->p_input_item );
594 595
}

596
/**************************************************************************
597
 * Get mrl from a media descriptor object
598 599
 **************************************************************************/
char *
600
libvlc_media_get_mrl( libvlc_media_t * p_md )
601
{
602
    assert( p_md );
603
    return input_item_GetURI( p_md->p_input_item );
604 605
}

606
/**************************************************************************
607
 * Getter for meta information
608 609
 **************************************************************************/

610
char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta )
611
{
612
    char *psz_meta = NULL;
613

614 615 616 617 618 619 620 621 622 623 624 625 626
    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 );
    }
627
    return psz_meta;
628
}
629

Rémi Duraffort's avatar
Rémi Duraffort committed
630 631 632 633 634 635 636 637 638 639 640 641 642
/**************************************************************************
 * 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 );
643
    vlc_object_t *p_obj = VLC_OBJECT(p_md->p_libvlc_instance->p_libvlc_int);
Rémi Duraffort's avatar
Rémi Duraffort committed
644 645 646
    return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS;
}

647 648 649 650 651
/**************************************************************************
 * Getter for state information
 * Can be error, playing, buffering, NothingSpecial.
 **************************************************************************/

652
libvlc_state_t
653
libvlc_media_get_state( libvlc_media_t *p_md )
654
{
655
    assert( p_md );
656 657 658 659 660 661 662 663
    return p_md->state;
}

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

void
664
libvlc_media_set_state( libvlc_media_t *p_md,
665
                                   libvlc_state_t state )
666 667 668 669 670 671
{
    libvlc_event_t event;

    p_md->state = state;

    /* Construct the event */
672
    event.type = libvlc_MediaStateChanged;
673
    event.u.media_state_changed.new_state = state;
674 675 676 677 678

    /* Send the event */
    libvlc_event_send( p_md->p_event_manager, &event );
}

679 680 681 682
/**************************************************************************
 * subitems
 **************************************************************************/
libvlc_media_list_t *
683
libvlc_media_subitems( libvlc_media_t * p_md )
684
{
685
    libvlc_media_list_t *p_subitems = media_get_subitems( p_md, true );
686 687 688
    if( p_subitems )
        libvlc_media_list_retain( p_subitems );
    return p_subitems;
689
}
690

691
/**************************************************************************
Rémi Duraffort's avatar
Rémi Duraffort committed
692
 * Getter for statistics information
693 694 695 696 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
 **************************************************************************/
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;
}

726 727 728 729
/**************************************************************************
 * event_manager
 **************************************************************************/
libvlc_event_manager_t *
730
libvlc_media_event_manager( libvlc_media_t * p_md )
731
{
732
    assert( p_md );
733

734 735
    return p_md->p_event_manager;
}
736 737

/**************************************************************************
738
 * Get duration of media object (in ms)
739
 **************************************************************************/
740
int64_t
741
libvlc_media_get_duration( libvlc_media_t * p_md )
742
{
743
    assert( p_md );
744

745
    if( !p_md->p_input_item )
746
    {
747
        libvlc_printerr( "No input item" );
748 749
        return -1;
    }
750

751 752 753
    if (!input_item_IsPreparsed( p_md->p_input_item ))
        return -1;

754
    return from_mtime(input_item_GetDuration( p_md->p_input_item ));
755 756
}

757
static int media_parse(libvlc_media_t *media, bool b_async,
758
                       libvlc_media_parse_flag_t parse_flag, int timeout)
759
{
760 761 762 763 764
    bool needed;

    vlc_mutex_lock(&media->parsed_lock);
    needed = !media->has_asked_preparse;
    media->has_asked_preparse = true;
765 766
    if (needed)
        media->is_parsed = false;
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
    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;
        }
786

787 788
        if (parse_flag & libvlc_media_parse_network)
            parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
789 790
        if (parse_flag & libvlc_media_do_interact)
            parse_scope |= META_REQUEST_OPTION_DO_INTERACT;
791
        ret = libvlc_MetadataRequest(libvlc, item, parse_scope, timeout, media);
792 793 794 795 796 797 798 799 800 801 802 803 804 805
        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;
806 807
}

808
/**************************************************************************
809
 * Parse the media and wait.
810 811 812 813
 **************************************************************************/
void
libvlc_media_parse(libvlc_media_t *media)
{
814
    media_parse( media, false, libvlc_media_fetch_local, -1 );
815 816 817
}

/**************************************************************************
818
 * Parse the media but do not wait.
819 820 821 822
 **************************************************************************/
void
libvlc_media_parse_async(libvlc_media_t *media)
{
823
    media_parse( media, true, libvlc_media_fetch_local, -1 );
824
}
825

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

837 838 839 840 841 842
void
libvlc_media_parse_stop( libvlc_media_t *media )
{
    libvlc_MetadataCancel( media->p_libvlc_instance->p_libvlc_int, media );
}

843
/**************************************************************************
844
 * Get parsed status for media object.
845
 **************************************************************************/
846
int
847
libvlc_media_is_parsed(libvlc_media_t *media)
848
{
849
    bool parsed;
850

851 852 853 854
    vlc_mutex_lock(&media->parsed_lock);
    parsed = media->is_parsed;
    vlc_mutex_unlock(&media->parsed_lock);
    return parsed;
855 856
}

857 858 859 860 861 862 863 864 865 866 867
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;
}

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

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

/**************************************************************************
 * Get media descriptor's elementary streams description
 **************************************************************************/
int
896
libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** pp_es )
897 898 899 900 901 902 903
{
    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;
904
    *pp_es = (i_es > 0) ? malloc( i_es * sizeof(libvlc_media_track_info_t) ) : NULL;
905

906
    if( !*pp_es ) /* no ES, or OOM */
907 908 909 910 911 912 913 914
    {
        vlc_mutex_unlock( &p_input_item->lock );
        return 0;
    }

    /* Fill array */
    for( int i = 0; i < i_es; i++ )
    {
915
        libvlc_media_track_info_t *p_mes = *pp_es+i;
916 917 918
        const es_format_t *p_es = p_input_item->es[i];

        p_mes->i_codec = p_es->i_codec;
919
        p_mes->i_id = p_es->i_id;
920 921 922 923 924 925 926 927

        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:
928
            p_mes->i_type = libvlc_track_unknown;
929 930
            break;
        case VIDEO_ES:
931
            p_mes->i_type = libvlc_track_video;
932 933
            p_mes->u.video.i_height = p_es->video.i_visible_height;
            p_mes->u.video.i_width = p_es->video.i_visible_width;
934 935
            break;
        case AUDIO_ES:
936
            p_mes->i_type = libvlc_track_audio;
937 938
            p_mes->u.audio.i_channels = p_es->audio.i_channels;
            p_mes->u.audio.i_rate = p_es->audio.i_rate;
939 940
            break;
        case SPU_ES:
941
            p_mes->i_type = libvlc_track_text;
942 943 944 945 946 947 948
            break;
        }
    }

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

950
unsigned
951 952 953 954 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
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;
981
            free( p_mes );
982
            vlc_mutex_unlock( &p_input_item->lock );
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
            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;
1008 1009
            p_mes->video->i_height = p_es->video.i_visible_height;
            p_mes->video->i_width = p_es->video.i_visible_width;
1010 1011 1012 1013
            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;
1014 1015 1016 1017 1018

            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;

1019 1020 1021 1022 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;

            p_mes->video->pose.f_yaw_degrees = p_es->video.pose.f_yaw_degrees;
            p_mes->video->pose.f_pitch_degrees = p_es->video.pose.f_pitch_degrees;
            p_mes->video->pose.f_roll_degrees = p_es->video.pose.f_roll_degrees;
            p_mes->video->pose.f_fov_degrees = p_es->video.pose.f_fov_degrees;
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
            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;
}

1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
/**************************************************************************
 * 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 );
    }
}
1066 1067 1068 1069

/**************************************************************************
 * Release media descriptor's elementary streams description array
 **************************************************************************/
1070
void libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count )
1071
{
1072
    for( unsigned i = 0; i < i_count; ++i )
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
    {
        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 );
}
1096 1097 1098 1099 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

/**************************************************************************
 * 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;
    }
}
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144

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;
1145
        break;
1146 1147 1148 1149 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