media.c 36.2 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 74
    [libvlc_meta_AlbumArtist]  = vlc_meta_AlbumArtist,
    [libvlc_meta_DiscNumber]   = vlc_meta_DiscNumber
75 76
};

77
static const libvlc_meta_t vlc_to_libvlc_meta[] =
78 79 80 81 82 83 84 85 86 87 88 89 90 91
{
    [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,
92
    [vlc_meta_ESNowPlaying] = libvlc_meta_NowPlaying,
93 94 95
    [vlc_meta_Publisher]    = libvlc_meta_Publisher,
    [vlc_meta_EncodedBy]    = libvlc_meta_EncodedBy,
    [vlc_meta_ArtworkURL]   = libvlc_meta_ArtworkURL,
96 97 98 99 100 101
    [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,
102
    [vlc_meta_Actors]       = libvlc_meta_Actors,
103 104
    [vlc_meta_AlbumArtist]  = libvlc_meta_AlbumArtist,
    [vlc_meta_DiscNumber]   = libvlc_meta_DiscNumber
105 106
};

107 108
static libvlc_media_list_t *media_get_subitems( libvlc_media_t * p_md,
                                                bool b_create )
109 110 111 112
{
    libvlc_media_list_t *p_subitems = NULL;

    vlc_mutex_lock( &p_md->subitems_lock );
113
    if( p_md->p_subitems == NULL && b_create )
114 115 116
    {
        p_md->p_subitems = libvlc_media_list_new( p_md->p_libvlc_instance );
        if( p_md->p_subitems != NULL )
117 118
        {
            p_md->p_subitems->b_read_only = true;
119
            p_md->p_subitems->p_internal_md = p_md;
120
        }
121 122 123 124 125 126
    }
    p_subitems = p_md->p_subitems;
    vlc_mutex_unlock( &p_md->subitems_lock );
    return p_subitems;
}

127 128 129 130
/**************************************************************************
 * input_item_subitem_added (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_subitem_added( const vlc_event_t *p_event,
131
                                       void * user_data )
132
{
133 134
    libvlc_media_t * p_md = user_data;
    libvlc_media_t * p_md_child;
135
    libvlc_media_list_t *p_subitems;
136 137
    libvlc_event_t event;

138
    p_md_child = libvlc_media_new_from_input_item(
139
                p_md->p_libvlc_instance,
140
                p_event->u.input_item_subitem_added.p_new_child );
141

142
    /* Add this to our media list */
143
    p_subitems = media_get_subitems( p_md, true );
144
    if( p_subitems != NULL )
145 146
    {
        libvlc_media_list_lock( p_subitems );
147
        libvlc_media_list_internal_add_media( p_subitems, p_md_child );
148 149
        libvlc_media_list_unlock( p_subitems );
    }
150

151
    /* Construct the event */
152
    event.type = libvlc_MediaSubItemAdded;
153
    event.u.media_subitem_added.new_child = p_md_child;
154 155 156

    /* Send the event */
    libvlc_event_send( p_md->p_event_manager, &event );
157
    libvlc_media_release( p_md_child );
158 159
}

160 161 162 163 164 165
/**************************************************************************
 * input_item_subitemtree_added (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_subitemtree_added( const vlc_event_t * p_event,
                                          void * user_data )
{
166
    VLC_UNUSED( p_event );
167 168 169 170 171 172 173 174 175 176 177
    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 );
}

178 179 180 181 182 183
/**************************************************************************
 * input_item_meta_changed (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_meta_changed( const vlc_event_t *p_event,
                                     void * user_data )
{
184
    libvlc_media_t * p_md = user_data;
185 186 187
    libvlc_event_t event;

    /* Construct the event */
188
    event.type = libvlc_MediaMetaChanged;
189
    event.u.media_meta_changed.meta_type =
190 191 192 193 194 195
        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 );
}

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

    /* Construct the event */
206
    event.type = libvlc_MediaDurationChanged;
207 208
    event.u.media_duration_changed.new_duration =
        from_mtime(p_event->u.input_item_duration_changed.new_duration);
209 210 211 212 213 214 215 216

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

/**************************************************************************
 * input_item_preparsed_changed (Private) (vlc event Callback)
 **************************************************************************/
217 218
static void input_item_preparsed_changed(const vlc_event_t *p_event,
                                         void * user_data)
