HTML5视频 - 在iPhone上无法正确设置currentTime

时间:2013-08-16 05:32:11

标签: iphone html5 video html5-video

我有一个基本的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上遇到过这个问题?

8 个答案:

答案 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(可能还会破坏其他浏览器)。

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

  

在音频/视频的加载过程中,以下事件按此顺序发生:

     
      
  1. loadstart
  2.   
  3. durationchange
  4.   
  5. loadedmetadata
  6.   
  7. 已加载数据
  8.   
  9. 进步
  10.   
  11. 可以玩
  12.   
  13. 可以播放
  14.   
     

-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>