Media.hpp 25.1 KB
Newer Older
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
1
/*****************************************************************************
2
 * Media.hpp: Media API
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
3
 *****************************************************************************
4
 * Copyright © 2015 libvlcpp authors & VideoLAN
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
5
 *
6
 * Authors: Alexey Sokolov <alexey+vlc@asokolov.org>
7
 *          Hugo Beauzée-Luyssen <hugo@beauzee.fr>
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * 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
 * (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
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * 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.
 *****************************************************************************/

#ifndef LIBVLC_CXX_MEDIA_H
#define LIBVLC_CXX_MEDIA_H

27 28
#include "common.hpp"

29
#include <vector>
30
#include <stdexcept>
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
31

32
namespace VLC
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
33 34
{

35
class MediaEventManager;
36 37
class Instance;
class MediaList;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
38

39
class Media : protected CallbackOwner<4>, public Internal<libvlc_media_t>
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
40
{
41 42 43 44 45 46 47 48
private:
    enum class CallbackIdx : unsigned int
    {
        Open,
        Read,
        Seek,
        Close,
    };
49
#if !defined(_MSC_VER) || _MSC_VER >= 1900
50
    static constexpr unsigned int NbEvents = 4;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
51 52 53
#else
    static const unsigned int NbEvents = 4;
#endif
54

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
55
public:
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
56 57 58 59
    ///
    /// \brief The FromType enum is used to drive the media creation.
    /// A media is usually created using a string, which can represent one of 3 things:
    ///
60
    enum class FromType
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    {
        /**
         * Create a media for a certain file path.
         */
        FromPath,
        /**
         * Create a media with a certain given media resource location,
         * for instance a valid URL.
         *
         * \note To refer to a local file with this function,
         * the file://... URI syntax <b>must</b> be used (see IETF RFC3986).
         * We recommend using FromPath instead when dealing with
         * local files.
         */
        FromLocation,
        /**
         * Create a media as an empty node with a given name.
         */
        AsNode,
    };
81
    // To be able to write Media::FromLocation
82
#if !defined(_MSC_VER) || _MSC_VER >= 1900
83 84 85
    constexpr static FromType FromPath = FromType::FromPath;
    constexpr static FromType FromLocation = FromType::FromLocation;
    constexpr static FromType AsNode = FromType::AsNode;
86 87 88 89 90
#else
    static const FromType FromPath = FromType::FromPath;
    static const FromType FromLocation = FromType::FromLocation;
    static const FromType AsNode = FromType::AsNode;
#endif
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
91

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    enum class ParseFlags
    {
        /**
         * Parse media if it's a local file
         */
        Local = libvlc_media_parse_local,
        /**
         * Parse media even if it's a network file
         */
        Network = libvlc_media_parse_network,
        /**
         * Fetch meta and covert art using local resources
         */
        FetchLocal = libvlc_media_fetch_local,
        /**
         * Fetch meta and covert art using network resources
         */
        FetchNetwork = libvlc_media_fetch_network,
        /**
         * Interact with the user (via libvlc_dialog_cbs) when preparsing this item
         * (and not its sub items). Set this flag in order to receive a callback
         * when the input is asking for credentials.
         */
        Interact = libvlc_media_do_interact,
    };

118
    enum class ParsedStatus
119
    {
120 121 122 123
        Init = libvlc_media_parsed_status_init,
        Skipped = libvlc_media_parsed_status_skipped,
        Failed = libvlc_media_parsed_status_failed,
        Done = libvlc_media_parsed_status_done,
124 125
    };

126 127 128 129 130 131 132 133 134 135
    enum class Type
    {
        Unknown = libvlc_media_type_unknown,
        File = libvlc_media_type_file,
        Directory = libvlc_media_type_directory,
        Disc = libvlc_media_type_disc,
        Stream = libvlc_media_type_stream,
        Playlist = libvlc_media_type_playlist,
    };

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
136
    /**
137 138 139 140
     * @brief Media Constructs a libvlc Media instance
     * @param instance  A libvlc instance
     * @param mrl       A path, location, or node name, depending on the 3rd parameter
     * @param type      The type of the 2nd argument. \sa{FromType}
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
141
     */
142
    Media(Instance& instance, const std::string& mrl, FromType type)
143 144 145 146 147 148
        : Internal{ libvlc_media_release }
    {
        InternalPtr ptr = nullptr;
        switch (type)
        {
        case FromLocation:
149
            ptr = libvlc_media_new_location( getInternalPtr<libvlc_instance_t>( instance ), mrl.c_str() );
150 151
            break;
        case FromPath:
152
            ptr = libvlc_media_new_path( getInternalPtr<libvlc_instance_t>( instance ), mrl.c_str() );
153 154
            break;
        case AsNode:
155
            ptr = libvlc_media_new_as_node( getInternalPtr<libvlc_instance_t>( instance ), mrl.c_str() );
156 157 158 159 160 161
            break;
        default:
            break;
        }
        if ( ptr == nullptr )
            throw std::runtime_error("Failed to construct a media");
162
        m_obj.reset( ptr, libvlc_media_release );
163
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
164 165

    /**
166 167
     * Create a media for an already open file descriptor.
     * The file descriptor shall be open for reading (or reading and writing).
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
168 169
     *
     * Regular file descriptors, pipe read descriptors and character device
170 171 172 173 174 175 176 177
     * descriptors (including TTYs) are supported on all platforms.
     * Block device descriptors are supported where available.
     * Directory descriptors are supported on systems that provide fdopendir().
     * Sockets are supported on all platforms where they are file descriptors,
     * i.e. all except Windows.
     *
     * \note This library will <b>not</b> automatically close the file descriptor
     * under any circumstance. Nevertheless, a file descriptor can usually only be
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
178 179 180
     * rendered once in a media player. To render it a second time, the file
     * descriptor should probably be rewound to the beginning with lseek().
     *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
181
     * \param instance the instance
182
     * \param fd open file descriptor
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
183
     * \return the newly created media
184
     */
185 186 187
    Media(Instance& instance, int fd)
        : Internal { libvlc_media_new_fd( getInternalPtr<libvlc_instance_t>( instance ), fd ),
                     libvlc_media_release }
188 189
    {
    }
190 191 192 193 194

    /**
     * Get media instance from this media list instance. This action will increase
     * the refcount on the media instance.
     * The libvlc_media_list_lock should NOT be held upon entering this function.
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
195
     *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
196
     * \param list a media list instance
197
     * \return media instance
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
198
     */
199
    Media(MediaList& list)
200 201 202 203
        : Internal{ libvlc_media_list_media( getInternalPtr<libvlc_media_list_t>( list ) ),
                    libvlc_media_release }
    {
    }
204

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 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 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
    /**
     * Callback prototype to open a custom bitstream input media.
     *
     * The same media item can be opened multiple times. Each time, this callback
     * is invoked. It should allocate and initialize any instance-specific
     * resources, then store them in *datap. The instance resources can be freed
     * in the @ref libvlc_close_cb callback.
     *
     * \param opaque private pointer as passed to libvlc_media_new_callbacks()
     * \param datap storage space for a private data pointer [OUT]
     * \param sizep byte length of the bitstream or 0 if unknown [OUT]
     *
     * \note For convenience, *datap is initially NULL and *sizep is initially 0.
     *
     * \return 0 on success, non-zero on error. In case of failure, the other
     * callbacks will not be invoked and any value stored in *datap and *sizep is
     * discarded.
     */
    using ExpectedMediaOpenCb = int(void*, void** datap, uint64_t* sizep);

    /**
     * Callback prototype to read data from a custom bitstream input media.
     *
     * \param opaque private pointer as set by the @ref libvlc_media_open_cb
     *               callback
     * \param buf start address of the buffer to read data into
     * \param len bytes length of the buffer
     *
     * \return strictly positive number of bytes read, 0 on end-of-stream,
     *         or -1 on non-recoverable error
     *
     * \note If no data is immediately available, then the callback should sleep.
     * \warning The application is responsible for avoiding deadlock situations.
     * In particular, the callback should return an error if playback is stopped;
     * if it does not return, then libvlc_media_player_stop() will never return.
     */
    using ExpectedMediaReadCb = ssize_t(void* opaque, unsigned char* buf, size_t len);

    /**
     * Callback prototype to seek a custom bitstream input media.
     *
     * \param opaque private pointer as set by the @ref libvlc_media_open_cb
     *               callback
     * \param offset absolute byte offset to seek to
     * \return 0 on success, -1 on error.
     */
    using ExpectedMediaSeekCb = int(void* opaque, uint64_t);

    /**
     * Callback prototype to close a custom bitstream input media.
     * \param opaque private pointer as set by the @ref libvlc_media_open_cb
     *               callback
     */
    using ExpectedMediaCloseCb = void(void* opaque);

    /**
     * Create a media with custom callbacks to read the data from.
     *
     * \param instance LibVLC instance
     * \param open_cb callback to open the custom bitstream input media
     * \param read_cb callback to read data (must not be nullptr)
     * \param seek_cb callback to seek, or nullptr if seeking is not supported
     * \param close_cb callback to close the media, or nullptr if unnecessary
     *
     * \return the newly created media.
     *
     * \throw std::runtime_error if the media creation fails
     *
     * \note If open_cb is NULL, the opaque pointer will be passed to read_cb,
     * seek_cb and close_cb, and the stream size will be treated as unknown.
     *
     * \note The callbacks may be called asynchronously (from another thread).
     * A single stream instance need not be reentrant. However the open_cb needs to
     * be reentrant if the media is used by multiple player instances.
     *
     * \warning The callbacks may be used until all or any player instances
     * that were supplied the media item are stopped.
     *
     * \see ExpectedMediaOpenCb
     * \see ExpectedMediaReadCb
     * \see ExpectedMediaSeekCb
     * \see ExpectedMediaCloseCb
     *
     * \version LibVLC 3.0.0 and later.
     */

    template <typename OpenCb, typename ReadCb, typename SeekCb, typename CloseCb>
    Media( Instance& instance, OpenCb&& openCb, ReadCb&& readCb, SeekCb&& seekCb, CloseCb&& closeCb )
    {
        static_assert( signature_match_or_nullptr<OpenCb, ExpectedMediaOpenCb>::value, "Mismatched Open callback prototype" );
        static_assert( signature_match_or_nullptr<SeekCb, ExpectedMediaSeekCb>::value, "Mismatched Seek callback prototype" );
        static_assert( signature_match_or_nullptr<CloseCb, ExpectedMediaCloseCb>::value, "Mismatched Close callback prototype" );
        static_assert( signature_match<ReadCb, ExpectedMediaReadCb>::value, "Mismatched Read callback prototype" );

        auto ptr = libvlc_media_new_callbacks( instance,
            imem::CallbackWrapper<(unsigned int)CallbackIdx::Open, libvlc_media_open_cb>::
                wrap<imem::GuessBoxingStrategy<OpenCb, imem::BoxingStrategy::Setup>::Strategy>(
303
                    *m_callbacks, std::forward<OpenCb>( openCb ) ),
304 305
            imem::CallbackWrapper<(unsigned int)CallbackIdx::Read, libvlc_media_read_cb>::
                wrap<imem::GuessBoxingStrategy<OpenCb, imem::BoxingStrategy::Unbox>::Strategy>(
306
                    *m_callbacks, std::forward<ReadCb>( readCb ) ),
307 308
            imem::CallbackWrapper<(unsigned int)CallbackIdx::Seek, libvlc_media_seek_cb>::
                wrap<imem::GuessBoxingStrategy<OpenCb, imem::BoxingStrategy::Unbox>::Strategy>(
309
                    *m_callbacks, std::forward<SeekCb>( seekCb ) ),
310 311
            imem::CallbackWrapper<(unsigned int)CallbackIdx::Close, libvlc_media_close_cb>::
                wrap<imem::GuessBoxingStrategy<OpenCb, imem::BoxingStrategy::Cleanup>::Strategy>(
312 313
                    *m_callbacks, std::forward<CloseCb>( closeCb ) ),
            m_callbacks.get()
314 315 316 317 318 319 320 321
        );
        if ( ptr == nullptr )
            throw std::runtime_error( "Failed to create media" );
        m_obj.reset( ptr, libvlc_media_release );
    }

#endif

322
    explicit Media( Internal::InternalPtr ptr, bool incrementRefCount)
323 324
        : Internal{ ptr, libvlc_media_release }
    {
325
        if ( incrementRefCount && ptr != nullptr )
326 327
            retain();
    }
328

329 330 331 332 333 334 335
    /**
     * Create an empty VLC Media instance.
     *
     * Calling any method on such an instance is undefined.
    */
    Media() = default;

336 337 338 339 340
    /**
     * Check if 2 Media objects contain the same libvlc_media_t.
     * \param another another Media
     * \return true if they contain the same libvlc_media_t
     */
341 342 343 344
    bool operator==(const Media& another) const
    {
        return m_obj == another.m_obj;
    }
345

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
    /**
     * Add an option to the media.
     *
     * This option will be used to determine how the media_player will read
     * the media. This allows to use VLC's advanced reading/streaming options
     * on a per-media basis.
     *
     * \note The options are listed in 'vlc long-help' from the command line,
     * e.g. "-sout-all". Keep in mind that available options and their
     * semantics vary across LibVLC versions and builds.
     *
     * \warning Not all options affects libvlc_media_t objects: Specifically,
     * due to architectural issues most audio and video options, such as text
     * renderer options, have no effects on an individual media. These
     * options must be set through Instance::Instance() instead.
     *
     * \param psz_options  the options (as a string)
     */
364 365
    void addOption(const std::string& psz_options)
    {
366
        libvlc_media_add_option(*this,psz_options.c_str());
367
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385

    /**
     * Add an option to the media with configurable flags.
     *
     * This option will be used to determine how the media_player will read
     * the media. This allows to use VLC's advanced reading/streaming options
     * on a per-media basis.
     *
     * The options are detailed in vlc long-help, for instance "--sout-all".
     * Note that all options are not usable on medias: specifically, due to
     * architectural issues, video-related options such as text renderer
     * options cannot be set on a single media. They must be set on the whole
     * libvlc instance instead.
     *
     * \param psz_options  the options (as a string)
     *
     * \param i_flags  the flags for this option
     */
386 387
    void addOptionFlag(const std::string& psz_options, unsigned i_flags)
    {
388
        libvlc_media_add_option_flag(*this,psz_options.c_str(), i_flags);
389
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
390 391 392 393 394 395

    /**
     * Get the media resource locator (mrl) from a media descriptor object
     *
     * \return string with mrl of media descriptor object
     */
396 397
    std::string mrl()
    {
398 399 400 401
        auto str = wrapCStr( libvlc_media_get_mrl(*this) );
        if ( str == nullptr )
            return {};
        return str.get();
402
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
403 404 405 406

    /**
     * Duplicate a media descriptor object.
     */
407
    Media duplicate()
408
    {
409
        auto obj = libvlc_media_duplicate(*this);
410 411 412 413 414
        // Assume failure to duplicate is due to VLC_ENOMEM.
        // libvlc_media_duplicate(nullptr) would also return nullptr, but
        // we consider the use of an empty libvlcpp instance undefined.
        if ( obj == nullptr )
            throw std::bad_alloc();
415
        return Media( obj, false );
416
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
417 418 419 420 421 422

    /**
     * Read the meta of the media.
     *
     * If the media has not yet been parsed this will return NULL.
     *
423
     * This methods automatically calls parseAsync() , so after
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
424
     * calling it you may receive a libvlc_MediaMetaChanged event. If you
425
     * prefer a synchronous version ensure that you call parse()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
426 427
     * before get_meta().
     *
428
     * \see parse()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
429
     *
430
     * \see parseAsync()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
431 432 433 434 435 436 437
     *
     * \see libvlc_MediaMetaChanged
     *
     * \param e_meta  the meta to read
     *
     * \return the media's meta
     */
438 439
    std::string meta(libvlc_meta_t e_meta)
    {
440 441 442 443
        auto str = wrapCStr(libvlc_media_get_meta(*this, e_meta) );
        if ( str == nullptr )
            return {};
        return str.get();
444
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
445 446 447 448 449 450 451 452 453

    /**
     * Set the meta of the media (this function will not save the meta, call
     * libvlc_media_save_meta in order to save the meta)
     *
     * \param e_meta  the meta to write
     *
     * \param psz_value  the media's meta
     */
454 455
    void setMeta(libvlc_meta_t e_meta, const std::string& psz_value)
    {
456
        libvlc_media_set_meta(*this, e_meta, psz_value.c_str());
457 458
    }

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
459 460 461 462 463 464

    /**
     * Save the meta previously set
     *
     * \return true if the write operation was successful
     */
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
465
    bool saveMeta()
466
    {
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
467
        return libvlc_media_save_meta(*this) != 0;
468
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
469 470 471 472 473 474 475 476 477 478 479

    /**
     * Get current state of media descriptor object. Possible media states
     * are defined in libvlc_structures.c ( libvlc_NothingSpecial=0,
     * libvlc_Opening, libvlc_Buffering, libvlc_Playing, libvlc_Paused,
     * libvlc_Stopped, libvlc_Ended, libvlc_Error).
     *
     * \see libvlc_state_t
     *
     * \return state of media descriptor object
     */
480 481
    libvlc_state_t state()
    {
482
        return libvlc_media_get_state(*this);
483
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
484 485 486 487 488 489 490 491 492

    /**
     * Get the current statistics about the media
     *
     * \param p_stats  structure that contain the statistics about the media
     * (this structure must be allocated by the caller)
     *
     * \return true if the statistics are available, false otherwise
     */
493 494
    bool stats(libvlc_media_stats_t * p_stats)
    {
495
        return libvlc_media_get_stats(*this, p_stats) != 0;
496
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
497 498 499 500 501 502 503

    /**
     * Get event manager from media descriptor object. NOTE: this function
     * doesn't increment reference counting.
     *
     * \return event manager object
     */
504
    MediaEventManager& eventManager()
505
    {
506
        if ( m_eventManager == nullptr )
507
        {
508
            libvlc_event_manager_t* obj = libvlc_media_event_manager(*this);
509
            m_eventManager = std::make_shared<MediaEventManager>( obj );
510
        }
511
        return *m_eventManager;
512
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
513 514 515 516 517 518

    /**
     * Get duration (in ms) of media descriptor object item.
     *
     * \return duration of media item or -1 on error
     */
519 520
    libvlc_time_t duration()
    {
521
        return libvlc_media_get_duration(*this);
522
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
523 524 525 526 527 528 529

    /**
     * Parse a media.
     *
     * This fetches (local) meta data and tracks information. The method is
     * synchronous.
     *
530
     * \see parseAsync()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
531
     *
532
     * \see meta()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
533
     *
534
     * \see tracksInfo()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
535
     */
536 537
    void parse()
    {
538
        libvlc_media_parse(*this);
539
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
540

541
#if LIBVLC_VERSION_INT < LIBVLC_VERSION(3, 0, 0, 0)
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
542 543 544 545
    /**
     * Parse a media.
     *
     * This fetches (local) meta data and tracks information. The method is
546
     * the asynchronous of parse() .
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
547 548 549 550 551
     *
     * To track when this is over you can listen to libvlc_MediaParsedChanged
     * event. However if the media was already parsed you will not receive
     * this event.
     *
552
     * \see parse()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
553 554 555
     *
     * \see libvlc_MediaParsedChanged
     *
556
     * \see meta()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
557
     *
558
     * \see tracks()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
559
     */
560 561
    void parseAsync()
    {
562
        libvlc_media_parse_async(*this);
563
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
564 565 566 567 568 569 570 571 572

    /**
     * Get Parsed status for media descriptor object.
     *
     * \see libvlc_MediaParsedChanged
     *
     * \return true if media object has been parsed otherwise it returns
     * false
     */
573 574
    bool isParsed()
    {
575
        return libvlc_media_is_parsed(*this) != 0;
576
    }
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
#else
    /**
     * Parse the media asynchronously with options.
     *
     * This fetches (local or network) art, meta data and/or tracks information.
     * This method is the extended version of libvlc_media_parse_async().
     *
     * To track when this is over you can listen to libvlc_MediaParsedStatus
     * event. However if this functions returns an error, you will not receive any
     * events.
     *
     * It uses a flag to specify parse options (see libvlc_media_parse_flag_t). All
     * these flags can be combined. By default, media is parsed if it's a local
     * file.
     *
     * \see ParsedStatus
     * \see meta()
     * \see tracks()
     * \see parsedStatus
     * \see ParseFlag
     *
     * \return true on success, false otherwise
     * \version LibVLC 3.0.0 or later
     */
    bool parseWithOptions( ParseFlags flags )
    {
603
        return libvlc_media_parse_with_options( *this, static_cast<libvlc_media_parse_flag_t>( flags ) ) == 0;
604 605
    }

606
    ParsedStatus parsedStatus()
607
    {
608
        return static_cast<ParsedStatus>( libvlc_media_get_parsed_status( *this ) );
609 610
    }
#endif
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
611 612 613 614 615 616 617 618

    /**
     * Sets media descriptor's user_data. user_data is specialized data
     * accessed by the host application, VLC.framework uses it as a pointer
     * to an native object that references a libvlc_media_t pointer
     *
     * \param p_new_user_data  pointer to user data
     */
619 620
    void setUserData(void * p_new_user_data)
    {
621
        libvlc_media_set_user_data(*this, p_new_user_data);
622
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
623 624 625 626 627 628

    /**
     * Get media descriptor's user_data. user_data is specialized data
     * accessed by the host application, VLC.framework uses it as a pointer
     * to an native object that references a libvlc_media_t pointer
     */
629 630
    void* userData()
    {
631
        return libvlc_media_get_user_data(*this);
632
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
633 634 635 636

    /**
     * Get media descriptor's elementary streams description
     *
637
     * Note, you need to call parse() or play the media at least once
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
638
     * before calling this function. Not doing this will result in an empty
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
639
     * list.
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
640 641 642
     *
     * \version LibVLC 2.1.0 and later.
     *
643
     * \return a vector containing all tracks
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
644
     */
645 646 647
    std::vector<MediaTrack> tracks()
    {
        libvlc_media_track_t**  tracks;
648
        uint32_t                nbTracks = libvlc_media_tracks_get(*this, &tracks);
649 650 651 652 653 654
        std::vector<MediaTrack> res;

        if ( nbTracks == 0 )
            return res;

        for ( uint32_t i = 0; i < nbTracks; ++i )
655
            res.emplace_back( tracks[i] );
656 657 658
        libvlc_media_tracks_release( tracks, nbTracks );
        return res;
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
659

660 661 662 663 664 665 666 667
    std::shared_ptr<MediaList> subitems()
    {
        auto p = libvlc_media_subitems( *this );
        if ( p == nullptr )
            return nullptr;
        return std::make_shared<MediaList>( p );
    }

668 669 670 671 672
    Type type()
    {
        return static_cast<Type>( libvlc_media_get_type( *this ) );
    }

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 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
    /**
     * Add a slave to the current media.
     *
     * A slave is an external input source that may contains an additional subtitle
     * track (like a .srt) or an additional audio track (like a .ac3).
     *
     * \note This function must be called before the media is parsed (via parseWithOptions())
     *  or before the media is played (via MediaPlayer::play())
     *
     * \version LibVLC 3.0.0 and later.
     *
     * \param uri Uri of the slave (should contain a valid scheme).
     * \param type subtitle or audio
     * \param priority from 0 (low priority) to 4 (high priority)
     *
     * \return true on success, false on error.
     */
    bool addSlave(MediaSlave::Type type, unsigned priority, std::string const &uri)
    {
        return libvlc_media_slaves_add(*this, (libvlc_media_slave_type_t)type, priority, uri.c_str()) == 0;
    }

    /**
     * Clear all slaves previously added by addSlave() or
     * internally.
     *
     * \version LibVLC 3.0.0 and later.
     */
    void slavesClear()
    {
        libvlc_media_slaves_clear(*this);
    }

    /**
     * Get a media descriptor's slaves in a vector
     *
     * The list will contain slaves parsed by VLC or previously added by
     * addSlave(). The typical use case of this function is to save
     * a list of slave in a database for a later use.
     *
     * \version LibVLC 3.0.0 and later.
     *
     * \see addSlave()
     *
     * \return a vector of MediaSlave
     */
    std::vector<MediaSlave> slaves() const
    {
        libvlc_media_slave_t **list = nullptr;

723
        auto length = libvlc_media_slaves_get(*this, &list);
724 725
        if (length == 0)
            return {};
726 727 728 729
        auto deletor = [length](libvlc_media_slave_t **p_list) {
            libvlc_media_slaves_release(p_list, length);
        };
        std::unique_ptr<libvlc_media_slave_t*, decltype(deletor)> scope_gard(list, deletor);
730 731 732 733
        std::vector<MediaSlave> res(list, list + length);
        return res;
    }

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
734
private:
735

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
736 737
    /**
     * Retain a reference to a media descriptor object (libvlc_media_t). Use
738
     * release() to decrement the reference count of a media
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
739 740
     * descriptor object.
     */
741 742 743
    void retain()
    {
        if ( isValid() )
744
            libvlc_media_retain(*this);
745
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
746

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
747

748
private:
749
    std::shared_ptr<MediaEventManager> m_eventManager;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
750 751
};

752 753 754 755 756 757
inline VLC::Media::ParseFlags operator|(Media::ParseFlags l, Media::ParseFlags r)
{
    using T = typename std::underlying_type<Media::ParseFlags>::type;
    return static_cast<Media::ParseFlags>( static_cast<T>( l ) | static_cast<T>( r ) );
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
758 759 760 761
} // namespace VLC

#endif