219
{
220
    libvlc_media_t *media = user_data;
221 222
    libvlc_event_t event;

223 224 225 226 227 228 229
    /* Eventually notify libvlc_media_parse() */
    vlc_mutex_lock(&media->parsed_lock);
    media->is_parsed = true;
    vlc_cond_broadcast(&media->parsed_cond);
    vlc_mutex_unlock(&media->parsed_lock);


230
    /* Construct the event */
231 232
    event.type = libvlc_MediaParsedChanged;
    event.u.media_parsed_changed.new_status =
233 234 235
        p_event->u.input_item_preparsed_changed.new_status;

    /* Send the event */
236
    libvlc_event_send(media->p_event_manager, &event);
237
}
238

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
/**************************************************************************
 * input_item_preparse_ended (Private) (vlc event Callback)
 **************************************************************************/
static void input_item_preparse_ended( const vlc_event_t * p_event,
                                       void * user_data )
{
    VLC_UNUSED( p_event );
    libvlc_media_t * p_md = user_data;
    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 );
    }
}

258 259 260
/**************************************************************************
 * Install event handler (Private)
 **************************************************************************/
261
static void install_input_item_observer( libvlc_media_t *p_md )
262
{
263 264 265 266
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemAdded,
                      input_item_subitem_added,
                      p_md );
267 268 269 270
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemMetaChanged,
                      input_item_meta_changed,
                      p_md );
271 272 273 274 275 276 277 278
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemDurationChanged,
                      input_item_duration_changed,
                      p_md );
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemPreparsedChanged,
                      input_item_preparsed_changed,
                      p_md );
279 280 281 282
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemTreeAdded,
                      input_item_subitemtree_added,
                      p_md );
283 284 285 286
    vlc_event_attach( &p_md->p_input_item->event_manager,
                      vlc_InputItemPreparseEnded,
                      input_item_preparse_ended,
                      p_md );
287 288 289 290 291
}

/**************************************************************************
 * Uninstall event handler (Private)
 **************************************************************************/
292
static void uninstall_input_item_observer( libvlc_media_t *p_md )
293
{
294 295 296 297
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemAdded,
                      input_item_subitem_added,
                      p_md );
298 299 300 301
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemMetaChanged,
                      input_item_meta_changed,
                      p_md );
302 303 304 305 306 307 308 309
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemDurationChanged,
                      input_item_duration_changed,
                      p_md );
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemPreparsedChanged,
                      input_item_preparsed_changed,
                      p_md );
310 311 312 313
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemSubItemTreeAdded,
                      input_item_subitemtree_added,
                      p_md );
314 315 316 317
    vlc_event_detach( &p_md->p_input_item->event_manager,
                      vlc_InputItemPreparseEnded,
                      input_item_preparse_ended,
                      p_md );
318
}
319 320

/**************************************************************************
321 322 323
 * Create a new media descriptor object from an input_item
 * (libvlc internal)
 * That's the generic constructor
324
 **************************************************************************/
325
libvlc_media_t * libvlc_media_new_from_input_item(
326
                                   libvlc_instance_t *p_instance,
327
                                   input_item_t *p_input_item )
328
{
329
    libvlc_media_t * p_md;
330 331

    if (!p_input_item)
332
    {
333
        libvlc_printerr( "No input item given" );
334 335
        return NULL;
    }
336

Rémi Duraffort's avatar
Rémi Duraffort committed
337
    p_md = calloc( 1, sizeof(libvlc_media_t) );
338 339
    if( !p_md )
    {
340
        libvlc_printerr( "Not enough memory" );
341 342 343
        return NULL;
    }

344 345
    p_md->p_libvlc_instance = p_instance;
    p_md->p_input_item      = p_input_item;
346
    p_md->i_refcount        = 1;
347

348 349
    vlc_cond_init(&p_md->parsed_cond);
    vlc_mutex_init(&p_md->parsed_lock);
350
    vlc_mutex_init(&p_md->subitems_lock);
351

352
    p_md->state = libvlc_NothingSpecial;
353

354 355 356 357
    /* 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;

358 359 360 361 362 363
    p_md->p_event_manager = libvlc_event_manager_new( p_md, p_instance );
    if( unlikely(p_md->p_event_manager == NULL) )
    {
        free(p_md);
        return NULL;
    }
364 365 366 367 368 369 370 371

    libvlc_event_manager_t *em = p_md->p_event_manager;
    libvlc_event_manager_register_event_type(em, libvlc_MediaMetaChanged);
    libvlc_event_manager_register_event_type(em, libvlc_MediaSubItemAdded);
    libvlc_event_manager_register_event_type(em, libvlc_MediaFreed);
    libvlc_event_manager_register_event_type(em, libvlc_MediaDurationChanged);
    libvlc_event_manager_register_event_type(em, libvlc_MediaStateChanged);
    libvlc_event_manager_register_event_type(em, libvlc_MediaParsedChanged);
372
    libvlc_event_manager_register_event_type(em, libvlc_MediaSubItemTreeAdded);
373

374
    vlc_gc_incref( p_md->p_input_item );
375

376 377
    install_input_item_observer( p_md );

378
    return p_md;
379 380
}

381
/**************************************************************************
382
 * Create a new media descriptor object
383
 **************************************************************************/
384 385
libvlc_media_t *libvlc_media_new_location( libvlc_instance_t *p_instance,
                                           const char * psz_mrl )
386
{
387
    input_item_t * p_input_item;
388
    libvlc_media_t * p_md;
389

390
    p_input_item = input_item_New( psz_mrl, NULL );
391

392
    if (!p_input_item)
393
    {
394
        libvlc_printerr( "Not enough memory" );
395 396
        return NULL;
    }
397

398
    p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
399

400
    /* The p_input_item is retained in libvlc_media_new_from_input_item */
401
    vlc_gc_decref( p_input_item );
402

403
    return p_md;
404 405
}

406 407 408
libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance,
                                       const char *path )
{
409
    char *mrl = vlc_path2uri( path, NULL );
410 411
    if( unlikely(mrl == NULL) )
    {
412
        libvlc_printerr( "%s", vlc_strerror_c(errno) );
413 414 415 416 417 418 419 420
        return NULL;
    }

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

421 422 423 424 425 426 427 428
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 );
}

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
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;
}

