webrtc格式视频流的学习

发布于:2024-12-07 ⋅ 阅读:(135) ⋅ 点赞:(0)

单个引入依赖到index.html的组件封装:

<template>
  <div id="rtcPlayer">
    <video id='webRtcPlayerBox' controls autoplay style="text-align:left;">
    </video>
  </div>
</template>

<script>
/* global ZLMRTCClient */
let webrtcPlayer = null;
export default {
  name: 'rtcPlayer',
  data () {
    return {
      timer: null,
      videoUrl: ''
    };
  },
  mounted () {
    let paramUrl = decodeURIComponent(this.$route.params.url)
    this.$nextTick(() => {
      if (typeof (this.videoUrl) == "undefined") {
        this.videoUrl = paramUrl;
      }
      console.log("初始化时的地址为: " + this.videoUrl)
      this.play(this.videoUrl)
    })
  },
  watch: {
    videoUrl (newData, oldData) {
      this.pause();
      this.play(newData);
    },
    immediate: true
  },
  methods: {
    setVideoUrl (url) {
      this.videoUrl = url
    },
    play: function (url) {
      webrtcPlayer = new ZLMRTCClient.Endpoint({
        element: document.getElementById('webRtcPlayerBox'),// video 标签
        debug: true,// 是否打印日志
        zlmsdpUrl: url,//流地址
        simulecast: false,
        useCamera: false,
        audioEnable: true,
        videoEnable: true,
        recvOnly: true,
        usedatachannel: false,
      })
      webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, (e) => {// ICE 协商出错
        console.error('ICE 协商出错')
        this.eventcallbacK("ICE ERROR", "ICE 协商出错")
      });

      webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, (e) => {//获取到了远端流,可以播放
        console.log('播放成功', e.streams)
        this.eventcallbacK("playing", "播放成功")
      });

      webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e) => {// offer anwser 交换失败
        console.error('offer anwser 交换失败', e)
        this.eventcallbacK("OFFER ANSWER ERROR ", "offer anwser 交换失败")
        if (e.code == -400 && e.msg == "流不存在") {
          console.log("流不存在")
          this.timer = setTimeout(() => {
            this.webrtcPlayer.close();
            this.play(url)
          }, 100)

        }
      });
      webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, (s) => {// 获取到了本地流
        // document.getElementById('selfVideo').srcObject=s;
        this.eventcallbacK("LOCAL STREAM", "获取到了本地流")
      });

    },
    pause: function () {
      if (webrtcPlayer != null) {
        webrtcPlayer.close();
        webrtcPlayer = null;
      }

    },
    eventcallbacK: function (type, message) {
      console.log("player 事件回调")
      console.log(type)
      console.log(message)
    }
  },
  unmounted () {
    clearTimeout(this.timer);
  },
}
</script>

<style>
.LodingTitle {
  min-width: 70px;
}

#rtcPlayer {
  width: 100%;
  background-color: #0f2229;
  padding: 5px;
}

#webRtcPlayerBox {
  width: 100%;
  height: 130px;
  object-fit: fill;
}
</style>

应用:

<template>
  <div class="video-play-cls">
    <WebRTC v-if="styleStr === 'webrtc'" ref="webRTCRef" />
  </div>
</template>

<script setup>
import WebRTC from '../components/FlvPlayerTest.vue'
import { ref, computed, onMounted, nextTick } from 'vue'

// 视频源路径
const videoUrl = ref('url播放地址')

// 根据视频源决定使用哪个视频组件
const styleStr = computed(() => {
  return /webrtc/.test(videoUrl.value) ? 'webrtc' : '';
})

const webRTCRef = ref(null)

onMounted(async () => {
  // 等待 DOM 渲染完成后再设置视频源
  await nextTick(); // 等待 DOM 更新完成
  if (styleStr.value === 'webrtc' && webRTCRef.value) {
    // 只有在 styleStr 是 'webrtc' 的时候才会调用 setVideoUrl
    webRTCRef.value.setVideoUrl(videoUrl.value)
  }
})
</script>

<style scoped>
.video-play-cls {
  height: 150px;
}
</style>

效果:

多个webrtc格式视频流播放组件封装:

<template>
  <div class="webrtc-play" v-for="(videoId, index) in videoIds" :key="index">
    <video :ref="'videoPlayer' + videoId" :class="videoId" :id="videoId" controls autoplay></video>
    <div v-if="uavText" class="uav-text">{{ uavText }}</div>
  </div>
</template>

