You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中筛选h.265编码的视频文件?

筛选H.265编码视频的解决方案

由于file_picker仅能通过扩展名筛选文件,而VideoPlayerController没有提供读取视频编码的API,要实现H.265编码视频的筛选,需要读取视频文件的元数据来判断编码格式,以下是两种可行方案:

方案一:使用第三方Dart包 video_metadata

这个包可以直接读取视频文件的元数据,包括编码信息,无需编写原生代码。

  1. 添加依赖到pubspec.yaml:
dependencies:
  video_metadata: ^0.5.0 # 请使用最新版本
  1. 实现筛选逻辑:
import 'package:file_picker/file_picker.dart';
import 'package:video_metadata/video_metadata.dart';
import 'dart:io';

Future<void> pickAndValidateH265Video() async {
  // 先筛选MP4格式缩小范围
  final fileResult = await FilePicker.platform.pickFiles(
    type: FileType.video,
    allowedExtensions: ['mp4'],
  );

  if (fileResult == null) return;

  final selectedFile = fileResult.files.first;
  final file = File(selectedFile.path!);
  
  // 获取视频元数据
  final metadata = await MetadataRetriever.fromFile(file);
  final videoTrack = metadata.videoTracks.firstOrNull;

  // H.265对应的编码标识通常为'hevc'
  if (videoTrack != null && videoTrack.codec == 'hevc') {
    // 符合条件,执行上传逻辑
    print("选中的视频为H.265编码,开始上传");
  } else {
    // 不符合,提示用户
    print("请选择采用H.265编码的MP4视频");
  }
}

方案二:原生平台实现(Android + iOS)

如果第三方包无法满足需求,可通过MethodChannel调用原生API获取编码信息,兼容性更强。

Flutter端代码

import 'package:flutter/services.dart';
import 'package:file_picker/file_picker.dart';

final MethodChannel _videoCodecChannel = MethodChannel('video.codec.checker');

Future<void> pickH265Video() async {
  final fileResult = await FilePicker.platform.pickFiles(
    type: FileType.video,
    allowedExtensions: ['mp4'],
  );

  if (fileResult == null) return;

  final filePath = fileResult.files.first.path!;
  // 调用原生方法获取编码
  final codec = await _videoCodecChannel.invokeMethod<String>(
    'getVideoCodec',
    {'filePath': filePath},
  );

  // H.265在不同平台的编码标识可能不同:Android返回'hevc',iOS返回'hvc1'/'hev1'
  if (codec != null && {'hevc', 'hvc1', 'hev1'}.contains(codec.toLowerCase())) {
    // 执行上传
    print("视频编码符合H.265标准");
  } else {
    print("请选择H.265编码的视频");
  }
}

Android端实现(Kotlin)

在MainActivity.kt中添加MethodChannel逻辑:

import android.media.MediaMetadataRetriever
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL_NAME = "video.codec.checker"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_NAME).setMethodCallHandler { call, result ->
            when (call.method) {
                "getVideoCodec" -> {
                    val filePath = call.argument<String>("filePath")
                    if (filePath == null) {
                        result.error("INVALID_PATH", "文件路径为空", null)
                        return@setMethodCallHandler
                    }
                    val codec = getVideoCodec(filePath)
                    result.success(codec)
                }
                else -> result.notImplemented()
            }
        }
    }

    private fun getVideoCodec(filePath: String): String? {
        val retriever = MediaMetadataRetriever()
        return try {
            retriever.setDataSource(filePath)
            retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_CODEC)
        } catch (e: Exception) {
            null
        } finally {
            retriever.release()
        }
    }
}

iOS端实现(Swift)

在AppDelegate.swift中添加MethodChannel逻辑:

import UIKit
import Flutter
import AVFoundation

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    private let CHANNEL_NAME = "video.codec.checker"

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel(name: CHANNEL_NAME, binaryMessenger: controller.binaryMessenger)
        
        channel.setMethodCallHandler { [weak self] call, result in
            guard let self = self else { return }
            switch call.method {
            case "getVideoCodec":
                guard let filePath = call.arguments as? String else {
                    result(FlutterError(code: "INVALID_PATH", message: "文件路径为空", details: nil))
                    return
                }
                self.retrieveVideoCodec(filePath: filePath, result: result)
            default:
                result(FlutterMethodNotImplemented)
            }
        }
        
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

    private func retrieveVideoCodec(filePath: String, result: @escaping FlutterResult) {
        let fileURL = URL(fileURLWithPath: filePath)
        let asset = AVAsset(url: fileURL)
        
        asset.loadValuesAsynchronously(forKeys: ["tracks"]) {
            var error: NSError?
            let status = asset.statusOfValue(forKey: "tracks", error: &error)
            
            if status == .loaded {
                let videoTracks = asset.tracks(withMediaType: .video)
                guard let videoTrack = videoTracks.first else {
                    result(nil)
                    return
                }
                
                // 获取编码子类型
                let codecSubtype = videoTrack.formatDescriptions.compactMap {
                    $0 as? CMFormatDescription
                }.first.flatMap {
                    CMFormatDescriptionGetMediaSubType($0).stringValue
                }
                result(codecSubtype)
            } else {
                result(FlutterError(code: "LOAD_FAILED", message: error?.localizedDescription, details: nil))
            }
        }
    }
}

注意事项

  • 不同平台返回的H.265编码标识可能存在差异,需多值判断(如hevc、hvc1、hev1)。
  • 读取大视频文件的元数据可能存在性能开销,建议在子线程中处理或添加加载提示。

内容的提问来源于stack exchange,提问作者BongsoonChoi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 12:40:14