449 450 451
/**************************************************************************
 * Create a new media descriptor object
 **************************************************************************/
452 453
libvlc_media_t * libvlc_media_new_as_node( libvlc_instance_t *p_instance,
                                           const char * psz_name )
454 455
{
    input_item_t * p_input_item;
456
    libvlc_media_t * p_md;
457
    libvlc_media_list_t * p_subitems;
458

459
    p_input_item = input_item_New( "vlc://nop", psz_name );
460 461 462

    if (!p_input_item)
    {
463
        libvlc_printerr( "Not enough memory" );
464 465 466
        return NULL;
    }

467
    p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
468

469
    p_subitems = media_get_subitems( p_md, true );
470 471 472 473
    if( p_subitems == NULL) {
        libvlc_media_release( p_md );
        return NULL;
    }
474 475 476 477

    return p_md;
}

478 479
/**************************************************************************
 * Add an option to the media descriptor,
480 481
 * that will be used to determine how the media_player will read the
 * media. This allow to use VLC advanced reading/streaming
482 483 484 485
 * options in a per-media basis
 *
 * The options are detailled in vlc --long-help, for instance "--sout-all"
 **************************************************************************/
486 487
void libvlc_media_add_option( libvlc_media_t * p_md,
                              const char * psz_option )
488
{
489
    libvlc_media_add_option_flag( p_md, psz_option,
490
                          VLC_INPUT_OPTION_UNIQUE|VLC_INPUT_OPTION_TRUSTED );
491 492
}

493
/**************************************************************************
494
 * Same as libvlc_media_add_option but with configurable flags.
495
 **************************************************************************/
496
void libvlc_media_add_option_flag( libvlc_media_t * p_md,
497
                                   const char * ppsz_option,
498
                                   unsigned i_flags )
499
{
500
    input_item_AddOption( p_md->p_input_item, ppsz_option, i_flags );
501 502
}

503 504 505
/**************************************************************************
 * Delete a media descriptor object
 **************************************************************************/
506
void libvlc_media_release( libvlc_media_t *p_md )
507
{
508
    if (!p_md)
509 510
        return;

511 512 513 514
    p_md->i_refcount--;

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

516 517
    if( p_md->p_subitems )
        libvlc_media_list_release( p_md->p_subitems );
518

519 520 521
    uninstall_input_item_observer( p_md );
    vlc_gc_decref( p_md->p_input_item );

522 523
    vlc_cond_destroy( &p_md->parsed_cond );
    vlc_mutex_destroy( &p_md->parsed_lock );
524
    vlc_mutex_destroy( &p_md->subitems_lock );
525

526 527
    /* Construct the event */
    libvlc_event_t event;
528
    event.type = libvlc_MediaFreed;
529
    event.u.media_freed.md = p_md;
530 531 532 533

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

534 535
    libvlc_event_manager_release( p_md->p_event_manager );

536 537 538 539
    free( p_md );
}

