]> git.saurik.com Git - wxWidgets.git/blame - src/msw/moviectrl.cpp
allow multiple movie loading as per Julian's suggestion. DOC.
[wxWidgets.git] / src / msw / moviectrl.cpp
CommitLineData
4ad7af2b
RN
1/////////////////////////////////////////////////////////////////////////////
2// Name: msw/moviectrl.cpp
3// Purpose: wxMovieCtrl MSW
4// Author: Ryan Norton <wxprojects@comcast.net>
5// Modified by:
6// Created: 11/07/04
7// RCS-ID: $Id$
8// Copyright: (c) Ryan Norton
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12//#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13//#pragma implementation "moviectrl.h"
14//#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20#pragma hdrstop
21#endif
22
bcac1ec2
RN
23#define wxUSE_MOVIECTRL 1
24
4ad7af2b
RN
25#if wxUSE_MOVIECTRL
26
27#include "wx/moviectrl.h"
28#include "wx/msw/ole/oleutils.h" //for wxBasicString
29
30#include <dshow.h>
31
32IMPLEMENT_CLASS(wxMovieCtrl, wxControl);
0568fd59
RN
33IMPLEMENT_DYNAMIC_CLASS(wxMovieEvent, wxEvent);
34DEFINE_EVENT_TYPE(wxEVT_MOVIE_FINISHED);
4ad7af2b
RN
35
36#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
37
38#define WM_GRAPHNOTIFY WM_USER+13
39
40#ifdef __WXDEBUG__
41#define wxDSVERIFY(x) wxASSERT( SUCCEEDED ((x)) )
42#else
43#define wxDSVERIFY(x) (x)
44#endif
45
4ad7af2b
RN
46//it's there someplace :)
47extern "C" WXDLLIMPEXP_BASE HWND
48wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
49
50bool wxMovieCtrl::Create(wxWindow* parent, wxWindowID id, const wxString& fileName,
51 const wxString& label, const wxPoint& pos, const wxSize& size,
52 long style, const wxString& name)
53{
3a774635
RN
54 //do some window stuff - ORDER IS IMPORTANT
55 //base create
56 if ( !wxControl::Create(parent, id, pos, size, wxNO_BORDER | wxCLIP_CHILDREN, wxDefaultValidator, name) )
57 return false;
58
59 //Set our background color to black by default
60 SetBackgroundColour(*wxBLACK);
61
62 if(!fileName.empty())
63 {
64 if (!Load(fileName))
65 return false;
66
67 SetLabel(label);
68
69 if(!Play())
70 return false;
71 }
72 else
73 wxControl::SetLabel(label);
74
75 return true;
76}
77
78bool wxMovieCtrl::Load(const wxString& fileName)
79{
80 if(m_bLoaded)
81 Cleanup();
82
4ad7af2b
RN
83 //cast helpers
84 IGraphBuilder*& pGB = (IGraphBuilder*&) m_pGB;
85 IMediaControl*& pMC = (IMediaControl*&) m_pMC;
86 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
87 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
88 IBasicAudio*& pBA = (IBasicAudio*&) m_pBA;
89 IBasicVideo*& pBV = (IBasicVideo*&) m_pBV;
90 IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
91
92 //create our filter graph
93 CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
94 IID_IGraphBuilder, (void**)&pGB);
95
96 //load the graph & render
97 if (FAILED(pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL)))
98 {
99 wxFAIL_MSG("Could not load movie!");
100 return false;
101 }
102
103 //get the interfaces, all of them
104 wxDSVERIFY( pGB->QueryInterface(IID_IMediaControl, (void**)&pMC) );
105 wxDSVERIFY( pGB->QueryInterface(IID_IMediaEventEx, (void**)&pME) );
106 wxDSVERIFY( pGB->QueryInterface(IID_IMediaSeeking, (void**)&pMS) );
107 wxDSVERIFY( pGB->QueryInterface(IID_IVideoWindow, (void**)&pVW) );
108 wxDSVERIFY( pGB->QueryInterface(IID_IBasicAudio, (void**)&pBA) );
109 wxDSVERIFY( pGB->QueryInterface(IID_IBasicVideo, (void**)&pBV) );
110
111 //get the _actual_ size of the movie & remember it
112 long nX, nY, nSX, nSY;
0568fd59
RN
113 if (FAILED(pVW->GetWindowPosition(&nX,&nY,&nSX,&nSY)))
114 m_bVideo = false;
115 else
116 {
117 m_bVideo = true;
118
119 this->Connect( wxID_ANY,
120 wxEVT_SIZE,
121 (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxMovieCtrl::OnSize );
122 }
4ad7af2b
RN
123
124 m_bestSize.x = nSX;
125 m_bestSize.y = nSY;
126
0568fd59
RN
127 if (m_bVideo)
128 {
129 wxDSVERIFY( pVW->put_Owner((OAHWND)this->GetHandle()) );
130 wxDSVERIFY( pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS) );
131 // wxDSVERIFY( pME->SetNotifyWindow((OAHWND)this->GetHandle(), WM_GRAPHNOTIFY, 0) );
132 wxDSVERIFY( pVW->put_Visible(OATRUE) ); //OATRUE actually == -1 :)
133 }
4ad7af2b
RN
134
135 //set the time format
136 wxDSVERIFY( pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME) );
137
3a774635 138 m_bLoaded = true;
4ad7af2b
RN
139 return true;
140}
141
142void wxMovieCtrl::SetLabel(const wxString& label)
143{
144 wxControl::SetLabel(label);
145
146 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
147
148 //wxBasicString will have a null string on an
149 //empty wxString - gotta love those workarounds!!
0568fd59 150 if(!label.empty() && m_bVideo)
4ad7af2b
RN
151 {
152 wxBasicString theBasicString(label.mb_str());
153 wxDSVERIFY( pVW->put_Caption(theBasicString.Get()) );
154 }
155}
156
157bool wxMovieCtrl::Play()
158{
159 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Run() );
160}
161
162bool wxMovieCtrl::Pause()
163{
164 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Pause() );
165}
166
167bool wxMovieCtrl::Stop()
168{
169 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Stop() );
170}
171
172#if wxUSE_DATETIME
173
174bool wxMovieCtrl::Seek(const wxTimeSpan& where)
175{
176 //DS uses 100 nanos - so we need a 10 mult
177 LONGLONG pos = ((size_t)where.GetMilliseconds().ToLong()) * 10;
178
179 return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetPositions(
180 &pos,
181 AM_SEEKING_AbsolutePositioning,
182 NULL,
183 AM_SEEKING_NoPositioning
184 ) );
185}
186
0568fd59
RN
187wxTimeSpan wxMovieCtrl::Tell()
188{
189 LONGLONG outCur, outStop;
190 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetPositions(&outCur, &outStop) );
191
192 return outCur;
193}
194
195wxTimeSpan wxMovieCtrl::Length()
196{
197 LONGLONG outDuration;
198 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetDuration(&outDuration) );
199
200 return outDuration;
201}
202
4ad7af2b
RN
203#endif // wxUSE_DATETIME
204
205wxMovieCtrlState wxMovieCtrl::GetState()
206{
207 HRESULT hr;
208 OAFilterState theState;
209 hr = ((IMediaControl*&)m_pMC)->GetState(INFINITE, &theState);
210
211 wxASSERT( SUCCEEDED(hr) );
212
213 //MSW state is the same as ours
214 //State_Stopped = 0,
215 //State_Paused = State_Stopped + 1,
216 //State_Running = State_Paused + 1
217
218 return (wxMovieCtrlState) theState;
219}
220
0568fd59
RN
221double wxMovieCtrl::GetPlaybackRate()
222{
223 double dRate;
224 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetRate(&dRate) );
225 return dRate;
226}
227
228bool wxMovieCtrl::SetPlaybackRate(double dRate)
229{
230 return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetRate(dRate) );
231}
232
233WXLRESULT wxMovieCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
234{
4ad7af2b 235 //cast helpers
0568fd59 236// IMediaControl*& pMC = (IMediaControl*&) m_pMC;
4ad7af2b 237 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
0568fd59 238// IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
4ad7af2b
RN
239
240 if (nMsg == WM_GRAPHNOTIFY)
241 {
242 LONG evCode, evParam1, evParam2;
243 HRESULT hr=S_OK;
244
4ad7af2b
RN
245 // Process all queued events
246 while(SUCCEEDED(pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
247 (LONG_PTR *) &evParam2, 0)
248 )
249 )
250 {
251 // Free memory associated with callback, since we're not using it
252 hr = pME->FreeEventParams(evCode, evParam1, evParam2);
253
0568fd59 254 // If this is the end of the clip, notify handler
4ad7af2b
RN
255 if(EC_COMPLETE == evCode)
256 {
0568fd59
RN
257 wxMovieEvent theEvent(wxEVT_MOVIE_FINISHED, this->GetId());
258 GetParent()->ProcessEvent(theEvent);
259/*
4ad7af2b
RN
260 LONGLONG pos=0;
261
262 // Reset to first frame of movie
263 hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
264 NULL, AM_SEEKING_NoPositioning);
265 if (FAILED(hr))
266 {
267 hr = pMC->Stop();
268 // for filters that don't support seeking do a rewind
269 if (FAILED(hr))
270 {
271 wxFAIL_MSG(
272 wxString::Format(TEXT("Failed(0x%08lx) to stop media clip!\r\n"), hr)
273 );
274 break;
275 }
276
277 hr = hr = pMC->Run();
278
279 if (FAILED(hr))
280 {
281 wxFAIL_MSG(
282 wxString::Format(TEXT("Failed(0x%08lx) to reset media clip!\r\n"), hr)
283 );
284 break;
285 }
286 }
0568fd59 287*/
4ad7af2b
RN
288 }
289 }
290 return wxControl::MSWDefWindowProc(nMsg, wParam, lParam);
291 }
4ad7af2b 292 //pass the event to our parent
0568fd59
RN
293 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
294}
4ad7af2b 295
3a774635 296void wxMovieCtrl::Cleanup()
4ad7af2b 297{
3a774635
RN
298 if(m_bVideo)
299 this->Disconnect( wxID_ANY,
300 wxEVT_SIZE,
301 (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxMovieCtrl::OnSize );
302
4ad7af2b
RN
303 //cast helpers
304 IGraphBuilder*& pGB = (IGraphBuilder*&) m_pGB;
305 IMediaControl*& pMC = (IMediaControl*&) m_pMC;
306 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
307 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
308 IBasicAudio*& pBA = (IBasicAudio*&) m_pBA;
309 IBasicVideo*& pBV = (IBasicVideo*&) m_pBV;
310 IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
311
312 // Hide then disown the window
313 if(pVW)
314 {
315 pVW->put_Visible(OAFALSE); //OSFALSE == 0
316 pVW->put_Owner(NULL);
317 }
318
319 // Release and zero DirectShow interfaces
320 SAFE_RELEASE(pME);
321 SAFE_RELEASE(pMS);
322 SAFE_RELEASE(pMC);
323 SAFE_RELEASE(pBA);
324 SAFE_RELEASE(pBV);
325 SAFE_RELEASE(pVW);
326 SAFE_RELEASE(pGB);
327}
328
3a774635
RN
329wxMovieCtrl::~wxMovieCtrl()
330{
331 if (m_bLoaded)
332 Cleanup();
333}
334
4ad7af2b
RN
335wxSize wxMovieCtrl::DoGetBestSize() const
336{
337 return m_bestSize;
338}
339
4ad7af2b
RN
340void wxMovieCtrl::OnSize(wxSizeEvent& evt)
341{
342 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
343 wxDSVERIFY( pVW->SetWindowPosition(0, 0, evt.GetSize().GetWidth(), evt.GetSize().GetHeight()) );
344
345 evt.Skip();
346}
4ad7af2b
RN
347
348#endif //wxUSE_MOVIECTRL