我有一个基本的html 5视频设置,我可以从中加载四个视频中的一个。我遇到的问题是,当我加载下一个视频时,它继续从前一个时间位置播放。设置currentTime属性的努力似乎是短暂的或完全被忽略。
我已将听众添加到一系列事件中,并在每个事件中都有这样的内容;
myPlayer.addEventListener("loadeddata", function() {
console.log(" loadeddata: before = " + myPlayer.currentTime);
myPlayer.currentTime = 0.1;
console.log(" loadeddata: after = " + myPlayer.currentTime);
}, false);
有时我会看到一个事件的时间变化,但不能正确保存;
durationchange: before = 19.773332595825195
durationchange: after = 0.10000000149011612
loadedmetadata: before = 0.10000000149011612
loadedmetadata: after = 19.773332595825195
loadeddata: before = 19.773332595825195
loadeddata: after = 0.10000000149011612
canplay: before = 0.10000000149011612
canplay: after = 19.773332595825195
有时甚至似乎根本没有设置;
durationchange: before = 50.66666793823242
durationchange: after = 50.66666793823242
loadedmetadata: before = 50.66666793823242
loadedmetadata: after = 50.66666793823242
loadeddata: before = 50.66666793823242
loadeddata: after = 50.66666793823242
canplay: before = 50.66666793823242
canplay: after = 50.66666793823242
这似乎与HTML5 video - not setting the current time中的问题相似,但似乎没有任何解决方案。有没有人在iPhone上遇到过这个问题?
答案 0 :(得分:7)
根据我的发现,问题似乎是仅在iPhone上(iPad工作正常),currentTime属性在“canplaythrough”事件之前将无法正确设置,但是在此时更改当前时间将导致明显的打嗝。解决方案是在调用load ...后故意暂停视频...
myVideo.load();
myVideo.pause();
...然后在时间重置时调用播放。
然而,第二个问题是当新电影的持续时间短于当前时间位置时。在这种情况下,不仅currentTime无法设置,而且“canplaythrough”从未被调用,而QT只是在视频的末尾无效。
我发现两个问题的解决办法是强制进行二次加载,如果在“canplaythrough”之前没有重置currentTime。它有点与计时器回调有关,但它似乎可以做到这一点;
var myVideo = document.getElementById("video1");
myVideo.addEventListener("canplay", function() {
console.log(" canplay: before = " + myVideo.currentTime);
myVideo.currentTime = 0.1;
console.log(" canplay: after = " + myVideo.currentTime);
if( myVideo.currentTime < 1 ) {
myVideo.play();
}
else {
myVideo.load();
myVideo.pause();
setTimeout(checkStarted, 500);
}
}, false);
function checkStarted()
{
console.log(" checkStarted called");
myVideo.play();
}
答案 1 :(得分:2)
以下是恢复视频位置的Angular / Ionic解决方案。它适用于IOS,Android,Chrome和Safari。
HTML:
<video preload="metadata"
poster="{{ resource.thumbnail_file }}"
playsinline webkit-playsinline
#videos>
...
</video>
打字稿:
@ViewChildren('videos') videos: QueryList<any>;
videoCache: Map<number, number> = new Map<number, number>();
private restoreVideoPositions() {
var context = this;
setTimeout(() => {
this.videos.forEach(function (item, idx) {
var video = item.nativeElement;
var currentTime = context.videoCache.get(video.id);
if (currentTime != null && currentTime > 0) {
console.log('add listener', currentTime);
video.addEventListener("loadeddata", function () {
if (video.readyState >= 3) {
video.currentTime = currentTime;
// video.play();
}
});
video.load();
}
});
}, 0);
}
private storeVideoPositions() {
var context = this;
this.videoCache.clear()
this.videos.forEach(function (item, idx) {
var video = item.nativeElement;
video.pause();
context.videoCache.set(video.id, video.currentTime)
});
}
答案 2 :(得分:2)
我必须将 preload
属性设置为 metadata
(在主视频元素的 HTML 上)并在 currentTime
事件中设置视频元素的 loadedmetadata
听众。
<video id="myVideo" preload="metadata">
<source src="/path/to/video" type="video/mp4">
</video>
JS
VideoEl.addEventListener('loadedmetadata', VideoMetaDataLoaded);
function VideoMetaDataLoaded() {
VideoEl.currentTime = newTime;
}
答案 3 :(得分:1)
TL; DR:在currentTime
事件上更改loadeddata
。这也适用于音频。
看起来Safari(问题仍然存在于Safari 11.1上)是Safari不允许currentTime
在首次加载视频时更改,前提是该视频尚未加载{ {1}}。更大的问题是:错误的解决方案可能会破坏Chrome(可能还会破坏其他浏览器)。
幸运的是,在加载媒体时,我们可以听很多事件:
在音频/视频的加载过程中,以下事件按此顺序发生:
- loadstart
- durationchange
- loadedmetadata
- 已加载数据
- 进步
- 可以玩
- 可以播放
-W3Schools(我知道它不是首选来源,但我在MDN上找不到相同的信息)
我尝试针对不同的事件调整currentTime
,但是在前3个事件中,Safari会将时间移回0;并且在5和6上似乎阻止了视频在Chrome中播放,因为它会卡在currentTime
上(我可以解决这个问题,但我认为有更好的解决方案)。
(我不想加载整个文件到正确的位置,因为我想支持大量的视频。所以currentTime
对我来说不是一个选择。)
canplaythrough
事件的描述为:
媒体的第一帧加载完成后,将触发
loadeddata
事件。-MDN
当我在loadeddata
上更改了currentTime
时,Safari可以告诉该框架已加载并且可用,并且可以正确更新。这也不会导致Chrome在播放时冻结在一个位置。
音频的问题和解决方案是相同的。
答案 4 :(得分:0)
我在这里使用了后两个答案的组合,但是由于iOS上的HTMLVideoElement.prototype.HAVE_CURRENT_DATA
事件通常永远不会高于2,因此必须将就绪状态限制降低为2(loadeddata
。
答案 5 :(得分:0)
在这里其他答案的帮助下,我想出了下一个解决方案:
HTMLVideoElement.prototype.playFromTime = function(currentTime){
let that = this;
that.pause();
that.currentTime = currentTime;
let loadedMetadata;
loadedMetadata = function(event){
that.currentTime = currentTime;
that.removeEventListener("loadedmetadata", loadedMetadata);
}
if(that.currentTime !== currentTime){
that.addEventListener("loadedmetadata", loadedMetadata);
}
that.play();
}
//usage example:
myVidElement.playFromTime(20);
在我的情况下,这可以在Safari上的iPhone,台式机上的Safari,macOS上的Firefox,macOS上的Chrome上使用。这就是我现在测试过的全部。
答案 6 :(得分:0)
这是本地资产上 chrome 的问题。发生在我身上。当我从本地资产提供视频并设置时间时,它将视频重置为 0。 所以对我有用的解决方案是从 s3 存储桶提供视频。
答案 7 :(得分:0)
使用 React 滚动播放视频时遇到了同样的问题。以下为我解决了。
useEffect(() => {
videoRef.current.load();
}, []);
const { render } = ReactDOM;
const { useState, useEffect, useRef } = React;
const Video = ({ src, height, length }) => {
const [currentTime, setCurrentTime] = useState(0);
const videoRef = useRef(null);
useEffect(() => {
// This is needed for IOS
videoRef.current.load();
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
const getCurrentTime = () => {
const percentScrolled = window.scrollY / (height - window.innerHeight);
return length * percentScrolled;
};
const handleScroll = (e) => {
const time = getCurrentTime();
videoRef.current.currentTime = time;
setCurrentTime(time);
};
return (
<div style={{ height }}>
<p>Time: {currentTime.toFixed(2)}s</p>
<video ref={videoRef} muted playsInline>
<source src={src} type="video/mp4" />
Your browser does not support the video tag.
</video>
</div>
);
};
const App = () => {
return (
<Video
length={5}
height={3000}
src="https://lqez.github.io/js/airpodsvf/video.mp4"
/>
);
};
render(<App />, document.getElementById("root"));
body {
background: black;
}
p {
color: slategrey;
top: 0;
position: fixed;
z-index: 1;
padding: 20px;
}
video {
top: 60px;
position: fixed;
width: 100%;
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>