webRTC播放视频
后面在项目中会用到通过推拉播放视频流的技术,所以最近预研了一下webRTC
首先需要引入封装好的webRTC客户端的js文件ZLMRTCClient.js
下面是地址需要的自行下载
http://my.zsyou.top/2024/ZLMRTCClient.js
 
配置说明
new ZLMRTCClient.Endpoint({})
- element: 一个HTML视频元素的ID或引用,用于显示接收到的远程媒体流。这通常是一个video元素。
- debug: 一个布尔值,指定是否启用调试模式。如果启用,则会输出调试日志,有助于问题的排查和调试。
- zlmsdpUrl: 这是一个URL,指向用于SDP(会话描述协议)消息交换的服务器。在WebRTC通信中,SDP消息用于协商媒体流的参数,如编解码器、IP地址和端口等。
- simulcast: 一个布尔值,指定是否启用多路复用(Simulcast)。多路复用允许同时发送多个分辨率和比特率的视频流,以便客户端可以根据其网络条件和能力选择合适的流。
- useCamera: 一个布尔值,指定是否使用摄像头作为视频源。如果为false,可能需要使用屏幕共享或其他视频源。
- audioEnable: 一个布尔值,指定是否启用音频流。
- videoEnable: 一个布尔值,指定是否启用视频流。
- recvOnly: 一个布尔值,指定是否仅接收媒体流(即作为接收端)。如果为true,则不会发送本地媒体流到远端。
- resolution: 一个对象,指定期望的视频分辨率。包含w(宽度)和h(高度)属性。如果这两个值非零,则用于设置视频流的分辨率。
- usedatachannel: 一个布尔值,指定是否使用数据通道(DataChannel)。数据通道允许在WebRTC连接上直接发送和接收任意数据。
方法
-  receive():
 作用:将Endpoint实例配置为仅接收模式。在这个模式下,Endpoint不会发送本地媒体流到远端,而是监听并接收来自远端的媒体流。
-  start():
 作用:启动Endpoint实例,允许它发送和接收媒体流。此方法会根据配置决定是否开启摄像头和麦克风,并尝试与远端建立连接。
-  sendMsg(data):
 作用:发送消息通过数据通道。如果数据通道已打开,此方法将指定的数据发送给远端。
-  closeDataChannel():
 作用:关闭数据通道(如果已打开)。此方法会尝试关闭与远端的数据通道连接,并清理相关资源。
-  close():
 作用:关闭Endpoint实例。此方法会关闭WebRTC连接(如果已建立)、关闭数据通道(如果已打开),并清理所有相关资源。
-  _onIceCandidate(event):
 作用:内部方法,用于处理ICE候选者信息的接收。ICE(Interactive Connectivity Establishment)是WebRTC用于NAT和防火墙穿越的技术。此方法会将ICE候选者信息记录并可能发送给远端(未在代码片段中直接展示发送逻辑)。
-  _onTrack(event):
 作用:内部方法,用于处理接收到的媒体轨道(如音频或视频轨道)。当从远端接收到新的媒体轨道时,此方法会被触发,并将媒体轨道添加到本地渲染的媒体流中。
-  _onIceCandidateError(event):
 作用:内部方法,用于处理ICE候选者错误。当ICE候选者收集过程中发生错误时,此方法会被触发,并可能记录错误信息或执行其他错误处理逻辑。
-  _onconnectionstatechange(event):
 作用:内部方法,用于处理连接状态的变化。当WebRTC连接的状态发生变化时(如连接建立、断开等),此方法会被触发,并可以据此更新UI或执行其他逻辑。
-  _onDataChannelOpen(event):
 作用:内部方法,用于处理数据通道打开的事件。当使用数据通道时,一旦数据通道成功打开,此方法会被触发。
-  _onDataChannelMsg(event):
 作用:内部方法,用于处理通过数据通道接收到的消息。当数据通道接收到新消息时,此方法会被触发,并处理接收到的消息。
-  _onDataChannelErr(event):
 作用:内部方法,用于处理数据通道错误。当数据通道发生错误时,此方法会被触发,并可能记录错误信息或执行其他错误处理逻辑。
-  _onDataChannelClose(event):
 作用:内部方法,用于处理数据通道关闭的事件。当数据通道被关闭时,此方法会被触发,并可以据此清理相关资源。
