wxMovieCtrl - for playing movies - mac carbon QT 3 MSW-compatable implementation and MSW DirectX7 directshow implementation

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@30332 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Ryan Norton
2004-11-07 08:27:51 +00:00
parent 9b621a7f7a
commit 4ad7af2b83
5 changed files with 759 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/msw/moviectrl.h
// Purpose: DirectX7+ wxMovieCtrl MSW
// Author: Ryan Norton <wxprojects@comcast.net>
// Modified by:
// Created: 11/07/04
// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/defs.h"
#if wxUSE_MOVIECTRL
#include "wx/datetime.h"
enum wxMovieCtrlState
{
wxMOVIECTRL_STOPPED,
wxMOVIECTRL_PAUSED,
wxMOVIECTRL_PLAYING
};
class wxMovieCtrl : public wxControl
{
public:
wxMovieCtrl()
{ }
wxMovieCtrl(wxWindow* parent, wxWindowID id, const wxString& fileName, const wxString& label = wxT(""),
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = 0, const wxString& name = wxPanelNameStr)
{ Create(parent, id, fileName, label, pos, size, style, name); }
~wxMovieCtrl();
bool Create(wxWindow* parent, wxWindowID id, const wxString& fileName, const wxString& label = wxT(""),
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = 0, const wxString& name = wxPanelNameStr);
bool Play();
bool Pause();
bool Stop();
wxMovieCtrlState GetState();
#if wxUSE_DATETIME
bool Seek(const wxTimeSpan& where);
#endif
virtual void SetLabel(const wxString& label);
protected:
void OnSize(wxSizeEvent& evt);
wxSize DoGetBestSize() const;
bool InitQT();
struct MovieRecord* m_movie;
wxSize m_bestSize;
class _wxQTTimer* m_timer;
DECLARE_DYNAMIC_CLASS(wxMovieCtrl);
DECLARE_EVENT_TABLE()
};
#endif // wxUSE_MOVIECTRL

16
include/wx/moviectrl.h Normal file
View File

@@ -0,0 +1,16 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/moviectrl.h
// Purpose: wxMovieCtrl class
// Author: Ryan Norton <wxprojects@comcast.net>
// Modified by:
// Created: 11/07/04
// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#if defined(__WXMSW__)
#include "wx/msw/moviectrl.h"
#elif defined(__WXMAC__)
#include "wx/mac/carbon/moviectrl.h"
#endif

View File

@@ -0,0 +1,77 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/msw/moviectrl.h
// Purpose: DirectX7+ wxMovieCtrl MSW
// Author: Ryan Norton <wxprojects@comcast.net>
// Modified by:
// Created: 11/07/04
// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/defs.h"
#if wxUSE_MOVIECTRL
#include "wx/datetime.h"
enum wxMovieCtrlState
{
wxMOVIECTRL_STOPPED,
wxMOVIECTRL_PAUSED,
wxMOVIECTRL_PLAYING
};
class wxMovieCtrl : public wxControl
{
public:
wxMovieCtrl()
{ }
wxMovieCtrl(wxWindow* parent, wxWindowID id, const wxString& fileName, const wxString& label = wxT(""),
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = 0, const wxString& name = wxPanelNameStr)
{ Create(parent, id, fileName, label, pos, size, style, name); }
~wxMovieCtrl();
bool Create(wxWindow* parent, wxWindowID id, const wxString& fileName, const wxString& label = wxT(""),
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = 0, const wxString& name = wxPanelNameStr);
bool Play();
bool Pause();
bool Stop();
wxMovieCtrlState GetState();
#if wxUSE_DATETIME
bool Seek(const wxTimeSpan& where);
#endif
virtual void SetLabel(const wxString& label);
protected:
void OnSize(wxSizeEvent& evt);
wxSize DoGetBestSize() const;
// void OnActivate(wxActivateEvent& evt);
//msw-specific - we need to overload the window proc
// WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam);
void* m_pGB;
void* m_pMC;
void* m_pME;
void* m_pVW;
void* m_pBA;
void* m_pBV;
void* m_pMS;
wxSize m_bestSize;
DECLARE_DYNAMIC_CLASS(wxMovieCtrl);
DECLARE_EVENT_TABLE()
};
#endif // wxUSE_MOVIECTRL

