观看麻豆影视文化有限公司-国产 高清 在线-国产 日韩 欧美 亚洲-国产 日韩 欧美 综合-日日夜夜免费精品视频-日日夜夜噜

ea7是什么意思(聽ea7是什么意思)

  • 生活
  • 2023-04-21 11:57

自從HTML5提供了video標(biāo)簽,在網(wǎng)頁中播放視頻已經(jīng)變成一個(gè)非常簡(jiǎn)單的事,只要一個(gè)video標(biāo)簽,src屬性設(shè)置為視頻的地址就完事了。由于src指向真實(shí)的視頻網(wǎng)絡(luò)地址,在早期一般網(wǎng)站資源文件不怎么通過referer設(shè)置防盜鏈,當(dāng)我們拿到視頻的地址后可以隨意的下載或使用(每次放假回家,就會(huì)有親戚找我?guī)兔囊恍┮曨l網(wǎng)站上下東西)。

目前的云存儲(chǔ)服務(wù)商大部分都支持referer防盜鏈。其原理就是在訪問資源時(shí),請(qǐng)求頭會(huì)帶上發(fā)起請(qǐng)求的頁面地址,判斷其不存在(表示直接訪問圖片地址)或不在白名單內(nèi),即為盜鏈。

可是從某個(gè)時(shí)間開始我們打開調(diào)試工具去看各大視頻網(wǎng)站的視頻src會(huì)發(fā)現(xiàn),它們統(tǒng)統(tǒng)變成了這樣的形式。

拿b站的一個(gè)視頻來看,紅框中的視頻地址,這個(gè)blob是個(gè)什么東西?。

其實(shí)這個(gè)BlobURL也不是什么新技術(shù),國(guó)內(nèi)外出來都有一陣子了,但是網(wǎng)上的相關(guān)的文章不多也不是很詳細(xì),今天就和大家一起分享學(xué)習(xí)一下。

Blob和ArrayBuffer

最早是數(shù)據(jù)庫(kù)直接用Blob來存儲(chǔ)二進(jìn)制數(shù)據(jù)對(duì)象,這樣就不用關(guān)注存儲(chǔ)數(shù)據(jù)的格式了。在web領(lǐng)域,Blob對(duì)象表示一個(gè)只讀原始數(shù)據(jù)的類文件對(duì)象,雖然是二進(jìn)制原始數(shù)據(jù)但是類似文件的對(duì)象,因此可以像操作文件對(duì)象一樣操作Blob對(duì)象。

ArrayBuffer對(duì)象用來表示通用的、固定長(zhǎng)度的原始二進(jìn)制數(shù)據(jù)緩沖區(qū)。我們可以通過newArrayBuffer(length)來獲得一片連續(xù)的內(nèi)存空間,它不能直接讀寫,但可根據(jù)需要將其傳遞到TypedArray視圖或DataView對(duì)象來解釋原始緩沖區(qū)。實(shí)際上視圖只是給你提供了一個(gè)某種類型的讀寫接口,讓你可以操作ArrayBuffer里的數(shù)據(jù)。TypedArray需指定一個(gè)數(shù)組類型來保證數(shù)組成員都是同一個(gè)數(shù)據(jù)類型,而DataView數(shù)組成員可以是不同的數(shù)據(jù)類型。

TypedArray視圖的類型數(shù)組對(duì)象有以下幾個(gè):

Int8Array:8位有符號(hào)整數(shù),長(zhǎng)度1個(gè)字節(jié)。Uint8Array:8位無符號(hào)整數(shù),長(zhǎng)度1個(gè)字節(jié)。Uint8ClampedArray:8位無符號(hào)整數(shù),長(zhǎng)度1個(gè)字節(jié),溢出處理不同。Int16Array:16位有符號(hào)整數(shù),長(zhǎng)度2個(gè)字節(jié)。Uint16Array:16位無符號(hào)整數(shù),長(zhǎng)度2個(gè)字節(jié)。Int32Array:32位有符號(hào)整數(shù),長(zhǎng)度4個(gè)字節(jié)。Uint32Array:32位無符號(hào)整數(shù),長(zhǎng)度4個(gè)字節(jié)。Float32Array:32位浮點(diǎn)數(shù),長(zhǎng)度4個(gè)字節(jié)。Float64Array:64位浮點(diǎn)數(shù),長(zhǎng)度8個(gè)字節(jié)。

