Ver código fonte

feat: canvas绘制

shuisheng 2 anos atrás
pai
commit
3ff38c207e

+ 1 - 1
README.md

@@ -77,7 +77,7 @@ billd 直播间,目前实现了类似 [bilibili 的 Web 在线直播](https://
   style="height:500px"
 />
 
-> 分列表
+> 分列表
 
 <img
   src="https://github.com/galaxy-s10/billd-live/assets/61055341/5a29c965-9979-4ba8-b120-ab2a164d0bf2" 

+ 2 - 1
package.json

@@ -39,6 +39,7 @@
     "billd-scss": "^0.0.7",
     "billd-utils": "^0.0.12",
     "browser-tool": "^1.0.5",
+    "flv.js": "^1.6.2",
     "js-cookie": "^3.0.5",
     "mediasoup-client": "^3.6.84",
     "msr": "^1.3.4",
@@ -55,7 +56,6 @@
     "webrtc-adapter": "^8.2.2"
   },
   "devDependencies": {
-    "@types/video.js": "^7.3.52",
     "@babel/core": "^7.14.0",
     "@babel/preset-env": "^7.14.2",
     "@commitlint/cli": "^16.0.1",
@@ -63,6 +63,7 @@
     "@rushstack/eslint-patch": "^1.1.0",
     "@soda/friendly-errors-webpack-plugin": "^1.8.1",
     "@types/node": "^18.11.9",
+    "@types/video.js": "^7.3.52",
     "@typescript-eslint/parser": "^5.8.1",
     "@vue/compiler-sfc": "^3.2.31",
     "@vue/eslint-config-prettier": "^7.0.0",

Diferenças do arquivo suprimidas por serem muito extensas
+ 334 - 251
pnpm-lock.yaml


BIN
public/fddm_yycy.flv


+ 1 - 1
public/index.html

@@ -14,7 +14,7 @@
       rel="icon"
       href="<%= BASE_URL %>favicon.ico"
     />
-    <script src="<%= BASE_URL %>flv.min.js"></script>
+    <!-- <script src="<%= BASE_URL %>flv.min.js"></script> -->
     <title><%= htmlWebpackPlugin.options.title %></title>
   </head>
 

BIN
public/zjl_bnsdmm.flv


+ 6 - 5
src/hooks/use-play.ts

@@ -1,16 +1,17 @@
 import '@/assets/css/videojs.scss';
-
+import { useAppStore } from '@/store/app';
+import flvJs from 'flv.js';
 import videoJs from 'video.js';
 import Player from 'video.js/dist/types/player';
 import { onMounted, onUnmounted, ref, watch } from 'vue';
 
-import { useAppStore } from '@/store/app';
+export * as flvJs from 'flv.js';
 
 // @ts-ignore
-export const flvJs = window.flvjs;
+// export const flvJs = window.flvjs as flvJs;
 
 export function useFlvPlay() {
-  const flvPlayer = ref();
+  const flvPlayer = ref<flvJs.Player>();
 
   onMounted(() => {});
 
@@ -48,7 +49,7 @@ export function useFlvPlay() {
     }
   }
 
-  return { startFlvPlay, destroyFlv };
+  return { flvPlayer, startFlvPlay, destroyFlv };
 }
 
 export function useHlsPlay() {

+ 17 - 1
src/hooks/use-pull.ts

@@ -30,15 +30,18 @@ import {
 } from '@/network/webSocket';
 import { useNetworkStore } from '@/store/network';
 import { useUserStore } from '@/store/user';
+import { videoToCanvas } from '@/utils';
 
 export function usePull({
   localVideoRef,
   remoteVideoRef,
+  canvasRef,
   isSRS,
   isFlv,
 }: {
   localVideoRef: Ref<HTMLVideoElement[]>;
   remoteVideoRef: Ref<HTMLVideoElement | undefined>;
+  canvasRef: Ref<HTMLDivElement | undefined>;
   isSRS?: boolean;
   isFlv?: boolean;
 }) {
@@ -71,7 +74,7 @@ export function usePull({
     }[]
   >([]);
 
-  const { startFlvPlay } = useFlvPlay();
+  const { flvPlayer, startFlvPlay } = useFlvPlay();
   const { startHlsPlay } = useHlsPlay();
 
   const track = reactive({
@@ -479,6 +482,12 @@ export function usePull({
             flvurl: flvurl.value,
             videoEl: remoteVideoRef.value!,
           });
+          videoToCanvas(
+            remoteVideoRef.value!,
+            canvasRef.value!,
+            flvPlayer.value?.mediaInfo.width,
+            flvPlayer.value?.mediaInfo.height
+          );
         } else if (route.query.liveType === liveTypeEnum.srsHlsPull) {
           if (!autoplayVal.value) return;
           await startHlsPlay({
@@ -502,6 +511,12 @@ export function usePull({
               flvurl: flvurl.value,
               videoEl: remoteVideoRef.value!,
             });
+            videoToCanvas(
+              remoteVideoRef.value!,
+              canvasRef.value!,
+              flvPlayer.value?.mediaInfo.width,
+              flvPlayer.value?.mediaInfo.height
+            );
           }
         }
       }
@@ -690,6 +705,7 @@ export function usePull({
     startGetDisplayMedia,
     addTrack,
     addVideo,
+    flvPlayer,
     videoLoading,
     balance,
     roomName,

+ 85 - 0
src/utils/index.ts

@@ -1,3 +1,88 @@
+import { getRangeRandom } from 'billd-utils';
+
 export const sum = (a, b) => {
   return a + b;
 };
+
+/**
+ * @description 获取随机字符串(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz)
+ * @example: getRandomString(4) ===> abd3
+ * @param {number} length
+ * @return {*}
+ */
+export const getRandomString = (length: number): string => {
+  const str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+  let res = '';
+  for (let i = 0; i < length; i += 1) {
+    res += str.charAt(getRangeRandom(0, str.length - 1));
+  }
+  return res;
+};
+
+export function videoToCanvas(
+  videoElement: HTMLVideoElement,
+  targetEl: HTMLElement,
+  width: number,
+  height
+) {
+  if (!videoElement || !targetEl) {
+    return;
+  }
+  const canvas = document.createElement('canvas');
+  canvas.width = width;
+  canvas.height = height;
+  const ctx = canvas.getContext('2d')!;
+  const newVideo = videoElement.cloneNode(false);
+
+  const requestAnimationFrame = window.requestAnimationFrame;
+  const cancelAnimationFrame = window.cancelAnimationFrame;
+  let timer;
+
+  function drawCanvas() {
+    ctx.drawImage(videoElement, 0, 0);
+    timer = requestAnimationFrame(drawCanvas);
+  }
+
+  function stopDrawing() {
+    cancelAnimationFrame(timer);
+  }
+
+  newVideo.addEventListener(
+    'play',
+    function () {
+      drawCanvas();
+    },
+    false
+  );
+  newVideo.addEventListener('pause', stopDrawing, false);
+  newVideo.addEventListener('ended', stopDrawing, false);
+
+  targetEl.parentNode?.replaceChild(canvas, targetEl);
+
+  drawCanvas();
+
+  // this.play = function () {
+  //   newVideo.play();
+  // };
+
+  // this.pause = function () {
+  //   newVideo.pause();
+  // };
+
+  // this.playPause = function () {
+  //   if (newVideo.paused) {
+  //     this.play();
+  //   } else {
+  //     this.pause();
+  //   }
+  // };
+
+  // this.change = function (src) {
+  //   if (!src) {
+  //     return;
+  //   }
+  //   newVideo.src = src;
+  // };
+
+  // this.drawFrame = drawCanvas;
+}

+ 25 - 6
src/views/pull/index.vue

@@ -38,7 +38,7 @@
                 })`,
               }"
             ></div>
-            <video
+            <!-- <video
               id="remoteVideo"
               ref="remoteVideoRef"
               autoplay
@@ -50,7 +50,8 @@
               x5-video-orientation="portraint"
               :muted="appStore.muted"
               @click="showControls = !showControls"
-            ></video>
+            ></video> -->
+            <div ref="canvasRef"></div>
             <div
               v-if="
                 route.query.liveType === liveTypeEnum.srsHlsPull &&
@@ -219,6 +220,7 @@
             @click="sendDanmu"
           >
             发送
+            <span @click="aaa">222</span>
           </div>
         </div>
       </div>
@@ -260,10 +262,14 @@ const showSidebar = ref(true);
 const topRef = ref<HTMLDivElement>();
 const bottomRef = ref<HTMLDivElement>();
 const danmuListRef = ref<HTMLDivElement>();
+const canvasRef = ref<HTMLDivElement>();
 const containerRef = ref<HTMLDivElement>();
-const remoteVideoRef = ref<HTMLVideoElement>();
 const localVideoRef = ref<HTMLVideoElement[]>([]);
-
+const videoEl = document.createElement('video');
+videoEl.muted = true;
+videoEl.playsInline = true;
+videoEl.setAttribute('webkit-playsinline', 'true');
+const remoteVideoRef = ref(videoEl);
 const {
   initPull,
   closeWs,
@@ -276,6 +282,7 @@ const {
   startGetDisplayMedia,
   addTrack,
   addVideo,
+  flvPlayer,
   videoLoading,
   balance,
   roomName,
@@ -295,6 +302,7 @@ const {
 } = usePull({
   localVideoRef,
   remoteVideoRef,
+  canvasRef,
   isFlv: route.query.liveType === liveTypeEnum.srsFlvPull,
   isSRS: route.query.liveType === liveTypeEnum.srsWebrtcPull,
 });
@@ -302,6 +310,18 @@ const showPlayBtn = ref(true);
 
 const { startHlsPlay } = useHlsPlay();
 
+watch(
+  () => videoLoading.value,
+  (newVal) => {
+    if (newVal) return;
+    // remoteVideoRef.value.style.width = flvPlayer.value?.mediaInfo.width! + 'px';
+    // remoteVideoRef.value.style.height =
+    //   flvPlayer.value?.mediaInfo.height! + 'px';
+    // console.log(flvPlayer.value?.mediaInfo.width, 888);
+    // videoToCanvas(remoteVideoRef.value, canvasRef.value!);
+  }
+);
+
 async function startPull() {
   showPlayBtn.value = false;
   await startHlsPlay({
@@ -470,11 +490,10 @@ onMounted(() => {
 
           inset: 0;
         }
-        :deep(video) {
+        :deep(canvas) {
           position: absolute;
           top: 0;
           left: 50%;
-          width: 100%;
           height: 100%;
           transform: translate(-50%);
         }

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff