import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'video_decode_plugin_platform_interface.dart'; /// 视频帧类型 enum FrameType { /// I帧 iFrame, /// P帧 pFrame, } /// 视频编码类型 enum CodecType { /// H.264编码 h264, /// H.265编码 h265, } /// 帧可用回调函数类型 typedef FrameAvailableCallback = void Function(int textureId); /// 解码器实例内部类 class _DecoderInstance { final int textureId; FrameAvailableCallback? frameCallback; _DecoderInstance(this.textureId); } /// 视频解码器配置 class VideoDecoderConfig { /// 视频宽度,默认640 final int width; /// 视频高度,默认360 final int height; /// 帧率,可为空 final int? frameRate; /// 编码类型,默认h264 final CodecType codecType; /// 缓冲区大小(帧数),默认25帧 final int bufferSize; /// 解码线程数,默认1线程 final int threadCount; /// 是否为调试模式,默认false final bool isDebug; /// 是否启用硬件解码,默认true final bool enableHardwareDecoder; /// 构造函数 VideoDecoderConfig({ this.width = 640, this.height = 360, this.frameRate, this.codecType = CodecType.h264, this.bufferSize = 25, this.threadCount = 1, this.isDebug = false, this.enableHardwareDecoder = true, }); /// 转换为Map Map toMap() { return { 'width': width, 'height': height, 'frameRate': frameRate, 'codecType': codecType.toString().split('.').last, 'bufferSize': bufferSize, 'threadCount': threadCount, 'isDebug': isDebug, 'enableHardwareDecoder': enableHardwareDecoder, }; } } /// 视频解码插件主类 class VideoDecodePlugin { static const MethodChannel _channel = MethodChannel('video_decode_plugin'); // 解码器映射表,支持多实例 static final Map _decoders = {}; // 默认解码器ID static int? _defaultTextureId; // 监听器初始化标志 static bool _listenerInitialized = false; /// 初始化方法通道监听器 static void _initializeMethodCallHandler() { if (!_listenerInitialized) { _channel.setMethodCallHandler((call) async { switch (call.method) { case 'onFrameAvailable': final Map args = call.arguments; final int textureId = args['textureId']; // 调用特定纹理ID的帧回调 final decoder = _decoders[textureId]; if (decoder != null && decoder.frameCallback != null) { decoder.frameCallback!(textureId); } return null; default: throw PlatformException( code: 'Unimplemented', details: 'The method ${call.method} is not implemented', ); } }); _listenerInitialized = true; } } /// 获取平台版本 static Future getPlatformVersion() { return VideoDecodePluginPlatform.instance.getPlatformVersion(); } /// 检查当前平台是否支持 static bool get isPlatformSupported { return Platform.isAndroid || Platform.isIOS; } /// 设置帧回调(默认解码器) static void setFrameCallback(FrameAvailableCallback callback) { if (_defaultTextureId != null) { setFrameCallbackForTexture(_defaultTextureId!, callback); } } /// 为特定纹理ID设置帧回调 static void setFrameCallbackForTexture( int textureId, FrameAvailableCallback callback) { _initializeMethodCallHandler(); final decoder = _decoders[textureId]; if (decoder != null) { decoder.frameCallback = callback; } } /// 初始化解码器 static Future initDecoder(VideoDecoderConfig config) async { // 先释放之前的默认解码器 if (_defaultTextureId != null) { await releaseDecoder(); } return await createDecoder(config); } /// 创建新的解码器实例(支持多实例) static Future createDecoder(VideoDecoderConfig config) async { if (!isPlatformSupported) { debugPrint('当前平台不支持视频解码插件'); return null; } // 确保监听器已初始化 _initializeMethodCallHandler(); try { final textureId = await _channel.invokeMethod('initDecoder', config.toMap()); if (textureId != null) { // 创建新解码器实例并保存 final decoder = _DecoderInstance(textureId); _decoders[textureId] = decoder; // 设置为默认解码器 _defaultTextureId = textureId; } return _defaultTextureId; } catch (e) { debugPrint('初始化解码器失败: $e'); return null; } } /// 获取默认纹理ID static int? get textureId => _defaultTextureId; /// 获取所有活跃的纹理ID static List get allTextureIds => _decoders.keys.toList(); /// 解码视频帧(默认解码器) static Future decodeFrame( Uint8List frameData, FrameType frameType) async { if (_defaultTextureId == null) { debugPrint('解码器未初始化'); return false; } return decodeFrameForTexture(_defaultTextureId!, frameData, frameType); } /// 为特定纹理ID解码视频帧 static Future decodeFrameForTexture( int textureId, Uint8List frameData, FrameType frameType) async { if (!_decoders.containsKey(textureId)) { debugPrint('找不到纹理ID: $textureId'); return false; } try { return await _channel.invokeMethod('decodeFrame', { 'textureId': textureId, 'frameData': frameData, 'frameType': frameType.index, }) ?? false; } catch (e) { debugPrint('解码帧失败: $e'); return false; } } /// 释放默认解码器资源 static Future releaseDecoder() async { if (_defaultTextureId == null) { return true; } final result = await releaseDecoderForTexture(_defaultTextureId!); if (result) { _defaultTextureId = null; } return result; } /// 释放特定纹理ID的解码器资源 static Future releaseDecoderForTexture(int textureId) async { if (!_decoders.containsKey(textureId)) { return true; } try { final result = await _channel.invokeMethod('releaseDecoder', { 'textureId': textureId, }) ?? false; if (result) { // 从映射表中移除 _decoders.remove(textureId); // 如果释放的是默认解码器,重置默认ID if (_defaultTextureId == textureId) { _defaultTextureId = null; } } return result; } catch (e) { debugPrint('释放解码器失败: $e'); return false; } } /// 释放所有解码器 static Future releaseAllDecoders() async { bool allSuccess = true; // 复制键列表,因为我们会在迭代过程中修改映射 final textureIds = List.from(_decoders.keys); // 释放每个解码器 for (final textureId in textureIds) { final success = await releaseDecoderForTexture(textureId); if (!success) { allSuccess = false; } } // 清空状态 _decoders.clear(); _defaultTextureId = null; return allSuccess; } /// 清除特定纹理ID的回调 static void clearCallbackForTexture(int textureId) { final decoder = _decoders[textureId]; if (decoder != null) { decoder.frameCallback = null; } } /// 清除所有回调 static void clearAllCallbacks() { for (final decoder in _decoders.values) { decoder.frameCallback = null; } } /// 注册插件(不需要手动调用) static void registerWith() { // 仅用于插件注册 } /// 获取解码器统计信息 /// /// [textureId] 纹理ID /// 返回包含统计信息的Map,包括: /// - totalFramesReceived: 接收的总帧数 /// - framesRendered: 成功渲染的帧数 /// - framesDropped: 丢弃的帧数 /// - lastFrameTimestamp: 最后一帧时间戳 /// - averageProcessingTimeMs: 平均处理时间(毫秒) /// - decoderCount: 当前活跃的解码器数量 static Future> getDecoderStats(int textureId) async { try { final params = { 'textureId': textureId, }; final result = await _channel.invokeMethod>( 'getDecoderStats', params); if (result == null) { return {}; } // 将Object?类型转换为明确的类型 final Map typedResult = {}; result.forEach((key, value) { if (key is String) { typedResult[key] = value; } }); return typedResult; } catch (e) { if (kDebugMode) { print('获取解码器统计信息失败: $e'); } return {}; } } }