View File

@@ -0,0 +1,304 @@
/////////////////////////////////////////////////////////////////////////////
// Name: mac/carbon/moviectrl.cpp
// Purpose: wxMovieCtrl MAC CARBON QT
// Author: Ryan Norton <wxprojects@comcast.net>
// Modified by:
// Created: 11/07/04
// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
//#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
//#pragma implementation "moviectrl.h"
//#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#define wxUSE_MOVIECTRL 1
#if wxUSE_MOVIECTRL
#include "wx/moviectrl.h"
#include "wx/sound.h"
#include "wx/timer.h"
IMPLEMENT_CLASS(wxMovieCtrl, wxControl);
BEGIN_EVENT_TABLE(wxMovieCtrl, wxControl)
EVT_SIZE(wxMovieCtrl::OnSize)
END_EVENT_TABLE()
//MESSY headers
#ifdef __WXMAC__
#include "wx/mac/uma.h"
#include <Movies.h>
#include <Gestalt.h>
#endif
//quicktime media layer only required for mac emulation on pc
#ifndef __WXMAC__
#include <qtml.h>
#endif
#include <QuickTimeComponents.h>
//Time between timer calls
#define MOVIE_DELAY 100
// ------------------------------------------------------------------
// wxQTTimer - Handle Asyncronous Playing
// ------------------------------------------------------------------
class _wxQTTimer : public wxTimer
{
public:
_wxQTTimer(Movie movie) :
m_movie(movie), m_bPaused(false)
{
}
~_wxQTTimer()
{
}
bool GetPaused() {return m_bPaused;}
void SetPaused(bool bPaused) {m_bPaused = bPaused;}
void Notify()
{
if (!m_bPaused)
{
if(!IsMovieDone(m_movie))
MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie
else
Stop();
}
}
protected:
Movie m_movie;
bool m_bPaused;
};
//Determines whether version 3 of QT is installed
Boolean wxIsQuickTime3Installed (void)
{
#ifdef __WXMAC__
short error;
long result;
error = Gestalt (gestaltQuickTime, &result);
return (error == noErr) && (((result >> 16) & 0xffff) >= 0x0300);
#else
return true;
#endif
}
bool wxMovieCtrl::InitQT ()
{
if (wxIsQuickTime3Installed())
{
#ifndef __WXMAC__
int nError;
//-2093 no dll
if ((nError = InitializeQTML(0)) != noErr)
{
wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
}
#endif
EnterMovies();
return true;
}
else
{
wxFAIL_MSG(wxT("Quicktime is not installed, or Your Version of Quicktime is <= 4."));
return false;
}
}
bool wxMovieCtrl::Create(wxWindow* parent, wxWindowID id, const wxString& fileName,
const wxString& label, const wxPoint& pos, const wxSize& size,
long WXUNUSED(style), const wxString& name)
{
if ( !InitQT() )
return false;
OSErr err = noErr;
short movieResFile;
FSSpec sfFile;
#ifdef __WXMAC__
wxMacFilename2FSSpec( m_sndname , &sfFile ) ;
#else
int nError;
if ((nError = NativePathNameToFSSpec ((char*) fileName.c_str(), &sfFile, 0)) != noErr)
{
wxFAIL_MSG(wxString::Format(wxT("File:%s does not exist\nError:%i"),
fileName.c_str(), nError));
return false;
}
#endif
if (OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
{
wxFAIL_MSG(wxT("Quicktime couldn't open the file"));
return false;
}
short movieResID = 0;
Str255 movieName;
err = NewMovieFromFile (
&m_movie,
movieResFile,
&movieResID,
movieName,
newMovieActive,
NULL); //wasChanged
CloseMovieFile (movieResFile);
if (err != noErr)
{
wxFAIL_MSG(wxT("Could not create movie"));
return false;
}
m_timer = new _wxQTTimer(m_movie);
wxASSERT(m_timer);
//get the real size of the movie
Rect outRect;
::GetMovieNaturalBoundsRect (m_movie, &outRect);
m_bestSize.x = outRect.right - outRect.left;
m_bestSize.y = outRect.bottom - outRect.top;
//do some window stuff
if ( !wxControl::Create(parent, id, pos, size, wxNO_BORDER, wxDefaultValidator, name) )
return false;
//Set our background color to black by default
SetBackgroundColour(*wxBLACK);
//reparent movie
#ifdef __WXMSW__
CreatePortAssociation(this->GetHWND(), NULL, 0L);
#endif
SetMovieGWorld(m_movie, (CGrafPtr)
#ifdef __WXMSW__
GetNativeWindowPort(this->GetHWND())
#else
this->GetHandle()
#endif
, nil);
//go!
SetLabel(label);
Play();
return true;
}
void wxMovieCtrl::SetLabel(const wxString& label)
{
wxControl::SetLabel(label);
}
bool wxMovieCtrl::Play()
{
::StartMovie(m_movie);
m_timer->SetPaused(false);
m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
return ::GetMoviesError() == noErr;
}
bool wxMovieCtrl::Pause()
{
::StopMovie(m_movie);
m_timer->SetPaused(true);
return ::GetMoviesError() == noErr;
}
bool wxMovieCtrl::Stop()
{
m_timer->SetPaused(false);
::StopMovie(m_movie);
if(::GetMoviesError() != noErr)
return false;
::GoToEndOfMovie(m_movie);
return ::GetMoviesError() == noErr;
}
#if wxUSE_DATETIME
bool wxMovieCtrl::Seek(const wxTimeSpan& where)
{
TimeRecord theTimeRecord;
theTimeRecord.value.lo = ((size_t)where.GetMilliseconds().ToLong()) * 10;
theTimeRecord.scale = ::GetMovieTimeScale(m_movie);
theTimeRecord.base = ::GetMovieTimeBase(m_movie);
::SetMovieTime(m_movie, &theTimeRecord);
if (::GetMoviesError() != noErr)
return false;
return true;
}
#endif // wxUSE_DATETIME
wxMovieCtrlState wxMovieCtrl::GetState()
{
if( m_timer->IsRunning() == true )
return wxMOVIECTRL_STOPPED;
if ( m_timer->GetPaused() == false )
return wxMOVIECTRL_PLAYING;
else
return wxMOVIECTRL_PAUSED;
}
wxMovieCtrl::~wxMovieCtrl()
{
if (m_timer)
{
delete m_timer;
StopMovie(m_movie);
DisposeMovie(m_movie);
//Note that ExitMovies() is not neccessary, but
//the docs are fuzzy on whether or not TerminateQTML is
ExitMovies();
#ifndef __WXMAC__
TerminateQTML();
#endif
}
}
wxSize wxMovieCtrl::DoGetBestSize() const
{
return m_bestSize;
}
void wxMovieCtrl::OnSize(wxSizeEvent& evt)
{
Rect theRect;
theRect.left = 0;
theRect.top = 0;
theRect.bottom = evt.GetSize().y;
theRect.right = evt.GetSize().x;
::SetMovieBox(m_movie, &theRect);
wxASSERT(::GetMoviesError() == noErr);
evt.Skip();
}
#endif //wxUSE_MOVIECTRL

295
src/msw/moviectrl.cpp Normal file
View File

@@ -0,0 +1,295 @@
/////////////////////////////////////////////////////////////////////////////
// Name: msw/moviectrl.cpp
// Purpose: wxMovieCtrl MSW
// Author: Ryan Norton <wxprojects@comcast.net>
// Modified by:
// Created: 11/07/04
// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
//#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
//#pragma implementation "moviectrl.h"
//#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_MOVIECTRL
#include "wx/moviectrl.h"
#include "wx/msw/ole/oleutils.h" //for wxBasicString
#include <dshow.h>
IMPLEMENT_CLASS(wxMovieCtrl, wxControl);
#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
#define WM_GRAPHNOTIFY WM_USER+13
#ifdef __WXDEBUG__
#define wxDSVERIFY(x) wxASSERT( SUCCEEDED ((x)) )
#else
#define wxDSVERIFY(x) (x)
#endif
BEGIN_EVENT_TABLE(wxMovieCtrl, wxControl)
EVT_SIZE(wxMovieCtrl::OnSize)
// EVT_ACTIVATE(wxMovieCtrl::OnActivate)
END_EVENT_TABLE()
//it's there someplace :)
extern "C" WXDLLIMPEXP_BASE HWND
wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
bool wxMovieCtrl::Create(wxWindow* parent, wxWindowID id, const wxString& fileName,
const wxString& label, const wxPoint& pos, const wxSize& size,
long style, const wxString& name)
{
//cast helpers
IGraphBuilder*& pGB = (IGraphBuilder*&) m_pGB;
IMediaControl*& pMC = (IMediaControl*&) m_pMC;
IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
IBasicAudio*& pBA = (IBasicAudio*&) m_pBA;
IBasicVideo*& pBV = (IBasicVideo*&) m_pBV;
IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
//create our filter graph
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGB);
//load the graph & render
if (FAILED(pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL)))
{
wxFAIL_MSG("Could not load movie!");
return false;
}
//get the interfaces, all of them
wxDSVERIFY( pGB->QueryInterface(IID_IMediaControl, (void**)&pMC) );
wxDSVERIFY( pGB->QueryInterface(IID_IMediaEventEx, (void**)&pME) );
wxDSVERIFY( pGB->QueryInterface(IID_IMediaSeeking, (void**)&pMS) );
wxDSVERIFY( pGB->QueryInterface(IID_IVideoWindow, (void**)&pVW) );
wxDSVERIFY( pGB->QueryInterface(IID_IBasicAudio, (void**)&pBA) );
wxDSVERIFY( pGB->QueryInterface(IID_IBasicVideo, (void**)&pBV) );
//get the _actual_ size of the movie & remember it
long nX, nY, nSX, nSY;
pVW->GetWindowPosition(&nX,&nY,&nSX,&nSY);
m_bestSize.x = nSX;
m_bestSize.y = nSY;
//do some window stuff - ORDER IS IMPORTANT
//base create
if ( !wxControl::Create(parent, id, pos, size, wxNO_BORDER | wxCLIP_CHILDREN, wxDefaultValidator, name) )
return false;
//Set our background color to black by default
SetBackgroundColour(*wxBLACK);
wxDSVERIFY( pVW->put_Owner((OAHWND)this->GetHandle()) );
wxDSVERIFY( pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS) );
// wxDSVERIFY( pME->SetNotifyWindow((OAHWND)this->GetHandle(), WM_GRAPHNOTIFY, 0) );
wxDSVERIFY( pVW->put_Visible(OATRUE) ); //OATRUE actually == -1 :)
//set the time format
wxDSVERIFY( pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME) );
SetLabel(label);
Play();
return true;
}
void wxMovieCtrl::SetLabel(const wxString& label)
{
wxControl::SetLabel(label);
IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
//wxBasicString will have a null string on an
//empty wxString - gotta love those workarounds!!
if(!label.empty())
{
wxBasicString theBasicString(label.mb_str());
wxDSVERIFY( pVW->put_Caption(theBasicString.Get()) );
}
}
bool wxMovieCtrl::Play()
{
return SUCCEEDED( ((IMediaControl*&)m_pMC)->Run() );
}
bool wxMovieCtrl::Pause()
{
return SUCCEEDED( ((IMediaControl*&)m_pMC)->Pause() );
}
bool wxMovieCtrl::Stop()
{
return SUCCEEDED( ((IMediaControl*&)m_pMC)->Stop() );
}
#if wxUSE_DATETIME
bool wxMovieCtrl::Seek(const wxTimeSpan& where)
{
//DS uses 100 nanos - so we need a 10 mult
LONGLONG pos = ((size_t)where.GetMilliseconds().ToLong()) * 10;
return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetPositions(
&pos,
AM_SEEKING_AbsolutePositioning,
NULL,
AM_SEEKING_NoPositioning
) );
}
#endif // wxUSE_DATETIME
wxMovieCtrlState wxMovieCtrl::GetState()
{
HRESULT hr;
OAFilterState theState;
hr = ((IMediaControl*&)m_pMC)->GetState(INFINITE, &theState);
wxASSERT( SUCCEEDED(hr) );
//MSW state is the same as ours
//State_Stopped = 0,
//State_Paused = State_Stopped + 1,
//State_Running = State_Paused + 1
return (wxMovieCtrlState) theState;
}
//WXLRESULT wxMovieCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
//{
/*
//cast helpers
IMediaControl*& pMC = (IMediaControl*&) m_pMC;
IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
if (nMsg == WM_GRAPHNOTIFY)
{
LONG evCode, evParam1, evParam2;
HRESULT hr=S_OK;
//make sure we exist
if (!pME)
return S_OK;
// Process all queued events
while(SUCCEEDED(pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
(LONG_PTR *) &evParam2, 0)
)
)
{
// Free memory associated with callback, since we're not using it
hr = pME->FreeEventParams(evCode, evParam1, evParam2);
// If this is the end of the clip, reset to beginning
if(EC_COMPLETE == evCode)
{
LONGLONG pos=0;
// Reset to first frame of movie
hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
NULL, AM_SEEKING_NoPositioning);
if (FAILED(hr))
{
hr = pMC->Stop();
// for filters that don't support seeking do a rewind
if (FAILED(hr))
{
wxFAIL_MSG(
wxString::Format(TEXT("Failed(0x%08lx) to stop media clip!\r\n"), hr)
);
break;
}
hr = hr = pMC->Run();
if (FAILED(hr))
{
wxFAIL_MSG(
wxString::Format(TEXT("Failed(0x%08lx) to reset media clip!\r\n"), hr)
);
break;
}
}
}
}
return wxControl::MSWDefWindowProc(nMsg, wParam, lParam);
}
*/
//pass the event to our parent
// return wxControl::MSWWindowProc(nMsg, wParam, lParam);
//}
wxMovieCtrl::~wxMovieCtrl()
{
//cast helpers
IGraphBuilder*& pGB = (IGraphBuilder*&) m_pGB;
IMediaControl*& pMC = (IMediaControl*&) m_pMC;
IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
IBasicAudio*& pBA = (IBasicAudio*&) m_pBA;
IBasicVideo*& pBV = (IBasicVideo*&) m_pBV;
IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
// Hide then disown the window
if(pVW)
{
pVW->put_Visible(OAFALSE); //OSFALSE == 0
pVW->put_Owner(NULL);
}
// Release and zero DirectShow interfaces
SAFE_RELEASE(pME);
SAFE_RELEASE(pMS);
SAFE_RELEASE(pMC);
SAFE_RELEASE(pBA);
SAFE_RELEASE(pBV);
SAFE_RELEASE(pVW);
SAFE_RELEASE(pGB);
}
wxSize wxMovieCtrl::DoGetBestSize() const
{
return m_bestSize;
}
//
//EVENT OVERRIDES
//
void wxMovieCtrl::OnSize(wxSizeEvent& evt)
{
IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
wxDSVERIFY( pVW->SetWindowPosition(0, 0, evt.GetSize().GetWidth(), evt.GetSize().GetHeight()) );
evt.Skip();
}
/*
void wxMovieCtrl::OnActivate(wxActivateEvent& evt)
{
if (evt.GetActive())
{
//HACK: Make the window show :)
SetSize(GetSize());
}
}
*/
#endif //wxUSE_MOVIECTRL