HTML5 - 如何流式传输大型 .mp4 文件?

96

我正在尝试设置一个非常基本的HTML5页面,加载一个大小为20MB的.mp4视频。似乎浏览器需要下载整个视频而不是仅播放视频的一部分并流式传输剩余部分。

这篇文章是我在搜索中找到的最相近的东西...我尝试了Hand Brake和Data Go Round两种方法,但似乎都没有改变:

有什么想法可以做到这一点或者这是否可能呢?

以下是我使用的代码:

<video controls="controls">
    <source src="/video.mp4" type="video/mp4" />
    Your browser does not support the video tag.
</video>
2个回答

171
  1. 确保moov元数据在mdat(音视频数据)之前。这也被称为“快速启动”或“网络优化”。例如,Handbrake有一个“Web Optimized”复选框,而ffmpeg具有输出选项-movflags faststart
  2. 确保您的Web服务器报告正确的Content-Type(video/mp4)。
  3. 确保您的Web服务器已配置为提供字节范围请求
  4. 确保您的Web服务器没有在mp4文件的压缩之上应用gzip或deflate压缩。

您可以使用curl -I http://yoursite/video.mp4检查您的Web服务器发送的标头,或使用浏览器中的开发人员工具(ChromeFirefox)(如果页面已缓存,请重新加载)。 HTTP响应头应包括Content-Type: video/mp4Accept-Ranges: bytes,而不应包括Content-Encoding:


3
@longda:可以显示mp4文件结构的命令行实用程序包括L-SMASH boxdumper,Atomic Parsley -T和mp4v2 mp4file --dump - mark4o
3
为了记录(主要因为我是个笨蛋),你可以通过命令行这样进行调用:atomicparsley <文件名> -T (选项放在最后)。再次感谢@mark4o提供的帮助! - longda
从我的测试来看,我认为 "快速启动"或"网络优化" 选项可以防止文件跳跃。即使我的服务器提供字节范围,当使用videojs播放MP4文件,并点击进度条的末尾时,播放器也会停止工作。 - Avatar
1
@Matheretter:“快速开始”或“网络优化”只是意味着moov位于开头而不是结尾,这样可以在整个文件下载完成之前使用字节范围请求进行寻求。如果这导致寻求不起作用,则检查处理字节范围请求的代码中是否存在错误,如果moov位于末尾,则不会使用它(在了解需要哪些字节之前,它已经下载完整个文件)。我在您的另一个问题中看到您已编写自定义PHP代码来处理此问题。 - mark4o
1
你有这个的参考资料吗? - 0xcaff
显示剩余9条评论

10

以下是我用于在C#(MVC)中创建Web API控制器的解决方案,它将使用字节范围(部分请求)来提供视频文件。部分请求允许浏览器仅下载所需的视频部分以播放,而不是整个视频。这使得它更加高效。

请注意,此功能只适用于最近的版本。

var stream = new FileStream(videoFilename, FileMode.Open, FileAccess.Read , FileShare.Read);

var mediaType = MediaTypeHeaderValue.Parse($"video/{videoFormat}");

if (Request.Headers.Range != null)
{
    try
    {
        var partialResponse = Request.CreateResponse(HttpStatusCode.PartialContent);
        partialResponse.Content = new ByteRangeStreamContent(stream, Request.Headers.Range, mediaType);

        return partialResponse;
    }
    catch (InvalidByteRangeException invalidByteRangeException)
    {
        return Request.CreateErrorResponse(invalidByteRangeException);
    }
}
else
{
    // If it is not a range request we just send the whole thing as normal
    var fullResponse = Request.CreateResponse(HttpStatusCode.OK);

    fullResponse.Content = new StreamContent(stream);
    fullResponse.Content.Headers.ContentType = mediaType;

    return fullResponse;
}

2
这个答案很简单,处理非常简单的流式数据。完美运行。 - James Woodall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接