当前位置: 首页 > news >正文

h265 flv.js组件封装Vue3

组件playVideo.vue

<!-- flv视频播放组件 -->
<template>
  <div class="videoPlayer">
    <!-- 标题 -->
    <div class="title">
      <span></span>
      <span>{{ videoObj.title }}</span>
      <span class="closeIco" @click="closeVideo(videoObj.videoObj.id)">×</span>
    </div>
    <!-- 视频 -->
    <div class="videoBox">
      <video @click="preventDefaultClick" muted playsinline :id="videoObj.videoObj.id"
        class="video video-js vjs-default-skin vjs-big-play-centered" ref="videoElement" controlsList="nodownload"
        disablePictureInPicture style="object-fit: fill !important;" controls></video>
    </div>
    <!-- 控制台 -->
    <!-- <div class="controls"></div> -->
  </div>
</template>

<script setup>
import { useCarStore } from '@/store/carStore';
import { nextTick } from 'vue';
const carStore = useCarStore();

const props = defineProps({
  videoObj: {
    type: Object,
    default: () => {
      return {};
    },
  },
});
// 获取 video 元素的引用 
const videoElement = ref(null);
let flvPlayer = null;
let id = ref(null);

watch(() => props.videoObj,
  async (val) => {
    if (val.videoObj.id == id.value) return;
    id.value = val.videoObj.id;
    console.log("视频组件接收到", val);
    // console.log("视频组件接收到", val.videoObj.url);
    let url = val.videoObj.url;
    // let url = "http://116.62.199.225:9980/httpflv.rplay.d390159f9576e142a6c0c5ff35f443bf.admin*5bd5ed5652c0c639fcc027dc90951fff.8802.1.0.1";
    if (!url) return;
    await nextTick();

    setTimeout(() => {
      initPlayer(url);
    }, 1000);

  },
  { immediate: true }
);

const initPlayer = (url) => {

  // 先销毁旧实例
  if (flvPlayer) {
    flvPlayer.pause();
    flvPlayer.unload();
    flvPlayer.detachMediaElement();
    flvPlayer.destroy();
    flvPlayer = null;
  }

  if (!flvjs.isSupported()) {
    console.error('FLV is not supported');
    return;
  }

  flvPlayer = flvjs.createPlayer({
    type: 'flv',
    url: url,
    cors: true,
    isLive: true, //是否为直播流
    hasAudio: false, //是否包含音频
    hasVideo: true, //是否包含视频
    autoplay: true, // 自动播放
    stashInitialSize: 512  // 增大初始缓存
    // muted: true, // 静音
    // language: "zh-CN",
    // controls: true, // 启用控件
    // preload: "auto", // 自动加载
    // errorDisplay: true, // 错误展示
    // fluid: false, // 跟随外层容器变化大小
    // loop: false, // 循环播放
    // notSupportedMessage: "此视频暂无法播放,请稍后再试",
    // userActions: {
    //   hotkeys: true, // 是否支持热键
    // }
  }, {
    enableStashBuffer: true,  // 强制启用缓存
    autoCleanupSourceBuffer: false,  // 关闭自动清理
    stashSize: 2 * 1024 * 1024  // 设置2MB缓存区
    // enableStashBuffer: false, //是否启用缓冲区
    // fixAudioTimestampGap: false, //是否修复音频时间戳的间隙
    // autoCleanupSourceBuffer: true,  // 自动清理 SourceBuffer[2](@ref)
    // autoCleanupMaxBackwardDuration: 30  // 延长清理间隔(单位秒)
  });

  flvPlayer.attachMediaElement(videoElement.value);
  flvPlayer.load();
  flvPlayer.play();
};

// 请求视频并设置 URL
// onMounted(() => {
//   const url = "http://116.62.199.225:9980/httpflv.rplay.d390159f9576e142a6c0c5ff35f443bf.admin*5bd5ed5652c0c639fcc027dc90951fff.8802.1.0.1";

//   if (url) {
//     initPlayer(url);
//   } else {
//     console.error('Video URL is not provided');
//   }
// });

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

