Instance.hpp 20.7 KB
Newer Older
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
1
/*****************************************************************************
2
 * Instance.hpp: Instance 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>
8
 *          Bastien Penavayre <bastienpenava@gmail.com>
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * 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_INSTANCE_H
#define LIBVLC_CXX_INSTANCE_H

28
#include "common.hpp"
29
#include "Internal.hpp"
30
#include "structures.hpp"
31
#include "Dialog.hpp"
32
#include "MediaDiscoverer.hpp"
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
33

34 35
#include <string>
#include <vector>
36
#include <cstring>
37
#include <cstdio>
38

39 40
namespace VLC
{
41 42

#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
43
using Question = libvlc_dialog_question_type;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
44

45 46 47 48 49 50
namespace DialogType
{
    static constexpr Question normal = LIBVLC_DIALOG_QUESTION_NORMAL;
    static constexpr Question warning = LIBVLC_DIALOG_QUESTION_WARNING;
    static constexpr Question critical = LIBVLC_DIALOG_QUESTION_CRITICAL;
}
51
#endif
52

53
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
54
class Instance : protected CallbackOwner<8>, public Internal<libvlc_instance_t>
55 56 57
#else
class Instance : protected CallbackOwner<5>, public Internal<libvlc_instance_t>
#endif
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
58
{
59
private:
60
    enum class CallbackIdx : unsigned int
61
    {
62 63 64
        Exit = 0,
        Log,
        ErrorDisplay,
65
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
66 67 68 69 70
        LoginDisplay,
        QuestionDisplay,
        ProgressDisplay,
        CancelDialog,
        ProgressUpdate
71
#endif
72
    };
73

74
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
75
    std::shared_ptr<libvlc_dialog_cbs> m_callbacks_pointers;
76
#endif
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
public:
    /**
     * Create and initialize a libvlc instance. This functions accept a list
     * of "command line" arguments similar to the main(). These arguments
     * affect the LibVLC instance default configuration.
     *
     * \version Arguments are meant to be passed from the command line to
     * LibVLC, just like VLC media player does. The list of valid arguments
     * depends on the LibVLC version, the operating system and platform, and
     * set of available LibVLC plugins. Invalid or unsupported arguments will
     * cause the function to fail (i.e. return NULL). Also, some arguments
     * may alter the behaviour or otherwise interfere with other LibVLC
     * functions.
     *
     * \warning There is absolutely no warranty or promise of forward,
     * backward and cross-platform compatibility with regards to
     * Instance::Instance() arguments. We recommend that you do not use them,
     * other than when debugging.
     *
     * \param argc  the number of arguments (should be 0)
     *
     * \param argv  list of arguments (should be NULL)
     */
100
    Instance(int argc, const char *const * argv)
101 102 103 104
        : Internal{ libvlc_new( argc, argv ), libvlc_release }
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
          , m_callbacks_pointers { std::make_shared<libvlc_dialog_cbs>() }
#endif
105 106
    {
    }
107

108 109 110 111 112 113 114
    /**
     * Create an empty VLC instance.
     *
     * Calling any method on such an instance is undefined.
    */
    Instance() = default;

115 116 117 118 119
    /**
     * Check if 2 Instance objects contain the same libvlc_instance_t.
     * \param another another Instance
     * \return true if they contain the same libvlc_instance_t
     */
120 121 122 123 124
    bool operator==(const Instance& another) const
    {
        return m_obj == another.m_obj;
    }

125

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
126 127 128
    /**
     * Try to start a user interface for the libvlc instance.
     *
129
     * \param name  interface name, or empty string for default
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
130
     */
131
    bool addIntf(const std::string& name)
