使用Quicktime 實現視頻直播(Live video using Quicktime) (轉)

Quicktime是一個跨瀏覽器的播放插件,能夠實現RTSP視頻直播,可用於電視直播或視頻監控平臺。本文主要講了關於播放器如何實現直播、事件響應、播放器全屏、動態修改播放路徑等問題。

   須要準備的軟件:quicktime安裝文件、RTSP模擬器(或VLC播放器)。
   如下是個人實現方式:javascript

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 直播路徑(便於動態切換播放路徑); html

4. kioskmode="true" 隱藏播放器右鍵菜單。java

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 };

 

代碼說明: ios

1. 上述代碼並不完整,須要根據實際狀況做相應調整;
2. 基本使用方式:Player.regQuickTimeEvents().setPlayerParameters(url);
3. Quicktime在播放RTSP時會有3-5秒延遲,這是緩存所至,但控件沒有提供相應清空緩存方法,只有經過SetRate()來設置播放速率來清除緩存。web

播放截圖:

瀏覽器

可能出現的問題:
1. 在顯示/隱藏播放控件、全屏/恢復時會致使從新加載視頻;緩存

 

3. 相關資源

1.  JavaScript Scripting Guide for QuickTime
2.  QuickTime: Embed Tag Attributes
3. QuickTime fullscreen ( 很帥的東西) app

 

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
相關文章
相關標籤/搜索