// 点击关闭单个视频
const closeVideo = async (id) => {
  // if (flvPlayer) {
  //   flvPlayer.pause();
  //   await new Promise(r => setTimeout(r, 300)); // 增加300ms延迟
  //   flvPlayer.unload();
  //   flvPlayer.detachMediaElement();
  //   flvPlayer.destroy();
  // }
  if (flvPlayer) {
    try {
      // 等待播放器状态稳定
      await flvPlayer.pause();
      flvPlayer.unload();
      flvPlayer.detachMediaElement();
      await new Promise(resolve => setTimeout(resolve, 200)); // 缓冲区清理延迟
    } catch (e) {
      console.warn('Player cleanup warning:', e);
    } finally {
      flvPlayer.destroy();
      flvPlayer = null;
    }
  }
  nextTick(() => {
    carStore.removeCarById(id);
  });
};
// const closeVideo = (id) => {
//   if (flvPlayer) {
//     flvPlayer.pause(); // 暂停播放数据流
//     flvPlayer.unload(); // 取消数据流加载
//     flvPlayer.detachMediaElement(); // 将播放实例从节点中取出
//     flvPlayer.destroy(); // 销毁播放实例
//     flvPlayer = null;
//   }
//   nextTick(()=>{
//     carStore.removeCarById(id);
//   })
// };

// 点击视频阻止默认时间
const preventDefaultClick = (event) => {
  event.preventDefault();
};

// onMounted(() => {
//   console.log(6666, H265Player);
// });

// const currentPlayer = ref(null);
/**
 * 数据部分
 */
// const data = reactive({
//   id: null,
//   currentPlayer: null,
//   initNum: 0,
//   player: null,
//   options: {
//     autoplay: true, // 自动播放
//     muted: true, // 静音
//     language: "zh-CN",
//     controls: false, // 控制条
//     preload: "auto", // 自动加载
//     errorDisplay: true, // 错误展示
//     fluid: false, // 跟随外层容器变化大小,跟随的是外层宽度
//     loop: false, // 循环播放
//     // width: "500px",
//     // height: "500px",
//     // controlBar: false, // 设为false不渲染控制条DOM元素,只设置controls为false虽然不展示,但是存在
//     // textTrackDisplay: false,  // 不渲染字幕相关DOM
//     userActions: {
//       hotkeys: true, // 是否支持热键
//     },
//     notSupportedMessage: "此视频暂无法播放,请稍后再试",
//     // notSupportedMessage: "",
//     // techOrder: ["h5", "flash"], // 定义Video.js技术首选的顺序
//     sources: [
//       {
//         src: "", // 视频或者直播地址
//         // src: "http://116.62.199.225:9980/httpflv.rplay.4328eea7-9ce9-4f3e-8731-69c344007546.admin*5bd5ed5652c0c639fcc027dc90951fff.1444.2.0.1", // 视频或者直播地址
//         // type: "application/x-mpegURL",
//         // type: "rtmp/flv"
//         type: "video/x-flv"
//       },
//     ],
//   },
// });
// const { id, player, options, currentPlayer } = toRefs(data);

// 初始化视频播放器
// const init = () => {
//   if (player.value) {
//     player.value.dispose();
//   }
//   try {
//     player.value = videojs(
//       currentPlayer.value,
//       options.value,
//       function onPlayerReady() {
//         videojs.log(`Your player is ready!`);
//       }
//     );
//   } catch (error) {
//     console.error('Failed to initialize video player:', error);
//     // 处理错误,例如显示错误信息给用户
//   }
// };

// // 关闭视频
// const closeVideo = (id) => {
//   if (player.value) {
//     player.value.dispose();
//     player.value = null;
//   }
//   carStore.removeCarById(id);
// };

// watch(() => props.videoObj,
//   async (val) => {
//     // if (player.value) {
//     //   player.value.dispose();
//     //   player.value = null;
//     // }
//     // console.log(111, val.videoObj.id);
//     // console.log(222, id.value);
//     // console.log(333, val.videoObj.id == id.value);

//     if (val.videoObj.id == id.value) return;
//     id.value = val.videoObj.id;
//     // console.log("视频组件接收到", val.videoObj.id, id.value);
//     let url = val.videoObj.url;
//     // let url = "http://116.62.199.225:9980/httpflv.rplay.4328eea7-9ce9-4f3e-8731-69c344007546.admin*5bd5ed5652c0c639fcc027dc90951fff.1444.2.0.1";
//     if (!url) return;
//     if (val.videoObj.autoPlay) data.options.controls = true;
//     if (val.videoObj.loop) data.options.loop = true;
//     if (player.value) {
//       // toRaw(player.value).src(url);
//       // toRaw(player.value).src(url);
//       player.value.src({ type: 'video/x-flv', src: url });
//     } else {
//       // console.log("视频组件初始化", url);
//       options.value.sources[0].src = url;
//       // setTimeout(() => {
//       // 确保 DOM 更新
//       await nextTick();
//       setTimeout(() => {
//         init();
//       }, 0);
//       // }, 700);
//     }
//   },
//   { immediate: true }
// );

// onBeforeUnmount(() => {
//   if (player.value) {
//     player.value.dispose();
//     player.value = null;
//   }
// });

