Flutter媒体信息获取插件media_info的使用

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

Flutter媒体信息获取插件media_info的使用

插件概述

media_info 是一个用于确定音频、视频和照片属性的Flutter插件。根据底层平台的不同版本,会应用各种方法来获取字段。目前支持的属性包括:

  • 宽度
  • 高度
  • 帧速率
  • 持续时间(以毫秒为单位)
  • MIME类型
  • 轨道数量

此外,还可以生成缩略图。

Pub

示例代码

以下是一个完整的示例应用程序,展示了如何使用 media_info 插件来获取媒体文件的信息,并生成不同分辨率的缩略图。

import 'dart:async';
import 'dart:io';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:media_info/media_info.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class Resolution {
  const Resolution(this.w, this.h);

  final int w;
  final int h;

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is Resolution && other.w == w && other.h == h;
  }

  @override
  int get hashCode => w.hashCode ^ h.hashCode;
}

const List<Resolution> _resolutions = [
  Resolution(384, 216),
  Resolution(512, 288),
  Resolution(640, 360),
  Resolution(768, 432),
  Resolution(896, 504),
  Resolution(1024, 576),
  Resolution(1152, 648),
  Resolution(1280, 720),
  Resolution(1408, 792),
  Resolution(1536, 864),
  Resolution(1664, 936),
  Resolution(1792, 1008),
  Resolution(1920, 1080),
];

class _MyAppState extends State<MyApp> {
  String? _file;
  Map<String, dynamic>? _mediaInfoCache;
  final Map<String, Future<String>> _thumbnails = <String, Future<String>>{};

  final MediaInfo _mediaInfo = MediaInfo();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      showPerformanceOverlay: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Media Info App'),
        ),
        body: SafeArea(
          child: SingleChildScrollView(
            child: Padding(
              padding: const EdgeInsets.all(24.0),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: <Widget>[
                  Text(_file ?? 'Please select a file'),
                  Text(
                    (_mediaInfoCache?.keys ?? <String>[])
                        .map((String k) => '$k: ${_mediaInfoCache![k]}')
                        .join(',\n\n'),
                    style: Theme.of(context).textTheme.bodyText2,
                  ),
                  Builder(
                    builder: (BuildContext context) {
                      if (_thumbnails.isEmpty) {
                        return const SizedBox();
                      }

                      final List<String> listW = _thumbnails.keys.toList();
                      listW.sort((a, b) {
                        final wA = int.parse(a.split('x').first);
                        final wB = int.parse(b.split('x').first);

                        return wA.compareTo(wB);
                      });

                      final List<Widget> widgets = <Widget>[];
                      for (final String res in listW) {
                        widgets.addAll([
                          Text(res),
                          FutureBuilder<String>(
                            future: _thumbnails[res],
                            builder: (BuildContext context, snapshot) {
                              if (snapshot.hasData) {
                                return Image.file(File(snapshot.data!));
                              }
                              if (snapshot.hasError) {
                                return Text(
                                  'E: ${snapshot.error}',
                                  style: TextStyle(color: Colors.red),
                                );
                              }

                              return const SizedBox();
                            },
                          ),
                          Divider(),
                        ]);
                      }

                      return Column(
                        mainAxisSize: MainAxisSize.min,
                        children: widgets,
                      );
                    },
                  ),
                ],
              ),
            ),
          ),
        ),
        floatingActionButton: _buildSelectButton(),
      ),
    );
  }

  Widget _buildSelectButton() {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        FloatingActionButton(
          key: Key("asset file"),
          child: Icon(Icons.file_copy),
          tooltip: 'Load Asset',
          onPressed: _loadFromAsset,
        ),
        SizedBox(width: 24),
        FloatingActionButton(
          key: Key("local file"),
          child: Icon(Icons.attach_file),
          onPressed: _selectFile,
        ),
        SizedBox(width: 24),
        FloatingActionButton(
          key: Key("remote file"),
          child: Icon(Icons.wifi),
          onPressed: _loadRemoteFile,
        ),
      ],
    );
  }

  void _loadFromAsset() async {
    var dir = Directory.systemTemp.createTempSync();
    var temp = File("${dir.path}/video.mp4")..createSync();

    final bytes =
        await rootBundle.load('assets/videos/pexels_videos_2268807.mp4');
    temp.writeAsBytesSync(
        bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes));

    setState(() {
      _file = temp.path;
      _mediaInfoCache = null;
      _thumbnails.clear();
    });

    _fetchFileDetails();
  }

  void _selectFile() async {
    final FilePickerResult? mediaFile = await FilePicker.platform.pickFiles();

    if (!mounted || mediaFile == null) {
      return;
    }

    setState(() {
      _file = mediaFile.files.single.path;
      _mediaInfoCache = null;
      _thumbnails.clear();
    });

    _fetchFileDetails();
  }

  void _fetchFileDetails() async {
    final Map<String, dynamic> mediaInfo = await _mediaInfo.getMediaInfo(_file!);

    if (!mounted || mediaInfo.isEmpty) {
      return;
    }

    setState(() {
      _mediaInfoCache = mediaInfo;
    });

    final Directory cacheDir = await getTemporaryDirectory();
    final int cacheName = _file.hashCode;

    final int w = mediaInfo['width'];
    final int h = mediaInfo['height'];

    final String mime = mediaInfo['mimeType'];
    if (mime.startsWith("video/")) {
      Set<Resolution> resolutions = Set();
      resolutions.addAll(_resolutions);
      resolutions.add(Resolution(w, h));

      for (final Resolution res in resolutions) {
        final String target = File('${cacheDir.path}/$cacheName.${res.w}.${res.h}').path;
        if (File(target).existsSync()) {
          File(target).deleteSync();
        }

        _thumbnails['${res.w}x${res.h}'] = _mediaInfo.generateThumbnail(
          _file!,
          target,
          res.w,
          res.h,
          positionMs: 100,
        );
      }
    }

    setState(() {});
  }

  void _loadRemoteFile() async {
    setState(() {
      _file = "remote file";
      _mediaInfoCache = null;
      _thumbnails.clear();
    });

    Set<Resolution> resolutions = Set();
    resolutions.add(Resolution(1280, 720));

    final Directory cacheDir = await getTemporaryDirectory();
    final int cacheName = _file.hashCode;

    for (final Resolution res in resolutions) {
      final String target = File('${cacheDir.path}/$cacheName.${res.w}').path;
      if (File(target).existsSync()) {
        File(target).deleteSync();
      }

      _thumbnails['${res.w}x${res.h}'] = _mediaInfo.generateThumbnail(
        "https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4",
        target,
        res.w,
        res.h,
        positionMs: 5000,
      );
    }

    setState(() {});
  }
}

关键点解释

  1. 选择文件:通过 FloatingActionButton 提供了三种方式加载文件:

    • 从本地资源加载 (_loadFromAsset)
    • 从本地文件系统选择文件 (_selectFile)
    • 加载远程文件 (_loadRemoteFile)
  2. 获取媒体信息_fetchFileDetails 方法使用 MediaInfo.getMediaInfo 获取媒体文件的详细信息,并将其存储在 _mediaInfoCache 中。

  3. 生成缩略图:如果媒体文件是视频,则会根据预定义的分辨率列表生成缩略图,并将这些缩略图的生成任务存储在 _thumbnails 中。

  4. 显示信息:在界面上显示媒体文件的路径、详细信息以及生成的缩略图。

注意事项

  • 确保在 pubspec.yaml 文件中添加了 media_info 和其他依赖项。
  • 如果需要处理远程文件,请确保网络权限已正确配置。
  • 对于本地资源文件,确保在 pubspec.yaml 中正确配置了资源路径。

通过以上步骤,您可以轻松地使用 media_info 插件来获取媒体文件的详细信息并生成缩略图。希望这个示例能帮助您更好地理解和使用该插件。


更多关于Flutter媒体信息获取插件media_info的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter媒体信息获取插件media_info的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用media_info插件来获取媒体信息的一个基本示例。这个插件允许你获取关于视频和音频文件的详细信息,比如时长、分辨率、比特率等。

首先,确保你的Flutter项目已经配置好,并且已经添加了media_info插件。你可以在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  media_info: ^x.y.z  # 请使用最新版本号替换x.y.z

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

接下来是一个简单的示例代码,展示如何使用media_info插件获取媒体信息:

import 'package:flutter/material.dart';
import 'package:media_info/media_info.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Media Info Example'),
        ),
        body: Center(
          child: MediaInfoExample(),
        ),
      ),
    );
  }
}

class MediaInfoExample extends StatefulWidget {
  @override
  _MediaInfoExampleState createState() => _MediaInfoExampleState();
}

class _MediaInfoExampleState extends State<MediaInfoExample> {
  MediaInfo? mediaInfo;
  String? errorMessage;

  @override
  void initState() {
    super.initState();
    _getMediaInfo('path/to/your/media/file.mp4');
  }

  Future<void> _getMediaInfo(String mediaPath) async {
    try {
      mediaInfo = await MediaInfo.fromFile(mediaPath);
      setState(() {});
    } catch (e) {
      errorMessage = e.toString();
      setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        if (errorMessage != null)
          Text(
            'Error: $errorMessage',
            style: TextStyle(color: Colors.red),
          ),
        if (mediaInfo != null)
          Column(
            children: <Widget>[
              Text('Duration: ${mediaInfo!.duration} ms'),
              Text('Width: ${mediaInfo!.width} px'),
              Text('Height: ${mediaInfo!.height} px'),
              Text('Bitrate: ${mediaInfo!.bitrate} bps'),
              Text('Format: ${mediaInfo!.format}'),
              // 根据需要添加更多信息
            ],
          ),
        ElevatedButton(
          onPressed: () {
            // 重新获取媒体信息(例如,用于测试不同的文件路径)
            // _getMediaInfo('path/to/another/media/file.mp3');
          },
          child: Text('Get Media Info'),
        ),
      ],
    );
  }
}

注意事项

  1. 文件路径:确保你提供的文件路径是正确的,并且该文件存在于你的设备或模拟器上。对于Android设备,你可能需要将文件放在应用的files目录中或使用适当的文件访问权限。
  2. 权限:对于访问设备上的文件,你可能需要在AndroidManifest.xmlInfo.plist中添加相应的权限声明。
  3. 错误处理:在实际应用中,添加更详细的错误处理逻辑,以应对各种可能的异常情况。

这个示例展示了如何使用media_info插件来获取媒体文件的基本信息,并将其显示在Flutter应用的界面上。你可以根据具体需求进一步扩展这个示例。

回到顶部