用法
首先需要在html中引入文件
<!--  index.html-->
  <script type="text/javascript" src="http://my.zsyou.top/2024/ZLMRTCClient.js"></script>
<!--  app.vue-->
<template>
  <div class="app-container">
    <InputSearch
        v-model:value="videoUrl"
        placeholder="input search text"
        size="large"
        @search="onSearch"
    >
      <template #enterButton>
        <Button @click="btnPlay()">播放</Button>
      </template>
    </InputSearch>
    <div id="rtcPlayer">
      <video id='webRtcPlayerBox' autoplay controls style="text-align:left;">
        Your browser is too old which doesn't support HTML5 video.
      </video>
    </div>
  </div>
</template>
<script setup>
import {nextTick, onUnmounted, ref} from 'vue'
import {Button, InputSearch, message} from 'ant-design-vue'
const videoUrl = ref('')
let webrtcPlayer = null
function btnPlay() {
  nextTick(() => {
    if (typeof (videoUrl.value) == "undefined" || videoUrl.value === '') {
      return message.error('请填写视频地址')
    }
    play(videoUrl.value)
  })
}
let timer = null
function play(url) {
  webrtcPlayer = new ZLMRTCClient.Endpoint({
    element: document.getElementById('webRtcPlayerBox'),// TML视频元素的ID或引用,用于显示接收到的远程媒体流。通常是一个<video>元素
    debug: true,// 指定是否启用调试模式。如果启用,则会输出调试日志,有助于问题的排查和调试。
    zlmsdpUrl: url,//这是一个URL,指向用于SDP(会话描述协议)消息交换的服务器。在WebRTC通信中,SDP消息用于协商媒体流的参数,如编解码器、IP地址和端口等。
    simulecast: false,//指定是否启用多路复用(Simulcast)。多路复用允许同时发送多个分辨率和比特率的视频流,以便客户端可以根据其网络条件和能力选择合适的流。
    useCamera: false,//指定是否使用摄像头作为视频源。如果为false,可能需要使用屏幕共享或其他视频源。
    audioEnable: true,//指定是否启用音频流。
    videoEnable: true,//指定是否启用视频流。
    recvOnly: true,//指定是否仅接收媒体流(即作为接收端)。如果为true,则不会发送本地媒体流到远端。
    usedatachannel: false,//指定是否使用数据通道(DataChannel)。数据通道允许在WebRTC连接上直接发送和接收任意数据。
    //resolution: // 一个对象,指定期望的视频分辨率。包含w(宽度)和h(高度)属性。如果这两个值非零,则用于设置视频流的分辨率。
  })
  webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, (e) => {// ICE 协商出错
    console.error('ICE 协商出错')
    eventcallbacK("ICE ERROR", "ICE 协商出错")
  });
  webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, (e) => {//获取到了远端流,可以播放
    console.log('播放成功', e.streams)
    eventcallbacK("playing", "播放成功")
  });
  webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e) => {// offer anwser 交换失败
    console.error('offer anwser 交换失败', e)
    eventcallbacK("OFFER ANSWER ERROR ", "offer anwser 交换失败")
    if (e.code == -400 && e.msg == "流不存在") {
      console.log("流不存在")
      timer = setTimeout(() => {
        webrtcPlayer.close();
        play(url)
      }, 100)
    }
  });
  webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, (s) => {// 获取到了本地流
    // document.getElementById('selfVideo').srcObject=s;
    eventcallbacK("LOCAL STREAM", "获取到了本地流")
  });
}
/**
 * 停止播放
 */
function pause() {
  if (webrtcPlayer != null) {
    webrtcPlayer.close();
    webrtcPlayer = null;
  }
}
function eventcallbacK(type, message) {
  console.log("player 事件回调", type, message)
}
onUnmounted(() => {
  clearTimeout(timer)
})
</script>
<style>
.app-container {
  min-width: 50vw;
}
#rtcPlayer {
  width: 100%;
  background: #c1c1c1;
}
#webRtcPlayerBox {
  width: 100%;
  max-height: 56vh;
  background-color: #000;
}
</style>

![BUUCTF [MRCTF2020]Ezpop](https://i-blog.csdnimg.cn/direct/0371319440d7436e8706d1d68c27c0f0.png)

















