📄 mediactrl.cpp
字号:
short movieResFile;
FSSpec sfFile;
wxMacFilename2FSSpec( fileName, &sfFile );
if (OpenMovieFile( &sfFile, &movieResFile, fsRdPerm ) != noErr)
return false;
short movieResID = 0;
Str255 movieName;
err = NewMovieFromFile(
&m_movie,
movieResFile,
&movieResID,
movieName,
newMovieActive,
NULL); // wasChanged
//
// check GetMoviesStickyError() because it may not find the
// proper codec and play black video and other strange effects,
// not to mention mess up the dynamic backend loading scheme
// of wxMediaCtrl - so it just does what the QuickTime player does
//
if (err == noErr && ::GetMoviesStickyError() == noErr)
{
::CloseMovieFile(movieResFile);
// Create movie controller/control
DoNewMovieController();
FinishLoad();
return true;
}
return false;
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::Load (URL Version)
//
// 1) Build an escaped URI from location
// 2) Create a handle to store the URI string
// 3) Put the URI string inside the handle
// 4) Make a QuickTime URL data ref from the handle with the URI in it
// 5) Clean up the URI string handle
// 6) Do some prerolling
// 7) Finish Loading
//---------------------------------------------------------------------------
bool wxQTMediaBackend::Load(const wxURI& location)
{
if (m_movie)
Cleanup();
::ClearMoviesStickyError(); // clear previous errors so
// GetMoviesStickyError is useful
wxString theURI = location.BuildURI();
OSErr err;
size_t len;
const char* theURIString;
#if wxUSE_UNICODE
wxCharBuffer buf = wxConvLocal.cWC2MB(theURI, theURI.length(), &len);
theURIString = buf;
#else
theURIString = theURI;
len = theURI.length();
#endif
Handle theHandle = ::NewHandleClear(len + 1);
wxASSERT(theHandle);
::BlockMoveData(theURIString, *theHandle, len + 1);
// create the movie from the handle that refers to the URI
err = ::NewMovieFromDataRef(
&m_movie,
newMovieActive | newMovieAsyncOK /* | newMovieIdleImportOK*/,
NULL, theHandle,
URLDataHandlerSubType);
::DisposeHandle(theHandle);
if (err == noErr && ::GetMoviesStickyError() == noErr)
{
// Movie controller resets prerolling, so we must create first
DoNewMovieController();
long timeNow;
Fixed playRate;
timeNow = ::GetMovieTime(m_movie, NULL);
wxASSERT(::GetMoviesError() == noErr);
playRate = ::GetMoviePreferredRate(m_movie);
wxASSERT(::GetMoviesError() == noErr);
//
// Note that the callback here is optional,
// but without it PrePrerollMovie can be buggy
// (see Apple ml). Also, some may wonder
// why we need this at all - this is because
// Apple docs say QuickTime streamed movies
// require it if you don't use a Movie Controller,
// which we don't by default.
//
m_preprerollupp =
NewMoviePrePrerollCompleteUPP( wxQTMediaBackend::PPRMProc );
::PrePrerollMovie( m_movie, timeNow, playRate,
m_preprerollupp, (void*)this);
return true;
}
return false;
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::DoNewMovieController
//
// Attaches movie to moviecontroller or creates moviecontroller
// if not created yet
//---------------------------------------------------------------------------
void wxQTMediaBackend::DoNewMovieController()
{
if (!m_mc)
{
// Get top level window ref for some mac functions
WindowRef wrTLW = (WindowRef) m_ctrl->MacGetTopLevelWindowRef();
// MovieController not set up yet, so we need to create a new one.
// You have to pass a valid movie to NewMovieController, evidently
::SetMovieGWorld(m_movie,
(CGrafPtr) GetWindowPort(wrTLW),
NULL);
wxASSERT(::GetMoviesError() == noErr);
Rect bounds = wxMacGetBoundsForControl(
m_ctrl,
m_ctrl->GetPosition(),
m_ctrl->GetSize());
m_mc = ::NewMovieController(
m_movie, &bounds,
mcTopLeftMovie | mcNotVisible /* | mcWithFrame */ );
wxASSERT(::GetMoviesError() == noErr);
::MCDoAction(m_mc, 32, (void*)true); // mcActionSetKeysEnabled
wxASSERT(::GetMoviesError() == noErr);
// Setup a callback so we can tell when the user presses
// play on the player controls
m_mcactionupp =
NewMCActionFilterWithRefConUPP( wxQTMediaBackend::MCFilterProc );
::MCSetActionFilterWithRefCon( m_mc, m_mcactionupp, (long)this );
wxASSERT(::GetMoviesError() == noErr);
// Part of a suggestion from Greg Hazel to repaint movie when idle
m_ctrl->PushEventHandler(new wxQTMediaEvtHandler(this));
// Create offscreen GWorld for where to "show" when window is hidden
Rect worldRect;
worldRect.left = worldRect.top = 0;
worldRect.right = worldRect.bottom = 1;
::NewGWorld(&m_movieWorld, 0, &worldRect, NULL, NULL, 0);
// Catch window messages:
// if we do not do this and if the user clicks the play
// button on the controller, for instance, nothing will happen...
EventTypeSpec theWindowEventTypes[] =
{
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp },
{ kEventClassMouse, kEventMouseDragged },
{ kEventClassKeyboard, kEventRawKeyDown },
{ kEventClassKeyboard, kEventRawKeyRepeat },
{ kEventClassKeyboard, kEventRawKeyUp },
{ kEventClassWindow, kEventWindowUpdate },
{ kEventClassWindow, kEventWindowActivated },
{ kEventClassWindow, kEventWindowDeactivated }
};
m_windowUPP =
NewEventHandlerUPP( wxQTMediaBackend::WindowEventHandler );
InstallWindowEventHandler(
wrTLW,
m_windowUPP,
GetEventTypeCount( theWindowEventTypes ), theWindowEventTypes,
this,
&m_windowEventHandler );
}
else
{
// MovieController already created:
// Just change the movie in it and we're good to go
Point thePoint;
thePoint.h = thePoint.v = 0;
::MCSetMovie(m_mc, m_movie,
(WindowRef)m_ctrl->MacGetTopLevelWindowRef(),
thePoint);
wxASSERT(::GetMoviesError() == noErr);
}
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::FinishLoad
//
// Performs operations after a movie ready to play/loaded.
//---------------------------------------------------------------------------
void wxQTMediaBackend::FinishLoad()
{
// Dispose of the PrePrerollMovieUPP if we used it
DisposeMoviePrePrerollCompleteUPP(m_preprerollupp);
// get the real size of the movie
DoLoadBestSize();
// show the player controls if the user wants to
if (m_interfaceflags)
DoSetControllerVisible(m_interfaceflags);
// we want millisecond precision
::SetMovieTimeScale(m_movie, 1000);
wxASSERT(::GetMoviesError() == noErr);
// start movie progress timer
m_timer = new wxQTMediaPlayTimer(this);
wxASSERT(m_timer);
m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
// send loaded event and refresh size
NotifyMovieLoaded();
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::DoLoadBestSize
//
// Sets the best size of the control from the real size of the movie
//---------------------------------------------------------------------------
void wxQTMediaBackend::DoLoadBestSize()
{
// get the real size of the movie
Rect outRect;
::GetMovieNaturalBoundsRect(m_movie, &outRect);
wxASSERT(::GetMoviesError() == noErr);
// determine best size
m_bestSize.x = outRect.right - outRect.left;
m_bestSize.y = outRect.bottom - outRect.top;
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::Play
//
// Start the QT movie
// (Apple recommends mcActionPrerollAndPlay but that's QT 4.1+)
//---------------------------------------------------------------------------
bool wxQTMediaBackend::Play()
{
Fixed fixRate = (Fixed) (wxQTMediaBackend::GetPlaybackRate() * 0x10000);
if (!fixRate)
fixRate = ::GetMoviePreferredRate(m_movie);
wxASSERT(fixRate != 0);
if (!m_bPlaying)
::MCDoAction( m_mc, 8 /* mcActionPlay */, (void*) fixRate);
bool result = (::GetMoviesError() == noErr);
if (result)
{
m_bPlaying = true;
QueuePlayEvent();
}
return result;
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::Pause
//
// Stop the movie
//---------------------------------------------------------------------------
bool wxQTMediaBackend::DoPause()
{
// Stop the movie A.K.A. ::StopMovie(m_movie);
if (m_bPlaying)
{
::MCDoAction( m_mc, 8 /*mcActionPlay*/, (void *) 0);
m_bPlaying = false;
return ::GetMoviesError() == noErr;
}
// already paused
return true;
}
bool wxQTMediaBackend::Pause()
{
bool bSuccess = DoPause();
if (bSuccess)
this->QueuePauseEvent();
return bSuccess;
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::Stop
//
// 1) Stop the movie
// 2) Seek to the beginning of the movie
//---------------------------------------------------------------------------
bool wxQTMediaBackend::DoStop()
{
if (!wxQTMediaBackend::DoPause())
return false;
::GoToBeginningOfMovie(m_movie);
return ::GetMoviesError() == noErr;
}
bool wxQTMediaBackend::Stop()
{
bool bSuccess = DoStop();
if (bSuccess)
QueueStopEvent();
return bSuccess;
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::GetPlaybackRate
//
// 1) Get the movie playback rate from ::GetMovieRate
//---------------------------------------------------------------------------
double wxQTMediaBackend::GetPlaybackRate()
{
return ( ((double)::GetMovieRate(m_movie)) / 0x10000);
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::SetPlaybackRate
//
// 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
//---------------------------------------------------------------------------
bool wxQTMediaBackend::SetPlaybackRate(double dRate)
{
::SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
return ::GetMoviesError() == noErr;
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::SetPosition
//
// 1) Create a time record struct (TimeRecord) with appropriate values
// 2) Pass struct to SetMovieTime
//---------------------------------------------------------------------------
bool wxQTMediaBackend::SetPosition(wxLongLong where)
{
TimeRecord theTimeRecord;
memset(&theTimeRecord, 0, sizeof(TimeRecord));
theTimeRecord.value.lo = where.GetValue();
theTimeRecord.scale = ::GetMovieTimeScale(m_movie);
theTimeRecord.base = ::GetMovieTimeBase(m_movie);
::SetMovieTime(m_movie, &theTimeRecord);
if (::GetMoviesError() != noErr)
return false;
return true;
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::GetPosition
//
// Calls GetMovieTime
//---------------------------------------------------------------------------
wxLongLong wxQTMediaBackend::GetPosition()
{
return ::GetMovieTime(m_movie, NULL);
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::GetVolume
//
// Gets the volume through GetMovieVolume - which returns a 16 bit short -
//
// +--------+--------+
// + (1) + (2) +
// +--------+--------+
//
// (1) first 8 bits are value before decimal
// (2) second 8 bits are value after decimal
//
// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
// 1 (full gain and sound)
//---------------------------------------------------------------------------
double wxQTMediaBackend::GetVolume()
{
short sVolume = ::GetMovieVolume(m_movie);
if (sVolume & (128 << 8)) //negative - no sound
return 0.0;
return sVolume / 256.0;
}
//---------------------------------------------------------------------------
// wxQTMediaBackend::SetVolume
//
// Sets the volume through SetMovieVolume - which takes a 16 bit short -
//
// +--------+--------+
// + (1) + (2) +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -