使用ATL完成QuickTime多媒體文件播放
發(fā)表時(shí)間:2024-02-12 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]摘要 本文主要介紹了Windows平臺(tái)上Visual C++ 6利用ATL庫(kù)和QuickTime SDK開(kāi)發(fā)播放QuickTime多媒體軟件。為從事多媒體播放開(kāi)發(fā)工作者提供借鑒和參考。關(guān)鍵詞 多媒體 播放 QuickTime ATL 1 前言在當(dāng)今多媒體播放軟件主要有Windows media...
摘要 本文主要介紹了Windows平臺(tái)上Visual C++ 6利用ATL庫(kù)和QuickTime SDK開(kāi)發(fā)播放QuickTime多媒體軟件。為從事多媒體播放開(kāi)發(fā)工作者提供借鑒和參考。
關(guān)鍵詞 多媒體 播放 QuickTime ATL
1 前言
在當(dāng)今多媒體播放軟件主要有Windows media player、Real player和QuickTime。 Apple公司的QuickTime于1991年登臺(tái)亮相,是Apple公司面向?qū)I(yè)視頻編輯、Web網(wǎng)站創(chuàng)建和CD-ROM內(nèi)容制作領(lǐng)域開(kāi)發(fā)的多媒體技術(shù)平臺(tái),QuickTime支持幾乎所有主流的個(gè)人計(jì)算機(jī)平臺(tái),是數(shù)字媒體領(lǐng)域事實(shí)上的工業(yè)標(biāo)準(zhǔn),是創(chuàng)建3D動(dòng)畫(huà)、實(shí)時(shí)效果、虛擬現(xiàn)實(shí)、A/V和其他數(shù)字流媒體的重要基礎(chǔ)。
由于眾多企業(yè)有對(duì)QuickTime player應(yīng)用的需求,在國(guó)內(nèi)外相關(guān)資料中有用Windows SDK或MFC的相關(guān)應(yīng)用,本文試用小巧的ATL庫(kù)和QuickTime SDK開(kāi)發(fā)定制QuickTime 多媒體播放軟件做了分析。
2 QuickTime Windows程序的開(kāi)發(fā)概述
2.1開(kāi)發(fā)前的準(zhǔn)備
登陸Apple官方網(wǎng)站下載QuickTime SDK和了解有關(guān)技術(shù)資料。
由于QuickTime原先是為Mac OS設(shè)計(jì),所以它里面的許多概念和函數(shù)的調(diào)用都是面向Mac。
表1 Windows and QTML 術(shù)語(yǔ)比較
Windows 術(shù)語(yǔ)
QTML 對(duì)應(yīng)術(shù)語(yǔ)
Message ( MSG )
Event ( EventRecord )
Graphics Device Interface (GDI)
QuickDraw
Device context ( DC )
Graphics port ( CGrafPort )
Window handle ( HWND )
Window pointer ( CWindowPtr )
Common Dialog Box Library
Standard File Package
對(duì)于一個(gè)原來(lái)是Windows程序員必須對(duì)于一些QuickTime概念有些最基本的了解才能比較快的掌握典型QuickTime Windows程序的開(kāi)發(fā)。
2.2開(kāi)發(fā)基本步驟
開(kāi)發(fā)一個(gè)簡(jiǎn)單的QuickTime Windows程序必須采取下面基本步驟加入到Windows應(yīng)用中。
2.2.1在程序的開(kāi)頭初始化QuickTime媒體層(InitializQTML)和QuickTime(EnterMovies)。
2.2.2和電影窗口建立圖形端口的關(guān)聯(lián)(CreatePortAssociation)。
2.2.3打開(kāi)電影(OpenMovieFile)和得到電影的句柄(NewMovieFromFile)。
2.2.4創(chuàng)建在屏幕上顯示電影圖像的控件(NewMovieController)。
2.2.5在Windows處理函數(shù)中,將接收的Windows消息轉(zhuǎn)換為QTML事件(WinEventToMacEvent)并將它們傳到電影控件處理(MCIsPlayerEvent)。
2.2.6如果不在用到,釋放電影句柄(DisposeMovie)和電影控件(DisPoseMovieController)。
2.2.7當(dāng)銷(xiāo)毀窗口時(shí),破壞電影圖形端口的關(guān)聯(lián)(DestroyPortAssociation)。
3 在ATL上實(shí)現(xiàn)播放
3.1用ATL創(chuàng)建Windows窗口
以CWindowImpl為基類(lèi),編寫(xiě)自己的窗口類(lèi)CQTVideoWnd。并且定義宏來(lái)接收窗口消息。
#define MY_QT_MSG_HANDLE(func) \
{ \
BOOL bHandled = TRUE; \
lResult; \
func(uMsg,wParam,lParam,bHandled); \
if(bHandled) \
return TRUE; \
}
class CQTVideoWnd:
public CWindowImpl<CVideoPlayerQT>
{
public:
CQTVideoWnd(HWND hParent, RECT& rc, IVideoPlayerNotifySink* pVPSink);
virtual ~ CQTVideoWnd();
public:
BEGIN_MSG_MAP(CVideoPlayerQT)
MY_QT_MSG_HANDLE (NewProc)
END_MSG_MAP()
protected:
LRESULT NewProc(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
……
CQuickTime m_QT;
……
}
CQuickTime為筆者調(diào)用QuickTime API的輔助類(lèi),后面將介紹。
NewProc成員函數(shù)根據(jù)接收不同的窗口消息分別調(diào)用不同的成員函數(shù)處理。
LRESULT CQTVideoWnd::NewProc(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if(uMsg == WM_ERASEBKGND)
{
bHandled = FALSE;
LRESULT theResult = DefWindowProc(uMsg, wParam, lParam);
m_QT.ProcessMovieEvent (m_hWnd, uMsg, wParam, lParam);
return theResult;
}
else
{
m_QT.ProcessMovieEvent (m_hWnd, uMsg, wParam, lParam);
switch(uMsg)
{
case WM_CREATE:
OnCreate(uMsg, wParam, lParam,bHandled);
break;
case WM_PAINT:
OnPaint(uMsg, wParam, lParam,bHandled);
break;
case WM_DESTROY:
OnDestroy(uMsg, wParam, lParam,bHandled);
break;
default:
bHandled = FALSE;
break;
}
}
return 0;
}
其中OnCreate、OnPaint、OnDestroy等成員函數(shù)將根據(jù)2.2,分別調(diào)用輔助類(lèi)CQuickTime處理。如
LRESULT CQTVideoWnd::OnCreate(UINT uMsg, WPARAM wParam , LPARAM lParam, BOOL& bHandled)
{
m_QT.OnMovieWindowCreate(m_hWnd,NULL);
return 0;
}
3.2 CQuickTime
CQuickTime為調(diào)用QuickTime API函數(shù)的輔助類(lèi)。
3.2.1初始化和退出應(yīng)用
InitializeQT和Terminate分別為初始化QuickTime媒體層和退出QuickTime媒體層。它們可以在程序的開(kāi)始和結(jié)束。我們?cè)贑QTVideoWnd的構(gòu)造函數(shù)和析構(gòu)函數(shù)中調(diào)用它們。
BOOL CQuickTime::InitializeQT(IQTEventSink* pQTEventSink /*= NULL*/)
{
……
OSErr Err = noErr;
// Initialize QuickTime Media Layer
Err = InitializeQTML(0);
// Initialize QuickTime
if(Err == noErr)
{
Err = EnterMovies();
}
else
{
Err = QT_NOPLAYER;
}
if(Err == noErr)
{
//Because we can not distinguish the error from which object
//So we marked SetMoviesErrorProc
// SetMoviesErrorProc(MoviesErrorProc,(long)this);
}
else
Err = QT_INITIAL_ERR;
……
return Err == noErr ? TRUE : FALSE;
}
如果要得到QuickTime的錯(cuò)誤代碼,我們可以在初始化完后調(diào)用SetMoviesErrorProc函數(shù),但是假如一個(gè)應(yīng)用中有多個(gè)QuickTime的電影對(duì)象。我們將不能區(qū)分錯(cuò)誤來(lái)自哪個(gè)對(duì)象。
void CQuickTime::Terminate()
{
// Clean up
ExitMovies();
TerminateQTML();
DebugInfo("CQuickTime::Terminate this = %p,m_pQTEventSink = %p",this,m_pQTEventSink);
}
3.2.2得到電影的句柄
如果是本地文件調(diào)用OpenLocalMovie,得到句柄后保存在成員變量里m_Movie。該函數(shù)打開(kāi)電影后創(chuàng)建Movie Controller。Apple公司推薦一般用Movie Controller來(lái)播放電影。
BOOL CQuickTime::OpenLocalMovie(LPCSTR fullPath)
{
_ASSERTE(fullPath && m_hViewWnd);
if(!fullPath !m_hViewWnd)
return FALSE;
VIDEO_STATUE oldState = m_enState;
if ( strlen ((char*)fullPath ) != 0)
{
OSErr err;
short nTheFile = 0;
long lControllerFlags = 0L;
FSSpec sfFile;
short nMovieResFile;
short nMovieResId;
char theFullPath[255];
// Close any previously opened movie
CloseMovie();
// make a copy of our full path name
strcpy ( (char *)theFullPath, (const char *) fullPath );
// convert theFullPath to pstring
c2pstr( (char*)theFullPath );
// Make a FSSpec with a pascal string filename
FSMakeFSSpec(0,0L,(unsigned char*)theFullPath, &sfFile);
// Set the port
SetGWorld((CGrafPtr)GetHWNDPort(m_hViewWnd), nil);
// Open the movie file
err = OpenMovieFile(&sfFile, &nMovieResFile, fsRdPerm);
if (err == noErr)
{
// Get the Movie from the file
nMovieResId = 0;
err = NewMovieFromFile(&m_Movie,nMovieResFile,
&nMovieResId,
nil,
newMovieActive, /* flags */
nil);
// Close the movie file
CloseMovieFile(nMovieResFile);
if (err == noErr)
{
SetMovieTimeScale(m_Movie,1000);
m_bBegineDownload = TRUE;
// Create the movie controller
CreateNewMovieController(m_hViewWnd,m_Movie,&m_MC);
p2cstr((unsigned char*)theFullPath);
if(m_MC)
{
return TRUE;
}
}
}
}
CloseMovie();
return FALSE;
}
如果是URL文件,調(diào)用OpenURLMovie,該函數(shù)跟OpenLocalMovie區(qū)別主要在于不用NewMovieFromFile而用NewMovieFromDataRef來(lái)得到句柄。
一般電影在創(chuàng)建完Movie Controller后最好調(diào)用PrePrerollMovie。
void CQuickTime::CreateNewMovieController(HWND hwnd, Movie theMovie, MovieController *theMC)
{
……
PrePrerollMovie(theMovie, GetMovieTime(theMovie, NULL), GetMoviePreferredRate(theMovie), NewMoviePrePrerollCompleteProc(QTPrePrerollCompleteProc), (void *)m_hViewWnd);
}
3.2.3關(guān)閉電影
void CQuickTime::CloseMovie(void)
{
if (m_MC)
{
DisposeMovieController(m_MC);
}
if (m_Movie)
{
DisposeMovie(m_Movie);
}
m_Movie = NULL;
m_MC = NULL;
}
3.2.4建立和取消電影窗口關(guān)聯(lián)
int CQuickTime::OnMovieWindowCreate(HWND hWnd, CREATESTRUCT *lpCreateStruct)
{
if ( hWnd != NULL)
{
m_hViewWnd = hWnd; // the view's hwnd
// Create GrafPort <-> HWND association
CreatePortAssociation(m_hViewWnd, NULL, kQTMLHandlePortEvents);
}
return 0;
}
void CQuickTime::OnMovieWindowDestroy()
{
if(m_Movie)
AbortPrePrerollMovie(m_Movie,noErr);
CGrafPtr windowPort = NULL;
// close any movies before destroying PortAssocation
CloseMovie();
// Destroy the view's GrafPort <-> HWND association
if (m_hViewWnd)
windowPort = (CGrafPtr)GetHWNDPort(m_hViewWnd);
if (windowPort)
DestroyPortAssociation(windowPort);
}
3.2.5控制電影播放
筆者用控制MCDoAction來(lái)控制播放,這樣可以得到播放的狀態(tài),當(dāng)然也可以調(diào)用StartMovie、StopMovie等api函數(shù)。例如,
void CQuickTime::Play()
{
if(m_Movie)
{
MCDoAction (m_MC, mcActionPlay, (void *)GetMoviePreferredRate(m_Movie));
long controllerFlags;
MCGetControllerInfo(m_MC,&controllerFlags);
if((controllerFlags&mcInfoIsPlaying))
//Now this is playing state.
}
}
4 綜述
通過(guò)上面較為詳細(xì)的討論對(duì)于建立一個(gè)QuickTime的窗口,打開(kāi)和控制QuickTime電影文件的播放的基本概念和基本過(guò)程,我認(rèn)為QuickTime Player在Windows的平臺(tái)的應(yīng)用將更為寬廣。同時(shí)為Apple公司在多媒體播放上的努力而致敬。