HLS(HTTP Live Streaming)是如今大多数网站播放点播视频所用的格式。它不是一个巨大的 MP4 文件,而是用一个小小的文本播放列表来描述视频,列表指向同一视频的多个版本,每个版本都被切成短片段。播放器会提前下载几个片段,测量它们到达的速度,并随时在版本之间切换。使用手机网络的观众拿到轻量版本,使用光纤的观众看到清晰版本,而且没有人需要等整个文件下载完才能看到第一帧。
本指南介绍两种把 UFOLOAD 上的 HLS 视频放到你自己网页上的方法:一种是用 iframe 嵌入现成的播放器,大约一分钟就能完成;另一种是用 hls.js 驱动你自己的 <video> 元素,让你完全掌控页面。两者使用同一个视频流,所以你可以先用 iframe,以后再换成 hls.js,无需重新上传任何内容。
UFOLOAD 的 HLS 流是什么样的
文件上传后,转码器会用 H.264 视频和 AAC 立体声音频将其编码为一到四个版本,称为清晰度档位(rendition):360p、720p、1080p 和 2160p(4K)。档位绝不会超过源文件,因此上传 720p 的视频会生成 720p 和 360p,而不会放大成 1080p。你实际能获得的最高档位还取决于你的套餐,当前限制见价格页面。如果想全面了解档位是如何选定的,请阅读自适应码率阶梯详解。
每个档位都以普通 MP4 的形式存储,索引位于文件开头。观众开始播放时,存储层会即时把这些 MP4 文件封装成 HLS:主播放列表(master.m3u8)列出每个档位及其峰值带宽、分辨率和编解码器,而每个档位都有自己的播放列表,由四秒长的片段组成。关键帧的位置与片段边界对齐,正因如此,播放器才能在视频中途干净利落地切换画质。
播放列表和片段由缓存节点提供,并带有 Access-Control-Allow-Origin: * 响应头,因此运行在你域名上的播放器可以直接请求它们。每个 URL 都经过签名并带有过期时间,这一点在后面讨论 hls.js 方案时会很重要。
第 1 步:上传视频并等待就绪
你可以在控制面板中拖入文件或粘贴直链上传,也可以使用 FTP、WebDAV 或 API(curl、Python 和 Node.js 示例见通过 API 上传视频)。文件会依次经历 uploading、queued、processing 和 ready 这几个状态;failed 状态会附带原因,并可在控制面板中重试。短片几分钟内即可就绪,长片需要更久,付费套餐享有优先编码队列。
你不必等到页面完全做好。如果有人在文件仍在处理时打开播放器,播放器会显示带进度的处理提示,并在处理完成后自动切换到视频。不过,发布页面前还是要确认状态为 ready,以免页面上线后,最早的访客看到的只是一个进度条。
你需要视频的标识符。控制面板会在分享面板中显示它,API 则以 public_id 字段返回,这是一个 11 个字符的短代码。嵌入地址中填写的就是这个代码。
第 2 步:用 iframe 嵌入播放器
上传完成后,以及在每个视频的分享面板中,控制面板都会提供一段 iframe 代码,看起来就像下面第一段代码。将 VIDEO_ID 替换为你的视频标识符即可。播放器页面本身不会被搜索引擎收录,这正是嵌入所需要的:参与排名的是你的页面,而不是播放器框架。
<iframe width="640" height="360"
src="https://iframe.andromedans.live/e/VIDEO_ID"
title="My video"
frameborder="0"
allow="autoplay; fullscreen; picture-in-picture"
allowfullscreen></iframe>固定的像素尺寸在手机上会出问题。要做响应式页面,可以把 iframe 包在一个保持 16:9 比例的容器里,让框架填满它。播放器会铺满整个框架,因此视频可以平滑缩放。
<div style="position:relative;aspect-ratio:16/9;max-width:960px">
<iframe src="https://iframe.andromedans.live/e/VIDEO_ID"
title="My video"
style="position:absolute;inset:0;width:100%;height:100%;border:0"
loading="lazy"
allow="autoplay; fullscreen; picture-in-picture"
allowfullscreen></iframe>
</div>可以添加到地址中的参数
autoplay=1会在播放器加载后开始播放。大多数情况下浏览器会阻止带声音的自动播放,所以请配合mute=1使用。mute=1让视频以静音状态开始播放,观众可以随时取消静音。loop=1让视频在结束后从头重新播放。t=30从第 30 秒开始播放,便于用深层链接直接跳到长视频中的某个时刻。
地址中的参数总是优先于播放器工作室中的同名设置。播放器工作室适合设置全局默认值,例如皮肤、强调色、Logo 和按钮布局;当某个页面需要不同表现时,就使用参数。你甚至可以为每个嵌入域名保留单独的播放器配置文件。
如果播放器提示不允许嵌入,很可能是你页面的域名不在允许嵌入的域名列表中。要了解这个列表如何工作,请参阅域名锁定与地区限制。
第 3 步(可选):用 hls.js 播放视频流
iframe 是最快捷的方式,但有时你需要自己的页面结构:自定义控制栏、放在轮播图里的视频、由你自己的代码发出的统计事件。这时你需要播放列表地址和一个播放器库。除 Safari 外,其他浏览器都无法原生播放 HLS,因此通常的选择是 hls.js,这是一个把 HLS 片段送入标准 <video> 元素的 JavaScript 库。Safari 和 iOS 原生支持 HLS,不需要它。
播放列表地址就是视频对象的 links.playback 字段。请在你的服务器上用 API 密钥请求它,因为密钥绝不能出现在浏览器代码中。同一个请求还会返回 links.expires_at;链接带签名且有时效,所以每次渲染页面时都要请求新链接,而不是把链接存进数据库。
const BASE = 'https://ufoload.com/api/v1'
export async function playbackUrl(fileId) {
const res = await fetch(`${BASE}/files/${fileId}`, {
headers: { Authorization: `Bearer ${process.env.UFOLOAD_API_KEY}` },
})
if (!res.ok) throw new Error(`UFOLOAD API: ${res.status}`)
const { file, links } = await res.json()
if (file.status !== 'ready') return null // still processing
return links.playback // signed master.m3u8 URL
}如果需要默认值以外的有效期,POST /files/{id}/links 接受 60 秒到 30 天之间的 ttl,还可以把链接绑定到 IP 地址或 Cookie。完整说明见 API 文档。另外还有一个无需密钥的公开端点 GET /api/v1/public/files/{id},观看页和嵌入页使用的就是它,其链接有效期为六小时。
在页面上创建播放器。下面的代码在支持的环境中使用 hls.js,在 Safari 上回退到原生播放,其他情况下显示一条简单的提示。请自行托管库文件或固定版本号,而不是总加载最新版。
<video id="player" controls playsinline preload="metadata"
poster="POSTER_URL" style="width:100%;aspect-ratio:16/9;background:#000"></video>
<script src="/vendor/hls.min.js"></script>
<script>
const video = document.getElementById('player')
const src = 'PLAYLIST_URL_FROM_YOUR_SERVER'
if (window.Hls && Hls.isSupported()) {
const hls = new Hls()
hls.loadSource(src)
hls.attachMedia(video)
hls.on(Hls.Events.ERROR, (_, data) => {
if (!data.fatal) return
if (data.type === Hls.ErrorTypes.NETWORK_ERROR) hls.startLoad()
else if (data.type === Hls.ErrorTypes.MEDIA_ERROR) hls.recoverMediaError()
else hls.destroy()
})
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = src // Safari, iOS
} else {
video.outerHTML = '<p>This browser cannot play HLS video.</p>'
}
</script>视频对象还带有用作封面图的 links.poster,以及用于悬停预览缩略图的 links.sprite,如果你自己做进度条,可以用上它们。使用 hls.js 意味着放弃 UFOLOAD 播放器替你完成的那些功能:画质菜单、章节、字幕选择、Logo 叠加,以及在有广告可投放时显示的广告。这才是真正的取舍,下表做了总结。
iframe 还是 hls.js:该用哪个
| 问题 | iframe 播放器 | 在你的页面上使用 hls.js |
|---|---|---|
| 搭建时间 | 一分钟,复制粘贴即可 | 一小时或更久,另需一个小型服务器端点 |
| 播放器功能 | 画质菜单、章节、字幕、悬停预览、Logo,以及有广告时的广告 | 你自己做什么就有什么 |
| 变现 | 有广告可投放时,广告会在播放器中展示并计数 | 不可用,因为广告层位于 UFOLOAD 播放器中 |
| 样式 | 在播放器工作室中设置皮肤、颜色、Logo 和按钮 | 任意 HTML 和 CSS |
| 链接过期 | 自动处理 | 每次渲染页面时都要请求新链接 |
| 域名锁定 | 强制执行允许嵌入的域名列表 | 不适用于你自己提供的链接,因此请使用较短的 TTL 并绑定 IP 或 Cookie |
故障排查清单
- 黑屏或一直转圈。 打开浏览器的网络面板,查找
master.m3u8。返回 403 说明链接已过期,或者观众被国家/地区或 IP 规则拦截;请请求新链接。 - 在 HTTPS 页面上被浏览器拦截。 所有内容都必须走 HTTPS。切勿把
http://地址粘贴到 iframe 或 hls.js 中。 - 自动播放没有反应。 浏览器会阻止带声音的自动播放。请添加
mute=1,或在 hls.js 中调用play()之前设置video.muted = true。 - 显示处理提示而不是视频。 文件尚未就绪。轮询
GET /files/{id},直到status变为ready。 - 只能播放低画质。 播放器起步较保守,测出吞吐量后会立即提升画质。你的套餐和源文件也会限制最高档位;请对照价格和功能页面。
页面跑通之后,你可能想防止盗链,或者在有广告可投放时从中获得收益。接下来的指南分别介绍了这两点:限制视频可被嵌入的位置和在播放器中投放广告,为你的视频网站变现。如果你还在考虑把视频托管在哪里,视频托管选择清单列出了需要比较的要点。