{"id":13426053,"url":"https://github.com/transitive-bullshit/ffmpeg-concat","last_synced_at":"2025-05-14T05:11:46.251Z","repository":{"id":31504983,"uuid":"128102393","full_name":"transitive-bullshit/ffmpeg-concat","owner":"transitive-bullshit","description":"Concats a list of videos together using ffmpeg with sexy OpenGL transitions.","archived":false,"fork":false,"pushed_at":"2025-03-28T22:22:15.000Z","size":12135,"stargazers_count":935,"open_issues_count":51,"forks_count":117,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-05-11T22:03:45.751Z","etag":null,"topics":["ffmpeg","fluent-ffmpeg","opengl","transition"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/transitive-bullshit.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2018-04-04T18:15:11.000Z","updated_at":"2025-04-24T13:54:26.000Z","dependencies_parsed_at":"2024-01-03T02:24:25.364Z","dependency_job_id":"56dac11d-917e-48ab-9f2c-eee0711e0e1a","html_url":"https://github.com/transitive-bullshit/ffmpeg-concat","commit_stats":{"total_commits":70,"total_committers":6,"mean_commits":"11.666666666666666","dds":"0.15714285714285714","last_synced_commit":"e52fd02f9faae86da0ef638319460692b720e0ec"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Fffmpeg-concat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Fffmpeg-concat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Fffmpeg-concat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Fffmpeg-concat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/transitive-bullshit","download_url":"https://codeload.github.com/transitive-bullshit/ffmpeg-concat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254076850,"owners_count":22010611,"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":["ffmpeg","fluent-ffmpeg","opengl","transition"],"created_at":"2024-07-31T00:01:25.299Z","updated_at":"2025-05-14T05:11:41.227Z","avatar_url":"https://github.com/transitive-bullshit.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","HarmonyOS","General Tools"],"sub_categories":["Windows Manager","Comparative Analysis of Codecs"],"readme":"# ffmpeg-concat\n\n\u003e Concats a list of videos together using ffmpeg with sexy OpenGL transitions.\n\n[![NPM](https://img.shields.io/npm/v/ffmpeg-concat.svg)](https://www.npmjs.com/package/ffmpeg-concat) [![Build Status](https://travis-ci.com/transitive-bullshit/ffmpeg-concat.svg?branch=master)](https://travis-ci.com/transitive-bullshit/ffmpeg-concat) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n\n![](https://raw.githubusercontent.com/transitive-bullshit/ffmpeg-concat/master/media/example.gif)\n\n*(example of 9 videos concatenated together with unique transitions)*\n\n*(note that the quality and fps is only poor due to the GIF preview; [here](https://raw.githubusercontent.com/transitive-bullshit/ffmpeg-concat/master/media/example.mp4) is the original)*\n\n- [![china](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **中文/Chinese**](https://github.com/transitive-bullshit/ffmpeg-concat/blob/master/readme.zh.md)\n\n## Intro\n\n[FFmpeg](http://ffmpeg.org/) is the de facto standard in command-line video editing, but it is really difficult to concatenate videos together using non-trivial transitions. Here are some [convoluted](https://superuser.com/questions/778762/crossfade-between-2-videos-using-ffmpeg) [examples](https://video.stackexchange.com/questions/17502/concate-two-video-file-with-fade-effect-with-ffmpeg-in-linux) of a simple cross-fade between two videos. FFmpeg filter graphs are extremely powerful, but for implementing transitions, they are just too complicated and error-prone.\n\n[GL Transitions](https://gl-transitions.com/), on the other hand, is a great open source initiative spearheaded by [Gaëtan Renaudeau](https://github.com/gre) that is aimed at using GLSL to establish a universal [collection](https://gl-transitions.com/gallery) of transitions. Its extremely simple spec makes it really easy to customize existing transitions or write your own as opposed to struggling with complex ffmpeg filter graphs.\n\n**This module and CLI make it easy to concat videos together using gl-transitions.**\n\n## Install\n\nThis module requires [ffmpeg](http://ffmpeg.org/) to be installed.\n\n```bash\nnpm install --save ffmpeg-concat\n\n# or if you want to use the CLI\nnpm install -g ffmpeg-concat\n```\n\nThis package runs on Linux, macOS, and Windows.\n\nNode.js versions 10.13.0 and up are supported. Note (**macOS only**): due to an inadvertant low-level breaking change in libuv's process handling code, OpenGL [is not supported](https://github.com/stackgl/headless-gl#supported-platforms-and-nodejs-versions) when running Node.js version 12.13.1 through to 13.6.0 on macOS. A fix has been released in Node.js version 13.7.0. A fix for 12.x is pending. Other platforms are unaffected.\n\n## CLI\n\n```sh\n  Usage: ffmpeg-concat [options] \u003cvideos...\u003e\n\n  Options:\n\n    -V, --version                         output the version number\n    -o, --output \u003coutput\u003e                 path to mp4 file to write (default: out.mp4)\n    -t, --transition-name \u003cname\u003e          name of gl-transition to use (default: fade)\n    -d, --transition-duration \u003cduration\u003e  duration of transition to use in ms (default: 500)\n    -T, --transitions \u003cfile\u003e              json file to load transitions from\n    -f, --frame-format \u003cformat\u003e           format to use for temp frame images (default: raw)\n    -c, --concurrency \u003cnumber\u003e            number of videos to process in parallel (default: 4)\n    -C, --no-cleanup-frames               disables cleaning up temp frame images\n    -O, --temp-dir \u003cdir\u003e                  temporary working directory to store frame data\n    -v, --verbose                         enable verbose logging from FFmpeg\n    -h, --help                            output usage information\n\n  Example:\n\n    ffmpeg-concat -t circleopen -d 750 -o huzzah.mp4 0.mp4 1.mp4 2.mp4\n```\n\n## Usage\n\n```js\nconst concat = require('ffmpeg-concat')\n\n// concat 3 mp4s together using 2 500ms directionalWipe transitions\nawait concat({\n  output: 'test.mp4',\n  videos: [\n    'media/0.mp4',\n    'media/1.mp4',\n    'media/2.mp4'\n  ],\n  transition: {\n    name: 'directionalWipe',\n    duration: 500\n  }\n})\n```\n\n```js\n// concat 5 mp4s together using 4 different transitions\nawait concat({\n  output: 'test.mp4',\n  videos: [\n    'media/0.mp4',\n    'media/1.mp4',\n    'media/2.mp4',\n    'media/0.mp4',\n    'media/1.mp4'\n  ],\n  transitions: [\n    {\n      name: 'circleOpen',\n      duration: 1000\n    },\n    {\n      name: 'crossWarp',\n      duration: 800\n    },\n    {\n      name: 'directionalWarp',\n      duration: 500,\n      // pass custom params to a transition\n      params: { direction: [ 1, -1 ] }\n    },\n    {\n      name: 'squaresWire',\n      duration: 2000\n    }\n  ]\n})\n```\n\n## API\n\n### concat(options)\n\nConcatenates video files together along with OpenGL transitions. Returns a `Promise` for when the output video has been written.\n\nNote that you must specify `videos`, `output`, and either `transition` or `transitions`.\n\nNote that the output video's size and fps are determined by the first input video.\n\n#### options\n\n##### videos\n\nType: `Array\u003cString\u003e`\n**Required**\n\nArray of videos to concat, where each item is a path or URL to a video file.\n\n##### output\n\nType: `String`\n**Required**\n\nPath to an `mp4` video file to write.\n\nNote: we currently only support outputting to mp4; please open an issue if you'd like to see support for more formats.\n\n##### transition\n\nType: `Object`\n\nSpecifies a default transition to be used between each video.\n\nNote that you must specify either `transition` or `transitions`, depending on how much control you want over each transition. If you specify both, `transitions` takes precedence.\n\n```js\n// example\nconst transition = {\n  duration: 1000, // ms\n  name: 'directionalwipe', // gl-transition name to use (will match with lower-casing)\n  params: { direction: [1, -1] } // optionally override default parameters\n}\n```\n\n##### transitions\n\nType: `Array\u003cObject\u003e`\n\nSpecifies a (possibly unique) transition between each video. If there are N videos, then there should be N - 1 transitions.\n\nNote that you must specify either `transition` or `transitions`, depending on how much control you want over each transition. If you specify both, `transitions` takes precedence.\n\n```js\n// example\nconst transitions = [\n  {\n    duration: 1000,\n    name: 'fade'\n  },\n  {\n    duration: 500,\n    name: 'swap'\n  }\n]\n```\n\n##### audio\n\nType: `String`\n**Optional**\n\nPath or URL to an audio file to use as the audio track for the output video.\n\nif parameter is not provided - assuming user wants to concat the source scenes audio.\n\n##### args\n\nType: `Array\u003cString\u003e`\n**Optional**\n\nDefault: `['-c:v', 'libx264', '-profile:v', 'main', '-preset', 'medium', '-crf 20', '-movflags', 'faststart']`\n\nArray of output-only ffmpeg command line arguments for the final video.\n\n##### frameFormat\n\nType: `string`\nDefault: `raw`\n\nThe format for temporary frame images. You may, for example, use `png` or `jpg`.\n\nNote: the default is `raw` for performance reasons, as writing and reading raw binary pixel data is much faster than encoding and decoding `png` frames. Raw format is difficult to preview and debug, however, in which case you may want to change `frameFormat` to `png`.\n\n##### concurrency\n\nType: `Number`\nDefault: `4`\n\nMax number of videos to process in parallel.\n\n##### log\n\nType: `Function`\nDefault: `noop`\n\nOptional function to log progress and the underlying ffmpeg commands. You may, for example, use `console.log`\n\n##### cleanupFrames\n\nType: `boolean`\nDefault: `true`\n\nBy default, we cleanup temporary frame images. Set this to `false` if you need to debug intermediate results.\n\n##### tempDir\n\nType: `string`\nDefault: random  directory in `/tmp`\n\nThe temporary working directory to store intermediate frame data. This is where the frames in `cleanupFrames` will be saved.\n\n## Transitions\n\nHere are some [gl-transitions](https://gl-transitions.com/) that I've found particularly useful for quality video transitions:\n\n- [fade](https://gl-transitions.com/editor/fade)\n- [fadegrayscale](https://gl-transitions.com/editor/fadegrayscale)\n- [circleopen](https://gl-transitions.com/editor/circleopen)\n- [directionalwarp](https://gl-transitions.com/editor/directionalwarp)\n- [directionalwipe](https://gl-transitions.com/editor/directionalwipe)\n- [crosswarp](https://gl-transitions.com/editor/crosswarp)\n- [crosszoom](https://gl-transitions.com/editor/CrossZoom)\n- [dreamy](https://gl-transitions.com/editor/Dreamy)\n- [squareswire](https://gl-transitions.com/editor/squareswire)\n- [angular](https://gl-transitions.com/editor/angular)\n- [radial](https://gl-transitions.com/editor/Radial)\n- [cube](https://gl-transitions.com/editor/cube)\n- [swap](https://gl-transitions.com/editor/swap)\n\n## Related\n\n- [ffmpeg-gl-transition](https://github.com/transitive-bullshit/ffmpeg-gl-transition) - Low-level ffmpeg filter for applying GLSL transitions between video streams ([gl-transitions](https://gl-transitions.com/)). It allows the use of more advanced and customizable filter graphs, but it requires you to build a custom version of ffmpeg.\n- [gl-transitions](https://gl-transitions.com/) - Collection of GLSL transitions.\n- [fluent-ffmpeg](https://github.com/fluent-ffmpeg/node-fluent-ffmpeg) - Underlying ffmpeg wrapper library.\n- [awesome-ffmpeg](https://github.com/transitive-bullshit/awesome-ffmpeg) - A curated list of awesome ffmpeg resources with a focus on JavaScript.\n\n## License\n\nMIT © [Travis Fischer](https://github.com/transitive-bullshit)\n\nSupport my OSS work by \u003ca href=\"https://twitter.com/transitive_bs\"\u003efollowing me on twitter \u003cimg src=\"https://storage.googleapis.com/saasify-assets/twitter-logo.svg\" alt=\"twitter\" height=\"24px\" align=\"center\"\u003e\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransitive-bullshit%2Fffmpeg-concat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftransitive-bullshit%2Fffmpeg-concat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransitive-bullshit%2Fffmpeg-concat/lists"}