Media.hpp 27.5 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
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
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 118
    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,
    };

119
    enum class ParsedStatus
120
    {
121 122 123
        Skipped = libvlc_media_parsed_status_skipped,
        Failed = libvlc_media_parsed_status_failed,
        Done = libvlc_media_parsed_status_done,
124
        Timeout = libvlc_media_parsed_status_timeout,
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,
    };
136
#endif
137

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
138
    /**
139 140 141 142
     * @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
143
     */
144
    Media(Instance& instance, const std::string& mrl, FromType type)
145 146 147 148 149 150
        : Internal{ libvlc_media_release }
    {
        InternalPtr ptr = nullptr;
        switch (type)
        {
        case FromLocation:
151
            ptr = libvlc_media_new_location( getInternalPtr<libvlc_instance_t>( instance ), mrl.c_str() );
152 153
            break;
        case FromPath:
154
            ptr = libvlc_media_new_path( getInternalPtr<libvlc_instance_t>( instance ), mrl.c_str() );
155 156
            break;
        case AsNode:
157
            ptr = libvlc_media_new_as_node( getInternalPtr<libvlc_instance_t>( instance ), mrl.c_str() );
158 159 160 161 162 163
            break;
        default:
            break;
        }
        if ( ptr == nullptr )
            throw std::runtime_error("Failed to construct a media");
164
        m_obj.reset( ptr, libvlc_media_release );
165
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
166 167

    /**
168 169
     * 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
170 171
     *
     * Regular file descriptors, pipe read descriptors and character device
172 173 174 175 176 177 178 179
     * 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
180 181 182
     * 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
183
     * \param instance the instance
184
     * \param fd open file descriptor
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
185
     * \return the newly created media
186
     */
187 188 189
    Media(Instance& instance, int fd)
        : Internal { libvlc_media_new_fd( getInternalPtr<libvlc_instance_t>( instance ), fd ),
                     libvlc_media_release }
190 191
    {
    }
192 193 194 195 196

    /**
     * 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
197
     *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
198
     * \param list a media list instance
199
     * \return media instance
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
200
     */
201
    Media(MediaList& list)
202 203 204 205
        : Internal{ libvlc_media_list_media( getInternalPtr<libvlc_media_list_t>( list ) ),
                    libvlc_media_release }
    {
    }
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 303 304
#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>(
305
                    *m_callbacks, std::forward<OpenCb>( openCb ) ),
306 307
            imem::CallbackWrapper<(unsigned int)CallbackIdx::Read, libvlc_media_read_cb>::
                wrap<imem::GuessBoxingStrategy<OpenCb, imem::BoxingStrategy::Unbox>::Strategy>(
308
                    *m_callbacks, std::forward<ReadCb>( readCb ) ),
309 310
            imem::CallbackWrapper<(unsigned int)CallbackIdx::Seek, libvlc_media_seek_cb>::
                wrap<imem::GuessBoxingStrategy<OpenCb, imem::BoxingStrategy::Unbox>::Strategy>(
311
                    *m_callbacks, std::forward<SeekCb>( seekCb ) ),
312 313
            imem::CallbackWrapper<(unsigned int)CallbackIdx::Close, libvlc_media_close_cb>::
                wrap<imem::GuessBoxingStrategy<OpenCb, imem::BoxingStrategy::Cleanup>::Strategy>(
314 315
                    *m_callbacks, std::forward<CloseCb>( closeCb ) ),
            m_callbacks.get()
316 317 318 319 320 321 322 323
        );
        if ( ptr == nullptr )
            throw std::runtime_error( "Failed to create media" );
        m_obj.reset( ptr, libvlc_media_release );
    }

#endif

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

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

338 339 340 341 342
    /**
     * 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
     */
343 344 345 346
    bool operator==(const Media& another) const
    {
        return m_obj == another.m_obj;
    }
347

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
    /**
     * 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)
     */
