特殊
HTML标签template中存在head和body均会自动清除,比如 <template><head><title>t</title></head><body>x</body></template> 用t.innerHTML获取的是:
<title>t</title>x
带声调拼音,在中文OS默认宋体下高度未对齐 解决 font-family: sans-serif;
录音录像:
navigator.mediaDevices.getUserMedia({audio: true}) // {video: true, audio: true}
.then(stream=>{ var mr=new MediaRecorder(stream, {mimeType: "audio/webm;codecs=opus"}); // 遍历属性:
for(var k in mr){ console.log(k+": "+mr[k]); } }).catch(console.error);
录制格式支持情况: 媒体文件信息查看工具(或用ffprobe) - https://github.com/MediaArea/MediaInfo
mimeType - 若不写codecs属性,或与其值无任何匹配项,则根据MIME容器推断出兼容的编解码格式;通常左起依次尝试,若音频写在了视频前方,则视频编码时会自动跳过,通过逗号分隔。
首选Chrome、Edge和Firefox均支持的*.webm容器文件:audio/webm;codecs=opus 和 video/webm;codecs=opus,vp8
iOS Safari 18.4起已支持WebM+Opus(旧版本只支持video/mp4;codecs=opus) - https://developer.apple.com/documentation/safari-release-notes/safari-18_4-release-notes#Media
网络传输用有损压缩的 audio/webm;codecs=opus 无损录音用PCM(PCM非WAV专用):MediaRecorder.isTypeSupported("audio/webm;codecs=pcm");
Chrome支持媒体格式列表 - https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/fast/mediarecorder/MediaRecorder-isTypeSupported.html
AudioWorklet取代了弃用的ScriptProcessor,用于主线程外处理提升效率。
解码音频数据 - new AudioContext().decodeAudioData(buffer, function(audioBuffer) { /* 拼接、修剪 */ });
decodeAudioData 会自动忽略webm容器内视频数据,并将原始数据填充到AudioBuffer对象中,内部采用PCM数据格式,丢弃文件头等专用信息。
OfflineAudioContext - 纯计算不走硬件。
var oac=new OfflineAudioContext(decodedAudioData...); oac.createBufferSource(); ... const renderedBuffer = await oac.startRendering()
库:
ffmpeg.wasm(约30MB) - https://github.com/ffmpegwasm/ffmpeg.wasm
await ffmpeg.run('-i', 'bj.mp4', '-i', 'record.mp3', '-c:v', 'copy', '-c:a', 'aac', '-strict', 'experimental', '-map', '0:v:0', '-map', '1:a:0', 'output.mp4');
webm js库 - https://github.com/jscodec/jswebm
mp4 - https://gpac.github.io/mp4box.js/
flac - https://github.com/mmig/libflac.js
webm转wav - https://blog.csdn.net/u012663281/article/details/112919404
var types = [
"video/webm",
"audio/webm",
"video/webm;codecs=vp8",
"video/webm;codecs=daala",
"video/webm;codecs=h264",
"audio/webm;codecs=opus",
"video/mpeg",
];
for (var i in types) {
console.log(
"Is " +
types[i] +
" supported? " +
(MediaRecorder.isTypeSupported(types[i]) ? "Maybe!" : "Nope :("),
);
}
map方法内await不会等待: arrays.map(async (chunk, index) => { await fetch(url); })
可换为:for (const chunk of ac) { await fetch(url); }
测量用时:
performance.mark('start-x');
// doSomething();
performance.mark('end-x');
performance.measure('x', 'start-x', 'end-x');