[vlc-commits] [Git][videolan/npapi-vlc][master] 2 commits: activex: allow to parse item and retreive information before playing

Jean-Baptiste Kempf gitlab at videolan.org
Tue Nov 21 16:25:28 CET 2017


Jean-Baptiste Kempf pushed to branch master at videolan / VLC Browser Plugins


Commits:
5cd1ab48 by Pierre Lamot at 2017-11-21T16:25:04+01:00
activex: allow to parse item and retreive information before playing

  VLC ActiveX API doesn't follow libvlc API and doesn't expose Media to the user
  so preparse is made by allowing to preparse a specific item from the playlist.

  Informations about the media can be retreive using the same API (video.width, ...),
  throught a fallback when the MediaPlayer isn't playing.

  parse will only allow parsing the first item of the playlist, as other item, and information
  about them, are only accessible by playing them.

Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>

- - - - -
7177e3cb by Pierre Lamot at 2017-11-21T16:25:04+01:00
activex: add method to allow stopping the player asynchonously

Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>

- - - - -


7 changed files:

- activex/axvlc.idl
- activex/plugin.cpp
- activex/plugin.h
- activex/vlccontrol2.cpp
- activex/vlccontrol2.h
- common/vlc_player.cpp
- common/vlc_player.h


Changes:

=====================================
activex/axvlc.idl
=====================================
--- a/activex/axvlc.idl
+++ b/activex/axvlc.idl
@@ -90,6 +90,7 @@ library AXVLC
     const int DISPID_MediaPlayerMutedEvent = 219;
     const int DISPID_MediaPlayerUnmutedEvent = 220;
     const int DISPID_MediaPlayerAudioVolumeEvent = 221;
+    const int DISPID_MediaPlayerStopAsyncDoneEvent = 222;
 
     [
       uuid(DF48072F-5EF8-434e-9B40-E2F3AE759B5F),
@@ -120,6 +121,8 @@ library AXVLC
             void MediaPlayerEndReached();
             [id(DISPID_MediaPlayerStoppedEvent), helpstring("Playback stopped")]
             void MediaPlayerStopped();
+            [id(DISPID_MediaPlayerStopAsyncDoneEvent), helpstring("Playback stop async done")]
+            void MediaPlayerStopAsyncDone();
 
             [id(DISPID_MediaPlayerTimeChangedEvent), helpstring("Time changed")]
             void MediaPlayerTimeChanged([in] long time);
@@ -335,6 +338,9 @@ library AXVLC
         [helpstring("Stop current clip.")]
         HRESULT stop();
 
+        [helpstring("Stop current clip asynchronously.")]
+        HRESULT stop_async();
+
         [helpstring("Advance to next item in playlist.")]
         HRESULT next();
 
@@ -349,6 +355,9 @@ library AXVLC
 
         [propget, helpstring("Returns the playlist items collection object.")]
         HRESULT items([out, retval] IVLCPlaylistItems** obj);
+
+        [helpstring("Parse the head media from playlist")]
+        HRESULT parse([in] long options, [in] long timeout_ms, [out, retval] long* status);
     };
 
     [


=====================================
activex/plugin.cpp
=====================================
--- a/activex/plugin.cpp
+++ b/activex/plugin.cpp
@@ -1024,6 +1024,13 @@ void VLCPlugin::fireOnMediaPlayerStoppedEvent()
     vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerStoppedEvent, &dispparamsNoArgs);
 };
 
+void VLCPlugin::fireOnMediaPlayerStopAsyncDoneEvent()
+{
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    vlcConnectionPointContainer->fireEvent(DISPID_MediaPlayerStopAsyncDoneEvent, &dispparamsNoArgs);
+};
+
+
 void VLCPlugin::fireOnMediaPlayerForwardEvent()
 {
     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};


=====================================
activex/plugin.h
=====================================
--- a/activex/plugin.h
+++ b/activex/plugin.h
@@ -250,6 +250,7 @@ public:
     void fireOnMediaPlayerEncounteredErrorEvent();
     void fireOnMediaPlayerEndReachedEvent();
     void fireOnMediaPlayerStoppedEvent();
