淺談video標(biāo)簽在移動(dòng)端的運(yùn)用

最近在移動(dòng)端項(xiàng)目用到了video標(biāo)簽展示視頻恒削,原本以為作為html5標(biāo)準(zhǔn)一員的video到了今天兼容性應(yīng)該沒什么問題了,可一用才知道還是有些坑的......那么在這里就由淺入深的論述一下使用video的心得吧(一些眾所周知的常用屬性和我沒怎么用過的在此均省略不表)尾序。

屬性

  • src
    要播放的視頻的 URL蔓同。只支持3種格式:MP4、WebM蹲诀、Ogg斑粱。另外src除了可以使用放在服務(wù)器的絕對路徑和項(xiàng)目中的相對路徑(對于本地路徑在PC端有一些限制,移動(dòng)端貌似無法取到本地視頻)脯爪,還支持 base64碼(需添加前綴data:video/mp4;base64, 注意有逗號)
  • poster
    規(guī)定視頻正在下載時(shí)顯示的圖像则北,直到用戶點(diǎn)擊播放按鈕。(也就是視頻播放之前顯示的一個(gè)預(yù)覽圖)其值和img標(biāo)簽的src屬性相同痕慢,填上一個(gè)圖片路徑或者base64尚揣。
  • playsinline webkit-playsinline
    視頻在移動(dòng)端播放時(shí)會(huì)自動(dòng)全屏,而這個(gè)屬性就是為了阻止全屏動(dòng)作的掖举,添加-webkit-前綴增加在ios safari上的兼容性快骗。(只用寫上屬性名就行,和autoplay,loop之類的類似)
  • muted
    如果出現(xiàn)該屬性塔次,視頻的音頻輸出為靜音方篮。
  • autoplay
    自動(dòng)播放,但是在ios上無法執(zhí)行自動(dòng)播放......(添加muted可以自動(dòng)播放)需要用戶執(zhí)行play方法励负。(具體可參考視頻播放--踩坑小計(jì)

以上幾種屬性是寫video標(biāo)簽時(shí)經(jīng)常設(shè)置的幾種屬性藕溅,以下的幾種則一般是需要在js中獲取的屬性,以便進(jìn)行一些操作继榆。

  • networkState
    返回音頻/視頻的當(dāng)前網(wǎng)絡(luò)狀態(tài)(activity)巾表。
    返回值如下
    • 0 = NETWORK_EMPTY - 音頻/視頻尚未初始化
    • 1 = NETWORK_IDLE - 音頻/視頻是活動(dòng)的且已選取資源,但并未使用網(wǎng)絡(luò)
    • 2 = NETWORK_LOADING - 瀏覽器正在下載數(shù)據(jù)
    • 3 = NETWORK_NO_SOURCE - 未找到音頻/視頻來源

一般用到的就是1和2,當(dāng)值為1的時(shí)候表示視頻已經(jīng)可以播放了(至少是當(dāng)前幀已經(jīng)加載好了略吨,不過ios此時(shí)播放可能會(huì)白屏)集币,值為2的時(shí)候播放下一幀會(huì)卡住(安卓)或者白屏(ios)。

注意:
  1. 返回的值是Number類型,這使得在使用mint-ui這類的ui框架調(diào)試時(shí)可能會(huì)Toast一個(gè)空值,需要先轉(zhuǎn)為字符串才能顯示翠忠。
  2. 關(guān)于ios上返回2繼續(xù)播放會(huì)白屏的問題(僅僅出現(xiàn)在視頻第一次點(diǎn)擊播放的時(shí)候)鞠苟,這里我暫時(shí)沒發(fā)現(xiàn)是什么原因?qū)е碌模ㄓ锌赡苁且曨l太大??)
  • readyState
    readyState 屬性返回音頻/視頻的當(dāng)前就緒狀態(tài)偶妖。
    返回值如下
    • 0 = HAVE_NOTHING - 沒有關(guān)于音頻/視頻是否就緒的信息
    • 1 = HAVE_METADATA - 關(guān)于音頻/視頻就緒的元數(shù)據(jù)
    • 2 = HAVE_CURRENT_DATA - 關(guān)于當(dāng)前播放位置的數(shù)據(jù)是可用的姜凄,但沒有足夠的數(shù)據(jù)來播放下一幀/毫秒
    • 3 = HAVE_FUTURE_DATA - 當(dāng)前及至少下一幀的數(shù)據(jù)是可用的
    • 4 = HAVE_ENOUGH_DATA - 可用數(shù)據(jù)足以開始播放
      這里的返回值也是Number類型的

我在項(xiàng)目中先使用的就是這個(gè)屬性,在返回1或2的時(shí)候代表剛進(jìn)入這個(gè)頁面瀏覽器還在加載視頻趾访,返回4則代表整個(gè)視頻已經(jīng)加載完畢了态秧。可是我發(fā)現(xiàn)ios在返回3的時(shí)候立即播放還是有時(shí)會(huì)出現(xiàn)白屏扼鞋,而安卓在返回3的時(shí)候是可以播放的申鱼,因此最后我選擇了使用networkState來對視頻加載狀態(tài)進(jìn)行判斷。

  • 不可思議的currentTime
    定義是這么說的:設(shè)置或返回音頻/視頻播放的當(dāng)前位置(以秒計(jì))云头。當(dāng)設(shè)置該屬性時(shí)捐友,播放會(huì)跳躍到指定的位置。
    而我使用這個(gè)屬性來判斷視頻是否能連續(xù)播放溃槐,當(dāng)視頻播放的時(shí)候如果這個(gè)屬性的值‘走動(dòng)了’匣砖,可以認(rèn)為視頻已經(jīng)可以播放下一幀了。感謝h5 video 移動(dòng)端填坑記這篇文章提供的方法昏滴。

方法

我一般用到的方法也就是play(),pause()這里不過多贅述猴鲫。

事件

  • canplay
    當(dāng)瀏覽器能夠開始播放指定的音頻/視頻時(shí),會(huì)發(fā)生 canplay 事件谣殊。
    乍一看有了這個(gè)事件似乎就不需要上面各種state去判斷視頻能否播放了拂共,可惜萬惡的ios不支持這個(gè)事件,實(shí)測第一次進(jìn)入頁面ios在canplay事件觸發(fā)的時(shí)候視頻的networkState仍然處于2這個(gè)狀態(tài)姻几,也就是還未加載完成......
  • progress
    當(dāng)瀏覽器正在下載指定的音頻/視頻時(shí)宜狐,會(huì)發(fā)生 progress 事件。
    我使用這個(gè)事件的方向可能有點(diǎn)‘歪門邪道’蛇捌,眾所周知一個(gè)視頻在頁面加載的時(shí)候等待時(shí)間或許會(huì)有點(diǎn)長抚恒,一般網(wǎng)站使用的是一個(gè)圖片或者gif去代替video標(biāo)簽,當(dāng)視頻加載好了的時(shí)候就讓video顯示出來豁陆。而上面的canplay用不了柑爸,所以我抱著試試的想法在progress事件觸發(fā)的時(shí)候讓loading圖隱藏起來(loading圖默認(rèn)顯示),結(jié)果實(shí)際效果讓我很滿意盒音,progress事件觸發(fā)的時(shí)候視頻的poster已經(jīng)顯示出來了,我初步判斷第一次觸發(fā)這個(gè)事件應(yīng)該是視頻第一幀可能前幾幀都加載好了馅而。
  • timeupdate
    timeupdate 事件在音頻/視頻(audio/video)的播放位置發(fā)生改變時(shí)觸發(fā)祥诽。
    這個(gè)事件一看就是結(jié)合上面的currentTime屬性用的。在后文我會(huì)詳述瓮恭。
  • waiting
    waiting 事件在視頻由于需要緩沖下一幀而停止時(shí)觸發(fā)雄坪。
    在我的項(xiàng)目用它主要是因?yàn)閕os白屏的時(shí)候會(huì)觸發(fā)這個(gè)事件......這樣我可以在這個(gè)事件中讓視頻暫停。
  • ended
    ended 事件在音頻/視頻(audio/video)播放完成后觸發(fā)屯蹦。
    由于我的視頻沒有用loop屬性所以我使用這個(gè)事件來提示用戶視頻播放結(jié)束维哈。

應(yīng)用

項(xiàng)目基于vue绳姨,ui框架使用的是mint-ui,還是直接上代碼吧...

    <div class="video-con fl">
        <div class="video" @click="$_videoFromApp_getVideoRecord">
            <!-- 后臺(tái)沒有視頻時(shí)顯示的內(nèi)容 -->
            <img class="no-video" v-show="videoFromApp_noVideo" :src="require('@/images/icon/video.png')" alt="">
            <div class="bg-gray" v-show="videoFromApp_noVideo"></div>
            <!-- 視頻處于暫停時(shí)顯示的內(nèi)容 -->
            <div v-show="!videoFromApp_playing">
                <img class="play-video" v-show="!videoFromApp_noVideo"
                     :src="require('@/images/icon/play-video.png')" alt="">
                <span class="play-time" v-show="!videoFromApp_noVideo">{{videoFromApp_videoTime}}</span>
            </div>
            <!-- loading -->
            <mt-spinner v-show="videoFromApp_loading" class="loading-css" type="fading-circle"></mt-spinner>
            <!-- 視頻 -->
            <video webkit-playsinline playsinline
                   ref="indentVideo"
                   class="real-video"
                   :src="videoFromApp_videoSrc"
                   v-show="!videoFromApp_noVideo"
                   :poster="videoFromApp_videoImg"
                   @progress="$_videoFromApp_hasVideo"
                   @waiting="$_videoFromApp_waiting"
                   @ended="$_videoFromApp_endVideo"></video>
        </div>
    </div>

js部分

