国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Web端直接播放 .ts 視頻

mmy123456 / 3267人閱讀

摘要:常見(jiàn)方案在網(wǎng)上查找的大部分解決方案都是用諸如等網(wǎng)頁(yè)播放器,接收索引文件的方式來(lái)播放切片。根據(jù)實(shí)測(cè),只用這一個(gè)庫(kù)即可在端直接播放視頻,如下是它的轉(zhuǎn)化流程。

最近項(xiàng)目中需要前端播放 .ts 格式視頻,搗鼓了幾天學(xué)習(xí)到很多知識(shí),也發(fā)掘了一種優(yōu)秀的解決方案,分享給有同樣需求的同學(xué)。

常見(jiàn)方案

在網(wǎng)上查找的大部分解決方案都是用諸如videojs等網(wǎng)頁(yè)播放器,接收 .m3u8索引文件的方式來(lái)播放ts切片。這種方案的缺點(diǎn)是需要后端對(duì)原始ts切片做處理,生成 .m3u8索引文件

ffmpeg -i source.ts -c copy -map 0 -f segment -segment_list playlist.m3u8 -segment_time 10 output%03d.ts

項(xiàng)目中已存儲(chǔ)的 .ts 切片數(shù)量眾多,已經(jīng)占用了NAS服務(wù)器絕大部分的資源,生成的 .m3u8 索引雖然非常小,但會(huì)生成一堆切片后的新 .ts 視頻,例如上述指令將會(huì)生成一堆 10s 長(zhǎng)度的 ts新切片。出于各種考慮后端的同學(xué)拒絕了這種重新生成新切片加索引的方案。

邪道方案

在我們的項(xiàng)目中,每一個(gè)ts切片已經(jīng)就是一個(gè)獨(dú)立內(nèi)容的視頻了,時(shí)長(zhǎng)在20s以內(nèi),因此其實(shí)不用切割,只需要生成一個(gè)索引文件就可以了, .m3u8格式如下:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:93
#EXTINF:92.008578,
test.ts
#EXT-X-ENDLIST

定義好的時(shí)長(zhǎng)并不影響最終網(wǎng)頁(yè)播放器計(jì)算出的時(shí)長(zhǎng),因此可以取一個(gè)統(tǒng)一的極大值,整體上就只有倒數(shù)第二行的ts文件名需要根據(jù)不同 ts 視頻修改,可以用腳本統(tǒng)一生成所有ts文件的索引文件。這個(gè)方案極其low,當(dāng)然也被后端同學(xué)拒絕了。

插件方案

VLC Web Plugin,一個(gè)需要VLC播放器以及瀏覽器插件的方案,并且不支持Chrome,使用復(fù)雜,感興趣的同學(xué)可以自行嘗試。

優(yōu)雅方案

在中文互聯(lián)網(wǎng)搜索無(wú)果后,果斷轉(zhuǎn)向了Google,然而也未果,正當(dāng)我絕望地準(zhǔn)備調(diào)整心態(tài),接受下載后VLC播放的保底方案時(shí),終于發(fā)現(xiàn)了一絲線索,在vediojs的Github頁(yè)面中,Issue1441 和 Issue4297 中,面對(duì)videojs能否直接播放 .ts 的疑問(wèn),開(kāi)發(fā)團(tuán)隊(duì)都表示雖然庫(kù)本身沒(méi)有直接的相關(guān)實(shí)現(xiàn),但可以利用相關(guān)的邏輯自行實(shí)現(xiàn)。最重要的是都指出了mux.js這一工具。根據(jù)實(shí)測(cè),只用這一個(gè)庫(kù)即可在web端直接播放 .ts 視頻,如下是它的轉(zhuǎn)化流程。

代碼示例

示例中是以 ajax 的方式接收 .ts 二進(jìn)制數(shù)據(jù),mux.js引入方式可以直接標(biāo)簽引入,也可以npm install mux.js后 import進(jìn)頁(yè)面。

