Skip to content

点播和直播,到底差在哪

很多播放问题的根源是:把直播当点播处理了,或者反过来。

这两件事在浏览器里看着都是 <video> 在放画面,但底层假设完全不同。


一句话区别

点播(VOD)直播(Live)
内容已经全部存在正在产生
时间轴固定,有明确终点没有终点,右端一直往前长
用户能做什么拖到任意位置、倍速、暂停后原地续播只能看"现在";暂停 = 落后于直播
首要指标起播速度、清晰度延迟
断了怎么办从断点继续追到最新,不该从断点继续

最后一行是最容易写错的地方。


为什么直播断线不能"从断点继续"

点播断网重连,回到原来的位置继续播——这是对的,内容不会跑。

直播不行。你断网 30 秒,直播已经往前走了 30 秒。如果重连后从断点继续:

真实直播进度  ────────────────────────▶ 现在
你的播放位置  ──────────▶ 落后 30 秒

而且这个落后永远不会自己追上——你以 1 倍速播放,直播也以 1 倍速产生。 观众会发现自己看到的和弹幕里聊的对不上,越看越怪。

这一条 SDK 目前没有替你处理(坑 #34)

ReconnectPlugin 只做「断网自动重连」(坑 #1 #2),重连逻辑里没有直播分支 —— 它不会帮你追到最新位置。

如果你做的是互动直播,重连后建议自己刷新一次。

⚠️ load 不在组件句柄上——换源的正规方式是改 source prop(声明式)。但这里要的是 「同一个 URL 重新拉一次」,prop 没变化就不会触发。所以要走 getPlayerHandle() 拿底层句柄:

js
// ref 是 <VideoPlayer> / <VideoPlayerFrame> 的 ref
onReconnectSuccess() {
  if (!isLive) return
  ref.value?.getPlayerHandle()?.load(liveSource)   // 重新拉流 = 回到最新
}

getPlayerHandle() 在五种接入方式里的语义见 命令能力矩阵

这个坑登记在案但未实现,和另外 7 个一起列在 还没做的清单里。

不过 live: true 仍然必须传——它决定选源优先级:

js
{ url: '...', live: true }   // 直播优先 FLV(延迟低),点播优先 HLS(有 ABR)

漏了它,直播会按点播的优先级选源,白白多十几秒延迟。


为什么直播的缓冲策略完全相反

点播:缓冲越多越好。 网络好的时候多缓一点,后面卡了有余量。

直播:缓冲就是延迟。 你缓冲了 10 秒的内容,意味着你看到的画面比现场晚 10 秒。

这就是直播播放器的核心矛盾:

缓冲少 → 延迟低,但一抖就卡
缓冲多 → 很流畅,但延迟高

不同协议在这条线上的取舍不同,这也是三种协议那篇要讲的事。


时间轴的差异会漏进你的 UI

timeupdate 事件在两种场景下含义不同:

vue
<script setup lang="ts">
import { VideoPlayerFrame } from '@sentinel-lab/video-vue-frame'

const src = 'https://your-cdn/video.m3u8'

function onTimeUpdate({ time, duration }: { time: number; duration: number }) {
  // 点播:duration 是总时长,time/duration 就是进度百分比
  // 直播:**duration 恒为 0**,不是 Infinity —— Infinity 过不了 JSON 序列化,
  // player-core 在源头就把它归一成 0(直播本来也不该读 duration)
}
</script>

<template>
  <VideoPlayerFrame :source="src" @time-update="onTimeUpdate" />
</template>

直播不要画进度条——没有"百分之多少"这回事。画一个"直播中"标签 和"回到最新"按钮更合理。

参考实现里的 LiveBadge.vue 就是干这个的。


一个中间形态:直播回放

直播结束后生成的录像,本质是点播

  • live: false(或不传)
  • 用 HLS 就够,不需要 FLV
  • 可以拖进度条、可以倍速

别因为它"来自直播"就当直播处理。判断标准只有一个: 内容是已经全部存在,还是正在产生?


接下来