Blob與ArrayBuffer的區(qū)別是,除了原始字節(jié)以外它還提供了mimetype作為元數(shù)據(jù),Blob和ArrayBuffer之間可以進(jìn)行轉(zhuǎn)換。

File對(duì)象其實(shí)繼承自Blob對(duì)象,并提供了提供了name,lastModifiedDate,size,type等基礎(chǔ)元數(shù)據(jù)。

創(chuàng)建Blob對(duì)象并轉(zhuǎn)換成ArrayBuffer:

//創(chuàng)建一個(gè)以二進(jìn)制數(shù)據(jù)存儲(chǔ)的html文件consttext="<div>helloworld</div>";constblob=newBlob([text],{type:"text/html"});//Blob{size:22,type:"text/html"}//以文本讀取consttextReader=newFileReader();textReader.readAsText(blob);textReader.onload=function(){console.log(textReader.result);//<div>helloworld</div>};//以ArrayBuffer形式讀取constbufReader=newFileReader();bufReader.readAsArrayBuffer(blob);bufReader.onload=function(){console.log(newUint8Array(bufReader.result));//Uint8Array(22)[60,100,105,118,62,104,101,108,108,111,32,119,111,114,108,100,60,47,100,105,118,62]};

創(chuàng)建一個(gè)相同數(shù)據(jù)的ArrayBuffer,并轉(zhuǎn)換成Blob:

//我們直接創(chuàng)建一個(gè)Uint8Array并填入上面的數(shù)據(jù)constu8Buf=newUint8Array([60,100,105,118,62,104,101,108,108,111,32,119,111,114,108,100,60,47,100,105,118,62]);constu8Blob=newBlob([u8Buf],{type:"text/html"});//Blob{size:22,type:"text/html"}consttextReader=newFileReader();textReader.readAsText(u8Blob);textReader.onload=function(){console.log(textReader.result);//同樣得到div>helloworld</div>};

更多Blob和ArrayBuffer的相關(guān)內(nèi)容可以參看下面的資料:

MDNBlobMDNArrayBuffer阮一峰js標(biāo)準(zhǔn)參考教程二進(jìn)制數(shù)組

URL.createObjectURL

video標(biāo)簽,audio標(biāo)簽還是img標(biāo)簽的src屬性,不管是相對(duì)路徑,絕對(duì)路徑,或者一個(gè)網(wǎng)絡(luò)地址,歸根結(jié)底都是指向一個(gè)文件資源的地址。既然我們知道了Blob其實(shí)是一個(gè)可以當(dāng)作文件用的二進(jìn)制數(shù)據(jù),那么只要我們可以生成一個(gè)指向Blob的地址,是不是就可以用在這些標(biāo)簽的src屬性上,答案肯定是可以的,這里我們要用到的就是URL.createObjectURL()。

constobjectURL=URL.createObjectURL(object);//blob:http://localhost:1234/abcedfgh-1234-1234-1234-abcdefghijkl復(fù)制代碼

這里的object參數(shù)是用于創(chuàng)建URL的File對(duì)象、Blob對(duì)象或者M(jìn)ediaSource對(duì)象,生成的鏈接就是以blob:開頭的一段地址,表示指向的是一個(gè)二進(jìn)制數(shù)據(jù)。

其中l(wèi)ocalhost:1234是當(dāng)前網(wǎng)頁的主機(jī)名稱和端口號(hào),也就是location.host,而且這個(gè)BlobURL是可以直接訪問的。需要注意的是,即使是同樣的二進(jìn)制數(shù)據(jù),每調(diào)用一次URL.createObjectURL***,就會(huì)得到一個(gè)不一樣的BlobURL。這個(gè)URL的存在時(shí)間,等同于網(wǎng)頁的存在時(shí)間,一旦網(wǎng)頁刷新或卸載,這個(gè)BlobURL就失效。