+    void fireOnMediaPlayerStopAsyncDoneEvent();
 
     void fireOnMediaPlayerTimeChangedEvent(libvlc_time_t time);
     void fireOnMediaPlayerPositionChangedEvent(float position);


=====================================
activex/vlccontrol2.cpp
=====================================
--- a/activex/vlccontrol2.cpp
+++ b/activex/vlccontrol2.cpp
@@ -466,7 +466,32 @@ STDMETHODIMP VLCAudio::get_count(long* trackNumber)
     if( NULL == trackNumber )
         return E_POINTER;
 
-    *trackNumber = negativeToZero( _plug->get_player().get_mp().audioTrackCount() );
+    libvlc_state_t state = _plug->get_player().get_mp().state();
+    switch (state)
+    {
+    case libvlc_Buffering:
+    case libvlc_Playing:
+    case libvlc_Paused:
+    {
+        *trackNumber = negativeToZero( _plug->get_player().get_mp().audioTrackCount() );
+        break;
+    }
+    default:
+    {
+        auto media = _plug->get_player().get_media(0);
+        if ( !media )
+        {
+            *trackNumber = 0;
+            return S_OK;
+        }
+        int count = 0;
+        for (auto track:  media->tracks())
+            if (track.type() == VLC::MediaTrack::Type::Audio)
+                count++;
+        *trackNumber = count;
+        break;
+    }
+    }
 
     return S_OK;
 }
@@ -476,11 +501,37 @@ STDMETHODIMP VLCAudio::description(long trackId, BSTR* name)
     if( NULL == name )
         return E_POINTER;
 
-    auto tracks = _plug->get_player().get_mp().audioTrackDescription();
-    if ( trackId >= tracks.size() )
+    libvlc_state_t state = _plug->get_player().get_mp().state();
+    switch (state)
+    {
+    case libvlc_Buffering:
+    case libvlc_Playing:
+    case libvlc_Paused:
+    {
+        auto tracks = _plug->get_player().get_mp().audioTrackDescription();
+        if ( trackId >= tracks.size() )
+            return E_INVALIDARG;
+        *name = BSTRFromCStr( CP_UTF8, tracks[trackId].name().c_str() );
+        return (NULL == *name) ? E_OUTOFMEMORY : S_OK;
+    }
+    default:
+    {
+        auto media = _plug->get_player().get_media(0);
+        if ( !media )
+            return E_INVALIDARG;
+        for (auto track:  media->tracks())
+            if (track.type() == VLC::MediaTrack::Type::Audio)
+            {
+                if (trackId == 0)
+                {
+                    *name = BSTRFromCStr( CP_UTF8, track.description().c_str() );
+                    return (NULL == *name) ? E_OUTOFMEMORY : S_OK;
+                }
+                trackId--;
+            }
         return E_INVALIDARG;
-    *name = BSTRFromCStr( CP_UTF8, tracks[trackId].name().c_str() );
-    return (NULL == *name) ? E_OUTOFMEMORY : S_OK;
+    }
+    }
 }
 
 STDMETHODIMP VLCAudio::get_channel(long *channel)
@@ -633,7 +684,30 @@ STDMETHODIMP VLCInput::get_length(double* length)
     if( NULL == length )
         return E_POINTER;
 
-    *length = static_cast<double>(_plug->get_player().get_mp().length() );
+
+
+    libvlc_state_t state = _plug->get_player().get_mp().state();
+    switch (state)
+    {
+    case libvlc_Buffering:
+    case libvlc_Playing:
+    case libvlc_Paused:
+    {
+        *length = static_cast<double>(_plug->get_player().get_mp().length() );
+        break;
+    }
+    default:
+    {
+        auto media = _plug->get_player().get_media(0);
+        if ( !media )
+        {
+            *length = 0.0;
+            return S_OK;
+        }
+        *length = static_cast<double>(media->duration());
+        break;
+    }
+    }
 
     return S_OK;
 }
@@ -706,7 +780,11 @@ STDMETHODIMP VLCInput::get_fps(double* fps)
 
     auto media = _plug->get_player().get_mp().media();
     if ( media == nullptr )
