如何在两个视频播放/缓冲时同步它们的相同源。

huangapple go评论75阅读模式
英文:

How to synchronize two videos with the same source when they're playing/buffering

问题

在应用的主页/首屏页面中,我放置了两个视频,使用自动播放无控件的方式供用户观看。

这两个视频都使用了相同的MP4视频源,大小约为90MB:

<source src={VIDEO_SRC} type="video/mp4" />

第一个视频较大,位于背景,并具有模糊效果,仅用于改善视觉效果。

<video
  key="big-video"
  loop
  muted
  autoPlay
  preload="none"
  poster="/MainVideoPoster.jpg"
  className="w-full h-full object-cover object-center blur-sm"
>
  <source src={VIDEO_SRC} type="video/mp4" />
</video>

第二个视频位于模糊视频上方,这是用户要观看的视频。

<video
  key="small-video"
  loop
  muted
  autoPlay
  preload="none"
  poster="/MainVideoPoster.jpg"
  className="w-full h-full object-contain object-center screen-md:object-contain"
>
  <source src={VIDEO_SRC} type="video/mp4" />
</video>

我们的目标是实现类似于此页面的效果:此处

以下是我注意到的问题:

  • 看起来浏览器下载视频两次而不是一次,尽管这两个视频具有相同的源并且在同一页上(第二个位于第一个之上)。

  • 视频未同步播放。例如,由于缓冲,第一个视频暂停,但第二个视频不会同时暂停,因此可以看出模糊视频与其上方的普通视频显示的帧不同。

如何同步这两个视频并确保下载相同的源?是否有更好的实现方式?

谢谢!

英文:

In the application's home/landing page, I placed two videos with autoplay and no controls that the user would see.

Both videos use the same source of an MP4 video of approx. 90MB in size:

&lt;source src={VIDEO_SRC} type=&quot;video/mp4&quot; /&gt;

The first video is of bigger size, is in the background and has a blur effect, so it's just there to improve the visual appearance.

        &lt;video
          key=&quot;big-video&quot;
          loop
          muted
          autoPlay
          preload=&quot;none&quot;
          poster=&quot;/MainVideoPoster.jpg&quot;
          className=&quot;w-full h-full object-cover object-center blur-sm&quot;
        &gt;
          &lt;source src={VIDEO_SRC} type=&quot;video/mp4&quot; /&gt;
        &lt;/video&gt;

The second video is on top of the blurred video. This is the one that the user would watch.

        &lt;video
          key=&quot;small-video&quot;
          loop
          muted
          autoPlay
          preload=&quot;none&quot;
          poster=&quot;/MainVideoPoster.jpg&quot;
          className=&quot;w-full h-full object-contain object-center screen-md:object-contain&quot;
        &gt;
          &lt;source src={VIDEO_SRC} type=&quot;video/mp4&quot; /&gt;
        &lt;/video&gt;

The idea is to achieve something similar to what you can find on this page: here

These are the problems that I noticed:

  • It feels like the browser is downloading the video twice instead of once, even though both videos have the same source and are on the same page (second on top of first)

  • The videos are not synchronized. E.g. the first one pauses due to buffering, the second one doesn't pause at the same time, and it becomes noticeable that the blurry video isn't displaying the same frame as the normal video on top of it.

How can I synchronize both videos and make sure that the same source is being downloaded?

Is there a better way to achieve this?

Thank you!

答案1

得分: 1

抱歉,媒体组(mediaGroup)属性,它可以让你实现你想要的效果,但是它已经不在规范中了,浏览器也在移除它...

另外,请注意,就连LoL网站也存在这个问题。

但是,这不会阻止我们...

你手头的工具可以改变播放速度,获取和设置当前时间。

还有一些事件可供使用,这样你可以在视频因缓冲而停止时做出反应。

// 检查canplay事件,以了解两个视频何时准备好播放并开始它们。
let video1ready, video2ready = false;
function tryStart(){
if(video1ready && video2ready){
video1.play();
video2.play();
}
}
video1.on('canplay', () => {
video1ready = true;
tryStart();
});
video2.on('canplay', () => {
video2ready = true;
tryStart();
});
// 停止加载下一帧时,让另一个视频也等待。
video1.on('waiting', () => { video2.pause(); });
video2.on('waiting', () => { video1.pause(); });
// 从缓冲中恢复播放,继续播放另一个视频。
video1.on('playing', () => { video2.play(); });
video2.on('playing', () => { video1.play(); });

所以,基本上,通过这样做,我们可能能够更接近同步。思路是使两个视频在另一个视频的状态发生变化时播放/暂停。

现在,另一种方法也可以是监视播放时间并将它们同步在一起。这在某种程度上很容易,但如果发生缓冲,正在播放的视频将会在播放时抖动并回退几毫秒。

你可以每隔X毫秒检查一次,然后同步两个视频:

