日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

前端视频流播放

發布時間:2023/12/2 HTML 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 前端视频流播放 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前端視頻流播放

1. 開始

最近寫了一個小功能,是在前端播放視頻流(格式flv/mp4,編碼h.264/h.265),一開始找到了LivePlayer。但很遺憾后續被告知需要支持h.265(chrome目前支持h.264編碼但不支持h.265);于是又搜尋了一番找到了Easyplayer,照著上面Vue集成的部分搞了一下,WTF居然不行?出現了跟這個issue一樣的問題,于是就換了個思路,直接把它用原生方式引入,成功了,具體操作如下:

1-1. 在npm包里找到相應文件放到public下(我多套了個文件夾,不套也可以)

1-2. 在index.html中引入資源文件

1-3. (可選)修改webpack配置

若不配置,vue-loader會報warning,提示此組件不是Vue的組件也不是標準組件庫里的組件。

configureWebpack->module->rules下:

1-4. 使用

按照文檔上HTML集成示例使用即可。

2. 錄播h.265流無法播放

這個時候已經能用了,但而后又發現了一個問題,直播推h.265的流沒有任何問題,但是錄播的流不知道為什么無法解析。后來領導從別人那順了一份舊版本的EasyPlayer說是可以,我就又看了一下,寫完發現果然可以。

舊版本集成方式和新版本一樣,就是使用起來不太一樣,使用方式可以看文檔舊版EasyPlayer。由于項目上了ts,于是又自己寫了一個聲明文件,很簡陋,湊活著用:

declare class WasmPlayer {constructor(url: string | undefined | null,id: string,cb?: (e: any) => void,opts?: {decodeType?: 'auto' | 'soft';openAudio?: boolean;BigPlay?: boolean;Height?: boolean;HideKbs?: boolean;cbUserPtr?: any;cfKbs?: (e: any) => void;}) {return}play(url: string, autoplay = 0, currentTime = 0) {return}pause() {return}destroy() {return}openAudio() {return}closeAudio() {return}startLoading() {return}endLoading() {return}fullScreen() {return}setSnap(url: string) {return}endSnap() {return} }

另外舊版本的EasyPlayer下面自帶一條無法清除的toolbar,toolbar上還有一個無法清除的logo,點擊會跳轉到官網。這個就只能在源碼里修改了,由于源代碼已經做過混淆,讓我找了半天。清除logo全局搜索this.logo.style=,并將其中的display改為none;toolbar全局搜索timeBox.style,這兩者前者還有驗證函數,會驗證logo的樣式,因此再搜索LogoTimer修改其中的驗證條件;后者會定時修改樣式為初始樣式,因此需要再搜索setTimeout,找到其中有timeBox.style的一條代碼,修改其樣式。至此大功告成。

3. 增加截圖和視頻錄制

本來我覺得這個問題大概不是什么問題,因為本身新版EasyPlayer是自帶的,但找了找發現舊版并沒有這個方法。沒辦法只能自己寫了。

一開始我以為EasyPlayer它是默認將視頻流渲染成canvas的。因此只做了對canvas的截圖和錄制。

截圖方法:

async function snapshot() {const playerEle = document.getElementById(id.value) as HTMLElementconst children = playerEle.childrenconst canvas = Object.values(children).find(child => child.tagName.toLocaleLowerCase() === 'canvas') as HTMLCanvasElementlet url = ''if (canvas) {// 由于視頻流有空白幀,渲染到canvas上后導致canvas截圖空白,故如果截圖時機不好會截出來空白的圖,因此判斷圖片大小以避免空白圖(空白圖大小<100kb)const interval = setInterval(() => {url = canvas.toDataURL('image/jpg')if (url.length > 204800) {clearInterval(interval)const aEle = document.createElement('a')aEle.setAttribute('href', url.replace('image/jpg', 'image/octet-stream'))aEle.setAttribute('download',`${props.videoOpts.channel_no}-${props.videoOpts.guid}.jpg`)aEle.click()aEle.remove()}}, 50)} }

甚至本來截圖我是沒想到它會能截出來空白的,后來發現之后給它加了個循環,直到截出正常圖片為止。

錄制方法:

let recorder: MediaRecorder let blobData: Blob[] = []function record() {const playerEle = document.getElementById(id.value) as HTMLElementconst children = playerEle.childrenconst canvas = Object.values(children).find((child) => child.tagName.toLocaleLowerCase() === 'canvas') as HTMLCanvasElementif (canvas) {const stream = canvas.captureStream(30)recorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=vp9'})recorder.ondataavailable = (e) => {blobData.push(e.data)}recorder.start(10)} }function stopRecord() {recorder.stop()const blob = new Blob(blobData)const url = window.URL.createObjectURL(blob)const aEle = document.createElement('a')aEle.setAttribute('href', url)aEle.setAttribute('download', `${props.videoOpts.channel_no}-${props.videoOpts.guid}.webm`)aEle.click()aEle.remove()blobData = [] }

本來到這也就告一段落了,結果某一天,又發現h.264視頻無法截圖也無法錄制,查找了一番發現是EasyPlayer會分析視頻編碼格式,如果是h.264格式就會利用<video>標簽簡化操作,只有h.265編碼才會轉成canvas。于是我又改了下截圖方法,至于錄制方法,我暫時不知道怎么錄制<video>播放的視頻,唯一能想到的就是每秒截圖30次拼接起來,但考慮到性能開銷太大,于是讓后端處理了,如果有大佬會的話麻煩告知一下。

改進后的截圖:

async function snapshot() {const playerEle = document.getElementById(id.value) as HTMLElementconst children = playerEle.childrenconst canvas = Object.values(children).find(child => child.tagName.toLocaleLowerCase() === 'canvas') as HTMLCanvasElementconst video = Object.values(children).find(child => child.tagName.toLocaleLowerCase() === 'video') as HTMLVideoElementlet url = ''if (canvas) {// 由于視頻流有空白幀,渲染到canvas上后導致canvas截圖空白,故如果截圖時機不好會截出來空白的圖,因此判斷圖片大小以避免空白圖(空白圖大小<100kb)const interval = setInterval(() => {url = canvas.toDataURL('image/jpg')if (url.length > 204800) {clearInterval(interval)const aEle = document.createElement('a')aEle.setAttribute('href', url.replace('image/jpg', 'image/octet-stream'))aEle.setAttribute('download',`${props.videoOpts.channel_no}-${props.videoOpts.guid}.jpg`)aEle.click()aEle.remove()}}, 50)} else if (video) {const target = await html2canvas(video)url = target.toDataURL('image/jpg')const aEle = document.createElement('a')aEle.setAttribute('href', url.replace('image/jpg', 'image/octet-stream'))aEle.setAttribute('download', `${props.videoOpts.channel_no}-${props.videoOpts.guid}.jpg`)aEle.click()aEle.remove()} else {message.error('不支持的dom類型')return} }

其中video的截圖使用了html2canvas。

至此整個視頻流播放問題都解決了,以后說不定還會再用ffmpeg自己寫一個視頻流解析的組件。

總結

以上是生活随笔為你收集整理的前端视频流播放的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。