-        return E_FAIL;
+    {
+        media = _plug->get_player().get_media(0);
+        if ( media == nullptr )
+            return E_FAIL;
+    }
     auto tracks = media->tracks();
     for ( const auto& t : tracks )
     {
@@ -832,6 +910,30 @@ STDMETHODIMP VLCPlaylistItems::remove(long item)
 }
 
 /****************************************************************************/
+enum PlaylistAsyncMessages
+{
+    PM_INPUT_STOP = WM_USER +1,
+    PM_DESTROY
+};
+
+VLCPlaylist::VLCPlaylist(VLCPlugin *p):
+    VLCInterface<VLCPlaylist,IVLCPlaylist>(p),
+    _p_vlcplaylistitems(new VLCPlaylistItems(p))
+{
+    _async_thread = CreateThread ( NULL , 0 ,
+        (LPTHREAD_START_ROUTINE)VLCPlaylist::async_handler_cb,
+        (LPVOID)this , 0, &_async_thread_id );
+}
+
+VLCPlaylist::~VLCPlaylist()
+{
+    PostThreadMessage(_async_thread_id, PM_DESTROY, 0, 0);
+    WaitForSingleObject(_async_thread, INFINITE);
+    CloseHandle (_async_thread);
+
+    delete _p_vlcplaylistitems;
+}
+
 
 STDMETHODIMP VLCPlaylist::get_itemCount(long* count)
 {
@@ -963,6 +1065,12 @@ STDMETHODIMP VLCPlaylist::stop()
     return S_OK;
 }
 
+STDMETHODIMP VLCPlaylist::stop_async()
+{
+    PostThreadMessage(_async_thread_id, PM_INPUT_STOP, 0, 0);
+    return S_OK;
+}
+
 STDMETHODIMP VLCPlaylist::next()
 {
     _plug->get_player().mlp().next();
@@ -1001,6 +1109,46 @@ STDMETHODIMP VLCPlaylist::get_items(IVLCPlaylistItems** obj)
     return E_OUTOFMEMORY;
 }
 
+STDMETHODIMP VLCPlaylist::parse(long options, long timeout, long *status)
+{
+    if ( timeout < 0 )
+        return E_INVALIDARG;
+    if ( status == nullptr )
+        return E_POINTER;
+    *status = _plug->get_player().preparse_item_sync( 0, options, timeout );
+    return S_OK;
+}
+
+void VLCPlaylist::async_handler_cb(LPVOID obj)
+{
+    VLCPlaylist* that = (VLCPlaylist*) obj;
+    that->async_handler();
+}
+
+
+void VLCPlaylist::async_handler()
+{
+    MSG msg;
+    bool b_quit = false;
+    while (!b_quit && GetMessage(&msg, 0, 0, 0))
+    {
+        switch(msg.message)
+        {
+        case PM_INPUT_STOP:
+            this->stop();
+            _plug->fireOnMediaPlayerStopAsyncDoneEvent();
+            break;
+        case PM_DESTROY:
+            b_quit = true;
+            break;
+        default:
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+            break;
+        }
+    }
+}
+
 /****************************************************************************/
 
 STDMETHODIMP VLCSubtitle::get_track(long* spu)
@@ -1027,20 +1175,72 @@ STDMETHODIMP VLCSubtitle::get_count(long* spuNumber)
     if( NULL == spuNumber )
         return E_POINTER;
 
