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