var $ = document.querySelector.bind(document);
    var vjsParsed,
        video, 
        mediaSource;
    // 定義通用的事件回調(diào)處理函數(shù),只做打印事件類型
    function logevent (event) {
      console.log(event);
    }
    
    // ajax
    let xhr = new XMLHttpRequest();
    xhr.open("GET", "./test.ts");
    // 接收的是 video/mp2t 二進(jìn)制數(shù)據(jù),Blob類型也可以,但arraybuffer類型方便后續(xù)直接處理 
    xhr.responseType = "arraybuffer";
    xhr.send();
    xhr.onreadystatechange = function () {
      if (xhr.readyState ==4) {
        if (xhr.status == 200) {
          transferFormat(xhr.response);
        } else {
          console.log("error");
        }
      }
    }
    
    function transferFormat (data) {
      // 將源數(shù)據(jù)從ArrayBuffer格式保存為可操作的Uint8Array格式
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
      var segment = new Uint8Array(data); 
      var combined = false;
      // 接收無(wú)音頻ts文件,OutputType設(shè)置為"video",帶音頻ts設(shè)置為"combined"
      var outputType = "video";
      var remuxedSegments = [];
      var remuxedBytesLength = 0;
      var remuxedInitSegment = null;

      // remux選項(xiàng)默認(rèn)為true,將源數(shù)據(jù)的音頻視頻混合為mp4,設(shè)為false則不混合
      var transmuxer = new muxjs.mp4.Transmuxer({remux: false});
      
      // 監(jiān)聽(tīng)data事件,開(kāi)始轉(zhuǎn)換流
      transmuxer.on("data", function(event) {
        console.log(event);
        if (event.type === outputType) {
          remuxedSegments.push(event);
          remuxedBytesLength += event.data.byteLength;
          remuxedInitSegment = event.initSegment;
        }
      });
      // 監(jiān)聽(tīng)轉(zhuǎn)換完成事件,拼接最后結(jié)果并傳入MediaSource
      transmuxer.on("done", function () {
        var offset = 0;
        var bytes = new Uint8Array(remuxedInitSegment.byteLength + remuxedBytesLength)
        bytes.set(remuxedInitSegment, offset);
        offset += remuxedInitSegment.byteLength;

        for (var j = 0, i = offset; j < remuxedSegments.length; j++) {
          bytes.set(remuxedSegments[j].data, i);
          i += remuxedSegments[j].byteLength;
        }
        remuxedSegments = [];
        remuxedBytesLength = 0;
        // 解析出轉(zhuǎn)換后的mp4相關(guān)信息,與最終轉(zhuǎn)換結(jié)果無(wú)關(guān)
        vjsParsed = muxjs.mp4.tools.inspect(bytes);
        console.log("transmuxed", vjsParsed);

        prepareSourceBuffer(combined, outputType, bytes);
      });
      // push方法可能會(huì)觸發(fā)"data"事件,因此要在事件注冊(cè)完成后調(diào)用
      transmuxer.push(segment); // 傳入源二進(jìn)制數(shù)據(jù),分割為m2ts包,依次調(diào)用上圖中的流程
      // flush的調(diào)用會(huì)直接觸發(fā)"done"事件,因此要事件注冊(cè)完成后調(diào)用
      transmuxer.flush(); // 將所有數(shù)據(jù)從緩存區(qū)清出來(lái)
    }

    function prepareSourceBuffer (combined, outputType, bytes) {
      var buffer;
      video = document.createElement("video");
      video.controls = true;
      // MediaSource Web API: https://developer.mozilla.org/zh-CN/docs/Web/API/MediaSource
      mediaSource = new MediaSource(); 
      video.src = URL.createObjectURL(mediaSource);
    
      $("#video-wrapper").appendChild(video); // 將H5 video元素添加到對(duì)應(yīng)DOM節(jié)點(diǎn)下
    
      // 轉(zhuǎn)換后mp4的音頻格式 視頻格式
      var codecsArray = ["avc1.64001f", "mp4a.40.5"];
    
      mediaSource.addEventListener("sourceopen", function () {
        // MediaSource 實(shí)例默認(rèn)的duration屬性為NaN
        mediaSource.duration = 0;
        // 轉(zhuǎn)換為帶音頻、視頻的mp4
        if (combined) {
          buffer = mediaSource.addSourceBuffer("video/mp4;codecs="" + "avc1.64001f,mp4a.40.5" + """);
        } else if (outputType === "video") {
          // 轉(zhuǎn)換為只含視頻的mp4
          buffer = mediaSource.addSourceBuffer("video/mp4;codecs="" + codecsArray[0] + """);
        } else if (outputType === "audio") {
          // 轉(zhuǎn)換為只含音頻的mp4
          buffer = mediaSource.addSourceBuffer("audio/mp4;codecs="" + (codecsArray[1] ||codecsArray[0]) + """);
        }
    
        buffer.addEventListener("updatestart", logevent);
        buffer.addEventListener("updateend", logevent);
        buffer.addEventListener("error", logevent);
        video.addEventListener("error", logevent);
        // mp4 buffer 準(zhǔn)備完畢,傳入轉(zhuǎn)換后的數(shù)據(jù)
        // 將 bytes 放入 MediaSource 創(chuàng)建的sourceBuffer中
        // https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/appendBuffer
        buffer.appendBuffer(bytes);
        // 自動(dòng)播放
        // video.play();
      });
    };

IE8及以上 、 IE Edge 、Chrome 、 Firefox 瀏覽器下均能正常播放。希望本文能幫到各位開(kāi)發(fā)同學(xué)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/102520.html

相關(guān)文章

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<