介绍flv.js以及前端使用flv.js通过useWebsocket动态获取视频流地址进行播放

简介

flv.js是一款使用纯 JavaScript 编写的 HTML5 Flash 视频 (FLV) 播放器,无需 Flash即可播放视频。

  • 具有 H.264 + AAC / MP3 编解码器播放功能的 FLV 容器
  • 多部分分段视频播放
  • HTTP FLV低延迟直播流播放
  • 通过 WebSocket 播放 FLV 直播流
  • 兼容 Chrome、FireFox、Safari 10、IE11 和 Edge
  • 极低的开销,并由您的浏览器硬件加速

tips:对于 FLV 直播流播放,可以考虑使用mpegts.js,mpegts.js 针对低延迟实时流播放进行了优化,例如 DVB/ISDB 电视或监控摄像头, 基于flv.js开发。

概述

flv.js 的工作原理是将 FLV 文件流转换为 ISO BMFF(碎片 MP4)片段,然后<video>通过媒体源扩展API 将 mp4 片段输入 HTML5 元素。

演示

flv.js demo

安装

npm install --save flv.js

方法

flvjs.createPlayer()

function createPlayer(mediaDataSource: MediaDataSource, config?: Config): Player;

根据中指定的type字段创建一个播放器实例mediaDataSource(可选)config。

MediaDataSource
FieldTypeDescription
typestring媒体类型,'flv'或'mp4'
isLive?boolean数据源是否为实时流
cors?boolean是否启用CORS进行http提取
withCredentials?boolean是否对Cookie进行http提取
hasAudio?boolean流是否有音频轨道
hasVideo?boolean流中是否有视频轨道
duration?number总媒体持续时间(以毫秒为单位)
filesize?number媒体文件的总文件大小,以字节为单位
url?string表示媒体URL,可以以'https(s)'或'ws(s)'(WebSocket)开头
segments?Array<MediaSegment>多段播放的可选字段,请参见MediaSegment

如果segments存在字段,则transmuxer会将其MediaDataSource视为多部分源。

在多部分模式下,结构中的duration filesize url字段MediaDataSource将被忽略。

MediaSegment
FieldTypeDescription
durationnumber必填字段,指示段持续时间(以毫秒为单位)
filesize?number可选字段,指示段文件大小(以字节为单位)
urlstring必填字段,指示段文件URL

 

Config
FieldTypeDefaultDescription
enableWorker?booleanfalse启用分离的线程进行转换(暂时不稳定)
enableStashBuffer?booleantrue启用IO隐藏缓冲区。如果您需要实时(最小延迟)来进行实时流播放,则设置为false,但是如果网络抖动,则可能会停顿。
stashInitialSize?number384KB指示IO暂存缓冲区的初始大小。默认值为384KB。指出合适的尺寸可以改善视频负载/搜索时间。
isLive?booleanfalse同样要isLive在MediaDataSource,如果忽略已经在MediaDataSource结构集合。
lazyLoad?booleantrue如果有足够的数据可播放,则中止http连接。
lazyLoadMaxDuration?number3 * 60指示要保留多少秒的数据lazyLoad
lazyLoadRecoverDuration?number30指示lazyLoad恢复时间边界,以秒为单位。
deferLoadAfterSourceOpen?booleantrue在MediaSource sourceopen事件触发后加载。在Chrome上,在后台打开的标签页可能不会触发sourceopen事件,除非切换到该标签页。
autoCleanupSourceBufferbooleanfalse对SourceBuffer进行自动清理
autoCleanupMaxBackwardDurationnumber3 * 60当向后缓冲区持续时间超过此值(以秒为单位)时,请对SourceBuffer进行自动清理
autoCleanupMinBackwardDurationnumber2 * 60指示进行自动清除时为反向缓冲区保留的持续时间(以秒为单位)。
fixAudioTimestampGapbooleantrue当检测到较大的音频时间戳间隙时,请填充无声音频帧,以避免A / V不同步。
accurateSeek?booleanfalse精确查找任何帧,不限于视频IDR帧,但可能会慢一些。可用的Chrome > 50,FireFox和Safari。
seekType?string'range''range'使用范围请求进行搜索,或'param'在url中添加参数以指示请求范围。
seekParamStart?string'bstart'指示的搜索起始参数名称 seekType = 'param'
seekParamEnd?string'bend'指示的搜索结束参数名称 seekType = 'param'
rangeLoadZeroStart?booleanfalseRange: bytes=0-如果使用范围查找,则发送首次负载
customSeekHandler?objectundefined指示自定义搜索处理程序
reuseRedirectedURL?booleanfalse重复使用301/302重定向的url进行子序列请求,例如搜索,重新连接等。
referrerPolicy?stringno-referrer-when-downgrade指示使用FetchStreamLoader时的推荐人策略
headers?objectundefined指示将添加到请求的其他标头