<script>
......
        //播放視頻
        $_videoFromApp_getVideoRecord(v){
           ......
            if (this.videoFromApp_playing) {
                    this.videoFromApp_playing = false;
                    this.$refs.indentVideo.pause();
                } else {
                    this.videoFromApp_playing = true;
                    let video = this.$refs.indentVideo;
                    let networkState = this.$refs.indentVideo.networkState;
                    let readyState = this.$refs.indentVideo.readyState;
                    if(networkState==1){
                        this.$refs.indentVideo.play();
                        this.videoFromApp_loading = true;
                        video.ontimeupdate = ()=>{
                            if(video.currentTime > 0.1){
                                this.videoFromApp_loading = false;
                            }
                        }
                    }else{
                        Toast({
                            message: '拼命加載中阔挠,請稍后',
                            position: 'bottom',
                            duration: 1000
                        });
                        this.videoFromApp_playing = false;
                    }
                }
        },
        //視頻初步加載
        $_videoFromApp_hasVideo(){
            this.videoFromApp_loading = false;
        },
        //緩沖
        $_videoFromApp_waiting(){
            this.$refs.indentVideo.pause();
            this.videoFromApp_playing = false;
            Toast({
                message: '拼命加載中飘庄,請稍后',
                position: 'bottom',
                duration: 1000
            });
        },
        //視頻播放完成
        $_videoFromApp_endVideo(){
            this.videoFromApp_playing = false;
        },
</script>

在此就簡述一下播放視頻方法,當(dāng)視頻處于暫停狀態(tài)時(shí)购撼,點(diǎn)擊播放跪削,判斷networkState,當(dāng)值為1的時(shí)候允許播放,此時(shí)監(jiān)聽timeupdate事件迂求,(使用addEventListener監(jiān)聽會(huì)有毛病碾盐,如果看過我之前的一篇關(guān)于iframe的文章應(yīng)該會(huì)有所了解)先加上loading,如果currentTime > 0.1代表視頻已經(jīng)能流暢播放了揩局,再隱藏loading毫玖。這個(gè)過程中如果無法播放的話就會(huì)走到waitting事件中,視頻會(huì)暫停凌盯。
再次點(diǎn)擊繼續(xù)重復(fù)這個(gè)過程直到視頻可以正常播放孕豹。

寫在后面

其實(shí)吧本文寫作的真正目的是為了拋磚引玉,文中所寫的一些方法只為解決項(xiàng)目中的燃眉之急十气,文中部分內(nèi)容僅僅為個(gè)人觀點(diǎn)励背,如果各位讀者發(fā)現(xiàn)了文中的缺陷與問題,歡迎在評論區(qū)留言探討砸西。

======================
2018-11-12更新
關(guān)于播放白屏的原因:最近發(fā)現(xiàn)安卓部分手機(jī)播放視頻又白屏了叶眉,最終總結(jié)出了避免白屏的方法。
1.播放視頻的格式最好是mp4 avc h.264格式的芹枷,不是這種格式的視頻用video播放很可能白屏衅疙。
2.如果視頻格式已經(jīng)是avch264的了那么就需要看看是后臺(tái)原因還是原生那邊的原因了,一般來說應(yīng)該是后臺(tái)的問題鸳慈,ios目前獲取視頻的時(shí)候請求頭會(huì)帶一個(gè)與斷點(diǎn)續(xù)傳有關(guān)的信息饱溢,后臺(tái)需要對此進(jìn)行相應(yīng)的配置。而部分安卓手機(jī)也會(huì)用類似的方式請求視頻走芋,目前項(xiàng)目里的后臺(tái)同事將返回的狀態(tài)碼從200改成了206就ok了绩郎。

最后,轉(zhuǎn)載請注明出處http://www.reibang.com/p/8f39050aa607

本文參考文章
視頻播放--踩坑小計(jì)
h5 video 移動(dòng)端填坑記
移動(dòng)端實(shí)踐 - video

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末翁逞,一起剝皮案震驚了整個(gè)濱河市肋杖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挖函,老刑警劉巖迈着,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姆蘸,死亡現(xiàn)場離奇詭異境蔼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)振定,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肉拓,“玉大人后频,你說我怎么就攤上這事〉鄞兀” “怎么了徘郭?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長丧肴。 經(jīng)常有香客問我残揉,道長,這世上最難降的妖魔是什么芋浮? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任抱环,我火速辦了婚禮,結(jié)果婚禮上纸巷,老公的妹妹穿的比我還像新娘镇草。我一直安慰自己,他們只是感情好瘤旨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布梯啤。 她就那樣靜靜地躺著,像睡著了一般存哲。 火紅的嫁衣襯著肌膚如雪因宇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天祟偷,我揣著相機(jī)與錄音察滑,去河邊找鬼。 笑死修肠,一個(gè)胖子當(dāng)著我的面吹牛贺辰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嵌施,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼饲化,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了艰管?” 一聲冷哼從身側(cè)響起滓侍,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎牲芋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缸浦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年夕冲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裂逐。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡歹鱼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卜高,到底是詐尸還是另有隱情弥姻,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布掺涛,位于F島的核電站庭敦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏薪缆。R本人自食惡果不足惜秧廉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拣帽。 院中可真熱鬧疼电,春花似錦、人聲如沸减拭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拧粪。三九已至修陡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間既们,已是汗流浹背濒析。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啥纸,地道東北人号杏。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像斯棒,于是被迫代替她去往敵國和親盾致。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355