{"id":21942378,"url":"https://github.com/chijete/crafyvideojs","last_synced_at":"2025-03-22T15:26:39.090Z","repository":{"id":265032535,"uuid":"894879919","full_name":"chijete/CrafyVideoJS","owner":"chijete","description":"FAST In-browser javascript MP4 video decode and encode library","archived":false,"fork":false,"pushed_at":"2024-12-10T02:52:03.000Z","size":126,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-27T15:45:55.806Z","etag":null,"topics":["bitrate","fast-video-frame-extraction","h264-avc","h264-decoder","h264-encoder","h264-parser","hardware-acceleration","in-browser-javascript","mp4-files","mp4-video","mp4box","video-editing","video-processing","video-resolution","videocuttool","videodecode","videoencoder","videoencoding","videotrimming","webgl"],"latest_commit_sha":null,"homepage":"https://chijete.github.io/CrafyVideoJS/","language":"JavaScript","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/chijete.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":"2024-11-27T06:59:44.000Z","updated_at":"2024-12-10T02:52:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"0965f9f5-00c3-4bef-8074-c696148bef16","html_url":"https://github.com/chijete/CrafyVideoJS","commit_stats":null,"previous_names":["chijete/crafyvideojs"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chijete%2FCrafyVideoJS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chijete%2FCrafyVideoJS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chijete%2FCrafyVideoJS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chijete%2FCrafyVideoJS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chijete","download_url":"https://codeload.github.com/chijete/CrafyVideoJS/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244976527,"owners_count":20541489,"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":["bitrate","fast-video-frame-extraction","h264-avc","h264-decoder","h264-encoder","h264-parser","hardware-acceleration","in-browser-javascript","mp4-files","mp4-video","mp4box","video-editing","video-processing","video-resolution","videocuttool","videodecode","videoencoder","videoencoding","videotrimming","webgl"],"created_at":"2024-11-29T03:19:34.775Z","updated_at":"2025-03-22T15:26:39.068Z","avatar_url":"https://github.com/chijete.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CrafyVideoJS\n\n**CrafyVideoJS** is a lightweight, hardware-accelerated (GPU) client-side JavaScript library for manipulating, decoding, and encoding MP4 H.264 (AVC) videos directly in the browser. By leveraging the browser's `VideoEncoder` and `VideoDecoder` APIs combined with [mp4box.js](https://github.com/gpac/mp4box.js \"mp4box.js\"), this library provides fast and efficient video processing without requiring server-side support.\n\n## Features\n\n- ✂️ **Cut videos**: Trim a video to a specific start and end time.\n- ⚙️ **Adjust bitrate**: Modify the output video's bitrate.\n- 🎥 **Change resolution**: Resize videos while maintaining aspect ratio.\n- ℹ️ **Video info extraction**: Retrieve metadata and structural information.\n- 🛠️ **Decode and encode**: Perform decoding and encoding of both video and audio tracks.\n\n## Installation\n\n**Requirement:** [mp4box.js](https://github.com/gpac/mp4box.js \"mp4box.js\") library. \n\nYou can use the file hosted in this repository:\n\n```html\n\u003cscript src=\"MP4Box_minified.js\"\u003e\u003c/script\u003e\n```\n\nSimply include the library in your project:\n\n```html\n\u003cscript src=\"CrafyVideoJS.js\"\u003e\u003c/script\u003e\n```\n\nFor production environments, use the minified version:\n\n```html\n\u003cscript src=\"CrafyVideoJS_minified.js\"\u003e\u003c/script\u003e\n```\n\n**Note:** It only works in modern browsers that support [VideoEncoder](https://developer.mozilla.org/en-US/docs/Web/API/VideoEncoder/ \"VideoEncoder\") and [VideoDecoder](https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder/ \"VideoDecoder\").\n\n## Live Demo\n\nCheck out the [online demo](https://chijete.github.io/CrafyVideoJS/) to see CrafyVideoJS in action!\n\n---\n\n## Documentation\n\n### Example of use\n\n```javascript\nvar CrafyVideoJS_instance = new CrafyVideoJS();\n\n// Input video must be MP4 H.264 (avc) or MP4 H.265 (hvc)\nfunction onInputFileChange(file) {\n\tvar reader = new FileReader();\n\treader.onload = function () {\n\t\tCrafyVideoJS_instance.onProgress = function (progressData) {\n\t\t\tconsole.log(\"ETA in ms:\", progressData['video']['eta']);\n\t\t};\n\t\tCrafyVideoJS_instance.onResult = function (result) {\n\t\t\tconsole.log(\"Link to output video:\", URL.createObjectURL(new Blob([result['video_array_buffer']], { type: \"video/mp4\" })));\n\t\t};\n\t\tCrafyVideoJS_instance.onError = function (error) {\n      console.error(\"Error:\", error);\n    };\n    // Video compression example, setting max bitrate and max resolution (720p):\n\t\tCrafyVideoJS_instance.processVideo({\n\t\t\tfile: this.result,\n\t\t\tmax_video_bitrate: 1_500_000,\n\t\t\tmax_video_resolution: 1280\n\t\t});\n\t};\n\treader.readAsArrayBuffer(file);\n}\n```\n\n### `CrafyVideoJS.onProgress`\n\nThis **event** is fired every time a sample is decoded or encoded.\n\n#### Object as parameter\n\n```json\n{\n  \"video\": {\n    \"decoding\": {\n      \"index\": 11,\n      \"count\": 1000,\n      \"percentage\": 1,\n      \"percentage_original\": 1.1,\n      \"eta\": 11.5236\n    },\n    \"encoding\": {\n      \"index\": 11,\n      \"count\": 1000,\n      \"percentage\": 1,\n      \"percentage_original\": 1.1,\n      \"eta\": 9.5235\n    },\n    \"eta\": 12.123456\n  },\n  \"audio\": {\n    \"decoding\": {\n      \"index\": 11,\n      \"count\": 1000,\n      \"percentage\": 1,\n      \"percentage_original\": 1.1\n    },\n    \"encoding\": {\n      \"index\": 11,\n      \"count\": 1000,\n      \"percentage\": 1,\n      \"percentage_original\": 1.1\n    }\n  }\n}\n```\n\n- `\"count\"` is the total number of samples.\n- `\"index\"` is the index of the last sample processed.\n- `\"percentage\"` is rounded.\n- `\"eta\"` is in miliseconds.\n\n### `CrafyVideoJS.onResult`\n\nThis **event** is triggered when the encoding of the output video finishes successfully.\n\n#### Object as parameter\n\n| Key                            | Type                 | Description                            |\n|--------------------------------|----------------------|----------------------------------------|\n| `video_array_buffer`           | `ArrayBuffer`        | Output video as an `ArrayBuffer`.      |\n| `reencoding_time_seconds`      | `float`              | Total processing time in seconds.      |\n| `reencoding_video_frames`      | `int`                | Total number of encoded video samples.      |\n| `reencoding_video_fps`         | `int`                | Average number of encoded video samples per second.      |\n| `reencoding_audio_frames`      | `int`                | Total number of encoded audio samples.      |\n| `reencoding_audio_fps`         | `int`                | Average number of encoded audio samples per second.      |\n\n### `CrafyVideoJS.onError`\n\nThis **event** is triggered when a fatal error occurs, that is, processing stops completely due to a problem.\n\n#### Parameters\n\n| Parameter         | Type          | Description                           |\n|-------------------|---------------|---------------------------------------|\n| `error`           | `error`       | Error info                            |\n\n### `CrafyVideoJS.processVideo(options)`\n\nThis is the main function to load a video as an `ArrayBuffer`, decode it, apply transformations, and re-encode it.\n\n#### Parameters\n\n| Parameter                         | Type          | Default         | Description                                                                                                       |\n|-----------------------------------|---------------|-----------------|-------------------------------------------------------------------------------------------------------------------|\n| `file`                            | `ArrayBuffer` | **Required**    | Input video file as an `ArrayBuffer`.                                                                             |\n| `start_timestamp`                 | `int`         | `false`         | (Optional) Start trimming the video from this timestamp (in microseconds).                                        |\n| `end_timestamp`                   | `int`         | `false`         | (Optional) Trim the video up to this timestamp (in microseconds).                                                 |\n| `max_video_bitrate`               | `int`         | `false`         | (Optional) Set the maximum output video bitrate (in bits). If the bitrate of the input video is lower, it will not be modified.                                                        |\n| `max_video_resolution`            | `int`         | `false`         | (Optional) Defines the longest edge of the output video in pixels (example: 1920 for 1080p, 1280 for 720p, etc). If the video resolution is lower, it will not be modified.  |\n| `queue_max_size`                  | `int`         | `10`            | (Optional) Maximum number of video frames in the processing queue. (A larger number will increase parallel graphics calculations and provide a slight speed improvement, but may cause a bottleneck. A value greater than 15 is not recommended.)                                                       |\n| `redimension_system`              | `string`      | `'bitmap'`      | (Optional) Video resizing method: `\"webgl\"` or `\"bitmap\"`. (`\"bitmap\"` is the recommended option). [reference](https://developer.mozilla.org/es/docs/Web/API/Window/createImageBitmap \"reference\")                |\n| `encoder_latencyMode`             | `string`      | `'quality'`     | (Optional) Encoder latency mode: `\"quality\"` or `\"realtime\"`. [reference](https://developer.mozilla.org/en-US/docs/Web/API/VideoEncoder/configure#latencymode \"reference\")                                                     |\n| `video_info_read_max_time`        | `int`         | `60000`         | (Optional) Maximum time (in milliseconds) to retrieve input video information. If this time limit is exceeded, an error is returned.                                          |\n| `redimension_resizeQuality`       | `string`      | `'low'`         | (Optional) Resize quality: `\"pixelated\"`, `\"low\"`, `\"medium\"`, or `\"high\"`. [reference](https://developer.mozilla.org/es/docs/Web/API/Window/createImageBitmap#options \"reference\")                                       |\n| `max_input_video_size`            | `int`         | `false`         | (Optional) Maximum input video file size in bytes. If the input video exceeds this size, an error is returned.                                                                |\n| `max_input_video_samplesCount`    | `int`         | `false`         | (Optional) Maximum number of video samples in the input. If the input video exceeds this number of samples, an error is returned. `Number of samples = Duration in seconds * FPS`                                                           |\n| `preprocess_video_info_function`  | `function`    | `false`         | (Optional) Async function to preprocess the input video metadata and dynamically modify the method parameters.           |\n| `audio_queue_max_size`  | `int`    | `20`         | (Optional) Maximum number of audio frames in the processing queue. (A larger number will increase parallel graphics calculations and provide a slight speed improvement, but may cause a bottleneck. A value greater than 30 is not recommended.)           |\n\n##### `file`\n\nAllowed formats and codecs:\n\n- MP4\n  - Video codec:\n    - H.264 (AVC)\n    - H.265 (HVC)\n  - Audio codec:\n    - mp4a\n    - Opus\n\n##### `max_video_bitrate`\n\nFixed maximum.\n\n```javascript\nCrafyVideoJS_instance.processVideo({\n  max_video_bitrate: 1_500_000 // Fixed int.\n});\n```\n\nInput video bitrate percentage.\n\n```javascript\nCrafyVideoJS_instance.processVideo({\n  max_video_bitrate: {\n    \"type\": \"percentage_of_original\",\n    \"percentage\": 50\n  }\n});\n```\n\nFixed maximum based on closest resolution to output video resolution.\n\n```javascript\nCrafyVideoJS_instance.processVideo({\n  max_video_bitrate: {\n    \"type\": \"max_by_resolution\",\n    \"data\": {\n      // (Total resolution = Video width * Video height): Max bitrate\n      2073600: 5_000_000, // 1080p, 5mbps\n      921600: 1_000_000, // 720p, 1mbps\n      307200: 300_000 // 480p, 300kbps\n    }\n  }\n});\n```\n\nPercentage of input video bitrate based on closest resolution to output video resolution.\n\n```javascript\nCrafyVideoJS_instance.processVideo({\n  max_video_bitrate: {\n    \"type\": \"percentage_of_original_by_resolution\",\n    \"data\": {\n      // (Total resolution = Video width * Video height): Percentage of input video bitrate\n      2073600: 50, // 1080p, 50%\n      921600: 40, // 720p, 40%\n      307200: 30 // 480p, 30%\n    }\n  }\n});\n```\n\nPercentage of input video bitrate based on closest resolution to output video resolution, combined with a fixed maximum.\n\n```javascript\nCrafyVideoJS_instance.processVideo({\n  max_video_bitrate: {\n    \"type\": \"percentage_and_max_of_original_by_resolution\",\n    \"data\": {\n      // (Total resolution = Video width * Video height): {percentage, max}\n      2073600: {\n        \"percentage\": 50,\n        \"max\": 5_000_000\n      },\n      921600: {\n        \"percentage\": 40,\n        \"max\": 1_000_000\n      },\n      307200: {\n        \"percentage\": 30,\n        \"max\": 300_000\n      }\n    }\n  }\n});\n```\n\n##### `max_video_resolution`\n\nFixed maximum.\n\n```javascript\nCrafyVideoJS_instance.processVideo({\n  max_video_resolution: 1920 // 1080p\n});\n```\n\nFixed maximum based on closest number of samples to number of samples from the input video.\n\n```javascript\nCrafyVideoJS_instance.processVideo({\n  max_video_resolution: {\n    \"type\": \"by_near_samplesCount\",\n    \"data\": {\n      // (Number of samples = Video seconds duration * Video FPS): Max resolution\n      1200: 1920, // 1080p\n      30000: 1280 // 720p\n    }\n  }\n});\n```\n\nFixed maximum based on a maximum number of samples from the input video.\n\n```javascript\nCrafyVideoJS_instance.processVideo({\n  max_video_resolution: {\n    \"type\": \"by_max_samplesCount\",\n    \"data\": {\n      // (Number of samples = Video seconds duration * Video FPS): Max resolution\n      1200: 1920,\n      30000: 1280,\n      0: 640 // 0 is used when the number of samples in the input video is greater than all the maximums set.\n    }\n  }\n});\n```\n\n##### `preprocess_video_info_function`\n\nIf set, this function will be called after reading the input video data and will wait for your response to continue.\n\nThe function will receive the input video information as a parameter, and must respond with an object that has the same structure as the one used as options in `CrafyVideoJS.processVideo(options)`.\n\nThis feature allows fine-grained control over configuration parameters for video processing based on input video information.\n\nExample:\n\n```javascript\nCrafyVideoJS_instance.processVideo({\n  preprocess_video_info_function: async function (video_info) {\n    // Process video_info (mp4box file).\n    return {\n      redimension_resizeQuality: \"high\"\n    };\n  }\n});\n```\n\n---\n\n## Comparison with FFmpeg WASM\n\n[ffmpeg.wasm](https://github.com/ffmpegwasm/ffmpeg.wasm \"ffmpeg.wasm\")\n\n| Feature                   | **CrafyVideoJS**                              | **FFmpeg WASM**                             |\n|---------------------------|-----------------------------------------------|---------------------------------------------|\n| **Performance**           | Very fast (hardware-accelerated via GPU).     | Slow (WebAssembly is CPU-only).             |\n| **Browser Compatibility** | Modern browsers supporting `VideoEncoder` and `VideoDecoder` (no Firefox support yet). | Works in most browsers, including Firefox. |\n| **Formats/Codecs**        | Video input: MP4 (H.264/AVC), MP4 (H.265/HVC). Video output: MP4 (H.264/AVC) only.                         | Wide range of formats and codecs.           |\n| **Use Case**              | Ideal for MP4 H.264-focused applications requiring efficiency. | Flexible for various video processing tasks.|\n\n**Note:** CrafyVideoJS plans to support additional codecs and formats in future releases.\n\n---\n\n## Contributing\n\nWe welcome contributions to improve CrafyVideoJS! Here's how you can help:\n\n- **Major Changes**: Fork the repository, create a branch, implement your changes, and submit a pull request.\n- **Bug Reports \u0026 Feature Requests**: Open an issue with as much detail as possible, including error messages and steps to reproduce (if applicable).\n- **Small Fixes**: Feel free to directly submit issues or pull requests for minor changes.\n\n---\n\n## Credits and thanks\n\n- [mp4-h264-re-encode](https://github.com/vjeux/mp4-h264-re-encode)\n- [mp4box.js](https://github.com/gpac/mp4box.js)\n- [chatgpt](https://chatgpt.com/)\n- [claude](https://claude.ai/)\n\n---\n\n## License\n\nCrafyVideoJS is licensed under the MIT License. See the `LICENSE` file for more details.\n\n---\n\nHappy coding! 🚀\n\nMade with 💙 by [Crafy Holding](https://chijete.com/ \"Crafy Holding\").","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchijete%2Fcrafyvideojs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchijete%2Fcrafyvideojs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchijete%2Fcrafyvideojs/lists"}