QuickTime SDK的使用

来源:互联网 发布:网络计划图 编辑:程序博客网 时间:2024/04/29 21:32

第一节 QuickTime流式传输


  QT流是通过网络将视频从服务器发送到客户的传输方式。与文件传输不同,客户端边下载边播放,而不必等到下载完毕。服务器将视频内容分成包,通过网络发送出去;在接收端,包被重新组装,到来后就可播放。QT支持单播和组播。


接收、播放视频内容
  一般的,可通过打开视频文件、SDP文件与URL来打开流视频。通常调用NewMovieFromFile来打开视频文件,也可以调用NewMovieFromDataRef从URL打开视频文件。对实时流视频,URL必须使用RTSP协议。以RTSP URL打开视频的代码如下:

char url[] = /"rtsp://www.mycompany.com/mymovie.mov/"; 
  Handle urlDataRef;
  urlDataRef = NewHandle(strlen(url) + 1);
  if ( ( err = MemError()) != noErr) goto bail;
  BlockMoveData(url, *urlDataRef, strlen(url) + 1);
  err = NewMovieFromDataRef(&movieInfo->theMovie, newMovieActive,
  nil, urlDataRef, URLDataHandlerSubType);
  DisposeHandle(urlDataRef);

应用要可靠的播放实时流视频,必须遵从如下步骤:
·以高级视频工具箱或视频导入器打开视频。
·不要假定播放的视频轨结构反映了原始视频的轨结构。
·使用视频控制器播放视频,或使用新PrePrerollMovie函数在播放前设置流。
·显示视频控制器返回的状态信息。
·播放视频时准备处理播放错误
·准备动态改变视频特征,如高度、宽度等。
·不要认为视频立即开始播放。
·服务器流式传输视频内容
  服务器需要RTP服务软件与RTSP控制器应用传输视频内容,但不需要在服务器上安装QuickTime。如服务器仅充当组播中继,则不需要任何其它软件,以通常方式转发所请求的RTP流。
  服务器在QT流视频中使用提示轨将视频打包成RTP流。如服务器发送有提示视频的单播, QuickTime视频控制器将允许用户暂停、快进与快退,这将用到RTSP与服务器通讯。RTP 服务器不需要知道QuickTime 媒体类型或codecs。视频文件中提示轨为将      QuickTime媒体转化为RTP包提供了信息。每个提示轨包含建立特定轨媒体包头所需的数据,也提供了指向媒体数据的指针。RTP服务器要能够充分解析QuickTime视频文件以找到每个提示轨,然后再找到提示轨指向的轨和采样数据。提示轨包括一些必要的预计算值,使服务器创建RTP包更容易。提示轨减少了RTP服务器很多计算量,结果使RTP服务器发送数据更有效。

第二节 QuickTime流式传输服务器(QTSS)端模块

  QTSS是一个代码公开、基于标准的流式传输服务器,可运行在多种UNIX操作系统上,如Mac OS Server、Linux、 FreeBSD与Solaris。要使用QTSS编程接口,必须熟悉RTSP、RTP、RTCP与SDP协议。QTSS的核心功能是作为模块实现的,对模块的支持被设计进服务器的核心。可开发独立的模块,在服务器启动后载入;也可将代码与服务器一起编译。两种方法的模块是相同的,不同的是编译方式。
  每个QTSS 模块必须实现两个程序:主程序与分派程序。主程序是在QTSS初始化模块时调用,而服务器调用分派模块实现特定目的。
主程序模块:

QTSS_Error MyModule _Main(void*inPrivateArgs) 
{
return _stublibrary_main(inPrivateArgs,MyModuleDispatch );
}

分派程序模块:
  

void MyModuleDispatch (QTSS_Role inRole,QTSS_RoleParamPtr inParams); 


2.1 模块角色

  角色给模块提供了为执行某种类型处理而已定义好的状态。QTSS_Role定义每个角色的类型,并表示服务器的内部处理状态。一般的,服务器使用对象来交换模块间的信息。

