输入视频文件时获取视频持续时间

Get video duration when input a video file

本文关键字:视频 持续时间 获取 文件 输入      更新时间:2023-09-26

我正在做一个使用HTML和Javascript的项目,该项目将使用本地文件在本地运行。我需要通过输入选择一个文件,获取它的信息,然后决定是否添加到我的列表中并复制。如果我决定使用它,我就必须把它放在队列中以便以后使用。否则,我将放弃并选择另一个文件。

我面临的问题是,我找不到一种方法来获取视频持续时间,只需在输入时选择它。

我搜索了很多,但没有找到任何方法来获取持续时间。在下面的代码中,我尝试使用"file.duration",但没有成功,它只是返回"未定义。"。

这是我的输入,正如你所看到的,很正常。

<div id="input-upload-file" class="box-shadow">
   <span>upload! (ღ˘⌣˘ღ)</span> <!--ignore the text face lol -->
   <input type="file" class="upload" id="fileUp" name="fileUpload" onchange="setFileInfo()">
</div>

这是我用来获取所有信息的函数。

function setFileInfo(){
  showInfo(); //change div content
  var file = document.getElementById("fileUp").files[0];
  var pid =  1;
  var Pname = file.name;
  Pname = Pname.slice(0, Pname.indexOf(".")); //get filename without extension
  var Ptype = file.type;
  var Psize = bytesToSize(file.size); //turns into KB,MB, etc...
  var Pprior = setPriority(Ptype); //returns 1, 2 or 3 
  var Pdur = file.duration;
  var Pmem = getMemory(Psize); //returns size * (100 || 10 || 1)
  var Pown = 'user';
  /* a lot of stuff throwing this info to the HTML */
  console.log(Pdur);
}

有办法做到这一点吗?如果没有,有什么替代方案可以帮助我?

在现代浏览器中,您可以使用带有非附加视频元素的URL API的URL.createObjectURL()来加载文件内容。

var myVideos = [];
window.URL = window.URL || window.webkitURL;
document.getElementById('fileUp').onchange = setFileInfo;
function setFileInfo() {
  var files = this.files;
  myVideos.push(files[0]);
  var video = document.createElement('video');
  video.preload = 'metadata';
  video.onloadedmetadata = function() {
    window.URL.revokeObjectURL(video.src);
    var duration = video.duration;
    myVideos[myVideos.length - 1].duration = duration;
    updateInfos();
  }
  video.src = URL.createObjectURL(files[0]);;
}
function updateInfos() {
  var infos = document.getElementById('infos');
  infos.textContent = "";
  for (var i = 0; i < myVideos.length; i++) {
    infos.textContent += myVideos[i].name + " duration: " + myVideos[i].duration + ''n';
  }
}
<div id="input-upload-file" class="box-shadow">
  <span>upload! (ღ˘⌣˘ღ)</span>
  <input type="file" class="upload" id="fileUp" name="fileUpload">
</div>
<pre id="infos"></pre>

在继续执行更多代码之前,我需要验证一个文件,下面是在Kaiido的帮助下我的方法!

用户上传文件时的onchange事件:

$("input[type=file]").on("change", function(e) {
    var file = this.files[0]; // Get uploaded file
    validateFile(file) // Validate Duration
    e.target.value = ''; // Clear value to allow new uploads
})

现在验证持续时间:

function validateFile(file) {
    var video = document.createElement('video');
    video.preload = 'metadata';
    video.onloadedmetadata = function() {
        window.URL.revokeObjectURL(video.src);
        if (video.duration < 1) {
            console.log("Invalid Video! video is less than 1 second");
            return;
        }
        methodToCallIfValid();
    }
    video.src = URL.createObjectURL(file);
}

这里是async/await Promise版本:

const loadVideo = file => new Promise((resolve, reject) => {
    try {
        let video = document.createElement('video')
        video.preload = 'metadata'
        video.onloadedmetadata = function () {
            resolve(this)
        }
        video.onerror = function () {
            reject("Invalid video. Please select a video file.")
        }
        video.src = window.URL.createObjectURL(file)
    } catch (e) {
        reject(e)
    }
})

可按如下方式使用:

const video = await loadVideo(e.currentTarget.files[0])
console.log(video.duration)

FileReader获取视频时长很简单,在async/await中也很容易管理。

const getVideoDuration = file =>
  new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      const media = new Audio(reader.result);
      media.onloadedmetadata = () => resolve(media.duration);
    };
    reader.readAsDataURL(file);
    reader.onerror = error => reject(error);
  });
const duration = await getVideoDuraion(file);

其中fileFile对象

实时示例

const getVideoDuration = (file) =>
  new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      const media = new Audio(reader.result);
      media.onloadedmetadata = () => resolve(media.duration);
    };
    reader.readAsDataURL(file);
    reader.onerror = (error) => reject(error);
  });
const handleChange = async (e) => {
  const duration = await getVideoDuration(e.target.files[0]);
  document.querySelector("#duration").innerText = `Duration: ${duration}`;
};
<div>
  <input type="file" onchange="handleChange(event)" />
  <p id="duration">Duration: </p>
</div>

这就是我在S3上推送视频之前获得视频持续时间的方法。。我正在使用此代码上传4+GB的视频文件。

注意-对于.avi、.flv、.vob、.mpeg等格式,将找不到持续时间,因此请向用户发送一条简单的消息来处理它

  //same method can be used for images/audio too, making some little changes
  getVideoDuration = async (f) => {
    const fileCallbackToPromise = (fileObj) => {
      return Promise.race([
        new Promise((resolve) => {
          if (fileObj instanceof HTMLImageElement) fileObj.onload = resolve;
          else fileObj.onloadedmetadata = resolve;
        }),
        new Promise((_, reject) => {
          setTimeout(reject, 1000);
        }),
      ]);
    };
    const objectUrl = URL.createObjectURL(f);
    // const isVideo = type.startsWith('video/');
    const video = document.createElement("video");
    video.src = objectUrl;
    await fileCallbackToPromise(video);
    return {
      duration: video.duration,
      width: video.videoWidth,
      height: video.videoHeight,
    };
}

//call the function
//removing unwanted code for clarity
const meta = await this.getVideoDuration(file);
//meta.width, meta.height, meta.duration is ready for you to use

我已经在nano-metadata包中实现了获取视频时长https://github.com/kalashnikovisme/nano-metadata.

你可以做一些类似的事情

import nanoMetadata from 'nano-metadata'
const change = (e) => {
  const file = e.target.files[0]
  
  nanoMetadata.video.duration(file).then((duration) => {
    console.log(duration) // will show you video duration in seconds
  })
}