//---------------------------------------------------------------------------
#if wxUSE_MEDIACTRL
+#include "wx/dcclient.h"
+#include "wx/thread.h"
+
//---------------------------------------------------------------------------
// Externals (somewhere in src/msw/app.cpp)
//---------------------------------------------------------------------------
// Basically, the way directshow works is that you tell it to render
// a file, and it builds and connects a bunch of filters together.
//
-// There are many, many ways to do this.
+// There are many, many ways to do this.
//
// WAYS TO RENDER A FILE (URLS WORK IN DS ALSO)
//
// 1) Create an instance of IGraphBuilder and call RenderFile on it
// 2) Create an instance of IMediaControl and call RenderFile on it
-// 3) Create an instance of IAMMultiMediaStream, call
+// 3) Create an instance of IAMMultiMediaStream, call
// IAMMultiMediaStream::AddStream and pass an IDirectDraw instance for
-// the video, and pass an IDirectSound(Buffer?) instance or use the
+// the video, and pass an IDirectSound(Buffer?) instance or use the
// default sound renderer, then call RenderFile or RenderMoniker
// 4) Create a Moniker instance for the file and create and build
// all of the filtergraph manually
//
// Our issue here is that we can't use the default representation of 1 and 2
-// because the IVideoWindow instance hogs a lot of the useful window
+// because the IVideoWindow instance hogs a lot of the useful window
// messages such as WM_SETCURSOR.
//
-// Solution #1 was to use #3 by creating a seperate IDirectDraw instance
+// Solution #1 was to use #3 by creating a seperate IDirectDraw instance
// for our window and blitting to that through a thread... unfortunately
// the blitting resizing is very low quality and its quite slow.
//
-// The current way is to use windowless rendering and have directshow
+// The current way is to use windowless rendering and have directshow
// do all the DirectDraw-style clipping to our window
//
// ~~~~~~~~~~~~~~AFTER RENDERING THE FILE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// When done rendering the file, we need to get several interfaces from
// either a IMediaControl or IGraphBuilder instance -
//
-// IMediaPosition - we can set the rate with this... we can also get
+// IMediaPosition - we can set the rate with this... we can also get
// positions and set positions through this with REFTIME (double) instead
// of the normal LONGLONG that IAMMultiMediaStream and IMediaControl use
//
//
// Interfaces that we don't use but might be useful one day -
//
-// IDirectDrawVideo - you can get this through the IFilter returned
+// IDirectDrawVideo - you can get this through the IFilter returned
// from L"Video Renderer" filter from FindFilter on the IGraphBuilder.
// Through this we can set the IDirectDraw instance DrawShow uses.
//
// There are two ways we can do this -
// 1) Have a thread compare the current position to the end position
// about every 10 milliseconds
-// 2) Have IMediaSeekingEx send a message to a windowproc or signal a
+// 2) Have IMediaSeekingEx send a message to a windowproc or signal a
// windows event
//
// Note that we can do these both, I.E. if an IMediaSeekingEx interface
#endif
//---------------------------------------------------------------------------
// IIDS - used by CoCreateInstance and IUnknown::QueryInterface
-// Dumped from amstream.idl, quartz.idl, direct draw and with some
+// Dumped from amstream.idl, quartz.idl, direct draw and with some
// confirmation from WINE
//
// Some of these are not used but are kept here for future reference anyway
struct DDSURFACEDESC
{
- DWORD dwSize;
- DWORD dwFlags;
- DWORD dwHeight;
- DWORD dwWidth;
+ DWORD dwSize;
+ DWORD dwFlags;
+ DWORD dwHeight;
+ DWORD dwWidth;
union
{
- LONG lPitch;
- DWORD dwLinearSize;
+ LONG lPitch;
+ DWORD dwLinearSize;
};
- DWORD dwBackBufferCount;
+ DWORD dwBackBufferCount;
union
{
- DWORD dwMipMapCount;
- DWORD dwZBufferBitDepth;
- DWORD dwRefreshRate;
+ DWORD dwMipMapCount;
+ DWORD dwZBufferBitDepth;
+ DWORD dwRefreshRate;
};
- DWORD dwAlphaBitDepth;
- DWORD dwReserved;
- LPVOID lpSurface;
- DDCOLORKEY ddckCKDestOverlay;
- DDCOLORKEY ddckCKDestBlt;
- DDCOLORKEY ddckCKSrcOverlay;
- DDCOLORKEY ddckCKSrcBlt;
- DDPIXELFORMAT ddpfPixelFormat;
- struct DDSCAPS {DWORD dwCaps;} ddsCaps;
+ DWORD dwAlphaBitDepth;
+ DWORD dwReserved;
+ LPVOID lpSurface;
+ DDCOLORKEY ddckCKDestOverlay;
+ DDCOLORKEY ddckCKDestBlt;
+ DDCOLORKEY ddckCKSrcOverlay;
+ DDCOLORKEY ddckCKSrcBlt;
+ DDPIXELFORMAT ddpfPixelFormat;
+ struct DDSCAPS {DWORD dwCaps;} ddsCaps;
};
struct IDirectDrawClipper : public IUnknown
STDMETHOD(GetClipper)(LPDIRECTDRAWCLIPPER*) PURE;
STDMETHOD(GetColorKey)(DWORD, LPDDCOLORKEY) PURE;
STDMETHOD(GetDC)(HDC *) PURE;
- STDMETHOD(GetFlipStatus)(DWORD) PURE;
+ STDMETHOD(GetFlipStatus)(DWORD) PURE;
STDMETHOD(GetOverlayPosition)(LPLONG, LPLONG ) PURE;
STDMETHOD(GetPalette)(LPDIRECTDRAWPALETTE FAR*) PURE;
STDMETHOD(GetPixelFormat)(LPDDPIXELFORMAT) PURE;
STDMETHOD(SetClipper)(LPDIRECTDRAWCLIPPER) PURE;
STDMETHOD(SetColorKey)(DWORD, LPDDCOLORKEY) PURE;
STDMETHOD(SetOverlayPosition)(LONG, LONG ) PURE;
- STDMETHOD(SetPalette)(IUnknown*) PURE;
+ STDMETHOD(SetPalette)(IUnknown*) PURE;
STDMETHOD(Unlock)(LPVOID) PURE;
STDMETHOD(UpdateOverlay)(LPRECT, LPDIRECTDRAWSURFACE,LPRECT,
DWORD, struct DDOVERLAYFX*) PURE;
STDMETHOD(SetDisplayMode)(DWORD, DWORD,DWORD, DWORD, DWORD) PURE;
STDMETHOD(WaitForVerticalBlank)(DWORD, HANDLE ) PURE;
};
-
+
//---------------------------------------------------------------------------
-// AMMEDIA COM INTERFACES
+// AMMEDIA COM INTERFACES
//---------------------------------------------------------------------------
struct IMediaStream;
struct IMultiMediaStream;
struct IMediaStream : public IUnknown
{
STDMETHOD(GetMultiMediaStream)(IMultiMediaStream **) PURE;
- STDMETHOD(GetInformation)(GUID *, int *) PURE;
+ STDMETHOD(GetInformation)(GUID *, int *) PURE;
STDMETHOD(SetSameFormat)(IMediaStream *, DWORD) PURE;
STDMETHOD(AllocateSample)(DWORD, IStreamSample **) PURE;
- STDMETHOD(CreateSharedSample)(IStreamSample *, DWORD,
+ STDMETHOD(CreateSharedSample)(IStreamSample *, DWORD,
IStreamSample **) PURE;
STDMETHOD(SendEndOfStream)(DWORD dwFlags) PURE;
};
struct IMultiMediaStream : public IUnknown
{
STDMETHOD(GetInformation)(DWORD *, int *) PURE;
- STDMETHOD(GetMediaStream)(REFGUID, IMediaStream **) PURE;
+ STDMETHOD(GetMediaStream)(REFGUID, IMediaStream **) PURE;
STDMETHOD(EnumMediaStreams)(long, IMediaStream **) PURE;
STDMETHOD(GetState)(int *pCurrentState) PURE;
STDMETHOD(SetState)(int NewState) PURE;
STDMETHOD(Initialize)(int, DWORD, IUnknown *) PURE;
STDMETHOD(GetFilterGraph)(IUnknown **) PURE;
STDMETHOD(GetFilter)(IUnknown **) PURE;
- STDMETHOD(AddMediaStream)(IUnknown *, const GUID*, DWORD,
+ STDMETHOD(AddMediaStream)(IUnknown *, const GUID*, DWORD,
IMediaStream **) PURE;
STDMETHOD(OpenFile)(LPCWSTR, DWORD) PURE;
STDMETHOD(OpenMoniker)(IBindCtx *, IMoniker *, DWORD) PURE;
STDMETHOD(GetNativeVideoSize)(LONG *, LONG *, LONG *, LONG *) PURE;
STDMETHOD(GetMinIdealVideoSize)(LONG *, LONG *) PURE;
STDMETHOD(GetMaxIdealVideoSize)(LONG *, LONG *) PURE;
- STDMETHOD(SetVideoPosition)(const LPRECT,const LPRECT) PURE;
+ STDMETHOD(SetVideoPosition)(const LPRECT,const LPRECT) PURE;
STDMETHOD(GetVideoPosition)(LPRECT, LPRECT) PURE;
STDMETHOD(GetAspectRatioMode)(DWORD *) PURE;
STDMETHOD(SetAspectRatioMode)(DWORD) PURE;
STDMETHOD(SetRenderingPrefs)(DWORD) PURE;
STDMETHOD(GetRenderingPrefs)(DWORD *) PURE;
STDMETHOD(SetRenderingMode)(DWORD) PURE;
- STDMETHOD(GetRenderingMode)(DWORD *) PURE;
+ STDMETHOD(GetRenderingMode)(DWORD *) PURE;
};
-
+
typedef IUnknown IBaseFilter;
typedef IUnknown IPin;
typedef IUnknown IEnumFilters;
-typedef int AM_MEDIA_TYPE;
+typedef int AM_MEDIA_TYPE;
struct IFilterGraph : public IUnknown
{
{
public:
void OnPaint(wxPaintEvent&);
- void OnMove(wxMoveEvent&);
- void OnSize(wxSizeEvent&);
void OnEraseBackground(wxEraseEvent&);
};
void Cleanup();
void OnStop();
- bool SetWindowlessMode(IGraphBuilder* pGB,
+ bool SetWindowlessMode(IGraphBuilder* pGB,
IVMRWindowlessControl** ppVMC = NULL);
wxControl* m_ctrl;
IMediaControl* m_pMC;
IMediaEvent* m_pME;
IMediaPosition* m_pMS;
-
+ bool m_bVideo;
+
wxAMMediaThread* m_pThread;
wxSize m_bestSize;
#ifdef __WXDEBUG__
HMODULE m_hQuartzDll;
LPAMGETERRORTEXT m_lpAMGetErrorText;
+ wxString GetErrorString(HRESULT hrdsv);
#endif
friend class wxAMMediaThread;
#define wxDL_METHOD_LOAD( lib, name, success ) \
pfn_ ## name = (name ## Type) lib.GetSymbol( wxT(#name), &success ); \
- if (!success) return false;
+ if (!success) { wxLog::EnableLogging(bWasLoggingEnabled); return false; }
+
//Class that utilizes Robert Roeblings Dynamic Library Macros
class WXDLLIMPEXP_MEDIA wxQuickTimeLibrary
{
m_ok = false;
+ bool bWasLoggingEnabled = wxLog::EnableLogging(false); //Turn off the wxDynamicLibrary logging
+
if(!m_dll.Load(wxT("qtmlClient.dll")))
+ {
+ wxLog::EnableLogging(bWasLoggingEnabled);
return false;
+ }
- bool bOk;
+ bool bOk; //TODO: Get rid of this, use m_ok instead (not a biggie)
wxDL_METHOD_LOAD( m_dll, StartMovie, bOk );
wxDL_METHOD_LOAD( m_dll, StopMovie, bOk );
wxDL_METHOD_LOAD( m_dll, GetMovieVolume, bOk );
wxDL_METHOD_LOAD( m_dll, SetMovieVolume, bOk );
+ wxLog::EnableLogging(bWasLoggingEnabled);
m_ok = true;
return true;
// Usual debugging macros
//---------------------------------------------------------------------------
#ifdef __WXDEBUG__
-#include "wx/msgdlg.h"
#define MAX_ERROR_TEXT_LEN 160
-//
-// FIXME : Just use wxASSERT_MSG here instead of msgdlg - but
-// stackwalker still crashes win2k, so do msgdlg for now...
-//
-#define wxAMVERIFY(x) \
-{ \
- HRESULT hrdsv = (x); \
- if ( FAILED(hrdsv) ) \
- { \
- wxChar szError[MAX_ERROR_TEXT_LEN]; \
- if( m_lpAMGetErrorText != NULL && \
- (*m_lpAMGetErrorText)(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0) \
- { \
- wxMessageBox( wxString::Format(wxT("DirectShow error \"%s\" \n")\
- wxT("(numeric %i)\n")\
- wxT("occured at line %i in ") \
- wxT("mediactrl.cpp"), \
- (int)hrdsv, szError, __LINE__) ); \
- wxASSERT(false);\
- } \
- else \
- { \
- wxMessageBox( wxString::Format(wxT("Unknown error (%i) ") \
- wxT("occurred at") \
- wxT(" line %i in mediactrl.cpp."), \
- (int)hrdsv, __LINE__) ); \
- wxASSERT(false);\
- } \
- } \
+#include "wx/log.h" //wxLogDebug et al.
+
+//Get the error string for Active Movie
+wxString wxAMMediaBackend::GetErrorString(HRESULT hrdsv)
+{
+ wxChar szError[MAX_ERROR_TEXT_LEN];
+ if( m_lpAMGetErrorText != NULL &&
+ (*m_lpAMGetErrorText)(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0)
+ {
+ return wxString::Format(wxT("DirectShow error \"%s\" \n")
+ wxT("(numeric %i)\n")
+ wxT("occured at line %i in ")
+ wxT("mediactrl.cpp"),
+ szError, (int)hrdsv, __LINE__);
+ }
+ else
+ {
+ return wxString::Format(wxT("Unknown error (%i) ")
+ wxT("occurred at")
+ wxT(" line %i in mediactrl.cpp."),
+ (int)hrdsv, __LINE__);
+ }
}
+
+#define wxAMFAIL(x) wxFAIL_MSG(GetErrorString(x));
#define wxVERIFY(x) wxASSERT((x))
+#define wxAMLOG(x) wxLogDebug(GetErrorString(x))
#else
#define wxAMVERIFY(x) (x)
#define wxVERIFY(x) (x)
+#define wxAMLOG(x)
+#define wxAMFAIL(x)
#endif
//---------------------------------------------------------------------------
//
// Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
//---------------------------------------------------------------------------
-wxAMMediaBackend::wxAMMediaBackend() : m_state(wxMEDIASTATE_STOPPED),
-m_pVMC(NULL)
- #ifdef __WXDEBUG__
- , m_hQuartzDll(NULL)
- #endif
+wxAMMediaBackend::wxAMMediaBackend()
+ :m_state(wxMEDIASTATE_STOPPED)
+ ,m_pVMC(NULL)
+ ,m_pGB(NULL)
+ ,m_pBA(NULL)
+ ,m_pMC(NULL)
+ ,m_pME(NULL)
+ ,m_pMS(NULL)
+ ,m_pThread(NULL)
+#ifdef __WXDEBUG__
+ ,m_hQuartzDll(NULL)
+#endif
{
}
//Make sure a valid windowless video mixing interface exists
IGraphBuilder* pGB;
- if( CoCreateInstance(CLSID_FilgraphManager, NULL,
+ if( ::CoCreateInstance(CLSID_FilgraphManager, NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGB) != 0 )
return false;
validator, name) )
return false;
- m_ctrl = ctrl;
-
- //
- // Connect Events
- //
- //TODO: Greg Hazel reports problems with this... but win2k seems fine on mine...
- //-------------------------------------------------------------------------------
// My problem with this was only with a previous patch, probably the third rewrite
- // fixed it as a side-effect. In fact, the erase background style of drawing not
- // only works now, but is much better than paint-based updates (the paint event
- // handler flickers if the wxMediaCtrl shares a sizer with another child window,
+ // fixed it as a side-effect. In fact, the erase background style of drawing not
+ // only works now, but is much better than paint-based updates (the paint event
+ // handler flickers if the wxMediaCtrl shares a sizer with another child window,
// or is on a notebook)
// - Greg Hazel
- m_ctrl->Connect(m_ctrl->GetId(), wxEVT_ERASE_BACKGROUND,
+ ctrl->Connect(ctrl->GetId(), wxEVT_ERASE_BACKGROUND,
wxEraseEventHandler(wxAMMediaEvtHandler::OnEraseBackground),
NULL, (wxEvtHandler*) this);
- //m_ctrl->Connect(m_ctrl->GetId(), wxEVT_PAINT,
- // wxPaintEventHandler(wxAMMediaEvtHandler::OnPaint),
- // NULL, (wxEvtHandler*) this);
-
- //
- // As noted below, we need to catch the Top Level Window's
- // move events because they are not sent to us if the media control
- // size remains the same but it actually moves in window coordinates
- //
- wxWindow* pTheTLW = m_ctrl->GetParent();
- while( pTheTLW->GetParent() )
- pTheTLW = pTheTLW->GetParent();
- //
- // FIXMEHACKFIXMEHACKFIXME
- // This is really nasty... basically the deal is not only above
- // but the repainting is messed up when the parent is maximized
- // too, so we've got to catch all 4 events!
- //
- m_ctrl->Connect(m_ctrl->GetId(), wxEVT_MOVE,
- wxMoveEventHandler(wxAMMediaEvtHandler::OnMove),
- NULL, (wxEvtHandler*) this);
- m_ctrl->Connect(m_ctrl->GetId(), wxEVT_SIZE,
- wxSizeEventHandler(wxAMMediaEvtHandler::OnSize),
- NULL, (wxEvtHandler*) this);
-
- pTheTLW->Connect(pTheTLW->GetId(), wxEVT_MOVE,
- wxMoveEventHandler(wxAMMediaEvtHandler::OnMove),
- NULL, (wxEvtHandler*) this);
- pTheTLW->Connect(pTheTLW->GetId(), wxEVT_SIZE,
- wxSizeEventHandler(wxAMMediaEvtHandler::OnSize),
- NULL, (wxEvtHandler*) this);
-
//
// done...
//
+ m_ctrl = ctrl;
return true;
}
// Adds a Video Mixing Renderer to a Filter Graph and obtains the
// windowless control from it
//---------------------------------------------------------------------------
-bool wxAMMediaBackend::SetWindowlessMode(IGraphBuilder* pGB,
+bool wxAMMediaBackend::SetWindowlessMode(IGraphBuilder* pGB,
IVMRWindowlessControl** ppVMC)
{
+ HRESULT hr;
+
//
// Create and add a custom Video Mixing Render to the graph
//
IBaseFilter* pVMR;
- if( CoCreateInstance(CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC_SERVER,
- IID_IBaseFilter, (void**)&pVMR) != 0 )
+ if( ::CoCreateInstance(CLSID_VideoMixingRenderer, NULL,
+ CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pVMR) != 0 )
return false;
- if ( pGB->AddFilter(pVMR, L"Video Mixing Renderer") != 0)
+ hr = pGB->AddFilter(pVMR, L"Video Mixing Renderer");
+ if ( hr != 0)
{
+ wxAMLOG(hr);
pVMR->Release();
return false;
}
//
// Set the graph to windowless mode
//
- IVMRFilterConfig* pConfig;
- if( pVMR->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig) != 0 )
+ IVMRFilterConfig* pConfig;
+ hr = pVMR->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
+ if( hr != 0 )
{
+ wxAMLOG(hr);
pVMR->Release();
return false;
}
- if( pConfig->SetRenderingMode(2) != 0) //2 == VMRMode_Windowless
+ hr = pConfig->SetRenderingMode(2);
+ if( hr != 0) //2 == VMRMode_Windowless
{
- pConfig->Release();
+ wxAMLOG(hr);
+ pConfig->Release();
pVMR->Release();
return false;
}
- pConfig->Release();
+ pConfig->Release();
//
// Obtain the windowless control
//
IVMRWindowlessControl* pVMC;
- if( pVMR->QueryInterface(IID_IVMRWindowlessControl, (void**)&pVMC) != 0 )
+ hr = pVMR->QueryInterface(IID_IVMRWindowlessControl, (void**)&pVMC);
+ if( hr != 0 )
{
- pVMR->Release();
+ wxAMLOG(hr);
+ pVMR->Release();
return false;
}
else
pVMC->Release();
- pVMR->Release();
- return true;
+ pVMR->Release();
+ return true;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
bool wxAMMediaBackend::Load(const wxString& fileName)
{
+ HRESULT hr;
+
//if previously loaded cleanup
if(m_pVMC)
Cleanup();
//Create interfaces - we already checked for success in CreateControl
- CoCreateInstance(CLSID_FilgraphManager, NULL, CLSCTX_INPROC_SERVER,
+ ::CoCreateInstance(CLSID_FilgraphManager, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&m_pGB);
// Set and clip output
SetWindowlessMode(m_pGB, &m_pVMC);
- if( m_pVMC->SetVideoClippingWindow((HWND)m_ctrl->GetHandle()) != 0 )
+ hr = m_pVMC->SetVideoClippingWindow((HWND)m_ctrl->GetHandle());
+
+ if(hr != 0)
{
m_bestSize.x = m_bestSize.y = 0;
- wxASSERT(false);
+ wxAMFAIL(hr);
+ return false;
}
//load the graph & render
if( m_pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL) != 0 )
return false;
+ //
//Get the interfaces, all of them
- wxAMVERIFY( m_pGB->QueryInterface(IID_IMediaEvent, (void**)&m_pME) );
- wxAMVERIFY( m_pGB->QueryInterface(IID_IMediaControl, (void**)&m_pMC) );
- wxAMVERIFY( m_pGB->QueryInterface(IID_IMediaPosition, (void**)&m_pMS) );
- wxAMVERIFY( m_pGB->QueryInterface(IID_IBasicAudio, (void**)&m_pBA) );
+ //
+ hr = m_pGB->QueryInterface(IID_IMediaEvent, (void**)&m_pME);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return false;
+ }
+
+ hr = m_pGB->QueryInterface(IID_IMediaControl, (void**)&m_pMC);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return false;
+ }
+
+ hr = m_pGB->QueryInterface(IID_IMediaPosition, (void**)&m_pMS);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return false;
+ }
+
+ hr = m_pGB->QueryInterface(IID_IBasicAudio, (void**)&m_pBA);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ //not critical
+ }
+ //
// Get original video size
- if( m_pVMC->GetNativeVideoSize((LONG*)&m_bestSize.x, (LONG*)&m_bestSize.y,
- NULL, NULL) != 0 )
+ //
+ hr = m_pVMC->GetNativeVideoSize((LONG*)&m_bestSize.x, (LONG*)&m_bestSize.y,
+ NULL, NULL);
+ if(hr != 0)
{
m_bestSize.x = m_bestSize.y = 0;
- wxASSERT(false);
+ wxAMFAIL(hr);
+ return false;
}
+ if(m_bestSize.x == 0 && m_bestSize.y == 0)
+ m_bVideo = false;
+ else
+ m_bVideo = true;
+
//
// Force the parent window of this control to recalculate
// the size of this if sizers are being used
m_ctrl->GetParent()->Update();
m_ctrl->SetSize(m_ctrl->GetSize());
+ //
+ // Create the event thread
+ //
m_pThread = new wxAMMediaThread;
m_pThread->pThis = this;
m_pThread->Create();
m_pThread->Run();
+ //
+ // done
+ //
return true;
}
return Load(location.BuildUnescapedURI());
}
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::Cleanup
+//
+// Releases all the directshow interfaces we use
+// TODO: Maybe only create one instance of IAMMultiMediaStream and reuse it
+// rather than recreating it each time?
+//---------------------------------------------------------------------------
+void wxAMMediaBackend::Cleanup()
+{
+ // RN: This could be a bad ptr if load failed after
+ // m_pVMC was created
+ if(m_pThread)
+ {
+ m_pThread->Delete();
+ m_pThread = NULL;
+ }
+
+ // Release and zero DirectShow interfaces
+ SAFE_RELEASE(m_pMC);
+ SAFE_RELEASE(m_pME);
+ SAFE_RELEASE(m_pMS);
+ SAFE_RELEASE(m_pBA);
+ SAFE_RELEASE(m_pGB);
+ SAFE_RELEASE(m_pVMC);
+}
+
+
//---------------------------------------------------------------------------
// wxAMMediaBackend::Play
//
//---------------------------------------------------------------------------
bool wxAMMediaBackend::SetPosition(wxLongLong where)
{
- return SUCCEEDED( m_pMS->put_CurrentPosition(
+ HRESULT hr = m_pMS->put_CurrentPosition(
((LONGLONG)where.GetValue()) / 1000.0
- ) );
+ );
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return false;
+ }
+
+ return true;
}
//---------------------------------------------------------------------------
wxLongLong wxAMMediaBackend::GetPosition()
{
double outCur;
- wxAMVERIFY( m_pMS->get_CurrentPosition(&outCur) );
+ HRESULT hr = m_pMS->get_CurrentPosition(&outCur);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return 0;
+ }
//h,m,s,milli - outdur is in 1 second (double)
outCur *= 1000;
}
//---------------------------------------------------------------------------
-// wxAMMediaBackend::SetVolume
+// wxAMMediaBackend::GetVolume
//
-// Sets the volume through the IBasicAudio interface -
+// Gets the volume through the IBasicAudio interface -
// value ranges from 0 (MAX volume) to -10000 (minimum volume).
// -100 per decibel.
//---------------------------------------------------------------------------
-bool wxAMMediaBackend::SetVolume(double dVolume)
+double wxAMMediaBackend::GetVolume()
{
- return SUCCEEDED(m_pBA->put_Volume( (long) ((dVolume-1.0) * 10000.0) ) );
+ if(m_pBA)
+ {
+ long lVolume;
+ HRESULT hr = m_pBA->get_Volume(&lVolume);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return 0.0;
+ }
+
+ return (((double)(lVolume + 10000)) / 10000.0);
+ }
+
+ wxLogDebug(wxT("No directshow audio interface"));
+ return 0.0;
}
//---------------------------------------------------------------------------
-// wxAMMediaBackend::GetVolume
+// wxAMMediaBackend::SetVolume
//
-// Gets the volume through the IBasicAudio interface -
+// Sets the volume through the IBasicAudio interface -
// value ranges from 0 (MAX volume) to -10000 (minimum volume).
// -100 per decibel.
//---------------------------------------------------------------------------
-double wxAMMediaBackend::GetVolume()
+bool wxAMMediaBackend::SetVolume(double dVolume)
{
- long lVolume;
- if ( SUCCEEDED( m_pBA->get_Volume(&lVolume) ) )
- return (((double)(lVolume + 10000)) / 10000.0);
- return 0.0;
+ if(m_pBA)
+ {
+ HRESULT hr = m_pBA->put_Volume( (long) ((dVolume-1.0) * 10000.0) );
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return false;
+ }
+ return true;
+ }
+
+ wxLogDebug(wxT("No directshow audio interface"));
+ return false;
}
//---------------------------------------------------------------------------
// 1) Obtains the duration of the media from IAMMultiMediaStream
// 2) Converts that value to our time base, and returns it
//
-// NB: With VBR MP3 files the default DirectShow MP3 render does not
+// NB: With VBR MP3 files the default DirectShow MP3 render does not
// read the Xing header correctly, resulting in skewed values for duration
// and seeking
//---------------------------------------------------------------------------
wxLongLong wxAMMediaBackend::GetDuration()
{
double outDuration;
- wxAMVERIFY( m_pMS->get_Duration(&outDuration) );
+ HRESULT hr = m_pMS->get_Duration(&outDuration);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return 0;
+ }
//h,m,s,milli - outdur is in 1 second (double)
outDuration *= 1000;
double wxAMMediaBackend::GetPlaybackRate()
{
double dRate;
- wxAMVERIFY( m_pMS->get_Rate(&dRate) );
+ HRESULT hr = m_pMS->get_Rate(&dRate);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return 0.0;
+ }
return dRate;
}
//---------------------------------------------------------------------------
bool wxAMMediaBackend::SetPlaybackRate(double dRate)
{
- return m_pMS->put_Rate(dRate) == 0;
-}
-
-//---------------------------------------------------------------------------
-// wxAMMediaBackend::Cleanup
-//
-// Releases all the directshow interfaces we use
-// TODO: Maybe only create one instance of IAMMultiMediaStream and reuse it
-// rather than recreating it each time?
-//---------------------------------------------------------------------------
-void wxAMMediaBackend::Cleanup()
-{
- m_pThread->Delete();
- m_pThread = NULL;
+ HRESULT hr = m_pMS->put_Rate(dRate);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return false;
+ }
- // Release and zero DirectShow interfaces
- SAFE_RELEASE(m_pMC);
- SAFE_RELEASE(m_pME);
- SAFE_RELEASE(m_pMS);
- SAFE_RELEASE(m_pBA);
- SAFE_RELEASE(m_pGB);
- SAFE_RELEASE(m_pVMC);
+ return true;
}
-
//---------------------------------------------------------------------------
// wxAMMediaBackend::GetVideoSize
//
//
// We take care of this in our redrawing
//---------------------------------------------------------------------------
-void wxAMMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y),
+void wxAMMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y),
int w, int h)
{
- if(m_pVMC)
+ //don't use deferred positioning on windows
+ if(m_pVMC && m_bVideo)
{
RECT srcRect, destRect;
-
+
//portion of video to display in window
srcRect.top = 0; srcRect.left = 0;
srcRect.bottom = m_bestSize.y; srcRect.right = m_bestSize.x;
destRect.bottom = h; destRect.right = w;
//set the windowless control positions
- if( m_pVMC->SetVideoPosition(&srcRect, &destRect) != 0 )
- {
- wxASSERT_MSG(false, wxT("Could not set video position!"));
- }
-
-/*
- //oddly enough, it doesn't redraw the frame after moving...
- //TODO: Use wxClientDC?
- HDC hdc = ::GetDC((HWND)m_ctrl->GetHandle());
- if( m_pVMC->RepaintVideo((HWND)m_ctrl->GetHandle(),
- hdc) != 0 )
+ HRESULT hr = m_pVMC->SetVideoPosition(&srcRect, &destRect);
+ if(FAILED(hr))
{
- wxASSERT(false);
+ wxAMLOG(hr);
}
- ::ReleaseDC((HWND)m_ctrl->GetHandle(), hdc);
-*/
}
}
-//---------------------------------------------------------------------------
-// wxAMMediaEvtHandler::OnMove
-//
-// Oddly enough Move isn't called on MSW when the parent moves
-// and the child (us) doesn't, so we have to do it twice I guess :(
-//---------------------------------------------------------------------------
-void wxAMMediaEvtHandler::OnMove(wxMoveEvent& evt)
-{
- wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
- pThis->Move(pThis->m_ctrl->GetPosition().x,
- pThis->m_ctrl->GetPosition().y,
- pThis->m_ctrl->GetSize().x,
- pThis->m_ctrl->GetSize().y );
- evt.Skip();
-}
-void wxAMMediaEvtHandler::OnSize(wxSizeEvent& evt)
-{
- wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
- pThis->Move(pThis->m_ctrl->GetPosition().x,
- pThis->m_ctrl->GetPosition().y,
- pThis->m_ctrl->GetSize().x,
- pThis->m_ctrl->GetSize().y );
- evt.Skip();
-}
-
//---------------------------------------------------------------------------
// wxAMMediaThread::Entry
//
(LONG_PTR *) &evParam2, 0) == 0 )
{
// Cleanup memory that GetEvent allocated
- if( pThis->m_pME->FreeEventParams(evCode, evParam1, evParam2) != 0 )
+ HRESULT hr = pThis->m_pME->FreeEventParams(evCode,
+ evParam1, evParam2);
+ if(hr != 0)
{
- wxASSERT(false);
+ //Even though this makes a messagebox this
+ //is windows where we can do gui stuff in seperate
+ //threads :)
+ wxFAIL_MSG(pThis->GetErrorString(hr));
}
-
// If this is the end of the clip, notify handler
- if(1 == evCode) //EC_COMPLETE
+ else if(1 == evCode) //EC_COMPLETE
{
pThis->OnStop();
}
void wxAMMediaEvtHandler::OnEraseBackground(wxEraseEvent& evt)
{
wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
- if(pThis->m_pVMC)
+ if(pThis->m_pVMC && pThis->m_bVideo)
{
//TODO: Use wxClientDC?
HDC hdc = ::GetDC((HWND)pThis->m_ctrl->GetHandle());
- if( pThis->m_pVMC->RepaintVideo((HWND)pThis->m_ctrl->GetHandle(),
- hdc) != 0 )
+ HRESULT hr = pThis->m_pVMC->RepaintVideo((HWND)pThis->m_ctrl->GetHandle(),
+ hdc);
+ if(FAILED(hr))
{
- wxASSERT(false);
+ wxFAIL_MSG(pThis->GetErrorString(hr));
}
::ReleaseDC((HWND)pThis->m_ctrl->GetHandle(), hdc);
}
}
}
-//---------------------------------------------------------------------------
-// wxAMMediaEvtHandler::OnPaint
-//
-// Handle redrawing
-//---------------------------------------------------------------------------
-void wxAMMediaEvtHandler::OnPaint(wxPaintEvent& WXUNUSED(evt))
-{
- wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
- wxPaintDC dc(pThis->m_ctrl);
- if( pThis->m_pVMC )
- {
- if( pThis->m_pVMC->RepaintVideo((HWND)pThis->m_ctrl->GetHandle(),
- (HDC)dc.GetHDC()) != 0 )
- {
- wxASSERT(false);
- }
- }
-}
-
//---------------------------------------------------------------------------
// End of wxAMMediaBackend
//---------------------------------------------------------------------------