使用Quicktime 实现视频直播(Live video using Quicktime) (转)

Quicktime是一个跨浏览器的播放插件,可以实现RTSP视频直播,可用于电视直播或视频监控平台。本文主要讲了关于播放器如何实现直播、事件响应、播放器全屏、动态修改播放路径等问题。

   需要准备的软件:quicktime安装文件、RTSP模拟器(或VLC播放器)。
   以下是我的实现方式:

1. 播放器HTML静态代码

 

01 <div id="player">
02   <!--[if IE]><object id="qt_event_source" classid="clsid:CB927D12-4FF7-4a9e-A169-56E4B8A75598" style="display:none;"></object><![endif]-->
03   <object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" width="640" height="480" codebase="http://www.apple.com/qtactivex/qtplugin.cab#version=7,6,9,0" standby="控件加载中..." name="QT_OBJ" id="QT_OBJ" style="behavior:url(#qt_event_source);overflow:hidden;">
04     <param name="src" value="ress/preview.mov"/>
05     <!-- <param name="qtsrc" value="rtsp://"/> -->
06     <param name="enablejavascript" value="true"/>
07     <param name="postdomevents" value="true"/>
08     <param name="controller" value="false"/>
09     <param name="scale" value="tofit"/>
10     <param name="kioskmode" value="true"/>
11     <param name="bgcolor" value="#000000"/>
12     <param name="qtsrcdontusebrowser" value="true"/>
13     <param name="cache" value="false"/>
14     <!-- qtsrc=""  -->
15     <embed src="ress/preview.mov" width="640" height="480" pluginspage="http://www.apple.com/quicktime/download/" name="QT_EMB" id="QT_EMB" enablejavascript="true" postdomevents="true" controller="false" scale="tofit" kioskmode="true" bgcolor="#000000" qtsrcdontusebrowser="true" cache="false" style="overflow:hidden;"></embed>
16   </object>
17 </div>

 

代码说明:
1. object 用于IE浏览器,而 embed 用于非IE浏览器;
2. qt_event_source 对象是为了给IE浏览器注册事件,通过style( style="behavior:url(#qt_event_source);overflow:hidden;")绑定行为;
3. src="ress/preview.mov" 用于在页面加载后初始化控件,因为在上述代码中没有初始化 qtsrc 直播路径(便于动态切换播放路径);

4. kioskmode="true" 隐藏播放器右键菜单。

2. Javascript代码实现(部分)

 

001 var Player = {
002     /**
003      * 播放器对象
004      */
005     object : null,
006     stream : {
007         /**
008          * 视频初始化原始宽度
009          */
010         width : 640,
011         /**
012          * 视频初始化原始高度
013          */
014         height : 480
015     },
016     /**
017      * 设置播放路径
018      
019      * @param url
020      */
021     setPlayerParameters : function(url) {
022         try {
023             if (Player.object) {
024                 var qt = Player.object;
025                 if (!$.browser.msie && !qt.SetURL) {
026                     return this;
027                 }
028                 qt.SetURL(url);
029                 qt.SetControllerVisible(false);
030                 qt.SetKioskMode(true);
031                 qt.SetVolume(100);
032                 qt.SetBgColor('#ffffff');
033             }
034         } catch (e) {
035             alert('resetPlayerParameters - ' + e.toString());
036         }
037         return this;
038     },
039     /**
040      * 设置播放速率
041   
042      * 实现实时播放
043      */
044     setRate : function() {
045         if (Player.object)
046             Player.object.SetRate(10);
047     },
048     /**
049      * 初始化播放路径,如:rtsp://192.168.0.100:554/3
050      
051      * @param stream
052      * @returns
053      */
054     initGUrl : function(stream) {
055         var host = location.hostname;
056         var port = '';// ':'+554;
057         var url = [ 'rtsp://', host, port, '/', stream ].join('');
058         return url;
059     },
060     /**
061      * 注册事件,为IE浏览器注册时要多加个'on'在事件前面
062      */
063     regQuickTimeEvents : function() {
064         var listerners = Player.listerners;
065         if (document.addEventListener) {
066             var obj = document.QT_EMB;
067             if (obj) {
068                 Player.object = obj;
069                 obj.addEventListener("qt_timechanged",
070                         listerners._qt_timechanged_listerner);
071                 obj.addEventListener("qt_stalled",
072                         listerners._qt_stalled_listerner);
073                 obj
074                         .addEventListener("qt_error",
075                                 listerners._qt_error_listerner);
076             }
077         } else {
078             var obj = document.QT_OBJ;
079             if (obj) {
080                 Player.object = obj;
081                 obj.attachEvent("onqt_timechanged",
082                         listerners._qt_timechanged_listerner);
083                 obj.attachEvent("onqt_stalled",
084                         listerners._qt_stalled_listerner);
085                 obj.attachEvent("onqt_error", listerners._qt_error_listerner);
086             }
087         }
088         return this;
089     },
090     listerners : {
091         _qt_timechanged_listerner : function() {
092             if (Player.object) {
093                 var qt = Player.object;
094                 if (!$.browser.msie && !qt.SetRate) {
095                     return false;
096                 }
097                 // 通过设置播放率快速播放来消耗缓存达到实时播放
098                 qt.SetRate(10);
099                 qt.SetBgColor('#000000');
100                 Player.getStreamWidthHeight(qt, true);
101                 Player.adaptation();
102             }
103         },
104         _qt_stalled_listerner : function() {
105             alert('连接已终断,正在尝试重新连接...');
106         },
107         _qt_error_listerner : function() {
108             alert('播放时发生错误,请刷新页面或重新登录来解决此问题!');
109         }
110     },
111     /**
112      * 将视频填充到当前播放器大小一致,并维持原始长宽比
113   
114      * SetRectangle参数中每个值都必须是整形,不能有小数 在计算时可能出现高度或宽度相差一个像素
115      */
116     adaptation : function() {
117         try {
118             if (!Player.object)
119                 return false;
120             var object = Player.object;
121             var qt = $(object);
122             var w_box = qt.width();
123             var h_box = qt.height();
124             var wh = Player.getStreamWidthHeight(object, false);
125             if (!wh)
126                 return false;
127             var w_per = wh.width || 640;
128             var h_per = wh.height || 480;
129             var rect = [ 0, 0, 640, 480 ];
130             var dw = w_per / w_box;
131             var dh = h_per / h_box;
132             if (dw == dh) {
133                 rect[2] = parseInt(w_box);
134                 rect[3] = parseInt(h_box);
135             } else if (dw > dh) {
136                 var h_per_new = h_per / dw;
137                 var offset = (h_box - h_per_new) / 2;
138                 rect[1] = parseInt(offset);
139                 rect[2] = parseInt(w_box);
140                 rect[3] = parseInt(h_per_new + offset);
141             } else {
142                 var w_per_new = w_per / dh;
143                 var offset = (w_box - w_per_new) / 2;
144                 rect[0] = parseInt(offset);
145                 rect[2] = parseInt(w_per_new + offset);
146                 rect[3] = parseInt(h_box);
147             }
148             if (!$.browser.msie && !object.SetRectangle) {
149                 return false;
150             }
151             object.SetRectangle(rect.join(','));
152         } catch (e) {
153             // TODO
154         }
155     },
156     /**
157      * 获取播放器对象的高度和宽度
158      
159      * @param playerObj
160      * @param isInit
161      *            是否将 Player.stream中的参数重写
162      * @returns
163      */
164     getStreamWidthHeight : function(playerObj, isFlash) {
165         try {
166             if (!playerObj)
167                 return false;
168             if (!$.browser.msie && !playerObj.GetRectangle) {
169                 return false;
170             }
171             var rect = playerObj.GetRectangle().split(',');
172             var width = parseInt(rect[2]) - parseInt(rect[0]);
173             var height = parseInt(rect[3]) - parseInt(rect[1]);
174             if (isFlash) {
175                 this.stream.width = width;
176                 this.stream.height = height;
177             }
178             return {
179                 width : width || this.stream.width,
180                 height : height || this.stream.height
181             };
182         } catch (e) {
183             // TODO
184         }
185     },
186     /**
187      * @param{Object} el 被放大对象
188      */
189     requestFullScreen : function(el) {
190         var agent = '';// TODO 获取浏览器名称
191         var obj = $(el);
192           
193         // 支持大多数浏览器全屏功能,除了FCK IE!
194         var requestMethod = el.requestFullScreen || el.webkitRequestFullScreen
195                 || el.mozRequestFullScreen || el.msRequestFullScreen;
196           
197         if (requestMethod) {
198             requestMethod.call(el);
199             var stream = Player.stream;
200             el.SetRectangle([ 0, 0, stream.width, stream.height ].join(','));
201             obj.width(window.screen.width);
202             obj.height(window.screen.height);
203   
204             // 根据不同浏览器作相应调整
205             if (agent.name == 'safari') {
206                 obj.offset({
207                     top : 0,
208                     left : 0
209                 });
210             }
211         } else {
212             // 如果浏览器没有全屏接口就放大显示区
213             // TODO
214         }
215     }
216 };

 

