video_info_handler.dart 3.33 KB
import 'dart:io';

import 'package:appframe/services/dispatcher.dart';
import 'package:appframe/utils/file_type_util.dart';
import 'package:dio/dio.dart';
import 'package:ffmpeg_kit_flutter_new/ffprobe_kit.dart';
import 'package:ffmpeg_kit_flutter_new/media_information_session.dart';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';

class VideoInfoHandler extends MessageHandler {
  @override
  Future handleMessage(params) async {
    if (params is! Map<String, dynamic>) {
      throw Exception('参数错误');
    }

    final url = params['url'] as String;
    final filePath = await _getFilePath(url);
    final file = File(filePath);

    if (!file.existsSync()) {
      throw Exception('视频文件不存在');
    }

    // 使用 ffmpeg_kit_flutter_new 获取视频信息
    final mediaInfoSession = await FFprobeKit.getMediaInformation(filePath);
    final returnCode = await mediaInfoSession.getReturnCode();
    if (!ReturnCode.isSuccess(returnCode)) {
      throw Exception('获取视频信息失败');
    }

    final result = await _extractVideoInfo(mediaInfoSession, file, filePath);
    return result;
  }

  /// 根据URL获取文件路径,如果URL是网络地址则下载到本地
  Future<String> _getFilePath(String url) async {
    if (url.startsWith('http')) {
      // 获取后缀名
      String ext = path.extension(url);
      // 获取应用文档目录路径
      final Directory tempDir = await getApplicationDocumentsDirectory();

      final targetPath = path.join(tempDir.path, '${DateTime.now().millisecondsSinceEpoch}$ext');

      final resp = await Dio().download(url, targetPath);
      if (resp.statusCode != 200) {
        throw Exception('文件下载失败');
      }

      return targetPath;
    } else {
      return url;
    }
  }

  /// 提取视频信息
  Future<Map<String, dynamic>> _extractVideoInfo(
      MediaInformationSession mediaInfoSession, File file, String filePath) async {
    final mediaInformation = mediaInfoSession.getMediaInformation();
    if (mediaInformation == null) {
      throw Exception('获取视频信息失败');
    }

    // 获取视频时长
    final durationStr = mediaInformation.getDuration();
    if (durationStr == null) {
      throw Exception('获取视频信息失败');
    }

    var duration = (double.tryParse(durationStr) ?? 0).ceil();

    // 获取视频流信息
    final videoStreams = mediaInformation
        .getStreams()
        .where((stream) => stream.getAllProperties() != null && stream.getAllProperties()!['codec_type'] == 'video')
        .toList();
    if (videoStreams.isEmpty) {
      throw Exception('获取视频信息失败');
    }

    final videoStream = videoStreams[0];
    final properties = videoStream.getAllProperties();
    int width = properties!['width'] ?? 0;
    int height = properties['height'] ?? 0;

    // 获取文件大小
    final size = await file.length();

    // 获取MIME类型并转换为文件扩展名
    final mimeType = await FileTypeUtil.getMimeType(file);
    final fileExtension = FileTypeUtil.getExtensionFromMime(mimeType);

    return {
      'tempFilePath': '/temp$filePath',
      'width': width,
      'height': height,
      'type': fileExtension,
      'duration': duration, // 已经是秒单位
      'size': size,
    };
  }
}