zoukankan      html  css  js  c++  java
  • 使用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  
  • 相关阅读:
    tyflow birth节点
    tyflow雨滴在物体上滑落测试
    【bootstrap】如何在js中动态修改提示冒泡(Tooltips)的显示内容
    解决office自动更新失败,错误代码0xc0000142
    hosts文件路径(Windows)
    【微信测试版】支持安卓平板和手机同时登录
    【javascript】canvas画布涂鸦及保存图片到本地
    【python】图片批量压缩(多线程)
    【python】提取pdf文件中的所有图片
    【python】计算程序运行所消耗的总时间
  • 原文地址:https://www.cnblogs.com/hahaha22/p/3630796.html
Copyright © 2011-2022 走看看