|
|
|
date: Tue, 15 Jul 2008 05:10:05 -0700,
group: microsoft.public.windowsmedia.sdk
back
Re: Obtaining media duration using WMP SDK without windowing code
OK. I did not mean literally. Here is some of the code that I snipped out
and more: (error checking excluded)
hr = CoCreateInstance(__uuidof(WindowsMediaPlayer), NULL,
CLSCTX_INPROC_SERVER, __uuidof(IWMPPlayer), (void **)&player);
printf("hr=0x%x CoCreateInstance(__uuidof(WindowsMediaPlayer)\n", hr);
hr = player->QueryInterface(__uuidof(IConnectionPointContainer), (void
**)&eventProducer);
hr = player->QueryInterface(__uuidof(IWMPSettings), (void **)&settings);
hr = eventProducer->FindConnectionPoint(__uuidof(IWMPEvents),
&eventPoint);
eventListener = new FI_WmpEventDispatch(player);
eventListener->AddRef();
hr = eventPoint->Advise((IWMPEvents *)eventListener,
&eventListenerCookie);
printf("hr=0x%x adviseCookie=%x\n", hr, eventListenerCookie);
hr = player->get_uiMode(&uiMode);
printf("hr=0x%x uiMode=%S\n", hr, uiMode);
hr = settings->get_autoStart(&autoStart);
printf("hr=0x%x autoStart=%hd\n", hr, autoStart);
hr = player->put_uiMode(L"invisible");
printf("hr=0x%x put_uiMode\n", hr);
hr = player->put_URL((BSTR)url);
printf("hr=0x%x put_URL=%S\n", hr, url);
hr = player->get_status(&status);
printf("hr=0x%x status=%S\n", hr, status);
hr = player->get_uiMode(&uiMode);
printf("hr=0x%x uiMode=%S\n", hr, uiMode);
hr = player->get_error(&error);
printf("hr=0x%x get_error\n", hr);
hr = player->get_currentMedia(&media);
printf("hr=0x%x currentMedia=0x%x\n", hr, error);
printf("sleeping 15s.....\n");
OS_Sleep(15000);
hr = media->get_duration(&duration);
printf("hr=0x%x duration=%lf\n", hr, duration);
hr = error->get_errorCount(&numErrors);
printf("hr=0x%x numErrors=%ld\n", hr, numErrors);
if (player)
{
player->close();
player->Release();
}
if (eventPoint)
{
eventPoint->Unadvise(eventListenerCookie);
eventPoint->Release();
}
Auto start is not set explicitly since it is true by default
"fAutoStart
[in] VARIANT_BOOL indicating whether the current media item begins playing
automatically. The default is TRUE."
The output is as follows:
hr=0x0 CoCreateInstance(__uuidof(WindowsMediaPlayer)
event dispatch addref 0
event dispatch query IWMPEvents 0
event dispatch addref 1
hr=0x0 adviseCookie=1
hr=0x0 uiMode=full
hr=0x0 autoStart=-1
hr=0x0 put_uiMode
event dispatch open state change playlistChanging
event dispatch status change
event dispatch play state change transitioning
event dispatch status change
event dispatch open state change playlistChanged
current playlist name=Playlist1 count=1
event dispatch open state change playlistOpenNoMedia
event dispatch status change
event dispatch open state change openingUnknownUrl
event dispatch status change Connecting...
event dispatch play state change transitioning
event dispatch status change Connecting...
event dispatch open state change mediaOpening
current media name=x url=D:\Movies\x.mp3
event dispatch status change Opening media...
hr=0x0 put_URL=D:\Movies\x.mp3
hr=0x0 status=Opening media...
hr=0x0 uiMode=invisible
hr=0x0 get_error
hr=0x0 currentMedia=0x82a58c
sleeping 15s.....
hr=0x0 duration=0.000000
hr=0x0 numErrors=0
event dispatch open state change playlistOpenNoMedia
event dispatch status change Ready
event dispatch play state change ready
event dispatch status change Ready
event dispatch release 0
event dispatch release 1
duration 0.000000
As you can see the status remains "Opening media..." during the entire sleep
time. What exactly is causing this? No errors either.
Kurien
date: Tue, 15 Jul 2008 17:42:41 -0700
author: Kurien Mathew
Re: Obtaining media duration using WMP SDK without windowing code
I modified the code to include an event waiting. But that does not resolve
the issue. The player remains stuck in "Opening media..."
void waitForEvents(MyWmpEventDispatch *eventListener, int numWaits)
{
int k = 0;
while (k < numWaits)
{
HANDLE h = eventListener->GetOpenedEvent();
DWORD cnt = 1;
DWORD dw = MsgWaitForMultipleObjects(cnt, &h, true, 500, QS_ALLINPUT);
if ((dw >= WAIT_OBJECT_0) && (dw < (WAIT_OBJECT_0 + cnt)))
break;
printf("event wait %lu\n", dw);
k++;
}
}
HRESULT getDuration(const wchar_t *url, double &duration)
{
HRESULT hr = S_OK;
IWMPPlayer *player = NULL;
IWMPMedia *media = NULL;
IWMPError *error = NULL;
long numErrors = 0;
BSTR status = NULL;
BSTR uiMode = NULL;
IConnectionPointContainer *eventProducer = NULL;
IConnectionPoint *eventPoint = NULL;
DWORD eventListenerCookie = 0;
MyWmpEventDispatch *eventListener = NULL;
VARIANT_BOOL autoStart = FALSE;
IWMPSettings *settings = NULL;
IWMPControls *controls = NULL;
hr = CoCreateInstance(__uuidof(WindowsMediaPlayer), NULL,
CLSCTX_INPROC_SERVER, __uuidof(IWMPPlayer), (void **)&player);
ERRCHECK(hr);
printf("hr=0x%x CoCreateInstance(__uuidof(WindowsMediaPlayer)\n", hr);
hr = player->QueryInterface(__uuidof(IConnectionPointContainer), (void
**)&eventProducer);
ERRCHECK(hr);
hr = player->QueryInterface(__uuidof(IWMPSettings), (void **)&settings);
ERRCHECK(hr);
hr = player->QueryInterface(__uuidof(IWMPControls), (void **)&controls);
ERRCHECK(hr);
hr = player->get_error(&error);
ERRCHECK(hr);
hr = eventProducer->FindConnectionPoint(__uuidof(IWMPEvents),
&eventPoint);
ERRCHECK(hr);
eventListener = new MyWmpEventDispatch(player);
NEWCHECK(eventListener);
eventListener->AddRef();
hr = eventPoint->Advise((IWMPEvents *)eventListener,
&eventListenerCookie);
ERRCHECK(hr);
printf("hr=0x%x adviseCookie=%x\n", hr, eventListenerCookie);
hr = settings->put_autoStart(FALSE);
ERRCHECK(hr);
printf("hr=0x%x put_autoStart\n", hr);
hr = player->get_uiMode(&uiMode);
ERRCHECK(hr);
printf("hr=0x%x uiMode=%S\n", hr, uiMode);
hr = settings->get_autoStart(&autoStart);
ERRCHECK(hr);
printf("hr=0x%x autoStart=%hd\n", hr, autoStart);
hr = player->put_uiMode(L"invisible");
ERRCHECK(hr);
printf("hr=0x%x put_uiMode\n\n", hr);
// hr = settings->put_autoStart(TRUE);
// ERRCHECK(hr);
// printf("hr=0x%x put_autoStart\n", hr);
waitForEvents(eventListener, 10);
hr = player->put_URL((BSTR)url);
ERRCHECK(hr);
printf("hr=0x%x put_URL=%S\n\n", hr, url);
waitForEvents(eventListener, 10);
// hr = controls->pause();
// ERRCHECK(hr);
// printf("hr=0x%x pause\n", hr);
//
// waitForEvents(eventListener, 10);
//
hr = controls->play();
ERRCHECK(hr);
printf("hr=0x%x play\n\n", hr);
waitForEvents(eventListener, 20);
hr = player->get_status(&status);
ERRCHECK(hr);
printf("hr=0x%x status=%S\n", hr, status);
hr = player->get_currentMedia(&media);
ERRCHECK(hr);
printf("hr=0x%x currentMedia=0x%x\n", hr, error);
hr = media->get_duration(&duration);
ERRCHECK(hr);
printf("hr=0x%x duration=%lf\n", hr, duration);
hr = error->get_errorCount(&numErrors);
ERRCHECK(hr);
printf("hr=0x%x numErrors=%ld\n\n", hr, numErrors);
bail:
RELEASE(media);
RELEASE(error);
if (player)
{
player->close();
player->Release();
}
if (eventPoint)
{
eventPoint->Unadvise(eventListenerCookie);
eventPoint->Release();
}
RELEASE(eventProducer);
RELEASE(eventListener);
RELEASE(settings);
RELEASE(controls);
return hr;
}
The output is as follows:
hr=0x0 CoCreateInstance(__uuidof(WindowsMediaPlayer)
event disp addref 0
event disp query IWMPEvents 0
event disp addref 1
hr=0x0 adviseCookie=1
hr=0x0 put_autoStart
hr=0x0 uiMode=full
hr=0x0 autoStart=0
hr=0x0 put_uiMode
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event disp PlaylistChange
event disp OpenStateChange playlistChanging
event disp StatusChange
event disp PlayStateChange transitioning
event disp StatusChange
event disp CurrentItemChange
event disp OpenStateChange playlistChanged
event disp PlaylistChange
event disp CurrentPlaylistChange
event disp PlaylistChange
event disp CurrentPlaylistChange
current playlist name=Playlist1 count=1
event disp OpenStateChange playlistOpenNoMedia
event disp StatusChange
event disp CurrentItemChange
event disp PlayStateChange ready
event disp StatusChange Ready
hr=0x0 put_URL=D:\Movies\Ali.mp3
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event disp OpenStateChange openingUnknownUrl
event disp StatusChange Connecting...
event disp PlayStateChange transitioning
event disp StatusChange Connecting...
event disp OpenStateChange mediaOpening
current media name=Ali url=D:\Movies\Ali.mp3
event disp StatusChange Opening media...
event disp CurrentItemChange
hr=0x0 play
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
hr=0x0 status=Opening media...
hr=0x0 currentMedia=0x82a71c
hr=0x0 duration=0.000000
hr=0x0 numErrors=0
event disp OpenStateChange playlistOpenNoMedia
event disp StatusChange Ready
event disp PlayStateChange ready
event disp StatusChange Ready
event disp release 0
event disp release 1
Kurien
date: Wed, 16 Jul 2008 07:54:00 -0700
author: Kurien Mathew
Re: Obtaining media duration using WMP SDK without windowing code
The addition of the message dispatch loop did it. Thanks for the valuable
input that is missing from the docs.
The code was modified as below:
void waitForEvents(MyWmpEventDispatch *eventListener, int numWaits)
{
int k = 0;
while (k < numWaits)
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
HANDLE h = eventListener->GetOpenedEvent();
DWORD cnt = 1;
DWORD dw = MsgWaitForMultipleObjects(cnt, &h, true, 500,
QS_ALLEVENTS);
if ((dw >= WAIT_OBJECT_0) && (dw < (WAIT_OBJECT_0 + cnt)))
break;
printf("event wait %lu\n", dw);
k++;
}
}
The output is as below:
hr=0x0 CoCreateInstance(__uuidof(WindowsMediaPlayer)
event disp addref 0
event disp query IWMPEvents 0
event disp addref 1
hr=0x0 adviseCookie=1
hr=0x0 put_autoStart
hr=0x0 uiMode=full
hr=0x0 autoStart=0
hr=0x0 put_uiMode
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event disp PlaylistChange
event disp OpenStateChange playlistChanging
event disp StatusChange
event disp PlayStateChange transitioning
event disp StatusChange
event disp CurrentItemChange
event disp OpenStateChange playlistChanged
event disp PlaylistChange
event disp CurrentPlaylistChange
event disp PlaylistChange
event disp CurrentPlaylistChange
current playlist name=Playlist1 count=1
event disp OpenStateChange playlistOpenNoMedia
event disp StatusChange
event disp CurrentItemChange
event disp PlayStateChange ready
event disp StatusChange Ready
hr=0x0 put_URL=D:\Movies\Ali.mp3
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event wait 258
event disp OpenStateChange openingUnknownUrl
event disp StatusChange Connecting...
event disp PlayStateChange transitioning
event disp StatusChange Connecting...
event disp OpenStateChange mediaOpening
current media name=Ali url=D:\Movies\Ali.mp3
event disp StatusChange Opening media...
event disp CurrentItemChange
hr=0x0 play
event wait 258
event disp AudioLanguageChange
event disp OpenStateChange mediaOpen
event disp StatusChange Playing 'Ali': 271 K bits/second
event disp PlayStateChange playing
event disp StatusChange Playing 'Ali': 271 K bits/second
event disp MediaChange
hr=0x0 status=Playing 'Ali': 271 K bits/second
hr=0x0 currentMedia=0x82a71c
hr=0x0 duration=221.257000
hr=0x0 numErrors=0
event disp OpenStateChange mediaChanging
event disp StatusChange Media changing...
event disp PlayStateChange transitioning
event disp StatusChange Media changing...
event disp OpenStateChange playlistOpenNoMedia
event disp StatusChange
event disp PlayStateChange ready
event disp StatusChange Ready
event disp release 0
event disp release 1
Thanks
Kurien
date: Wed, 16 Jul 2008 10:12:01 -0700
author: Kurien Mathew
Re: Obtaining media duration using WMP SDK without windowing code
Kurien Mathew wrote:
> Are there other ways to obtain media attributes without windowing?
>
You can use the Format SDK for that. Below is some sample code to give
you an idea
C_ComPtr <IWMReader> _reader;
HRESULT hr = _video._WMCreateReader( NULL, 0, &_reader );
//
// Get the IWMReaderAdvanced interface
//
hr = _reader->QueryInterface( IID_IWMReaderAdvanced, (void
**)&_readerAdvanced );
//
// Get the IWMHeaderInfo interface of the reader
//
hr = _reader->QueryInterface( IID_IWMHeaderInfo, (void
**)&_readerHeaderInfo );
//
// Get the profile of the reader
//
hr = _reader->QueryInterface( IID_IWMProfile, (void
**)&_readerProfile );
//
// Open the reader, using "this" as the callback interface.
//
hr = _reader->Open( file.c_str(), callback, NULL );
// get image parameters (output number one)
C_ComPtr <IWMOutputMediaProps> readerOutputProps;
HRESULT hr = _reader->GetOutputProps( _videoOutput,
&readerOutputProps );
DWORD size = 0;
WM_MEDIA_TYPE *mediaType;
hr = readerOutputProps->GetMediaType( 0, &size );
boost::scoped_array<BYTE> tmp( new BYTE [size] );
mediaType = reinterpret_cast<WM_MEDIA_TYPE*>( tmp.get() ); //lint
!e826 // suspicious ptr conversion
hr = readerOutputProps->GetMediaType( mediaType, &size );
WMVIDEOINFOHEADER const * const videoHeader =
reinterpret_cast<WMVIDEOINFOHEADER*>(mediaType->pbFormat); //lint !e826
// suspicious ptr conversion
w = (WORD)videoHeader->bmiHeader.biWidth;
h = (WORD)videoHeader->bmiHeader.biHeight;
WMT_ATTR_DATATYPE enumType;
WORD cbLength = sizeof( duration );
WORD stream = 0;
HRESULT hr = _readerHeaderInfo->GetAttributeByName( &stream,
g_wszWMDuration, &enumType,
(BYTE *)&duration, &cbLength );
date: Wed, 16 Jul 2008 12:59:51 -0700
author: sasha
Re: Obtaining media duration using WMP SDK without windowing code
From: "Kurien Mathew"
> The whole issue started because DirectShow does not
> provide the correct duration for VBR MP3 files.
You could've asked that, there is a simple solution :-)
By default, DirectShow uses the
AsyncFileSource+MPEG1Splitter to parse MP3s (since, after
all, they are just like any other MPA file). However, the
MPEG1Splitter is old and generic and does not handle all the
"innovations" used in MP3s (large tags, tags that emulate
start codes, VBR streams...).
By default, WMP forces DirectShow to use its internal
ASF/MP3 parser instead but you can not use that. However,
the parser simply relies on the WMReader object in the WMF
runtime so you can use the WMASFReader filter, which also
wraps the WMReader, to achieve the same result.
If I were you, I would do the following:
1. co-create an empty graph
2. co-create the WMASFReader filter
3. add the filter to the graph
4. query the filter for IFileSourceFilter
5. call IFileSourceFilter::Load()
6. if it succeeds, enum its output pins
(IBaseFilter::EnumPins()) and render them
(IGraphBuilder::Render())
7. if it fails, remove the filter from the graph and fall
back to IGraphBuilder::RenderFile()
Notice that, if you only need to gather stream info, you can
make that *a lot* faster: e.g. you do not really need to
render the pins but you can query the first pin for
IMediaSeeking or you can use a custom sink filter that has
infinite input pins and that accepts any audio or video
types, so that a full graph can be built very quickly, or
you can use the WMReader (or WMSyncReader or
WMMetadataEditor) directly and fall back to DirectShow only
if that fails.
--
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
date: Thu, 17 Jul 2008 14:08:44 -0400
author: Alessandro Angeli
|
|