-    *spuNumber = _plug->get_player().get_mp().spuCount();
+    libvlc_state_t state = _plug->get_player().get_mp().state();
+    switch (state)
+    {
+    case libvlc_Buffering:
+    case libvlc_Playing:
+    case libvlc_Paused:
+    {
+        *spuNumber = _plug->get_player().get_mp().spuCount();
+        break;
+    }
+    default:
+    {
+        auto media = _plug->get_player().get_media(0);
+        if ( !media )
+        {
+            *spuNumber = 0;
+            return S_OK;
+        }
+        int count = 0;
+        for (auto track:  media->tracks())
+            if (track.type() == VLC::MediaTrack::Type::Subtitle)
+                count++;
+        *spuNumber = count;
+        break;
+    }
+    }
+
     return S_OK;
 }
 
 STDMETHODIMP VLCSubtitle::description(long nameID, BSTR* name)
 {
     if( NULL == name )
-       return E_POINTER;
+        return E_POINTER;
 
-    auto tracks = _plug->get_player().get_mp().spuDescription();
-    if ( nameID >= tracks.size() )
+    libvlc_state_t state = _plug->get_player().get_mp().state();
+    switch (state)
+    {
+    case libvlc_Buffering:
+    case libvlc_Playing:
+    case libvlc_Paused:
+    {
+        auto tracks = _plug->get_player().get_mp().spuDescription();
+        if ( nameID >= tracks.size() )
+            return E_INVALIDARG;
+        *name = BSTRFromCStr( CP_UTF8, tracks[nameID].name().c_str() );
+        return (NULL == *name) ? E_OUTOFMEMORY : S_OK;
+    }
+    default:
+    {
+        auto media = _plug->get_player().get_media(0);
+        if ( !media )
+            return E_INVALIDARG;
+        for (auto track:  media->tracks())
+            if (track.type() == VLC::MediaTrack::Type::Subtitle)
+            {
+                if (nameID == 0)
+                {
+                    *name = BSTRFromCStr( CP_UTF8, track.description().c_str() );
+                    return (NULL == *name) ? E_OUTOFMEMORY : S_OK;
+                }
+                nameID--;
+            }
         return E_INVALIDARG;
-    *name = BSTRFromCStr( CP_UTF8, tracks[nameID].name().c_str() );
-    return (NULL == *name) ? E_OUTOFMEMORY : S_OK;
+    }
+    }
 }
 
 /****************************************************************************/
@@ -1066,8 +1266,36 @@ STDMETHODIMP VLCVideo::get_width(long* width)
     if( NULL == width )
         return E_POINTER;
 
-    unsigned int height;
-    _plug->get_player().get_mp().size( 0, (unsigned int*)width, &height );
+    libvlc_state_t state = _plug->get_player().get_mp().state();
+    switch (state)
+    {
+    case libvlc_Buffering:
+    case libvlc_Playing:
+    case libvlc_Paused:
+    {
+        unsigned int height;
+        _plug->get_player().get_mp().size( 0, (unsigned int*)width, &height );
+        break;
+    }
+    default:
+    {
+        auto media = _plug->get_player().get_media(0);
+        if ( !media )
+        {
+            *width = 0;
+            return S_OK;
+        }
+        for ( auto track : media->tracks() )
+        {
+            if (track.type() == VLC::MediaTrack::Type::Video)
+            {
+                *width = track.width();
+                break;
+            }
+        }
+        break;
+    }
+    }
     return S_OK;
 }
 
@@ -1076,8 +1304,37 @@ STDMETHODIMP VLCVideo::get_height(long* height)
     if( NULL == height )
         return E_POINTER;
 
-    unsigned int width;
-    _plug->get_player().get_mp().size( 0, &width, (unsigned int*)height );
+
+    libvlc_state_t state = _plug->get_player().get_mp().state();
+    switch (state)
+    {
+    case libvlc_Buffering:
+    case libvlc_Playing:
+    case libvlc_Paused:
+    {
+        unsigned int width;
+        _plug->get_player().get_mp().size( 0, &width, (unsigned int*)height );
+        break;
+    }
+    default:
+    {
+        auto media = _plug->get_player().get_media(0);
+        if ( !media )
+        {
+            *height = 0;
+            return S_OK;
+        }
+        for ( auto track : media->tracks() )
+        {
+            if (track.type() == VLC::MediaTrack::Type::Video)
+            {
+                *height = track.height();
+                break;
+            }
+        }
+        break;
+    }
+    }
     return S_OK;
 }
 
@@ -1321,7 +1578,32 @@ STDMETHODIMP VLCVideo::get_count(long* trackNumber)
     if( NULL == trackNumber )
         return E_POINTER;
 
