분류, 패키지 및 저장소 검색

video_trimmer 표지
패키지 상세v5.0.0

video_trimmer

비디오를 자르는 데 사용할 수 있는 플러터 패키지입니다. 이 패키지는 파일 시스템에 자른 비디오 파일을 가져오고, 자르고, 저장하는 것을 지원합니다.

AndroidiOS
30일 다운로드
1.3만
좋아요
505
Pub 점수
150

패키지 설치

flutter pub add video_trimmer

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

모바일 애플리케이션 내에서 비디오를 자르는 데 특화된 플러터 패키지입니다. 사용자는 비디오 파일을 가져와 사용자 지정 시작 및 종료 시간 사이에서 자르고 결과 클립을 디바이스의 파일 시스템에 저장할 수 있습니다. 이 패키지는 안드로이드와 iOS 플랫폼을 모두 지원하며, 앱 내에서 멀티미디어 편집을 원활하게 제공합니다. 외부 서비스에 의존하지 않고 기본적인 비디오 조작이 필요한 애플리케이션에 적합합니다.

사용 사례

  • 사용자가 업로드한 비디오 자르기
  • 긴 녹화에서 짧은 비디오 클립 만들기
  • 소셜 미디어 앱에 영상 편집 기능 통합
  • 공유를 위한 비디오 콘텐츠 준비
  • 튜토리얼 또는 데모 비디오 편집
  • 자르기 후 비디오를 로컬에 저장

주요 기능

  • 장치 저장소에서 비디오 검색
  • 정확한 시간 선택으로 비디오 자르기
  • 자르기된 비디오를 파일 시스템에 저장
  • Android 및 iOS를 지원합니다
  • 간단한 통합용 API
  • 원본 비디오 품질 유지

적합한 대상

  • 비디오 자르기 필요하는 모바일 앱
  • 소셜 미디어 또는 콘텐츠 제작 도구
  • 교육 또는 튜토리얼 앱
  • 사용자 생성 비디오 콘텐츠를 처리하는 앱
  • 다중미디어 편집기를 개발하는 개발자

고려 사항

  • Android 및 iOS에서 파일 시스템 권한이 필요합니다
  • 큰 비디오 파일은 성능에 영향을 줄 수 있습니다
  • 기본 자르기만 가능 (고급 편집 없음)
  • 큰 파일 크기 처리가 필요할 수 있습니다
  • 비디오 처리를 위한 네이티브 플랫폼 기능에 의존합니다

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

Awesome Flutter Pub Version GitHub stars GitHub license

Video Trimmer

A Flutter package for trimming videos

Features
  • Customizable video trimmer.
  • Supports two types of trim viewer, fixed length and scrollable.
  • Video playback control.
  • Retrieving and storing video file.

Also, supports conversion to GIF.

NOTE: Versions 5.0.0 and above uses a native video trimmer without the overhead of FFmpeg. Have a look at the Changelog for breaking changes if you are below version 5.0.0.

Following 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.

Example

The example app running on an iPhone 13 Pro device:

Trimmer

Usage

Add the dependency video_trimmer to your pubspec.yaml file:

For using main version of FFmpeg package:

dependencies:
  video_trimmer: ^5.0.0
Android configuration

No additional configuration is needed for using on Android platform. You are good to go!

iOS configuration
  • Add the following keys to your Info.plist file, located in <project root>/ios/Runner/Info.plist:
    <key>NSCameraUsageDescription</key>
    <string>Used to demonstrate image picker plugin</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>Used to capture audio for image picker plugin</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Used to demonstrate image picker plugin</string>
    

Functionalities

Loading input video file
final Trimmer _trimmer = Trimmer();
await _trimmer.loadVideo(videoFile: file);
Saving trimmed video

Returns a string to indicate whether the saving operation was successful.

await _trimmer
    .saveTrimmedVideo(startValue: _startValue, endValue: _endValue)
    .then((value) => setState(() => _value = value));
Video playback state

Returns the video playback state. If true then the video is playing, otherwise it is paused.

await _trimmer.videoPlaybackControl(
  startValue: _startValue,
  endValue: _endValue,
);

Widgets

