[vlc-devel] [RFC 2/2] activex: allow to parse item and retreive information before playing

Pierre Lamot pierre at videolabs.io
Thu Oct 5 19:24:19 CEST 2017


  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.
---
 activex/axvlc.idl       |   3 +
 activex/vlccontrol2.cpp | 298 ++++++++++++++++++++++++++++++++++++++++++++----
 activex/vlccontrol2.h   |   1 +
 common/vlc_player.cpp   |  73 ++++++++++++
 common/vlc_player.h     |   4 +
 5 files changed, 356 insertions(+), 23 deletions(-)

diff --git a/activex/axvlc.idl b/activex/axvlc.idl
index 5eb3822..0109fa3 100644
--- a/activex/axvlc.idl
+++ b/activex/axvlc.idl
@@ -349,6 +349,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);
     };
 
     [
diff --git a/activex/vlccontrol2.cpp b/activex/vlccontrol2.cpp
index ec20618..4e88e15 100644
--- 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 )
     {
@@ -1001,6 +1079,16 @@ 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;
+}
+
 /****************************************************************************/
 
 STDMETHODIMP VLCSubtitle::get_track(long* spu)
@@ -1027,20 +1115,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 +1206,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 +1244,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 +1518,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 +1553,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 +1669,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;
diff --git a/activex/vlccontrol2.h b/activex/vlccontrol2.h
index db6c52e..b9baf4c 100644
--- a/activex/vlccontrol2.h
+++ b/activex/vlccontrol2.h
@@ -309,6 +309,7 @@ public:
     STDMETHODIMP clear();
     STDMETHODIMP removeItem(long);
     STDMETHODIMP get_items(IVLCPlaylistItems**);
+    STDMETHODIMP parse(long options, long timeout, long* status);
 
 private:
     VLCPlaylistItems*    _p_vlcplaylistitems;
diff --git a/common/vlc_player.cpp b/common/vlc_player.cpp
index 3b64f3f..46e393a 100644
--- 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() )
diff --git a/common/vlc_player.h b/common/vlc_player.h
index 9d48c62..20a297a 100644
--- 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();
-- 
2.14.2



More information about the vlc-devel mailing list