-    *trackNumber = negativeToZero( _plug->get_player().get_mp().videoTrackCount() );
+    libvlc_state_t state = _plug->get_player().get_mp().state();
+    switch (state)
+    {
+    case libvlc_Buffering:
+    case libvlc_Playing:
+    case libvlc_Paused:
+    {
+        *trackNumber = negativeToZero( _plug->get_player().get_mp().videoTrackCount() );
+        break;
+    }
+    default:
+    {
+        auto media = _plug->get_player().get_media(0);
+        if ( !media )
+        {
+            *trackNumber = 0;
+            return S_OK;
+        }
+        int count = 0;
+        for (auto track:  media->tracks())
+            if (track.type() == VLC::MediaTrack::Type::Video)
+                count++;
+        *trackNumber = count;
+        break;
+    }
+    }
 
     return S_OK;
 }
@@ -1331,11 +1613,37 @@ STDMETHODIMP VLCVideo::description(long trackId, BSTR* name)
     if( NULL == name )
         return E_POINTER;
 
-    auto tracks = _plug->get_player().get_mp().videoTrackDescription();
-    if ( trackId >= tracks.size() )
+    libvlc_state_t state = _plug->get_player().get_mp().state();
+    switch (state)
+    {
+    case libvlc_Buffering:
+    case libvlc_Playing:
+    case libvlc_Paused:
+    {
+        auto tracks = _plug->get_player().get_mp().videoTrackDescription();
+        if ( trackId >= tracks.size() )
+            return E_INVALIDARG;
+        *name = BSTRFromCStr( CP_UTF8, tracks[trackId].name().c_str() );
+        return (NULL == *name) ? E_OUTOFMEMORY : S_OK;
+    }
+    default:
+    {
+        auto media = _plug->get_player().get_media(0);
+        if ( !media )
+            return E_INVALIDARG;
+        for (auto track:  media->tracks())
+            if (track.type() == VLC::MediaTrack::Type::Video)
+            {
+                if (trackId == 0)
+                {
+                    *name = BSTRFromCStr( CP_UTF8, track.description().c_str() );
+                    return (NULL == *name) ? E_OUTOFMEMORY : S_OK;
+                }
+                trackId--;
+            }
         return E_INVALIDARG;
-    *name = BSTRFromCStr( CP_UTF8, tracks[trackId].name().c_str() );
-    return (NULL == *name) ? E_OUTOFMEMORY : S_OK;
+    }
+    }
 }
 
 STDMETHODIMP VLCVideo::get_marquee(IVLCMarquee** obj)
@@ -1421,7 +1729,11 @@ STDMETHODIMP VLCMediaDescription::get_meta(BSTR* val, libvlc_meta_t e_meta)
 
     auto media = _plug->get_player().get_mp().media();
     if ( media == nullptr )
-        return E_FAIL;
+    {
+        media = _plug->get_player().get_media(0);
+        if ( media == nullptr )
+            return E_FAIL;
+    }
     auto info = media->meta( e_meta );
     *val = BSTRFromCStr( CP_UTF8, info.c_str() );
     return *val ? S_OK : E_FAIL;


=====================================
activex/vlccontrol2.h
=====================================
--- a/activex/vlccontrol2.h
+++ b/activex/vlccontrol2.h
@@ -289,10 +289,8 @@ public:
 class VLCPlaylist: public VLCInterface<VLCPlaylist,IVLCPlaylist>
 {
 public:
-    VLCPlaylist(VLCPlugin *p):
-        VLCInterface<VLCPlaylist,IVLCPlaylist>(p),
-        _p_vlcplaylistitems(new VLCPlaylistItems(p)) { }
-    virtual ~VLCPlaylist() { delete _p_vlcplaylistitems; }
+    VLCPlaylist(VLCPlugin *p);
+    virtual ~VLCPlaylist();
 
     // IVLCPlaylist methods
     STDMETHODIMP get_itemCount(long*);
@@ -304,14 +302,22 @@ public:
     STDMETHODIMP pause();
     STDMETHODIMP togglePause();
     STDMETHODIMP stop();
+    STDMETHODIMP stop_async();
     STDMETHODIMP next();
     STDMETHODIMP prev();
     STDMETHODIMP clear();
     STDMETHODIMP removeItem(long);
     STDMETHODIMP get_items(IVLCPlaylistItems**);
+    STDMETHODIMP parse(long options, long timeout, long* status);
+
+private:
+    static void async_handler_cb(LPVOID obj);
+    void async_handler();
 
 private:
     VLCPlaylistItems*    _p_vlcplaylistitems;
+    HANDLE               _async_thread;
+    DWORD                _async_thread_id;
 };
 
 class VLCSubtitle: public VLCInterface<VLCSubtitle,IVLCSubtitle>


