使用HTML5视频标签播放本地(硬盘)视频文件?

101

我想实现以下目标。

<video src="file:///Users/username/folder/video.webm">
</video>

这个功能的意图是让用户能够从他/她的硬盘中选择一个文件。

并且不进行上传的原因当然是传输成本和存储配额。没有保存文件的理由。

这可行吗?


它绝对不会与文件输入一起工作。可能会在HTML5的ondrop上工作,但我认为您无法利用它进行文件上传。最好的选择可能是制作一个Chrome扩展程序。 - Brian Nickel
4个回答

268
可以播放本地视频文件。
<input type="file" accept="video/*"/>
<video controls autoplay></video>

当使用input元素选择文件时:
  1. 触发'change'事件
  2. input.files FileList获取第一个File对象
  3. 创建指向该文件对象的object URL
  4. 将该对象URL设置为video.src属性的值
  5. 放松并享受观看 :)

http://jsfiddle.net/dsbonev/cCCZ2/embedded/result,js,html,css/

(function localFileVideoPlayer() {
  'use strict'
  var URL = window.URL || window.webkitURL
  var displayMessage = function(message, isError) {
    var element = document.querySelector('#message')
    element.innerHTML = message
    element.className = isError ? 'error' : 'info'
  }
  var playSelectedFile = function(event) {
    var file = this.files[0]
    var type = file.type
    var videoNode = document.querySelector('video')
    var canPlay = videoNode.canPlayType(type)
    if (canPlay === '') canPlay = 'no'
    var message = 'Can play type "' + type + '": ' + canPlay
    var isError = canPlay === 'no'
    displayMessage(message, isError)

    if (isError) {
      return
    }

    var fileURL = URL.createObjectURL(file)
    videoNode.src = fileURL
  }
  var inputNode = document.querySelector('input')
  inputNode.addEventListener('change', playSelectedFile, false)
})()
video,
input {
  display: block;
}

input {
  width: 100%;
}

.info {
  background-color: aqua;
}

.error {
  background-color: red;
  color: white;
}
<h1>HTML5 local video file player example</h1>
<div id="message"></div>
<input type="file" accept="video/*" />
<video controls autoplay></video>


这在我的 Mac 上的 Chrome 上有效。在 Safari 6.1 上无效。 - Patrick Cullen
1
似乎 Safari 存在已知问题: https://dev59.com/Z3fZa4cB1Zd3GeqPRGr9 和 https://bugs.webkit.org/show_bug.cgi?id=101671 - Patrick Cullen
如何通过jQuery实现? - Sachi-17
你赢得了互联网! - Sujal Mandal
1
这太棒了,我希望我可以多给这个不使用jQuery的点赞100次。 - BoundForGlory
显示剩余7条评论

15

只有在以“file”协议从本地用户硬盘加载HTML文件时,才能实现这一点。

如果HTML页面由服务器通过HTTP提供服务,您无法通过在src属性中指定具有file://协议的本地文件来访问任何本地文件,因为这将意味着您可以访问用户计算机上的任何文件,而不需要用户知道,这将是一个巨大的安全风险。

正如Dimitar Bonev所说,如果用户自己使用文件选择器选择文件,则可以访问文件。没有这个步骤,出于很好的原因,所有浏览器都禁止访问。因此,虽然他的答案对许多人可能很有用,但它放宽了原始问题中代码的要求。


Dimitrov Bonev的解决方案表明这个解决方案是不正确的--你可以通过input type=file访问本地文件。 - J.T. Taylor
2
嗯,他的解决方案只有在用户先选择文件的情况下才有效。你仍然不能在HTML源代码中指定文件路径(正如问题所述)并以这种方式访问它。因此,他的解决方案在技术上适用于另一个问题。 - Holger Just
VLC播放器还可以在电脑上播放任何文件,但是这也存在安全风险。如果他们想要,它可以将我们硬盘上的文件下载到他们的服务器上,而我们却毫不知情,不是吗?那么为什么没有安全风险呢?最坏的情况下,用户只能手动接受浏览器播放文件的请求。因为有一些情况下,用户会百分之百地信任该页面,因为这些用户和网页创建者在同一家公司工作。 - Dariux
@holger 是的,我曾经为我的应用程序寻找这个解决方案,并且出于与OP相同的原因而苦苦挣扎。也许主要问题在于我一直在寻找获取文件路径的方法,但实际上是不可能的。也许我应该寻找的是“如何将我的应用程序指向用户选择的文件?”我认为OP的问题已经足够明确地表达了这一点,但这种思维方式会让人们变得盲目:<video src="file:///Users/username/folder/video.webm"> 这显示了用户机器上的路径。否则会说什么呢? - Fishbite

6

我曾经遇到过这个问题。 由于安全设置的限制,网站无法访问本地PC上的视频文件(这是可以理解的)。 唯一的解决方法是在本地PC上运行一个Web服务器(server2Go),然后将网页中所有与视频文件相关的引用都改为localhost/video.mp4。

<div id="videoDiv">
     <video id="video" src="http://127.0.0.1:4001/videos/<?php $videoFileName?>" width="70%" controls>
    </div>
<!--End videoDiv-->

不是理想的解决方案,但对我有效。

2
如果您将文件复制到缓存位置并将视频源的路径设置为它,它将播放。将文件复制到context.getExternalCacheDir().getAbsolutePath()。对我来说有效。 - Derek Wade
也可以在用户计算机上使用任何Web服务器,如Apache或Mongoose。 - Dariux

5

我尽力将Dimitar Bonev的答案简化。

<html>
<head>
<title>HTML5 local video file player example</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>HTML5 local video file player example</h1>
<input type="file" accept="video/*"><br>
<video controls></video>
<script type="text/javascript">
 (function localFileVideoPlayer() {
   'use strict'
   var playSelectedFile = function(event) {
   var file = this.files[0]
   var URL = window.URL || window.webkitURL 
   var fileURL = URL.createObjectURL(file)
   var videoNode = document.querySelector('video')
   videoNode.src = fileURL
   }
  var inputNode = document.querySelector('input')
  inputNode.addEventListener('change', playSelectedFile, false)
 })()
</script>
<p>I hereby signed confess solemnly that I have no idea what this code does. But it now works. 
<p>Firefox Lubuntu 18.03
<p>Simplified: `http://jsfiddle.net/dsbonev/cCCZ2/` `https://stackoverflow.com/users/691308/dimitar-bonev`
</body>
</html>

老兄,我***爱你。这太棒了!它可以作为一个很好的技巧来玩本地航班和Chromecast(如果您的浏览器支持投屏)。 - eltbus
我很乐意帮忙。 :-) 事实是这是一段疯狂的代码。 - xerostomus
Xerostomus,社区已经达成共识,宗教传教不应出现在 Stack Overflow 的帖子中。如果您想在这里展示有关神论的材料,可以在您的外部网站上进行(最好)或在您的 Stack Overflow 个人资料中进行(这里给予了广泛的自我表达空间)。 - halfer
2
好的,我明白你想避免关于宗教的无用争吵。但是无论如何,我希望我可以(私下)感谢上帝,这个疯狂的代码片段能够工作,不是吗? :-) - xerostomus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接