// 每250毫秒将video1的时间设置为video2的时间。
setInterval(() => {
video1.currentTime = video2.currentTime;
}, 250);

比起让视频跳跃,更优雅的解决方案是让它赶上或减慢速度,以便它们能够一起回到正轨...我认为减慢最快的速度会更有意义,因为加快速度需要更多的帧速度,缓冲仍然会发生。你可以在上面的间隔中进行设置。

setInterval(() => {
const delta = Math.abs(video1.currentTime - video2.currentTime);
if (delta < 0.01 && delta > 0) { // 两个视频非常接近,让我们用较难的方式同步它们。
video1.currentTime = video2.currentTime;
}
if (delta > 0.01) {
if (video1.currentTime > video2.currentTime) {
// 根据我们需要在250ms循环中赶上多少毫秒来设置播放速度较低。不要设置得低于0.8,否则会太明显。
video1.playbackRate = Math.max(0.8, 1 - (delta / 0.250));
} else {
video2.playbackRate = Math.max(0.8, 1 - (delta / 0.250));
}
}
}, 250);

我还没有测试过任何东西,但理论上应该可以正常工作。这些数字都是任意的,你可能需要调整它们以达到期望的效果。

此外,我使用了setInterval,但也许requestAnimationFrame会使事情变得更好更准确。

--

我刚刚意识到我只涵盖了同步部分,没有涉及到两个视频使用一个来源的问题。这是因为没有办法实现这一点。正如其他人建议的那样,使用一个缩小版本的源文件来为模糊的视频提供支持,你可以通过压缩来进行优化,即使存在压缩的伪影,当视频模糊时它们不会显示出来。

英文:

Unfortunately, the mediaGroup property which let you achieve just what you wanted is out of specifications and browsers are removing it...

Also, be aware that even LoL website has this problem.

But, that won't stop us...

The tools you have at hand is a way to change playback rate, get and set current time.

There are also events available to you so you can react when a video stops for buffering etc.

// Check canplay event to know when both videos are ready to play and start them.
let video1ready,video2ready  = false;
function tryStart(){
    if(video1ready &amp;&amp; video2ready){
        video1.play();
        video2.play();
    }
}
video1.on(&#39;canplay&#39;,()=&gt;{
    video1ready = true;
    tryStart();
});
video2.on(&#39;canplay&#39;,()=&gt;{
    video2ready = true;
    tryStart();
});
// Stopped to load next frame, make the other video wait too.
video1.on(&#39;waiting&#39;,()=&gt;{video2.pause();});
video2.on(&#39;waiting&#39;,()=&gt;{video1.pause();});
// Resumed from buffering, continue playing the other video too.
video1.on(&#39;playing&#39;,()=&gt;{video2.play();});
video2.on(&#39;playing&#39;,()=&gt;{video1.play();});

So, basically with this, we may be able to get a lot closer to sync. The idea is to simply make both video play/pause if/when the other is changing state.

Now, another approach could also be to monitor the playTime and sync those together. This is somewhat very easy, but if buffering occurs this can get messy as the running video will be jittering while playing and being seek back a few milliseconds.

You could have a check every X milliseconds and synchronize both videos:

// Set video1&#39;s time to video2&#39;s, every 250 millisecond.
setInterval(()=&gt;{
    video1.currentTime = video2.currentTime;
},250);

A more elegant solution than just making the video jump is to make it catch up, or slow down the fastest so they both get back on track together... I'd say slowing down the fartest would make more sense, as speeding up would requires more frames faster and buffering would keep happening. You can play with the playback speed, setting it at 0.8 let's say instead of 1. In an interval, like above.

setInterval(()=&gt;{
    const delta = Math.abs(video1.currentTime - video2.currentTime);
    if(delta  &lt;.01 &amp;&amp; delta &gt; 0){ // Both videos are very close, let&#39;s sync them the hard way.
        video1.currentTime = video2.currentTime;
    }
    if(delta &gt; .01){
        if(video1.currentTime &gt; video2.currentTime){
            // Set the playbackRate lower, according to how many milliseconds we need to catch in the 250ms loop. Without setting lower than 0.8 or it would be too visible.
            video1.playbackRate = Math.max(0.8,1-(delta/.250));
        }else{
            video2.playbackRate = Math.max(0.8,1-(delta/.250));
        }
    }
},250);

I have not tested anything, but the theory is there and it should work at least OK. The numbers are all arbitrary, you may need to play with them to have the desired effects.

Also, I am using setInterval but maybe requestAnimationFrame would make things better and more accurate.

--

I just realized I covered the synchronisation part and nothing about having one source for two videos. This is simply because there is no way to have that. As others suggested, use a scaled down source for the blurred video, you could have it very well optimized even with compression artifacts. They will not show when blurred.

huangapple
  • 本文由 发表于 2023年6月15日 20:40:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76482583.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定