1. 程式人生 > 其它 >上傳檔案時如何獲取視訊長度

上傳檔案時如何獲取視訊長度

上傳時如何獲取視訊長度

思路

首先,獲取視訊長度,我們通過瀏覽器自帶的API就可以獲取,如下:

<!-- html -->
<video src="xxx.mp4"></video>

<!-- JS -->
const oVideo = document.getElementById('video');

oVideo.duration; // 此屬性就可以拿到時間

此時可以發現,src中只能填入路徑,但是上傳檔案我們只有檔案,所以問題就集中在如何拿到路徑

  • 思路一:通常預覽圖片的時候,我們會將檔案轉成base64 然後賦值給 src,那麼此時視訊是不是可以同理呢..

  • 思路二:URL.createObjectURL()

此方法能建立一個臨時的URL,和此視窗的生命週期繫結,剛好符合

MDN解釋

靜態方法會建立一個 DOMString,其中包含一個表示引數中給出的物件的URL。這個 URL 的生命週期和建立它的視窗中的 document 繫結。這個新的URL 物件表示指定的 File 物件或 Blob 物件。

注意URL.revokeObjectURL() 方法來釋放

  • 思路三:既然拿到了file 物件,能不能直接從中獲取資訊

從file物件的屬性中來看 沒有此類資訊, 那麼如何來解決呢?

分析mp4檔案,總所周知,計算機上所有的檔案都是以2進位制的形式存在,各種不同型別的檔案都是有不同的規則來組織起來的,本質都是0和1,那麼以mp4

為例,在檔案的二進位制中,肯定有對於時長的描述,藉助JS中操作二進位制資料的能力處理Uint8Array、DataView、ArrayBuffer

那麼主要問題就是知道檔案規範...

程式碼實現

  • 方法一 (檔案過大就會慢)
function change (e) {
      const file = oFile.files[0];
      let reader = new FileReader();

      const oVideo = document.createElement('video');

      const aBlob = new Blob([file],{type:'video/mp4'})
      reader.onload = function(result) {
        // console.log(reader.result);
        oVideo.src = reader.result
      }
      reader.readAsDataURL(aBlob);
      // oVideo.preload = 'metadata';
      oVideo.onloadedmetadata = function (e) {
        // 視訊總長度,秒為單位
        console.log('....', oVideo.duration);
      }
      // document.body.appendChild(oVideo);
    }
  • 方法二
const file = oFile.files[0];
const oVideo = document.createElement('video');

// oVideo.preload = 'metadata';
oVideo.onloadedmetadata = function (e) {
  // 視訊總長度,秒為單位
  console.log( '....', oVideo.duration);
}
oVideo.src = URL.createObjectURL(file)

注意:preload="metadata" > 提示儘管作者認為使用者不需要檢視該視訊,不過抓取元資料(比如:長度)還是很合理的。

上述兩種方式都是借用Video元素提供的API和onloadedmetadata事件實現

  • 方法三
function change2 () {
       const file = oFile.files[0];
      console.log(file)

      file.arrayBuffer().then(res => {
        console.log(res)

        const ui8 = new Uint8Array(res);
        const view = new DataView(res)
        console.log(ui8)
        console.log(view)
        analysis(view);
      })
    }


    function analysis (view) {
      // 下標
      let idx = 0;

      for(; idx < view.byteLength ;) {

        boxHeader = analysisHeaderBox(view, idx);
        console.log(boxHeader, '...')

        // 找到moov 處理
        if (boxHeader.type === 'moov') {
          // 跳過頭
          const son = view.buffer.slice(idx + 8, view.byteLength);
          analysis(new DataView(son));
        }

        if (boxHeader.type === 'mvhd') {
          // 跳過頭
          const son = view.buffer.slice(idx + 8, boxHeader.size);
          analysisMvhdBox(new DataView(son));
        }

        // 偏移
        idx += boxHeader.size;
      }
    }

    // box header 中的 size 和 type
    function analysisHeaderBox (view, offset) {
      const size  = view.getUint32(offset);

      offset += 4;
      let type = analysisBoxType(
        view.getUint8(offset),
        view.getUint8(offset + 1),
        view.getUint8(offset + 2),
        view.getUint8(offset + 3)
      );
      return {
        size,
        type
      };
    }

    // 根據碼點獲取字串
    function analysisBoxType () {
      let str = '';
      for(var i = 0; i < arguments.length; i++) {
        str += String.fromCharCode(arguments[i]);
      }
      return str;
    } 

    function analysisMvhdBox (view) {
      console.log(view, '...')

      const timescale = view.getUint32(12);
      const duration = view.getUint32(16);

      console.log(timescale, duration, duration/timescale, '...')
    }


擴充套件

通過第三種方式,有以下好處

  • 可解析不同的檔案型別,可以獲取檔案內容中的資訊

  • 並且不依賴於 BOM環境 即使在node環境下也是能使用。

  • 就算沒有後綴或者字尾錯誤也可以判斷出來檔案是不是MAP4或其他型別

參考

參考:
https://blog.csdn.net/w5025/article/details/123097108

http://www.360doc.com/content/20/0902/20/49586_933661079.shtml

https://zhuanlan.zhihu.com/p/457888765