/**************************************************************************
540 541
 * Retain a media descriptor object
 **************************************************************************/
542
void libvlc_media_retain( libvlc_media_t *p_md )
543
{
544
    assert (p_md);
545 546 547 548 549
    p_md->i_refcount++;
}

/**************************************************************************
 * Duplicate a media descriptor object
550
 **************************************************************************/
551 552
libvlc_media_t *
libvlc_media_duplicate( libvlc_media_t *p_md_orig )
553
{
554
    return libvlc_media_new_from_input_item(
555
        p_md_orig->p_libvlc_instance, p_md_orig->p_input_item );
556 557
}

558
/**************************************************************************
559
 * Get mrl from a media descriptor object
560 561
 **************************************************************************/
char *
562
libvlc_media_get_mrl( libvlc_media_t * p_md )
563
{
564
    assert( p_md );
565
    return input_item_GetURI( p_md->p_input_item );
566 567
}

568
/**************************************************************************
569
 * Getter for meta information
570 571
 **************************************************************************/

572
char *libvlc_media_get_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta )
573
{
574
    char *psz_meta = NULL;
575

576 577 578 579 580 581 582 583 584 585 586 587 588
    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 );
    }
589
    return psz_meta;
590
}
591

Rémi Duraffort's avatar
Rémi Duraffort committed
592 593 594 595 596 597 598 599 600 601 602 603 604
/**************************************************************************
 * 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 );
605
    vlc_object_t *p_obj = VLC_OBJECT(p_md->p_libvlc_instance->p_libvlc_int);
Rémi Duraffort's avatar
Rémi Duraffort committed
606 607 608
    return input_item_WriteMeta( p_obj, p_md->p_input_item ) == VLC_SUCCESS;
}

609 610 611 612 613
/**************************************************************************
 * Getter for state information
 * Can be error, playing, buffering, NothingSpecial.
 **************************************************************************/

614
libvlc_state_t
615
libvlc_media_get_state( libvlc_media_t *p_md )
616
{
617
    assert( p_md );
618 619 620 621 622 623 624 625
    return p_md->state;
}

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

void
626
libvlc_media_set_state( libvlc_media_t *p_md,
627
                                   libvlc_state_t state )
628 629 630 631 632 633
{
    libvlc_event_t event;

    p_md->state = state;

    /* Construct the event */
634
    event.type = libvlc_MediaStateChanged;
635
    event.u.media_state_changed.new_state = state;
636 637 638 639 640

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

641 642 643 644
/**************************************************************************
 * subitems
 **************************************************************************/
libvlc_media_list_t *
645
libvlc_media_subitems( libvlc_media_t * p_md )
646
{
647
    libvlc_media_list_t *p_subitems = media_get_subitems( p_md, true );
648 649 650
    if( p_subitems )
        libvlc_media_list_retain( p_subitems );
    return p_subitems;
651
}
652

653
/**************************************************************************
Rémi Duraffort's avatar
Rémi Duraffort committed
654
 * Getter for statistics information
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
 **************************************************************************/
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;
}

688 689 690 691
/**************************************************************************
 * event_manager
 **************************************************************************/
libvlc_event_manager_t *
692
libvlc_media_event_manager( libvlc_media_t * p_md )
693
{
694
    assert( p_md );
695

696 697
    return p_md->p_event_manager;
}
698 699

/**************************************************************************
700
 * Get duration of media object (in ms)
701
 **************************************************************************/
702
int64_t
703
libvlc_media_get_duration( libvlc_media_t * p_md )
704
{
705
    assert( p_md );
706

707
    if( !p_md->p_input_item )
708
    {
709
        libvlc_printerr( "No input item" );
710 711
        return -1;
    }
712

713 714 715
    if (!input_item_IsPreparsed( p_md->p_input_item ))
        return -1;

716
    return from_mtime(input_item_GetDuration( p_md->p_input_item ));
717 718
}

719 720
static int media_parse(libvlc_media_t *media, bool b_async,
                       libvlc_media_parse_flag_t parse_flag)
721
{
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
    bool needed;

    vlc_mutex_lock(&media->parsed_lock);
    needed = !media->has_asked_preparse;
    media->has_asked_preparse = true;
    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;
        }
746

747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
        if (parse_flag & libvlc_media_parse_network)
            parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
        ret = libvlc_MetaRequest(libvlc, item, parse_scope);
        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;
764 765
}

766
/**************************************************************************
767
 * Parse the media and wait.
768 769 770 771
 **************************************************************************/
