1. 基本概念
QuickTime 使用两种基本结构存储信息:标准原子(classic atoms) 和 QT原子(QT atoms),标准原子是简单原子,QT原子是原子容器原子,允许建立复杂的分层结构。QuickTime atom containers 提供在QuickTime 中存储信息的基本结构,它是QT atoms 的树型分层结构。
原子(Atoms)
1、QuickTime 文件的基本数据单元是原子(atom),每个原子包含数据及数据的大小和数据类型信息。原子包含报头和原子数据,报头允许小型尺度或扩展尺度的数据,多数原子使用小型尺度(32位),通常只有媒体数据原子需要64位大小。
2、QuickTime 原子容器(Atom Containers)
QuickTime atom container是QuickTime文件中存储信息的基本结构,一个原子容器是QT atom的属性分层结构。每个 QT atom 包含数据或其它原子。如果一个原子包含其它原子,它就是父原子(parent atom),被包含的原子叫子原子(child atoms)。每个父原子的子原子由atom type 和atom ID惟一地标识。 包含数据的 QT atom 叫页原子(leaf atom).
3、QuickTime File结构
QuickTime文件简单地说就是一群原子的集合, 对原子的次序没有规定。
文件系统支持文件扩展名,QuickTime文件扩展名通常是 .mov 。在 Macintosh 平台上,QuickTime文件类型是MooV 。在因特网上, QuickTime 文件由mime 型 "video/quicktime" 来提供服务。
4、QuickTime movie
QuickTime movie atoms 的原子类型为 'moov' 。它是其它类型的容器,依层类推,它包含轨道原子( track atoms),而轨道原子又包含媒体原子(media atoms),最底层是页原子(leaf atoms),包含实际数据。
Movie有一个或多个轨道组成,每个轨道都独立于其它轨道,轨道提供一种强大、灵活的结构,使用它可以精确地控制产生复杂的交互电影。每个轨道都代表了一个独特的随时间变化的功能或方面。一个单个movie 可以有许多不同的轨道类型,包括video, audio, text, sprite, Flash, HREF, hinting, QuickTime VR和 chapter divisions。
例:Movie track-包含整个movie的版权、注释及其它概要信息
Video track-数字化视频、着色的3D动画或其他编辑图像的序列,和可选特殊效果。
Text track--输入到QuickTime中的标题、 片头字幕等字符信息。
Hint track-包含允许流服务器通过实时流方式传输媒体轨道的信息。
movie包含三个轨道:video、 music、text,轨道中显示的资料包含在媒体结构中。QuickTime movies 在时间轴上组织媒体,它把movies和媒体数据结构作为普通的时间存在锚在时间坐标系上。
第一节 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 indexelsereturn *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)。