132
    {
133
        return libvlc_add_intf( *this, name.length() > 0 ? name.c_str() : nullptr ) == 0;
134
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
135 136 137 138 139 140 141 142 143 144 145 146

    /**
     * Registers a callback for the LibVLC exit event. This is mostly useful
     * if the VLC playlist and/or at least one interface are started with
     * libvlc_playlist_play() or Instance::addIntf() respectively. Typically,
     * this function will wake up your application main loop (from another
     * thread).
     *
     * \note This function should be called before the playlist or interface
     * are started. Otherwise, there is a small race condition: the exit
     * event could be raised before the handler is registered.
     *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
147 148 149
     * \param cb  callback to invoke when LibVLC wants to exit, or nullptr to
     * disable the exit handler (as by default). It is expected to be a
     * std::function<void()>, or an equivalent Callable type
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
150
     */
151 152
    template <typename ExitCb>
    void setExitHandler(ExitCb&& exitCb)
153
    {
154 155
        static_assert(signature_match_or_nullptr<ExitCb, void()>::value, "Mismatched exit callback" );
        libvlc_set_exit_handler( *this,
156 157
            CallbackWrapper<(unsigned int)CallbackIdx::Exit, void(*)(void*)>::wrap( *m_callbacks, std::forward<ExitCb>( exitCb ) ),
            m_callbacks.get() );
158
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
159 160 161 162 163 164 165 166 167 168 169 170

    /**
     * Sets the application name. LibVLC passes this as the user agent string
     * when a protocol requires it.
     *
     * \param name  human-readable application name, e.g. "FooBar player
     * 1.2.3"
     *
     * \param http  HTTP User Agent, e.g. "FooBar/1.2.3 Python/2.6.0"
     *
     * \version LibVLC 1.1.1 or later
     */
171 172
    void setUserAgent(const std::string& name, const std::string& http)
    {
173
        libvlc_set_user_agent( *this, name.c_str(), http.c_str() );
174
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
175 176 177 178 179 180 181 182 183 184 185 186 187

    /**
     * Sets some meta-information about the application. See also
     * Instance::setUserAgent() .
     *
     * \param id  Java-style application identifier, e.g. "com.acme.foobar"
     *
     * \param version  application version numbers, e.g. "1.2.3"
     *
     * \param icon  application icon name, e.g. "foobar"
     *
     * \version LibVLC 2.1.0 or later.
     */
188 189
    void setAppId(const std::string& id, const std::string& version, const std::string& icon)
    {
190
        libvlc_set_app_id( *this, id.c_str(), version.c_str(), icon.c_str() );
191
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
192 193 194 195 196 197 198 199 200 201

    /**
     * Unsets the logging callback for a LibVLC instance. This is rarely
     * needed: the callback is implicitly unset when the instance is
     * destroyed. This function will wait for any pending callbacks
     * invocation to complete (causing a deadlock if called from within the
     * callback).
     *
     * \version LibVLC 2.1.0 or later
     */
202 203
    void logUnset()
    {
204
        libvlc_log_unset( *this );
205
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
206 207 208 209 210 211 212 213 214 215

    /**
     * Sets the logging callback for a LibVLC instance. This function is
     * thread-safe: it will wait for any pending callbacks invocation to
     * complete.
     *
     * \note Some log messages (especially debug) are emitted by LibVLC while
     * is being initialized. These messages cannot be captured with this
     * interface.
     *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
216 217 218
     * \param logCb A std::function<void(int, const libvlc_log_t*, std::string)>
     *              or an equivalent Callable type instance.
     *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
219 220 221 222 223
     * \warning A deadlock may occur if this function is called from the
     * callback.
     *
     * \version LibVLC 2.1.0 or later
     */
224 225
    template <typename LogCb>
    void logSet(LogCb&& logCb)
226
    {
227 228 229
        static_assert(signature_match<LogCb, void(int, const libvlc_log_t*, std::string)>::value,
                      "Mismatched log callback" );
        auto wrapper = [logCb](int level, const libvlc_log_t* ctx, const char* format, va_list va) {
230 231 232 233 234
            const char* psz_module;
            const char* psz_file;
            unsigned int i_line;
            libvlc_log_get_context( ctx, &psz_module, &psz_file, &i_line );

235 236 237
#ifndef _MSC_VER
            VaCopy vaCopy(va);
            int len = vsnprintf(nullptr, 0, format, vaCopy.va);
238 239 240 241 242 243
            if (len < 0)
                return;
            std::unique_ptr<char[]> message{ new char[len + 1] };
            char* psz_msg = message.get();
            if (vsnprintf(psz_msg, len + 1, format, va) < 0 )
                return;
244 245 246 247
            char* psz_ctx;
            if (asprintf(&psz_ctx, "[%s] (%s:%d) %s", psz_module, psz_file, i_line, psz_msg) < 0)
                return;
            std::unique_ptr<char, void(*)(void*)> ctxPtr(psz_ctx, &free);
248 249
#else
            //MSVC treats passing nullptr as 1st vsnprintf(_s) as an error
250 251 252
            char psz_msg[512];
            if ( vsnprintf(psz_msg, sizeof(psz_msg) - 1, format, va) < 0 )
                return;
253 254
            char psz_ctx[1024];
            sprintf_s(psz_ctx, "[%s] (%s:%d) %s", psz_module, psz_file, i_line, psz_msg);
255
#endif
256
            logCb( level, ctx, std::string{ psz_ctx } );
257
        };
258 259
        libvlc_log_set(*this, CallbackWrapper<(unsigned int)CallbackIdx::Log, libvlc_log_cb>::wrap( *m_callbacks, std::move(wrapper)),
            m_callbacks.get() );
260
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
261 262 263 264 265 266 267 268 269

    /**
     * Sets up logging to a file.
     *
     * \param stream  FILE pointer opened for writing (the FILE pointer must
     * remain valid until Instance::logUnset() )
     *
     * \version LibVLC 2.1.0 or later
     */
270 271
    void logSetFile(FILE * stream)
    {
272
        libvlc_log_set_file( *this, stream );
273
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
274 275 276 277 278 279

    /**
     * Returns a list of audio filters that are available.
     *
     * \see ModuleDescription
     */
280 281
    std::vector<ModuleDescription> audioFilterList()
    {
282 283
        std::unique_ptr<libvlc_module_description_t, decltype(&libvlc_module_description_list_release)>
                ptr( libvlc_audio_filter_list_get(*this), libvlc_module_description_list_release );
284 285 286
        if ( ptr == nullptr )
            return {};
        libvlc_module_description_t* p = ptr.get();
287 288 289
        std::vector<ModuleDescription> res;
        while ( p != NULL )
        {
290
            res.emplace_back( p );
291 292 293 294 295
            p = p->p_next;
        }
        return res;
    }

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
296 297 298 299 300 301

    /**
     * Returns a list of video filters that are available.
     *
     * \see ModuleDescription
     */
302 303
    std::vector<ModuleDescription> videoFilterList()
    {
304 305
        std::unique_ptr<libvlc_module_description_t, decltype(&libvlc_module_description_list_release)>
                ptr( libvlc_video_filter_list_get(*this), &libvlc_module_description_list_release );
306 307 308
        if ( ptr == nullptr )
            return {};
        libvlc_module_description_t* p = ptr.get();
309 310 311
        std::vector<ModuleDescription> res;
        while ( p != NULL )
        {
312
            res.emplace_back( p );
313 314 315 316
            p = p->p_next;
        }
        return res;
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
317 318 319 320

    /**
     * Gets the list of available audio output modules.
     *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
321
     * \see AudioOutputDescription
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
322
     */
323 324
    std::vector<AudioOutputDescription> audioOutputList()
    {
325 326 327 328
        std::unique_ptr<libvlc_audio_output_t, decltype(&libvlc_audio_output_list_release)>
                result( libvlc_audio_output_list_get(*this), libvlc_audio_output_list_release );
        if ( result == nullptr )
            return {};
329
        std::vector<AudioOutputDescription> res;
330 331

        libvlc_audio_output_t* p = result.get();
332 333
        while ( p != NULL )
        {
334
            res.emplace_back( p );
335 336 337 338
            p = p->p_next;
        }
        return res;
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357

    /**
     * Gets a list of audio output devices for a given audio output module,
     *
     * \see Audio::outputDeviceSet() .
     *
     * \note Not all audio outputs support this. In particular, an empty
     * (NULL) list of devices does imply that the specified audio output does
     * not work.
     *
     * \note The list might not be exhaustive.
     *
     * \warning Some audio output devices in the list might not actually work
     * in some circumstances. By default, it is recommended to not specify
     * any explicit audio device.
     *
     * \param psz_aout  audio output name (as returned by
     * Instance::audioOutputList() )
     *
358
     * \return A vector containing all audio output devices for this module
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
359 360 361
     *
     * \version LibVLC 2.1.0 or later.
     */
362 363
    std::vector<AudioOutputDeviceDescription> audioOutputDeviceList(const std::string& aout)
    {
364 365 366 367
        std::unique_ptr<libvlc_audio_output_device_t, decltype(&libvlc_audio_output_device_list_release)>
                devices(  libvlc_audio_output_device_list_get( *this, aout.c_str() ), libvlc_audio_output_device_list_release );
        if ( devices == nullptr )
            return {};
368
        std::vector<AudioOutputDeviceDescription> res;
369 370

        for ( auto p = devices.get(); p != nullptr; p = p->p_next )
371
            res.emplace_back( p );
372 373
        return res;
    }
374

375
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
    /**
     * Called when an error message needs to be displayed.
     *
     * \param title title of the dialog
     * \param text text of the dialog
     */
    using ErrorCb = void(std::string &&title, std::string &&text);
    /**
     *Called when a login dialog needs to be displayed.
     *
     *You can interact with this dialog by using the postLogin method on dialog to post an answer or the dismiss method to cancel this dialog.
     *
     *\note to receive this callack, CancelCb should not be NULL.
     *\param dialog used to interact with the dialog
     *\param title title of the dialog
     *\param text text of the dialog
     *\param defaultUserName user name that should be set on the user form
     *\param askToStore if true, ask the user if he wants to save the credentials
     */
    using LoginCb = void(Dialog &&dialog, std::string &&title, std::string &&text, std::string &&defaultUserName, bool askToStore);
    /**
     * Called when a question dialog needs to be displayed
     *
     * You can interact with this dialog by using the postAction method on dialog
     * to post an answer or dismiss method to cancel this dialog.
     *
     * \note to receive this callack, CancelCb should not be
     * NULL.
     *
     * \param dialog used to interact with the dialog
     * \param title title of the diaog
     * \param text text of the dialog
     * \param qtype question type (or severity) of the dialog
     * \param cancel text of the cancel button
     * \param action1 text of the first button, if NULL, don't display this
     * button
     * \param action2 text of the second button, if NULL, don't display
     * this button
     */
    using QuestionCb = void(Dialog &&dialog, std::string &&title, std::string &&text, Question qType, std::string &&cancel, std::string &&action1, std::string &&action2);
    /**
     * Called when a progress dialog needs to be displayed
     *
     * If cancellable (cancel != NULL), you can cancel this dialog by
     * calling the dismiss method on dialog
     *
     * \note to receive this callack, CancelCb and
     * UpdtProgressCb should not be NULL.
     *
     * \param dialog used to interact with the dialog
     * \param title title of the diaog
     * \param text text of the dialog
     * \param indeterminate true if the progress dialog is indeterminate
     * \param position initial position of the progress bar (between 0.0 and
     * 1.0)
     * \param cancel text of the cancel button, if NULL the dialog is not
     * cancellable
     */
    using DspProgressCb = void(Dialog &&dialog, std::string &&title, std::string &&text, bool intermediate, float position, std::string &&cancel);
    /**
     * Called when a displayed dialog needs to be cancelled
     *
     * The implementation must call the method dismiss on dialog to really release
     * the dialog.
     *
     * \param dialog used to interact with the dialog
     */
    using CancelCb = void(Dialog &&dialog);
    /**
     * Called when a progress dialog needs to be updated
     *
     * \param dialog used to interact with the dialog
     * \param position osition of the progress bar (between 0.0 and 1.0)
     * \param text new text of the progress dialog
     */
    using UpdtProgressCb = void(Dialog &&dialog, float position, std::string &&text);

    /**
     * Replaces all the dialog callbacks for this Instance instance
     *
     * \param error   lambda callback that will get called when an error message needs to be displayed.     \see ErrorCb
     * \param login   lambda callback that will get called when a login dialog needs to be displayed. \see LoginCb
     * \param question   lambda callback that will get called when a question dialog needs to be displayed. \see QuestionCb
     * \param dspProgress   lambda callback that will get called when a progress dialog needs to be displayed. \see DspProgressCb
     * \param cancel   lambda callback that will get called when a displayed dialog needs to be cancelled. \see CancelCb
     * \param updtProgress   lambda callback that will get called when a progress dialog needs to be updated. \see UpdtProgressCb
     */
    template <class Error, class Login, class Question, class DspProgress, class Cancel, class UpdtProgress>
    void setDialogHandlers(Error&& error, Login&& login, Question&& question, DspProgress&& dspProgress, Cancel &&cancel, UpdtProgress &&updtProgress)
    {
        static_assert(signature_match_or_nullptr<Error, ErrorCb>::value, "Mismatched error display callback prototype");
        static_assert(signature_match_or_nullptr<Login, LoginCb>::value, "Mismatched login display callback prototype");
        static_assert(signature_match_or_nullptr<Question, QuestionCb>::value, "Mismatched question display callback prototype");
        static_assert(signature_match_or_nullptr<DspProgress, DspProgressCb>::value, "Mismatched progress display callback prototype");
        static_assert(signature_match_or_nullptr<Cancel, CancelCb>::value, "Mismatched cancel callback prototype");
        static_assert(signature_match_or_nullptr<UpdtProgress, UpdtProgressCb>::value, "Mismatched update progress callback prototype");

473 474 475 476 477 478 479 480 481
        libvlc_dialog_cbs tmp = {
            CallbackWrapper<(unsigned)CallbackIdx::ErrorDisplay, decltype(libvlc_dialog_cbs::pf_display_error)>::wrap(*m_callbacks, std::forward<Error>(error)),
            CallbackWrapper<(unsigned)CallbackIdx::LoginDisplay, decltype(libvlc_dialog_cbs::pf_display_login)>::wrap(*m_callbacks, std::forward<Login>(login)),
            CallbackWrapper<(unsigned)CallbackIdx::QuestionDisplay, decltype(libvlc_dialog_cbs::pf_display_question)>::wrap(*m_callbacks, std::forward<Question>(question)),
            CallbackWrapper<(unsigned)CallbackIdx::ProgressDisplay, decltype(libvlc_dialog_cbs::pf_display_progress)>::wrap(*m_callbacks, std::forward<DspProgress>(dspProgress)),
            CallbackWrapper<(unsigned)CallbackIdx::CancelDialog, decltype(libvlc_dialog_cbs::pf_cancel)>::wrap(*m_callbacks, std::forward<Cancel>(cancel)),
            CallbackWrapper<(unsigned)CallbackIdx::ProgressUpdate, decltype(libvlc_dialog_cbs::pf_update_progress)>::wrap(*m_callbacks, std::forward<UpdtProgress>(updtProgress))
        };
        m_callbacks_pointers = std::make_shared<libvlc_dialog_cbs>(tmp);
482 483 484 485 486 487 488 489 490 491 492 493
        libvlc_dialog_set_callbacks(*this, m_callbacks_pointers.get(), m_callbacks.get());
    }

    /**
     * Unset all callbacks
     */
    void unsetDialogHandlers()
    {
        memset(m_callbacks_pointers.get(), 0, sizeof(libvlc_dialog_cbs));
        std::fill(m_callbacks->begin() + 2, m_callbacks->end(), nullptr);
        libvlc_dialog_set_callbacks(*this, nullptr, nullptr);
    }
494

495
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
    /**
     * Get media discoverer services by category
     *
     * \version LibVLC 3.0.0 and later.
     *
     * \param category  The category of services to fetch
     *
     * \return A vector containing the available media discoverers
     */
    std::vector<MediaDiscoverer::Description> mediaDiscoverers(MediaDiscoverer::Category category)
    {
        libvlc_media_discoverer_description** pp_descs;
        auto nbSd = libvlc_media_discoverer_list_get( *this, static_cast<libvlc_media_discoverer_category>( category ),
                                                      &pp_descs );
        if ( nbSd == 0 )
            return {};
        auto releaser = [nbSd](libvlc_media_discoverer_description** ptr) {
            libvlc_media_discoverer_list_release( ptr, nbSd );
        };
        std::unique_ptr<libvlc_media_discoverer_description*, decltype(releaser)> descPtr( pp_descs, releaser );
        std::vector<MediaDiscoverer::Description> res;
        res.reserve( nbSd );
        for ( auto i = 0u; i < nbSd; ++i )
            res.emplace_back( pp_descs[i]->psz_name, pp_descs[i]->psz_longname, pp_descs[i]->i_cat );
        return res;
    }
522
#endif
523

524
#endif
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
525 526 527 528 529 530
};

} // namespace VLC

#endif