</script>

<style scoped lang="scss">
.videoPlayer {
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0);
  display: flex;
  flex-flow: column;

  &:hover {
    .closeIco {
      opacity: 1 !important;
    }
  }

  video {
    width: 100% !important;
    height: 100% !important;
    object-fit: fill !important;
  }

  video::-webkit-media-controls-play-button {
    display: none !important;
  }

  video::-webkit-media-controls-timeline {
    display: none !important;
  }

  .title {
    height: vh(25);
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 vh(5);
    background-color: #202020;
    color: #fff;
    z-index: 99;

    span {
      &:nth-child(2) {
        font-size: vh(14);
        white-space: nowrap;
        /* 防止文本换行 */
        overflow: hidden;
        /* 隐藏溢出的文本 */
        text-overflow: ellipsis;
        /* 溢出文本显示为省略号 */
        max-width: 100%;
        /* 设置最大宽度 */
        display: block;
      }

      &:nth-child(3) {
        font-size: vh(25);
        cursor: pointer;
        opacity: 0;

        &:hover {
          transform: scale(1.1);
          transition: all 0.1s;
        }
      }
    }
  }

  .videoBox {
    width: 100% !important;
    height: calc(100% - vh(25)) !important;

    // border: 3px solid pink !important; 
    // ::v-deep .vjs-tech {
    //   object-fit: fill !important;
    // }

    // // 播放按钮
    // ::v-deep .vjs-tech ::-webkit-media-controls-play-button {
    //   display: none;
    // }

    // ::v-deep .vjs-tech ::-webkit-media-controls-timeline {
    //   display: none;
    // }

    // ::v-deep .vjs-modal-dialog-content {
    //   display: none !important;
    // }

    // ::v-deep .vjs-modal-dialog {
    //   display: none !important;
    // }

    // ::v-deep .vjs-control-bar {
    //   opacity: 1 !important;
    // }

    // ::v-deep .vjs-controls-disabled .vjs-control-bar,
    // .vjs-using-native-controls .vjs-control-bar,
    // .vjs-error .vjs-control-bar {
    //   display: block !important;
    // }
  }

  // .controls {

  // }
}
</style>

引入使用

    <div class="container_center_body" ref="fullscreenDiv" v-if="videoList && videoList.length > 0">
      <div class="videos" :class="`videos_${rowId}`" v-for="(item, index) in videoList" :key="index">
        <videoPlayer v-if="item.id" :videoObj="{
          title: item.allName,
          player: null,
          videoObj: {
            id: item.id, // 确保 id 唯一
            url: item.wsUrl,
            // url: item.url,
            autoPlay: true,
            loop: true
          }
        }"></videoPlayer>
      </div>
    </div>




import videoPlayer from "@/components/playVideo/index.vue";

.html入口文件引入

    <script type="module" src="/src/main.js"></script>
    <script type="module" src="/flv/flv.min.js"></script>

资源文件下载:

→点击下载

相关文章:

  • 【软考-架构】8.4、信息化战略规划-CRO-SCM-应用集成-电子商务
  • 【Linux】VMware17 安装 Ubuntu24.04 虚拟机
  • Ubutu20.04安装docker与docker-compose
  • Spring Boot 异步返回对象深度解析
  • #pandas #python#数据标注 pd.crosstab()
  • STM32U575RIT6单片机(四)
  • 嵌入式c学习七
  • 企业架构与IT方法论:现代企业的基石
  • SQLark 实战 | 如何通过对象名和 DDL 快速搜索数据库对象
  • Unity TextMeshPro中显示建筑特殊符号
  • 【NGINX代理附件上传服务配置优化】
  • java项目之基于ssm的旅游论坛(源码+文档)
  • k8s搭建kube-prometheus
  • 在 Ubuntu 中用 Docker 安装 RAGFlow
  • 相同Vlan间的通信
  • HBase启动问题排查指南:解决HMaster和HRegionServer未运行的常见错误
  • 【C语言】使用结构体实现位段
  • Redis之单线程与多线程
  • ASP.NET Core 使用 MongoDB
  • Git Flow 分支管理策略
  • 广东高州发生山体滑坡,造成2人遇难4人送医救治1人失联
  • 上海市第二十届青少年科技节启动:为期半年,推出百余项活动
  • 精品消费“精”在哪?多在体验上下功夫
  • 美联储官员:美国经济增速可能放缓,现行关税政策仍将导致物价上涨
  • “9+2”复式票,浦东购彩者拿下体彩大乐透1153万头奖
  • 一周文化讲座|“我的生命不过是温柔的疯狂”