Since 0.9.0, tab recording (recording.start) fails on my machine in two independent ways. 0.8.0 (which used chrome.tabCapture) worked.
Environment
- playwriter CLI 0.9.0, extension 0.0.170
- Linux x64 (Ubuntu 22.04), Node 24
- ffmpeg 4.4.2 (distro package)
- NVIDIA T1000, driver 550.120
1. ffmpeg segfaults with h264_nvenc when the input frame aspect ratio changes
For MP4 output the recorder picks the encoder from detectEncoder(), which chooses h264_nvenc here. Recording fails with:
Error: ffmpeg exited with SIGSEGVI can reproduce it without Chrome. Two MJPEG frames whose aspect ratio differs (1920x992, then 1440x810), piped into the same arguments the recorder builds:
ffmpeg -hide_banner -loglevel error -nostdin -f image2pipe -c:v mjpeg \
-framerate 30 -thread_queue_size 512 -i two-frames.mjpeg \
-vf 'scale=1920:992:force_original_aspect_ratio=decrease,pad=1920:992:(ow-iw)/2:(oh-ih)/2,format=yuv420p' \
-c:v h264_nvenc -b:v 5714k -movflags +faststart -y out.mp4| Input | h264_nvenc | libx264 |
|---|---|---|
| Constant 1920x992 | OK | OK |
| 1920x992 then 960x496 (same aspect) | OK | OK |
| 1920x992 then 1440x810 (aspect changes) | SIGSEGV | OK |
Aspect change with -reinit_filter 0 | SIGSEGV | not tested |
gdb puts the top frames inside libnvidia-encode.so, called from avcodec_send_frame. The kernel log shows the live recording crash and the reproduction crashing at the same offset. So it may be an NVIDIA or ffmpeg 4.4 bug, but the recorder is what sends it frames that change size. The single-frame probe in detectEncoder() cannot catch this.
2. The first screenshot can time out before ffmpeg starts
Separately, recording.start sometimes fails before ffmpeg is spawned:
cdpSession.send: Protocol error (Page.captureScreenshot):
Extension request timeout after 30000ms: forwardCDPCommandThe stack is PageCapture.start → ScreenRecording.start → recording.start, on the initial Page.captureScreenshot. Raising the CLI --timeout does not help, because the 30 s limit is inside the extension. If I call Page.startScreencast on the same CDP session first, the screenshot returns in about 3 s. That worked in 5 of 5 recordings.
Workaround
There is no codec option on recording.start, and no env override. I work around both problems by using the exported PageCapture with a buildArgs callback that calls buildRecordingFfmpegArgs({ ..., codec: 'libx264' }), and by starting the screencast before recording.
Suggestions
- Let
recording.startaccept a codec (or honour an env var), or fall back tolibx264when the hardware encoder exits abnormally. - Or keep the output size constant before encoding, so the encoder never sees a change in input size or aspect.
- Start the screencast before taking the first screenshot, or don't block on that screenshot.
Activity
2Follow-up on the NVENC crash. The trigger is a change in the sample aspect ratio (SAR), not the frame size:
- What
scale+paddoes: when the input aspect ratio changes,scale=…:force_original_aspect_ratio=decrease,pad=…keeps the output at 1920x992 but rewrites the frame's SAR. Withshowinfo, frame 0 hassar:22351/22350and frame 1 hassar:51088/46935. - What ffmpeg then does: ffmpeg passes the new SAR to the encoder.
h264_nvencsees a DAR change (aspect ratio change (DAR): 1442:745 -> 6592:3129at-loglevel verbose) and callsnvEncReconfigureEncoder()mid-stream (libavcodec/nvenc.c,reconfig_encoder()). That's where it segfaults on driver 550.120. The same code is still in ffmpeg master, so a newer ffmpeg likely won't help. - The fix: add
setsar=1to the end of the recording filter, as below. With the two-frame repro: 3/3 crashes without it, 3/3 clean runs with it. A constant non-1 SAR (setsar=4/3) also passes, so the trigger is the change in SAR, not its value.
scale=W:H:force_original_aspect_ratio=decrease,pad=W:H:(ow-iw)/2:(oh-ih)/2,format=yuv420p,setsar=1
Both issues come from 323854137ead34345079ba1a148f12217eb040fd ("feat: record and stream via CDP screencast + ffmpeg, no extension click"):
detectEncoder()(screen-recording.ts,const codec = extension === '.webm' ? 'libvpx' : (await detectEncoder()).codec). Before,detectEncoder()was only used for streaming.PageCapture.startnow takes a firstPage.captureScreenshot("Static pages never paint, so Chrome sends no screencast frame. Seed one.").