=====================================
common/vlc_player.cpp
=====================================
--- a/common/vlc_player.cpp
+++ b/common/vlc_player.cpp
@@ -23,6 +23,12 @@
 #include "config.h"
 #endif
 
+#if defined(_WIN32)
+#  include <windows.h>
+#else
+#  include <future>
+#endif
+
 #include "vlc_player.h"
 
 bool vlc_player::open(VLC::Instance& inst)
@@ -95,6 +101,73 @@ void vlc_player::clear_items()
     }
 }
 
+int vlc_player::preparse_item_sync(unsigned int idx, int options, unsigned int timeout)
+{
+    int retval = -1;
+
+    VLC::MediaList::Lock lock( _ml );
+    auto media = _ml.itemAtIndex( idx );
+    if ( !media )
+        return -1;
+    auto em = media->eventManager();
+
+#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
+#  if defined(_WIN32)
+    HANDLE barrier = CreateEvent(nullptr, true,  false, nullptr);
+    if ( barrier == nullptr )
+        return -1;
+
+    auto event = em.onParsedChanged(
+        [&barrier, &retval](VLC::Media::ParsedStatus status )
+    {
+        retval = int( status );
+        SetEvent( barrier );
+    });
+
+    media->parseWithOptions( VLC::Media::ParseFlags( options ), timeout );
+
+    DWORD waitResult = WaitForSingleObject( barrier, INFINITE );
+    switch ( waitResult ) {
+    case WAIT_OBJECT_0:
+        break;
+    default:
+        retval = -1;
+        break;
+    }
+    CloseHandle( barrier );
+    event->unregister();
+#  else
+    std::promise<int> promise;
+    std::future<int> future = promise.get_future();
+
+    auto event = em.onParsedChanged(
+        [&promise]( VLC::Media::ParsedStatus status )
+    {
+        promise.set_value( int( status ) );
+    });
+
+    media->parseWithOptions( VLC::Media::ParseFlags( options ), timeout );
+
+    future.wait();
+    retval = future.get();
+    event->unregister();
+#  endif
+#else
+    media->parse();
+    if ( media->isParsed() )
+        retval = int( VLC::Media::ParsedStatus::Done );
+    else
+        retval = int( VLC::Media::ParsedStatus::Failed );
+#endif
+
+    return retval;
+}
+
+std::shared_ptr<VLC::Media> vlc_player::get_media(unsigned int idx)
+{
+    return _ml.itemAtIndex(idx);
+}
+
 void vlc_player::play()
 {
     if( 0 == items_count() )


=====================================
common/vlc_player.h
=====================================
--- a/common/vlc_player.h
+++ b/common/vlc_player.h
@@ -48,6 +48,8 @@ public:
 
     void play();
 
+    int preparse_item_sync(unsigned int idx, int options, unsigned int timeout);
+
     VLC::MediaPlayer& get_mp()
     {
         return _mp;
@@ -58,6 +60,8 @@ public:
         return _ml_p;
     }
 
+    std::shared_ptr<VLC::Media> get_media( unsigned int idx );
+
     int currentAudioTrack();
     int currentSubtitleTrack();
     int currentVideoTrack();



View it on GitLab: https://code.videolan.org/videolan/npapi-vlc/compare/aa98041e46e34ba4698bdf50a3fbf240246729b4...7177e3cb9c581223b21193571b247c7d8478a7ae

---
View it on GitLab: https://code.videolan.org/videolan/npapi-vlc/compare/aa98041e46e34ba4698bdf50a3fbf240246729b4...7177e3cb9c581223b21193571b247c7d8478a7ae
You're receiving this email because of your account on code.videolan.org.


More information about the vlc-commits mailing list