瀏覽器中視頻播放器實(shí)現(xiàn)的基本思路與代碼
前言
自定義個(gè)播放器,組件都是用的原生的,所以有點(diǎn)丑,重點(diǎn)關(guān)注業(yè)務(wù)邏輯吧。
界面大概長下面這個(gè)樣子。
大家可以看著界面,在腦海中想一下自己會(huì)如何實(shí)現(xiàn)這個(gè)視頻播放器??梢詥栕约阂韵聨讉€(gè)問題:
- 這個(gè)組件會(huì)接受那些props
- 如何獲取視頻的基本信息,包括時(shí)長,分辨率等
- 暫停、播放如何實(shí)現(xiàn)
- 拖動(dòng)進(jìn)度條的邏輯如何實(shí)現(xiàn)
- 視頻初始加載顯示loading如何處理
- 視頻播放過程中卡頓顯示loading如何處理
瀏覽器中的音視頻知識總結(jié)
視頻編碼
視頻,其實(shí)就是一系列連續(xù)播放的圖片,如果1s鐘播放24張圖片,視頻的幀率就是24。
如果視頻的的尺寸是1920*1080,即一張圖片的尺寸是1920*1080*3 bytes,乘3是因?yàn)橐粋€(gè)像素點(diǎn)3個(gè)比特,分別存放rbg,那么一個(gè)30分鐘的視頻所需要的存儲(chǔ)空間如下:
//1s視頻需要的存儲(chǔ)空間為: 1920*1080*3*24 bytes //30min視頻需要的存儲(chǔ)空間: 1920*1080*3*24 * 60*30=250.28GB
可以看到,非常大,所以視頻需要壓縮,于是就有了編碼(codec)的概念。視頻的編碼格式可以理解為壓縮格式,不同的編碼格式壓縮率不同,常見的編碼格式有 h264,mpeg4,vp8等。
此外,需要注意的一點(diǎn)是,因?yàn)榫幋a格式是有版權(quán)問題的,所以不同的瀏覽器支持的編碼格式不同,所以就會(huì)出現(xiàn)有些編碼格式的視頻在某些瀏覽器播放不了,或者只有聲音沒有畫面的情況。
我們前端開發(fā)只需要記住一點(diǎn),主流瀏覽器支持的視頻編碼格式是h264。
封裝格式
一個(gè)視頻文件內(nèi)會(huì)包含視頻流和音頻流,還有一些元數(shù)據(jù),例如分辨率信息,標(biāo)題等,這個(gè)文件的格式我們稱為封裝格式,可以理解為打包格式,常見的mp4,webp,mov,mpeg等都是封裝格式。
封裝格式往往是與視頻編碼無關(guān)的,一個(gè)mp4文件,里面的視頻流編碼可以是h264,也可以是mpeg,所以就會(huì)出現(xiàn),同樣都是mp4文件,有的瀏覽器可以放,有的瀏覽器就放不了的問題。
音視頻標(biāo)簽
<video controls poster="1.jpg" src="1.mp4" loop muted></video> <audio controls src="1.mp3"></audio>
src指定資源地址,poster為視頻指定一張封面圖,controls表示瀏覽器應(yīng)該顯示UI控件(每個(gè)瀏覽器樣式不同)
常用屬性
下面是video和audio的通用屬性
常用事件
video和audio通用事件
常用方法
- play() 控制視頻開始播放
- pause() 控制視頻暫停播放
有了上述的屬性、事件及方法,我們就可以做很多事了,比如自定義播放器,使用播放器本地預(yù)覽視頻等。
整體思路如下
- 該組件接收一個(gè)視頻的src作為參數(shù)
- 監(jiān)聽onLoadedMetadata事件,獲取視頻時(shí)長(duration),真實(shí)寬高(videoWidth,videoHeight)
- 點(diǎn)擊播放/暫停時(shí),調(diào)用視頻元素的play/pause方法
- 播放時(shí),監(jiān)聽onTimeUpdate,獲取當(dāng)前播放時(shí)間(currentTime),計(jì)算出進(jìn)度條的進(jìn)度
- 拖動(dòng)進(jìn)度條,設(shè)置視頻當(dāng)前播放時(shí)間,與步驟4相反
- 視頻初始加載時(shí),顯示loading。即組件初次渲染時(shí),loading屬性默認(rèn)為true,即顯示加載效果,當(dāng)視頻元數(shù)據(jù)加載時(shí),取消loading
- 視頻卡頓時(shí),顯示loading。該功能的實(shí)現(xiàn)是監(jiān)聽的onWaiting事件,不卡頓時(shí),取消loading,監(jiān)聽的是onCanPlay事件
代碼實(shí)現(xiàn)
代碼是用React實(shí)現(xiàn)的,用Vue也是一樣的,關(guān)注業(yè)務(wù)邏輯即可。如果大家有需求,我可以再更新下這篇文章,添加上Vue的代碼。
注意:dom原生事件在react中需要前面加個(gè)on,然后寫成駝峰的形式
function formatDuration(duration) { var sec_num = parseInt(duration, 10); // don't forget the second param var hours = Math.floor(sec_num / 3600); var minutes = Math.floor((sec_num - (hours * 3600)) / 60); var seconds = sec_num - (hours * 3600) - (minutes * 60); if (hours < 10) {hours = "0"+hours;} if (minutes < 10) {minutes = "0"+minutes;} if (seconds < 10) {seconds = "0"+seconds;} return hours+':'+minutes+':'+seconds; } import React, { createRef, useState } from 'react' import './VideoPlayer.css' function VideoPlayer({src}){ const videoDom=createRef() // 視頻當(dāng)前播放時(shí)間 const [curTime,setCurTime]=useState(0) // 視頻時(shí)長 const [duration,setDuration]=useState(0) // 視頻狀態(tài),是否暫停 const [isPause,setPause]=useState(true) // 視頻真是尺寸 const [size,setSize]=useState({width:1920,height:1080}) // 視頻加載中 const [waiting,setWaiting]=useState(true) // 視頻元數(shù)據(jù)加載成功 const onLoad=(e)=>{ const {duration,videoWidth,videoHeight}=e.target setDuration(duration) setSize({width:videoWidth,height:videoHeight}) setWaiting(false) } // 控制播放暫停 const handlePlay=(play)=>{ const v=videoDom.current if(play){ setPause(false) v.play() }else{ setPause(true) v.pause() } } // 拖動(dòng)slider時(shí)改變視頻currentTime const onSliderChange=(e)=>{ setCurTime(e.target.value) videoDom.current.currentTime=e.target.value } // 監(jiān)聽video timeupdate const onTimeUpdate=()=>{ const v=videoDom.current setCurTime(v.currentTime) if(v.ended){ handlePlay(false) v.currentTime=0 } } // 卡頓時(shí),顯示加載中提示 const onWaiting=()=>{ setWaiting(true) } // 可以播放時(shí),隱藏加載中提示 const onCanPlay=()=>{ setWaiting(false) } return <div className="video-wrapper"> <video ref={videoDom} src={src} onLoadedMetadata={onLoad} onTimeUpdate={onTimeUpdate} onWaiting={onWaiting} onCanPlay={onCanPlay} ></video> {/* 視頻加載時(shí)顯示loading */} {waiting && <div className="waiting">loading...</div>} <div className="video-controls"> {/* 播放按鈕 */} {isPause? <button onClick={()=>{handlePlay(true)}}>播放</button>: <button onClick={()=>{handlePlay(false)}}>暫停</button>} {/* 進(jìn)度條 */} <input type="range" min="0" max={duration} value={curTime} onChange={onSliderChange}/> {/* 時(shí)間信息和分辨率信息 */} <span>{formatDuration(curTime)}/{formatDuration(duration)}</span> <span>分辨率:{size.width}x{size.height}</span> </div> </div> } export default VideoPlayer
樣式寫了一點(diǎn)點(diǎn),VideoPlayer.css
.video-wrapper{ width:800px; } .video-wrapper>video{ width: 100%; } .video-controls{ margin-top: 20px; }
本文的重點(diǎn)不在于React,React只是一個(gè)載體,同樣的邏輯可以很容易地用Vue實(shí)現(xiàn),重點(diǎn)在于自定義一個(gè)視頻播放器的邏輯。
總結(jié)
到此這篇關(guān)于瀏覽器中視頻播放器實(shí)現(xiàn)的基本思路與代碼的文章就介紹到這了,更多相關(guān)瀏覽器中視頻播放器實(shí)現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React如何實(shí)現(xiàn)像Vue一樣將css和js寫在同一文件
這篇文章主要介紹了React如何實(shí)現(xiàn)像Vue一樣將css和js寫在同一文件問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01簡易的redux?createStore手寫實(shí)現(xiàn)示例
這篇文章主要介紹了簡易的redux?createStore手寫實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10React報(bào)錯(cuò)之Parameter event implicitly has a
這篇文章主要為大家介紹了React報(bào)錯(cuò)之Parameter event implicitly has an any type,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08詳解如何優(yōu)雅地在React項(xiàng)目中使用Redux
這篇文章主要介紹了詳解如何優(yōu)雅地在React項(xiàng)目中使用Redux,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12