媒体源扩展中的有趣行为

问题描述 投票:0回答:1

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

  1. 视频播放器播放第一段
  2. 源缓冲区数据耗尽,导致视频暂停
  3. 当用户准备好后,他们点击一个按钮,将第2段添加到源缓冲区。
  4. 视频继续播放第2段

这很好用,只是当视频出现在步骤2中暂停时,它并没有停止在第一段的最后一帧。相反,它停止在第一段结束前两帧。这最后两帧并没有被丢弃,只是被播放了。之后 用户点击按钮来推进视频。这是我的应用程序的一个问题,并且 我正在想办法确保在步骤2结束前播放第一段的所有帧。.

我怀疑这最后两帧在视频解码器缓冲区中被卡住了。尤其是在我的媒体源上调用endOfStream(),在将第1个片段添加到源缓冲区后,会导致第1个片段一直播放,没有任何帧遗留。

其他信息

  • 我使用下面的ffmpeg命令从一系列PNGs中创建了每个视频段文件。

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

  • 也许这就是一个线索?流媒体结束的情况没有正确处理(最后一帧被丢弃)。
  • 另一个有趣的事情是,如果视频只有2帧或更少,MSE根本不会播放。
  • 我使用的浏览器是Chrome。我的MSE播放器的代码只是取自Google Developers的例子,但为了完整起见,我还是把它贴在这里。这段代码只涵盖了第2步,因为这就是问题所在。
<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));
}

ffmpeg html5-video mp4 h.264 media-source
1个回答
0
投票

这很好用,只是当视频在步骤2中出现暂停时,它并没有停止在第一段的最后一帧。取而代之的是,它停止在第1个片段结束前的两帧。这最后两帧并没有被丢弃,只是在之后播放......

这种行为取决于浏览器。让我们从以下几个方面开始 规范报价:

当媒体元素需要更多的数据时,用户代理应该尽早将其从HAVE_ENOUGH_DATA过渡到HAVE_FUTURE_DATA,以便网络应用能够在不造成播放中断的情况下做出响应。例如,当当前回放位置在缓冲数据结束前500ms时进行过渡,使应用程序在回放停顿前有大约500ms的时间来追加更多的数据。

你所看到的行为是MSE兼容的浏览器意识到数据流还没有结束,但它也意识到它的数据正在耗尽。它通过改变它的 准备就绪状态 但它没有义务播放它已经持有的每一帧。它根据当前播放的时钟时间与可用数据的结束时间进入缓冲状态。

尽管上面的链接说...

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

......实际的实现可能会有不同的解释,并改用 HAVE_CURRENT_DATA 有点太早了,那就是多保留了几个视频帧,但知道它还没有结束流和进一步的帧丢失。这是一种浏览器实现的特殊性,你只能忍受。

© www.soinside.com 2019 - 2024. All rights reserved.