flvjs实现直播流并自定义实现全屏到指定区域

template中关键代码

          <div class="page-item-box rel">
            <div v-if="!state.left.videos.isFullScream" class="video-box overflow_auto" id='fullscreen-container'>
              <div class="videos-item rel" v-for="(item,index) in state.list" :key="index">
                <div class="rel wh-100">
                  <span  class="video-fullScreen-btn fullScreen-btn-common pointer">
                    <img @click.stop="state.fullScreenClick(item,$event)" src="/public/img/video/fullScreen.png" alt="全屏">
                  </span>
                  <MyMonitor
                    :videoObj="item"
                    src="liveAddress"
                  />
                </div>
              </div>
            </div>
            <div class="video-fullScreen-box wh-100" v-else>
              <div class="rel wh-100">
                <span  class="video-nofullScreen-btn fullScreen-btn-common btn pointer">
                  <img @click.self="state.isFullScream=false" src="/public/img/video/no-fullScreen.png" alt="退出全屏">
                </span>
                <MyMonitor
                  :videoObj="state.fullVideoItem"
                  src="liveAddress"
                />
              </div>
            </div>
          </div></div>

js关键代码


import MyMonitor from "./component/MyMonitor.vue";
export default defineComponent({
  name:'home',
  components:{MyTable,detailLayer,warning,envDetail,login,MyMonitor},
  setup(){
 let state = reactive({
    isFullScream :false,
    fullVideoItem:{},
    list:[
            {
              name:'1',
              muted:true,
              liveAddress:'ws://192.***.***.***:***/live?url=rtmp://***.***.com/live/***'
            }
          ],
 fullScreenClick(item,event){
            event.stopPropagation();
            state.fullVideoItem = item
            state.isFullScream = true
          }
})
onActivated(async ()=>{
      state.left.videos.isFullScream=false
    })
 return{
      state
    }
})

MyMonitor组件

<template>
  <div class="videoContainer my-video" id="videoDom">
    <div class="flex-center video-box bg-black" v-show="!videoObj[src] || showErrorInfo"><span>该视频无法播放!</span></div>
    <video
      :autoplay="true"
      v-show="videoObj[src] && !showErrorInfo"
      ref="videoPlayerContainer"
      class="centeredVideo"
      controls
      controlslist="nofullscreen nodownload"
      :muted="videoObj.muted"></video>
  </div>
</template>

<script>
import {defineComponent, onMounted, onUnmounted, onDeactivated, reactive, ref, toRefs, watch} from 'vue';
import 'video.js/dist/video-js.css';
import 'videojs-flvjs-es6'
import flvjs from 'flv.js'


export default defineComponent({
  name: 'MyMonitor',
  emits: [],
  props: {
    videoObj: {
      type: Object,
      default: {
        /*name:'测试21',
        muted:true,
        liveAddress:'http:/***.168.10.***:8000/flwis-1.5.0/demo/xsy3.flv'*/
      }
    },
    src: {
      type: String,
      default: ''
    },
  },
  setup(props, {emit}) {
    let videoPlayerContainer = ref();
    const state = reactive({
      videoId: 0,
      flvPlayer: null,
      lastDecodedFrame:0,
      connectCount:0,
      showErrorInfo:false,
      createPlayer(url){
        state.showErrorInfo=false
        state.flvPlayer = flvjs.createPlayer(
          {
            type: "flv", //媒体类型
            url: url || '', //flv格式媒体URL
            isLive: true, //数据源是否为直播流
            hasAudio: true, //数据源是否包含有音频
            hasVideo: true, //数据源是否包含有视频
            enableStashBuffer: false, //是否启用缓存区
            muted: props.videoObj.muted,
            duration: 1,
          },
          {
            enableWorker: false, // 是否启用分离的线程进行转换
            enableStashBuffer: true, //关闭IO隐藏缓冲区
            autoCleanupSourceBuffer: true, //自动清除缓存
            fluid: true
          }
        );
      },
      flv_load(url) {
        state.destoryVideo();
        if (flvjs.isSupported()) {
          state.createPlayer(url);
          state.flvPlayer.attachMediaElement(videoPlayerContainer.value); //将播放实例注册到节点
          state.flvPlayer.load(); //加载数据流
          // state.flvPlayer.play(); //播放数据流
          state.flvPlayer.on('error', function (err) {
            state.flvPlayer.pause()
            state.flvPlayer.unload()
          })
          state.flvPlayer.on("statistics_info", function (res) {
            if(state.connectCount >= 10){
              state.destoryVideo()
              state.showErrorInfo=true
              state.connectCount = 0;
              return;
            }

            if (state.lastDecodedFrame === 0) {
              state.lastDecodedFrame = res.decodedFrames;
              state.connectCount++;
              return;
            }
          });
        }
      },
      destoryVideo() {
        if (state.flvPlayer) {
          state.flvPlayer?.pause();
          state.flvPlayer?.unload();
          state.flvPlayer?.detachMediaElement();
          state.flvPlayer.destroy();
          state.flvPlayer = null;
        }
      },

    })
    watch(() => props.videoObj, (val) => {
      props.videoObj[props.src] && state.flv_load(val[props.src]);
    })
    onMounted(() => {
      state.flv_load(props.videoObj[props.src]);
    })
    onUnmounted(() => {
      state.destoryVideo()
    })
    onDeactivated(() => {
      state.destoryVideo()
    })
    return {
      ...toRefs(state),
      videoPlayerContainer,
    }
  }
})
</script>

<style lang="less" scoped>
.my-video, .video-box, .centeredVideo {
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,.6);
  .flex_center;
  /*  @keyframes ani-color{
      from {color:#333;}
      to {color:#fff;}
    }
    >span{
      animation: ani-color 5s;
    }*/

  :deep(.vjs-modal-dialog-content), .bg-black {
    background: linear-gradient(#323232,#000);

  }

  :deep(.video-js .vjs-control) {
    width: 2em;
    font-size: 12px;
  }

  :deep(.video-js .vjs-modal-dialog) {
    overflow: hidden;
  }

  :deep(.video-js .vjs-time-control) {
    margin-right: 25px;
  }

  :deep(.video-js .vjs-picture-in-picture-control) {
    margin-right: 10px;
  }

  :deep(.vjs-fullscreen-control.vjs-control.vjs-button) {
    //display: none!important;
  }

  :deep(.video-js .vjs-progress-control .vjs-progress-holder) {
  }

  :deep(.vjs-progress-control.vjs-control) {
    //max-width: 40px;
  }

  :deep(.vjs_video_3-dimensions.vjs-fluid:not(.vjs-audio-only-mode)), :deep(.vjs-fluid:not(.vjs-audio-only-mode)) {
    padding-top: unset;
  }

  :deep(.video-js) {
    height: 100%;
    width: 100%;
    overflow: hidden;
  }
  :deep(#flvjs-video-player .video-control-bar .fullscreen) {
    display: none !important;
  }
  :deep(.vjs-fullscreen-control.vjs-control.vjs-button){
    display: none!important;
  }
  /* 隐藏控制条 */
  .flvjs-control-bar {
    display: none;
  }

}

video::-webkit-media-controls-fullscreen-button {
  display:none !important;
}
video::-moz-media-controls-fullscreen-button {
  display:none !important;
}
video::-moz-full-screen-ancestor::-moz-full-screen-controls {
  display: none !important;
}
</style>

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值