在主线程 chrome 块中同时录制视频和音频,导致无效音频
Recording video simultaneously with audio in chrome blocks on main thread, causing invalid audio
所以,我有一个我认为相当有趣且希望不是棘手的问题。我在 Chrome 中录制了一个 audio/video getUserMedia 流。单独地,曲目记录得非常好。但是,当尝试同时记录两者时,一个会阻塞主线程,从而阻塞另一个。我知道有办法解决这个问题。 Muaz Khan 有一些演示似乎没有阻塞。
音频是通过 web audio API 录制的。我将音轨传输到处理器节点,处理器节点将其转换为 16b 单声道并将其流式传输到 node.js 服务器。
视频是通过通常的 canvas hack 和 Whammy.js 录制的。录制时,视频帧被绘制到canvas,然后生成的图像数据被推入帧数组,随后由Whammy编码到webm容器中,随后上传到node.js服务器。
然后通过 ffmpeg 服务器端将两者混合在一起并存储结果。
到目前为止我的想法是:
- 将一个委托给工作线程。不幸的是,据我所知,canvas 和流都是 DOM 的成员。
- 在node.js中安装无头浏览器并与客户端建立rtc连接,从而暴露整个流服务器端
整个局面最终会被Audio Worker implementation解决。工作组似乎已经停止 public 进度更新,虽然事情有点混乱。
有什么解决线程阻塞的建议吗?
网络音频连接:
var context = new AudioContext();
var source = context.createMediaStreamSource(stream);
var node = context.createScriptProcessor(2048, 1, 1);
node.onaudioprocess = audioProcess;
source.connect(node);
node.connect(context.destination);
网络音频处理:
if (!recording.audio) return;
var leftChannel = e.inputBuffer.getChannelData(0);
Socket.emit('record-audio', convertFloat32ToInt16(leftChannel));
视频帧缓冲:
if (recording.video) {
players.canvas.context.fillRect(0, 0, players.video.width, players.video.height);
players.canvas.context.drawImage(players.video.element, 0, 0, players.video.width, players.video.height);
frames.push({
duration: 100,
image: players.canvas.element.toDataURL('image/webp')
});
lastTime = new Date().getTime();
requestAnimationFrame(drawFrame);
} else {
requestAnimationFrame(getBlob);
}
更新:我已经设法阻止这两个操作完全相互阻塞,但它仍然足以使我的音频失真。
目前在 Chrome 中成功进行 getUserMedia 录制有一些关键因素,这些关键因素来自从原始问题所附的有用评论和我自己的经验中收集到的信息集合。
- 从录音中获取数据时 canvas,编码为 jpeg。我一直在尝试 webp 来满足 Whammy.js 的要求。生成一个 webp dataURI 显然是一个周期猪。
- 将尽可能多的非DOM 操作委托给工作线程。对于任何流媒体/上传操作(例如,通过 websockets 的音频样本流媒体)尤其如此
- 避免使用 requestAnimationFrame 来促进记录 canvas 绘图。它是资源密集型的,正如 Aldel 所指出的,如果用户切换选项卡,它可能会失败。使用 setInterval 更 efficient/reliable。它还允许更好的帧率控制。
- 至少Chrome,暂时避免客户端AV编码。在服务器端流式传输音频样本和视频帧以进行处理。虽然客户端 AV 编码库非常酷,但它们似乎还不足以用于生产。
此外,对于 Node.js ffmpeg 自动化,我强烈推荐 fluent-ffmpeg。特别感谢 Benjamin Trent 提供的一些实际示例。
@aldel 是对的。增加 bufferSize 值可以修复它。例如。 bufferSize= 16384;
在 chrome 中尝试 this demo 并记录 audio+video
。您将听到与 720p 视频帧并行的清晰录制的 WAV。
顺便说一句,我同意 jesup 的观点,应该首选 MediaRecorder 解决方案。
Chromium 人员非常接近,希望 M47/48 能带来 MediaRecorder 实现!至少对于视频 (vp8) 录制。
whammy.js 也有基于 chrome 的替代方案:
所以,我有一个我认为相当有趣且希望不是棘手的问题。我在 Chrome 中录制了一个 audio/video getUserMedia 流。单独地,曲目记录得非常好。但是,当尝试同时记录两者时,一个会阻塞主线程,从而阻塞另一个。我知道有办法解决这个问题。 Muaz Khan 有一些演示似乎没有阻塞。
音频是通过 web audio API 录制的。我将音轨传输到处理器节点,处理器节点将其转换为 16b 单声道并将其流式传输到 node.js 服务器。
视频是通过通常的 canvas hack 和 Whammy.js 录制的。录制时,视频帧被绘制到canvas,然后生成的图像数据被推入帧数组,随后由Whammy编码到webm容器中,随后上传到node.js服务器。
然后通过 ffmpeg 服务器端将两者混合在一起并存储结果。
到目前为止我的想法是:
- 将一个委托给工作线程。不幸的是,据我所知,canvas 和流都是 DOM 的成员。
- 在node.js中安装无头浏览器并与客户端建立rtc连接,从而暴露整个流服务器端
整个局面最终会被Audio Worker implementation解决。工作组似乎已经停止 public 进度更新,虽然事情有点混乱。
有什么解决线程阻塞的建议吗?
网络音频连接:
var context = new AudioContext();
var source = context.createMediaStreamSource(stream);
var node = context.createScriptProcessor(2048, 1, 1);
node.onaudioprocess = audioProcess;
source.connect(node);
node.connect(context.destination);
网络音频处理:
if (!recording.audio) return;
var leftChannel = e.inputBuffer.getChannelData(0);
Socket.emit('record-audio', convertFloat32ToInt16(leftChannel));
视频帧缓冲:
if (recording.video) {
players.canvas.context.fillRect(0, 0, players.video.width, players.video.height);
players.canvas.context.drawImage(players.video.element, 0, 0, players.video.width, players.video.height);
frames.push({
duration: 100,
image: players.canvas.element.toDataURL('image/webp')
});
lastTime = new Date().getTime();
requestAnimationFrame(drawFrame);
} else {
requestAnimationFrame(getBlob);
}
更新:我已经设法阻止这两个操作完全相互阻塞,但它仍然足以使我的音频失真。
目前在 Chrome 中成功进行 getUserMedia 录制有一些关键因素,这些关键因素来自从原始问题所附的有用评论和我自己的经验中收集到的信息集合。
- 从录音中获取数据时 canvas,编码为 jpeg。我一直在尝试 webp 来满足 Whammy.js 的要求。生成一个 webp dataURI 显然是一个周期猪。
- 将尽可能多的非DOM 操作委托给工作线程。对于任何流媒体/上传操作(例如,通过 websockets 的音频样本流媒体)尤其如此
- 避免使用 requestAnimationFrame 来促进记录 canvas 绘图。它是资源密集型的,正如 Aldel 所指出的,如果用户切换选项卡,它可能会失败。使用 setInterval 更 efficient/reliable。它还允许更好的帧率控制。
- 至少Chrome,暂时避免客户端AV编码。在服务器端流式传输音频样本和视频帧以进行处理。虽然客户端 AV 编码库非常酷,但它们似乎还不足以用于生产。
此外,对于 Node.js ffmpeg 自动化,我强烈推荐 fluent-ffmpeg。特别感谢 Benjamin Trent 提供的一些实际示例。
@aldel 是对的。增加 bufferSize 值可以修复它。例如。 bufferSize= 16384;
在 chrome 中尝试 this demo 并记录 audio+video
。您将听到与 720p 视频帧并行的清晰录制的 WAV。
顺便说一句,我同意 jesup 的观点,应该首选 MediaRecorder 解决方案。
Chromium 人员非常接近,希望 M47/48 能带来 MediaRecorder 实现!至少对于视频 (vp8) 录制。
whammy.js 也有基于 chrome 的替代方案: