頻、視頻的格式
開始學(xué)習(xí)之前,我們要下載些素材用來測試使用,地址如下:https://pan.baidu.com/s/1reRWno0ibYRcYXjw4MClqw
提取碼:td80
其中包括兩個視頻一個音頻和一個安裝程序。
學(xué)習(xí)如何在頁面中添加音頻、視頻之前應(yīng)該了解一點基礎(chǔ)知識。
我們應(yīng)該都有在互聯(lián)網(wǎng)上下載電影、視頻、音樂的經(jīng)歷,大家會注意到,有的視頻文件名的后綴是.avi,有的視頻是.mp4,還有.mov的,據(jù)不完全統(tǒng)計,常見的各種視頻格式有十幾種之多。
常見的音頻的格式比起視頻來會顯得少一些,一般是.wav和.mp3格式。
為什么存儲相同的內(nèi)容可以有這么多不同的格式呢?
格式產(chǎn)生的核心在于對音頻、視頻等多媒體文件進行的不同編碼方式。
那什么是編碼呢?
簡單來說我們可以把"編碼"這個詞分成兩個部分,第一個是"編",也就是"整理、組織"的意思,第二個是"碼",也就是我們平時所說的"數(shù)碼"。
首先說"碼",我們的計算機中的數(shù)據(jù)最終都是通過二進制的數(shù)字(0和1)來存儲或計算的,這些0或1就是數(shù)碼。無論代碼、程序、圖片、音樂、視頻、文字等的存儲與計算都不例外。不管多么復(fù)雜或簡單的文件,在計算機看來,都是一大堆0和1。
一個0或1被稱為1比特,圖片或視頻中的一個黑白像素通常是8比特(八位),如果一張1080乘720個像素的圖片所占內(nèi)存的大小就是1080*720*8=6220800字節(jié),約等于0,74mb。如果一個視頻每秒中有25幀,也就是一秒鐘在我們眼前閃過25張圖片(視頻播放實際上就是在我們眼前快速的更替圖片,這些圖片在大腦中會被自動連成動作,這也是小的時候在課本的角上畫好一套走路的小人的不同動作后,快速翻動書頁,畫面中的小人會走路的原因,大家可以自行百度"視覺暫留原理")。
一秒鐘25張1080乘720的圖片的視頻,一秒鐘就會占0.74*25=18.5mb的內(nèi)存。如果是一分鐘呢,18.5*60=1110mb約等于1.08gb。這樣的數(shù)據(jù)量是不是很嚇人。
但事實上我們下載的1080*720的一小時三十分鐘左右的視頻的體積往往也沒有超過1gb,這又是為什么呢?
這就是"編"的功勞!對數(shù)碼進行整理和組織的主要目的是壓縮體積,壓縮數(shù)據(jù)體積既能節(jié)省磁盤又能方便傳播與攜帶,是信息技術(shù)的關(guān)鍵技術(shù)之一,壓縮的方法一般有兩類,一類叫做無損壓縮,也就是通過對這一大堆數(shù)碼進行一個特殊的組合使其占有更小的空間,一類叫做有損壓縮,是在無損壓縮的基礎(chǔ)上剔除掉人眼睛識別不到的冗余信息。具體的壓縮過程涉及到很多數(shù)學(xué)知識,這里大家簡單了解一下即可。
壓縮后的視頻或音頻文件最終通過播放器對該文件的壓縮算法進行逆向運算后,還原成計算機可以解讀的畫面和聲音再呈現(xiàn)給觀眾,這個過程叫做"解碼"。
通過"編"的方式壓縮文件體積,通過"解"的方式再還原出文件內(nèi)容成了處理大規(guī)模數(shù)據(jù)的通用手法。
不同的編碼和解碼方式催生出不同的文件格式,這種情況下,瀏覽器在播放視頻的時候就要有應(yīng)對不同格式的不同解碼方式,在15年以前,瀏覽器為了能夠播放不同格式的視頻,就要調(diào)用電腦中不同的播放器,這個過程的寫法非常麻煩。隨著技術(shù)不斷地整合,時至今日,在頁面中播放視頻不需要這么復(fù)雜的寫法了,但是因為每個瀏覽器都不是包打一切,因此,雖然不用指定播放器,但是也要預(yù)設(shè)不同格式的視頻來應(yīng)對不同的瀏覽器。
因此,我們在這一部分的學(xué)習(xí)中除了講解如何向頁面添加不同格式的音視頻外還會告訴大家如何為音視頻轉(zhuǎn)換格式。
為頁面添加音頻、視頻
添加音頻使用<audio></audio>標簽,這個標簽被所有瀏覽器支持,是html5推薦的音頻導(dǎo)入標簽,但是遺憾的是在html4標準中是不被支持的或者說是非法的。
這里給大家簡要介紹一下html5和html4的區(qū)別。
簡單來說呢,一個html文件的第一條語句是<!DOCTYPE HTML>,它就是HTML5標準的文件。如果是html4,它的第一條聲明語句有三種寫法,像這樣
一:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
二:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
三:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
版權(quán)聲明:本文為CSDN博主「痦子」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/yh1061632045/article/details/81518141
這讓我想到了孔乙己的"茴"字的多種寫法
是不是很麻煩,其實html5比html4更簡單,功能更強大,而且我們一直以html5的標準進行學(xué)習(xí),所以大家不必糾結(jié)。
下面我們導(dǎo)入一個音頻試試吧。示例代碼如下:
<!DOCTYPE HTML>
<html>
<head>
<title>音視頻導(dǎo)入</title>
</head>
<body>
<audio controls="controls">
<source src="audio/千年的祈禱.mp3" type="audio/mp3" />
</audio>
</body>
</html>
頁面效果如下:
其中controls屬性就是用來顯示播放控制界面的,就是這個:(偷懶的話可以寫成"controls"就ok,不必加"="以及后面的內(nèi)容了。)
如果以后您使用自己編寫的控制界面,就可以不添加這個屬性。
刪掉這個屬性后就是這樣:這樣為自定義的播放控制界面留出了位置。
<audio></audio>標簽夾著<source>標簽,一個<audio></audio>標簽中可以添加多個<source>用以支持不同的格式要求。示例代碼如下:(這段代碼來自w3school)
<audio controls="controls">
<source src="song.ogg" type="audio/ogg" />
<source src="song.mp3" type="audio/mpeg" />
Your browser does not support the audio element.<!--你的瀏覽器不支持這個音頻元素-->
</audio>
type屬性是告訴瀏覽器音樂文件的類型。
不同格式的文件的生成需要我們自己去做,這就涉及到如何給一個音頻文件進行格式轉(zhuǎn)化的問題。這個問題我們明天再說,今天先學(xué)習(xí)為頁面添加音頻和視頻。
下面我們來看一下視頻的導(dǎo)入方法,示例代碼如下:
<video controls>
<source src="video/阿塔麗.mp4" type="video/mp4" />
</video>
頁面效果如下:
我們可以通過設(shè)置height和width屬性來控制視頻的面積。實例代碼如下:
<video controls width="850" height="500" >
<source src="video/阿塔麗.mp4" type="video/mp4" />
</video>
頁面效果如下:
視頻畫面變小了,和視頻并排的是我們之前添加的音頻文件,由此可知,這兩個元素都是內(nèi)聯(lián)元素。
今天的內(nèi)容結(jié)束了,明天我們繼續(xù)學(xué)習(xí)格式轉(zhuǎn)換和為不同瀏覽器預(yù)設(shè)不同音視頻格式的方法。
如果您有任何疑問請給我留言,如有問題或錯誤請予以斧正!
HTML序章(學(xué)習(xí)目的、對象、基本概念)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML是什么?——零基礎(chǔ)自學(xué)網(wǎng)頁制作
第一個HTML頁面如何寫?——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML頁面中head標簽有啥用?——零基礎(chǔ)自學(xué)網(wǎng)頁制作
初識meta標簽與SEO——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML中的元素使用方法1——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML中的元素使用方法2——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML元素中的屬性1——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML元素中的屬性2(路徑詳解)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
使用HTML添加表格1(基本元素)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
使用HTML添加表格2(表格頭部與腳部)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
使用HTML添加表格3(間距與顏色)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
使用HTML添加表格4(行顏色與表格嵌套)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
16進制顏色表示與RGB色彩模型——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML中的塊級元素與內(nèi)聯(lián)元素——零基礎(chǔ)自學(xué)網(wǎng)頁制作
初識HTML中的<div>塊元素——零基礎(chǔ)自學(xué)網(wǎng)頁制作
在HTML頁面中嵌入其他頁面的方法——零基礎(chǔ)自學(xué)網(wǎng)頁制作
封閉在家學(xué)網(wǎng)頁制作!為頁面嵌入PDF文件——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML表單元素初識1——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML表單元素初識2——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML表單3(下拉列表、多行文字輸入)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML表單4(form的action、method屬性)——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML列表制作講解——零基礎(chǔ)自學(xué)網(wǎng)頁制作
為HTML頁面添加視頻、音頻的方法——零基礎(chǔ)自學(xué)網(wǎng)頁制作
音視頻格式轉(zhuǎn)換神器與html視頻元素加字幕——零基礎(chǔ)自學(xué)網(wǎng)頁制作
HTML中使用<a>標簽實現(xiàn)文本內(nèi)鏈接——零基礎(chǔ)自學(xué)網(wǎng)頁制作
所周知,16年無疑是直播行業(yè)的春天,同時也是H5的一次高潮。
so,到現(xiàn)在用H5技術(shù)在移動端做網(wǎng)頁直播也是見怪不怪了,但是!!!
今天我們的主角是webApp下播放視頻
參考文獻:
1)HTML5+CSS3+JQuery打造自定義視頻播放器
簡介
HTML5的<video>標簽已經(jīng)被目前大多數(shù)主流瀏覽器所支持,包括還未正式發(fā)布的IE9也聲明將支持<video>標簽,利用瀏覽器原生特性嵌入視頻有很多好處,所以很多開發(fā)者想盡快用上,但是真正使用前還有些問題要考慮,尤其是 Opera/Firefox 和IE/Safari瀏覽器所支持的視頻編碼不同的問題,Google幾個月前發(fā)布的開源視頻編碼VP8有望能解決這一問題,另外Google還發(fā)布了開放網(wǎng)絡(luò)媒體項目WebM,旨在幫助開發(fā)者為開放網(wǎng)絡(luò)制作出世界級媒體格式,Opera, Firefox, Chrome和IE9都將支持VP8,而且Flash Player也將可以播放VP8,這就意味著我們很快就可以只制作一個版本的視頻然后在所有主流瀏覽器上播放了。另外一個主要的問題就是如何構(gòu)建自定義的HTML5<video>播放器,這是目前Flash Player的優(yōu)勢所在,利用Flash的IDE所提供的接口可以很方便的構(gòu)建一個個性化的視頻播放器,那HTML5的<video>標簽要怎樣才能實現(xiàn)呢?這個問題就是本文所要解決的!我們將開發(fā)一個HTML5<video>視頻播放器的jQuery插件,并且可以很方便的進行自定義,將分為以下幾個部分:
1.視頻控制工具條
2.視頻控制按鈕
3.打包成jQuery插件
4.外觀和體驗
5.自定義皮膚
視頻控制工具條
做為一個專業(yè)的web開發(fā)人員,我們創(chuàng)建一個視頻播放器時一定希望它的外觀在各個瀏覽器中看起來一致(consistent),但是通過下面的圖可以看到目前各個瀏覽器提供的視頻控制工具條外觀各不相同:
那就沒辦法了,我們得自己從頭來創(chuàng)建這個控制工具條,利用HTML和CSS再加上一些圖片實現(xiàn)起來并不算很難,另外通過HTML5多媒體元素提供的API我們可以很方便將創(chuàng)建的任何按鈕與播放/暫停等事件進行綁定。
視頻控制按鈕
基本的視頻控制工具條要包含一個播放/暫停按鈕,一個進度條,一個計時器和一個音量控制按鈕,我們將這些按鈕放在<video>元素下面,并用一個div作為父容器:
Java代碼
<div class="ghinda-video-controls">
<a class="ghinda-video-play" title="Play/Pause"></a>
<div class="ghinda-video-seek"></div>
<div class="ghinda-video-timer">00:00</div>
<div class="ghinda-volume-box">
<div class="ghinda-volume-slider"></div>
<a class="ghinda-volume-button" title="Mute/Unmute"></a>
</div>
</div>
復(fù)制代碼
注意,我們使用元素的class屬性來代替ID屬性是為了方便在一個頁面上使用多個播放器。
打包成jQuery插件
創(chuàng)建好控制按鈕后我們需要配合多媒體元素的API來實現(xiàn)視頻控制的目的,正如前面提到的一樣我們將我們的播放器打包成jQuery插件,這樣可以很好的實現(xiàn)復(fù)用,代碼如下:
Java代碼
$.fn.gVideo = function(options) {
// build main options before element iteration
var defaults = {
theme: 'simpledark',
childtheme: ''
};
var options = $.extend(defaults, options);
// iterate and reformat each matched element
return this.each(function() {
var $gVideo = $(this);
//create html structure
//main wrapper
var $video_wrap = $('<div></div>').addClass('ghinda-video-player').addClass(options.theme).addClass(options.childtheme);
//controls wraper
var $video_controls = $('<div class="ghinda-video-controls"><a class="ghinda-video-play" title="Play/Pause"></a><div class="ghinda-video-seek"></div><div class="ghinda-video-timer">00:00</div><div class="ghinda-volume-box"><div class="ghinda-volume-slider"></div><a class="ghinda-volume-button" title="Mute/Unmute"></a></div></div>');
$gVideo.wrap($video_wrap);
$gVideo.after($video_controls);
這里先假設(shè)您了解jQuery并知道如何創(chuàng)建一個jQuery插件,因為這個不在本文的討論范圍之內(nèi),在上面這段腳本中我們使用jQuery動態(tài)創(chuàng)建視頻控制工具條的元素,接下來為了綁定事件我們需要獲取對應(yīng)的元素:
Java代碼
//get newly created elements
var $video_container = $gVideo.parent('.ghinda-video-player');
var $video_controls = $('.ghinda-video-controls', $video_container);
var $ghinda_play_btn = $('.ghinda-video-play', $video_container);
var $ghinda_video_seek = $('.ghinda-video-seek', $video_container);
var $ghinda_video_timer = $('.ghinda-video-timer', $video_container);
var $ghinda_volume = $('.ghinda-volume-slider', $video_container);
var $ghinda_volume_btn = $('.ghinda-volume-button', $video_container);
$video_controls.hide(); // keep the controls hidden
這里我們通過className方式獲取,先讓工具條隱藏直到所有資源加載完成,現(xiàn)在來實現(xiàn)播放/暫停按鈕:
Java代碼
var gPlay = function() {
if($gVideo.attr('paused') == false) {
$gVideo[0].pause();
} else {
$gVideo[0].play();
}
};
$ghinda_play_btn.click(gPlay);
$gVideo.click(gPlay);
$gVideo.bind('play', function() {
$ghinda_play_btn.addClass('ghinda-paused-button');
});
$gVideo.bind('pause', function() {
$ghinda_play_btn.removeClass('ghinda-paused-button');
});
$gVideo.bind('ended', function() {
$ghinda_play_btn.removeClass('ghinda-paused-button');
});
大多數(shù)瀏覽器在右鍵點擊視頻時會提供一個獨立的菜單,它也提供了視頻控制功能,如果用戶通過這個右鍵菜單控制視頻那就會跟我們的自定義控件沖突,所以為了避免這一點我們需要綁定視頻播放器自身的“播放”,“暫停”和“結(jié)束”事件,在事件處理函數(shù)中處理播放/暫停按鈕,控制按鈕的樣式。
為了創(chuàng)建進度條的拖動塊,我們使用了jQuery UI的Slider組件:
Java代碼
var createSeek = function() {
if($gVideo.attr('readyState')) {
var video_duration = $gVideo.attr('duration');
$ghinda_video_seek.slider({
value: 0,
step: 0.01,
orientation: "horizontal",
range: "min",
max: video_duration,
animate: true,
slide: function(){
seeksliding = true;
},
stop:function(e,ui){
seeksliding = false;
$gVideo.attr("currentTime",ui.value);
}
});
$video_controls.show();
} else {
setTimeout(createSeek, 150);
}
};
createSeek();
正如你所看到的,這里我們寫了一個遞歸函數(shù),通過循環(huán)比較video的readyState屬性來判斷視頻是否已經(jīng)準備好,否則我們就不能獲得視頻的時長也無法創(chuàng)建滑動塊,當視頻準備好后我們初始化滑動塊并顯示控制工具條,下一步我們通過綁定video元素的timeupdate事件實現(xiàn)計時器功能:
Java代碼
var gTimeFormat=function(seconds){
var m=Math.floor(seconds/60)<10?"0"+Math.floor(seconds/60):Math.floor(seconds/60);
var s=Math.floor(seconds-(m*60))<10?"0"+Math.floor(seconds-(m*60)):Math.floor(seconds-(m*60));
return m+":"+s;
};
var seekUpdate = function() {
var currenttime = $gVideo.attr('currentTime');
if(!seeksliding) $ghinda_video_seek.slider('value', currenttime);
$ghinda_video_timer.text(gTimeFormat(currenttime));
};
$gVideo.bind('timeupdate', seekUpdate);
這里我們用seekUpdate函數(shù)獲取video的currentTime屬性值然后調(diào)用gTimeFormat函數(shù)進行格式化后得到當前播放的時間點。
至于音量控制控件我們還是利用jQuery UI的Slider組件然后利用自定義函數(shù)實現(xiàn)靜音和取消靜音的功能:
Java代碼
$ghinda_volume.slider({
value: 1,
orientation: "vertical",
range: "min",
max: 1,
step: 0.05,
animate: true,
slide:function(e,ui){
$gVideo.attr('muted',false);
video_volume = ui.value;
$gVideo.attr('volume',ui.value);
}
});
var muteVolume = function() {
if($gVideo.attr('muted')==true) {
$gVideo.attr('muted', false);
$ghinda_volume.slider('value', video_volume);
$ghinda_volume_btn.removeClass('ghinda-volume-mute');
} else {
$gVideo.attr('muted', true);
$ghinda_volume.slider('value', '0');
$ghinda_volume_btn.addClass('ghinda-volume-mute');
};
};
$ghinda_volume_btn.click(muteVolume);
最后當我們自己的自定義視頻控制工具條構(gòu)造完成后需要移除<video>標簽的controls屬性,這樣瀏覽器默認的工具條就被去掉了。
好了,我們的插件功能已經(jīng)全部完成了,調(diào)用方法:
Java代碼
$('video').gVideo();
這會將我們的插件應(yīng)用到頁面上每一個video元素上。
外觀和體驗
好的,現(xiàn)在到了比較有意思的部分,也就是播放器的外觀和體驗了。當插件功能已經(jīng)完成后利用一點CSS就可以很容易地自定義樣式了,我們將全部使用CSS3來實現(xiàn)。
首先,我們給播放器主容器加一些樣式:
Java代碼
.ghinda-video-player {
float: left;
padding: 10px;
border: 5px solid #61625d;
-moz-border-radius: 5px; /* FF1+ */
-ms-border-radius: 5px; /* IE future proofing */
-webkit-border-radius: 5px; /* Saf3+, Chrome */
border-radius: 5px; /* Opera 10.5, IE 9 */
background: #000000;
background-image: -moz-linear-gradient(top, #313131, #000000); /* FF3.6 */
background-image: -webkit-gradient(linear,left top,left bottombottom,color-stop(0, #313131),color-stop(1, #000000)); /* Saf4+, Chrome */
box-shadow: inset 0 15px 35px #535353;
}
下一步,我們設(shè)置視頻控制工具條左邊浮動使它們水平對齊,利用CSS3的opacity和transitions我們給播放/暫停和靜音/取消靜音按鈕添加了非常不錯的懸浮效果:
Java代碼
.ghinda-video-play {
display: block;
width: 22px;
height: 22px;
margin-right: 15px;
background: url(../images/play-icon.png) no-repeat;
opacity: 0.7;
-moz-transition: all 0.2s ease-in-out; /* Firefox */
-ms-transition: all 0.2s ease-in-out; /* IE future proofing */
-o-transition: all 0.2s ease-in-out; /* Opera */
-webkit-transition: all 0.2s ease-in-out; /* Safari and Chrome */
transition: all 0.2s ease-in-out;
}
.ghinda-paused-button {
background: url(../images/pause-icon.png) no-repeat;
}
.ghinda-video-play:hover {
opacity: 1;
}
如果您仔細看了前面那段根據(jù)視頻播放狀態(tài)(Playing/Paused)添加和移除播放/暫停按鈕樣式的JavaScript代碼,就會明白為什么.ghinda-paused-button為什么要重寫.ghinda-video-play的背景屬性了。
現(xiàn)在輪到滑動塊了,我們進度條和音量控制的滑動塊的實現(xiàn)都是利用了jQuery UI的Slider組件,這個組件它本身自帶了樣式,定義在jQuery UI對應(yīng)的css文件中,但是為了使滑動塊和播放器其他控件外觀保持一致我們?nèi)恐貙懥怂臉邮剑?/p>
Java代碼
.ghinda-video-seek .ui-slider-handle {
width: 15px;
height: 15px;
border: 1px solid #333;
top: -4px;
-moz-border-radius:10px;
-ms-border-radius:10px;
-webkit-border-radius:10px;
border-radius:10px;
background: #e6e6e6;
background-image: -moz-linear-gradient(top, #e6e6e6, #d5d5d5);
background-image: -webkit-gradient(linear,left top,left bottombottom,color-stop(0, #e6e6e6),color-stop(1, #d5d5d5));
box-shadow: inset 0 -3px 3px #d5d5d5;
}
.ghinda-video-seek .ui-slider-handle.ui-state-hover {
background: #fff;
}
.ghinda-video-seek .ui-slider-range {
-moz-border-radius:15px;
-ms-border-radius:15px;
-webkit-border-radius:15px;
border-radius:15px;
background: #4cbae8;
background-image: -moz-linear-gradient(top, #4cbae8, #39a2ce);
background-image: -webkit-gradient(linear,left top,left bottombottom,color-stop(0, #4cbae8),color-stop(1, #39a2ce));
box-shadow: inset 0 -3px 3px #39a2ce;
}
這時候音量控制的滑動塊一直顯示在音量按鈕旁邊,我們需要將它改成默認隱藏,當鼠標懸浮在音量按鈕上再動態(tài)顯示出來,使用transitions來實現(xiàn)這個效果會是個不錯的的選擇:
Java代碼
.ghinda-volume-box {
height: 30px;
-moz-transition: all 0.1s ease-in-out; /* Firefox */
-ms-transition: all 0.1s ease-in-out; /* IE future proofing */
-o-transition: all 0.2s ease-in-out; /* Opera */
-webkit-transition: all 0.1s ease-in-out; /* Safari and Chrome */
transition: all 0.1s ease-in-out;
}
.ghinda-volume-box:hover {
height: 135px;
padding-top: 5px;
}
.ghinda-volume-slider {
visibility: hidden;
opacity: 0;
-moz-transition: all 0.1s ease-in-out; /* Firefox */
-ms-transition: all 0.1s ease-in-out; /* IE future proofing */
-o-transition: all 0.1s ease-in-out; /* Opera */
-webkit-transition: all 0.1s ease-in-out; /* Safari and Chrome */
transition: all 0.1s ease-in-out;
}
.ghinda-volume-box:hover .ghinda-volume-slider {
position: relative;
visibility: visible;
opacity: 1;
}
利用一些基礎(chǔ)的CSS屬性以及CSS3提供的新屬性我們打造了一個全新的播放器外觀,它看起來是這個樣子:
自定義皮膚
可能您已經(jīng)注意到,我們在編寫插件的時候已經(jīng)定義了一些默認選項,它們是theme和childtheme,可以在調(diào)用插件的時候根據(jù)需要方便的應(yīng)用自定義皮膚。
這里解釋下theme就是所有控件的一整套樣式定義,childtheme就是在theme基礎(chǔ)上重寫某些樣式,我們在調(diào)用插件的時候可以同時指定這兩個選項或者其中的一個:
Java代碼
$('video').gVideo({
childtheme:'smalldark'
});
我們寫了一個示例的皮膚smalldark,它只重寫了部分的樣式,顯示效果是這樣的:
總結(jié)
利用HTML5 video,JavaScript和CSS3打造自定義的視頻播放器真的非常容易,t實現(xiàn)工具條功能用JavaScrip,外觀和體驗交給CSS3,我們得到了一個功能強大并且易于定制的解決方案!
enjoy!
2)mui Html5 Video 實現(xiàn)方案
前言: 最近項目中需要用到html5 視頻播放功能,于是稍微研究了解了下,遇到了很多坑,特此記錄下.
一、 Html5 Video
參考來源: http://www.xuanfengge.com/html5-video-play.html
(這篇博文確實幫助很大)
1.1、 目的
將Html5 Video功能應(yīng)用到實際項目中,針對不同的平臺和環(huán)境,進行個性化處理。
基本只考慮webkit瀏覽器兼容問題
1.2、 Html5 Video支持格式
只支持: .mp4后綴(.h264編碼格式),和.webm后綴(專用web視頻格式),以及.ogg后綴(音頻文件)
注意: Html5 Video 可以添加多個source源來進行兼容適配,這樣,當?shù)谝粋€源讀取出問題時會自動讀取下一個源. 比如可以同時在前面加上.webm和.mp4源,這樣一個出錯時會自動讀取另一個可用源(因為不同瀏覽器,支持的格式是不一樣的)
但是,Hybird模式的 Android 下,有些機型只能讀取第一個source來源(測試華為和聯(lián)想都是),所以也就是說在這種情況下,要確保第一個source源是正確的
各大瀏覽器兼容如圖所示:
見圖1
1.3、 不同平臺環(huán)境和對應(yīng)實現(xiàn)方案
說明: 這里分為兩大塊,普通瀏覽器環(huán)境(pc和手機,主要是移動端,pc不做特別處理)和Hybird模式的APP環(huán)境(Android和iOS).
注: Html5 video可以播放本地視頻或者網(wǎng)絡(luò)視頻
1.3.1、 普通瀏覽器環(huán)境
*用Html5 Video 自帶的播放欄控件
*用 Video 視頻統(tǒng)一處理方法處理后,點擊圖片手動隱藏圖片,設(shè)置視頻大小,手動播放視頻.
注: 播放效果則由各大瀏覽器自行實現(xiàn)
手機端瀏覽器實現(xiàn)的不同效果,比如:
QQ瀏覽器(包括QQ客戶端內(nèi)置的瀏覽器):播放時會自動進入全屏
華為自帶瀏覽器: 正常小窗口播放
1.3.2、 Hybird App環(huán)境
說明: 內(nèi)聯(lián)播放是指直接在video標簽中播放視頻,沒有必要進入全屏
1.3.2.1、 Android內(nèi)聯(lián)播放
*用Html5 Video 自帶的播放欄控件
*用 Video 視頻統(tǒng)一處理方法處理后,點擊圖片手動隱藏圖片,設(shè)置視頻大小,手動播放視頻.
*Android內(nèi)聯(lián)播放需要注意,必須開啟硬件加速,由于有些Android手機 webview是默認關(guān)閉硬件加速的,所以必須在創(chuàng)建這個帶視頻播放的webview時手動添加 硬件加速屬性才行.(詳情見plus創(chuàng)建webview的style)
style.hardwareAccelerated = true;
1.3.2.2、 iOS內(nèi)聯(lián)播放
*用Html5 Video 自帶的播放欄控件
*用 Video 視頻統(tǒng)一處理方法處理后,點擊圖片手動隱藏圖片,設(shè)置視頻大小,手動播放視頻.
*內(nèi)聯(lián)播放注意要點,由于iOS下默認是全屏播放的,所以需要經(jīng)過設(shè)置才能正常內(nèi)聯(lián)播放
第一步:在項目的manifest里面配置允許webview內(nèi)聯(lián)播放
"plus": { "splashscreen": { "autoclose": true,/*是否自動關(guān)閉程序啟動界面,true表示應(yīng)用加載應(yīng)用入口頁面后自動關(guān)閉;false則需調(diào)plus.navigator.closeSplashscreen()關(guān)閉*/ "waiting": true/*是否在程序啟動界面顯示等待雪花,true表示顯示,false表示不顯示。*/ }, "allowsInlineMediaPlayback": true,/*設(shè)置ios下允許內(nèi)聯(lián)播放*/ "popGesture": "close"
第二步: 創(chuàng)建video標簽時,手動加上內(nèi)聯(lián)播放的屬性(iOS不支持preload)
<!-- 讓ios支持內(nèi)聯(lián)播放,必須添加 webkit-playsinline 標簽 --> <video webkit-playsinline id="videoMedia" controls="controls" preload>
這樣iOS手機在播放的時候才會采用內(nèi)聯(lián)播放
1.3.2.3、 Android非內(nèi)聯(lián)播放
*通過NJS使用原生播放器來播放視頻,傳入的url可以是本地的或網(wǎng)絡(luò)的地址
*用 Video 視頻統(tǒng)一處理方法處理后,點擊圖片之后,圖片保持不變(所以沒有必要隱藏圖片),直接獲取視頻的資源地址,傳給原生播放器播放
注: 這種模式下,性能要比直接html5自帶播放器播放高
1.3.2.4、 iOS非內(nèi)聯(lián)播放
*用Html5 Video 自帶的播放欄控件(非內(nèi)聯(lián)播放需要去除特定內(nèi)聯(lián)屬性”webkit-playsinline”,這樣才能全屏播放)
if(!isInlinePlay){ //如果是非內(nèi)斂,ios需要去除內(nèi)聯(lián)樣式 mediaTarget.removeAttribute('webkit-playsinline'); }
*用 Video 視頻統(tǒng)一處理方法處理后,點擊圖片之后,圖片保持不變(所以沒有必要隱藏圖片),直接調(diào)用video.play()播放視頻(這時候會用一個全屏播放器來播放視頻)
1.3.3、 注意要點
如果采用NJS通過Android原生播放器播放視頻,目前無法監(jiān)聽到視頻的一些自定義事件.(如下載中,播放完畢,暫停,播放時間等)
而如果采用Html5 Video自帶播放,這些是可以通過腳本控制的.
所以選定方案時需要進行衡量
*另外,在Html5 Video播放時,無法監(jiān)聽到規(guī)定的結(jié)束事件seeked,只能在timeUpdate里面判斷,如果ended為true就代表結(jié)束了.
*在NJS通過Android原生播放器播放時,可以通過document監(jiān)聽resume和pause事件判斷是否進入播放和退出播放
1.4、 Tips
1.4.1、 關(guān)于Video 視頻統(tǒng)一處理的方案
說明: 由于將一個<Video>直接顯示在頁面中,會有各種五花八門的播放器效果,如圖:
(這里引用了參考來源的圖)
見圖2
顯然,體驗效果并不好,所以現(xiàn)在的做法是用一張模擬播放的圖片來替代<Video>所在的地方,而將Video元素設(shè)置為1*1像素大小.然后給圖片設(shè)置點擊監(jiān)聽,監(jiān)聽到點擊時,播放視頻.
注意:
*這里不要用{display: none}或者{width:0;height:0;}的方式,因為這樣視頻元素會處于未激活的狀態(tài),給后續(xù)的處理帶來麻煩.
*這里沒有考慮ios<6和一些低版本的Android的兼容性問題了(這些版本里,無法直接通過video.play()來播放),因為項目環(huán)境基本上要求Android>4.0 iOS 7.0以上的.
*關(guān)于點擊圖片播放視頻后,如果是內(nèi)聯(lián)播放模式下(或者是普通瀏覽器),就應(yīng)該將圖片隱藏,然后將視頻大小設(shè)置為本來的大小(一般為圖片大小);如果是非內(nèi)聯(lián)播放模式(全屏模式),就沒有必要隱藏圖片了,因為iOS下會自動打開一個全屏播放器來播放視頻,Android下考慮到Html5 video較卡,所以也會通過NJS使用原生播放器來全屏播放視頻.
1.4.2、 Android NJS播放視屏的實現(xiàn)代碼
說明: 這個是Dcloud論壇中有人分享的
//非內(nèi)聯(lián)模式下的plus下的android才用到 var Intent = plus.android.importClass("android.content.Intent"); var Uri = plus.android.importClass("android.net.Uri"); var main = plus.android.runtimeMainActivity(); var intent = new Intent(Intent.ACTION_VIEW); var uri = Uri.parse(url); intent.setDataAndType(uri, "video/*"); main.startActivity(intent);
1.4.3、 如何讀取元素的寬高
*在獲取視頻的寬度時,發(fā)現(xiàn)用 video.style.width無法獲取到寬度.
后來查了資料,發(fā)現(xiàn)dom.style.width(height)只能獲取在stye直接賦予的值.而如果是通過css樣式表賦予的值是無法直接獲取的,只能通過dom.offsetWidth(offsetHeight)獲取.
*設(shè)置元素寬和高是不要直接在style里設(shè)置,而是最好通過css樣式表賦予
*讀取元素寬和高時,用offsetWidth(offsetHeight)
1.4.4、 關(guān)于全屏播放的問題
在PC端webkit瀏覽器下,全屏代碼如下:
進入全屏: videoContainer(對應(yīng)的dom).webkitRequestFullscreen();
退出全屏: document.webkitCancelFullScreen();
*但是經(jīng)測試,在手機瀏覽器和Hybird模式下的手機環(huán)境中都無法使用,
應(yīng)該是手機瀏覽器中video 播放器的全屏模式和pc端的有區(qū)別,已經(jīng)脫離了webkit的全屏組件,而是用原生自己實現(xiàn)的.
1.5、 遇到問題及解決方法
1.5.1、 Video.currentTime 設(shè)置值時設(shè)置無效,或者變?yōu)?
原因分析:
與測試的服務(wù)器和端口有關(guān),測試環(huán)境是放在hbuild本地瀏覽器的,沒有處理好視頻快進問題,所以會導(dǎo)致每次快進后,視頻都會重置-在某些測試服務(wù)器上,則出現(xiàn)快進無效,但不會重置
解決方法:
將網(wǎng)頁用其它正式服務(wù)器打開均可正常,如tomcat,wampserver,甚至直接在本地打開也行.
1.5.2、 無法通過代碼Video.src獲取資源路徑
原因分析:
本實例中,Video是通過source添加src的,無法直接讀取video的src
解決方法:
可以通過讀取到第一個source的標簽,再獲取source的src
注:本來這個方法有一個缺點就是有可能第一個source的src不可用.但是由于Android中第一個source必須有用才行.否則無法正常播放.所以在確保第一個source正確的情況下能這樣用.
1.5.3、 部分Android機型無法退出全屏
描述:
在使用Html5 Video自帶播放器播放時,部分Android機型(如聯(lián)想K860點擊全屏按鈕進入全屏后,無法退出全屏-因為進入全屏后,全屏按鈕不見了)
原因分析: 可能是手機廠商擅自劫持了瀏覽器或者篡改了瀏覽器實現(xiàn)方式
解決方法:
目前無法解決,在這類機型中,建議直接采用非內(nèi)聯(lián)模式播放或者是盡量不要手動進入全屏
3)移動端HTML5<video>視頻播放優(yōu)化實踐
遇到的挑戰(zhàn)
移動端HTML5使用原生<video>標簽播放視頻,要做到兩個基本原則,速度快和體驗佳,先來分析一下這兩個問題。
下載速度
以一個8s短視頻為例,wifi環(huán)境下提供的高清視頻達到1000kbps,文件大小大約1MB;非wifi環(huán)境下提供的低碼率視頻是500kbps左右,文件大小大約500KB;參考QzoneTouch多普勒測速,2g網(wǎng)絡(luò)的平均速度是14KB/s,那么下載一個低碼率視頻耗時35s;那么要想流暢播放視頻,就需要一個加載等待的過程,這個過程要有明確的反饋,不能讓用戶有“壞掉了”的感覺。
多普勒測速數(shù)據(jù)參考
# | dns(s) | conn(s) | rtt(s) | tran(kb/s) |
---|---|---|---|---|
2g | 3.85785 | 2.33482 | 2.57478 | 14.0374 |
3g | 1.60643 | 0.743109 | 0.608047 | 60.1967 |
wifi | 0.986921 | 0.550208 | 0.444332 | 70.8728 |
用戶體驗
視頻是否可以自動播放,是否能循環(huán)播放,是否能顯示下載進度,播放的時候如何隱藏控制條,暫停的時候又能顯示出來呢。這些問題看上去貌似簡單,但是由于PC/iOS/Android這些不同平臺、不同的瀏覽器內(nèi)核、甚至相同內(nèi)核的不同版本,所實現(xiàn)的<video>屬性、方法和事件差異較大,解決兼容性問題又給開發(fā)造成了很大困擾。
分析原因
事件差異
下面是播放一個短視頻,在不同平臺觸發(fā)事件和獲取屬性的差異表現(xiàn)。
PC
# | event | readyState | currentTime (s) | buffered (s) | duration (s) | 視頻狀態(tài) |
---|---|---|---|---|---|---|
1 | loadstart | NOTHING | 0 | – | – | – |
2 | suspend | NOTHING | 0 | – | – | – |
3 | play | NOTHING | 0 | – | – | – |
4 | waiting | NOTHING | 0 | – | – | – |
5 | durationchange | METADATA | 0 | 5.35 | 7.91 | 獲取到視頻長度 |
6 | loadedmetadata | METADATA | 0 | 0.66 | 7.91 | 獲取到元數(shù)據(jù) |
7 | loadeddata | ENOUGHDATA | 0 | 0.66 | 7.91 | – |
8 | canplay | ENOUGH_DATA | 0 | 0.66 | 7.91 | – |
9 | playing | ENOUGH_DATA | 0 | 0.66 | 7.91 | 開始播放 |
10 | canplaythrough | ENOUGH_DATA | 0 | 0.66 | 7.91 | 可以流暢播放 |
11 | progress | ENOUGH_DATA | 0.11 | 3.68 | 7.91 | 持續(xù)下載 |
12 | timeupdate | ENOUGH_DATA | 0.14 | 4.44 | 7.91 | 播放進度變化 |
… | … | … | … | … | … | … |
23 | progress | ENOUGH_DATA | 1.77 | 7.91 | 7.91 | 下載完畢 |
24 | suspend | ENOUGH_DATA | 1.77 | 7.91 | 7.91 | – |
25 | timeupdate | ENOUGH_DATA | 1.9 | 7.91 | 7.91 | 繼續(xù)播放中 |
… | … | … | … | … | … | … |
48 | timeupdate | ENOUGH_DATA | 7.7 | 7.91 | 7.91 | – |
49 | timeupdate | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
50 | seeking | METADATA | 0 | 7.91 | 7.91 | – |
51 | waiting | METADATA | 0 | 7.91 | 7.91 | – |
52 | timeupdate | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
53 | seeked | ENOUGH_DATA | 0 | 7.91 | 7.91 | 播放完畢進度回到起點 |
54 | canplay | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
55 | playing | ENOUGH_DATA | 0 | 7.91 | 7.91 | 循環(huán)播放 |
56 | canplaythrough | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
57 | timeupdate | ENOUGH_DATA | 0.19 | 7.91 | 7.91 | – |
… | … | … | … | … | … | … |
iOS
# | event | readyState | currentTime (s) | buffered (s) | duration (s) | 視頻狀態(tài) |
---|---|---|---|---|---|---|
1 | loadstart | NOTHING | 0 | – | – | – |
2 | play | NOTHING | 0 | – | – | – |
3 | waiting | NOTHING | 0 | – | – | – |
4 | durationchange | METADATA | 0 | – | 7.91 | 獲取到視頻長度 |
5 | loadedmetadata | METADATA | 0 | – | 7.91 | 獲取到元數(shù)據(jù) |
6 | loadeddata | ENOUGHDATA | 0 | – | 7.91 | – |
7 | canplay | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
8 | canplaythrough | ENOUGH_DATA | 0 | 7.91 | 7.91 | 可以流暢播放 |
9 | playing | ENOUGH_DATA | 0 | 7.91 | 7.91 | 開始播放 |
10 | progress | ENOUGH_DATA | 0 | 7.91 | 7.91 | 下載完畢 |
11 | suspend | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
12 | timeupdate | ENOUGH_DATA | 0.02 | 7.91 | 7.91 | 播放進度變化 |
… | … | … | … | … | … | … |
43 | timeupdate | ENOUGH_DATA | 7.8 | 7.91 | 7.91 | – |
44 | timeupdate | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
45 | seeked | ENOUGH_DATA | 0 | 7.91 | 7.91 | 播放完畢進度回到起點 |
46 | timeupdate | ENOUGH_DATA | 0.22 | 7.91 | 7.91 | 循環(huán)播放 |
… | … | … | … | … | … | … |
Android
# | event | readyState | currentTime (s) | buffered (s) | duration (s) | 視頻狀態(tài) |
---|---|---|---|---|---|---|
1 | loadstart | NOTHING | 0 | – | – | – |
2 | play | NOTHING | 0 | – | – | – |
3 | waiting | NOTHING | 0 | 0 | – | – |
4 | durationchange | ENOUGH_DATA | 0 | 0 | 0 | – |
5 | durationchange | ENOUGH_DATA | 0 | 0 | 7.91 | 獲取到視頻長度 |
6 | loadedmetadata | ENOUGH_DATA | 0 | 0 | 7.91 | 獲取到元數(shù)據(jù) |
7 | loadeddata | ENOUGHDATA | 0 | 0 | 7.91 | – |
8 | canplay | ENOUGH_DATA | 0 | 0 | 7.91 | – |
9 | canplaythrough | ENOUGH_DATA | 0 | 0 | 7.91 | – |
10 | playing | ENOUGH_DATA | 0 | 0 | 7.91 | – |
11 | timeupdate | ENOUGH_DATA | 0 | 0 | 7.91 | – |
12 | progress | ENOUGH_DATA | 0 | 3.57 | 7.91 | 下載中 |
13 | timeupdate | ENOUGH_DATA | 0.2 | 6.89 | 7.91 | 開始播放 |
14 | progress | ENOUGH_DATA | 0 | 7.91 | 7.91 | 下載完畢 |
… | … | … | … | … | … | … |
49 | timeupdate | ENOUGH_DATA | 7.79 | 7.91 | 7.91 | – |
50 | progress | ENOUGH_DATA | 7.87 | 7.91 | 7.91 | – |
51 | timeupdate | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
52 | seeking | ENOUGH_DATA | 0 | 7.91 | 7.91 | 播放完畢進度回到起點 |
53 | timeupdate | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
54 | seeked | ENOUGH_DATA | 0 | 7.91 | 7.91 | 循環(huán)播放失敗卡住了 |
55 | progress | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
56 | stalled | ENOUGH_DATA | 0 | 7.91 | 7.91 | – |
一些常用且需要重點關(guān)注的<video>事件
event | iOS | Android |
---|---|---|
****************** | *********************************************** | *********************************************** |
play | 只是要播放視頻,響應(yīng)的是video.play()方法,并不代表已經(jīng)開始播放 | 和iOS一樣,僅是響應(yīng)video.play()方法 |
durationchange | 會執(zhí)行一次,一定會獲取到視頻的duration | 可能會執(zhí)行多次,只有最后一次才能獲取到真實的duration,前面的duration都是0;但低版本Android可能獲取到的duration是0或1;(本文提到的低版本Android大部分是4.1以下) |
canplay | 可以認為是視頻元素沒有問題,可以運行,沒有更多含義了,基本用不上 | 同iOS |
canplaythrough | 會有明確的緩沖,表示可以流暢播放了; | 沒有什么用,視頻仍然會卡住,數(shù)據(jù)可能還沒有開始加載; |
playing | 明確表示播放開始了; | 依然沒有用,視頻可能并沒有開始播放; |
progress | 有明確的下載,可以獲取到當前的buffer,并且全部下載完畢后不在觸發(fā); | 不一定有明確的數(shù)據(jù)下載,并且全部下載完畢后依然繼續(xù)觸發(fā); |
timeupdate | 會有明確的進度變化,可以獲取到currentTime; | 進度不一定變化,currentTime可能總是0,但是第一次有currentTime變化的timeupdate事件一定代表了視頻開始播放了; |
error | iOS中會有明確的錯誤拋出; | Android中某些瀏覽器會莫名其妙的拋出error; |
stalled | 網(wǎng)絡(luò)狀況不佳,導(dǎo)致視頻下載中斷; | 在沒有play之前,也可能會拋出該事件。 |
屬性差異
attributes | iOS | android |
---|---|---|
****************** | *********************************************** | *********************************************** |
poster 封面圖片 | 支持,但是加載速度明顯比在<img>中要慢; | 不一定支持(瀏覽器廠商的實現(xiàn)標準不統(tǒng)一); |
preload 預(yù)加載 | iPhone不支持; | 可能支持; |
autoplay 自動播放 | iPhone Safari中不支持,但在webview中可能被開啟;iOS開發(fā)文檔明確說明蜂窩網(wǎng)絡(luò)下不允許autoplay; | 可能支持; |
loop 循環(huán)播放 | 支持 | 可能支持; |
controls 控制條 | 支持,但是需要開始播放了才顯示 | 基本都支持顯示或者不顯示 |
width和height | 一定給出明確的屬性設(shè)置,切不能為0; | 如果不設(shè)置,僅僅通過CSS樣式去控制視頻大小,可能會導(dǎo)致標簽失效。 |
其他怪異bug和不友好表現(xiàn)
iOS | android |
---|---|
********************************************************* | ********************************************************* |
物理位置覆蓋在<video>區(qū)域上的元素,click和touch等事件會失效,比如一個<a>鏈接如果覆蓋在<video>上,那么點擊后沒有任何效果。 | – |
iOS8.0+中,單頁面播放視頻超過16個,再播放的視頻全部MediaError解碼異常無法播放。 | – |
iPhone的Safari會彈出一個全屏的播放器來播放視頻,iPad則支持內(nèi)聯(lián)播放。iOS7+ 如果webview(比如微信)開啟了webview.allowsInlineMediaPlayback = YES; ,可以通過設(shè)置webkit-playsinline 屬性支持內(nèi)聯(lián)播放; | 支持內(nèi)聯(lián)播放,但某些廠商會用自己的播放器劫持原生的視頻播放; |
下載視頻時,會先發(fā)送一個2字節(jié)的請求來獲取視頻元數(shù)據(jù)(比如時長),然后再不斷的發(fā)送分包續(xù)傳(206)請求來下載視頻,抓包顯示請求數(shù)和請求量至少有一倍的冗余(x2),這個嚴重的bug在iOS8中有明顯的修復(fù),但是分包的206請求仍然會有冗余數(shù)據(jù)的下載,浪費了流量。 | 比iOS的處理方式好,沒有第一個2字節(jié)請求,沒有流量損耗; |
– | 低版本Android(<=4.0.4)中,<video>如果在有相對和決定定位的層中,可能會導(dǎo)致整個頁面錯位。 |
– | 某些瀏覽器廠商會劫持<video>,用其“自己”的播放器來播放視頻,“破壞”了產(chǎn)品本身的播放體驗,那么只能case by case的解決了。 |
加載視頻時沒有進度提示,視覺上看不出是播放完了還是卡住了; | 加載視頻時,大都會顯示一個自帶的loading UI(菊花)。 |
最佳實踐
視頻初始化
如果將一個<video>直接顯示在頁面中,那么就會看到各種五花八門的播放器初始效果;
這顯然不是一個好的視覺體驗,那么通常的做法是制作一個模擬的視頻播放視圖,比如一個封面加一個播放按鈕。
而真實的<video>視頻元素要隱藏起來,如何隱藏呢?最好不要用{display: none}
或者{width:0;height:0;}
的方式,因為這樣視頻元素會處于未激活的狀態(tài),給后續(xù)的處理帶來麻煩。最佳的方式是將視頻設(shè)置成1×1像素大小,放在視覺邊緣的位置。
1 2 3 4 5 | <!--iOS--> <video webkit-playsinline width="1"height="1"class="vplayinside notaplink"x-webkit-airplay controls loop="loop"src="<%=src%>"></video> <!--Android--> <video width="1"height="1"controls loop="loop"src="<%=src%>"></video> |
自動播放
autoplay的支持依賴內(nèi)核和網(wǎng)絡(luò)狀況,比如iPhone在蜂窩網(wǎng)絡(luò)下明確禁用了autoplay;
經(jīng)過試驗,在沒有明確的用戶操作的情況下,直接通過video.play()
也是無法激活播放的;
并且在產(chǎn)品設(shè)計上,自動播放也不是一個舒服的用戶體驗,所以產(chǎn)品設(shè)計上盡量避免使用自動播放。
點擊播放
之前提到,視頻最好通過1px大小隱藏起來,那么這時如何觸發(fā)播放呢?
經(jīng)過試驗,當在明確的用戶操作(touch、click)時,通過這些用戶行為事件的回調(diào)函數(shù),用video.play()
是可以觸發(fā)視頻播放的,那么能否在用戶操作后,再去同步的創(chuàng)建和播放視頻呢?答案是肯定的,這無疑是一個視頻元素初始化的最佳實踐,但是有些差異需要注意。
iOS6+
可以在用戶的touch時間中動態(tài)創(chuàng)建并播放視頻。
iOS < 6
可以在用戶的touch時間中動態(tài)創(chuàng)建視頻,但不能播放;要再追加一個click事件來啟動播放;也就是說,給偽造的視頻播放按鈕同時綁定tap和click事件,在tap的時候創(chuàng)建,在之后300毫秒的click中去播放。
Android
大部分高版本Android可以像iOS6+那樣去處理,但是低版本的不行,必須要通過click事件去傳遞video.play()
,為了保持兼容,最好是用幫tap和click兩個事件來分別完成視頻的初始化和播放。
我們還發(fā)現(xiàn),有些低版本Android中,無法通過video.play()
來播放視頻,必須有真實的用戶點擊視頻元素才能播放;這種情況,有一個技巧就是在tap的時候初始化并放大視頻覆蓋在播放視圖中,讓300毫秒后的真實點擊行為穿透點擊在視頻元素上來實現(xiàn)播放。
循環(huán)播放
如果視頻需要循環(huán)播放,那么就增加loop
屬性,是否能循環(huán)播放就看瀏覽器是否支持了,因為還沒有找到hack技巧來強制循環(huán)播放;
即使,在不支持循環(huán)播放的Android中,通過監(jiān)聽seeked
事件知道了播放進度到了終點或起點暫停了,此時也無法通過video.play()
來讓視頻重新播放。
監(jiān)控下載進度
如何獲取視頻時長和已經(jīng)下載的時長?
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 視頻時長 varduration=video.duration // 獲取視頻已經(jīng)下載的時長 functiongetEnd(video){ varend=0 try{ end=video.buffered.end(0)||0 end=parseInt(end*1000+1)/1000 }catch(e){ } returnend } |
progress事件表示視頻在加載,但是它的觸發(fā)頻率和時機并不規(guī)律,最佳做法是通過一個定時器去實時獲取end,當end >= duration時,表示已經(jīng)下載完畢,再終止定時器。
1 2 3 4 5 6 7 8 9 10 | vartimer=setInterval(function(){ varend=getEnd(video), duration=video.duration if(end<duration){ return } clearInterval(timer) },1000) |
全部下載后再播放
假設(shè)播放短視頻,如果網(wǎng)絡(luò)不佳,會造成播放斷斷續(xù)續(xù),在iOS中這種停頓還沒有一個明確的等待提示,這不是一個好的體驗,那么是否可以將視頻全部下載完畢再播放呢?
在iOS中,可以在視頻剛開始下載的時候馬上暫停,此時下載還將繼續(xù),可以做一個loading的菊花告知視頻正在加載,然后等到視頻全部下載完再開始播放。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $(video).one('loadeddata',function(){ // 暫停,但下載還在繼續(xù) video.pause() // 啟動定時器檢測視頻下載進度 vartimer=setInterval(function(){ varend=getEnd(video), duration=video.duration if(end<duration){ return } varwidth=$(video).parent().width() // 下載完了,開始播放吧 $(video).attr{ width:width, height:width } video.play() clearInterval(timer) },1000) }) |
緩沖播放——邊下邊播時,選擇開始播放的最佳時間點
當視頻越來越長或者網(wǎng)絡(luò)慢時,等待視頻全部下載完再播放也不是好的體驗,最好能邊下邊播,緩沖到流暢狀態(tài)就開始播放,那什么時候播放才是最佳時間點呢?
在iOS中,canplaythrough事件就是這個最佳時間點,它是通過動態(tài)計算緩沖量和下載速度得出的視頻可以流暢播放的狀態(tài)反饋。
canplaythrough event: The user agent estimates that if playback were to be started now, the media resource could be rendered at the current playback rate all the way to its end without having to stop for further buffering.
注意:下載完再播放和緩沖播放只適用于iOS。
統(tǒng)計播放時間和播放次數(shù)
要統(tǒng)計實際的播放時間,要累加timeupdate事件變化的時間,再減去中間可能暫停的時間。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | $video.on('playing',function(){ // 開始播放是打點 $video.attr('data-updateTime',+newDate()) }) $video.on('pause',function(){ // 暫停播放時清除打點 $video.removeAttr('data-updateTime') }) // 累加播放時間 $video.on('timeupdate',function(event){ var$video=$(event.target), updateTime=parseInt($video.attr('data-updateTime')||0), playingTime=parseInt($video.attr('data-playingTime')||0), times=parseInt($video.attr('data-times')||0), newtimes=0, video=$video.get(0), duration=parseFloat($video.attr('data-duration')||0), now=+newDate() // 播放時間 playingTime=playingTime+now-updateTime // 播放次數(shù) newtimes=Math.ceil(playingTime/1000/duration) $video.attr('data-playingTime',playingTime) $video.attr('data-updateTime',now) }) |
異常處理
對error事件做詳細的上報;
對stalled事件做統(tǒng)計上報,并提示用戶網(wǎng)絡(luò)慢等。
參考數(shù)據(jù)
微視觸屏版iOS視頻測速
網(wǎng)絡(luò)環(huán)境 | 視頻碼率 | 獲取到視頻時長 時間點(s) | 開始流暢播放 時間點(s) | 全部下載完畢 時間點(s) | 視頻長度(s) |
---|---|---|---|---|---|
wifi | 1000kbps | 2.86 | 3.97 | 5.85 | 8.69 |
非wifi | 500kbps | 4.56 | 8 | 10.62 | 8.67 |
搬好凳子看HTML
首先我們在HB下創(chuàng)建一個新的app項目,名稱為 欠債
新建一個video.html
webkit-playsinline : 在ios中,加入此屬性,可以關(guān)閉自動全屏播放
object-fit:fill : 視頻充滿video容器的大小
詳細理由請看參考文獻2or3
在此我們向項目里放置一個mp4格式的視頻,視頻內(nèi)容不限,可以是小動畫,也可以是
ps:要在meta中加上,否則視頻會擴充變形哦
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
OK,現(xiàn)在布局已經(jīng)完成,一個視頻已經(jīng)在頁面中了
旁白:尼瑪,點了沒反應(yīng),那這怎么播放?
樓主:你們這群家伙看別的小視頻等個1小時都行。。。
旁白:一個簡單的播放器,至少要有 暫停/播放,進度條,視頻時長,全屏等控件吧
樓主:來來來,不要急,先來個播放按鈕寫在video標簽后面
<div class="bad-video"> <video class="" webkit-playsinline style="object-fit:fill;"> <source src='xx.mp4' type="video/mp4"></source> <p>設(shè)備不支持</p> <video> <img src="img/play.png"/> </div>
寫好樣式、
.bad-video { position: relative; overflow: hidden; background-color: #CCCCCC; } .bad-video .vplay{ position: absolute; width: 15%; z-index: 99; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); }
樓主:當當當
再在后面加一個控制條
<img src="img/play.png" class="vplay" /> <div class="controls"> <div> <div class="progressBar"> <div class="timeBar"></div> </div> </div> <div><span class="current">00:00</span>/<span class="duration">00:00</span></div> <div><span class="fill">全屏</span></div> </div>
.bad-video .controls { width: 100%; height: 2rem; line-height: 2rem; font-size: 0.8rem; color: white; display: block; position: absolute; bottom: 0; background-color: rgba(0, 0, 0, .55); display: -webkit-flex; display: flex; }.bad-video .controls>* { flex: 1; }.bad-video .controls>*:nth-child(1) { flex: 6; }.bad-video .controls>*:nth-child(2) { flex: 2; text-align: center; }.bad-video .controls .progressBar { margin: .75rem 5%; position: relative; width: 90%; height: .5rem; background-color: rgba(200, 200, 200, .55); border-radius: 10px; }.bad-video .controls .timeBar { position: absolute; top: 0; left: 0; width: 0; height: 100%; background-color: rgba(99, 110, 225, .85); border-radius: 10px; }
總算有個看起來像樣的了
旁白:樓主,可是還是不能播放啊
樓主:叫你別急,要不你先去擼一把,我寫好了文字@你
旁白:好啊,早說嘛,我先走了,記得@我
樓主:你走,省的我精神分裂碼兩個人的字
好,現(xiàn)在Html元素已經(jīng)基本上弄好啦,看起來不是那么low了
時的工作中常會遇到一些系統(tǒng)集成的需求,需要在軟件平臺集成視頻監(jiān)控系統(tǒng)。而軟件開發(fā)者往往不懂安防弱電系統(tǒng),不知道如何在自己的軟件界面中集成一些監(jiān)控的實時畫面。而監(jiān)控廠家提供的SDK比較復(fù)雜,很難在短時間完成集成的任務(wù)。最終導(dǎo)致軟件平臺的一些功能無法實現(xiàn),影響項目的質(zhì)量。
本文提供的方法主要基于VLC播放器的ActiveX插件,通過這個插件,在網(wǎng)頁中調(diào)用攝像機的RTSP流,實現(xiàn)圖像的實時預(yù)覽,音頻的監(jiān)聽等等功能。文章以海康的IP網(wǎng)絡(luò)攝像機為例給出具體的調(diào)用方法,供大家學(xué)習(xí)參照。
登錄VLC官網(wǎng) https://www.videolan.org/,選擇windows(32位)版本下載。
下載VLC軟件
運行安裝文件
選擇軟件安裝位置
一定記得要勾選網(wǎng)頁瀏覽器插件
完成安裝
可選用記事本(notepad)或?qū)I(yè)的編輯器,輸入如下代碼,保存為html網(wǎng)頁文件。
<html>
<body>
<title>TESTVDEIO-1-TEST</title>
<head>
<table>
<tbody>
<caption>視頻監(jiān)控演示</caption>
<tr>
<td>
<object type='application/x-vlc-plugin' pluginspage="http://www.videolan.org/" id='vlc' events='false' width="720" height="410">
<param name='mrl' value='rtsp://admin:q66668888@172.16.200.88:554/h264/ch1/main/av_stream' />
<param name='volume' value='50' />
<param name='autoplay' value='true' />
<param name='loop' value='false' />
<param name='fullscreen' value='false' />
<param name='controls' value='false' />
</td>
<td>
<object type='application/x-vlc-plugin' pluginspage="http://www.videolan.org/" id='vlc' events='false' width="720" height="410">
<param name='mrl' value='rtsp://admin:q66668888@172.16.200.89:554/h264/ch1/main/av_stream' />
<param name='volume' value='50' />
<param name='autoplay' value='true' />
<param name='loop' value='false' />
<param name='fullscreen' value='false' />
<param name='controls' value='false' />
</td>
</tr>
<tr>
<td>
<object type='application/x-vlc-plugin' pluginspage="http://www.videolan.org/" id='vlc' events='false' width="720" height="410">
<param name='mrl' value='rtsp://admin:q66668888@172.16.200.89:554/h264/ch1/main/av_stream' />
<param name='volume' value='50' />
<param name='autoplay' value='true' />
<param name='loop' value='false' />
<param name='fullscreen' value='false' />
<param name='controls' value='false' />
</td>
<td>
<object type='application/x-vlc-plugin' pluginspage="http://www.videolan.org/" id='vlc' events='false' width="720" height="410">
<param name='mrl' value='rtsp://admin:q66668888@172.16.200.88:554/h264/ch1/main/av_stream' />
<param name='volume' value='50' />
<param name='autoplay' value='true' />
<param name='loop' value='false' />
<param name='fullscreen' value='false' />
<param name='controls' value='false' />
</td>
</tr>
</tbody>
</table>
</object>
</body>
</html>
代碼編輯截圖
具體請參看海康專業(yè)文檔
先用Google Chrome瀏覽器測試,提示插件不支持。
Chrome瀏覽器提示插件不受支持
用微軟IE測試,需要安裝插件。
IE瀏覽器提示要安裝ActiveX插件
確認安裝插件
瀏覽器只顯示了第一個畫面。
IE瀏覽器顯示不完整
用編輯器測試,2種內(nèi)核都能正常顯示。
編輯器里測試效果
改用360瀏覽器,呈現(xiàn)2X2的畫面,實現(xiàn)最終的顯示效果。
360瀏覽器顯示的最終效果圖
本文參考了一些專業(yè)文章,就不一 一列出了,在這一并謝過!
由于本人水平有限,有不對的地方敬請指正。文章旨在拋磚引玉,通過討論,相互學(xué)習(xí),共同進步。
我是WoNew弱電蝸牛,一名從業(yè)多年的弱電工程師,在頭條傳播弱電專業(yè)知識和行業(yè)信息,分享工作中的經(jīng)驗和心得。
喜歡我的文章或視頻,歡迎點贊和轉(zhuǎn)發(fā)。有疑問或建議,也歡迎留言,我會盡力解答。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。