video_decode_plugin/lib/video_decode_plugin.dart
2025-04-28 09:11:51 +08:00

363 lines
8.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 {};
}
}
}