[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