{"id":18223056,"url":"https://github.com/federicocarboni/eloquent-ffmpeg","last_synced_at":"2025-04-03T04:30:32.872Z","repository":{"id":39724301,"uuid":"297385545","full_name":"federicocarboni/eloquent-ffmpeg","owner":"federicocarboni","description":"High-level API for FFmpeg's Command Line Tools","archived":false,"fork":false,"pushed_at":"2023-03-05T12:55:29.000Z","size":21289,"stargazers_count":86,"open_issues_count":11,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-02T06:01:40.182Z","etag":null,"topics":["audio","audio-processing","conversion","ffmpeg","ffmpeg-wrapper","nodejs","pause","streams","video","video-processing"],"latest_commit_sha":null,"homepage":"https://federicocarboni.github.io/eloquent-ffmpeg/api/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/federicocarboni.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-21T15:42:00.000Z","updated_at":"2025-02-11T15:51:12.000Z","dependencies_parsed_at":"2024-06-19T02:42:43.515Z","dependency_job_id":"a6a803eb-7520-4641-acd8-49e21c244543","html_url":"https://github.com/federicocarboni/eloquent-ffmpeg","commit_stats":{"total_commits":624,"total_committers":2,"mean_commits":312.0,"dds":"0.0016025641025640969","last_synced_commit":"d53eea2ff27f6d2f21b049bce13c42757ff62536"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/federicocarboni%2Feloquent-ffmpeg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/federicocarboni%2Feloquent-ffmpeg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/federicocarboni%2Feloquent-ffmpeg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/federicocarboni%2Feloquent-ffmpeg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/federicocarboni","download_url":"https://codeload.github.com/federicocarboni/eloquent-ffmpeg/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246938914,"owners_count":20857916,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio","audio-processing","conversion","ffmpeg","ffmpeg-wrapper","nodejs","pause","streams","video","video-processing"],"created_at":"2024-11-04T00:03:50.682Z","updated_at":"2025-04-03T04:30:32.214Z","avatar_url":"https://github.com/federicocarboni.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Eloquent FFmpeg\n[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/FedericoCarboni/eloquent-ffmpeg.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/FedericoCarboni/eloquent-ffmpeg/context:javascript)\n[![Known Vulnerabilities](https://snyk.io/test/github/FedericoCarboni/eloquent-ffmpeg/badge.svg?targetFile=package.json)](https://snyk.io/test/github/FedericoCarboni/eloquent-ffmpeg?targetFile=package.json)\n[![tests](https://github.com/FedericoCarboni/eloquent-ffmpeg/actions/workflows/tests.yml/badge.svg)](https://github.com/FedericoCarboni/eloquent-ffmpeg/actions/workflows/tests.yml)\n[![Codecov Coverage](https://img.shields.io/codecov/c/github/FedericoCarboni/eloquent-ffmpeg)](https://codecov.io/gh/FedericoCarboni/eloquent-ffmpeg/branch/master)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FFedericoCarboni%2Feloquent-ffmpeg.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FFedericoCarboni%2Feloquent-ffmpeg?ref=badge_shield)\n\nEloquent FFmpeg simplifies interactions with\n[FFmpeg's command line tools](https://ffmpeg.org/) into a simple yet powerful API.\nThis library is fully typed, so in editors such as VS Code, intellisense should help you get started.\nYou may also want to [view the API documentation](https://federicocarboni.github.io/eloquent-ffmpeg/api/globals.html)\nor [`examples/`](https://github.com/FedericoCarboni/eloquent-ffmpeg/tree/master/examples).\n\nIf something is missing or doesn't feel right, feel free to open an issue or a\npull request to change it. This library is still in a very early stage, but\nthere shouldn't be any major breaking changes.\n\n**Only NodeJS 10.x or higher is supported**\n\n## Prerequisites\nEloquent FFmpeg requires a recent version of FFmpeg to be installed. Make sure that ffmpeg and\nffprobe executables are in `PATH`, or use the options `ffmpegPath` and `ffprobePath`.\n\n**GitHub Actions**\n\nTo install FFmpeg on a GitHub Actions' runner use [FedericoCarboni/setup-ffmpeg](https://github.com/FedericoCarboni/setup-ffmpeg).\n\n## Usage\nSince most of Eloquent FFmpeg's methods are asynchronous it is advised to use\n`async-await` to improve readability.\n\nA simple example could use the following:\n\n```ts\n// Create a new command\nconst cmd = ffmpeg({\n  // Include any options here...\n});\n\n// Select input(s)\ncmd.input('input.mkv');\n// ... and output(s)\ncmd.output('output.mp4');\n\n// Spawn ffmpeg as a child process\nconst proc = await cmd.spawn();\n// Wait for the conversion to complete\nawait proc.complete();\n```\n\n### Streams\nStreams can be used as input sources and output destinations, there is no hard\nlimit on how many streams can be used. Pass Node.js streams directly to\n`FFmpegCommand.input()` and `FFmpegCommand.output()`.\n\nExample using Node.js' `fs` module.\n```ts\nconst cmd = ffmpeg();\ncmd.input(fs.createReadStream('input.mkv'));\n// The same output will be written to two destinations.\ncmd.output(fs.createWriteStream('dest1.webm'), 'dest2.webm')\n// When using streams the format must be explicitly specified\n// because it can't be inferred from the file extension.\n  .format('webm');\n\nconst proc = await cmd.spawn();\nawait proc.complete();\n```\n\n**Note:** Some formats require inputs and/or outputs to be seekable which means\nthat they cannot be used with streams, notable example being MP4. Some other\nformats require a special format name to be explicitly set, for example to use\nstreams for GIF files the input format must be `gif_pipe`.\n\nSee [FFmpegCommand.input()](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.ffmpegcommand.html#input) and [FFmpegCommand.output()](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.ffmpegcommand.html#output)\n\n### Concatenate Inputs\nTo concatenate inputs use `FFmpegCommand.concat()`, at the moment it is still unstable.\n\n```ts\nconst cmd = ffmpeg();\ncmd.concat(['file:input1.mkv', 'file:input2.mkv']);\ncmd.output('output.mkv');\n\nconst proc = await cmd.spawn();\nawait proc.complete();\n```\n\n**Note:** When passing inputs to `FFmpegCommand.concat()` the protocol must be explicitly specified:\n`file:` for example; streams are handled automatically. Sometimes it may be necessary to explicitly\nenable certain protocols.\n\n```ts\nconst cmd = ffmpeg();\ncmd.concat(['file:input1.mkv', 'https://example.com/input2.mkv'], {\n  protocols: ['file', 'tcp', 'tls', 'http', 'https'],\n});\ncmd.output('output.mkv');\n\nconst proc = await cmd.spawn();\nawait proc.complete();\n```\n\nSee [FFmpegCommand.concat()](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.ffmpegcommand.html#concat) and [ConcatOptions](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.concatoptions.html).\n\n### Input \u0026 Output Options\n\nEloquent FFmpeg exposes a few methods which act as a shortcut to set a few\noptions. See [FFmpegInput](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.ffmpeginput.html)\nand [FFmpegOutput](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.ffmpegoutput.html)\n\n```ts\nconst cmd = ffmpeg();\ncmd.input('input.mp4')\n  .format('mp4');\ncmd.output('output.mkv')\n  .audioCodec('aac');\n```\n\nTo set input and output options their `.args()` method can also be used.\n\n```ts\nconst cmd = ffmpeg();\ncmd.input('input.mp4')\n  .args('-format', 'mp4');\ncmd.output('output.mkv')\n  .args('-codec:a', 'aac');\n```\n\n### Logging and Debugging\nFor debbugging, [`FFmpegCommand.spawn()`](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.ffmpegcommand.html#spawn)'s [options](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.spawnoptions.html) accept [`logger`](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.spawnoptions.html#logger) and [`report`](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.spawnoptions.html#report).\n\nThe `report` option dumps the full command line arguments and logs to the specified file or, when\nnot specified, FFmpeg will create a file named `ffmpeg-YYYYMMDD-HHMMSS.log` in its current\ndirectory. When the log level is not specified FFmpeg defaults to `LogLevel.Debug`.\n\nSee [`-loglevel` and `-report` in FFmpeg's docs](https://ffmpeg.org/ffmpeg-all.html#Generic-options).\n\n```ts\nconst cmd = ffmpeg({\n  level: LogLevel.Warning,\n});\ncmd.input('input.mkv');\ncmd.output('output.mp4');\n\nconst proc = await cmd.spawn({\n  // Enable logger and report when not in production mode.\n  logger: process.env.NODE_ENV !== 'production' \u0026\u0026 {\n    warning: (message) =\u003e {\n      console.warn('FFmpeg warning:', message);\n    },\n  },\n  report: process.env.NODE_ENV !== 'production' \u0026\u0026 {\n    file: 'ffmpeg-123.log',\n    level: LogLevel.Debug,\n  },\n});\nawait proc.complete();\n```\n\n### Controlling the conversion\nMake sure to check [the API documentation for FFmpegProcess](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.ffmpegprocess.html).\n\n#### Monitor progress\nTo receive real-time updates on the conversion's progress, use the `FFmpegProcess.progress()` method.\nIt returns an async generator of [Progress](https://federicocarboni.github.io/eloquent-ffmpeg/api/interfaces/_src_lib_.progress.html).\n```ts\nconst cmd = ffmpeg();\ncmd.input('input.mkv');\ncmd.output('output.mp4');\nconst proc = await cmd.spawn();\nfor await (const { speed, time } of proc.progress()) {\n  console.log(`Converting @ ${speed}x – ${time}/${TOTAL_TIME}`);\n}\n// NOTE: The progress generator will return when ffmpeg writes a\n// `progress=end` line, which signals the end of progress updates,\n// not the conversion's completion.\n// Use proc.complete() to wait for completion.\nawait proc.complete();\nconsole.log('Hooray! Conversion complete!');\n```\nTo use Node.js' streams, `FFmpegProcess.progress()` can be turned into a Node.js readable stream\nusing `Readable.from()`.\n```ts\nconst cmd = ffmpeg();\ncmd.input('input.mkv');\ncmd.output('output.mp4');\nconst proc = await cmd.spawn();\nconst progress = Readable.from(proc.progress());\nprogress.on('data', ({ speed, time }) =\u003e {\n  console.log(`Converting @ ${speed}x – ${time}/${TOTAL_TIME}`);\n});\nprogress.on('end', () =\u003e {\n  // NOTE: The progress stream will end when ffmpeg writes a\n  // `progress=end` line, which signals the end of progress\n  // updates, not the conversion's completion.\n  console.log('No more progress updates');\n});\n// Use proc.complete() to wait for completion.\nawait proc.complete();\nconsole.log('Hooray! Conversion complete!');\n```\n**Tracking progress as a percentage:** To get a percentage from the progress the total\nduration of the media must be known, this is very easy if the duration is not modified.\n\nProbe the input file and calculate the percentage by dividing the current `time` by the `duration`\nand multiplying by 100.\n\n```ts\nconst cmd = ffmpeg();\nconst input = cmd.input('input.mkv');\nconst info = await input.probe();\ncmd.output('video.mp4');\nconst proc = await cmd.spawn();\nfor await (const { speed, time } of proc.progress()) {\n  console.log(`Converting @ ${speed}x – ${time / info.duration * 100}%`);\n}\nawait proc.complete();\nconsole.log('Hooray! Conversion complete!');\n```\n\n#### Pause and Resume\nThe conversion can be paused and resumed using `FFmpegProcess.pause()`\nand `FFmpegProcess.resume()`. Both methods are synchronous, they return `true`\nupon success, `false` otherwise.\n\n**Note:** On Windows this requires the optional dependency\n[ntsuspend](https://www.npmjs.com/package/ntsuspend) to be installed.\n\n```ts\nconst cmd = ffmpeg();\ncmd.input('input.mkv');\ncmd.output('output.mp4');\nconst proc = await cmd.spawn();\n// Pause the conversion\nproc.pause();\n// Resume...\nproc.resume();\n\nawait proc.complete();\n```\n\n#### Abort\nThe conversion can be terminated early using `FFmpegProcess.abort()`, this\ngracefully interrupts the conversion allowing FFmpeg to end the file correctly.\nThe method is asynchronous.\n\n**Note:** `abort()` resolves when FFmpeg exits, but it doesn't guarantee that it\nwill exit successfully, any possible errors should be handled explicitly.\n\n```ts\nconst cmd = ffmpeg();\ncmd.input('input.mkv');\ncmd.output('output.mp4');\nconst proc = await cmd.spawn();\nawait proc.abort();\n```\n\n## Errors\n### FFmpeg exited with code x\n\u003c!-- https://git.io/JTqA9#ffmpeg-exited-with-code-x --\u003e\nFFmpeg exited with a non-zero status code, which means that the conversion\nfailed. This typically occurs because of a corrupt input or a wrong\nconfiguration. See [Logging and Debugging](#logging-and-debugging).\n\n### FFmpeg exited prematurely\n\u003c!-- https://git.io/JTqA9#ffmpeg-exited-prematurely --\u003e\nFFmpeg exited without a status code. This typically means that the conversion\nwas forcefully terminated (or that an error occurred in a system call).\nSee [Logging and Debugging](#logging-and-debugging).\n\n### Cannot import ntsuspend\n\u003c!-- https://git.io/JTqA9#cannot-import-ntsuspend --\u003e\nThis error is likely caused by a corrupt or missing installation of [ntsuspend](https://www.npmjs.com/package/ntsuspend).\n`ntsuspend` is required to pause and resume the FFmpeg child process on Windows.\nTry to uninstall and reinstall `ntsuspend`, and if you experience further\nproblems open a new issue to get help.\n\n## License\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FFedericoCarboni%2Feloquent-ffmpeg.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FFedericoCarboni%2Feloquent-ffmpeg?ref=badge_large)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffedericocarboni%2Feloquent-ffmpeg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffedericocarboni%2Feloquent-ffmpeg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffedericocarboni%2Feloquent-ffmpeg/lists"}