{"id":13551989,"url":"https://github.com/sbis04/video_trimmer","last_synced_at":"2025-05-15T01:06:25.846Z","repository":{"id":39758729,"uuid":"260117061","full_name":"sbis04/video_trimmer","owner":"sbis04","description":"Flutter video trimmer package","archived":false,"fork":false,"pushed_at":"2025-04-27T09:05:09.000Z","size":23564,"stargazers_count":464,"open_issues_count":36,"forks_count":323,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-27T10:18:47.248Z","etag":null,"topics":["hacktoberfest","video-trimmer"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/video_trimmer","language":"Dart","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/sbis04.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"sbis04","patreon":"souvikbiswas","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":"sbis04","otechie":null,"custom":null}},"created_at":"2020-04-30T04:56:04.000Z","updated_at":"2025-04-27T09:05:13.000Z","dependencies_parsed_at":"2024-10-30T16:02:31.879Z","dependency_job_id":"55bca89f-e113-4cd3-9ad4-7534da29261a","html_url":"https://github.com/sbis04/video_trimmer","commit_stats":{"total_commits":231,"total_committers":6,"mean_commits":38.5,"dds":"0.025974025974025983","last_synced_commit":"208247d1834f3b8639a3ab64dcd6287715f1349b"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbis04%2Fvideo_trimmer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbis04%2Fvideo_trimmer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbis04%2Fvideo_trimmer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbis04%2Fvideo_trimmer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sbis04","download_url":"https://codeload.github.com/sbis04/video_trimmer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254254040,"owners_count":22039792,"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":["hacktoberfest","video-trimmer"],"created_at":"2024-08-01T12:01:57.042Z","updated_at":"2025-05-15T01:06:20.835Z","avatar_url":"https://github.com/sbis04.png","language":"Dart","funding_links":["https://github.com/sponsors/sbis04","https://patreon.com/souvikbiswas","https://issuehunt.io/r/sbis04"],"categories":["组件","Dart","Media [🔝](#readme)","Components"],"sub_categories":["媒体","Media"],"readme":"\u003ca href=\"https://github.com/Solido/awesome-flutter\"\u003e\n   \u003cimg alt=\"Awesome Flutter\" src=\"https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true\u0026style=flat-square\" /\u003e\n\u003c/a\u003e\n\u003ca href=\"https://pub.dev/packages/video_trimmer\"\u003e\n  \u003cimg alt=\"Pub Version\" src=\"https://img.shields.io/pub/v/video_trimmer?style=flat-square\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/sbis04/video_trimmer/stargazers\"\u003e\n  \u003cimg alt=\"GitHub stars\" src=\"https://img.shields.io/github/stars/sbis04/video_trimmer?style=flat-square\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/sbis04/video_trimmer/blob/master/LICENSE\"\u003e\n  \u003cimg alt=\"GitHub license\" src=\"https://img.shields.io/github/license/sbis04/video_trimmer?style=flat-square\"\u003e\n\u003c/a\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/sbis04/video_trimmer/refs/heads/main/screenshots/cover.png\" alt=\"Video Trimmer\" /\u003e\n\u003c/p\u003e\n\n\u003ch4 align=\"center\"\u003eA Flutter package for trimming videos\u003c/h4\u003e\n\n### Features\n\n* Customizable video trimmer.\n* Supports two types of trim viewer, fixed length and scrollable.\n* Video playback control.\n* Retrieving and storing video file.\n\nAlso, supports conversion to **GIF**.\n\n\u003e NOTE: Versions `3.0.0` and above uses the \"Full\" version of Flutter FFmpeg. To install the \"LTS\" version, use the \"x.x.x-LTS\" version of this package.\n\nFollowing image shows the structure of the `TrimViewer`. It consists of the `Duration` on top (displaying the start, end, and scrubber time), `TrimArea` consisting of the thumbnails, and `TrimEditor` which is an overlay that let's you select a portion from the video.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/sbis04/video_trimmer/refs/heads/main/screenshots/trim_preview.png\"/\u003e\n\u003c/p\u003e\n\n## Example\n\nThe [example app](https://github.com/sbis04/video_trimmer/tree/main/example) running on an iPhone 13 Pro device:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/sbis04/video_trimmer/refs/heads/main/screenshots/updated_trimmer_demo.gif\" alt=\"Trimmer\"/\u003e\n\u003c/p\u003e\n\n## Usage\n\nAdd the dependency `video_trimmer` to your **pubspec.yaml** file:\n\nFor using main version of FFmpeg package:\n\n```yaml\ndependencies:\n  video_trimmer: ^4.0.0\n```\n\nFor using LTS version of FFmpeg package:\n\n```yaml\ndependencies:\n  video_trimmer: ^4.0.0-LTS\n```\n\n### Android configuration\n\nNo additional configuration is needed for using on Android platform. You are good to go!\n\n### iOS configuration\n\n* Add the following keys to your **Info.plist** file, located in `\u003cproject root\u003e/ios/Runner/Info.plist`:\n  ```\n  \u003ckey\u003eNSCameraUsageDescription\u003c/key\u003e\n  \u003cstring\u003eUsed to demonstrate image picker plugin\u003c/string\u003e\n  \u003ckey\u003eNSMicrophoneUsageDescription\u003c/key\u003e\n  \u003cstring\u003eUsed to capture audio for image picker plugin\u003c/string\u003e\n  \u003ckey\u003eNSPhotoLibraryUsageDescription\u003c/key\u003e\n  \u003cstring\u003eUsed to demonstrate image picker plugin\u003c/string\u003e\n  ```\n\n## FFmpeg Release\n\nThis package supports both Main and [LTS version](https://github.com/arthenica/ffmpeg-kit/wiki/LTS-Releases) of the FFmpeg implementation.\n\n\u003ctable\u003e\n\u003cthead\u003e\n    \u003ctr\u003e\n        \u003cth align=\"center\"\u003e\u003c/th\u003e\n        \u003cth align=\"center\"\u003eMain Release\u003c/th\u003e\n        \u003cth align=\"center\"\u003eLTS Release\u003c/th\u003e\n    \u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n    \u003ctr\u003e\n        \u003ctd align=\"center\"\u003eAndroid API Level\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e24\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e16\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd align=\"center\"\u003eAndroid Camera Access\u003c/td\u003e\n        \u003ctd align=\"center\"\u003eYes\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e-\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd align=\"center\"\u003eAndroid Architectures\u003c/td\u003e\n        \u003ctd align=\"center\"\u003earm-v7a-neon\u003cbr\u003earm64-v8a\u003cbr\u003ex86\u003cbr\u003ex86-64\u003c/td\u003e\n        \u003ctd align=\"center\"\u003earm-v7a\u003cbr\u003earm-v7a-neon\u003cbr\u003earm64-v8a\u003cbr\u003ex86\u003cbr\u003ex86-64\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd align=\"center\"\u003eiOS Min SDK\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e12.1\u003c/td\u003e\n        \u003ctd align=\"center\"\u003e10\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd align=\"center\"\u003eiOS Architectures\u003c/td\u003e\n        \u003ctd align=\"center\"\u003earm64\u003cbr\u003earm64-simulator\u003cbr\u003earm64-mac-catalyst\u003cbr\u003ex86-64\u003cbr\u003ex86-64-mac-catalyst\u003c/td\u003e\n        \u003ctd align=\"center\"\u003earmv7\u003cbr\u003earm64\u003cbr\u003ei386\u003cbr\u003ex86-64\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n## Functionalities\n\n### Loading input video file\n\n```dart\nfinal Trimmer _trimmer = Trimmer();\nawait _trimmer.loadVideo(videoFile: file);\n```\n\n### Saving trimmed video\n\nReturns a string to indicate whether the saving operation was successful.\n\n```dart\nawait _trimmer\n    .saveTrimmedVideo(startValue: _startValue, endValue: _endValue)\n    .then((value) {\n  setState(() {\n    _value = value;\n  });\n});\n```\n\n### Video playback state \n\nReturns the video playback state. If **true** then the video is playing, otherwise it is paused.\n\n```dart\nawait _trimmer.videoPlaybackControl(\n  startValue: _startValue,\n  endValue: _endValue,\n);\n```\n\n### Advanced Command\n\nYou can use an advanced **FFmpeg** command if you require more customization. Just define your FFmpeg command using the `ffmpegCommand` property and set an output video format using `customVideoFormat`. \n\nRefer to the [Official FFmpeg Documentation](https://ffmpeg.org/documentation.html) for more information.\n\n\u003e **NOTE:** Passing a wrong video format to the `customVideoFormat` property may result in a crash.\n\n```dart\n// Example of defining a custom command\n\n// This is already used for creating GIF by\n// default, so you do not need to use this.\n\nawait _trimmer\n    .saveTrimmedVideo(\n        startValue: _startValue,\n        endValue: _endValue,\n        ffmpegCommand:\n            '-vf \"fps=10,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse\" -loop 0',\n        customVideoFormat: '.gif')\n    .then((value) {\n  setState(() {\n    _value = value;\n  });\n});\n```\n\n## Widgets\n\n### Display a video playback area\n\n```dart\nVideoViewer(trimmer: _trimmer)\n```\n\n### Display the video trimmer area\n\n```dart\nTrimViewer(\n  trimmer: _trimmer,\n  viewerHeight: 50.0,\n  viewerWidth: MediaQuery.of(context).size.width,\n  maxVideoLength: const Duration(seconds: 10),\n  onChangeStart: (value) =\u003e _startValue = value,\n  onChangeEnd: (value) =\u003e _endValue = value,\n  onChangePlaybackState: (value) =\u003e\n      setState(() =\u003e _isPlaying = value),\n)\n```\n\n## Example\n\nBefore using this example directly in a Flutter app, don't forget to add the `video_trimmer` \u0026 `file_picker` packages to your `pubspec.yaml` file.\n\nYou can try out this example by replacing the entire content of `main.dart` file of a newly created Flutter project.\n\n```dart\nimport 'dart:io';\n\nimport 'package:file_picker/file_picker.dart';\nimport 'package:flutter/material.dart';\nimport 'package:video_trimmer/video_trimmer.dart';\n\nvoid main() =\u003e runApp(MyApp());\n\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Video Trimmer',\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: HomePage(),\n    );\n  }\n}\n\nclass HomePage extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Video Trimmer\"),\n      ),\n      body: Center(\n        child: Container(\n          child: ElevatedButton(\n            child: Text(\"LOAD VIDEO\"),\n            onPressed: () async {\n              FilePickerResult? result = await FilePicker.platform.pickFiles(\n                type: FileType.video,\n                allowCompression: false,\n              );\n              if (result != null) {\n                File file = File(result.files.single.path!);\n                Navigator.of(context).push(\n                  MaterialPageRoute(builder: (context) {\n                    return TrimmerView(file);\n                  }),\n                );\n              }\n            },\n          ),\n        ),\n      ),\n    );\n  }\n}\n\nclass TrimmerView extends StatefulWidget {\n  final File file;\n\n  TrimmerView(this.file);\n\n  @override\n  _TrimmerViewState createState() =\u003e _TrimmerViewState();\n}\n\nclass _TrimmerViewState extends State\u003cTrimmerView\u003e {\n  final Trimmer _trimmer = Trimmer();\n\n  double _startValue = 0.0;\n  double _endValue = 0.0;\n\n  bool _isPlaying = false;\n  bool _progressVisibility = false;\n\n  Future\u003cString?\u003e _saveVideo() async {\n    setState(() {\n      _progressVisibility = true;\n    });\n\n    String? _value;\n\n    await _trimmer\n        .saveTrimmedVideo(startValue: _startValue, endValue: _endValue)\n        .then((value) {\n      setState(() {\n        _progressVisibility = false;\n        _value = value;\n      });\n    });\n\n    return _value;\n  }\n\n  void _loadVideo() {\n    _trimmer.loadVideo(videoFile: widget.file);\n  }\n\n  @override\n  void initState() {\n    super.initState();\n\n    _loadVideo();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(\"Video Trimmer\"),\n      ),\n      body: Builder(\n        builder: (context) =\u003e Center(\n          child: Container(\n            padding: EdgeInsets.only(bottom: 30.0),\n            color: Colors.black,\n            child: Column(\n              mainAxisAlignment: MainAxisAlignment.center,\n              mainAxisSize: MainAxisSize.max,\n              children: \u003cWidget\u003e[\n                Visibility(\n                  visible: _progressVisibility,\n                  child: LinearProgressIndicator(\n                    backgroundColor: Colors.red,\n                  ),\n                ),\n                ElevatedButton(\n                  onPressed: _progressVisibility\n                      ? null\n                      : () async {\n                          _saveVideo().then((outputPath) {\n                            print('OUTPUT PATH: $outputPath');\n                            final snackBar = SnackBar(\n                                content: Text('Video Saved successfully'));\n                            ScaffoldMessenger.of(context).showSnackBar(\n                              snackBar,\n                            );\n                          });\n                        },\n                  child: Text(\"SAVE\"),\n                ),\n                Expanded(\n                  child: VideoViewer(trimmer: _trimmer),\n                ),\n                Center(\n                  child: TrimViewer(\n                    trimmer: _trimmer,\n                    viewerHeight: 50.0,\n                    viewerWidth: MediaQuery.of(context).size.width,\n                    maxVideoLength: const Duration(seconds: 10),\n                    onChangeStart: (value) =\u003e _startValue = value,\n                    onChangeEnd: (value) =\u003e _endValue = value,\n                    onChangePlaybackState: (value) =\u003e\n                        setState(() =\u003e _isPlaying = value),\n                  ),\n                ),\n                TextButton(\n                  child: _isPlaying\n                      ? Icon(\n                          Icons.pause,\n                          size: 80.0,\n                          color: Colors.white,\n                        )\n                      : Icon(\n                          Icons.play_arrow,\n                          size: 80.0,\n                          color: Colors.white,\n                        ),\n                  onPressed: () async {\n                    bool playbackState = await _trimmer.videoPlaybackControl(\n                      startValue: _startValue,\n                      endValue: _endValue,\n                    );\n                    setState(() {\n                      _isPlaying = playbackState;\n                    });\n                  },\n                )\n              ],\n            ),\n          ),\n        ),\n      ),\n    );\n  }\n}\n```\n\n## Troubleshooting LTS version\n\nWhile running on the Android platform if it gives an error that the `minSdkVersion` needs to be `24`, or on iOS platform that the Podfile platform version should be `11`, first go to `pubspec.lock` file and see if the version of `ffmpeg_kit_flutter` has `-LTS` suffix. This should fix all issues for iOS platform.\n\nOn Android, if you still face the same issue, try adding the following to the `\u003cproject_directory\u003e/android/app/src/main/AndroidManifest.xml`:\n\n```\n\u003cmanifest xmlns:tools=\"http://schemas.android.com/tools\" ....... \u003e\n    \u003cuses-sdk tools:overrideLibrary=\"com.arthenica.ffmpegkit.flutter, com.arthenica.ffmpegkit\" /\u003e\n\u003c/manifest\u003e\n```\n\n## License\n\nCopyright (c) 2024 Souvik Biswas\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbis04%2Fvideo_trimmer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsbis04%2Fvideo_trimmer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbis04%2Fvideo_trimmer/lists"}