<script>
/* global ZLMRTCClient */
export default {
  name: 'WebRTC',
  data () {
    return {
      timers: {},
      videoIds: [], // 存储视频流的ID
      webrtcPlayers: {} // 存储多个 webrtcPlayer 实例
    };
  },
  props: {
    uavText: {
      type: String,
      default: ''
    },
  },
  methods: {
    play (url, id) {
      console.log(this.videoIds, 'this.videoIds');
      // 添加新的视频 ID
      if (!this.videoIds.includes(id)) {
        this.videoIds.push(id);
      }

      // 使用 nextTick 确保 DOM 更新完成
      this.$nextTick(() => {
        const videoElement = this.$refs['videoPlayer' + id][0];

        if (!videoElement) {
          console.error(`未找到视频元素 ${id}`);
          return;
        }

        // 初始化新的 ZLMRTCClient.Endpoint 实例
        const webrtcPlayer = new ZLMRTCClient.Endpoint({
          element: videoElement,
          debug: true,
          zlmsdpUrl: url,
          simulecast: false,
          useCamera: false,
          audioEnable: true,
          videoEnable: true,
          recvOnly: true,
          usedatachannel: false,
        });

        // 监听事件
        webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, () => {
          console.error('ICE 协商出错');
          this.eventCallback(id, "ICE ERROR", "ICE 协商出错");
        });

        webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, (e) => {
          console.log(`播放成功: ${id}`, e.streams);
          this.eventCallback(id, "playing", "播放成功");
        });

        webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e) => {
          console.error(`offer answer 交换失败: ${id}`, e);
          this.eventCallback(id, "OFFER ANSWER ERROR", "offer answer 交换失败");
          if (e.code === -400 && e.msg === "流不存在") {
            console.log(`流不存在: ${id}`);
            this.timers[id] = setTimeout(() => {
              webrtcPlayer.close();
              this.play(url, id);
            }, 100);
          }
        });

        webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, () => {
          this.eventCallback(id, "LOCAL STREAM", "获取到了本地流");
        });

        // 将 webrtcPlayer 实例存储在对象中
        this.webrtcPlayers[id] = webrtcPlayer;
      });
    },
    pause (id) {
      const player = this.webrtcPlayers[id];
      if (player) {
        player.close();
        delete this.webrtcPlayers[id];
        if (this.timers[id]) {
          clearTimeout(this.timers[id]);
        }
      }
    },
    eventCallback (id, type, message) {
      console.log(`播放器事件回调 - ${id}`);
      console.log(type);
      console.log(message);
    }
  },
  beforeUnmount () {
    // 清理所有定时器和 webrtcPlayer 实例
    Object.keys(this.timers).forEach((id) => clearTimeout(this.timers[id]));
    Object.keys(this.webrtcPlayers).forEach((id) => this.webrtcPlayers[id].close());
  }
};
</script>

<style scoped lang="scss">
.webrtc-play {
  position: relative;
  width: 100%;
  height: 100%;

  video {
    width: 100%;
    height: 100%;
    background-color: #000;
  }

  .uav-text {
    position: absolute;
    bottom: 5%;
    left: 5%;
    font-family: 'YouSheBiaoTiHei';
    font-size: 20px;
    color: #fff;
  }
}
</style>

应用:

<template>
  <div class="video-play-cls">
    <!-- 使用 v-for 渲染多个 WebRTC 组件 -->
    <WebRTC
      v-for="(item, index) in webRTCItems"
      :key="index"
      :id="item.id"
      :ref="webRTCRefs[index]"
    />
  </div>
</template>

<script setup>
import WebRTC from '@/components/video/WebRTC.vue'
import { ref, computed, onMounted, nextTick } from 'vue'


// 根据视频源决定使用哪个视频组件
const styleStr = computed(() => {
  return /flv/.test(videoUrl.value) ? 'webrtc' : '';
})

// WebRTC 组件实例的 refs
const webRTCRefs = ref([])

// WebRTC 组件项数据
const webRTCItems = ref([
  { id: 'videoId1', videoUrl: '视频源路径1' },
  { id: 'videoId2', videoUrl: '视频源路径2' }
])

onMounted(async () => {
  await nextTick() // 等待 DOM 更新完成
  if (styleStr.value === 'webrtc') {
    // 遍历每个 WebRTC 组件,传递不同的 id 和视频源
    webRTCItems.value.forEach((item, index) => {
      const webRTCInstance = webRTCRefs.value[index]
      if (webRTCInstance && webRTCInstance.value) {
        webRTCInstance.value.pause() // 停止当前播放
        webRTCInstance.value.play(item.videoUrl, item.id) // 播放对应的视频
      }
    })
  }
})
</script>

<style scoped lang="scss">
.video-play-cls {
  height: 150px;
}
</style>


网站公告

今日签到

点亮在社区的每一天
去签到