代码说明:

1. 上述代码并不完整,需要根据实际情况作相应调整;
2. 基本使用方式:Player.regQuickTimeEvents().setPlayerParameters(url);
3. Quicktime在播放RTSP时会有3-5秒延迟,这是缓存所至,但控件没有提供相应清空缓存方法,只有通过SetRate()来设置播放速率来清除缓存。

播放截图:

可能出现的问题:
1. 在显示/隐藏播放控件、全屏/恢复时会导致重新加载视频;

 

3. 相关资源

1.  JavaScript Scripting Guide for QuickTime
2.  QuickTime: Embed Tag Attributes
3. QuickTime fullscreen ( 很帅的东西)

 

4. Quicktime插件函数列表

 

AddCuePoint(time, fcnName, pause) void  
Clear() void  
GetAutoPlay() Number  
GetBgColor() String 获取播放器背景颜色
GetChapterCount() Number  
GetChapterName(chapterNum) String  
GetComponentVersion(type, subType, manufacturer) String  
GetControllerVisible() Number  
GetCurrentChapterIndex() Number  
GetDuration() Number  
GetEndTime() Number  
GetFieldOfView() Number  
GetHotspotTarget(hotspotID) String  
GetHotspotUrl(hotspotID) String  
GetHREF() Number  
GetIsLooping() Number  
GetIsQuickTimeRegistered() Number  
GetIsVRMovie() Number  
GetKioskMode() Number  
GetLanguage() String  
GetLoopIsPalindrome() Number  
GetMatrix() String  
GetMaxBytesLoaded() Number  
GetMaxTimeLoaded() Number  
GetMIMEType() String  
GetMovieID() Number  
GetMovieName() String  
GetMovieSize() Number  
GetMute() Number  
GetNodeCount() Number  
GetNodeID() Number  
GetPanAngle() Number  
GetPlayEveryFrame() Number  
GetPluginStatus() String  
GetPluginVersion() String  
GetQTNEXTUrl(index) String  
GetQuickTimeConnectionSpeed() Number  
GetQuickTimeLanguage() String  
GetQuickTimeVersion() String  
GetRate() Number  
GetRectangle() String  
GetResetPropertiesOnReload() Number  
GetSpriteTrackVariable(trackIndex, variableIndex) String  
GetStartTime() Number  
GetTarget() String  
GetTiltAngle() Number  
GetTime() Number  
GetTimeScale() Number  
GetTrackCount() Number  
GetTrackEnabled(index) Number  
GetTrackName(index) String  
GetTrackType(index) String  
GetURL() String  
GetUserData(type) String  
GetVolume() Number  
GoPreviousNode() void  
GoToChapter(chapterName) void  
Hide() void  
Play() void  
RemoveCuePoint(time, fcnName) void  
Rewind() void  
SendSpriteEvent(trackIndex, spriteID, messageID) void  
SetAutoPlay(autoPlay) void  
SetBgColor(color) void  
SetControllerVisible(visible) void  
SetCurrentChapterIndex(chapterIndex) void  
SetEndTime(time) void  
SetFieldOfView(fov) void  
SetHotspotTarget(hotspotID, target) void  
SetHotspotUrl(hotspotID, url) void  
SetHREF(url) void  
SetIsLooping(loop) void  
SetKioskMode(kioskMode) void  
SetLanguage(language) void  
SetLoopIsPalindrome(loop) void  
SetMatrix(matrix) void  
SetMovieID(movieID) void  
SetMovieName(movieName) void  
SetMute(mute) void  
SetNodeID(id) void  
SetPanAngle(angle) void  
SetPlayEveryFrame(playAll) void  
SetQTNEXTUrl(index, url) void  
SetRate(rate) void 设置播放速度。可设置较大速度以此作清除缓存的辅助工具。
SetRectangle(rect) void 设置显示画面大小和位置。
SetResetPropertiesOnReload(reset) void  
SetSpriteTrackVariable(trackIndex, variableIndex, value) void  
SetStartTime(time) void  
SetTarget(target) void  
SetTiltAngle(angle) void  
SetTime(time) void  
SetTrackEnabled(index, enabled) void  
SetURL(url) void  
SetVolume(volume) void  
Show() void  
ShowDefaultView() void  
Step(count) void  
Stop() void  
posted @ 2014-03-28 15:34  FLANKE  阅读(3484)  评论(0编辑  收藏  举报