video_decode_plugin/lib/video_decode_plugin.dart

363 lines
8.9 KiB
Dart
Raw Normal View History

2025-04-21 10:56:28 +08:00
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<String, dynamic> 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<int, _DecoderInstance> _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<dynamic, dynamic> 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<String?> 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<int?> initDecoder(VideoDecoderConfig config) async {
// 先释放之前的默认解码器
if (_defaultTextureId != null) {
await releaseDecoder();
}
return await createDecoder(config);
}
/// 创建新的解码器实例(支持多实例)
static Future<int?> createDecoder(VideoDecoderConfig config) async {
if (!isPlatformSupported) {
debugPrint('当前平台不支持视频解码插件');
return null;
}
// 确保监听器已初始化
_initializeMethodCallHandler();
try {
final textureId =
await _channel.invokeMethod<int>('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<int> get allTextureIds => _decoders.keys.toList();
/// 解码视频帧(默认解码器)
static Future<bool> decodeFrame(
Uint8List frameData, FrameType frameType) async {
if (_defaultTextureId == null) {
debugPrint('解码器未初始化');
return false;
}
return decodeFrameForTexture(_defaultTextureId!, frameData, frameType);
}
/// 为特定纹理ID解码视频帧
static Future<bool> decodeFrameForTexture(
int textureId, Uint8List frameData, FrameType frameType) async {
if (!_decoders.containsKey(textureId)) {
debugPrint('找不到纹理ID: $textureId');
return false;
}
try {
return await _channel.invokeMethod<bool>('decodeFrame', {
'textureId': textureId,
'frameData': frameData,
'frameType': frameType.index,
}) ??
false;
} catch (e) {
debugPrint('解码帧失败: $e');
return false;
}
}
/// 释放默认解码器资源
static Future<bool> releaseDecoder() async {
if (_defaultTextureId == null) {
return true;
}
final result = await releaseDecoderForTexture(_defaultTextureId!);
if (result) {
_defaultTextureId = null;
}
return result;
}
/// 释放特定纹理ID的解码器资源
static Future<bool> releaseDecoderForTexture(int textureId) async {
if (!_decoders.containsKey(textureId)) {
return true;
}
try {
final result = await _channel.invokeMethod<bool>('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<bool> releaseAllDecoders() async {
bool allSuccess = true;
// 复制键列表,因为我们会在迭代过程中修改映射
final textureIds = List<int>.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<Map<String, dynamic>> getDecoderStats(int textureId) async {
try {
final params = {
'textureId': textureId,
};
final result = await _channel.invokeMethod<Map<Object?, Object?>>(
'getDecoderStats', params);
if (result == null) {
return {};
}
// 将Object?类型转换为明确的类型
final Map<String, dynamic> typedResult = {};
result.forEach((key, value) {
if (key is String) {
typedResult[key] = value;
}
});
return typedResult;
} catch (e) {
if (kDebugMode) {
print('获取解码器统计信息失败: $e');
}
return {};
}
}
}