void
libvlc_media_parse(libvlc_media_t *media)
{
772
    media_parse( media, false, libvlc_media_fetch_local );
773 774 775
}

/**************************************************************************
776
 * Parse the media but do not wait.
777 778 779 780
 **************************************************************************/
void
libvlc_media_parse_async(libvlc_media_t *media)
{
781 782
    media_parse( media, true, libvlc_media_fetch_local );
}
783

784 785 786 787 788 789 790 791
/**************************************************************************
 * Parse the media asynchronously with options.
 **************************************************************************/
int
libvlc_media_parse_with_options( libvlc_media_t *media,
                                 libvlc_media_parse_flag_t parse_flag )
{
    return media_parse( media, true, parse_flag ) == VLC_SUCCESS ? 0 : -1;
792 793
}

794
/**************************************************************************
795
 * Get parsed status for media object.
796
 **************************************************************************/
797
int
798
libvlc_media_is_parsed(libvlc_media_t *media)
799
{
800
    bool parsed;
801

802 803 804 805
    vlc_mutex_lock(&media->parsed_lock);
    parsed = media->is_parsed;
    vlc_mutex_unlock(&media->parsed_lock);
    return parsed;
806 807 808
}

/**************************************************************************
Pierre's avatar
Pierre committed
809 810
 * Sets media descriptor's user_data. user_data is specialized data
 * accessed by the host application, VLC.framework uses it as a pointer to
811
 * an native object that references a libvlc_media_t pointer
812
 **************************************************************************/
Pierre's avatar
Pierre committed
813
void
814
libvlc_media_set_user_data( libvlc_media_t * p_md, void * p_new_user_data )
815
{
816 817
    assert( p_md );
    p_md->p_user_data = p_new_user_data;
818 819 820
}

/**************************************************************************
Pierre's avatar
Pierre committed
821 822
 * Get media descriptor's user_data. user_data is specialized data
 * accessed by the host application, VLC.framework uses it as a pointer to
823
 * an native object that references a libvlc_media_t pointer
824 825
 **************************************************************************/
void *
826
libvlc_media_get_user_data( libvlc_media_t * p_md )
827
{
828 829
    assert( p_md );
    return p_md->p_user_data;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
830
}
831 832 833 834 835

/**************************************************************************
 * Get media descriptor's elementary streams description
 **************************************************************************/
int
836
libvlc_media_get_tracks_info( libvlc_media_t *p_md, libvlc_media_track_info_t ** pp_es )
837 838 839 840 841 842 843
{
    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;
844
    *pp_es = (i_es > 0) ? malloc( i_es * sizeof(libvlc_media_track_info_t) ) : NULL;
845

846
    if( !*pp_es ) /* no ES, or OOM */
847 848 849 850 851 852 853 854
    {
        vlc_mutex_unlock( &p_input_item->lock );
        return 0;
    }

    /* Fill array */
    for( int i = 0; i < i_es; i++ )
    {
855
        libvlc_media_track_info_t *p_mes = *pp_es+i;
856 857 858
        const es_format_t *p_es = p_input_item->es[i];

        p_mes->i_codec = p_es->i_codec;
859
        p_mes->i_id = p_es->i_id;
860 861 862 863 864 865 866 867

        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:
868
            p_mes->i_type = libvlc_track_unknown;
869 870
            break;
        case VIDEO_ES:
871
            p_mes->i_type = libvlc_track_video;
872 873
            p_mes->u.video.i_height = p_es->video.i_height;
            p_mes->u.video.i_width = p_es->video.i_width;
874 875
            break;
        case AUDIO_ES:
876
            p_mes->i_type = libvlc_track_audio;
877 878
            p_mes->u.audio.i_channels = p_es->audio.i_channels;
            p_mes->u.audio.i_rate = p_es->audio.i_rate;
879 880
            break;
        case SPU_ES:
881
            p_mes->i_type = libvlc_track_text;
882 883 884 885 886 887 888
            break;
        }
    }

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

890
unsigned
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
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;
921
            free( p_mes );
922
            vlc_mutex_unlock( &p_input_item->lock );
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
            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;
            p_mes->video->i_height = p_es->video.i_height;
            p_mes->video->i_width = p_es->video.i_width;
            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;
            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;
}

972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
/**************************************************************************
 * 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 );
    }
}
992 993 994 995

/**************************************************************************
 * Release media descriptor's elementary streams description array
 **************************************************************************/
996
void libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count )
997
{
998
    for( unsigned i = 0; i < i_count; ++i )
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
    {
        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 );
}
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053

/**************************************************************************
 * 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;
    }
}