在 Electron 中,video 标签在加载大视频文件时,可能会遇到内存限制的问题而只显示音频。这是因为 Electron 默认情况下使用了 Chromium 的内存限制策略,对于大视频文件,它会尝试加载并播放音频,但限制视频的加载以节省内存。
1.默认情况下,Chromium 的内存限制策略将视音频分为两个阶段加载
1. 初始阶段(Initial phase):Chromium 会尝试加载视频的音频轨道,同时限制视频的加载,以减少内存使用。在这个阶段,video 标签只会显示音频而不显示视频。
2. 缓冲阶段(Buffering phase):一旦音频轨道被加载并播放,Chromium 将尝试加载视频的缓冲区。在这个阶段,视频将开始显示。
2.是否显示视频的临界值
临界值(Threshold):是根据视频文件的大小和设备的可用内存而定,并没有一个固定的数值。较小的视频文件可能会在初始阶段快速加载完音频,并在缓冲阶段开始显示视频。而较大的视频文件可能会导致初始阶段只显示音频,直到缓冲阶段才开始显示视频。
下列代码通过监听"loadedmetadata"事件,可根据videoWidth、videoHeight判断加载视频还是音频
handleVideo() {
const video = this.$refs['videoId'];
if (video) {
video.addEventListener("loadedmetadata", () => {
if (video.videoWidth !== 0 && video.videoHeight !== 0) {
// 视频加载成功,显示视频和音频
video.style.display = "block";
} else {
// 视频加载失败,只显示音频
video.style.height = "30px";
video.style.width = "240px";
this.isDownload = true;
}
});
}
},
3.可以尝试以下几种解决方法
1. 使用流式传输:将大视频文件分成小块进行流式传输,这样可以避免一次性加载整个视频文件。你可以使用流传输库如 `range-request` 来实现。
2. 使用 WebRTC:使用 WebRTC 技术来进行实时流传输,这样可以避免一次性加载整个视频文件。你可以使用 WebRTC 库如 `simple-peer` 或 `peerjs` 来实现。
3. 使用外部视频播放器:将视频文件的播放委托给外部的视频播放器应用,比如 VLC 播放器。你可以使用 Electron 的 `shell` 模块来打开外部应用程序,并传递视频文件的路径作为参数。
4. 调整内存限制(亲测没用):你可以通过修改 Electron 的启动参数来调整 Chromium 的内存限制策略。具体来说,你可以尝试修改 `app.commandLine.appendSwitch('max-old-space-size', '4096')` 来增加内存限制。
关于 `app.commandLine.appendSwitch('max-old-space-size', '4096')` 没有起作用的问题,可能是因为这个设置并不会直接影响到 Chromium 的内存限制策略。这个设置是用来增加 Node.js 进程的内存限制,而不是影响 Chromium 的内存使用。所以即使增加了 Node.js 进程的内存限制,Chromium 仍然会按照默认的内存限制策略进行加载。
5. 提供下载视频入口外部下载播放(思考出来实际应用的方法):在显示音频的控件中,使用绝对定位写一个下载图标,覆盖控件中的“...”按钮,绑定下载事件。
通过a标签下载
// <i class="download el-icon-download" v-show="isDownload" @click="downloadFile(url)"></i>
downloadFile(url) {
let a = document.createElement("a");
a.style.display = "none";
a.href = url; // 给a标签创建下载的链接
a.download = data.name;
// a.setAttribute('referrerpolicy', 'no-referrer'); // 添加Referrer-Policy属性,下载文件时将会发送空的 Referer 头部
a.setAttribute('referrerpolicy', 'origin-when-cross-origin');
a.setAttribute('referrer', 'http://my.uat.com'); // 下载文件时,将会在请求头中发送指定的 Referer 值
// 请注意,这种方法仅在浏览器环境中有效,在 Electron 环境中可能会有其他限制。
document.body.appendChild(a); // 把a标签作为子节点插入当前body下
a.click(); // 点击a标签下载
document.body.removeChild(a); // 下载完成移除元素
},
调用 shell
的 openExternal
方法来触发文件下载:
可以使用 session
模块来控制请求头。session.defaultSession.webRequest.onBeforeSendHeaders
方法来监听所有的请求,在下载文件之前判断请求的资源类型和 URL 是否符合条件,然后设置请求头中的 Referer。
下面的 filePath
是你想要保存文件的路径,需要根据你的实际需求进行修改。
const { session } = require('electron');
// 在下载文件之前设置请求头
session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
// 判断是否是下载请求
if (details.resourceType === 'mainFrame' && details.method === 'GET' && details.url.startsWith('https://customer')) {
// 设置 Referer 头部
details.requestHeaders['Referer'] = 'https://uat.com';
}
callback({ cancel: false, requestHeaders: details.requestHeaders });
});
downloadFile(data) {
const url = data.url;
const filePath = `path/to/save/${data.name}`;
shell.openExternal(url).then(() => {
console.log('File download started');
}).catch(err => {
console.error('File download failed:', err);
});
}
请注意,在使用以上方法之前,你需要确保你的电脑具备足够的内存和处理能力来处理大视频文件。另外,还需要注意用户体验和性能方面的考虑,确保视频加载和播放的流畅性
4.使用外部视频播放器的demo
在 Electron 中使用外部视频播放器可以通过 `shell` 模块打开外部应用程序来实现。
const { app, BrowserWindow, shell } = require('electron');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
});
// 加载你的 HTML 文件
mainWindow.loadFile('index.html');
// 当点击播放按钮时,打开外部视频播放器
mainWindow.webContents.on('did-finish-load', () => {
mainWindow.webContents.executeJavaScript(`
const playButton = document.getElementById('play-button');
playButton.addEventListener('click', () => {
const videoPath = '/path/to/your/video/file.mp4'; // 替换为你的视频文件路径
shell.openExternal(videoPath);
});
`);
});
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
在上面的代码中,我们首先创建了一个 Electron 窗口并加载了一个 HTML 文件。在 HTML 文件中,我们假设有一个播放按钮,当点击该按钮时,会调用 `shell.openExternal()` 方法来打开外部视频播放器并传递视频文件路径作为参数。
请注意,在示例中的 `videoPath` 变量中,你需要将 `/path/to/your/video/file.mp4` 替换为你实际的视频文件路径。另外,确保你的电脑上已安装了一个能够处理视频文件的外部播放器应用程序。