通過URL.revokeObjectURL(objectURL)釋放一個(gè)之前已經(jīng)存在的、通過調(diào)用URL.createObjectURL()創(chuàng)建的URL對(duì)象。當(dāng)你結(jié)束使用某個(gè)URL對(duì)象之后,應(yīng)該通過調(diào)用這個(gè)***來讓瀏覽器知道不用在內(nèi)存中繼續(xù)保留對(duì)這個(gè)文件的引用了,允許平臺(tái)在合適的時(shí)機(jī)進(jìn)行垃圾收集。

如果是以文件協(xié)議打開的html文件(即url為file://開頭),則地址中http://localhost:1234會(huì)變成null,而且此時(shí)這個(gè)BlobURL是無法直接訪問的。

實(shí)戰(zhàn)一:上傳圖片預(yù)覽

有時(shí)我們通過input上傳圖片文件之前,會(huì)希望可以預(yù)覽一下圖片,這個(gè)時(shí)候就可以通過前面所學(xué)到的東西實(shí)現(xiàn),而且非常簡(jiǎn)單。

html

<inputid="upload"type="file"/><imgid="preview"src=""alt="預(yù)覽"/>

javascript

constupload=document.querySelector("#upload");constpreview=document.querySelector("#preview");upload.onchange=function(){constfile=upload.files[0];//File對(duì)象constsrc=URL.createObjectURL(file);preview.src=src;};

這樣一個(gè)圖片上傳預(yù)覽就實(shí)現(xiàn)了,同樣這個(gè)***也適用于上傳視頻的預(yù)覽。

實(shí)戰(zhàn)二:以BlobURL加載網(wǎng)絡(luò)視頻

現(xiàn)在我們有一個(gè)網(wǎng)絡(luò)視頻的地址,怎么能將這個(gè)視頻地址變成BlobURL是形式呢,思路肯定是先要拿到存儲(chǔ)這個(gè)視頻原始數(shù)據(jù)的Blob對(duì)象,但是不同于input上傳可以直接拿到File對(duì)象,我們只有一個(gè)網(wǎng)絡(luò)地址。

我們知道平時(shí)請(qǐng)求接口我們可以使用xhr(jquery里的ajax和axios就是封裝的這個(gè))或fetch,請(qǐng)求一個(gè)服務(wù)端地址可以返回我們相應(yīng)的數(shù)據(jù),那如果我們用xhr或者fetch去請(qǐng)求一個(gè)圖片或視頻地址會(huì)返回什么呢?當(dāng)然是返回圖片和視頻的數(shù)據(jù),只不過要設(shè)置正確responseType才能拿到我們想要的格式數(shù)據(jù)。

functionajax(url,cb){constxhr=newXMLHttpRequest();xhr.open("get",url);xhr.responseType="blob";//""|"text"-字符串"blob"-Blob對(duì)象"arraybuffer"-ArrayBuffer對(duì)象xhr.onload=function(){cb(xhr.response);};xhr.send();}

注意XMLHttpRequest和FetchAPI請(qǐng)求會(huì)有跨域問題,可以通過跨域資源共享(CORS)解決。

看到responseType可以設(shè)置blob和arraybuffer我們應(yīng)該就有譜了,請(qǐng)求返回一個(gè)Blob對(duì)象,或者返回ArrayBuffer對(duì)象轉(zhuǎn)換成Blob對(duì)象,然后通過createObjectURL生成地址賦值給視頻的src屬性就可以了,這里我們直接請(qǐng)求一個(gè)Blob對(duì)象。

ajax('video.mp4',function(res){constsrc=URL.createObjectURL(res);video.src=src;})

用調(diào)試工具查看視頻標(biāo)簽的src屬性已經(jīng)變成一個(gè)BlobURL,表面上看起來是不是和各大視頻網(wǎng)站形式一致了,但是考慮一個(gè)問題,這種形式要等到請(qǐng)求完全部視頻數(shù)據(jù)才能播放,小視頻還好說,要是視頻資源大一點(diǎn)豈不爆炸,顯然各大視頻網(wǎng)站不可能這么干。

解決這個(gè)問題的***就是流媒體,其帶給我們最直觀體驗(yàn)就是使媒體文件可以邊下邊播(像我這樣的90后男性最早體會(huì)到流媒體好處的應(yīng)該是源于那款快子頭的播放器),web端如果要使用流媒體,有多個(gè)流媒體協(xié)議可以供我們選擇。

HLS和MPEGDASH

HLS(HTTPLiveStreaming),是由Apple公司實(shí)現(xiàn)的基于HTTP的媒體流傳輸協(xié)議。HLS以ts為傳輸格式,m3u8為索引文件(文件中包含了所要用到的ts文件名稱,時(shí)長(zhǎng)等信息,可以用播放器播放,也可以用vscode之類的編輯器打開查看),在移動(dòng)端大部分瀏覽器都支持,也就是說你可以用video標(biāo)簽直接加載一個(gè)m3u8文件播放視頻或者直播,但是在pc端,除了蘋果的Safari,需要引入庫(kù)來支持。

用到此方案的視頻網(wǎng)站比如優(yōu)酷,可以在視頻播放時(shí)通過調(diào)試查看Network里的xhr請(qǐng)求,會(huì)發(fā)現(xiàn)一個(gè)m3u8文件,和每隔一段時(shí)間請(qǐng)求幾個(gè)ts文件。

但是除了HLS,還有Adobe的HDS,微軟的MSS,方案一多就要有個(gè)標(biāo)準(zhǔn)點(diǎn)的東西,于是就有了MPEGDASH。

DASH(DynamicAdaptiveStreamingoverHTTP),是一種在互聯(lián)網(wǎng)上傳送動(dòng)態(tài)碼率的VideoStreaming技術(shù),類似于蘋果的HLS,DASH會(huì)通過mediapresentationdescription(MPD)將視頻內(nèi)容切片成一個(gè)很短的文件片段,每個(gè)切片都有多個(gè)不同的碼率,DASHClient可以根據(jù)網(wǎng)絡(luò)的情況選擇一個(gè)碼率進(jìn)行播放,支持在不同碼率之間無縫切換。

Youtube,B站都是用的這個(gè)方案。這個(gè)方案索引文件通常是mpd文件(類似HLS的m3u8文件功能),傳輸格式推薦的是fmp4(FragmentedMP4),文件擴(kuò)展名通常為.m4s或直接用.mp4。所以用調(diào)試查看b站視頻播放時(shí)的網(wǎng)絡(luò)請(qǐng)求,會(huì)發(fā)現(xiàn)每隔一段時(shí)間有幾個(gè)m4s文件請(qǐng)求。

不管是HLS還是DASH們,都有對(duì)應(yīng)的庫(kù)甚至是高級(jí)的播放器方便我們使用,但我們其實(shí)是想要學(xué)習(xí)一點(diǎn)實(shí)現(xiàn)。其實(shí)拋開掉索引文件的解析拿到實(shí)際媒體文件的傳輸?shù)刂罚瑪[在我們面前的只有一個(gè)如何將多個(gè)視頻數(shù)據(jù)合并讓video標(biāo)簽可以無縫播放。

與之相關(guān)的一篇B站文章推薦給感興趣的朋友:我們?yōu)槭裁词褂肈ASH

MediaSource

video標(biāo)簽src指向一個(gè)視頻地址,視頻播完了再將src修改為下一段的視頻地址然后播放,這顯然不符合我們無縫播放的要求。其實(shí)有了我們前面BlobURL的學(xué)習(xí),我們可能就會(huì)想到一個(gè)思路,用BlobURL指向一個(gè)視頻二進(jìn)制數(shù)據(jù),然后不斷將下一段視頻的二進(jìn)制數(shù)據(jù)添加拼接進(jìn)去。這樣就可以在不影響播放的情況下,不斷的更新視頻內(nèi)容并播放下去,想想是不是有點(diǎn)流的意思出來了。

要實(shí)現(xiàn)這個(gè)功能我們要通過MediaSource來實(shí)現(xiàn),MediaSource接口功能也很純粹,作為一個(gè)媒體數(shù)據(jù)容器可以和HTMLMediaElement進(jìn)行綁定。基本流程就是通過URL.createObjectURL創(chuàng)建容器的BLobURL,設(shè)置到video標(biāo)簽的src上,在播放過程中,我們?nèi)匀豢梢酝ㄟ^MediaSource.appendBuffer***往容器里添加數(shù)據(jù),達(dá)到更新視頻內(nèi)容的目的。

實(shí)現(xiàn)代碼如下:

constvideo=document.querySelector('video');//視頻資源存放路徑,假設(shè)下面有5個(gè)分段視頻video1.mp4~video5.mp4,第一個(gè)段為初始化視頻init.mp4constassetURL="http://www.demo.com";//視頻格式和編碼信息,主要為判斷瀏覽器是否支持視頻格式,但如果信息和視頻不符可能會(huì)報(bào)錯(cuò)constmimeCodec='video/mp4;codecs="avc1.42E01E,mp4a.40.2"';if('MediaSource'inwindow&&MediaSource.isTypeSupported(mimeCodec)){constmediaSource=newMediaSource();video.src=URL.createObjectURL(mediaSource);//將video與MediaSource綁定,此處生成一個(gè)BlobURLmediaSource.addEventListener('sourceopen',sourceOpen);//可以理解為容器打開}else{//瀏覽器不支持該視頻格式console.error('UnsupportedMIMEtypeorcodec:',mimeCodec);}functionsourceOpen(){constmediaSource=this;constsourceBuffer=mediaSource.addSourceBuffer(mimeCodec);leti=1;functiongetNextVideo(url){//ajax代碼實(shí)現(xiàn)翻看上文,數(shù)據(jù)請(qǐng)求類型為arraybufferajax(url,function(buf){//往容器中添加請(qǐng)求到的數(shù)據(jù),不會(huì)影響當(dāng)下的視頻播放。sourceBuffer.appendBuffer(buf);});}//每次appendBuffer數(shù)據(jù)更新完之后就會(huì)觸發(fā)sourceBuffer.addEventListener("updateend",function(){if(i===1){//第一個(gè)初始化視頻加載完就開始播放video.play();}if(i<6){//一段視頻加載完成后,請(qǐng)求下一段視頻getNextVideo(`${assetURL}/video${i}.mp4`);}if(i===6){//全部視頻片段加載完關(guān)閉容器mediaSource.endOfStream();URL.revokeObjectURL(video.src);//BlobURL已經(jīng)使用并加載,不需要再次使用的話可以釋放掉。}i++;});//加載初始視頻getNextVideo(`${assetURL}/init.mp4`);};

這段代碼修改自MDN的MediaSource詞條中的示例代碼,原例子中只有加載一段視頻,我修改為了多段視頻,代碼里面很多地方還可以優(yōu)化精簡(jiǎn),這里沒做就當(dāng)是為了方便我們看邏輯。

此時(shí)我們已經(jīng)基本實(shí)現(xiàn)了一個(gè)簡(jiǎn)易的流媒體播放功能,如果愿意可以再加入m3u8或mpd文件的解析,設(shè)計(jì)一下UI界面,就可以實(shí)現(xiàn)一個(gè)流媒體播放器了。

最后提一下一個(gè)坑,很多人跑了MDN的MediaSource示例代碼,可能會(huì)發(fā)現(xiàn)使用官方提供的視頻是沒問題的,但是用了自己的mp4視頻就會(huì)報(bào)錯(cuò),這是因?yàn)閒mp4文件擴(kuò)展名通常為.m4s或直接用.mp4,但卻是特殊的mp4文件。

