( ffmpegPath: string, encoderName: string, encodingMode: NativeExportEncodingMode, )
| 3888 | } |
| 3889 | |
| 3890 | export async function probeNativeVideoEncoder( |
| 3891 | ffmpegPath: string, |
| 3892 | encoderName: string, |
| 3893 | encodingMode: NativeExportEncodingMode, |
| 3894 | ) { |
| 3895 | const outputPath = path.join( |
| 3896 | app.getPath("temp"), |
| 3897 | `recordly-export-probe-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.mp4`, |
| 3898 | ); |
| 3899 | const args = buildNativeVideoExportArgs( |
| 3900 | encoderName, |
| 3901 | { |
| 3902 | width: 64, |
| 3903 | height: 64, |
| 3904 | frameRate: 1, |
| 3905 | bitrate: 1_500_000, |
| 3906 | encodingMode, |
| 3907 | }, |
| 3908 | outputPath, |
| 3909 | ); |
| 3910 | |
| 3911 | return new Promise<boolean>((resolve) => { |
| 3912 | const process = spawn(ffmpegPath, args, { |
| 3913 | stdio: ["pipe", "ignore", "pipe"], |
| 3914 | }); |
| 3915 | let stderrOutput = ""; |
| 3916 | const timeout = setTimeout(() => { |
| 3917 | try { |
| 3918 | process.kill("SIGKILL"); |
| 3919 | } catch { |
| 3920 | // ignore |
| 3921 | } |
| 3922 | resolve(false); |
| 3923 | }, 15000); |
| 3924 | |
| 3925 | process.stderr.on("data", (chunk: Buffer) => { |
| 3926 | stderrOutput += chunk.toString(); |
| 3927 | }); |
| 3928 | |
| 3929 | process.on("close", (code) => { |
| 3930 | clearTimeout(timeout); |
| 3931 | void removeTemporaryExportFile(outputPath); |
| 3932 | if (code !== 0 && stderrOutput.trim().length > 0) { |
| 3933 | console.warn( |
| 3934 | `[native-export] Encoder probe failed for ${encoderName}:`, |
| 3935 | stderrOutput.trim(), |
| 3936 | ); |
| 3937 | } |
| 3938 | resolve(code === 0); |
| 3939 | }); |
| 3940 | |
| 3941 | process.stdin.end(Buffer.alloc(getNativeVideoInputByteSize(64, 64), 0)); |
| 3942 | }); |
| 3943 | } |
| 3944 | |
| 3945 | export async function resolveNativeVideoEncoder( |
| 3946 | ffmpegPath: string, |
no test coverage detected