2.2 QTSS对象

  QTSS对象为模块从服务器取得数据与向服务器提供数据提供了一条途径。QTSS定义了几个对象,每个对象都有一套预定义的属性。服务器定义了如下一些对象类型描述客户连接和流,RTSP头、连接和请求,全局服务器信息、服务器偏好和错误信息。

  QtssRTPStreamObjectType:
  单个RTP流相关属性,RTP流对象(RTPStreamObject )是这个对象类型的
  事例,调用QTSS_AddRTPStream 创建。

  qtssClientSessionObjectType :
  客户连接相关属性。

  QtssRTSPSessionObjectType:
  RTSP客户服务器连接相关属性,RTSP连接对象(RTSPSessionObject ) 是这个对象类型的一个事例。

  QtssRTSPRequestObjectType:
  单个RTSP请求相关属性,RTSP请求对象(RTSPRequestObject ) 是这个对象类型的一个事例。

  qtssRTSPHeaderObjectType :
  单个RTSP请求相关的所有RTSP请求头。

  QtssServerObjectType:
  全局服务器属性,如服务器统计。

  QtssPrefsObjectType:
  服务器内部偏好存储系统的属性。

  qtssTextMessageObjectType :
  包含其值将返回给客户的属性。

  取得属性值
  模块使用存储在对象中的属性与服务器交换信息,因此需要频繁的设置或取得属性值。有些属性是抢先安全的,可在任何时候调用QTSS_GetValuePtr 取得其值;另一些属性是非抢先安全的,必须调用QTSS_GetValue 取得其值。获得对象属性代码如下:

UInt32 MyGetNumCurrentConnections(QTSS_ServerObject inServerObject) 
{
//qtssRTPSvrCurConn is a UInt32,so provide a UInt32 for the result.
UInt32 theNumConnections =0;
//Pass in the size of the attribute value.
UInt32 theLength =sizeof(theNumConnections);
//Retreive the value.
QTSS_Error theErr =QTSS_GetValue(inServerObject,qtssRTPSvrCurConn,0,
&theNumConnections,&theLength);
//Check for errors.If the length is not what was expected,return 0.
if ((theErr !=QTSS_NoErr)||(theLength !=sizeof(theNumConnections))
return 0;
return theNumConnections;
}

QTSS_RTSPMethod MyGetRTSPRequestMethod(QTSS_RTSPRequestObject inRTSPRequestObject)
{
QTSS_RTSPMethod*theMethod =NULL;
UInt32 theLen =0;
QTSS_Error theErr =QTSS_GetValuePtr(inRTSPRequestObject,qtssRTSPReqMethod,0,
(void**)&theMethod,&theLen);
if ((theErr !=QTSS_NoErr)||(theLen !=sizeof(QTSS_RTSPMethod))
return -1;//Return a -1 if there is an error,which is not a valid
//QTSS_RTSPMethod index
else
return *theMethod;
}


2.3 QTSS服务

  QTSS服务是模块可访问的,可以是服务器提供的内建服务,也可以是另一模块提供的附加服务。例如,日志模块允许其它模块向错误日志中写信息。模块使用回调程序注册、激活服务,与以添加、查找对象属性类似的方式添加、查找服务。

  每个服务有一个名称,要激活服务,调用模块必须知道服务名称,并将名称解析成ID。服务有着自身特定的参数块格式,输出服务的模块应将输出的服务仔细归档。模块在注册角色中调用QTSS_AddService将服务添加到服务器内部数据库中,代码如下所示:

void MyAddService() 
{
QTSS_Error theErr =QTSS_AddService(/"MyService/",&MyServiceFunction);
}
MyServiceFunction函数对应于必须在同一模块中实现的函数名称,如:
QTSS_Error MyServiceFunction(MyServiceArgs*inArgs)
{
//Each service function must take a single void*argument
//Implement the service here.
//Return a QTSS_Error.
}

  为了使用服务,模块调用QTSS_IDForService 获得服务的ID,并将服务名称作为一个参数。模块使用服务ID调用QTSS_DoService (page 63) 使服务运行,代码如下:

void MyInvokeService() 
{
//Service functions take a single void*parameter that corresponds
//to a parameter block specific to the service.
MyServiceParamBlock theParamBlock;
//Initialize service-specific parameters in the parameter block.
theParamBlock.myArgument =xxx;
QTSS_ServiceID theServiceID =qtssIllegalServiceID; //Get the service ID by providing the name of the service.
QTSS_Error theErr =QTSS_IDForService(/'MyService /',&theServiceID);
if (theErr !=QTSS_NoErr)
return;//The service isn /'t available.
//Run the service.
theErr =QTSS_DoService(theServiceID,&theParamBlock);
}
第三节 QuickTime的Windows编程 

  QuickTime为Windows编程提供了完整的开发包,这里只简单介绍在Windows环境下编程的步骤并给出例程。 开发基本步骤为:

  1、在程序其始处初始化QuickTime媒体层(InitializeQTML) 与QuickTime(EnterMovies) 。
  2、建立QuickDraw图形端口与视频窗口(CreatePortAssociation)的联系。
  3、打开视频文件(OpenMovieFile) 并从中提取视频内容(NewMovieFromFile)。
  4.、创建屏幕上显示视频的控制器 (NewMovieController)。
  5. 在窗口过程中,将输入信息转化成QTML事件(WinEventToMacEvent) 并将其传输给视频控制器进行处理 (MCIsPlayerEvent)。
  6、当不再需要时,处理视频(DisposeMovie) 和视频控制器。
  7、当窗口被破坏时(DestroyPortAssociation),处理视频窗口图形端口。
  8. 在程序结束处,中断QuickTime (ExitMovies) 与QuickTime 媒体层(TerminateQTML)。

以下例程说明了程序框架与建立典型Windows应用程序的步骤:

#define IDM_OPEN 101 

// Global variables
char movieFile[255]; // Name of movie file
Movie theMovie; // Movie object
MovieController theMC; // Movie controller
//////////////////////////////////////////////////////////////////////
int CALLBACK WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
  InitializeQTML(0); // Initialize QTML
  EnterMovies(); // Initialize QuickTime

///////////////////////////////////////////////////////////////////////
// Main message loop
///////////////////////////////////////////////////////////////////////

  ExitMovies(); // Terminate QuickTime
  TerminateQTML(); // Terminate QTML
} /* end WinMain */
//////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  MSG winMsg;
  EventRecord qtmlEvent;
  int wmEvent, wmId;
// Fill in contents of MSG structure

  NativeEventToMacEvent (&winMsg, &qtmlEvent);// Convert message to a QTML event
  MCIsPlayerEvent (theMC, (const EventRecord *) &qtmlEvent);
// Pass event to movie controller
switch ( message )
{
  case WM_CREATE:
  CreatePortAssociation (hWnd, NULL); // Register window with QTML
  break;
  case WM_COMMAND:
  wmEvent = HIWORD(wParam); // Parse menu selection
  wmId = LOWORD(wParam);
  switch ( wmId )
{
  case IDM_OPEN:
  CloseMovie (); // Close previous movie, if any
  if ( GetFile (movieFile) ) // Get file name from user
  OpenMovie (hWnd, movieFile); // Open the movie
  break;

  default:
  return DefWindowProc (hWnd, message,
  wParam, lParam); } /* end switch ( wmId ) */
  break;
  case WM_CLOSE:
    DestroyPortAssociation (hWnd); // Unregister window with QTML
  break;

  default:
  return DefWindowProc (hWnd, message, wParam, lParam);
} /* end switch ( message ) */
  return 0;
} /* end WndProc */
/////////////////////////////////////////////////////////////////
BOOL GetFile (char *movieFile)
{
  OPENFILENAME ofn;
// Fill in contents of OPENFILENAME structure

  if ( GetOpenFileName(&ofn) ) // Let user select file
    return TRUE;
  else
  return FALSE;
} /* end GetFile */
////////////////////////////////////////////////////////////////
void OpenMovie (HWND hwnd, char fileName[255])
{
  short theFile = 0;
  FSSpec sfFile;
  char fullPath[255];
  SetGWorld ( (CGrafPtr)GetNativeWindowPort( hwnd ), nil); // Set graphics port
  strcpy (fullPath, fileName); // Copy full pathname
  c2pstr (fullPath); // Convert to Pascal string
  FSMakeFSSpec (0, 0L, fullPath, &sfFile); // Make file-system
// specification record
  OpenMovieFile (&sfFile, &theFile, fsRdPerm); // Open movie file
  NewMovieFromFile (&theMovie, theFile, nil, // Get movie from file
  nil, newMovieActive, nil);
  CloseMovieFile (theFile); // Close movie file
  theMC = NewMovieController (theMovie, ... ); // Make movie controller

} /* end OpenMovie */
////////////////////////////////////////////////////////////////
void CloseMovie (void)
{
  if ( theMC ) // Destroy movie controller, if any
  DisposeMovieController (theMC);
  if ( theMovie ) // Destroy movie object, if any
  DisposeMovie (theMovie);
} /* end CloseMovie */