4

我有一个基本的 HTML5 视频设置,我从中加载四个视频之一。我遇到的问题是,当我加载下一个视频时,它会从上一个时间位置继续播放。设置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

这似乎与此处的问题相似,但似乎没有任何解决方案。有没有人在 iPhone 上遇到过这个问题?

4

8 回答 8

12

根据我的发现,问题似乎是仅在 iPhone 上(iPad 工作正常),直到“canplaythrough”事件才会正确设置 currentTime 属性,但是此时更改 currentTime 会导致明显的打嗝。解决方案是在调用 load 后故意暂停视频...

myVideo.load();
myVideo.pause();        

...然后在时间重置时调用 play 。

然而,第二个问题是当新电影的持续时间短于 currentTime 位置时。在这种情况下,不仅 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();
}
于 2013-08-16T22:44:43.480 回答
11

TL;DR:改变currentTime事件loadeddata。这也适用于音频。

看起来 Safari(并且问题仍然出现在 Safari 11.1 上)是 SafaricurrentTime在首次加载视频时不允许更改,如果它尚未加载帧currentTime。更大的问题:错误的解决方案可能会破坏 Chrome(也可能会破坏其他浏览器)。

幸运的是,我们有很多可以在媒体加载时监听的事件:

在音频/视频的加载过程中,会依次发生以下事件:

  1. 加载启动
  2. 持续时间变化
  3. 加载元数据
  4. 加载数据
  5. 进步
  6. 可以玩
  7. 可以通关

- W3Schools(我知道它不是首选来源,但我在 MDN 上找不到相同的信息)

我尝试调整currentTime不同的事件,但在前 3 个事件上,Safari 会将时间移回 0;在 5 和 6 上,它似乎阻止了视频在 Chrome 中播放,因为它会卡住currentTime(我本可以解决这个问题,但我认为有更好的解决方案)。

(我不想加载整个文件才能找到正确的位置,因为我想支持大量视频。所以canplaythrough不是我的选择。)

loadeddata事件的描述如下:

loadeddata当媒体的第一帧完成加载时触发该事件。

-MDN _

当我更改currentTimeon 时loadeddata,Safari 可以判断框架已加载且可用,并且会正确更新。它也不会导致 Chrome 在播放时冻结在一个位置。

音频的问题和解决方案是相同的。

于 2018-06-20T15:11:53.187 回答
5

我必须将preload属性设置为metadata(在主视频元素的 HTML 上)并currentTimeloadedmetadata事件侦听器中设置视频元素的属性。

 <video id="myVideo" preload="metadata">
    <source src="/path/to/video" type="video/mp4">
 </video>

JS

VideoEl.addEventListener('loadedmetadata', VideoMetaDataLoaded);

function VideoMetaDataLoaded() {
  VideoEl.currentTime = newTime;
}
于 2021-01-22T19:16:44.357 回答
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)
    });
  }
于 2017-10-25T15:40:43.330 回答
1

我在这里使用了最后两个答案的组合,但不得不将就绪状态限制减少到 2 ( HTMLVideoElement.prototype.HAVE_CURRENT_DATA),因为loadeddataiOS 上的事件通常永远不会超过 2。

于 2018-09-06T22:40:45.130 回答
1

在此处其他答案的帮助下,我提出了下一个解决方案:

HTMLVideoElement.prototype.playFromTime = function(currentTime){
    let that = this;
    that.load();
    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。这就是我目前测试的所有内容。

于 2020-11-13T13:29:55.393 回答
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>

于 2021-03-03T17:16:50.113 回答
-1

这是本地资产上 chrome 的问题。发生在我身上。当我从本地资产提供视频并设置时间时,它将视频重置为 0。所以对我有用的解决方案是从 s3 存储桶提供视频。

于 2021-01-05T13:57:49.097 回答