Skip to content
Commits on Source (2)
......@@ -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);
};
[
......
......@@ -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};
......
......@@ -250,6 +250,7 @@ public:
void fireOnMediaPlayerEncounteredErrorEvent();
void fireOnMediaPlayerEndReachedEvent();
void fireOnMediaPlayerStoppedEvent();
void fireOnMediaPlayerStopAsyncDoneEvent();
void fireOnMediaPlayerTimeChangedEvent(libvlc_time_t time);
void fireOnMediaPlayerPositionChangedEvent(float position);
......
......@@ -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;
......
......@@ -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>
......
......@@ -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() )
......
......@@ -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();
......