Flutter视频裁剪插件flutter_video_trimmer的使用

发布于 1周前 作者 phonegap100 来自 Flutter

Flutter视频裁剪插件flutter_video_trimmer的使用

特性

  • 可自定义视频裁剪器。
  • 支持两种类型的裁剪预览器:固定长度和可滚动。
  • 视频播放控制。
  • 获取并存储视频文件。

此外,还支持转换为 GIF

注意:版本 3.0.0 及以上使用了完整的 Flutter FFmpeg。要安装 LTS 版本,请使用此包的 x.x.x-LTS 版本。

以下图片展示了 TrimViewer 的结构。它由顶部的 Duration(显示开始时间、结束时间和滑块时间)、包含缩略图的 TrimArea 和一个允许你从视频中选择部分的 TrimEditor 组成。

Video Trimmer

示例

运行在 iPhone 13 Pro 设备上的示例应用:

Trimmer

使用

添加依赖

pubspec.yaml 文件中添加 flutter_video_trimmer 依赖:

对于使用主版本 FFmpeg 包的情况:

dependencies:
  flutter_video_trimmer: ^3.0.0

对于使用 LTS 版本 FFmpeg 包的情况:

dependencies:
  video_trimmer: ^3.0.0-LTS

Android 配置

无需额外配置即可在 Android 平台上使用。

iOS 配置

Info.plist 文件中添加以下键值对:

<key>NSCameraUsageDescription</key>
<string>用于演示图像选择插件</string>
<key>NSMicrophoneUsageDescription</key>
<string>用于捕获音频以供图像选择插件使用</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>用于演示图像选择插件</string>

FFmpeg 发行版

该包支持 FFmpeg 主版本和 LTS 版本。

主版本 LTS 版本
Android API Level 24 16
Android 相机访问 -
Android 架构 arm-v7a-neon, arm64-v8a, x86, x86-64 arm-v7a, arm-v7a-neon, arm64-v8a, x86, x86-64
iOS 最小 SDK 12.1 10
iOS 架构 arm64, arm64-simulator, arm64-mac-catalyst, x86-64, x86-64-mac-catalyst armv7, arm64, i386, x86-64

功能

加载输入视频文件

final Trimmer _trimmer = Trimmer();
await _trimmer.loadVideo(videoFile: file);

保存裁剪后的视频

返回一个字符串来指示保存操作是否成功。

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

视频播放状态

返回视频播放状态。如果为 true 则视频正在播放,否则暂停。

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

高级命令

你可以使用高级的 FFmpeg 命令进行更多定制。通过 ffmpegCommand 属性定义你的 FFmpeg 命令,并使用 customVideoFormat 设置输出视频格式。

有关更多信息,请参阅 官方 FFmpeg 文档

注意:传递错误的视频格式到 customVideoFormat 属性可能会导致崩溃。

// 定义自定义命令的示例

// 这个默认用于创建 GIF,因此你不需要使用这个。

await _trimmer
    .saveTrimmedVideo(
        startValue: _startValue,
        endValue: _endValue,
        ffmpegCommand:
            '-vf "fps=10,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0',
        customVideoFormat: '.gif')
    .then((value) {
  setState(() {
    _value = value;
  });
});

小部件

显示视频播放区域

VideoViewer(trimmer: _trimmer)

显示视频裁剪区域

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),
)

示例代码

替换新创建的 Flutter 项目的 main.dart 文件内容。

import 'dart:io';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_video_trimmer/flutter_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;
                    });
                  },
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

解决 LTS 版本问题

如果在 Android 平台上遇到 minSdkVersion 需要设置为 24 的错误,或者在 iOS 平台上遇到 Podfile 平台版本应为 11 的错误,首先查看 pubspec.lock 文件中 ffmpeg_kit_flutter 是否有 -LTS 后缀。这应该可以解决 iOS 平台的所有问题。

如果在 Android 上仍然遇到相同的问题,请尝试在 <project_directory>/android/app/src/main/AndroidManifest.xml 中添加以下内容:

<manifest xmlns:tools="http://schemas.android.com/tools" ....... >
    <uses-sdk tools:overrideLibrary="com.arthenica.ffmpegkit.flutter, com.arthenica.ffmpegkit" />
</manifest>

更多关于Flutter视频裁剪插件flutter_video_trimmer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter视频裁剪插件flutter_video_trimmer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用flutter_video_trimmer插件进行视频裁剪的示例代码。这个插件允许用户选择视频的一部分进行裁剪。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加flutter_video_trimmer依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_video_trimmer: ^0.5.0  # 请确保使用最新版本

然后运行flutter pub get来安装依赖。

2. 导入插件

在你的Dart文件中导入插件:

import 'package:flutter_video_trimmer/flutter_video_trimmer.dart';

3. 使用插件

以下是一个完整的示例,展示如何集成flutter_video_trimmer到你的Flutter应用中:

import 'package:flutter/material.dart';
import 'package:flutter_video_trimmer/flutter_video_trimmer.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: VideoTrimmerScreen(),
    );
  }
}

class VideoTrimmerScreen extends StatefulWidget {
  @override
  _VideoTrimmerScreenState createState() => _VideoTrimmerScreenState();
}

class _VideoTrimmerScreenState extends State<VideoTrimmerScreen> {
  late String videoPath;
  late File trimmedVideoFile;

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

  Future<void> _getSampleVideoPath() async {
    final directory = await getApplicationDocumentsDirectory();
    videoPath = '${directory.path}/sample_video.mp4';  // 替换为你的视频路径
    // 确保视频文件存在,或者你可以选择一个已存在的视频
    // 这里我们假设已经有一个名为sample_video.mp4的视频文件在指定目录
    setState(() {});
  }

  Future<void> _trimVideo(VideoTrimmerResult result) async {
    final directory = await getApplicationDocumentsDirectory();
    final trimmedVideoPath = '${directory.path}/trimmed_video.mp4';
    trimmedVideoFile = File(trimmedVideoPath);

    // 保存裁剪后的视频
    await FlutterVideoTrimmer.trimVideo(
      videoPath: videoPath,
      startTime: result.startTime,
      endTime: result.endTime,
      outputPath: trimmedVideoPath,
      showProgressBar: true,
    );

    // 处理裁剪后的视频文件,例如显示、上传等
    print('Trimmed Video Path: $trimmedVideoPath');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Video Trimmer Example'),
      ),
      body: Center(
        child: videoPath.isEmpty
            ? CircularProgressIndicator()
            : VideoTrimmer(
                videoPath: videoPath,
                onTrimmed: _trimVideo,
              ),
      ),
    );
  }
}

4. 运行应用

确保你的开发环境中已经有一个有效的视频文件,并替换videoPath为你的视频文件路径。运行你的Flutter应用,你应该能够看到一个视频裁剪界面,用户可以选择视频的开始和结束时间,然后点击确认进行裁剪。

注意事项

  • 确保视频文件路径是正确的,并且文件存在。
  • flutter_video_trimmer依赖于FFmpeg进行视频处理,因此在Android上可能需要配置FFmpeg的编译选项。
  • 在iOS上,你可能需要添加FFmpeg相关的权限配置。

这个示例应该能够帮助你快速集成flutter_video_trimmer到你的Flutter应用中。如果需要更详细的功能或自定义,请参考插件的官方文档。

回到顶部