flvjs.isSupported()

如果您的浏览器支持使用flv.js,则返回true

function isSupported(): boolean;

flvjs.getFeatureList()

function getFeatureList(): FeatureList;

返回FeatureList具有以下详细信息的对象:

FeatureList
FieldTypeDescription
mseFlvPlaybackboolean与flvjs.isSupported()相同,表示您的浏览器是否可以进行基本播放。
mseLiveFlvPlaybackbooleanHTTP FLV实时流是否可以在您的浏览器上工作。
networkStreamIOboolean指示网络加载程序是否正在流式传输。
networkLoaderNamestring指示网络加载程序类型名称。
nativeMP4H264Playbackboolean指示您的浏览器是否本身支持H.264 MP4视频文件。
nativeWebmVP8Playbackboolean指示您的浏览器是否本机支持WebM VP8视频文件。
nativeWebmVP9Playbackboolean指示您的浏览器是否本机支持WebM VP9视频文件。

实例方法


flv.js 提供了一系列方法来控制视频的播放、暂停、销毁等操作。

1.createPlayer


创建一个新的播放器实例。

参数

  • mediaDataSource(对象):包含流媒体的相关信息。
  • config(对象,可选):播放器的配置选项。
var flvPlayer = flvjs.createPlayer({
    type: 'flv',
    url: 'http://example.com/live.flv'
}, {
    isLive: true,
    enableWorker: true
});


2. attachMediaElement(element)


参数:

  • element(HTMLMediaElement):要绑定的 HTMLMediaElement,例如 <video> 标签。

说明:将播放器绑定到指定的 HTMLMediaElement。

flvPlayer.attachMediaElement(document.getElementById('videoElement'));


3. load()


参数:无
说明:加载媒体资源。调用此方法后,播放器将开始缓冲媒体数据。
 

flvPlayer.load();


4. play()


参数:无
说明:开始播放媒体。如果媒体已经加载,则从当前位置开始播放。

flvPlayer.play();


5. pause()


参数:无
说明:暂停播放。

flvPlayer.pause();


6. destroy()


参数:无
说明:销毁播放器实例并释放相关资源。

flvPlayer.destroy();


7. seek(seconds)


参数:

  • seconds(Number):要跳转到的位置,以秒为单位。

说明:将播放位置跳转到指定的时间点。

flvPlayer.seek(30); // 跳转到 30 秒的位置


8. updateStashBuffer(newBufferSize)


功能:动态更新播放器的缓冲区大小。
参数:

  • newBufferSize(Number):新的缓冲区大小,以秒为单位。此参数决定了播放器预加载数据的时长。

返回值:无
适用场景:当需要根据实时网络状况或播放情况调整缓冲区大小时,可以使用该方法。例如,丢帧时增大缓冲区以减少卡顿,或者当网络状况改善时减小缓冲区以降低延迟。


9. on(event, callback)


参数:

  • event(String):要监听的事件名称。
  • callback(Function):事件触发时调用的回调函数。

说明:注册一个事件监听器,用于处理播放器的各种事件。
 

flvPlayer.on(flvjs.Events.ERROR, function(eventType, detail) {
    console.error('Error type:', eventType);
    console.error('Error detail:', detail);
});

示例代码

<template>
  <div>
    <video id="videoElement" crossOrigin="anonymous" controls autoplay muted
      style="width: 100vw; height: calc(100vh - 6px)" />
  </div>
</template>
<script lang="ts" setup>
import { ref, onMounted, watchEffect, nextTick, onBeforeUnmount, reactive } from "vue";
import flvjs from "flv.js";
import { useWebSocket } from "@vueuse/core";

const isShowModal = ref(false);
const flvPlayer = ref();
const state = reactive({
  server: "ws://xx.xx.xx.xx:xxx/websocket", // 测试地址
  playUrl: "",
  status: ""
});

/**
 * status 是连接的状态值
 * data 是 socket 推送过来的消息
 */
const { status, data } = useWebSocket(state.server, {
  onConnected: function (ws) {
    console.log('websocket 连接成功!', ws)
  },
  onDisconnected: function (ws, event) {
    console.log('onDisconnected')
  },
  onError: function (ws, event) {
    console.log('onError')
  },
  onMessage: function (ws, event) {
    console.log('event.data', event.data)
    if (event.data) {
      const parsedData = JSON.parse(event.data)
      state.playUrl = parsedData.url;
    // 这里写对应的业务逻辑
    ......
    }
  },
  autoReconnect: true,
  heartbeat: false
});

// 设置视频配置(注意:createVideo应放在异步函数里或mounted之后,不可在created里直接加载,否则不生效)

const createVideo = () => {
  if (flvjs.isSupported()) {
    flvPlayer.value = flvjs.createPlayer(
      {
        type: "flv",
        isLive: true,
        // hasAudio: true, // 播放的音频文件是否有声音,这里若设置错误,视频会播放不出来
        url: state.playUrl
      },
      {
        enableWorker: false, // 是否多线程工作
        enableStashBuffer: false, // 是否启用缓存
        stashInitialSize: 128, // 缓存大小(kb)  默认384kb
        autoCleanupSourceBuffer: true // 是否自动清理缓存
      }
    );

    let videoElement = document.getElementById("videoElement");
    flvPlayer.value.attachMediaElement(videoElement); //挂载元素
    if (state.playUrl !== "") {
      flvPlayer.value.load(); //加载流
      flvPlayer.value.play(); //播放流
    }

    // 报错重连
    flvPlayer.value.on(flvjs.Events.ERROR, handleError);
  }
};

const destoryVideo = () => {
  if (flvPlayer.value) {
    flvPlayer.value.pause(); // 暂停播放数据流
    flvPlayer.value.unload(); // 取消数据流加载
    flvPlayer.value.detachMediaElement(); // 将播放实例从节点中取出
    flvPlayer.value.destroy(); // 销毁播放实例
    flvPlayer.value = null;
  }
};

const reloadVideo = () => {
  destoryVideo();
  createVideo();
};

const handleError = (err: any, errdet: any) => {
  if (err === flvjs.ErrorTypes.NETWORK_ERROR) {
    console.log("网络错误");
    if (errdet === flvjs.ErrorDetails.NETWORK_STATUS_CODE_INVALID) {
      console.log("http状态码异常");
    }
  } else if (err === flvjs.ErrorTypes.MEDIA_ERROR) {
    console.log("媒体错误");
    if (errdet === flvjs.ErrorDetails.MEDIA_FORMAT_UNSUPPORTED) {
      console.log("媒体格式不支持");
    }
  } else if (err === flvjs.ErrorTypes.OTHER_ERROR) {
    console.log("其他异常:", errdet);
  }

  reloadVideo();
};

onMounted(() => {
  nextTick(() => {
    createVideo();
  });
});
onBeforeUnmount(() => {
  destoryVideo();
});
</script>

可能遇到的问题

1.隐藏浏览器视频页面时,直播视频会自动暂停,重新回来到页面时,继续播放的还是隐藏浏览器视频页面前的画面,不是实时画面

原因分析:这种现象可能是由于浏览器默认行为导致的。在浏览器中,当页面切换到后台或不可见状态时,浏览器会暂停视频和其他资源的播放,以降低性能消耗。当页面再次切换到前台或可见状态时,浏览器会自动恢复资源的播放。这可能导致 FLV 视频流在切换页面时暂停播放,从而导致一段时间的延迟。

解决方法:

// 视频页面不在前台时,浏览器自动暂停视频,当页面恢复在前台时,跳转至最新时间播放
const seekFn = () => {
  if (flvPlayer.value && flvPlayer.value.buffered.length) { // 监听通过判断buffered属性(该属性记录了视频的缓存范围),若存在buffered,则应该将currentTime赋值到缓存范围尾端
    flvPlayer.value.currentTime = flvPlayer.value.buffered.end(0) - 0.1; // 指向当前buffer.end(index)往前一点点继续播
  }
}

onMounted(() => {
  // 监听浏览器的显隐
  document.addEventListener('visibilitychange', function () {
    // 离开了当前页面时触发
    if (document.visibilityState === 'hidden') {
      //   console.log('hidden');
    }
    // 打开或回到页面时触发
    if (document.visibilityState === 'visible') {
      // 防止视频延时
      seekFn()
    }
  });
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值