FragmentedMP4

通常我們使用的mp4文件是嵌套結(jié)構(gòu)的,客戶端必須要從頭加載一個(gè)MP4文件,才能夠完整播放,不能從中間一段開始播放。而FragmentedMP4(簡(jiǎn)稱fmp4),就如它的名字碎片mp4,是由一系列的片段組成,如果服務(wù)器支持byte-range請(qǐng)求,那么,這些片段可以獨(dú)立的進(jìn)行請(qǐng)求到客戶端進(jìn)行播放,而不需要加載整個(gè)文件。

我們可以通過這個(gè)網(wǎng)站判斷一個(gè)mp4文件是否為FragmentedMP4,網(wǎng)站地址。

我們通過FFmpeg或Bento4的mp4fragment來將普通mp4轉(zhuǎn)換為FragmentedMP4,兩個(gè)工具都是命令行工具,按照各自系統(tǒng)下載下來對(duì)應(yīng)的壓縮包,解壓后設(shè)置環(huán)境變量指向文件夾中的bin目錄,就可以使用相關(guān)命令了。

Bento4的mp4fragment,沒有太多參數(shù),命令如下:

mp4fragmentvideo.mp4video-fragmented.mp4

FFmpeg會(huì)需要設(shè)置一些參數(shù),命令如下:

ffmpeg-ivideo.mp4-movflagsempty_moov+default_base_moof+frag_keyframevideo-fragmented.mp4

Tips:網(wǎng)上大部分的資料中轉(zhuǎn)換時(shí)是不帶default_base_moof這個(gè)參數(shù)的,雖然可以轉(zhuǎn)換成功,但是經(jīng)測(cè)試如果不添加此參數(shù)網(wǎng)頁中MediaSource處理視頻時(shí)會(huì)報(bào)錯(cuò)。

視頻的切割分段可以使用Bento4的mp4slipt,命令如下:

mp4splitvideo.mp4--media-segmentvideo-%llu.mp4--pattern-parametersN

最后

之所以寫這篇文章其實(shí)是之前公司有個(gè)需求要了解一下BlobURL,稍微看了一下,后來不了了之。這次忙里偷閑重拾起來把它搞清楚,一邊學(xué)習(xí)一邊記錄,這篇文章中的很多點(diǎn)展開了其實(shí)有很多內(nèi)容,希望大家看了這篇文章能夠有所啟發(fā)或引起興趣,我的目的也就達(dá)到了,另外視頻這方面的東西真的是有點(diǎn)深的,文章中如果有錯(cuò)誤和疏漏也歡迎大家指出,我將及時(shí)修正。

