123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import { FFmpeg } from '@ffmpeg/ffmpeg';
- import { fetchFile, toBlobURL } from '@ffmpeg/util';
- import { showSaveFilePicker } from 'native-file-system-adapter';
- import workerUrl from '../../../../node_modules/@ffmpeg/ffmpeg/dist/esm/worker.js?worker&url';
- const ffmpeg = new FFmpeg();
- (async () => {
- await ffmpeg.load({
- coreURL: await toBlobURL(
- new URL('./core/package/pkg/esm/ffmpeg-core.js', import.meta.url),
- 'text/javascript'
- ),
- wasmURL: await toBlobURL(
- new URL('./core/package/pkg/esm/ffmpeg-core.wasm', import.meta.url),
- 'application/wasm'
- ),
- classWorkerURL: new URL(workerUrl, import.meta.url).toString(),
- });
- })();
- function formatDateTime(date) {
- function padZero(num) {
- return num < 10 ? '0' + num : num;
- }
- let year = date.getFullYear();
- let month = padZero(date.getMonth() + 1);
- let day = padZero(date.getDate());
- let hours = padZero(date.getHours());
- let minutes = padZero(date.getMinutes());
- let seconds = padZero(date.getSeconds());
- let Milliseconds = date.getMilliseconds();
- return `${year}${month}${day}${hours}${minutes}${seconds}${Milliseconds}`;
- }
- /**
- *
- * @param {Blob} blob
- * @param {String} fileName - 文件名
- */
- async function DownloadStreamSaver(blob, fileName, type) {
- const opts = {
- suggestedName: fileName,
- types: [{ 'image/png': ['png'] }],
- };
- if (window.parent != window) {
- window.parent.postMessage(
- { type: 'native-file-system-adapter', imgOrVideo: type, opts, blob },
- '*'
- );
- } else {
- if (type === 'img') {
- // 创建一个新的Image对象
- const img = new Image();
- img.src = URL.createObjectURL(blob);
- // 等待图片加载完成
- img.onload = () => {
- // 创建Canvas元素
- const canvas = document.createElement('canvas');
- const ctx = canvas.getContext('2d');
- // 设置Canvas大小
- canvas.width = img.width;
- canvas.height = img.height;
- if (ctx) {
- ctx.translate(img.width / 2, img.height / 2);
- ctx.rotate(Math.PI);
- ctx.translate(-img.width / 2, -img.height / 2);
- ctx.drawImage(img, 0, 0);
- }
- // 将旋转后的Canvas转换回Blob
- canvas.toBlob(async (rotatedBlob) => {
- const handle = await showSaveFilePicker(opts);
- const ws = await handle.createWritable();
- ws.write(rotatedBlob);
- ws.close();
- });
- };
- } else {
- const handle = await showSaveFilePicker(opts);
- const ws = await handle.createWritable();
- ws.write(blob);
- ws.close();
- }
- }
- }
- /**
- *
- * @param {String} url - 图片请求地址
- * @param {String} fileName - 文件名
- */
- async function UrlStreamSaverDownload(url, fileName) {
- const opts = {
- suggestedName: fileName,
- types: [{ 'image/png': ['png'] }],
- };
- const handle = await showSaveFilePicker(opts);
- const ws = await handle.createWritable();
- fetch(url)
- .then((response) => {
- if (!response.ok) {
- throw new Error('Network response was not ok ' + response.statusText);
- }
- return response.blob();
- })
- .then((blob) => {
- ws.write(blob);
- ws.close();
- })
- .catch((error) => {
- console.error(
- 'There has been a problem with your fetch operation:',
- error
- );
- });
- }
- /**
- *
- * @param {String} url - wss连接地址 wss://origin/VideoShow/Common?UUID=uuid&DeviceID=deviceID&Token=token
- * @param {String} className - 选择器 .video-class | #video-class ...
- * @param {String} device - 设备ID
- * @param {Function} callback - 画面渲染完成时的回调
- * @returns {Object} 包含两个Web Worker和一个关闭函数的对象
- */
- function useWorker(
- url,
- className,
- device,
- callback = () => {},
- cropFullInfo = ''
- ) {
- let canvas = document.querySelector(className);
- canvas = canvas.transferControlToOffscreen();
- const worker = new Worker(new URL('./worker.js', import.meta.url), {
- type: 'module',
- });
- worker.addEventListener('message', (msg) => {
- if (msg.data.type === 'img') {
- // saveAs(msg.data.img,`${formatDateTime(new Date())}.png`)
- DownloadStreamSaver(
- msg.data.img,
- `${formatDateTime(new Date())}.png`,
- msg.data.type
- );
- } else {
- callback();
- }
- });
- let DataType = 'Start';
- worker.postMessage(
- { DataType, canvas, url, device, cropFullInfo, className },
- [canvas]
- );
- const WebSocketWork = new Worker(
- new URL('./GetVideoStreaming.js', import.meta.url).href,
- {
- type: 'module',
- }
- );
- WebSocketWork.postMessage({ url });
- WebSocketWork.addEventListener('message', async (message) => {
- if (message.data.DataType === 'Track') {
- let DataType = 'Track';
- let codec = message.data.track.codec.startsWith('vp08')
- ? 'vp8'
- : message.data.track.codec;
- let codedHeight = message.data.track.video.height;
- let codedWidth = message.data.track.video.width;
- let description = message.data.tkinfo;
- worker.postMessage({
- DataType,
- codec,
- codedHeight,
- codedWidth,
- description,
- });
- }
- if (message.data.DataType === 'Samples') {
- let DataType = 'Samples';
- let type = message.data.sample.is_sync ? 'key' : 'delta';
- let timestamp =
- (1e6 * message.data.sample.cts) / message.data.sample.timescale;
- let duration =
- (1e6 * message.data.sample.duration) / message.data.sample.timescale;
- let data = message.data.sample.data;
- let showData = message.data.showData;
- worker.postMessage({
- DataType,
- type,
- timestamp,
- duration,
- data,
- showData,
- });
- }
- if (message.data.DataType === 'lx') {
- ffmpeg.on('log', ({ message: msg }) => {
- console.log(msg);
- });
- await ffmpeg.writeFile('test.mp4', await fetchFile(message.data.Data));
- ffmpeg.exec([
- '-i',
- 'test.mp4',
- '-c',
- 'copy',
- '-metadata:s:v',
- 'rotate=90',
- 'out.mp4',
- ]);
- const data = await ffmpeg.readFile('out.mp4');
- ffmpeg.deleteFile('test.mp4');
- DownloadStreamSaver(
- new Blob([data.buffer], { type: 'video/mp4' }),
- `${formatDateTime(new Date())}.mp4`,
- message.data.DataType
- );
- ffmpeg.deleteFile('out.mp4');
- }
- });
- return {
- worker,
- WebSocketWork,
- close: () => {
- WebSocketWork.terminate();
- worker.terminate();
- },
- };
- }
- window['OmnimatrixVideoPayer'] = useWorker;
- export { UrlStreamSaverDownload };
- export default useWorker;
|