Flutter视频处理插件videna的使用

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

Flutter视频处理插件videna的使用

Package Version License Platform

Videna 是一个用于在Windows和Linux上进行视频解码和播放的Flutter库。

特性

  • 将视频文件解码为帧
  • 在Flutter小部件中显示帧
  • 在视频中跳转到特定帧
  • 获取视频元数据(时长、分辨率等)
  • 支持广泛的视频格式

安装

要使用此包,在你的 pubspec.yaml 文件中添加 videna 作为依赖项:

dependencies:
  videna: ^0.0.1

然后,在终端中运行以下命令以获取包:

$ flutter pub get

使用方法

将包导入到你的Dart文件中:

import 'package:videna/videna.dart';

要播放本地视频文件,可以使用 Video 小部件:

final video = Video();

video.open('path_to_video_file.mp4');

类似地,要解码视频,可以使用 VidenaPlayer 类:

final videna = VidenaPlayer(imageCallback: (videoFrame) {},
                        imageMetadataCallback: (videoFrameMetadata) {},
                        progressCallback: (progress) {});

videna.open(file: 'path_to_video_file.mp4',
          speed: double.infinity,
          imgFormat: ImageFormat.yuv420P);

要从视频文件中获取元数据:

MediaMetadata m;
m = getMediaMetadataSync('path_to_video_file.mp4');
// 或者
m = await getMediaMetadata('path_to_video_file.mp4');

示例

完整的示例请参阅此仓库中的 example 目录。

import 'package:flutter/services.dart';
import 'package:videna/video.dart';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'dart:io';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  Videna.initialize();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Videna Example',
      theme: ThemeData(
          brightness: Brightness.light,
          colorSchemeSeed: const Color.fromARGB(255, 178, 150, 255)),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});
  [@override](/user/override)
  State<HomePage> createState() => HomePageState();
}

class HomePageState extends State<HomePage> {
  int index = 0;

  Uint8List? snapshotArray;

  String? snapshotName;

  Video video = Video();

  late ProgressBarProvider progressBar;

  final viewKey = GlobalKey();

  [@override](/user/override)
  void initState() {
    progressBar = video.getProgressBar();
    _init();
    super.initState();
  }

  void _init() async {
    setState(() {});
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Shortcuts(
        shortcuts: {
          LogicalKeySet(LogicalKeyboardKey.arrowLeft): SeekBckIntent(),
          LogicalKeySet(LogicalKeyboardKey.space): ToggleIntent(),
          LogicalKeySet(LogicalKeyboardKey.arrowRight): SeekFwdIntent()
        },
        child: Actions(
            actions: {
              SeekBckIntent: SeekBckAction(video, 1),
              ToggleIntent: ToggleAction(video),
              SeekFwdIntent: SeekFwdAction(video, 1)
            },
            child: Scaffold(
                appBar: Tab(
                    child: Table(children: [
                  TableRow(children: [
                    OutlinedButton(
                        onPressed: () async {
                          FilePickerResult? result =
                              await FilePicker.platform.pickFiles();
                          if (result != null) {
                            await video.open(result.files.single.path!);
                            progressBar = video.getProgressBar();
                            setState(() {});
                          } else {}
                        },
                        child: const Text('打开文件')),
                    OutlinedButton(
                      onPressed: () {
                        video.takeSnapshot();
                      },
                      child: const Text('快照'),
                    )
                  ])
                ])),
                body: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Flexible(
                          fit: FlexFit.loose,
                          child: FractionallySizedBox(
                              heightFactor: 0.635, child: video)),
                      Table(children: [
                        TableRow(
                            children: [const Row(), progressBar, const Row()]),
                        TableRow(children: [
                          backwardButtons(video),
                          OutlinedButton(
                              onPressed: () => {video.togglePause()},
                              child: const Icon(Icons.play_arrow)),
                          forwardButtons(video)
                        ]),
                      ])
                    ]))));
  }
}

Widget backwardButtons(Video video) {
  if (Platform.isAndroid) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        OutlinedButton(
            onPressed: () => {video.nFramesBackward(10)},
            child: const Text('-10')),
        OutlinedButton(
            onPressed: () => {video.nFramesBackward(3)},
            child: const Text('-3')),
        OutlinedButton(
            onPressed: () => {video.nFramesBackward(1)},
            child: const Text('-1'))
      ],
    );
  }
  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      OutlinedButton(
          onPressed: () => {video.nFramesBackward(10)},
          child: const Text('-10')),
      OutlinedButton(
          onPressed: () => {video.nFramesBackward(3)}, child: const Text('-3')),
      OutlinedButton(
          onPressed: () => {video.nFramesBackward(1)}, child: const Text('-1'))
    ],
  );
}

Widget forwardButtons(Video video) {
  if (Platform.isAndroid) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      verticalDirection: VerticalDirection.up,
      children: [
        OutlinedButton(
            onPressed: () => {video.nFramesForward(1)},
            child: const Text('1+')),
        OutlinedButton(
            onPressed: () => {video.nFramesForward(3)},
            child: const Text('3+')),
        OutlinedButton(
            onPressed: () => {video.nFramesForward(10)},
            child: const Text('10+')),
      ],
    );
  }
  return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
    OutlinedButton(
        onPressed: () => {video.nFramesForward(1)}, child: const Text('1+')),
    OutlinedButton(
        onPressed: () => {video.nFramesForward(3)}, child: const Text('3+')),
    OutlinedButton(
        onPressed: () => {video.nFramesForward(10)}, child: const Text('10+')),
  ]);
}

class ToggleIntent extends Intent {}

class ToggleAction extends Action<ToggleIntent> {
  final Video video;
  ToggleAction(this.video);
  [@override](/user/override)
  Object? invoke(covariant ToggleIntent intent) {
    video.togglePause();
    return null;
  }
}

class SeekFwdIntent extends Intent {}

class SeekFwdAction extends Action<SeekFwdIntent> {
  final Video video;
  final int n;
  SeekFwdAction(this.video, this.n);
  [@override](/user/override)
  Object? invoke(covariant SeekFwdIntent intent) {
    video.nFramesForward(n);
    return null;
  }
}

class SeekBckIntent extends Intent {}

class SeekBckAction extends Action<SeekBckIntent> {
  final Video video;
  final int n;
  SeekBckAction(this.video, this.n);
  [@override](/user/override)
  Object? invoke(covariant SeekBckIntent intent) {
    video.nFramesBackward(n);
    return null;
  }
}

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

1 回复

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


videna 是一个用于 Flutter 的视频处理插件,可以帮助你进行视频的编辑、转码、压缩、裁剪等操作。虽然 videna 并不是 Flutter 官方维护的插件,但它可能是一个社区开发的开源项目或其他第三方插件。在使用之前,请确保你了解该插件的功能、兼容性和维护状态。

以下是一个使用 videna 进行视频处理的基本步骤:

1. 添加依赖

首先,将 videna 插件添加到你的 pubspec.yaml 文件中:

dependencies:
  flutter:
    sdk: flutter
  videna: ^版本号  # 请替换为最新版本号

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

2. 导入插件

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

import 'package:videna/videna.dart';

3. 初始化插件

在使用 videna 之前,通常需要对其进行初始化:

await Videna.initialize();

4. 视频处理

videna 提供了多种视频处理功能,例如视频压缩、裁剪、合并等。以下是一些常见操作的示例:

视频压缩

String inputPath = '/path/to/input/video.mp4';
String outputPath = '/path/to/output/compressed_video.mp4';

await Videna.compressVideo(
  inputPath: inputPath,
  outputPath: outputPath,
  quality: VideoQuality.medium, // 压缩质量
);

视频裁剪

String inputPath = '/path/to/input/video.mp4';
String outputPath = '/path/to/output/cropped_video.mp4';

await Videna.cropVideo(
  inputPath: inputPath,
  outputPath: outputPath,
  startTime: Duration(seconds: 5), // 裁剪开始时间
  endTime: Duration(seconds: 15),  // 裁剪结束时间
);

视频合并

List<String> inputPaths = [
  '/path/to/video1.mp4',
  '/path/to/video2.mp4',
];
String outputPath = '/path/to/output/merged_video.mp4';

await Videna.mergeVideos(
  inputPaths: inputPaths,
  outputPath: outputPath,
);

5. 处理结果

处理完成后,你可以在 outputPath 指定的路径中找到处理后的视频文件。

6. 错误处理

在使用 videna 进行视频处理时,可能会遇到各种错误,例如文件不存在、权限问题等。建议在使用时进行错误处理:

try {
  await Videna.compressVideo(
    inputPath: inputPath,
    outputPath: outputPath,
    quality: VideoQuality.medium,
  );
} catch (e) {
  print('Error: $e');
}
回到顶部