首页 > 解决方案 > 媒体源扩展中的有趣行为

问题描述

我正在尝试使用 Media Source Extensions 构建一个相当标准的视频播放器;但是,我希望用户能够控制播放器何时移动到新的视频片段。例如,我们可能会看到以下行为:

  1. 视频播放器播放第一段
  2. 源缓冲区用完数据导致视频出现暂停
  3. 当用户准备好时,他们单击一个按钮,将第二段添加到源缓冲区
  4. 视频继续播放第二段

这很好用,除了当视频在第 2 步中出现暂停时,它不会在第 1 段的最后一帧停止。相反,它会在第一段结束前停止两帧。最后两帧不会被丢弃,它们只是用户单击按钮以推进视频后播放。这对我的应用程序来说是一个问题,我正在尝试找出一种方法来确保第 1 段中的所有帧都在 step 2 结束之前播放

我怀疑最后两帧在视频解码器缓冲区中被阻塞。特别是因为在将第一个片段添加到源缓冲区后在我的媒体源上调用 endOfStream() 会导致第一个片段一直播放,并且没有留下任何帧。

附加信息

ffmpeg -i %04d.png -movflags frag_keyframe+empty_moov+default_base_moof video_segment.mp4

<script>
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen, { once: true });

function sourceOpen() {
  URL.revokeObjectURL(video.src);
  const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.64001f"');
  sourceBuffer.mode = 'sequence';

  // Fetch the video and add it to the Source Buffer
  fetch('https://s3.amazonaws.com/bucket_name/video_file.mp4')
  .then(response => response.arrayBuffer())
  .then(data => sourceBuffer.appendBuffer(data));
}

标签: ffmpeghtml5-videomp4h.264media-source

解决方案


这很好用,除了当视频在第 2 步中出现暂停时,它不会在第 1 段的最后一帧停止。相反,它会在第一段结束前停止两帧。最后两帧没有被丢弃,它们只是在之后播放......

此行为取决于浏览器。让我们从规范报价开始:

当媒体元素需要更多数据时,用户代理应该足够早地将其从 HAVE_ENOUGH_DATA 转换为 HAVE_FUTURE_DATA 以便 Web 应用程序能够响应而不会导致播放中断。例如,当当前播放位置在缓冲数据结束前 500 毫秒时进行转换,使应用程序有大约 500 毫秒的时间在播放停止前追加更多数据。

您看到的行为是与 MSE 兼容的浏览器知道流尚未结束,但它也知道它正在用完数据。它通过更改其就绪状态来指示需要进一步的数据,但是它没有义务播放它已经拥有的每一帧。它根据当前播放的时钟时间与可用数据的结束进入缓冲状态。

即使上面的链接说...

例如,在视频中,这对应于用户代理具有来自当前帧的数据,但没有来自下一帧的数据

...实际的实现可能会对此有不同的解释,并且切换到HAVE_CURRENT_DATA有点过早,即持有更多的视频帧,但知道它还没有结束流并且缺少更多的帧。这是一种你必须忍受的浏览器实现特性。


推荐阅读