366 367
    void addOption(const std::string& psz_options)
    {
368
        libvlc_media_add_option(*this,psz_options.c_str());
369
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387

    /**
     * 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
     */
388 389
    void addOptionFlag(const std::string& psz_options, unsigned i_flags)
    {
390
        libvlc_media_add_option_flag(*this,psz_options.c_str(), i_flags);
391
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
392 393 394 395 396 397

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

    /**
     * Duplicate a media descriptor object.
     */
409
    Media duplicate()
410
    {
411
        auto obj = libvlc_media_duplicate(*this);
412 413 414 415 416
        // 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();
417
        return Media( obj, false );
418
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
419 420 421 422 423 424

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

    /**
     * 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
     */
456 457
    void setMeta(libvlc_meta_t e_meta, const std::string& psz_value)
    {
458
        libvlc_media_set_meta(*this, e_meta, psz_value.c_str());
459 460
    }

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
461 462 463 464 465 466

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

    /**
     * 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
     */
482 483
    libvlc_state_t state()
    {
484
        return libvlc_media_get_state(*this);
485
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
486 487 488 489 490 491 492 493 494

    /**
     * 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
     */
495 496
    bool stats(libvlc_media_stats_t * p_stats)
    {
497
        return libvlc_media_get_stats(*this, p_stats) != 0;
498
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
499 500 501 502 503 504 505

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

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

526
#if LIBVLC_VERSION_INT < LIBVLC_VERSION(3, 0, 0, 0)
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
527 528 529 530 531 532
    /**
     * Parse a media.
     *
     * This fetches (local) meta data and tracks information. The method is
     * synchronous.
     *
533
     * \see parseAsync()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
534
     *
535
     * \see meta()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
536
     *
537
     * \see tracksInfo()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
538
     */
539 540
    void parse()
    {
541
        libvlc_media_parse(*this);
542
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
543 544 545 546 547

    /**
     * Parse a media.
     *
     * This fetches (local) meta data and tracks information. The method is
548
     * the asynchronous of parse() .
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
549 550 551 552 553
     *
     * 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.
     *
554
     * \see parse()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
555 556 557
     *
     * \see libvlc_MediaParsedChanged
     *
558
     * \see meta()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
559
     *
560
     * \see tracks()
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
561
     */
562 563
    void parseAsync()
    {
564
        libvlc_media_parse_async(*this);
565
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
566 567 568 569 570 571 572 573 574

    /**
     * Get Parsed status for media descriptor object.
     *
     * \see libvlc_MediaParsedChanged
     *
     * \return true if media object has been parsed otherwise it returns
     * false
     */
575 576
    bool isParsed()
    {
577
        return libvlc_media_is_parsed(*this) != 0;
578
    }
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
#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
601 602 603 604
     * \param flags parse options
     * \param timeout maximum time allowed to preparse the media. If -1, the
     *      default "preparse-timeout" option will be used as a timeout. If 0, it will
     *      wait indefinitely. If > 0, the timeout will be used (in milliseconds).
605 606
     * \version LibVLC 3.0.0 or later
     */
607
    bool parseWithOptions( ParseFlags flags, int timeout )
608
    {
609
        return libvlc_media_parse_with_options( *this, static_cast<libvlc_media_parse_flag_t>( flags ), timeout ) == 0;
610 611
    }

612
    ParsedStatus parsedStatus()
613
    {
614
        return static_cast<ParsedStatus>( libvlc_media_get_parsed_status( *this ) );
615
    }
Pierre Lamot's avatar
Pierre Lamot committed
616 617 618 619 620

    void parseStop()
    {
        libvlc_media_parse_stop( *this );
    }
621
#endif
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
622 623 624 625 626 627 628 629

    /**
     * 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
     */
630 631
    void setUserData(void * p_new_user_data)
    {
632
        libvlc_media_set_user_data(*this, p_new_user_data);
633
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
634 635 636 637 638 639

    /**
     * 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
     */
640 641
    void* userData()
    {
642
        return libvlc_media_get_user_data(*this);
643
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
644 645 646 647

    /**
     * Get media descriptor's elementary streams description
     *
648
     * Note, you need to call parse() or play the media at least once
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
649
     * before calling this function. Not doing this will result in an empty
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
650
     * list.
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
651 652 653
     *
     * \version LibVLC 2.1.0 and later.
     *
654
     * \return a vector containing all tracks
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
655
     */
656 657 658
    std::vector<MediaTrack> tracks()
    {
        libvlc_media_track_t**  tracks;
659
        uint32_t                nbTracks = libvlc_media_tracks_get(*this, &tracks);
660 661 662 663 664 665
        std::vector<MediaTrack> res;

        if ( nbTracks == 0 )
            return res;

        for ( uint32_t i = 0; i < nbTracks; ++i )
666
            res.emplace_back( tracks[i] );
667 668 669
        libvlc_media_tracks_release( tracks, nbTracks );
        return res;
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
670

671 672 673 674 675 676 677 678
    std::shared_ptr<MediaList> subitems()
    {
        auto p = libvlc_media_subitems( *this );
        if ( p == nullptr )
            return nullptr;
        return std::make_shared<MediaList>( p );
    }

679
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
680 681 682 683 684
    Type type()
    {
        return static_cast<Type>( libvlc_media_get_type( *this ) );
    }

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 723 724 725 726 727 728 729 730 731 732 733 734
    /**
     * 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;

735
        auto length = libvlc_media_slaves_get(*this, &list);
736 737
        if (length == 0)
            return {};
738 739 740 741
        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);
742 743 744
        std::vector<MediaSlave> res(list, list + length);
        return res;
    }
745
#endif
746 747 748 749 750 751 752 753 754 755 756 757 758 759
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)
    using ThumbnailRequest = libvlc_media_thumbnail_request_t;

    enum class ThumbnailSeekSpeed
    {
        Precise = libvlc_media_thumbnail_seek_precise,
        Fast = libvlc_media_thumbnail_seek_fast,
    };

    ThumbnailRequest* thumbnailRequestByTime( libvlc_time_t time, ThumbnailSeekSpeed speed,
                                              uint32_t width, uint32_t height,
                                              Picture::Type type, libvlc_time_t timeout )
    {
        return libvlc_media_thumbnail_request_by_time( *this, time,
760
                    static_cast<libvlc_thumbnailer_seek_speed_t>( speed ), width,
761 762 763 764 765 766 767 768
                    height, static_cast<libvlc_picture_type_t>( type ), timeout );
    }

    ThumbnailRequest* thumbnailRequestByPos( float pos, ThumbnailSeekSpeed speed,
                                             uint32_t width, uint32_t height,
                                             Picture::Type type, libvlc_time_t timeout )
    {
        return libvlc_media_thumbnail_request_by_pos( *this, pos,
769
                    static_cast<libvlc_thumbnailer_seek_speed_t>( speed ), width,
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
                    height, static_cast<libvlc_picture_type_t>( type ), timeout );
    }

    /**
     * @brief thumbnailCancel cancels a thumbnailing request
     * @param request An opaque thumbnail request object.
     *
     * Cancelling the request will still cause onThumbnailGenerated callback
     * to be invoked, with nullptr as the picture instance.
     * If the request is cancelled after its completion, the behavior is undefined.
     */
    void thumbnailCancel( ThumbnailRequest* request )
    {
        libvlc_media_thumbnail_cancel( request );
    }

#endif

788

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
789
private:
790

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
791 792
    /**
     * Retain a reference to a media descriptor object (libvlc_media_t). Use
793
     * release() to decrement the reference count of a media
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
794 795
     * descriptor object.
     */
796 797 798
    void retain()
    {
        if ( isValid() )
799
            libvlc_media_retain(*this);
800
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
801

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

803
private:
804
    std::shared_ptr<MediaEventManager> m_eventManager;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
805 806
};

807
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
808 809
inline VLC::Media::ParseFlags operator|(Media::ParseFlags l, Media::ParseFlags r)
{
810
#if !defined(_MSC_VER) || _MSC_VER >= 1900
811
    using T = typename std::underlying_type<Media::ParseFlags>::type;
812 813 814
#else
    using T = std::underlying_type<Media::ParseFlags>::type;
#endif
815 816
    return static_cast<Media::ParseFlags>( static_cast<T>( l ) | static_cast<T>( r ) );
}
817
#endif
818

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
819 820 821 822
} // namespace VLC

#endif