Recording: prefer hardware H.264 (VideoToolbox) for the realtime pass
MediaRecorder in Electron 33 muxes MP4 with avc1 High profile + AAC; on macOS that encode runs on VideoToolbox hardware, whose realtime quality ceiling is far above software VP9 — the residual smearing came from there. Bitrate cap raised to 50 Mbps (hardware barely notices; the VP9 fallback undershoots regardless). ffmpeg sniffs containers by content, so the .webm temp name keeps working. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVMQ2JhsJ77pGKqcvvFHqc
This commit is contained in:
1 parent
be33fb9e7b
commit
d896a6f4b6
1 file changed
+13
-2
+13
-2
@@ -65,7 +65,18 @@ let recorder = null, recording = false, pendingRecOpts = null, recAutoStop = nul
|
|||||||
let recCanvas = null, recCtx = null, composeRAF = null;
|
let recCanvas = null, recCtx = null, composeRAF = null;
|
||||||
|
|
||||||
function pickMime() {
|
function pickMime() {
|
||||||
const cands = ['video/webm;codecs=vp9,opus', 'video/webm;codecs=vp8,opus', 'video/webm'];
|
// H.264 first: on macOS it runs on the VideoToolbox HARDWARE encoder, whose
|
||||||
|
// realtime quality ceiling is far above software VP9 — the visible smearing
|
||||||
|
// on fast abstract motion came from that first encode. ffmpeg sniffs the
|
||||||
|
// container by content, so the .webm temp extension stays harmless.
|
||||||
|
const cands = [
|
||||||
|
'video/mp4;codecs=avc1.640033,mp4a.40.2',
|
||||||
|
'video/x-matroska;codecs=avc1',
|
||||||
|
'video/webm;codecs=h264,opus',
|
||||||
|
'video/webm;codecs=vp9,opus',
|
||||||
|
'video/webm;codecs=vp8,opus',
|
||||||
|
'video/webm'
|
||||||
|
];
|
||||||
for (const m of cands) if (window.MediaRecorder && MediaRecorder.isTypeSupported(m)) return m;
|
for (const m of cands) if (window.MediaRecorder && MediaRecorder.isTypeSupported(m)) return m;
|
||||||
return 'video/webm';
|
return 'video/webm';
|
||||||
}
|
}
|
||||||
@@ -179,7 +190,7 @@ async function startRecording(opts) {
|
|||||||
// only preserve what survives this first encode.
|
// only preserve what survives this first encode.
|
||||||
recorder = new MediaRecorder(stream, {
|
recorder = new MediaRecorder(stream, {
|
||||||
mimeType: pickMime(),
|
mimeType: pickMime(),
|
||||||
videoBitsPerSecond: 30e6,
|
videoBitsPerSecond: 50e6, // hardware H.264 barely notices; VP9 fallback undershoots anyway
|
||||||
audioBitsPerSecond: 192e3
|
audioBitsPerSecond: 192e3
|
||||||
});
|
});
|
||||||
// Serialise chunk delivery: ondataavailable is async, so without a chain the
|
// Serialise chunk delivery: ondataavailable is async, so without a chain the
|
||||||
|
|||||||
Reference in new issue
Block a user