diff --git a/desktop/src/main/services/ffmpeg-worker.ts b/desktop/src/main/services/ffmpeg-worker.ts index a5ccf503b9..f14f3fc53f 100644 --- a/desktop/src/main/services/ffmpeg-worker.ts +++ b/desktop/src/main/services/ffmpeg-worker.ts @@ -357,6 +357,18 @@ const ffmpegGenerateHLSPlaylistAndSegments = async ( // - the first line specifies the key URI that is written into the playlist. // - the second line specifies the path to the local file system file from // where ffmpeg should read the key. + // + // [Note: ffmpeg newlines] + // + // Tested on Windows that ffmpeg recognizes these lines correctly. In + // general, ffmpeg tends to expect input and write output the Unix way (\n), + // even when we're running on Windows. + // + // - The ffmetadata and the HLS playlist file generated by ffmpeg uses \n + // separators, even on Windows. + // - The HLS key info file, expected as an input by ffmpeg, works fine when + // \n separated even on Windows. + // const keyInfo = [keyURI, keyPath].join("\n"); // Overview: @@ -491,6 +503,15 @@ const ffmpegGenerateHLSPlaylistAndSegments = async ( // Note: Depending on the size of the input file, this may take long! await execAsyncWorker(commandWithRedirection); + // While ffmpeg uses \n as the line separator in the generated playlist + // file on Windows too, add an extra safety check that should fail the + // HLS generation if this doesn't hold. See: [Note: ffmpeg newlines]. + if (process.platform == "win32") { + const playlistText = await fs.readFile(playlistPath, "utf-8"); + if (playlistText.includes("\r\n")) + throw new Error("Unexpected Windows newlines in playlist"); + } + // Determine the dimensions of the generated video from the stderr // output produced by ffmpeg during the conversion. dimensions = await detectVideoDimensions(stderrPath); @@ -544,10 +565,10 @@ const deletePathIgnoringErrors = async (tempFilePath: string) => { * * Stream #0:1[0x2](und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(progressive), 480x270 [SAR 1:1 DAR 16:9], 539 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default) */ -const videoStreamLineRegex = /Stream #.+: Video:(.+)$/; +const videoStreamLineRegex = /Stream #.+: Video:(.+)\r?\n/; /** {@link videoStreamLineRegex}, but global. */ -const videoStreamLinesRegex = /Stream #.+: Video:(.+)$/g; +const videoStreamLinesRegex = /Stream #.+: Video:(.+)\r?\n/g; /** * A regex that matches " kb/s" preceded by a space. See diff --git a/web/packages/gallery/services/ffmpeg/index.ts b/web/packages/gallery/services/ffmpeg/index.ts index b31f92b80d..8c7817ee4e 100644 --- a/web/packages/gallery/services/ffmpeg/index.ts +++ b/web/packages/gallery/services/ffmpeg/index.ts @@ -184,8 +184,13 @@ const parseFFmpegExtractedMetadata = (ffmpegOutput: Uint8Array) => { // with comments and newlines. // // https://ffmpeg.org/ffmpeg-formats.html#Metadata-2 + // + // On Windows, while I couldn't find it documented anywhere, the generated + // ffmetadata file uses Unix line separators ("\n"). But for the sake of + // extra (albeit possibly unnecessary) safety, handle both \r\n and \n + // separators in the split. See: [Note: ffmpeg newlines] - const lines = new TextDecoder().decode(ffmpegOutput).split("\n"); + const lines = new TextDecoder().decode(ffmpegOutput).split(/\r?\n/); const isPair = (xs: string[]): xs is [string, string] => xs.length == 2; const kvPairs = lines.map((property) => property.split("=")).filter(isPair);