作者:wangzy2019

鏈接:https://juejin.im/post/5d1ea7a8e51d454fd8057bea

來源:掘金

猜你喜歡

主站蜘蛛池模板: 91精品国产91久久久久青草 | 午夜看毛片 | 欧美激情伦妇在线观看 | 成年人免费在线视频观看 | 日本乱人伦毛片 | 免费观看性欧美一级 | 国产大臿蕉香蕉大视频女 | 一级成人 | 3d动漫精品成人一区二区三 | 精品国产91久久久久 | 偷拍亚洲欧美 | 国产精品欧美亚洲韩国日本不卡 | 理伦毛片 | 欧美日本视频一区 | 毛片大片免费看 | 日本丶国产丶欧美色综合 | 国产欧美日韩不卡在线播放在线 | 91欧美激情一区二区三区成人 | 国产成人在线看 | 19+韩国主播青草vip视频 | 国产制服 国产制服一区二区 | 91精品成人免费国产片 | 国产精品免费久久 | 亚洲美女在线观看播放 | 美国一级毛片片aa久久综合 | 精品国产乱码久久久久久一区二区 | 97在线视频免费观看费观看 | 91热国内精品永久免费观看 | 91成人啪国产啪永久地址 | 久久精品国产一区二区三区日韩 | 自拍视频一区 | 欧美二级在线观看免费 | 日韩中文字幕在线观看 | 国产欧美日韩精品第一区 | 三级毛片免费观看 | 亚洲精品韩国美女在线 | 天堂亚洲网| 国产精品一区二区四区 | 国产精品欧美一区二区三区不卡 | 亚洲视频在线观看 | 亚洲男人的天堂在线视频 |