gemercheung %!s(int64=2) %!d(string=hai) anos
pai
achega
5269b9aa94

+ 1 - 1
packages/core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@simaq/core",
-  "version": "1.1.9",
+  "version": "1.2.0",
   "main": "dist/index",
   "types": "dist/index",
   "files": [

+ 5 - 6
packages/core/src/lib/basicSimaqRecorder.ts

@@ -70,7 +70,8 @@ export class BasicSimaqRecorder extends EventEmitter {
     private systemAudio = false;
     private debug = false;
     private codecType = 'video/webm;codecs=vp9,opus';
-    private codecH264Type = 'video/mp4;codecs=h264,opus';
+    private codecFileType = 'video/webm';
+    // private codecH264Type = 'video/mp4;codecs=h264,opus';
 
     constructor(arg: InitConfigType) {
         super();
@@ -427,7 +428,7 @@ export class BasicSimaqRecorder extends EventEmitter {
                 this.emit(
                     'record',
                     new Blob([event.data], {
-                        type: this.codecType,
+                        type: this.codecFileType,
                     }),
                 );
             };
@@ -448,16 +449,14 @@ export class BasicSimaqRecorder extends EventEmitter {
             this.mediaRecorder.onresume = (event) => {
                 console.warn(`onresume stream: `, event);
             };
-
         } catch (error) {
             console.error('error', error);
         }
-
     }
 
     private handleAutoDownload(chunks: Blob[]): void {
         const downloadBlob = new Blob(chunks, {
-            type: this.codecH264Type,
+            type: this.codecFileType,
         });
         const url = URL.createObjectURL(downloadBlob);
         const a: HTMLAnchorElement = document.createElement('a');
@@ -465,7 +464,7 @@ export class BasicSimaqRecorder extends EventEmitter {
         a.style.display = 'none';
         a.href = url;
         const name = new Date().getTime();
-        a.download = `${name}.mp4`;
+        a.download = `${name}.webm`;
         a.click();
         window.URL.revokeObjectURL(url);
     }

+ 2 - 2
play/index.html

@@ -4,8 +4,8 @@
         <meta charset="UTF-8" />
         <link rel="icon" type="image/svg+xml" href="/vite.svg" />
         <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-        <link rel="stylesheet" href="/player/goldplay-h265.css" />
-        <script src="/player/goldplay-h265-sdk.js"></script>
+        <!-- <link rel="stylesheet" href="/player/goldplay-h265.css" /> -->
+        <!-- <script src="/player/goldplay-h265-sdk.js"></script> -->
 
         <title>Simaq video recorder SDK</title>
     </head>

+ 5 - 3
play/package.json

@@ -9,14 +9,16 @@
         "preview": "vite preview"
     },
     "dependencies": {
+        "@ffmpeg/ffmpeg": "^0.12.6",
+        "@ffmpeg/util": "^0.12.1",
         "@simaq/core": "workspace:^1.1.7",
+        "howler": "^2.2.3",
         "lodash-es": "^4.17.21",
-        "vue": "^3.2.40",
-        "howler": "^2.2.3"
+        "vue": "^3.2.40"
     },
     "devDependencies": {
-        "@vitejs/plugin-vue": "^3.1.2",
         "@types/howler": "^2.2.7",
+        "@vitejs/plugin-vue": "^3.1.2",
         "typescript": "^4.8.4",
         "vite": "^3.1.7",
         "vite-plugin-mkcert": "^1.10.1",

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 16 - 0
play/public/ffmpeg-core.js


BIN=BIN
play/public/ffmpeg-core.wasm


+ 80 - 22
play/src/App.vue

@@ -2,12 +2,49 @@
 // This starter template is using Vue 3 <script setup> SFCs
 // Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
 import HelloWorld from './components/HelloWorld.vue';
+import { FFmpeg } from '@ffmpeg/ffmpeg';
 import { VideoRecorder } from '@simaq/core';
-import { onMounted } from 'vue';
+import { onMounted, ref } from 'vue';
 import { Howler, Howl } from 'howler';
+import { fetchFile, toBlobURL } from '@ffmpeg/util';
+const ffmpeg = new FFmpeg();
+
+const load = async () => {
+    // const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/esm';
+    const baseMTURL = 'https://unpkg.com/@ffmpeg/core-mt@0.12.3/dist/esm';
+    try {
+        // debugger
+        ffmpeg.on('log', ({ message }) => {
+            console.log(message);
+        });
+        // toBlobURL is used to bypass CORS issue, urls with the same
+        // domain can be used directly.
+        await ffmpeg.load({
+            coreURL: await toBlobURL(
+                `${baseMTURL}/ffmpeg-core.js`,
+                'text/javascript',
+            ),
+            wasmURL: await toBlobURL(
+                `${baseMTURL}/ffmpeg-core.wasm`,
+                'application/wasm',
+            ),
+            workerURL: await toBlobURL(
+                `${baseMTURL}/ffmpeg-core.worker.js`,
+                'text/javascript',
+            ),
+        });
+        console.log('ffmpeg-isLoad');
+    } catch (error) {
+        console.error('ffmpeg-load-error', error);
+    }
+};
+onMounted(async () => {
+    load();
+});
+
 // import { add } from "lodash-es";
 // import { meaningOfLife } from "@simaq/foo";
-console.log('howler', Howler, Howl);
+// console.log('howler', Howler, Howl);
 let sound = new Howl({
     html5: false,
     src: ['gs-16b-2c-44100hz.wav'],
@@ -16,11 +53,12 @@ const videoRecorder = new VideoRecorder({
     // uploadUrl: '',
     resolution: '4k',
     autoDownload: false,
-    platform: 'canvas',
+    platform: 'electron',
     // disabledAudio: false,
     config: {
-        frameRate: 60,
-        canvasId: '#testCanvas',
+        // frameRate: 60,
+        chromeMediaSourceId:""
+        // canvasId: '#testCanvas',
     },
     systemAudio: true,
     debugShowVideo: false,
@@ -45,10 +83,10 @@ videoRecorder.on('record', (data: Blob) => {
     //录屏后片断数据
     console.log('record', data);
 });
-videoRecorder.on('endRecord', (data) => {
+videoRecorder.on('endRecord', async (data) => {
     console.log('endRecord', data);
     sound.stop();
-    handleAutoDownload([data]);
+    handleAutoDownload(data);
     //结束录屏event
 });
 videoRecorder.on('cancelRecord', () => {
@@ -56,21 +94,41 @@ videoRecorder.on('cancelRecord', () => {
     //cancel录屏event
 });
 const handleAutoDownload = async (chunks: Blob[]) => {
-    const downloadBlob = new Blob(chunks, {
-        type: 'video/mp4; codecs=h264',
-    });
-    // const downloadBlob = await fixWebmMetaInfo(
-    //     new Blob(chunks, { type: 'video/webm; codecs=h264' }),
-    // );
-    const url = URL.createObjectURL(downloadBlob);
-    const a: HTMLAnchorElement = document.createElement('a');
-    document.body.appendChild(a);
-    a.style.display = 'none';
-    a.href = url;
-    const name = new Date().getTime();
-    a.download = `${name}.mp4`;
-    a.click();
-    window.URL.revokeObjectURL(url);
+    try {
+        console.log('handleAutoDownload');
+        const downloadBlob = new Blob(chunks, {
+            type: 'video/webm',
+        });
+        const url = URL.createObjectURL(downloadBlob);
+
+        await ffmpeg.writeFile('input.webm', await fetchFile(url));
+
+        console.log('进入3', await ffmpeg.listDir('/'));
+        console.log('进入3', await ffmpeg.readFile('input.webm'));
+        await ffmpeg.exec([
+            '-i',
+            'input.webm',
+            // '-c:a copy -c:v libx264',
+            'output.mp4',
+        ]);
+        const data = await ffmpeg.readFile('output.mp4');
+        console.log('进入成功', data);
+
+        const covertURl = URL.createObjectURL(
+            //@ts-ignore
+            new Blob([data.buffer], { type: 'video/mp4' }),
+        );
+        const a: HTMLAnchorElement = document.createElement('a');
+        document.body.appendChild(a);
+        a.style.display = 'none';
+        a.href = covertURl;
+        const name = new Date().getTime();
+        a.download = `${name}.mp4`;
+        a.click();
+        window.URL.revokeObjectURL(url);
+    } catch (error) {
+        console.error(error);
+    }
 };
 onMounted(() => {
     // const GoldPlay = (window as any).GoldPlay;

+ 9 - 0
play/vite.config.ts

@@ -5,4 +5,13 @@ import mkcert from 'vite-plugin-mkcert';
 // https://vitejs.dev/config/
 export default defineConfig({
     plugins: [vue(), mkcert()],
+    optimizeDeps: {
+        exclude: ['@ffmpeg/ffmpeg', '@ffmpeg/util'],
+    },
+    server: {
+        headers: {
+            'Cross-Origin-Opener-Policy': 'same-origin',
+            'Cross-Origin-Embedder-Policy': 'require-corp',
+        },
+    },
 });

+ 23 - 0
pnpm-lock.yaml

@@ -60,6 +60,12 @@ importers:
 
   play:
     dependencies:
+      '@ffmpeg/ffmpeg':
+        specifier: ^0.12.6
+        version: 0.12.6
+      '@ffmpeg/util':
+        specifier: ^0.12.1
+        version: 0.12.1
       '@simaq/core':
         specifier: workspace:^1.1.7
         version: link:../packages/core
@@ -167,6 +173,23 @@ packages:
       - supports-color
     dev: true
 
+  /@ffmpeg/ffmpeg@0.12.6:
+    resolution: {integrity: sha512-4CuXDaqrCga5qBwVtiDDR45y65OGPYZd7VzwGCGz3QLdrQH7xaLYEjU19XL4DTCL0WnTSH8752b8Atyb1SiiLw==}
+    engines: {node: '>=18.x'}
+    dependencies:
+      '@ffmpeg/types': 0.12.1
+    dev: false
+
+  /@ffmpeg/types@0.12.1:
+    resolution: {integrity: sha512-n+v9yvxaBPi1Z/1wy2PvqMHvED3qV7LXBWnBmMBAAzybbs4KWp6wrhCTMxITORMHXpPZEEupsBH1iEoLuzYSUw==}
+    engines: {node: '>=16.x'}
+    dev: false
+
+  /@ffmpeg/util@0.12.1:
+    resolution: {integrity: sha512-10jjfAKWaDyb8+nAkijcsi9wgz/y26LOc1NKJradNMyCIl6usQcBbhkjX5qhALrSBcOy6TOeksunTYa+a03qNQ==}
+    engines: {node: '>=18.x'}
+    dev: false
+
   /@humanwhocodes/config-array@0.9.5:
     resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==}
     engines: {node: '>=10.10.0'}