Display a video playback area
VideoViewer(trimmer: _trimmer)
Display the video trimmer area
TrimViewer(
  trimmer: _trimmer,
  viewerHeight: 50.0,
  viewerWidth: MediaQuery.of(context).size.width,
  maxVideoLength: const Duration(seconds: 10),
  onChangeStart: (value) => _startValue = value,
  onChangeEnd: (value) => _endValue = value,
  onChangePlaybackState: (value) =>
      setState(() => _isPlaying = value),
)

Example

Before using this example directly in a Flutter app, don't forget to add the video_trimmer & file_picker packages to your pubspec.yaml file.

You can try out this example by replacing the entire content of main.dart file of a newly created Flutter project.

import 'dart:io';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:video_trimmer/video_trimmer.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video Trimmer',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Video Trimmer"),
      ),
      body: Center(
        child: Container(
          child: ElevatedButton(
            child: Text("LOAD VIDEO"),
            onPressed: () async {
              FilePickerResult? result = await FilePicker.platform.pickFiles(
                type: FileType.video,
                allowCompression: false,
              );
              if (result != null) {
                File file = File(result.files.single.path!);
                Navigator.of(context).push(
                  MaterialPageRoute(builder: (context) {
                    return TrimmerView(file);
                  }),
                );
              }
            },
          ),
        ),
      ),
    );
  }
}

class TrimmerView extends StatefulWidget {
  final File file;

  TrimmerView(this.file);

  @override
  _TrimmerViewState createState() => _TrimmerViewState();
}

class _TrimmerViewState extends State<TrimmerView> {
  final Trimmer _trimmer = Trimmer();

  double _startValue = 0.0;
  double _endValue = 0.0;

  bool _isPlaying = false;
  bool _progressVisibility = false;

  Future<String?> _saveVideo() async {
    setState(() {
      _progressVisibility = true;
    });

    String? _value;

    await _trimmer
        .saveTrimmedVideo(startValue: _startValue, endValue: _endValue)
        .then((value) {
      setState(() {
        _progressVisibility = false;
        _value = value;
      });
    });

    return _value;
  }

  void _loadVideo() {
    _trimmer.loadVideo(videoFile: widget.file);
  }

  @override
  void initState() {
    super.initState();

    _loadVideo();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Video Trimmer"),
      ),
      body: Builder(
        builder: (context) => Center(
          child: Container(
            padding: EdgeInsets.only(bottom: 30.0),
            color: Colors.black,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.max,
              children: <Widget>[
                Visibility(
                  visible: _progressVisibility,
                  child: LinearProgressIndicator(
                    backgroundColor: Colors.red,
                  ),
                ),
                ElevatedButton(
                  onPressed: _progressVisibility
                      ? null
                      : () async {
                          _saveVideo().then((outputPath) {
                            print('OUTPUT PATH: $outputPath');
                            final snackBar = SnackBar(
                                content: Text('Video Saved successfully'));
                            ScaffoldMessenger.of(context).showSnackBar(
                              snackBar,
                            );
                          });
                        },
                  child: Text("SAVE"),
                ),
                Expanded(
                  child: VideoViewer(trimmer: _trimmer),
                ),
                Center(
                  child: TrimViewer(
                    trimmer: _trimmer,
                    viewerHeight: 50.0,
                    viewerWidth: MediaQuery.of(context).size.width,
                    maxVideoLength: const Duration(seconds: 10),
                    onChangeStart: (value) => _startValue = value,
                    onChangeEnd: (value) => _endValue = value,
                    onChangePlaybackState: (value) =>
                        setState(() => _isPlaying = value),
                  ),
                ),
                TextButton(
                  child: _isPlaying
                      ? Icon(
                          Icons.pause,
                          size: 80.0,
                          color: Colors.white,
                        )
                      : Icon(
                          Icons.play_arrow,
                          size: 80.0,
                          color: Colors.white,
                        ),
                  onPressed: () async {
                    bool playbackState = await _trimmer.videoPlaybackControl(
                      startValue: _startValue,
                      endValue: _endValue,
                    );
                    setState(() {
                      _isPlaying = playbackState;
                    });
                  },
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

License

Copyright (c) 2025 Souvik Biswas

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

카테고리

의존성

의존성 목록 8 개

소스 저장소

이 패키지를 사용하는 프로젝트