|
@@ -1,5 +1,10 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="push-wrap">
|
|
<div class="push-wrap">
|
|
|
|
|
+ <input
|
|
|
|
|
+ type="file"
|
|
|
|
|
+ @change="ddddd"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div @click="aaaa">读取</div>
|
|
|
<div
|
|
<div
|
|
|
ref="topRef"
|
|
ref="topRef"
|
|
|
class="left"
|
|
class="left"
|
|
@@ -14,7 +19,9 @@
|
|
|
ref="pushCanvasRef"
|
|
ref="pushCanvasRef"
|
|
|
></canvas>
|
|
></canvas>
|
|
|
<div
|
|
<div
|
|
|
- v-if="!appStore.allTrack || appStore.allTrack.length <= 0"
|
|
|
|
|
|
|
+ v-if="
|
|
|
|
|
+ appCacheStore.allTrack.filter((item) => !item.hidden).length <= 0
|
|
|
|
|
+ "
|
|
|
class="add-wrap"
|
|
class="add-wrap"
|
|
|
>
|
|
>
|
|
|
<n-space>
|
|
<n-space>
|
|
@@ -133,18 +140,35 @@
|
|
|
<div class="title">素材列表</div>
|
|
<div class="title">素材列表</div>
|
|
|
<div class="list">
|
|
<div class="list">
|
|
|
<div
|
|
<div
|
|
|
- v-for="(item, index) in appStore.allTrack"
|
|
|
|
|
|
|
+ v-for="(item, index) in appCacheStore.allTrack.filter(
|
|
|
|
|
+ (item) => !item.hidden
|
|
|
|
|
+ )"
|
|
|
:key="index"
|
|
:key="index"
|
|
|
class="item"
|
|
class="item"
|
|
|
>
|
|
>
|
|
|
<span class="name">
|
|
<span class="name">
|
|
|
- ({{ mediaTypeEnumMap[item.type] }}){{ item.mediaName }}
|
|
|
|
|
|
|
+ ({{ mediaTypeEnumMap[item.type] }}-{{
|
|
|
|
|
+ item.audio === 1 ? '音频' : '视频'
|
|
|
|
|
+ }}){{ item.mediaName }}
|
|
|
</span>
|
|
</span>
|
|
|
- <div
|
|
|
|
|
- class="del"
|
|
|
|
|
- @click="handleDelTrack(item)"
|
|
|
|
|
- >
|
|
|
|
|
- x
|
|
|
|
|
|
|
+ <div class="control">
|
|
|
|
|
+ <div class="control-item">
|
|
|
|
|
+ <n-icon
|
|
|
|
|
+ size="16"
|
|
|
|
|
+ @click="handleChangeMuted(item)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <VolumeMuteOutline v-if="item.muted"></VolumeMuteOutline>
|
|
|
|
|
+ <VolumeHighOutline v-else></VolumeHighOutline>
|
|
|
|
|
+ </n-icon>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="control-item">
|
|
|
|
|
+ <n-icon
|
|
|
|
|
+ size="16"
|
|
|
|
|
+ @click="handleDelTrack(item)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <Close></Close>
|
|
|
|
|
+ </n-icon>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -225,10 +249,15 @@
|
|
|
@close="showMediaModalCpt = false"
|
|
@close="showMediaModalCpt = false"
|
|
|
@ok="addMediaOk"
|
|
@ok="addMediaOk"
|
|
|
></MediaModalCpt>
|
|
></MediaModalCpt>
|
|
|
|
|
+ <OpenMicophoneTipCpt
|
|
|
|
|
+ v-if="showOpenMicophoneTipCpt"
|
|
|
|
|
+ @close="showOpenMicophoneTipCpt = false"
|
|
|
|
|
+ ></OpenMicophoneTipCpt>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
<script lang="ts" setup>
|
|
|
|
|
+import { Close, VolumeHighOutline, VolumeMuteOutline } from '@vicons/ionicons5';
|
|
|
import { fabric } from 'fabric';
|
|
import { fabric } from 'fabric';
|
|
|
import { UploadFileInfo } from 'naive-ui';
|
|
import { UploadFileInfo } from 'naive-ui';
|
|
|
import { NODE_ENV } from 'script/constant';
|
|
import { NODE_ENV } from 'script/constant';
|
|
@@ -238,17 +267,20 @@ import * as workerTimers from 'worker-timers';
|
|
|
|
|
|
|
|
import { usePush } from '@/hooks/use-push';
|
|
import { usePush } from '@/hooks/use-push';
|
|
|
import { DanmuMsgTypeEnum, MediaTypeEnum, liveTypeEnum } from '@/interface';
|
|
import { DanmuMsgTypeEnum, MediaTypeEnum, liveTypeEnum } from '@/interface';
|
|
|
-import { AppRootState, useAppStore } from '@/store/app';
|
|
|
|
|
|
|
+import { AppRootState } from '@/store/app';
|
|
|
|
|
+import { useAppCacheStore } from '@/store/cache';
|
|
|
import { useUserStore } from '@/store/user';
|
|
import { useUserStore } from '@/store/user';
|
|
|
import { createVideo, generateBase64, getRandomEnglishString } from '@/utils';
|
|
import { createVideo, generateBase64, getRandomEnglishString } from '@/utils';
|
|
|
|
|
|
|
|
import MediaModalCpt from './mediaModal/index.vue';
|
|
import MediaModalCpt from './mediaModal/index.vue';
|
|
|
|
|
+import OpenMicophoneTipCpt from './openMicophoneTip/index.vue';
|
|
|
import SelectMediaModalCpt from './selectMediaModal/index.vue';
|
|
import SelectMediaModalCpt from './selectMediaModal/index.vue';
|
|
|
|
|
|
|
|
const route = useRoute();
|
|
const route = useRoute();
|
|
|
const userStore = useUserStore();
|
|
const userStore = useUserStore();
|
|
|
-const appStore = useAppStore();
|
|
|
|
|
|
|
+const appCacheStore = useAppCacheStore();
|
|
|
const currentMediaType = ref(MediaTypeEnum.camera);
|
|
const currentMediaType = ref(MediaTypeEnum.camera);
|
|
|
|
|
+const showOpenMicophoneTipCpt = ref(false);
|
|
|
const showSelectMediaModalCpt = ref(false);
|
|
const showSelectMediaModalCpt = ref(false);
|
|
|
const showMediaModalCpt = ref(false);
|
|
const showMediaModalCpt = ref(false);
|
|
|
const topRef = ref<HTMLDivElement>();
|
|
const topRef = ref<HTMLDivElement>();
|
|
@@ -304,6 +336,7 @@ const mediaTypeEnumMap = {
|
|
|
[MediaTypeEnum.screen]: '窗口',
|
|
[MediaTypeEnum.screen]: '窗口',
|
|
|
[MediaTypeEnum.img]: '图片',
|
|
[MediaTypeEnum.img]: '图片',
|
|
|
[MediaTypeEnum.txt]: '文字',
|
|
[MediaTypeEnum.txt]: '文字',
|
|
|
|
|
+ [MediaTypeEnum.media]: '视频',
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
watch(
|
|
watch(
|
|
@@ -338,26 +371,121 @@ function onPageVisibility() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function handleStartLive() {
|
|
|
|
|
- lastCoverImg.value = generateBase64(pushCanvasRef.value!);
|
|
|
|
|
|
|
+function initUserMedia() {
|
|
|
|
|
+ navigator.mediaDevices
|
|
|
|
|
+ .getUserMedia({
|
|
|
|
|
+ video: true,
|
|
|
|
|
+ audio: false,
|
|
|
|
|
+ })
|
|
|
|
|
+ .then(() => {
|
|
|
|
|
+ console.log('初始化获取摄像头成功');
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ console.log('初始化获取摄像头失败');
|
|
|
|
|
+ })
|
|
|
|
|
+ .finally(() => {
|
|
|
|
|
+ navigator.mediaDevices
|
|
|
|
|
+ .getUserMedia({
|
|
|
|
|
+ video: false,
|
|
|
|
|
+ audio: true,
|
|
|
|
|
+ })
|
|
|
|
|
+ .then(() => {
|
|
|
|
|
+ console.log('初始化获取麦克风成功');
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ console.log('初始化获取麦克风失败');
|
|
|
|
|
+ showOpenMicophoneTipCpt.value = true;
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- const allAudioTrack = appStore.allTrack.filter((item) => item.audio === 1);
|
|
|
|
|
- if (allAudioTrack.length) {
|
|
|
|
|
- audioCtx.value = new AudioContext();
|
|
|
|
|
|
|
+// 处理空音频轨
|
|
|
|
|
+function initNullAudio() {
|
|
|
|
|
+ // 创建一个AudioContext实例
|
|
|
|
|
+ const audioContext = new window.AudioContext();
|
|
|
|
|
+
|
|
|
|
|
+ // 创建一个GainNode实例来控制音频的音量
|
|
|
|
|
+ const gainNode = audioContext.createGain();
|
|
|
|
|
+
|
|
|
|
|
+ // 创建一个空的音频缓存
|
|
|
|
|
+ const buffer = audioContext.createBuffer(
|
|
|
|
|
+ 2,
|
|
|
|
|
+ audioContext.sampleRate * 3,
|
|
|
|
|
+ audioContext.sampleRate
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 创建一个用于播放音频的AudioBufferSourceNode
|
|
|
|
|
+ const source = audioContext.createBufferSource();
|
|
|
|
|
+ source.buffer = buffer;
|
|
|
|
|
+
|
|
|
|
|
+ // 将源连接到gain node,再连接到输出
|
|
|
|
|
+ source.connect(gainNode);
|
|
|
|
|
+ gainNode.connect(audioContext.destination);
|
|
|
|
|
+ const destination = audioContext.createMediaStreamDestination();
|
|
|
|
|
+
|
|
|
|
|
+ const audioTrack = {
|
|
|
|
|
+ id: getRandomEnglishString(8),
|
|
|
|
|
+ audio: 1,
|
|
|
|
|
+ video: 2,
|
|
|
|
|
+ mediaName: '',
|
|
|
|
|
+ type: MediaTypeEnum.webAudio,
|
|
|
|
|
+ track: destination.stream.getAudioTracks()[0],
|
|
|
|
|
+ trackid: destination.stream.getAudioTracks()[0].id,
|
|
|
|
|
+ stream: destination.stream,
|
|
|
|
|
+ streamid: destination.stream.id,
|
|
|
|
|
+ hidden: true,
|
|
|
|
|
+ };
|
|
|
|
|
+ appCacheStore.setAllTrack([...appCacheStore.allTrack, audioTrack]);
|
|
|
|
|
+ // const vel = createVideo({});
|
|
|
|
|
+ // vel.srcObject = destination.stream;
|
|
|
|
|
+ // document.body.appendChild(vel);
|
|
|
|
|
+}
|
|
|
|
|
+let streamTmp: MediaStream;
|
|
|
|
|
+let vel;
|
|
|
|
|
+
|
|
|
|
|
+function handleMixedAudio() {
|
|
|
|
|
+ const allAudioTrack = appCacheStore.allTrack.filter(
|
|
|
|
|
+ (item) => item.audio === 1
|
|
|
|
|
+ );
|
|
|
|
|
+ if (allAudioTrack.length && audioCtx.value) {
|
|
|
const gainNode = audioCtx.value.createGain();
|
|
const gainNode = audioCtx.value.createGain();
|
|
|
allAudioTrack.forEach((item) => {
|
|
allAudioTrack.forEach((item) => {
|
|
|
if (!audioCtx.value) return;
|
|
if (!audioCtx.value) return;
|
|
|
- // const destination = audioCtx.value.createMediaStreamDestination();
|
|
|
|
|
const audioInput = audioCtx.value.createMediaStreamSource(item.stream!);
|
|
const audioInput = audioCtx.value.createMediaStreamSource(item.stream!);
|
|
|
- // gainNode.connect(destination);
|
|
|
|
|
audioInput.connect(gainNode);
|
|
audioInput.connect(gainNode);
|
|
|
|
|
+ console.log('混流', item.stream?.id, item.stream);
|
|
|
});
|
|
});
|
|
|
|
|
+ if (streamTmp) {
|
|
|
|
|
+ const destination = audioCtx.value.createMediaStreamDestination();
|
|
|
|
|
+ streamTmp.addTrack(destination.stream.getAudioTracks()[0]);
|
|
|
|
|
+ gainNode.connect(destination);
|
|
|
|
|
+ const mixedStream = new MediaStream();
|
|
|
|
|
+ mixedStream.addTrack(destination.stream.getAudioTracks()[0]);
|
|
|
|
|
+ mixedStream.addTrack(canvasVideoStream.value!.getVideoTracks()[0]);
|
|
|
|
|
+ canvasVideoStream.value = mixedStream;
|
|
|
|
|
+ console.log('替换了');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
const destination = audioCtx.value.createMediaStreamDestination();
|
|
const destination = audioCtx.value.createMediaStreamDestination();
|
|
|
- // video.onloadeddata = () => {
|
|
|
|
|
|
|
+ streamTmp = destination.stream;
|
|
|
// @ts-ignore
|
|
// @ts-ignore
|
|
|
canvasVideoStream.value?.addTrack(destination.stream.getAudioTracks()[0]);
|
|
canvasVideoStream.value?.addTrack(destination.stream.getAudioTracks()[0]);
|
|
|
- // video.srcObject = destination.stream;
|
|
|
|
|
gainNode.connect(destination);
|
|
gainNode.connect(destination);
|
|
|
|
|
+ vel = createVideo({});
|
|
|
|
|
+ vel.srcObject = destination.stream;
|
|
|
|
|
+ document.body.appendChild(vel);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function handleStartLive() {
|
|
|
|
|
+ lastCoverImg.value = generateBase64(pushCanvasRef.value!);
|
|
|
|
|
+
|
|
|
|
|
+ const allAudioTrack = appCacheStore.allTrack.filter(
|
|
|
|
|
+ (item) => item.audio === 1
|
|
|
|
|
+ );
|
|
|
|
|
+ if (allAudioTrack.length) {
|
|
|
|
|
+ audioCtx.value = new AudioContext();
|
|
|
|
|
+ handleMixedAudio();
|
|
|
}
|
|
}
|
|
|
startLive();
|
|
startLive();
|
|
|
}
|
|
}
|
|
@@ -485,7 +613,7 @@ function changeCanvasAttr({
|
|
|
// fabricCanvas.value.forEachObject((canvas) => {
|
|
// fabricCanvas.value.forEachObject((canvas) => {
|
|
|
// canvas.setCoords();
|
|
// canvas.setCoords();
|
|
|
// });
|
|
// });
|
|
|
- appStore.allTrack.forEach((item) => {
|
|
|
|
|
|
|
+ appCacheStore.allTrack.forEach((item) => {
|
|
|
if (item.canvasDom) {
|
|
if (item.canvasDom) {
|
|
|
// 分辨率变小了,将图片变小
|
|
// 分辨率变小了,将图片变小
|
|
|
if (newHeight < oldHeight) {
|
|
if (newHeight < oldHeight) {
|
|
@@ -562,6 +690,11 @@ function initCanvas() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ scrollTo(0, 0);
|
|
|
|
|
+ }, 100);
|
|
|
|
|
+ initNullAudio();
|
|
|
|
|
+ initUserMedia();
|
|
|
initCanvas();
|
|
initCanvas();
|
|
|
document.addEventListener('visibilitychange', onPageVisibility);
|
|
document.addEventListener('visibilitychange', onPageVisibility);
|
|
|
});
|
|
});
|
|
@@ -582,6 +715,7 @@ async function addMediaOk(val: {
|
|
|
mediaName: string;
|
|
mediaName: string;
|
|
|
txtInfo?: { txt: string; color: string };
|
|
txtInfo?: { txt: string; color: string };
|
|
|
imgInfo?: UploadFileInfo[];
|
|
imgInfo?: UploadFileInfo[];
|
|
|
|
|
+ mediaInfo?: UploadFileInfo[];
|
|
|
}) {
|
|
}) {
|
|
|
showMediaModalCpt.value = false;
|
|
showMediaModalCpt.value = false;
|
|
|
if (val.type === MediaTypeEnum.screen) {
|
|
if (val.type === MediaTypeEnum.screen) {
|
|
@@ -600,9 +734,9 @@ async function addMediaOk(val: {
|
|
|
mediaName: val.mediaName,
|
|
mediaName: val.mediaName,
|
|
|
type: MediaTypeEnum.screen,
|
|
type: MediaTypeEnum.screen,
|
|
|
track: event.getVideoTracks()[0],
|
|
track: event.getVideoTracks()[0],
|
|
|
|
|
+ trackid: event.getVideoTracks()[0].id,
|
|
|
stream: event,
|
|
stream: event,
|
|
|
streamid: event.id,
|
|
streamid: event.id,
|
|
|
- trackid: event.getVideoTracks()[0].id,
|
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const { canvasDom, initScale } = await autoCreateVideo({
|
|
const { canvasDom, initScale } = await autoCreateVideo({
|
|
@@ -622,15 +756,20 @@ async function addMediaOk(val: {
|
|
|
mediaName: val.mediaName,
|
|
mediaName: val.mediaName,
|
|
|
type: MediaTypeEnum.screen,
|
|
type: MediaTypeEnum.screen,
|
|
|
track: event.getAudioTracks()[0],
|
|
track: event.getAudioTracks()[0],
|
|
|
|
|
+ trackid: event.getAudioTracks()[0].id,
|
|
|
stream: event,
|
|
stream: event,
|
|
|
streamid: event.id,
|
|
streamid: event.id,
|
|
|
- trackid: event.getAudioTracks()[0].id,
|
|
|
|
|
};
|
|
};
|
|
|
- appStore.setAllTrack([...appStore.allTrack, videoTrack, audioTrack]);
|
|
|
|
|
|
|
+ appCacheStore.setAllTrack([
|
|
|
|
|
+ ...appCacheStore.allTrack,
|
|
|
|
|
+ videoTrack,
|
|
|
|
|
+ audioTrack,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ handleMixedAudio();
|
|
|
addTrack(videoTrack);
|
|
addTrack(videoTrack);
|
|
|
addTrack(audioTrack);
|
|
addTrack(audioTrack);
|
|
|
} else {
|
|
} else {
|
|
|
- appStore.setAllTrack([...appStore.allTrack, videoTrack]);
|
|
|
|
|
|
|
+ appCacheStore.setAllTrack([...appCacheStore.allTrack, videoTrack]);
|
|
|
addTrack(videoTrack);
|
|
addTrack(videoTrack);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -649,9 +788,9 @@ async function addMediaOk(val: {
|
|
|
mediaName: val.mediaName,
|
|
mediaName: val.mediaName,
|
|
|
type: MediaTypeEnum.camera,
|
|
type: MediaTypeEnum.camera,
|
|
|
track: event.getVideoTracks()[0],
|
|
track: event.getVideoTracks()[0],
|
|
|
|
|
+ trackid: event.getVideoTracks()[0].id,
|
|
|
stream: event,
|
|
stream: event,
|
|
|
streamid: event.id,
|
|
streamid: event.id,
|
|
|
- trackid: event.getVideoTracks()[0].id,
|
|
|
|
|
};
|
|
};
|
|
|
const { canvasDom, initScale } = await autoCreateVideo({
|
|
const { canvasDom, initScale } = await autoCreateVideo({
|
|
|
stream: event,
|
|
stream: event,
|
|
@@ -661,7 +800,7 @@ async function addMediaOk(val: {
|
|
|
// @ts-ignore
|
|
// @ts-ignore
|
|
|
videoTrack.initScale = initScale;
|
|
videoTrack.initScale = initScale;
|
|
|
|
|
|
|
|
- appStore.setAllTrack([...appStore.allTrack, videoTrack]);
|
|
|
|
|
|
|
+ appCacheStore.setAllTrack([...appCacheStore.allTrack, videoTrack]);
|
|
|
addTrack(videoTrack);
|
|
addTrack(videoTrack);
|
|
|
console.log('获取摄像头成功');
|
|
console.log('获取摄像头成功');
|
|
|
} else if (val.type === MediaTypeEnum.microphone) {
|
|
} else if (val.type === MediaTypeEnum.microphone) {
|
|
@@ -676,11 +815,12 @@ async function addMediaOk(val: {
|
|
|
mediaName: val.mediaName,
|
|
mediaName: val.mediaName,
|
|
|
type: MediaTypeEnum.microphone,
|
|
type: MediaTypeEnum.microphone,
|
|
|
track: event.getAudioTracks()[0],
|
|
track: event.getAudioTracks()[0],
|
|
|
|
|
+ trackid: event.getAudioTracks()[0].id,
|
|
|
stream: event,
|
|
stream: event,
|
|
|
streamid: event.id,
|
|
streamid: event.id,
|
|
|
- trackid: event.getAudioTracks()[0].id,
|
|
|
|
|
};
|
|
};
|
|
|
- appStore.setAllTrack([...appStore.allTrack, audioTrack]);
|
|
|
|
|
|
|
+ appCacheStore.setAllTrack([...appCacheStore.allTrack, audioTrack]);
|
|
|
|
|
+ handleMixedAudio();
|
|
|
addTrack(audioTrack);
|
|
addTrack(audioTrack);
|
|
|
|
|
|
|
|
console.log('获取麦克风成功');
|
|
console.log('获取麦克风成功');
|
|
@@ -688,13 +828,13 @@ async function addMediaOk(val: {
|
|
|
const txtTrack = {
|
|
const txtTrack = {
|
|
|
id: getRandomEnglishString(8),
|
|
id: getRandomEnglishString(8),
|
|
|
audio: 2,
|
|
audio: 2,
|
|
|
- video: 2,
|
|
|
|
|
|
|
+ video: 1,
|
|
|
mediaName: val.mediaName,
|
|
mediaName: val.mediaName,
|
|
|
type: MediaTypeEnum.txt,
|
|
type: MediaTypeEnum.txt,
|
|
|
track: undefined,
|
|
track: undefined,
|
|
|
|
|
+ trackid: undefined,
|
|
|
stream: undefined,
|
|
stream: undefined,
|
|
|
streamid: undefined,
|
|
streamid: undefined,
|
|
|
- trackid: undefined,
|
|
|
|
|
};
|
|
};
|
|
|
if (fabricCanvas.value) {
|
|
if (fabricCanvas.value) {
|
|
|
const dom = markRaw(
|
|
const dom = markRaw(
|
|
@@ -710,7 +850,7 @@ async function addMediaOk(val: {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
// @ts-ignore
|
|
|
- appStore.setAllTrack([...appStore.allTrack, txtTrack]);
|
|
|
|
|
|
|
+ appCacheStore.setAllTrack([...appCacheStore.allTrack, txtTrack]);
|
|
|
addTrack(txtTrack);
|
|
addTrack(txtTrack);
|
|
|
|
|
|
|
|
console.log('获取文字成功', fabricCanvas.value);
|
|
console.log('获取文字成功', fabricCanvas.value);
|
|
@@ -718,13 +858,13 @@ async function addMediaOk(val: {
|
|
|
const imgTrack = {
|
|
const imgTrack = {
|
|
|
id: getRandomEnglishString(8),
|
|
id: getRandomEnglishString(8),
|
|
|
audio: 2,
|
|
audio: 2,
|
|
|
- video: 2,
|
|
|
|
|
|
|
+ video: 1,
|
|
|
mediaName: val.mediaName,
|
|
mediaName: val.mediaName,
|
|
|
type: MediaTypeEnum.img,
|
|
type: MediaTypeEnum.img,
|
|
|
track: undefined,
|
|
track: undefined,
|
|
|
|
|
+ trackid: undefined,
|
|
|
stream: undefined,
|
|
stream: undefined,
|
|
|
streamid: undefined,
|
|
streamid: undefined,
|
|
|
- trackid: undefined,
|
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
if (fabricCanvas.value) {
|
|
if (fabricCanvas.value) {
|
|
@@ -772,25 +912,221 @@ async function addMediaOk(val: {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
// @ts-ignore
|
|
|
- appStore.setAllTrack([...appStore.allTrack, imgTrack]);
|
|
|
|
|
|
|
+ appCacheStore.setAllTrack([...appCacheStore.allTrack, imgTrack]);
|
|
|
addTrack(imgTrack);
|
|
addTrack(imgTrack);
|
|
|
|
|
|
|
|
console.log('获取图片成功', fabricCanvas.value);
|
|
console.log('获取图片成功', fabricCanvas.value);
|
|
|
|
|
+ } else if (val.type === MediaTypeEnum.media) {
|
|
|
|
|
+ const mediaVideoTrack = {
|
|
|
|
|
+ id: getRandomEnglishString(8),
|
|
|
|
|
+ audio: 2,
|
|
|
|
|
+ video: 1,
|
|
|
|
|
+ mediaName: val.mediaName,
|
|
|
|
|
+ type: MediaTypeEnum.media,
|
|
|
|
|
+ track: undefined,
|
|
|
|
|
+ trackid: undefined,
|
|
|
|
|
+ stream: undefined,
|
|
|
|
|
+ streamid: undefined,
|
|
|
|
|
+ };
|
|
|
|
|
+ if (fabricCanvas.value) {
|
|
|
|
|
+ if (!val.mediaInfo) return;
|
|
|
|
|
+ const file = val.mediaInfo[0].file!;
|
|
|
|
|
+ console.log(file);
|
|
|
|
|
+ console.log(file.name);
|
|
|
|
|
+ const url = URL.createObjectURL(file);
|
|
|
|
|
+ console.log(url);
|
|
|
|
|
+ const videoEl = createVideo({});
|
|
|
|
|
+ videoEl.src = url;
|
|
|
|
|
+ videoEl.muted = false;
|
|
|
|
|
+ videoEl.style.width = `1px`;
|
|
|
|
|
+ videoEl.style.height = `1px`;
|
|
|
|
|
+ videoEl.style.position = 'fixed';
|
|
|
|
|
+ videoEl.style.bottom = '0';
|
|
|
|
|
+ videoEl.style.right = '0';
|
|
|
|
|
+ videoEl.style.opacity = '0';
|
|
|
|
|
+ videoEl.style.pointerEvents = 'none';
|
|
|
|
|
+ document.body.appendChild(videoEl);
|
|
|
|
|
+ const videoRes = await new Promise<HTMLVideoElement>((resolve) => {
|
|
|
|
|
+ videoEl.onloadedmetadata = () => {
|
|
|
|
|
+ resolve(videoEl);
|
|
|
|
|
+ };
|
|
|
|
|
+ });
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ const stream = videoRes.captureStream();
|
|
|
|
|
+ const { canvasDom, initScale } = await autoCreateVideo({
|
|
|
|
|
+ stream,
|
|
|
|
|
+ });
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ mediaVideoTrack.canvasDom = canvasDom;
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ mediaVideoTrack.initScale = initScale;
|
|
|
|
|
+ console.log('视频有音频', stream.getAudioTracks()[0]);
|
|
|
|
|
+ if (stream.getAudioTracks()[0]) {
|
|
|
|
|
+ const audioTrack = {
|
|
|
|
|
+ id: getRandomEnglishString(8),
|
|
|
|
|
+ audio: 1,
|
|
|
|
|
+ video: 2,
|
|
|
|
|
+ mediaName: val.mediaName,
|
|
|
|
|
+ type: MediaTypeEnum.media,
|
|
|
|
|
+ track: stream.getAudioTracks()[0],
|
|
|
|
|
+ trackid: stream.getAudioTracks()[0].id,
|
|
|
|
|
+ stream,
|
|
|
|
|
+ streamid: stream.id,
|
|
|
|
|
+ };
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ appCacheStore.setAllTrack([...appCacheStore.allTrack, audioTrack]);
|
|
|
|
|
+ handleMixedAudio();
|
|
|
|
|
+ addTrack(audioTrack);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ appCacheStore.setAllTrack([...appCacheStore.allTrack, mediaVideoTrack]);
|
|
|
|
|
+ addTrack(mediaVideoTrack);
|
|
|
|
|
+
|
|
|
|
|
+ console.log('获取视频成功', fabricCanvas.value);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
canvasVideoStream.value = pushCanvasRef.value!.captureStream();
|
|
canvasVideoStream.value = pushCanvasRef.value!.captureStream();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function handleChangeMuted(item: AppRootState['allTrack'][0]) {}
|
|
|
|
|
+
|
|
|
function handleDelTrack(item: AppRootState['allTrack'][0]) {
|
|
function handleDelTrack(item: AppRootState['allTrack'][0]) {
|
|
|
console.log('handleDelTrack', item);
|
|
console.log('handleDelTrack', item);
|
|
|
if (item.canvasDom !== undefined) {
|
|
if (item.canvasDom !== undefined) {
|
|
|
// @ts-ignore
|
|
// @ts-ignore
|
|
|
fabricCanvas.value?.remove(item.canvasDom);
|
|
fabricCanvas.value?.remove(item.canvasDom);
|
|
|
}
|
|
}
|
|
|
- const res = appStore.allTrack.filter((iten) => iten.id !== item.id);
|
|
|
|
|
- appStore.setAllTrack(res);
|
|
|
|
|
|
|
+ const res = appCacheStore.allTrack.filter((iten) => iten.id !== item.id);
|
|
|
|
|
+ appCacheStore.setAllTrack(res);
|
|
|
delTrack(item);
|
|
delTrack(item);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function aaaa(e) {
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ const requestFileSystem =
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ window.requestFileSystem || window.webkitRequestFileSystem;
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ const directoryEntry = window.directoryEntry || window.webkitDirectoryEntry;
|
|
|
|
|
+ function onError(err) {
|
|
|
|
|
+ console.log(err);
|
|
|
|
|
+ }
|
|
|
|
|
+ function onFs(fs) {
|
|
|
|
|
+ fs.root.getFile(
|
|
|
|
|
+ 'myvideo',
|
|
|
|
|
+ {},
|
|
|
|
|
+ function (fileEntry) {
|
|
|
|
|
+ fileEntry.file(function (file) {
|
|
|
|
|
+ console.log(file, 777);
|
|
|
|
|
+ const url = URL.createObjectURL(file);
|
|
|
|
|
+ console.log(url);
|
|
|
|
|
+ const videoEl = createVideo({});
|
|
|
|
|
+ videoEl.src = url;
|
|
|
|
|
+ // videoEl.muted = false;
|
|
|
|
|
+ // videoEl.style.width = `1px`;
|
|
|
|
|
+ // videoEl.style.height = `1px`;
|
|
|
|
|
+ // videoEl.style.position = 'fixed';
|
|
|
|
|
+ // videoEl.style.bottom = '0';
|
|
|
|
|
+ // videoEl.style.right = '0';
|
|
|
|
|
+ // videoEl.style.opacity = '0';
|
|
|
|
|
+ // videoEl.style.pointerEvents = 'none';
|
|
|
|
|
+ document.body.appendChild(videoEl);
|
|
|
|
|
+ }, onError);
|
|
|
|
|
+ },
|
|
|
|
|
+ onError
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Opening a file system with temporary storage
|
|
|
|
|
+ requestFileSystem(
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ window.PERSISTENT,
|
|
|
|
|
+ 1024 * 1024 * 1024 /* 1GB */,
|
|
|
|
|
+ onFs,
|
|
|
|
|
+ onError
|
|
|
|
|
+ );
|
|
|
|
|
+}
|
|
|
|
|
+function ddddd(e) {
|
|
|
|
|
+ const file = e.target.files[0] as File;
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ const requestFileSystem =
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ window.requestFileSystem || window.webkitRequestFileSystem;
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ const directoryEntry = window.directoryEntry || window.webkitDirectoryEntry;
|
|
|
|
|
+ function onError(err) {
|
|
|
|
|
+ console.log(err);
|
|
|
|
|
+ }
|
|
|
|
|
+ function onFs(fs) {
|
|
|
|
|
+ // 创建文件
|
|
|
|
|
+ fs.root.getFile(
|
|
|
|
|
+ 'myvideo',
|
|
|
|
|
+ { create: true },
|
|
|
|
|
+ function (fileEntry) {
|
|
|
|
|
+ // 创建文件写入流
|
|
|
|
|
+ fileEntry.createWriter(function (fileWriter) {
|
|
|
|
|
+ fileWriter.onwriteend = () => {
|
|
|
|
|
+ // 完成后关闭文件
|
|
|
|
|
+ fileWriter.abort();
|
|
|
|
|
+ };
|
|
|
|
|
+ // 写入文件内容
|
|
|
|
|
+ fileWriter.write(file);
|
|
|
|
|
+ console.log('写入文件内容');
|
|
|
|
|
+ // const content = new Blob([fileContent]);
|
|
|
|
|
+ // fileWriter.write(content);
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ () => {
|
|
|
|
|
+ console.log('err');
|
|
|
|
|
+ }
|
|
|
|
|
+ );
|
|
|
|
|
+ // fs.root.getDirectory(
|
|
|
|
|
+ // 'Documents',
|
|
|
|
|
+ // { create: true },
|
|
|
|
|
+ // function (directoryEntry) {
|
|
|
|
|
+ // console.log(directoryEntry);
|
|
|
|
|
+ // // directoryEntry.isFile === false
|
|
|
|
|
+ // // directoryEntry.isDirectory === true
|
|
|
|
|
+ // // directoryEntry.name === 'Documents'
|
|
|
|
|
+ // // directoryEntry.fullPath === '/Documents'
|
|
|
|
|
+ // },
|
|
|
|
|
+ // onError
|
|
|
|
|
+ // );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Opening a file system with temporary storage
|
|
|
|
|
+ requestFileSystem(
|
|
|
|
|
+ // @ts-ignore
|
|
|
|
|
+ window.PERSISTENT,
|
|
|
|
|
+ 1024 * 1024 * 1024 /* 1GB */,
|
|
|
|
|
+ onFs,
|
|
|
|
|
+ onError
|
|
|
|
|
+ );
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function readDirectory(directory) {
|
|
|
|
|
+ const dirReader = directory.createReader();
|
|
|
|
|
+ let entries = [];
|
|
|
|
|
+
|
|
|
|
|
+ const getEntries = () => {
|
|
|
|
|
+ dirReader.readEntries(
|
|
|
|
|
+ (results) => {
|
|
|
|
|
+ if (results.length) {
|
|
|
|
|
+ entries = entries.concat(toArray(results));
|
|
|
|
|
+ getEntries();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ (error) => {
|
|
|
|
|
+ /* handle error — error is a FileError object */
|
|
|
|
|
+ }
|
|
|
|
|
+ );
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ getEntries();
|
|
|
|
|
+ return entries;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function handleStartMedia(item: { type: MediaTypeEnum; txt: string }) {
|
|
function handleStartMedia(item: { type: MediaTypeEnum; txt: string }) {
|
|
|
currentMediaType.value = item.type;
|
|
currentMediaType.value = item.type;
|
|
|
showMediaModalCpt.value = true;
|
|
showMediaModalCpt.value = true;
|
|
@@ -935,15 +1271,21 @@ function handleStartMedia(item: { type: MediaTypeEnum; txt: string }) {
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
justify-content: space-between;
|
|
|
margin: 5px 0;
|
|
margin: 5px 0;
|
|
|
- font-size: 12px;
|
|
|
|
|
|
|
+ font-size: 14px;
|
|
|
&:hover {
|
|
&:hover {
|
|
|
- .del {
|
|
|
|
|
- display: block;
|
|
|
|
|
|
|
+ .control {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- .del {
|
|
|
|
|
|
|
+ .control {
|
|
|
display: none;
|
|
display: none;
|
|
|
- cursor: pointer;
|
|
|
|
|
|
|
+ .control-item {
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ &:not(:last-child) {
|
|
|
|
|
+ margin-right: 6px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
.bottom {
|
|
.bottom {
|