소스 검색

视频播放错误机制

zhangjie 3 년 전
부모
커밋
d7ff790e84

+ 12 - 4
src/features/invigilation/OnlinePatrol/PatrolWarningDetail.vue

@@ -422,13 +422,21 @@ export default {
     },
     videoMute(type) {
       if (type === "first") {
-        this.firstViewVideo.muted = !this.firstViewVideo.muted;
         this.secondViewVideo.muted = true;
-        this.$refs.FirstViewVideo.mutedPlayer(this.firstViewVideo.muted);
+        this.$refs.SecondViewVideo.mutedPlayer(true);
+
+        const res = this.$refs.FirstViewVideo.mutedPlayer(
+          this.firstViewVideo.muted
+        );
+        if (res) this.firstViewVideo.muted = !this.firstViewVideo.muted;
       } else {
-        this.secondViewVideo.muted = !this.secondViewVideo.muted;
         this.firstViewVideo.muted = true;
-        this.$refs.SecondViewVideo.mutedPlayer(this.secondViewVideo.muted);
+        this.$refs.FirstViewVideo.mutedPlayer(true);
+
+        const res = this.$refs.SecondViewVideo.mutedPlayer(
+          this.secondViewVideo.muted
+        );
+        if (res) this.secondViewVideo.muted = !this.secondViewVideo.muted;
       }
     },
     goBack() {

+ 12 - 4
src/features/invigilation/RealtimeMonitoring/WarningDetail.vue

@@ -840,13 +840,21 @@ export default {
     },
     videoMute(type) {
       if (type === "first") {
-        this.firstViewVideo.muted = !this.firstViewVideo.muted;
         this.secondViewVideo.muted = true;
-        this.$refs.FirstViewVideo.mutedPlayer(this.firstViewVideo.muted);
+        this.$refs.SecondViewVideo.mutedPlayer(true);
+
+        const res = this.$refs.FirstViewVideo.mutedPlayer(
+          this.firstViewVideo.muted
+        );
+        if (res) this.firstViewVideo.muted = !this.firstViewVideo.muted;
       } else {
-        this.secondViewVideo.muted = !this.secondViewVideo.muted;
         this.firstViewVideo.muted = true;
-        this.$refs.SecondViewVideo.mutedPlayer(this.secondViewVideo.muted);
+        this.$refs.FirstViewVideo.mutedPlayer(true);
+
+        const res = this.$refs.SecondViewVideo.mutedPlayer(
+          this.secondViewVideo.muted
+        );
+        if (res) this.secondViewVideo.muted = !this.secondViewVideo.muted;
       }
     },
     toViewImg(photo) {

+ 76 - 7
src/features/invigilation/common/FlvMedia.vue

@@ -1,18 +1,30 @@
 <template>
-  <video
+  <div
     class="flv-media"
-    ref="VideoMedia"
-    muted
-    @ended="destroyPlayer"
-  ></video>
+    v-loading="loading"
+    element-loading-text="加载中"
+    element-loading-background="rgba(0, 0, 0, 0.8)"
+  >
+    <video ref="VideoMedia" muted @ended="destroyPlayer"></video>
+    <div v-if="result.error" class="media-error">
+      <div class="media-error-content">
+        <div>{{ result.message }}</div>
+        <el-button type="text" icon="el-icon-refresh-left" @click="reloadVideo"
+          >重新播放</el-button
+        >
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
 import flvjs from "flv.js";
 // doc: https://github.com/bilibili/flv.js/blob/42343088f22619cf014a057b3878fe3d320016a6/docs/api.md
+import timeMixin from "../../../mixins/timeMixin";
 
 export default {
   name: "flv-media",
+  mixins: [timeMixin],
   props: {
     liveUrl: {
       type: String,
@@ -21,6 +33,13 @@ export default {
   data() {
     return {
       flvPlayer: null,
+      retryCount: 0,
+      maxRetryCount: 3,
+      loading: true,
+      result: {
+        error: false,
+        message: "",
+      },
     };
   },
   mounted() {
@@ -46,6 +65,47 @@ export default {
       this.flvPlayer.attachMediaElement(this.$refs.VideoMedia);
       this.flvPlayer.load();
       this.flvPlayer.play();
+      this.flvPlayer.on(flvjs.Events.ERROR, this.playError);
+      this.flvPlayer.on(flvjs.Events.METADATA_ARRIVED, () => {
+        this.loading = false;
+      });
+    },
+    playError(errorType) {
+      switch (errorType) {
+        case flvjs.ErrorTypes.NETWORK_ERROR:
+          console.log("网络问题,准备重试!");
+          this.retryPlay();
+          break;
+        case flvjs.ErrorTypes.MEDIA_ERROR:
+          console.log("媒体问题,准备重试!");
+          this.retryPlay();
+          break;
+        default:
+          console.log("未知问题,无法播放!");
+          this.result = {
+            error: true,
+            message: "播放失败!",
+          };
+          break;
+      }
+    },
+    retryPlay() {
+      if (this.retryCount >= this.maxRetryCount) {
+        console.log("已尝试最大次数重新播放!");
+        this.result = {
+          error: true,
+          message: "播放失败!",
+        };
+        this.retryCount = 0;
+        this.loading = false;
+        return;
+      }
+
+      this.addSetTime(() => {
+        this.reloadVideo();
+        this.retryCount++;
+        console.log("已重新播放");
+      }, 1000);
     },
     playPlayer() {
       this.flvPlayer.play();
@@ -60,14 +120,23 @@ export default {
       this.flvPlayer.detachMediaElement();
       this.flvPlayer.destroy();
       this.flvPlayer = null;
+      this.clearSetTs();
     },
     mutedPlayer(muted) {
       if (!this.flvPlayer) return;
       this.flvPlayer.muted = muted;
+      return true;
     },
     reloadVideo() {
-      this.destroyPlayer();
-      this.initVideo();
+      this.result = {
+        error: false,
+        message: "",
+      };
+      this.loading = true;
+      this.$nextTick(() => {
+        this.destroyPlayer();
+        this.initVideo();
+      });
     },
   },
   beforeDestroy() {

+ 5 - 9
src/features/invigilation/common/InvigilationStudent.vue

@@ -95,12 +95,13 @@ export default {
     },
     toMuted() {
       console.log(this.muted);
-      this.muted = !this.muted;
-      this.$emit("muted", this.muted);
-      this.mutedPlayer(this.muted);
+      const nextMuted = !this.muted;
+      this.$emit("muted", nextMuted);
+      const res = this.mutedPlayer(nextMuted);
+      if (res) this.muted = nextMuted;
     },
     mutedPlayer(muted) {
-      this.$refs.ThirdViewVideo.mutedPlayer(muted);
+      return this.$refs.ThirdViewVideo.mutedPlayer(muted);
     },
     dialogClose() {
       this.$refs.ThirdViewVideo.reloadVideo();
@@ -186,11 +187,6 @@ export default {
   //   background-image: url(../../../assets/icon-video.png);
   //   background-size: 100% 100%;
   // }
-
-  > video {
-    width: 100%;
-    height: 100%;
-  }
 }
 .student-info {
   position: relative;

+ 17 - 0
src/mixins/timeMixin.js

@@ -0,0 +1,17 @@
+export default {
+  data() {
+    return {
+      setTs: [],
+    };
+  },
+  methods: {
+    addSetTime(action, time = 1 * 1000) {
+      this.setTs.push(setTimeout(action, time));
+    },
+    clearSetTs() {
+      if (!this.setTs.length) return;
+      this.setTs.forEach((t) => clearTimeout(t));
+      this.setTs = [];
+    },
+  },
+};

+ 27 - 0
src/styles/base.scss

@@ -998,6 +998,33 @@ body {
   }
 }
 
+// flv-media
+.flv-media {
+  position: relative;
+  height: 100%;
+
+  > video {
+    display: block;
+    width: 100%;
+    height: 100%;
+  }
+
+  .media-error {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    top: 0;
+    left: 0;
+    z-index: 99;
+    background-color: rgba(0, 0, 0, 0.5);
+    color: #fff;
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: space-around;
+  }
+}
+
 .cc-image-preview {
   &-header {
     position: absolute;