利用ATL实现QuickTime多媒体文件播放 (转)

利用ATL实现QuickTime多媒体文件播放 (转)[@more@]

 XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" />

利用ATL实现QuickTime

媒体文件播放

 

摘要  本文主要介绍了windows平台上Visual C++ 6利用ATL库和QuickTime SDK开发播放QuickTime多媒体软件。为从事多媒体播放开发工作者提供借鉴和参考。

关键词  多媒体 播放 QuickTime ATL

 

1 前言

在当今多媒体播放软件主要有Windows Media playerreal player和QuickTime。 Apple公司的QuickTime于1991年登台亮相,是Apple公司面向专业视频编辑、web网站创建和CD-ROM内容制作领域开发的多媒体技术平台,QuickTime支持几乎所有主流的个人计算机平台,是数字媒体领域事实上的工业标准,是创建3D动画、实时效果、虚拟现实、A/V和其他数字流媒体的重要基础。

由于众多企业有对QuickTime player应用的需求,在国内外相关资料中有用Windows SDK或MFC的相关应用,本文试用小巧的ATL库和QuickTime SDK开发定制QuickTime 多媒体播放软件做了分析。

 

2 QuickTime Windows程序的开发概述

2.1开发前的准备

登陆Apple官方网站下载QuickTime SDK和了解有关技术资料。

由于QuickTime原先是为Mac OS设计,所以它里面的许多概念和函数调用都是面向Mac。

表1 Windows and QTML 术语比较

Windows 术语

QTML 对应术语

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

对于一个原来是Windows程序员必须对于一些QuickTime概念有些最基本的了解才能比较快的掌握典型QuickTime Windows程序的开发。

2.2开发基本步骤

开发一个简单的QuickTime Windows程序必须采取下面基本步骤加入到Windows应用中。

2.2.1在程序的开头初始化QuickTime媒体层(InitializQTML)和QuickTime(EnterMovies)。

2.2.2和电影窗口建立图形端口的关联(CreatePortAssociation)。

2.2.3打开电影(OpenMovieFile)和得到电影的句柄(NewMovieFromFile)。

2.2.4创建在屏幕上显示电影图像的控件(NewMovieController)。

2.2.5在Windows处理函数中,将接收的Windows消息转换为QTML事件(WinEventToMacEvent)并将它们传到电影控件处理(MCIsPlayerEvent)。

2.2.6如果不在用到,释放电影句柄(DisposeMovie)和电影控件(DisPoseMovieController)。

2.2.7当销毁窗口时,破坏电影图形端口的关联(DestroyPortAssociation)。

 

3 在ATL上实现播放

3.1用ATL创建Windows窗口

  以CWindowImpl为基类,编写自己的窗口类CQTVideoWnd。并且定义宏来接收窗口消息。

#define MY_QT_MSG_HANDLE(func) 

  { 

  BOOL bHandled = TRUE; 

    lResult;

    func(uMsg,wParam,lParam,bHandled); 

    if(bHandled) 

    return TRUE; 

  }

 

class CQTVideoWnd:

  public CWindowImpl

{

  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为笔者调用QuickTime api的辅助类,后面将介绍。

NewProc成员函数根据接收不同的窗口消息分别调用不同的成员函数处理。

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等成员函数将根据2.2,分别调用辅助类CQuickTime处理。如

LRESULT CQTVideoWnd::OnCreate(UINT uMsg, WPARAM wParam , LPARAM lParam, BOOL& bHandled)

{

  m_QT.OnMovieWindowCreate(m_hWnd,NULL);

  return 0;

}

 

3.2 CQuickTime

  CQuickTime为调用QuickTime API函数的辅助类。

3.2.1初始化和退出应用

InitializeQT和TeRminate分别为初始化QuickTime媒体层和退出QuickTime媒体层。它们可以在程序的开始和结束。我们在CQTVideoWnd的构造函数和析构函数中调用它们。

  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的错误代码,我们可以在初始化完后调用SetMoviesErrorProc函数,但是假如一个应用中有多个QuickTime的电影对象。我们将不能区分错误来自哪个对象。

 

void CQuickTime::Terminate()

{

  // Clean up

  ExitMovies();

  TerminateQTML();

  DebugInfo("CQuickTime::Terminate this = %p,m_pQTEventSink = %p",this,m_pQTEventSink);

}

 

3.2.2得到电影的句柄

如果是本地文件调用OpenLocalMovie,得到句柄后保存在成员变量里m_Movie。该函数打开电影后创建Movie Controller。Apple公司推荐一般用Movie Controller来播放电影。

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文件,调用OpenURLMovie,该函数跟OpenLocalMovie区别主要在于不用NewMovieFromFile而用NewMovieFromDataRef来得到句柄。

 

  一般电影在创建完Movie Controller后最好调用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关闭电影

  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建立和取消电影窗口关联

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来控制播放,这样可以得到播放的状态,当然也可以调用StartMovie、StopMovie等api函数。例如,

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 综述

  通过上面较为详细的讨论对于建立一个QuickTime的窗口,打开和控制QuickTime电影文件的播放的基本概念和基本过程,我认为QuickTime Player在Windows的平台的应用将更为宽广。同时为Apple公司在多媒体播放上的努力而致敬。


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-962084/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10752043/viewspace-962084/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值